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:
committed by
GitHub
parent
2bf443661d
commit
c33156b134
@@ -155,7 +155,7 @@ public enum SpServerError {
|
|||||||
SP_CONFIGURATION_VALUE_CHANGE_NOT_ALLOWED(
|
SP_CONFIGURATION_VALUE_CHANGE_NOT_ALLOWED(
|
||||||
"hawkbit.server.error.repo.tenantConfigurationValueChangeNotAllowed",
|
"hawkbit.server.error.repo.tenantConfigurationValueChangeNotAllowed",
|
||||||
"The requested tenant configuration value modification is not allowed."),
|
"The requested tenant configuration value modification is not allowed."),
|
||||||
SP_MULTIASSIGNMENT_NOT_ENABLED(
|
SP_MULTIASSIGNMENT(
|
||||||
"hawkbit.server.error.multiAssignmentNotEnabled",
|
"hawkbit.server.error.multiAssignmentNotEnabled",
|
||||||
"The requested operation requires multi assignments to be enabled."),
|
"The requested operation requires multi assignments to be enabled."),
|
||||||
SP_NO_WEIGHT_PROVIDED_IN_MULTIASSIGNMENT_MODE(
|
SP_NO_WEIGHT_PROVIDED_IN_MULTIASSIGNMENT_MODE(
|
||||||
|
|||||||
@@ -687,23 +687,6 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
|
|||||||
.andExpect(jsonPath("$.deployment.maintenanceWindow", equalTo("available")));
|
.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.
|
* The system should not create a new target because of a too long controller id.
|
||||||
*/
|
*/
|
||||||
@@ -759,16 +742,6 @@ class DdiRootControllerTest extends AbstractDDiApiIntegrationTest {
|
|||||||
return sendDeploymentActionFeedback(target, action, execution, finished, null);
|
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 {
|
private void withPollingTime(final String pollingTime, final Callable<Void> runnable) throws Exception {
|
||||||
getAs(withUser("tenantadmin", TENANT_CONFIGURATION),
|
getAs(withUser("tenantadmin", TENANT_CONFIGURATION),
|
||||||
() -> {
|
() -> {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
package org.eclipse.hawkbit.amqp;
|
package org.eclipse.hawkbit.amqp;
|
||||||
|
|
||||||
import static org.eclipse.hawkbit.context.AccessContext.asSystem;
|
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 static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.BATCH_ASSIGNMENTS_ENABLED;
|
||||||
|
|
||||||
import java.net.URI;
|
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.DmfConfirmRequest;
|
||||||
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest;
|
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest;
|
||||||
import org.eclipse.hawkbit.dmf.json.model.DmfMetadata;
|
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.DmfSoftwareModule;
|
||||||
import org.eclipse.hawkbit.dmf.json.model.DmfTarget;
|
import org.eclipse.hawkbit.dmf.json.model.DmfTarget;
|
||||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
|
||||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
|
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.TargetAssignDistributionSetEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
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.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.TargetAssignDistributionSetServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.TargetAttributesRequestedServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.TargetAttributesRequestedServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.TargetDeletedServiceEvent;
|
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 SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement;
|
||||||
private final DistributionSetManagement<? extends DistributionSet> distributionSetManagement;
|
private final DistributionSetManagement<? extends DistributionSet> distributionSetManagement;
|
||||||
private final DeploymentManagement deploymentManagement;
|
private final DeploymentManagement deploymentManagement;
|
||||||
private final RepositoryProperties repositoryProperties;
|
|
||||||
|
|
||||||
@SuppressWarnings("java:S107")
|
@SuppressWarnings("java:S107")
|
||||||
protected AmqpMessageDispatcherService(
|
protected AmqpMessageDispatcherService(
|
||||||
@@ -109,8 +101,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
final TargetManagement<? extends Target> targetManagement,
|
final TargetManagement<? extends Target> targetManagement,
|
||||||
final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement,
|
final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement,
|
||||||
final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
|
final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
|
||||||
final DeploymentManagement deploymentManagement,
|
final DeploymentManagement deploymentManagement) {
|
||||||
final RepositoryProperties repositoryProperties) {
|
|
||||||
super(rabbitTemplate);
|
super(rabbitTemplate);
|
||||||
this.artifactUrlHandler = artifactUrlHandler;
|
this.artifactUrlHandler = artifactUrlHandler;
|
||||||
this.amqpSenderService = amqpSenderService;
|
this.amqpSenderService = amqpSenderService;
|
||||||
@@ -119,7 +110,6 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
this.softwareModuleManagement = softwareModuleManagement;
|
this.softwareModuleManagement = softwareModuleManagement;
|
||||||
this.distributionSetManagement = distributionSetManagement;
|
this.distributionSetManagement = distributionSetManagement;
|
||||||
this.deploymentManagement = deploymentManagement;
|
this.deploymentManagement = deploymentManagement;
|
||||||
this.repositoryProperties = repositoryProperties;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBatchAssignmentsEnabled() {
|
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(
|
protected void sendUpdateMessageToTarget(
|
||||||
final ActionProperties actionsProps, final Target target,
|
final ActionProperties actionsProps, final Target target,
|
||||||
final Map<SoftwareModule, Map<String, String>> softwareModules) {
|
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));
|
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
|
* 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,
|
* 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;
|
: 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(
|
private static <T, R> List<R> partitionedParallelExecution(
|
||||||
final Collection<T> controllerIds, final Function<Collection<T>, List<R>> loadingFunction) {
|
final Collection<T> controllerIds, final Function<Collection<T>, List<R>> loadingFunction) {
|
||||||
// Ensure not exceeding the max value of MAX_PROCESSING_SIZE
|
// 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(
|
private void sendSingleUpdateMessage(
|
||||||
final ActionProperties action, final Target target, final Map<SoftwareModule, Map<String, String>> modules) {
|
final ActionProperties action, final Target target, final Map<SoftwareModule, Map<String, String>> modules) {
|
||||||
final String tenant = action.getTenant();
|
final String tenant = action.getTenant();
|
||||||
|
|||||||
@@ -9,15 +9,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.amqp;
|
package org.eclipse.hawkbit.amqp;
|
||||||
|
|
||||||
import static org.eclipse.hawkbit.repository.RepositoryConstants.MAX_ACTION_COUNT;
|
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
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.UpdateMode;
|
||||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
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;
|
||||||
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
|
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
|
||||||
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate.ActionStatusCreateBuilder;
|
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.SoftwareModule;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
|
import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
|
||||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
|
|
||||||
import org.eclipse.hawkbit.utils.IpUtil;
|
import org.eclipse.hawkbit.utils.IpUtil;
|
||||||
import org.springframework.amqp.AmqpRejectAndDontRequeueException;
|
import org.springframework.amqp.AmqpRejectAndDontRequeueException;
|
||||||
import org.springframework.amqp.core.Message;
|
import org.springframework.amqp.core.Message;
|
||||||
@@ -315,29 +310,7 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void sendUpdateCommandToTarget(final Target target) {
|
private void sendUpdateCommandToTarget(final Target target) {
|
||||||
if (TenantConfigHelper.getAsSystem(TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED, Boolean.class)) {
|
// send oldest action to Target
|
||||||
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) {
|
|
||||||
final Optional<Action> actionOptional = controllerManagement.findActiveActionWithHighestWeight(target.getControllerId());
|
final Optional<Action> actionOptional = controllerManagement.findActiveActionWithHighestWeight(target.getControllerId());
|
||||||
if (actionOptional.isEmpty()) {
|
if (actionOptional.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -265,11 +265,10 @@ public class DmfApiConfiguration {
|
|||||||
final SystemManagement systemManagement,
|
final SystemManagement systemManagement,
|
||||||
final TargetManagement<? extends Target> targetManagement,
|
final TargetManagement<? extends Target> targetManagement,
|
||||||
final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
|
final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
|
||||||
final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement, final DeploymentManagement deploymentManagement,
|
final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement, final DeploymentManagement deploymentManagement) {
|
||||||
final RepositoryProperties repositoryProperties) {
|
|
||||||
return new AmqpMessageDispatcherService(rabbitTemplate, amqpSenderService, artifactUrlHandler,
|
return new AmqpMessageDispatcherService(rabbitTemplate, amqpSenderService, artifactUrlHandler,
|
||||||
systemManagement, targetManagement, softwareModuleManagement, distributionSetManagement,
|
systemManagement, targetManagement, softwareModuleManagement, distributionSetManagement,
|
||||||
deploymentManagement, repositoryProperties);
|
deploymentManagement);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, Object> getTTLMaxArgsAuthenticationQueue() {
|
private static Map<String, Object> getTTLMaxArgsAuthenticationQueue() {
|
||||||
|
|||||||
@@ -78,9 +78,6 @@ import org.springframework.test.context.TestPropertySource;
|
|||||||
"spring.main.allow-bean-definition-overriding=true" })
|
"spring.main.allow-bean-definition-overriding=true" })
|
||||||
class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
|
class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
|
||||||
|
|
||||||
@Autowired
|
|
||||||
protected RepositoryProperties repositoryProperties;
|
|
||||||
|
|
||||||
private static final String TENANT = "DEFAULT";
|
private static final String TENANT = "DEFAULT";
|
||||||
private static final Long TENANT_ID = 4711L;
|
private static final Long TENANT_ID = 4711L;
|
||||||
|
|
||||||
@@ -117,7 +114,7 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
|
|||||||
|
|
||||||
amqpMessageDispatcherService = new AmqpMessageDispatcherService(rabbitTemplate, senderService,
|
amqpMessageDispatcherService = new AmqpMessageDispatcherService(rabbitTemplate, senderService,
|
||||||
artifactUrlHandlerMock, systemManagement, targetManagement,
|
artifactUrlHandlerMock, systemManagement, targetManagement,
|
||||||
softwareModuleManagement, distributionSetManagement, deploymentManagement, repositoryProperties);
|
softwareModuleManagement, distributionSetManagement, deploymentManagement);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ package org.eclipse.hawkbit.amqp;
|
|||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
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.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
@@ -112,10 +111,6 @@ class AmqpMessageHandlerServiceTest {
|
|||||||
TenantConfigHelper.setTenantConfigurationManagement(tenantConfigurationManagement);
|
TenantConfigHelper.setTenantConfigurationManagement(tenantConfigurationManagement);
|
||||||
messageConverter = new Jackson2JsonMessageConverter();
|
messageConverter = new Jackson2JsonMessageConverter();
|
||||||
lenient().when(rabbitTemplate.getMessageConverter()).thenReturn(messageConverter);
|
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(
|
amqpMessageHandlerService = new AmqpMessageHandlerService(
|
||||||
rabbitTemplate, amqpMessageDispatcherServiceMock, controllerManagementMock, confirmationManagementMock);
|
rabbitTemplate, amqpMessageDispatcherServiceMock, controllerManagementMock, confirmationManagementMock);
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
package org.eclipse.hawkbit.integration;
|
package org.eclipse.hawkbit.integration;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
|
||||||
import static org.eclipse.hawkbit.dmf.amqp.api.EventTopic.BATCH_DOWNLOAD;
|
import static org.eclipse.hawkbit.dmf.amqp.api.EventTopic.BATCH_DOWNLOAD;
|
||||||
import static org.eclipse.hawkbit.dmf.amqp.api.EventTopic.BATCH_DOWNLOAD_AND_INSTALL;
|
import static org.eclipse.hawkbit.dmf.amqp.api.EventTopic.BATCH_DOWNLOAD_AND_INSTALL;
|
||||||
import static org.eclipse.hawkbit.dmf.amqp.api.EventTopic.DOWNLOAD;
|
import static org.eclipse.hawkbit.dmf.amqp.api.EventTopic.DOWNLOAD;
|
||||||
@@ -18,31 +17,19 @@ import static org.eclipse.hawkbit.dmf.amqp.api.MessageType.EVENT;
|
|||||||
import static org.eclipse.hawkbit.repository.model.Action.ActionType.DOWNLOAD_ONLY;
|
import static org.eclipse.hawkbit.repository.model.Action.ActionType.DOWNLOAD_ONLY;
|
||||||
import static org.eclipse.hawkbit.repository.model.Action.ActionType.FORCED;
|
import static org.eclipse.hawkbit.repository.model.Action.ActionType.FORCED;
|
||||||
|
|
||||||
import java.util.AbstractMap.SimpleEntry;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
|
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
|
||||||
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
|
|
||||||
import org.eclipse.hawkbit.dmf.json.model.DmfActionRequest;
|
|
||||||
import org.eclipse.hawkbit.dmf.json.model.DmfActionStatus;
|
import org.eclipse.hawkbit.dmf.json.model.DmfActionStatus;
|
||||||
import org.eclipse.hawkbit.dmf.json.model.DmfBatchDownloadAndUpdateRequest;
|
import org.eclipse.hawkbit.dmf.json.model.DmfBatchDownloadAndUpdateRequest;
|
||||||
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest;
|
|
||||||
import org.eclipse.hawkbit.dmf.json.model.DmfMultiActionRequest;
|
|
||||||
import org.eclipse.hawkbit.dmf.json.model.DmfMultiActionRequest.DmfMultiActionElement;
|
|
||||||
import org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule;
|
|
||||||
import org.eclipse.hawkbit.dmf.json.model.DmfTarget;
|
import org.eclipse.hawkbit.dmf.json.model.DmfTarget;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
|
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.TargetAssignDistributionSetEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
||||||
@@ -51,23 +38,16 @@ import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
|||||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutCreatedEvent;
|
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupCreatedEvent;
|
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupUpdatedEvent;
|
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutUpdatedEvent;
|
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.TenantConfigurationCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.TenantConfigurationCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.exception.TenantConfigurationValueChangeNotAllowedException;
|
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||||
import org.eclipse.hawkbit.repository.model.DeploymentRequest;
|
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||||
import org.eclipse.hawkbit.repository.model.RepositoryModelConstants;
|
import org.eclipse.hawkbit.repository.model.RepositoryModelConstants;
|
||||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
|
||||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||||
@@ -212,294 +192,6 @@ class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpServiceInt
|
|||||||
assertDownloadAndInstallMessage(distributionSet2.getModules(), controllerId);
|
assertDownloadAndInstallMessage(distributionSet2.getModules(), controllerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If multi assignment is enabled multi-action messages are sent.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
@ExpectEvents({
|
|
||||||
@Expect(type = TargetCreatedEvent.class, count = 1),
|
|
||||||
@Expect(type = MultiActionAssignEvent.class, count = 2),
|
|
||||||
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0),
|
|
||||||
@Expect(type = CancelTargetAssignmentEvent.class, count = 0),
|
|
||||||
@Expect(type = ActionCreatedEvent.class, count = 2),
|
|
||||||
@Expect(type = ActionUpdatedEvent.class, count = 0),
|
|
||||||
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
|
|
||||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6),
|
|
||||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 2), // implicit lock
|
|
||||||
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6), // implicit lock
|
|
||||||
@Expect(type = TargetUpdatedEvent.class, count = 2),
|
|
||||||
@Expect(type = TargetPollEvent.class, count = 1),
|
|
||||||
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
|
|
||||||
void assignMultipleDsInMultiAssignMode() {
|
|
||||||
enableMultiAssignments();
|
|
||||||
final String controllerId = TARGET_PREFIX + "assignMultipleDsInMultiAssignMode";
|
|
||||||
registerAndAssertTargetWithExistingTenant(controllerId);
|
|
||||||
|
|
||||||
final Long actionId1 = assignNewDsToTarget(controllerId, 450);
|
|
||||||
final SimpleEntry<Long, EventTopic> action1Install = new SimpleEntry<>(actionId1, EventTopic.DOWNLOAD_AND_INSTALL);
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.MULTI_ACTION);
|
|
||||||
assertLatestMultiActionMessage(controllerId, Collections.singletonList(action1Install));
|
|
||||||
|
|
||||||
final Long actionId2 = assignNewDsToTarget(controllerId, 111);
|
|
||||||
final SimpleEntry<Long, EventTopic> action2Install = new SimpleEntry<>(actionId2, EventTopic.DOWNLOAD_AND_INSTALL);
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.MULTI_ACTION);
|
|
||||||
assertLatestMultiActionMessage(controllerId, Arrays.asList(action1Install, action2Install));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify payload of multi action messages.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void assertMultiActionMessagePayloads() {
|
|
||||||
final int expectedWeightIfNotSet = 1000;
|
|
||||||
final int weight1 = 600;
|
|
||||||
final String controllerId = UUID.randomUUID().toString();
|
|
||||||
registerAndAssertTargetWithExistingTenant(controllerId);
|
|
||||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
|
||||||
testdataFactory.addSoftwareModuleMetadata(ds);
|
|
||||||
|
|
||||||
final Long installActionId = makeAssignment(DeploymentRequest.builder(controllerId, ds.getId())
|
|
||||||
.actionType(ActionType.FORCED).build()).getAssignedEntity().get(0).getId();
|
|
||||||
enableMultiAssignments();
|
|
||||||
final Long downloadActionId = makeAssignment(DeploymentRequest.builder(controllerId, ds.getId())
|
|
||||||
.actionType(ActionType.DOWNLOAD_ONLY).weight(weight1).build()).getAssignedEntity().get(0).getId();
|
|
||||||
final Long cancelActionId = makeAssignment(
|
|
||||||
DeploymentRequest.builder(controllerId, ds.getId()).weight(DEFAULT_TEST_WEIGHT).build())
|
|
||||||
.getAssignedEntity().get(0).getId();
|
|
||||||
// make sure the latest message in the queue is the one triggered by the
|
|
||||||
// cancellation
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.DOWNLOAD_AND_INSTALL, EventTopic.MULTI_ACTION,
|
|
||||||
EventTopic.MULTI_ACTION);
|
|
||||||
deploymentManagement.cancelAction(cancelActionId);
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.MULTI_ACTION);
|
|
||||||
|
|
||||||
final List<DmfMultiActionElement> multiActionMessages = getLatestMultiActionMessages(controllerId);
|
|
||||||
assertThat(multiActionMessages).hasSize(3);
|
|
||||||
final DmfMultiActionElement installMessage = multiActionMessages.stream()
|
|
||||||
.filter(message -> message.getTopic().equals(EventTopic.DOWNLOAD_AND_INSTALL)).findFirst().get();
|
|
||||||
final DmfMultiActionElement downloadMessage = multiActionMessages.stream()
|
|
||||||
.filter(message -> message.getTopic().equals(EventTopic.DOWNLOAD)).findFirst().get();
|
|
||||||
final DmfMultiActionElement cancelMessage = multiActionMessages.stream()
|
|
||||||
.filter(message -> message.getTopic().equals(EventTopic.CANCEL_DOWNLOAD)).findFirst().get();
|
|
||||||
assertThat(installMessage.getWeight()).isEqualTo(expectedWeightIfNotSet);
|
|
||||||
assertThat(downloadMessage.getWeight()).isEqualTo(weight1);
|
|
||||||
assertThat(cancelMessage.getWeight()).isEqualTo(DEFAULT_TEST_WEIGHT);
|
|
||||||
|
|
||||||
assertThat(installMessage.getAction()).isExactlyInstanceOf(DmfDownloadAndUpdateRequest.class)
|
|
||||||
.hasFieldOrPropertyWithValue("actionId", installActionId);
|
|
||||||
assertThat(downloadMessage.getAction()).isExactlyInstanceOf(DmfDownloadAndUpdateRequest.class)
|
|
||||||
.hasFieldOrPropertyWithValue("actionId", downloadActionId);
|
|
||||||
assertThat(cancelMessage.getAction()).isExactlyInstanceOf(DmfActionRequest.class)
|
|
||||||
.hasFieldOrPropertyWithValue("actionId", cancelActionId);
|
|
||||||
assertDmfDownloadAndUpdateRequest((DmfDownloadAndUpdateRequest) installMessage.getAction(), ds.getModules(),
|
|
||||||
controllerId);
|
|
||||||
assertDmfDownloadAndUpdateRequest((DmfDownloadAndUpdateRequest) downloadMessage.getAction(), ds.getModules(),
|
|
||||||
controllerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle cancelation process of an action in multi assignment mode.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
@ExpectEvents({
|
|
||||||
@Expect(type = TargetCreatedEvent.class, count = 1),
|
|
||||||
@Expect(type = TargetUpdatedEvent.class, count = 2),
|
|
||||||
@Expect(type = TargetPollEvent.class, count = 1),
|
|
||||||
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1),
|
|
||||||
@Expect(type = MultiActionCancelEvent.class, count = 1),
|
|
||||||
@Expect(type = MultiActionAssignEvent.class, count = 2),
|
|
||||||
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0),
|
|
||||||
@Expect(type = CancelTargetAssignmentEvent.class, count = 0),
|
|
||||||
@Expect(type = ActionCreatedEvent.class, count = 2),
|
|
||||||
@Expect(type = ActionUpdatedEvent.class, count = 2),
|
|
||||||
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
|
|
||||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6),
|
|
||||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 2), // implicit lock
|
|
||||||
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6) // implicit lock
|
|
||||||
})
|
|
||||||
void cancelActionInMultiAssignMode() {
|
|
||||||
enableMultiAssignments();
|
|
||||||
final String controllerId = TARGET_PREFIX + "cancelActionInMultiAssignMode";
|
|
||||||
registerAndAssertTargetWithExistingTenant(controllerId);
|
|
||||||
|
|
||||||
final long actionId1 = assignNewDsToTarget(controllerId, 675);
|
|
||||||
final long actionId2 = assignNewDsToTarget(controllerId, 343);
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.MULTI_ACTION, EventTopic.MULTI_ACTION);
|
|
||||||
deploymentManagement.cancelAction(actionId1);
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.MULTI_ACTION);
|
|
||||||
|
|
||||||
final SimpleEntry<Long, EventTopic> action1Cancel = new SimpleEntry<>(actionId1, EventTopic.CANCEL_DOWNLOAD);
|
|
||||||
final SimpleEntry<Long, EventTopic> action2Install = new SimpleEntry<>(actionId2, EventTopic.DOWNLOAD_AND_INSTALL);
|
|
||||||
|
|
||||||
assertLatestMultiActionMessage(controllerId, Arrays.asList(action1Cancel, action2Install));
|
|
||||||
updateActionViaDmfClient(controllerId, actionId1, DmfActionStatus.CANCELED);
|
|
||||||
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.MULTI_ACTION);
|
|
||||||
assertLatestMultiActionMessage(controllerId, Collections.singletonList(action2Install));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle finishing an action in multi assignment mode.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
@ExpectEvents({
|
|
||||||
@Expect(type = TargetCreatedEvent.class, count = 1),
|
|
||||||
@Expect(type = MultiActionAssignEvent.class, count = 2),
|
|
||||||
@Expect(type = TargetAttributesRequestedEvent.class, count = 1),
|
|
||||||
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0),
|
|
||||||
@Expect(type = CancelTargetAssignmentEvent.class, count = 0),
|
|
||||||
@Expect(type = ActionCreatedEvent.class, count = 2),
|
|
||||||
@Expect(type = ActionUpdatedEvent.class, count = 1),
|
|
||||||
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
|
|
||||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6),
|
|
||||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 2), // implicit lock
|
|
||||||
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6), // implicit lock
|
|
||||||
@Expect(type = TargetUpdatedEvent.class, count = 3),
|
|
||||||
@Expect(type = TargetPollEvent.class, count = 1),
|
|
||||||
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
|
|
||||||
void finishActionInMultiAssignMode() {
|
|
||||||
enableMultiAssignments();
|
|
||||||
final String controllerId = TARGET_PREFIX + "finishActionInMultiAssignMode";
|
|
||||||
registerAndAssertTargetWithExistingTenant(controllerId);
|
|
||||||
|
|
||||||
final long actionId1 = assignNewDsToTarget(controllerId, 66);
|
|
||||||
final long actionId2 = assignNewDsToTarget(controllerId, 767);
|
|
||||||
final SimpleEntry<Long, EventTopic> action2Install = new SimpleEntry<>(actionId2, EventTopic.DOWNLOAD_AND_INSTALL);
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.MULTI_ACTION, EventTopic.MULTI_ACTION);
|
|
||||||
|
|
||||||
updateActionViaDmfClient(controllerId, actionId1, DmfActionStatus.FINISHED);
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.REQUEST_ATTRIBUTES_UPDATE, EventTopic.MULTI_ACTION);
|
|
||||||
assertRequestAttributesUpdateMessage(controllerId);
|
|
||||||
assertLatestMultiActionMessage(controllerId, Collections.singletonList(action2Install));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If multi assignment is enabled assigning a DS multiple times creates a new action every time.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
@ExpectEvents({
|
|
||||||
@Expect(type = TargetCreatedEvent.class, count = 1),
|
|
||||||
@Expect(type = MultiActionAssignEvent.class, count = 2),
|
|
||||||
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0),
|
|
||||||
@Expect(type = CancelTargetAssignmentEvent.class, count = 0),
|
|
||||||
@Expect(type = ActionCreatedEvent.class, count = 2),
|
|
||||||
@Expect(type = ActionUpdatedEvent.class, count = 0),
|
|
||||||
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
|
|
||||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
|
|
||||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
|
|
||||||
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 3), // implicit lock
|
|
||||||
@Expect(type = TargetUpdatedEvent.class, count = 2),
|
|
||||||
@Expect(type = TargetPollEvent.class, count = 1),
|
|
||||||
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
|
|
||||||
void assignDsMultipleTimesInMultiAssignMode() {
|
|
||||||
enableMultiAssignments();
|
|
||||||
final String controllerId = TARGET_PREFIX + "assignDsMultipleTimesInMultiAssignMode";
|
|
||||||
registerAndAssertTargetWithExistingTenant(controllerId);
|
|
||||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
|
||||||
|
|
||||||
final Long actionId1 = getFirstAssignedAction(assignDistributionSet(dsId, controllerId, 344)).getId();
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.MULTI_ACTION);
|
|
||||||
final Long actionId2 = getFirstAssignedAction(assignDistributionSet(dsId, controllerId, 775)).getId();
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.MULTI_ACTION);
|
|
||||||
|
|
||||||
final SimpleEntry<Long, EventTopic> action1Install = new SimpleEntry<>(actionId1, EventTopic.DOWNLOAD_AND_INSTALL);
|
|
||||||
final SimpleEntry<Long, EventTopic> action2Install = new SimpleEntry<>(actionId2, EventTopic.DOWNLOAD_AND_INSTALL);
|
|
||||||
assertLatestMultiActionMessage(controllerId, Arrays.asList(action1Install, action2Install));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If multi assignment is enabled multiple rollouts with the same DS lead to multiple actions.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
@ExpectEvents({
|
|
||||||
@Expect(type = TargetCreatedEvent.class, count = 1),
|
|
||||||
@Expect(type = MultiActionAssignEvent.class, count = 2),
|
|
||||||
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0),
|
|
||||||
@Expect(type = CancelTargetAssignmentEvent.class, count = 0),
|
|
||||||
@Expect(type = ActionCreatedEvent.class, count = 2),
|
|
||||||
@Expect(type = ActionUpdatedEvent.class, count = 2),
|
|
||||||
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
|
|
||||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
|
|
||||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
|
|
||||||
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 3), // implicit lock
|
|
||||||
@Expect(type = TargetUpdatedEvent.class, count = 1),
|
|
||||||
@Expect(type = TargetPollEvent.class, count = 1),
|
|
||||||
@Expect(type = RolloutCreatedEvent.class, count = 2),
|
|
||||||
@Expect(type = RolloutUpdatedEvent.class, count = 6),
|
|
||||||
@Expect(type = RolloutGroupCreatedEvent.class, count = 2),
|
|
||||||
@Expect(type = RolloutGroupUpdatedEvent.class, count = 6),
|
|
||||||
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
|
|
||||||
void startRolloutsWithSameDsInMultiAssignMode() {
|
|
||||||
enableMultiAssignments();
|
|
||||||
final String controllerId = TARGET_PREFIX + "startRolloutsWithSameDsInMultiAssignMode";
|
|
||||||
|
|
||||||
registerAndAssertTargetWithExistingTenant(controllerId);
|
|
||||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
|
||||||
final Set<Long> smIds = getSoftwareModuleIds(ds);
|
|
||||||
final String filterQuery = "controllerId==" + controllerId;
|
|
||||||
|
|
||||||
createAndStartRollout(ds, filterQuery, 122);
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.MULTI_ACTION);
|
|
||||||
assertLatestMultiActionMessageContainsInstallMessages(controllerId, Collections.singletonList(smIds));
|
|
||||||
|
|
||||||
createAndStartRollout(ds, filterQuery, 43);
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.MULTI_ACTION);
|
|
||||||
assertLatestMultiActionMessageContainsInstallMessages(controllerId, Arrays.asList(smIds, smIds));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If multi assignment is enabled finishing one rollout does not affect other rollouts of the target.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
@ExpectEvents({
|
|
||||||
@Expect(type = TargetCreatedEvent.class, count = 1),
|
|
||||||
@Expect(type = MultiActionAssignEvent.class, count = 3),
|
|
||||||
@Expect(type = ActionCreatedEvent.class, count = 3),
|
|
||||||
@Expect(type = ActionUpdatedEvent.class, count = 5),
|
|
||||||
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
|
|
||||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6),
|
|
||||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 2), // implicit lock
|
|
||||||
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6), // implicit lock
|
|
||||||
@Expect(type = TargetUpdatedEvent.class, count = 5),
|
|
||||||
@Expect(type = TargetPollEvent.class, count = 1),
|
|
||||||
@Expect(type = TargetAttributesRequestedEvent.class, count = 2),
|
|
||||||
@Expect(type = RolloutCreatedEvent.class, count = 3),
|
|
||||||
@Expect(type = RolloutUpdatedEvent.class, count = 9),
|
|
||||||
@Expect(type = RolloutGroupCreatedEvent.class, count = 3),
|
|
||||||
@Expect(type = RolloutGroupUpdatedEvent.class, count = 9),
|
|
||||||
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
|
|
||||||
void startMultipleRolloutsAndFinishInMultiAssignMode() {
|
|
||||||
enableMultiAssignments();
|
|
||||||
final String controllerId = TARGET_PREFIX + "startMultipleRolloutsAndFinishInMultiAssignMode";
|
|
||||||
|
|
||||||
registerAndAssertTargetWithExistingTenant(controllerId);
|
|
||||||
final String filterQuery = "controllerId==" + controllerId;
|
|
||||||
final DistributionSet ds1 = testdataFactory.createDistributionSet();
|
|
||||||
final Set<Long> smIds1 = getSoftwareModuleIds(ds1);
|
|
||||||
final DistributionSet ds2 = testdataFactory.createDistributionSet();
|
|
||||||
final Set<Long> smIds2 = getSoftwareModuleIds(ds2);
|
|
||||||
|
|
||||||
createAndStartRollout(ds1, filterQuery, 12);
|
|
||||||
createAndStartRollout(ds2, filterQuery, 45);
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.MULTI_ACTION, EventTopic.MULTI_ACTION);
|
|
||||||
createAndStartRollout(ds1, filterQuery, 65);
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.MULTI_ACTION);
|
|
||||||
assertLatestMultiActionMessageContainsInstallMessages(controllerId, Arrays.asList(smIds1, smIds2, smIds1));
|
|
||||||
|
|
||||||
final List<Long> installActions = getLatestMultiActionMessageActions(controllerId).stream()
|
|
||||||
.filter(entry -> entry.getValue().equals(EventTopic.DOWNLOAD_AND_INSTALL))
|
|
||||||
.map(Entry::getKey)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
updateActionViaDmfClient(controllerId, installActions.get(0), DmfActionStatus.FINISHED);
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.REQUEST_ATTRIBUTES_UPDATE, EventTopic.MULTI_ACTION);
|
|
||||||
assertLatestMultiActionMessageContainsInstallMessages(controllerId, Arrays.asList(smIds2, smIds1));
|
|
||||||
|
|
||||||
updateActionViaDmfClient(controllerId, installActions.get(1), DmfActionStatus.FINISHED);
|
|
||||||
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.REQUEST_ATTRIBUTES_UPDATE, EventTopic.MULTI_ACTION);
|
|
||||||
assertLatestMultiActionMessageContainsInstallMessages(controllerId, Collections.singletonList(smIds1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that a cancel assignment send a cancel message.
|
* Verify that a cancel assignment send a cancel message.
|
||||||
*/
|
*/
|
||||||
@@ -649,21 +341,6 @@ class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpServiceInt
|
|||||||
assertThat(replyToListener.getLatestEventMessage(eventTopic)).isNull();
|
assertThat(replyToListener.getLatestEventMessage(eventTopic)).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify that batch and multi-assignments can't be activated at the same time.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void assertBatchAndMultiAssignmentsNotCompatible() {
|
|
||||||
enableBatchAssignments();
|
|
||||||
assertThatExceptionOfType(TenantConfigurationValueChangeNotAllowedException.class)
|
|
||||||
.isThrownBy(() -> enableMultiAssignments());
|
|
||||||
disableBatchAssignments();
|
|
||||||
|
|
||||||
enableMultiAssignments();
|
|
||||||
assertThatExceptionOfType(TenantConfigurationValueChangeNotAllowedException.class)
|
|
||||||
.isThrownBy(() -> enableBatchAssignments());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify payload of batch assignments.
|
* Verify payload of batch assignments.
|
||||||
*/
|
*/
|
||||||
@@ -734,27 +411,6 @@ class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpServiceInt
|
|||||||
assertEventMessageNotPresent(EventTopic.DOWNLOAD_AND_INSTALL);
|
assertEventMessageNotPresent(EventTopic.DOWNLOAD_AND_INSTALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<Long> getSmIds(final DmfDownloadAndUpdateRequest request) {
|
|
||||||
return request.getSoftwareModules().stream().map(DmfSoftwareModule::getModuleId).collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<DmfDownloadAndUpdateRequest> getDownloadAndUpdateRequests(final DmfMultiActionRequest request) {
|
|
||||||
return request.getElements().stream()
|
|
||||||
.filter(AmqpMessageDispatcherServiceIntegrationTest::isDownloadAndUpdateRequest)
|
|
||||||
.map(multiAction -> (DmfDownloadAndUpdateRequest) multiAction.getAction()).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isDownloadAndUpdateRequest(final DmfMultiActionElement multiActionElement) {
|
|
||||||
return multiActionElement.getTopic().equals(EventTopic.DOWNLOAD)
|
|
||||||
|| multiActionElement.getTopic().equals(EventTopic.DOWNLOAD_AND_INSTALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<DmfMultiActionElement> getLatestMultiActionMessages(final String expectedControllerId) {
|
|
||||||
final Message multiactionMessage = replyToListener.getLatestEventMessage(EventTopic.MULTI_ACTION);
|
|
||||||
assertThat(multiactionMessage.getMessageProperties().getHeaders()).containsEntry(MessageHeaderKey.THING_ID, expectedControllerId);
|
|
||||||
return ((DmfMultiActionRequest) getDmfClient().getMessageConverter().fromMessage(multiactionMessage)).getElements();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateActionViaDmfClient(final String controllerId, final long actionId,
|
private void updateActionViaDmfClient(final String controllerId, final long actionId,
|
||||||
final DmfActionStatus status) {
|
final DmfActionStatus status) {
|
||||||
createAndSendActionStatusUpdateMessage(controllerId, actionId, status);
|
createAndSendActionStatusUpdateMessage(controllerId, actionId, status);
|
||||||
@@ -773,18 +429,6 @@ class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpServiceInt
|
|||||||
return actionId;
|
return actionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<Long> getSoftwareModuleIds(final DistributionSet ds) {
|
|
||||||
return ds.getModules().stream().map(SoftwareModule::getId).collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Rollout createAndStartRollout(final DistributionSet ds, final String filterQuery, final Integer weight) {
|
|
||||||
final Rollout rollout = testdataFactory.createRolloutByVariables(UUID.randomUUID().toString(), "", 1,
|
|
||||||
filterQuery, ds, "50", "5", ActionType.FORCED, weight, false);
|
|
||||||
rolloutManagement.start(rollout.getId());
|
|
||||||
rolloutHandler.handleAll();
|
|
||||||
return rollout;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void waitUntilTargetHasStatus(final String controllerId, final TargetUpdateStatus status) {
|
private void waitUntilTargetHasStatus(final String controllerId, final TargetUpdateStatus status) {
|
||||||
waitUntil(() -> {
|
waitUntil(() -> {
|
||||||
final Optional<Target> findTargetByControllerID = targetManagement.findByControllerId(controllerId);
|
final Optional<Target> findTargetByControllerID = targetManagement.findByControllerId(controllerId);
|
||||||
@@ -795,29 +439,4 @@ class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpServiceInt
|
|||||||
private void waitUntil(final Callable<Boolean> callable) {
|
private void waitUntil(final Callable<Boolean> callable) {
|
||||||
await().until(() -> SecurityContextSwitch.asPrivileged(callable));
|
await().until(() -> SecurityContextSwitch.asPrivileged(callable));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertLatestMultiActionMessageContainsInstallMessages(final String controllerId,
|
|
||||||
final List<Set<Long>> smIdsOfActionsExpected) {
|
|
||||||
final Message multiactionMessage = replyToListener.getLatestEventMessage(EventTopic.MULTI_ACTION);
|
|
||||||
assertThat(multiactionMessage.getMessageProperties().getHeaders()).containsEntry(MessageHeaderKey.THING_ID, controllerId);
|
|
||||||
final DmfMultiActionRequest multiActionRequest =
|
|
||||||
(DmfMultiActionRequest) getDmfClient().getMessageConverter().fromMessage(multiactionMessage);
|
|
||||||
|
|
||||||
final List<Set<Long>> smIdsOfActionsFound = getDownloadAndUpdateRequests(multiActionRequest).stream()
|
|
||||||
.map(AmqpMessageDispatcherServiceIntegrationTest::getSmIds).toList();
|
|
||||||
assertThat(smIdsOfActionsFound).containsExactlyInAnyOrderElementsOf(smIdsOfActionsExpected);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertLatestMultiActionMessage(final String controllerId,
|
|
||||||
final List<SimpleEntry<Long, EventTopic>> actionsExpected) {
|
|
||||||
final List<SimpleEntry<Long, EventTopic>> actionsFromMessage = getLatestMultiActionMessageActions(controllerId);
|
|
||||||
assertThat(actionsFromMessage).containsExactlyInAnyOrderElementsOf(actionsExpected);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<SimpleEntry<Long, EventTopic>> getLatestMultiActionMessageActions(final String expectedControllerId) {
|
|
||||||
final List<DmfMultiActionElement> multiActionRequest = getLatestMultiActionMessages(expectedControllerId);
|
|
||||||
return multiActionRequest.stream()
|
|
||||||
.map(request -> new SimpleEntry<>(request.getAction().getActionId(), request.getTopic()))
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1484,52 +1484,30 @@ class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegrationTe
|
|||||||
.andExpect(jsonPath("total", equalTo(1)));
|
.andExpect(jsonPath("total", equalTo(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Assigning targets multiple times to a DS in one request works in multi-assignment mode.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void multiAssignment() throws Exception {
|
|
||||||
final List<String> targetIds = testdataFactory.createTargets(2).stream().map(Target::getControllerId).toList();
|
|
||||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
|
||||||
|
|
||||||
final JSONArray body = new JSONArray();
|
|
||||||
body.put(getAssignmentObject(targetIds.get(0), MgmtActionType.FORCED, 56));
|
|
||||||
body.put(getAssignmentObject(targetIds.get(0), MgmtActionType.FORCED, 78));
|
|
||||||
body.put(getAssignmentObject(targetIds.get(1), MgmtActionType.FORCED, 67));
|
|
||||||
body.put(getAssignmentObject(targetIds.get(1), MgmtActionType.SOFT, 34));
|
|
||||||
|
|
||||||
enableMultiAssignments();
|
|
||||||
mvc.perform(post("/rest/v1/distributionsets/{ds}/assignedTargets", dsId).content(body.toString())
|
|
||||||
.contentType(APPLICATION_JSON))
|
|
||||||
.andDo(MockMvcResultPrinter.print())
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("total", equalTo(body.length())));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An assignment request containing a weight is only accepted when weight is valide and multi assignment is on.
|
* An assignment request containing a weight is only accepted when weight is valide and multi assignment is on.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void weightValidation() throws Exception {
|
void weightValidation() throws Exception {
|
||||||
final String targetId = testdataFactory.createTarget().getControllerId();
|
final String targetId = testdataFactory.createTarget().getControllerId();
|
||||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
final Long dsId1 = testdataFactory.createDistributionSet().getId();
|
||||||
|
final Long dsId2 = testdataFactory.createDistributionSet().getId();
|
||||||
final int weight = 78;
|
final int weight = 78;
|
||||||
|
|
||||||
final JSONArray bodyValide = new JSONArray().put(getAssignmentObject(targetId, MgmtActionType.FORCED, weight));
|
final JSONArray bodyValide = new JSONArray().put(getAssignmentObject(targetId, MgmtActionType.FORCED, weight));
|
||||||
final JSONArray bodyInvalide = new JSONArray()
|
final JSONArray bodyInvalide = new JSONArray()
|
||||||
.put(getAssignmentObject(targetId, MgmtActionType.FORCED, Action.WEIGHT_MIN - 1));
|
.put(getAssignmentObject(targetId, MgmtActionType.FORCED, Action.WEIGHT_MIN - 1));
|
||||||
|
|
||||||
mvc.perform(post("/rest/v1/distributionsets/{ds}/assignedTargets", dsId).content(bodyValide.toString())
|
mvc.perform(post("/rest/v1/distributionsets/{ds}/assignedTargets", dsId1).content(bodyValide.toString())
|
||||||
.contentType(APPLICATION_JSON))
|
.contentType(APPLICATION_JSON))
|
||||||
.andDo(MockMvcResultPrinter.print())
|
.andDo(MockMvcResultPrinter.print())
|
||||||
.andExpect(status().isOk());
|
.andExpect(status().isOk());
|
||||||
enableMultiAssignments();
|
mvc.perform(post("/rest/v1/distributionsets/{ds}/assignedTargets", dsId2).content(bodyInvalide.toString())
|
||||||
mvc.perform(post("/rest/v1/distributionsets/{ds}/assignedTargets", dsId).content(bodyInvalide.toString())
|
|
||||||
.contentType(APPLICATION_JSON))
|
.contentType(APPLICATION_JSON))
|
||||||
.andDo(MockMvcResultPrinter.print())
|
.andDo(MockMvcResultPrinter.print())
|
||||||
.andExpect(status().isBadRequest())
|
.andExpect(status().isBadRequest())
|
||||||
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.repo.constraintViolation")));
|
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.repo.constraintViolation")));
|
||||||
mvc.perform(post("/rest/v1/distributionsets/{ds}/assignedTargets", dsId).content(bodyValide.toString())
|
mvc.perform(post("/rest/v1/distributionsets/{ds}/assignedTargets", dsId2).content(bodyValide.toString())
|
||||||
.contentType(APPLICATION_JSON))
|
.contentType(APPLICATION_JSON))
|
||||||
.andDo(MockMvcResultPrinter.print())
|
.andDo(MockMvcResultPrinter.print())
|
||||||
.andExpect(status().isOk());
|
.andExpect(status().isOk());
|
||||||
|
|||||||
@@ -105,7 +105,6 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void getRollout() throws Exception {
|
void getRollout() throws Exception {
|
||||||
enableMultiAssignments();
|
|
||||||
approvalStrategy.setApprovalNeeded(true);
|
approvalStrategy.setApprovalNeeded(true);
|
||||||
try {
|
try {
|
||||||
approvalStrategy.setApprovalDecidedBy("exampleUsername");
|
approvalStrategy.setApprovalDecidedBy("exampleUsername");
|
||||||
@@ -1678,26 +1677,20 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
|
|||||||
null, null);
|
null, null);
|
||||||
final String valideWeightRequest = JsonBuilder.rollout("withWeight", "d", 2, dsId, "id==rollout*",
|
final String valideWeightRequest = JsonBuilder.rollout("withWeight", "d", 2, dsId, "id==rollout*",
|
||||||
new RolloutGroupConditionBuilder().withDefaults().build(), null, null, weight, null, null, null);
|
new RolloutGroupConditionBuilder().withDefaults().build(), null, null, weight, null, null, null);
|
||||||
final String valideWeightRequestMultiAssignment = JsonBuilder.rollout("withWeightMultiAssignment", "d", 2, dsId, "id==rollout*",
|
|
||||||
new RolloutGroupConditionBuilder().withDefaults().build(), null, null, weight, null, null, null);
|
|
||||||
|
|
||||||
mvc.perform(post("/rest/v1/rollouts").content(valideWeightRequest).contentType(MediaType.APPLICATION_JSON)
|
mvc.perform(post("/rest/v1/rollouts").content(valideWeightRequest).contentType(MediaType.APPLICATION_JSON)
|
||||||
.accept(MediaType.APPLICATION_JSON))
|
.accept(MediaType.APPLICATION_JSON))
|
||||||
.andDo(MockMvcResultPrinter.print())
|
.andDo(MockMvcResultPrinter.print())
|
||||||
.andExpect(status().isCreated());
|
.andExpect(status().isCreated());
|
||||||
enableMultiAssignments();
|
|
||||||
mvc.perform(post("/rest/v1/rollouts").content(invalideWeightRequest).contentType(MediaType.APPLICATION_JSON)
|
mvc.perform(post("/rest/v1/rollouts").content(invalideWeightRequest).contentType(MediaType.APPLICATION_JSON)
|
||||||
.accept(MediaType.APPLICATION_JSON))
|
.accept(MediaType.APPLICATION_JSON))
|
||||||
.andDo(MockMvcResultPrinter.print())
|
.andDo(MockMvcResultPrinter.print())
|
||||||
.andExpect(status().isBadRequest())
|
.andExpect(status().isBadRequest())
|
||||||
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.repo.constraintViolation")));
|
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.repo.constraintViolation")));
|
||||||
mvc.perform(post("/rest/v1/rollouts").content(valideWeightRequestMultiAssignment).contentType(MediaType.APPLICATION_JSON)
|
|
||||||
.accept(MediaType.APPLICATION_JSON))
|
|
||||||
.andDo(MockMvcResultPrinter.print())
|
|
||||||
.andExpect(status().isCreated());
|
|
||||||
|
|
||||||
final List<Rollout> rollouts = rolloutManagement.findAll(false, PAGE).getContent();
|
final List<Rollout> rollouts = rolloutManagement.findAll(false, PAGE).getContent();
|
||||||
assertThat(rollouts).hasSize(2);
|
assertThat(rollouts).hasSize(1);
|
||||||
assertThat(rollouts.get(0).getWeight()).get().isEqualTo(weight);
|
assertThat(rollouts.get(0).getWeight()).get().isEqualTo(weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -560,7 +560,6 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void createAutoAssignDS() throws Exception {
|
void createAutoAssignDS() throws Exception {
|
||||||
enableMultiAssignments();
|
|
||||||
enableConfirmationFlow();
|
enableConfirmationFlow();
|
||||||
|
|
||||||
final String filterName = "filter_01";
|
final String filterName = "filter_01";
|
||||||
@@ -643,7 +642,7 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
|
|||||||
filterId).content(valideWeightRequest).contentType(MediaType.APPLICATION_JSON))
|
filterId).content(valideWeightRequest).contentType(MediaType.APPLICATION_JSON))
|
||||||
.andDo(print())
|
.andDo(print())
|
||||||
.andExpect(status().isOk());
|
.andExpect(status().isOk());
|
||||||
enableMultiAssignments();
|
|
||||||
mvc.perform(post(MgmtTargetFilterQueryRestApi.TARGETFILTERS_V1 + "/{targetFilterQueryId}/autoAssignDS",
|
mvc.perform(post(MgmtTargetFilterQueryRestApi.TARGETFILTERS_V1 + "/{targetFilterQueryId}/autoAssignDS",
|
||||||
filterId).content(invalideWeightRequest).contentType(MediaType.APPLICATION_JSON))
|
filterId).content(invalideWeightRequest).contentType(MediaType.APPLICATION_JSON))
|
||||||
.andDo(print())
|
.andDo(print())
|
||||||
|
|||||||
@@ -2213,24 +2213,6 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
|
|||||||
.andExpect(jsonPath("total", equalTo(1)));
|
.andExpect(jsonPath("total", equalTo(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Assign multiple DSs to a target in one request with multiassignments enabled.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void multiAssignment() throws Exception {
|
|
||||||
final String targetId = testdataFactory.createTarget().getControllerId();
|
|
||||||
final List<Long> dsIds = testdataFactory.createDistributionSets(2).stream().map(DistributionSet::getId).toList();
|
|
||||||
|
|
||||||
final JSONArray body = new JSONArray();
|
|
||||||
dsIds.forEach(id -> body.put(getAssignmentObject(id, MgmtActionType.FORCED, 76)));
|
|
||||||
|
|
||||||
enableMultiAssignments();
|
|
||||||
mvc.perform(post("/rest/v1/targets/{targetId}/assignedDS", targetId).content(body.toString()).contentType(APPLICATION_JSON))
|
|
||||||
.andDo(MockMvcResultPrinter.print())
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("total", equalTo(2)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An assignment request containing a weight is only accepted when weight is valid and multi assignment is on.
|
* An assignment request containing a weight is only accepted when weight is valid and multi assignment is on.
|
||||||
*/
|
*/
|
||||||
@@ -2243,7 +2225,6 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
|
|||||||
final JSONObject bodyValid = getAssignmentObject(dsId, MgmtActionType.FORCED, weight);
|
final JSONObject bodyValid = getAssignmentObject(dsId, MgmtActionType.FORCED, weight);
|
||||||
final JSONObject bodyInvalid = getAssignmentObject(dsId, MgmtActionType.FORCED, Action.WEIGHT_MIN - 1);
|
final JSONObject bodyInvalid = getAssignmentObject(dsId, MgmtActionType.FORCED, Action.WEIGHT_MIN - 1);
|
||||||
|
|
||||||
enableMultiAssignments();
|
|
||||||
mvc.perform(post("/rest/v1/targets/{targetId}/assignedDS", targetId).content(bodyInvalid.toString()).contentType(APPLICATION_JSON))
|
mvc.perform(post("/rest/v1/targets/{targetId}/assignedDS", targetId).content(bodyInvalid.toString()).contentType(APPLICATION_JSON))
|
||||||
.andDo(MockMvcResultPrinter.print())
|
.andDo(MockMvcResultPrinter.print())
|
||||||
.andExpect(status().isBadRequest())
|
.andExpect(status().isBadRequest())
|
||||||
@@ -2272,48 +2253,24 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
|
|||||||
.andExpect(status().isOk());
|
.andExpect(status().isOk());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* An assignment request containing a valid weight when multi assignment is on.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void weightWithMultiAssignment() throws Exception {
|
|
||||||
final String targetId = testdataFactory.createTarget().getControllerId();
|
|
||||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
|
||||||
final int weight = 98;
|
|
||||||
|
|
||||||
final JSONObject bodyValid = getAssignmentObject(dsId, MgmtActionType.FORCED, weight);
|
|
||||||
|
|
||||||
enableMultiAssignments();
|
|
||||||
mvc.perform(post("/rest/v1/targets/{targetId}/assignedDS", targetId).content(bodyValid.toString()).contentType(APPLICATION_JSON))
|
|
||||||
.andDo(MockMvcResultPrinter.print())
|
|
||||||
.andExpect(status().isOk());
|
|
||||||
|
|
||||||
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).get().toList();
|
|
||||||
assertThat(actions).size().isEqualTo(1);
|
|
||||||
assertThat(actions.get(0).getWeight()).get().isEqualTo(weight);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get weight of action
|
* Get weight of action
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void getActionWeight() throws Exception {
|
void getActionWeight() throws Exception {
|
||||||
final String targetId = testdataFactory.createTarget().getControllerId();
|
final String targetId = testdataFactory.createTarget().getControllerId();
|
||||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
final Long dsId1 = testdataFactory.createDistributionSet().getId();
|
||||||
final int customWeightHigh = 800;
|
final Long dsId2 = testdataFactory.createDistributionSet().getId();
|
||||||
final int customWeightLow = 300;
|
final int customWeight = 800;
|
||||||
assignDistributionSet(dsId, targetId); // default weight 1000
|
assignDistributionSet(dsId1, targetId); // default weight 1000
|
||||||
enableMultiAssignments();
|
assignDistributionSet(dsId2, targetId, customWeight);
|
||||||
assignDistributionSet(dsId, targetId, customWeightHigh);
|
|
||||||
assignDistributionSet(dsId, targetId, customWeightLow);
|
|
||||||
|
|
||||||
mvc.perform(get("/rest/v1/targets/{targetId}/actions", targetId)
|
mvc.perform(get("/rest/v1/targets/{targetId}/actions", targetId)
|
||||||
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "WEIGHT:ASC"))
|
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "WEIGHT:ASC"))
|
||||||
.andDo(MockMvcResultPrinter.print())
|
.andDo(MockMvcResultPrinter.print())
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("content.[0].weight", equalTo(customWeightLow)))
|
.andExpect(jsonPath("content.[0].weight", equalTo(customWeight)))
|
||||||
.andExpect(jsonPath("content.[1].weight", equalTo(customWeightHigh)))
|
.andExpect(jsonPath("content.[1].weight", equalTo(1000)));
|
||||||
.andExpect(jsonPath("content.[2].weight", equalTo(1000)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.get
|
|||||||
import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.withUser;
|
import static org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch.withUser;
|
||||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_ENABLED;
|
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_ENABLED;
|
||||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY;
|
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY;
|
||||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED;
|
|
||||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED;
|
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED;
|
||||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED;
|
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED;
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
@@ -141,27 +140,6 @@ public class MgmtTenantManagementResourceTest extends AbstractManagementApiInteg
|
|||||||
assertDefaultDsTypeUpdateBadRequestFails(newDefaultDsType, oldDefaultDsType, status().isNotFound());
|
assertDefaultDsTypeUpdateBadRequestFails(newDefaultDsType, oldDefaultDsType, status().isNotFound());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The 'multi.assignments.enabled' property must not be changed to false.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void deactivateMultiAssignment() throws Exception {
|
|
||||||
final String bodyActivate = new JSONObject().put("value", true).toString();
|
|
||||||
final String bodyDeactivate = new JSONObject().put("value", false).toString();
|
|
||||||
|
|
||||||
mvc.perform(put(SYSTEM_V1 + "/configs/{keyName}", MULTI_ASSIGNMENTS_ENABLED)
|
|
||||||
.content(bodyActivate)
|
|
||||||
.contentType(MediaType.APPLICATION_JSON))
|
|
||||||
.andDo(MockMvcResultPrinter.print())
|
|
||||||
.andExpect(status().isNoContent());
|
|
||||||
|
|
||||||
mvc.perform(put(SYSTEM_V1 + "/configs/{keyName}", MULTI_ASSIGNMENTS_ENABLED)
|
|
||||||
.content(bodyDeactivate)
|
|
||||||
.contentType(MediaType.APPLICATION_JSON))
|
|
||||||
.andDo(MockMvcResultPrinter.print())
|
|
||||||
.andExpect(status().isForbidden());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Batch configuration should not be applied, because of invalid TenantConfiguration props
|
* The Batch configuration should not be applied, because of invalid TenantConfiguration props
|
||||||
*/
|
*/
|
||||||
@@ -249,36 +227,6 @@ public class MgmtTenantManagementResourceTest extends AbstractManagementApiInteg
|
|||||||
"Change BatchConfiguration was successful but TenantConfiguration property was not actually changed.");
|
"Change BatchConfiguration was successful but TenantConfiguration property was not actually changed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The 'repository.actions.autoclose.enabled' property must not be modified if Multi-Assignments is enabled.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void autoCloseCannotBeModifiedIfMultiAssignmentIsEnabled() throws Exception {
|
|
||||||
final String bodyActivate = new JSONObject().put("value", true).toString();
|
|
||||||
final String bodyDeactivate = new JSONObject().put("value", false).toString();
|
|
||||||
|
|
||||||
// enable Multi-Assignments
|
|
||||||
mvc.perform(put(SYSTEM_V1 + "/configs/{keyName}", MULTI_ASSIGNMENTS_ENABLED)
|
|
||||||
.content(bodyActivate)
|
|
||||||
.contentType(MediaType.APPLICATION_JSON))
|
|
||||||
.andDo(MockMvcResultPrinter.print())
|
|
||||||
.andExpect(status().isNoContent());
|
|
||||||
|
|
||||||
// try to enable Auto-Close
|
|
||||||
mvc.perform(put(SYSTEM_V1 + "/configs/{keyName}", REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED)
|
|
||||||
.content(bodyActivate)
|
|
||||||
.contentType(MediaType.APPLICATION_JSON))
|
|
||||||
.andDo(MockMvcResultPrinter.print())
|
|
||||||
.andExpect(status().isForbidden());
|
|
||||||
|
|
||||||
// try to disable Auto-Close
|
|
||||||
mvc.perform(put(SYSTEM_V1 + "/configs/{keyName}", REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED)
|
|
||||||
.content(bodyDeactivate)
|
|
||||||
.contentType(MediaType.APPLICATION_JSON))
|
|
||||||
.andDo(MockMvcResultPrinter.print())
|
|
||||||
.andExpect(status().isForbidden());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles DELETE request deleting a tenant specific configuration.
|
* Handles DELETE request deleting a tenant specific configuration.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException
|
|||||||
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
||||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
import org.eclipse.hawkbit.repository.exception.MultiAssignmentException;
|
||||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
|
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
|
||||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
@@ -76,8 +76,8 @@ public interface DeploymentManagement extends PermissionSupport {
|
|||||||
* @throws EntityNotFoundException if either provided {@link DistributionSet} or {@link Target}s do not exist
|
* @throws EntityNotFoundException if either provided {@link DistributionSet} or {@link Target}s do not exist
|
||||||
* @throws AssignmentQuotaExceededException if the maximum number of targets the distribution set can be
|
* @throws AssignmentQuotaExceededException if the maximum number of targets the distribution set can be
|
||||||
* assigned to at once is exceeded
|
* assigned to at once is exceeded
|
||||||
* @throws MultiAssignmentIsNotEnabledException if the request results in multiple assignments to the same
|
* @throws MultiAssignmentException if the request results in multiple assignments to the same
|
||||||
* target and multi-assignment is disabled
|
* target
|
||||||
*/
|
*/
|
||||||
@PreAuthorize(HAS_UPDATE_TARGET_AND_READ_DISTRIBUTION_SET)
|
@PreAuthorize(HAS_UPDATE_TARGET_AND_READ_DISTRIBUTION_SET)
|
||||||
List<DistributionSetAssignmentResult> assignDistributionSets(
|
List<DistributionSetAssignmentResult> assignDistributionSets(
|
||||||
@@ -102,8 +102,8 @@ public interface DeploymentManagement extends PermissionSupport {
|
|||||||
* defined by the {@link DistributionSetType}.
|
* defined by the {@link DistributionSetType}.
|
||||||
* @throws EntityNotFoundException if either provided {@link DistributionSet} or {@link Target}s do not exist
|
* @throws EntityNotFoundException if either provided {@link DistributionSet} or {@link Target}s do not exist
|
||||||
* @throws AssignmentQuotaExceededException if the maximum number of targets the distribution set can be assigned to at once is exceeded
|
* @throws AssignmentQuotaExceededException if the maximum number of targets the distribution set can be assigned to at once is exceeded
|
||||||
* @throws MultiAssignmentIsNotEnabledException if the request results in multiple assignments to the same
|
* @throws MultiAssignmentException if the request results in multiple assignments to the same
|
||||||
* target and multi-assignment is disabled
|
* target
|
||||||
*/
|
*/
|
||||||
@PreAuthorize(HAS_UPDATE_TARGET_AND_READ_DISTRIBUTION_SET)
|
@PreAuthorize(HAS_UPDATE_TARGET_AND_READ_DISTRIBUTION_SET)
|
||||||
List<DistributionSetAssignmentResult> offlineAssignedDistributionSets(Collection<Entry<String, Long>> assignments);
|
List<DistributionSetAssignmentResult> offlineAssignedDistributionSets(Collection<Entry<String, Long>> assignments);
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made
|
|
||||||
* available under the terms of the Eclipse Public License 2.0
|
|
||||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.eclipse.hawkbit.repository.event.remote;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generic deployment event for the Multi-Assignments feature. The event extends
|
|
||||||
* the {@link MultiActionEvent} and holds a list of controller IDs to identify
|
|
||||||
* the targets which are affected by a deployment action and a list of
|
|
||||||
* actionIds containing the identifiers of the affected actions
|
|
||||||
* as payload. This event is only published in case of an assignment.
|
|
||||||
*/
|
|
||||||
@NoArgsConstructor
|
|
||||||
public class MultiActionAssignEvent extends MultiActionEvent {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
*
|
|
||||||
* @param tenant tenant the event is scoped to
|
|
||||||
* @param actions the actions of the deployment action
|
|
||||||
*/
|
|
||||||
public MultiActionAssignEvent(String tenant, List<Action> actions) {
|
|
||||||
super(tenant, actions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made
|
|
||||||
* available under the terms of the Eclipse Public License 2.0
|
|
||||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.eclipse.hawkbit.repository.event.remote;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generic deployment event for the Multi-Assignments feature. The event extends the {@link MultiActionEvent} and holds a list of controller IDs
|
|
||||||
* to identify the targets which are affected by a deployment action and a list of actionIds containing the identifiers of the affected actions
|
|
||||||
* as payload. This event is only published in case of a cancellation.
|
|
||||||
*/
|
|
||||||
@NoArgsConstructor // for serialization libs like jackson
|
|
||||||
public class MultiActionCancelEvent extends MultiActionEvent {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public MultiActionCancelEvent(String tenant, List<Action> actions) {
|
|
||||||
super(tenant, actions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2019 Bosch Software Innovations GmbH and others
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made
|
|
||||||
* available under the terms of the Eclipse Public License 2.0
|
|
||||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.eclipse.hawkbit.repository.event.remote;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.AccessLevel;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.ToString;
|
|
||||||
import org.eclipse.hawkbit.repository.Identifiable;
|
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generic deployment event for the Multi-Assignments feature. The event payload holds a list of controller IDs identifying the targets which
|
|
||||||
* are affected by a deployment action (e.g. a software assignment (update) or a cancellation of an update).
|
|
||||||
*/
|
|
||||||
@NoArgsConstructor(access = AccessLevel.PROTECTED) // for serialization libs like jackson
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public abstract class MultiActionEvent extends RemoteTenantAwareEvent implements Iterable<String> {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private final List<String> controllerIds = new ArrayList<>();
|
|
||||||
private final List<Long> actionIds = new ArrayList<>();
|
|
||||||
|
|
||||||
protected MultiActionEvent(final String tenant, final List<Action> actions) {
|
|
||||||
super(tenant, null);
|
|
||||||
this.controllerIds.addAll(getControllerIdsFromActions(actions));
|
|
||||||
this.actionIds.addAll(getIdsFromActions(actions));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@NonNull
|
|
||||||
public Iterator<String> iterator() {
|
|
||||||
return controllerIds.iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<String> getControllerIdsFromActions(final List<Action> actions) {
|
|
||||||
return actions.stream().map(Action::getTarget).map(Target::getControllerId).distinct().toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<Long> getIdsFromActions(final List<Action> actions) {
|
|
||||||
return actions.stream().map(Identifiable::getId).toList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Contributors to the Eclipse Foundation
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made
|
|
||||||
* available under the terms of the Eclipse Public License 2.0
|
|
||||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.eclipse.hawkbit.repository.event.remote.service;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Service event for {@link MultiActionAssignEvent}. Event that needs single replica processing
|
|
||||||
*/
|
|
||||||
public class MultiActionAssignServiceEvent extends AbstractServiceRemoteEvent<MultiActionAssignEvent> {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
|
|
||||||
@JsonCreator
|
|
||||||
public MultiActionAssignServiceEvent(@JsonProperty("payload") final MultiActionAssignEvent remoteEvent) {
|
|
||||||
super(remoteEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Contributors to the Eclipse Foundation
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made
|
|
||||||
* available under the terms of the Eclipse Public License 2.0
|
|
||||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.eclipse.hawkbit.repository.event.remote.service;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Service event for {@link MultiActionCancelEvent}. Event that needs single replica processing
|
|
||||||
*/
|
|
||||||
public class MultiActionCancelServiceEvent extends AbstractServiceRemoteEvent<MultiActionCancelEvent> {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
|
|
||||||
@JsonCreator
|
|
||||||
public MultiActionCancelServiceEvent(@JsonProperty("payload") final MultiActionCancelEvent remoteEvent) {
|
|
||||||
super(remoteEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -21,14 +21,14 @@ import org.eclipse.hawkbit.exception.SpServerError;
|
|||||||
*/
|
*/
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class MultiAssignmentIsNotEnabledException extends AbstractServerRtException {
|
public class MultiAssignmentException extends AbstractServerRtException {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private static final SpServerError THIS_ERROR = SpServerError.SP_MULTIASSIGNMENT_NOT_ENABLED;
|
private static final SpServerError THIS_ERROR = SpServerError.SP_MULTIASSIGNMENT;
|
||||||
|
|
||||||
public MultiAssignmentIsNotEnabledException() {
|
public MultiAssignmentException() {
|
||||||
super(THIS_ERROR);
|
super(THIS_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
package org.eclipse.hawkbit.repository.helper;
|
package org.eclipse.hawkbit.repository.helper;
|
||||||
|
|
||||||
import static org.eclipse.hawkbit.context.AccessContext.asSystem;
|
import static org.eclipse.hawkbit.context.AccessContext.asSystem;
|
||||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED;
|
|
||||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.USER_CONFIRMATION_FLOW_ENABLED;
|
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.USER_CONFIRMATION_FLOW_ENABLED;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@@ -45,10 +44,6 @@ public final class TenantConfigHelper {
|
|||||||
return asSystem(() -> getTenantConfigurationManagement().getConfigurationValue(key, valueType).getValue());
|
return asSystem(() -> getTenantConfigurationManagement().getConfigurationValue(key, valueType).getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isMultiAssignmentsEnabled() {
|
|
||||||
return getAsSystem(MULTI_ASSIGNMENTS_ENABLED, Boolean.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isUserConfirmationFlowEnabled() {
|
public static boolean isUserConfirmationFlowEnabled() {
|
||||||
return getAsSystem(USER_CONFIRMATION_FLOW_ENABLED, Boolean.class);
|
return getAsSystem(USER_CONFIRMATION_FLOW_ENABLED, Boolean.class);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,10 +116,6 @@ public class TenantConfigurationProperties {
|
|||||||
* Configuration value for percentage of oldest actions to be cleaned if @maxActionsPerTarget quota is hit
|
* Configuration value for percentage of oldest actions to be cleaned if @maxActionsPerTarget quota is hit
|
||||||
*/
|
*/
|
||||||
public static final String ACTION_CLEANUP_ON_QUOTA_HIT_PERCENTAGE = "action.cleanup.onQuotaHit.percent";
|
public static final String ACTION_CLEANUP_ON_QUOTA_HIT_PERCENTAGE = "action.cleanup.onQuotaHit.percent";
|
||||||
/**
|
|
||||||
* Switch to enable/disable the multi-assignment feature.
|
|
||||||
*/
|
|
||||||
public static final String MULTI_ASSIGNMENTS_ENABLED = "multi.assignments.enabled";
|
|
||||||
/**
|
/**
|
||||||
* Switch to enable/disable the batch-assignment feature.
|
* Switch to enable/disable the batch-assignment feature.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ import org.eclipse.hawkbit.repository.event.remote.DistributionSetDeletedEvent;
|
|||||||
import org.eclipse.hawkbit.repository.event.remote.DistributionSetTagDeletedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.DistributionSetTagDeletedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.DistributionSetTypeDeletedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.DistributionSetTypeDeletedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent;
|
import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent;
|
|
||||||
import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
|
|
||||||
import org.eclipse.hawkbit.repository.event.remote.RolloutDeletedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.RolloutDeletedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.RolloutGroupDeletedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.RolloutGroupDeletedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.RolloutStoppedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.RolloutStoppedEvent;
|
||||||
@@ -68,8 +66,6 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TenantConfigurationUpd
|
|||||||
import org.eclipse.hawkbit.repository.event.remote.service.ActionCreatedServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.ActionCreatedServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.ActionUpdatedServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.ActionUpdatedServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.CancelTargetAssignmentServiceEvent;
|
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.TargetAssignDistributionSetServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.TargetAttributesRequestedServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.TargetAttributesRequestedServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.TargetCreatedServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.TargetCreatedServiceEvent;
|
||||||
@@ -162,9 +158,6 @@ public class EventType {
|
|||||||
// target attributes requested flag
|
// target attributes requested flag
|
||||||
TYPES.put(37, TargetAttributesRequestedEvent.class);
|
TYPES.put(37, TargetAttributesRequestedEvent.class);
|
||||||
|
|
||||||
// deployment event for assignments and /or cancellations
|
|
||||||
TYPES.put(38, MultiActionAssignEvent.class);
|
|
||||||
TYPES.put(39, MultiActionCancelEvent.class);
|
|
||||||
|
|
||||||
// tenant configuration
|
// tenant configuration
|
||||||
TYPES.put(40, TenantConfigurationCreatedEvent.class);
|
TYPES.put(40, TenantConfigurationCreatedEvent.class);
|
||||||
@@ -186,8 +179,6 @@ public class EventType {
|
|||||||
TYPES.put(1003, TargetAssignDistributionSetServiceEvent.class);
|
TYPES.put(1003, TargetAssignDistributionSetServiceEvent.class);
|
||||||
TYPES.put(1004, TargetAttributesRequestedServiceEvent.class);
|
TYPES.put(1004, TargetAttributesRequestedServiceEvent.class);
|
||||||
TYPES.put(1005, CancelTargetAssignmentServiceEvent.class);
|
TYPES.put(1005, CancelTargetAssignmentServiceEvent.class);
|
||||||
TYPES.put(1006, MultiActionAssignServiceEvent.class);
|
|
||||||
TYPES.put(1007, MultiActionCancelServiceEvent.class);
|
|
||||||
TYPES.put(1008, ActionCreatedServiceEvent.class);
|
TYPES.put(1008, ActionCreatedServiceEvent.class);
|
||||||
TYPES.put(1009, ActionUpdatedServiceEvent.class);
|
TYPES.put(1009, ActionUpdatedServiceEvent.class);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ import lombok.NonNull;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.AbstractRemoteEvent;
|
import org.eclipse.hawkbit.repository.event.remote.AbstractRemoteEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
|
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.TargetAssignDistributionSetEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
||||||
@@ -29,8 +27,6 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
|||||||
import org.eclipse.hawkbit.repository.event.remote.service.ActionCreatedServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.ActionCreatedServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.ActionUpdatedServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.ActionUpdatedServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.CancelTargetAssignmentServiceEvent;
|
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.TargetAssignDistributionSetServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.TargetAttributesRequestedServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.TargetAttributesRequestedServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.TargetCreatedServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.TargetCreatedServiceEvent;
|
||||||
@@ -77,8 +73,6 @@ public final class EventPublisherHolder {
|
|||||||
TargetAssignDistributionSetEvent.class,
|
TargetAssignDistributionSetEvent.class,
|
||||||
CancelTargetAssignmentEvent.class,
|
CancelTargetAssignmentEvent.class,
|
||||||
TargetAttributesRequestedEvent.class,
|
TargetAttributesRequestedEvent.class,
|
||||||
MultiActionAssignEvent.class,
|
|
||||||
MultiActionCancelEvent.class,
|
|
||||||
ActionCreatedEvent.class,
|
ActionCreatedEvent.class,
|
||||||
ActionUpdatedEvent.class
|
ActionUpdatedEvent.class
|
||||||
);
|
);
|
||||||
@@ -183,10 +177,6 @@ public final class EventPublisherHolder {
|
|||||||
return new CancelTargetAssignmentServiceEvent(cancelTargetAssignmentEvent);
|
return new CancelTargetAssignmentServiceEvent(cancelTargetAssignmentEvent);
|
||||||
} else if (event instanceof TargetAttributesRequestedEvent targetAttributesRequestedEvent) {
|
} else if (event instanceof TargetAttributesRequestedEvent targetAttributesRequestedEvent) {
|
||||||
return new TargetAttributesRequestedServiceEvent(targetAttributesRequestedEvent);
|
return new TargetAttributesRequestedServiceEvent(targetAttributesRequestedEvent);
|
||||||
} else if (event instanceof MultiActionAssignEvent multiActionAssignEvent) {
|
|
||||||
return new MultiActionAssignServiceEvent(multiActionAssignEvent);
|
|
||||||
} else if (event instanceof MultiActionCancelEvent multiActionCancelEvent) {
|
|
||||||
return new MultiActionCancelServiceEvent(multiActionCancelEvent);
|
|
||||||
} else if (event instanceof ActionCreatedEvent actionCreatedEvent) {
|
} else if (event instanceof ActionCreatedEvent actionCreatedEvent) {
|
||||||
return new ActionCreatedServiceEvent(actionCreatedEvent);
|
return new ActionCreatedServiceEvent(actionCreatedEvent);
|
||||||
} else if (event instanceof ActionUpdatedEvent actionUpdatedEvent) {
|
} else if (event instanceof ActionUpdatedEvent actionUpdatedEvent) {
|
||||||
|
|||||||
@@ -85,10 +85,6 @@ hawkbit.server.tenant.configuration.action-cleanup-on-quota-hit-percent.keyName=
|
|||||||
hawkbit.server.tenant.configuration.action-cleanup-on-quota-hit-percent.defaultValue=0
|
hawkbit.server.tenant.configuration.action-cleanup-on-quota-hit-percent.defaultValue=0
|
||||||
hawkbit.server.tenant.configuration.action-cleanup-on-quota-hit-percent.dataType=java.lang.Integer
|
hawkbit.server.tenant.configuration.action-cleanup-on-quota-hit-percent.dataType=java.lang.Integer
|
||||||
|
|
||||||
hawkbit.server.tenant.configuration.multi-assignments-enabled.keyName=multi.assignments.enabled
|
|
||||||
hawkbit.server.tenant.configuration.multi-assignments-enabled.defaultValue=false
|
|
||||||
hawkbit.server.tenant.configuration.multi-assignments-enabled.dataType=java.lang.Boolean
|
|
||||||
|
|
||||||
hawkbit.server.tenant.configuration.batch-assignments-enabled.keyName=batch.assignments.enabled
|
hawkbit.server.tenant.configuration.batch-assignments-enabled.keyName=batch.assignments.enabled
|
||||||
hawkbit.server.tenant.configuration.batch-assignments-enabled.defaultValue=false
|
hawkbit.server.tenant.configuration.batch-assignments-enabled.defaultValue=false
|
||||||
hawkbit.server.tenant.configuration.batch-assignments-enabled.dataType=java.lang.Boolean
|
hawkbit.server.tenant.configuration.batch-assignments-enabled.dataType=java.lang.Boolean
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ public abstract class AbstractDsAssignmentStrategy {
|
|||||||
|
|
||||||
private final ActionStatusRepository actionStatusRepository;
|
private final ActionStatusRepository actionStatusRepository;
|
||||||
private final QuotaManagement quotaManagement;
|
private final QuotaManagement quotaManagement;
|
||||||
private final BooleanSupplier multiAssignmentsConfig;
|
|
||||||
private final BooleanSupplier confirmationFlowConfig;
|
private final BooleanSupplier confirmationFlowConfig;
|
||||||
private final RepositoryProperties repositoryProperties;
|
private final RepositoryProperties repositoryProperties;
|
||||||
private final Consumer<MaxAssignmentsExceededInfo> maxAssignmentExceededHandler;
|
private final Consumer<MaxAssignmentsExceededInfo> maxAssignmentExceededHandler;
|
||||||
@@ -74,14 +73,13 @@ public abstract class AbstractDsAssignmentStrategy {
|
|||||||
AbstractDsAssignmentStrategy(
|
AbstractDsAssignmentStrategy(
|
||||||
final TargetRepository targetRepository,
|
final TargetRepository targetRepository,
|
||||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||||
final QuotaManagement quotaManagement, final BooleanSupplier multiAssignmentsConfig,
|
final QuotaManagement quotaManagement, final BooleanSupplier confirmationFlowConfig,
|
||||||
final BooleanSupplier confirmationFlowConfig, final RepositoryProperties repositoryProperties,
|
final RepositoryProperties repositoryProperties,
|
||||||
final Consumer<MaxAssignmentsExceededInfo> maxAssignmentExceededHandler) {
|
final Consumer<MaxAssignmentsExceededInfo> maxAssignmentExceededHandler) {
|
||||||
this.targetRepository = targetRepository;
|
this.targetRepository = targetRepository;
|
||||||
this.actionRepository = actionRepository;
|
this.actionRepository = actionRepository;
|
||||||
this.actionStatusRepository = actionStatusRepository;
|
this.actionStatusRepository = actionStatusRepository;
|
||||||
this.quotaManagement = quotaManagement;
|
this.quotaManagement = quotaManagement;
|
||||||
this.multiAssignmentsConfig = multiAssignmentsConfig;
|
|
||||||
this.confirmationFlowConfig = confirmationFlowConfig;
|
this.confirmationFlowConfig = confirmationFlowConfig;
|
||||||
this.repositoryProperties = repositoryProperties;
|
this.repositoryProperties = repositoryProperties;
|
||||||
this.maxAssignmentExceededHandler = maxAssignmentExceededHandler;
|
this.maxAssignmentExceededHandler = maxAssignmentExceededHandler;
|
||||||
@@ -211,10 +209,6 @@ public abstract class AbstractDsAssignmentStrategy {
|
|||||||
afterCommit(() -> EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new CancelTargetAssignmentEvent(action)));
|
afterCommit(() -> EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new CancelTargetAssignmentEvent(action)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isMultiAssignmentsEnabled() {
|
|
||||||
return multiAssignmentsConfig.getAsBoolean();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isConfirmationFlowEnabled() {
|
protected boolean isConfirmationFlowEnabled() {
|
||||||
return confirmationFlowConfig.getAsBoolean();
|
return confirmationFlowConfig.getAsBoolean();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ import org.eclipse.hawkbit.repository.exception.ForceQuitActionNotAllowedExcepti
|
|||||||
import org.eclipse.hawkbit.repository.exception.IncompatibleTargetTypeException;
|
import org.eclipse.hawkbit.repository.exception.IncompatibleTargetTypeException;
|
||||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
import org.eclipse.hawkbit.repository.exception.MultiAssignmentException;
|
||||||
import org.eclipse.hawkbit.repository.helper.TenantConfigHelper;
|
import org.eclipse.hawkbit.repository.helper.TenantConfigHelper;
|
||||||
import org.eclipse.hawkbit.repository.jpa.Jpa;
|
import org.eclipse.hawkbit.repository.jpa.Jpa;
|
||||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||||
@@ -159,10 +159,10 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
maxAssignmentsExceededInfo.requested,
|
maxAssignmentsExceededInfo.requested,
|
||||||
maxAssignmentsExceededInfo.quotaExceededException);
|
maxAssignmentsExceededInfo.quotaExceededException);
|
||||||
onlineDsAssignmentStrategy = new OnlineDsAssignmentStrategy(targetRepository, actionRepository, actionStatusRepository,
|
onlineDsAssignmentStrategy = new OnlineDsAssignmentStrategy(targetRepository, actionRepository, actionStatusRepository,
|
||||||
quotaManagement, this::isMultiAssignmentsEnabled, this::isConfirmationFlowEnabled, repositoryProperties,
|
quotaManagement, this::isConfirmationFlowEnabled, repositoryProperties,
|
||||||
maxAssignmentsExceededHandler);
|
maxAssignmentsExceededHandler);
|
||||||
offlineDsAssignmentStrategy = new OfflineDsAssignmentStrategy(targetRepository, actionRepository, actionStatusRepository,
|
offlineDsAssignmentStrategy = new OfflineDsAssignmentStrategy(targetRepository, actionRepository, actionStatusRepository,
|
||||||
quotaManagement, this::isMultiAssignmentsEnabled, this::isConfirmationFlowEnabled, repositoryProperties,
|
quotaManagement, this::isConfirmationFlowEnabled, repositoryProperties,
|
||||||
maxAssignmentsExceededHandler);
|
maxAssignmentsExceededHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,16 +423,12 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
public void cancelInactiveScheduledActionsForTargets(final List<Long> targetIds) {
|
public void cancelInactiveScheduledActionsForTargets(final List<Long> targetIds) {
|
||||||
if (!isMultiAssignmentsEnabled()) {
|
|
||||||
targetRepository.getAccessController().ifPresent(v -> {
|
targetRepository.getAccessController().ifPresent(v -> {
|
||||||
if (targetRepository.count(AccessController.Operation.UPDATE, TargetSpecifications.hasIdIn(targetIds)) != targetIds.size()) {
|
if (targetRepository.count(AccessController.Operation.UPDATE, TargetSpecifications.hasIdIn(targetIds)) != targetIds.size()) {
|
||||||
throw new EntityNotFoundException(Target.class, targetIds);
|
throw new EntityNotFoundException(Target.class, targetIds);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
actionRepository.switchStatus(Status.CANCELED, targetIds, false, Status.SCHEDULED);
|
actionRepository.switchStatus(Status.CANCELED, targetIds, false, Status.SCHEDULED);
|
||||||
} else {
|
|
||||||
log.debug("The Multi Assignments feature is enabled: No need to cancel inactive scheduled actions.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -668,12 +664,10 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkForMultiAssignment(final Collection<DeploymentRequest> deploymentRequests) {
|
private void checkForMultiAssignment(final Collection<DeploymentRequest> deploymentRequests) {
|
||||||
if (!isMultiAssignmentsEnabled()) {
|
|
||||||
final long distinctTargetsInRequest = deploymentRequests.stream()
|
final long distinctTargetsInRequest = deploymentRequests.stream()
|
||||||
.map(request -> request.getTargetWithActionType().getControllerId()).distinct().count();
|
.map(request -> request.getTargetWithActionType().getControllerId()).distinct().count();
|
||||||
if (distinctTargetsInRequest < deploymentRequests.size()) {
|
if (distinctTargetsInRequest < deploymentRequests.size()) {
|
||||||
throw new MultiAssignmentIsNotEnabledException();
|
throw new MultiAssignmentException();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -819,9 +813,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
final List<JpaTarget> targetEntities) {
|
final List<JpaTarget> targetEntities) {
|
||||||
final List<List<Long>> targetEntitiesIdsChunks = getTargetEntitiesAsChunks(targetEntities);
|
final List<List<Long>> targetEntitiesIdsChunks = getTargetEntitiesAsChunks(targetEntities);
|
||||||
|
|
||||||
if (!isMultiAssignmentsEnabled()) {
|
|
||||||
closeOrCancelActiveActions(assignmentStrategy, targetEntitiesIdsChunks);
|
closeOrCancelActiveActions(assignmentStrategy, targetEntitiesIdsChunks);
|
||||||
}
|
|
||||||
// cancel all scheduled actions which are in-active, these actions were
|
// cancel all scheduled actions which are in-active, these actions were
|
||||||
// not active before and the manual assignment which has been done cancels them
|
// not active before and the manual assignment which has been done cancels them
|
||||||
targetEntitiesIdsChunks.forEach(this::cancelInactiveScheduledActionsForTargets);
|
targetEntitiesIdsChunks.forEach(this::cancelInactiveScheduledActionsForTargets);
|
||||||
@@ -944,10 +936,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
}
|
}
|
||||||
|
|
||||||
private JpaAction closeActionIfSetWasAlreadyAssigned(final JpaAction action) {
|
private JpaAction closeActionIfSetWasAlreadyAssigned(final JpaAction action) {
|
||||||
if (isMultiAssignmentsEnabled()) {
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
|
|
||||||
final JpaTarget target = action.getTarget();
|
final JpaTarget target = action.getTarget();
|
||||||
if (target.getAssignedDistributionSet() != null && action.getDistributionSet().getId()
|
if (target.getAssignedDistributionSet() != null && action.getDistributionSet().getId()
|
||||||
.equals(target.getAssignedDistributionSet().getId())) {
|
.equals(target.getAssignedDistributionSet().getId())) {
|
||||||
@@ -965,9 +953,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<Action> startScheduledActionsAndHandleOpenCancellationFirst(final List<JpaAction> actions) {
|
private List<Action> startScheduledActionsAndHandleOpenCancellationFirst(final List<JpaAction> actions) {
|
||||||
if (!isMultiAssignmentsEnabled()) {
|
|
||||||
closeOrCancelOpenDeviceActions(actions);
|
closeOrCancelOpenDeviceActions(actions);
|
||||||
}
|
|
||||||
final List<JpaAction> savedActions = activateActionsOfRolloutGroup(actions);
|
final List<JpaAction> savedActions = activateActionsOfRolloutGroup(actions);
|
||||||
setInitialActionStatusOfRolloutGroup(savedActions);
|
setInitialActionStatusOfRolloutGroup(savedActions);
|
||||||
setAssignmentOnTargets(savedActions);
|
setAssignmentOnTargets(savedActions);
|
||||||
@@ -1017,10 +1003,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
actionStatusRepository.save(actionStatus);
|
actionStatusRepository.save(actionStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isMultiAssignmentsEnabled() {
|
|
||||||
return TenantConfigHelper.isMultiAssignmentsEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isConfirmationFlowEnabled() {
|
private boolean isConfirmationFlowEnabled() {
|
||||||
return TenantConfigHelper.isUserConfirmationFlowEnabled();
|
return TenantConfigHelper.isUserConfirmationFlowEnabled();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ public class JpaRolloutManagement implements RolloutManagement {
|
|||||||
this.repositoryProperties = repositoryProperties;
|
this.repositoryProperties = repositoryProperties;
|
||||||
|
|
||||||
onlineDsAssignmentStrategy = new OnlineDsAssignmentStrategy(targetRepository, actionRepository, actionStatusRepository,
|
onlineDsAssignmentStrategy = new OnlineDsAssignmentStrategy(targetRepository, actionRepository, actionStatusRepository,
|
||||||
quotaManagement, this::isMultiAssignmentsEnabled, this::isConfirmationFlowEnabled, repositoryProperties, null);
|
quotaManagement, this::isConfirmationFlowEnabled, repositoryProperties, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -554,7 +554,7 @@ public class JpaRolloutManagement implements RolloutManagement {
|
|||||||
storeActionsAndStatuses(actions, Action.Status.CANCELING);
|
storeActionsAndStatuses(actions, Action.Status.CANCELING);
|
||||||
|
|
||||||
// send cancellation messages to event publisher
|
// send cancellation messages to event publisher
|
||||||
onlineDsAssignmentStrategy.sendCancellationMessages(actions, AccessContext.tenant());
|
onlineDsAssignmentStrategy.sendCancellationMessages(actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void forceQuitActionsOfRollout(final Rollout rollout) {
|
private void forceQuitActionsOfRollout(final Rollout rollout) {
|
||||||
@@ -1033,10 +1033,6 @@ public class JpaRolloutManagement implements RolloutManagement {
|
|||||||
return new TargetCount(totalTargets, baseFilter);
|
return new TargetCount(totalTargets, baseFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isMultiAssignmentsEnabled() {
|
|
||||||
return TenantConfigHelper.isMultiAssignmentsEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isConfirmationFlowEnabled() {
|
private boolean isConfirmationFlowEnabled() {
|
||||||
return TenantConfigHelper.isUserConfirmationFlowEnabled();
|
return TenantConfigHelper.isUserConfirmationFlowEnabled();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ package org.eclipse.hawkbit.repository.jpa.management;
|
|||||||
|
|
||||||
import static org.eclipse.hawkbit.auth.SpPermission.READ_GATEWAY_SECURITY_TOKEN;
|
import static org.eclipse.hawkbit.auth.SpPermission.READ_GATEWAY_SECURITY_TOKEN;
|
||||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY;
|
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_GATEWAY_SECURITY_TOKEN_KEY;
|
||||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.BATCH_ASSIGNMENTS_ENABLED;
|
|
||||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED;
|
|
||||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.POLLING_TIME;
|
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.POLLING_TIME;
|
||||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED;
|
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED;
|
||||||
|
|
||||||
@@ -207,7 +205,6 @@ public class JpaTenantConfigurationManagement implements TenantConfigurationMana
|
|||||||
tenantConfiguration.setValue(valueToString);
|
tenantConfiguration.setValue(valueToString);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertValueChangeIsAllowed(e.getKey(), tenantConfiguration);
|
|
||||||
return tenantConfiguration;
|
return tenantConfiguration;
|
||||||
}).toList());
|
}).toList());
|
||||||
}
|
}
|
||||||
@@ -273,58 +270,6 @@ public class JpaTenantConfigurationManagement implements TenantConfigurationMana
|
|||||||
return CONVERSION_SERVICE.convert(key.getDefaultValue(), propertyType);
|
return CONVERSION_SERVICE.convert(key.getDefaultValue(), propertyType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Asserts that the requested configuration value change is allowed. Throws a {@link TenantConfigurationValueChangeNotAllowedException}
|
|
||||||
* otherwise.
|
|
||||||
*
|
|
||||||
* @param key The configuration key.
|
|
||||||
* @param valueChange The configuration to be validated.
|
|
||||||
* @throws TenantConfigurationValueChangeNotAllowedException if the requested configuration change is not allowed.
|
|
||||||
*/
|
|
||||||
private void assertValueChangeIsAllowed(final String key, final JpaTenantConfiguration valueChange) {
|
|
||||||
assertMultiAssignmentsValueChange(key, valueChange);
|
|
||||||
assertAutoCloseValueChange(key);
|
|
||||||
assertBatchAssignmentValueChange(key, valueChange);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertMultiAssignmentsValueChange(final String key, final JpaTenantConfiguration valueChange) {
|
|
||||||
if (MULTI_ASSIGNMENTS_ENABLED.equals(key) && !Boolean.parseBoolean(valueChange.getValue())) {
|
|
||||||
log.debug("The Multi-Assignments '{}' feature cannot be disabled.", key);
|
|
||||||
throw new TenantConfigurationValueChangeNotAllowedException();
|
|
||||||
}
|
|
||||||
if (MULTI_ASSIGNMENTS_ENABLED.equals(key) && Boolean.parseBoolean(valueChange.getValue())) {
|
|
||||||
JpaTenantConfiguration batchConfig = tenantConfigurationRepository.findByKey(BATCH_ASSIGNMENTS_ENABLED);
|
|
||||||
if (batchConfig != null && Boolean.parseBoolean(batchConfig.getValue())) {
|
|
||||||
log.debug(
|
|
||||||
"The Multi-Assignments '{}' feature cannot be enabled as it contradicts with the Batch-Assignments feature, which is already enabled .",
|
|
||||||
key);
|
|
||||||
throw new TenantConfigurationValueChangeNotAllowedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertAutoCloseValueChange(final String key) {
|
|
||||||
if (REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED.equals(key)
|
|
||||||
&& Boolean.TRUE.equals(Optional.ofNullable(getConfigurationValue0(MULTI_ASSIGNMENTS_ENABLED, Boolean.class))
|
|
||||||
.map(TenantConfigurationValue::getValue)
|
|
||||||
.orElse(null))) {
|
|
||||||
log.debug("The property '{}' must not be changed because the Multi-Assignments feature is currently enabled.", key);
|
|
||||||
throw new TenantConfigurationValueChangeNotAllowedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertBatchAssignmentValueChange(final String key, final JpaTenantConfiguration valueChange) {
|
|
||||||
if (BATCH_ASSIGNMENTS_ENABLED.equals(key) && Boolean.parseBoolean(valueChange.getValue())) {
|
|
||||||
final JpaTenantConfiguration multiConfig = tenantConfigurationRepository.findByKey(MULTI_ASSIGNMENTS_ENABLED);
|
|
||||||
if (multiConfig != null && Boolean.parseBoolean(multiConfig.getValue())) {
|
|
||||||
log.debug(
|
|
||||||
"The Batch-Assignments '{}' feature cannot be enabled as it contradicts with the Multi-Assignments feature, which is already enabled .",
|
|
||||||
key);
|
|
||||||
throw new TenantConfigurationValueChangeNotAllowedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PollStatus pollStatus(final long lastTargetQuery, final PollingInterval pollingInterval, final Duration pollingOverdueTime) {
|
private static PollStatus pollStatus(final long lastTargetQuery, final PollingInterval pollingInterval, final Duration pollingOverdueTime) {
|
||||||
final LocalDateTime currentDate = LocalDateTime.now();
|
final LocalDateTime currentDate = LocalDateTime.now();
|
||||||
final LocalDateTime lastPollDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastTargetQuery), ZoneId.systemDefault());
|
final LocalDateTime lastPollDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastTargetQuery), ZoneId.systemDefault());
|
||||||
|
|||||||
@@ -46,11 +46,11 @@ class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
OfflineDsAssignmentStrategy(
|
OfflineDsAssignmentStrategy(
|
||||||
final TargetRepository targetRepository,
|
final TargetRepository targetRepository,
|
||||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||||
final QuotaManagement quotaManagement, final BooleanSupplier multiAssignmentsConfig,
|
final QuotaManagement quotaManagement,
|
||||||
final BooleanSupplier confirmationFlowConfig, final RepositoryProperties repositoryProperties,
|
final BooleanSupplier confirmationFlowConfig, final RepositoryProperties repositoryProperties,
|
||||||
final Consumer<MaxAssignmentsExceededInfo> maxAssignmentExceededHandler) {
|
final Consumer<MaxAssignmentsExceededInfo> maxAssignmentExceededHandler) {
|
||||||
super(targetRepository, actionRepository, actionStatusRepository,
|
super(targetRepository, actionRepository, actionStatusRepository,
|
||||||
quotaManagement, multiAssignmentsConfig, confirmationFlowConfig, repositoryProperties, maxAssignmentExceededHandler);
|
quotaManagement, confirmationFlowConfig, repositoryProperties, maxAssignmentExceededHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -74,14 +74,11 @@ class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<JpaTarget> findTargetsForAssignment(final List<String> controllerIDs, final long setId) {
|
public List<JpaTarget> findTargetsForAssignment(final List<String> controllerIDs, final long setId) {
|
||||||
final Function<List<String>, List<JpaTarget>> mapper;
|
final Function<List<String>, List<JpaTarget>> mapper =
|
||||||
if (isMultiAssignmentsEnabled()) {
|
ids -> targetRepository.findAll(JpaManagementHelper.combineWithAnd(List.of(
|
||||||
mapper = ids -> targetRepository.findAll(TargetSpecifications.hasControllerIdIn(ids));
|
|
||||||
} else {
|
|
||||||
mapper = ids -> targetRepository.findAll(JpaManagementHelper.combineWithAnd(List.of(
|
|
||||||
TargetSpecifications.hasControllerIdAndAssignedDistributionSetIdNot(ids, setId),
|
TargetSpecifications.hasControllerIdAndAssignedDistributionSetIdNot(ids, setId),
|
||||||
TargetSpecifications.notEqualToTargetUpdateStatus(TargetUpdateStatus.PENDING))));
|
TargetSpecifications.notEqualToTargetUpdateStatus(TargetUpdateStatus.PENDING))));
|
||||||
}
|
|
||||||
return ListUtils.partition(controllerIDs, Constants.MAX_ENTRIES_IN_STATEMENT).stream().map(mapper).flatMap(List::stream).toList();
|
return ListUtils.partition(controllerIDs, Constants.MAX_ENTRIES_IN_STATEMENT).stream().map(mapper).flatMap(List::stream).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ import org.eclipse.hawkbit.context.AccessContext;
|
|||||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||||
import org.eclipse.hawkbit.repository.event.EventPublisherHolder;
|
import org.eclipse.hawkbit.repository.event.EventPublisherHolder;
|
||||||
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.TargetAssignDistributionSetEvent;
|
||||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||||
@@ -54,19 +52,14 @@ class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
OnlineDsAssignmentStrategy(
|
OnlineDsAssignmentStrategy(
|
||||||
final TargetRepository targetRepository,
|
final TargetRepository targetRepository,
|
||||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||||
final QuotaManagement quotaManagement, final BooleanSupplier multiAssignmentsConfig,
|
final QuotaManagement quotaManagement,
|
||||||
final BooleanSupplier confirmationFlowConfig, final RepositoryProperties repositoryProperties,
|
final BooleanSupplier confirmationFlowConfig, final RepositoryProperties repositoryProperties,
|
||||||
final Consumer<MaxAssignmentsExceededInfo> maxAssignmentExceededHandler) {
|
final Consumer<MaxAssignmentsExceededInfo> maxAssignmentExceededHandler) {
|
||||||
super(targetRepository, actionRepository, actionStatusRepository,
|
super(targetRepository, actionRepository, actionStatusRepository,
|
||||||
quotaManagement, multiAssignmentsConfig, confirmationFlowConfig, repositoryProperties, maxAssignmentExceededHandler);
|
quotaManagement, confirmationFlowConfig, repositoryProperties, maxAssignmentExceededHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendDeploymentEvents(final long distributionSetId, final List<Action> actions) {
|
public void sendDeploymentEvents(final long distributionSetId, final List<Action> actions) {
|
||||||
if (isMultiAssignmentsEnabled()) {
|
|
||||||
sendDeploymentEvent(actions);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<Action> filteredActions = getActionsWithoutCancellations(actions);
|
final List<Action> filteredActions = getActionsWithoutCancellations(actions);
|
||||||
if (filteredActions.isEmpty()) {
|
if (filteredActions.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@@ -106,13 +99,9 @@ class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<JpaTarget> findTargetsForAssignment(final List<String> controllerIDs, final long setId) {
|
public List<JpaTarget> findTargetsForAssignment(final List<String> controllerIDs, final long setId) {
|
||||||
final Function<List<String>, List<JpaTarget>> mapper;
|
final Function<List<String>, List<JpaTarget>> mapper =
|
||||||
if (isMultiAssignmentsEnabled()) {
|
ids -> targetRepository.findAll(
|
||||||
mapper = ids -> targetRepository.findAll(TargetSpecifications.hasControllerIdIn(ids));
|
TargetSpecifications.hasControllerIdAndAssignedDistributionSetIdNot(ids, setId));
|
||||||
} else {
|
|
||||||
mapper = ids -> targetRepository
|
|
||||||
.findAll(TargetSpecifications.hasControllerIdAndAssignedDistributionSetIdNot(ids, setId));
|
|
||||||
}
|
|
||||||
return ListUtils.partition(controllerIDs, Constants.MAX_ENTRIES_IN_STATEMENT).stream().map(mapper)
|
return ListUtils.partition(controllerIDs, Constants.MAX_ENTRIES_IN_STATEMENT).stream().map(mapper)
|
||||||
.flatMap(List::stream).toList();
|
.flatMap(List::stream).toList();
|
||||||
}
|
}
|
||||||
@@ -163,28 +152,16 @@ class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendDeploymentEvents(final List<DistributionSetAssignmentResult> assignmentResults) {
|
public void sendDeploymentEvents(final List<DistributionSetAssignmentResult> assignmentResults) {
|
||||||
if (isMultiAssignmentsEnabled()) {
|
|
||||||
sendDeploymentEvent(assignmentResults.stream().flatMap(result -> result.getAssignedEntity().stream()).toList());
|
|
||||||
} else {
|
|
||||||
assignmentResults.forEach(this::sendDistributionSetAssignedEvent);
|
assignmentResults.forEach(this::sendDistributionSetAssignedEvent);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void sendCancellationMessage(final JpaAction action) {
|
void sendCancellationMessage(final JpaAction action) {
|
||||||
if (isMultiAssignmentsEnabled()) {
|
|
||||||
sendMultiActionCancelEvent(action);
|
|
||||||
} else {
|
|
||||||
cancelAssignDistributionSetEvent(action);
|
cancelAssignDistributionSetEvent(action);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void sendCancellationMessages(final List<JpaAction> actions, final String tenant) {
|
void sendCancellationMessages(final List<JpaAction> actions) {
|
||||||
if (isMultiAssignmentsEnabled()) {
|
|
||||||
sendMultiActionCancelEvent(tenant, Collections.unmodifiableList(actions));
|
|
||||||
} else {
|
|
||||||
actions.forEach(this::cancelAssignDistributionSetEvent);
|
actions.forEach(this::cancelAssignDistributionSetEvent);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static Stream<Action> filterCancellations(final List<Action> actions) {
|
private static Stream<Action> filterCancellations(final List<Action> actions) {
|
||||||
return actions.stream().filter(action -> {
|
return actions.stream().filter(action -> {
|
||||||
@@ -200,19 +177,6 @@ class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
return filterCancellations(actions).toList();
|
return filterCancellations(actions).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendMultiActionCancelEvent(final Action action) {
|
|
||||||
sendMultiActionCancelEvent(action.getTenant(), Collections.singletonList(action));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendDeploymentEvent(final List<Action> actions) {
|
|
||||||
final List<Action> filteredActions = getActionsWithoutCancellations(actions);
|
|
||||||
if (filteredActions.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final String tenant = filteredActions.get(0).getTenant();
|
|
||||||
sendMultiActionAssignEvent(tenant, filteredActions);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendDistributionSetAssignedEvent(final DistributionSetAssignmentResult assignmentResult) {
|
private void sendDistributionSetAssignedEvent(final DistributionSetAssignmentResult assignmentResult) {
|
||||||
final List<Action> filteredActions = filterCancellations(assignmentResult.getAssignedEntity()).toList();
|
final List<Action> filteredActions = filterCancellations(assignmentResult.getAssignedEntity()).toList();
|
||||||
final DistributionSet set = assignmentResult.getDistributionSet();
|
final DistributionSet set = assignmentResult.getDistributionSet();
|
||||||
@@ -228,25 +192,4 @@ class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
afterCommit(() -> EventPublisherHolder.getInstance().getEventPublisher().publishEvent(
|
afterCommit(() -> EventPublisherHolder.getInstance().getEventPublisher().publishEvent(
|
||||||
new TargetAssignDistributionSetEvent(tenant, distributionSetId, actions, actions.get(0).isMaintenanceWindowAvailable())));
|
new TargetAssignDistributionSetEvent(tenant, distributionSetId, actions, actions.get(0).isMaintenanceWindowAvailable())));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper to fire a {@link MultiActionCancelEvent}. This method may only be
|
|
||||||
* called if the Multi-Assignments feature is enabled.
|
|
||||||
*
|
|
||||||
* @param tenant the event is scoped to
|
|
||||||
* @param actions assigned to the targets
|
|
||||||
*/
|
|
||||||
private void sendMultiActionCancelEvent(final String tenant, final List<Action> actions) {
|
|
||||||
afterCommit(() -> EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new MultiActionCancelEvent(tenant, actions)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper to fire a {@link MultiActionAssignEvent}. This method may only be called if the Multi-Assignments feature is enabled.
|
|
||||||
*
|
|
||||||
* @param tenant the event is scoped to
|
|
||||||
* @param actions assigned to the targets
|
|
||||||
*/
|
|
||||||
private void sendMultiActionAssignEvent(final String tenant, final List<Action> actions) {
|
|
||||||
afterCommit(() -> EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new MultiActionAssignEvent(tenant, actions)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -84,8 +84,7 @@ public final class WeightValidationHelper {
|
|||||||
public static void validateWeight(final boolean hasWeight, final boolean hasNoWeight) {
|
public static void validateWeight(final boolean hasWeight, final boolean hasNoWeight) {
|
||||||
// remove bypassing the weight enforcement as soon as weight can be set via UI
|
// remove bypassing the weight enforcement as soon as weight can be set via UI
|
||||||
final boolean bypassWeightEnforcement = true;
|
final boolean bypassWeightEnforcement = true;
|
||||||
final boolean multiAssignmentsEnabled = TenantConfigHelper.isMultiAssignmentsEnabled();
|
if (!bypassWeightEnforcement && hasNoWeight) {
|
||||||
if (!bypassWeightEnforcement && multiAssignmentsEnabled && hasNoWeight) {
|
|
||||||
throw new NoWeightProvidedInMultiAssignmentModeException();
|
throw new NoWeightProvidedInMultiAssignmentModeException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,44 +30,6 @@ class RemoteTenantEventTest extends AbstractRemoteEventTest {
|
|||||||
|
|
||||||
private static final String TENANT_DEFAULT = "DEFAULT";
|
private static final String TENANT_DEFAULT = "DEFAULT";
|
||||||
|
|
||||||
/**
|
|
||||||
* Verifies that a testMultiActionAssignEvent can be properly serialized and deserialized
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void testMultiActionAssignEvent() {
|
|
||||||
final List<String> controllerIds = List.of("id0", "id1", "id2", "id3", "id4loooooooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnnng");
|
|
||||||
final List<Action> actions = controllerIds.stream().map(this::createAction).toList();
|
|
||||||
|
|
||||||
final MultiActionAssignEvent assignEvent = new MultiActionAssignEvent(TENANT_DEFAULT, actions);
|
|
||||||
|
|
||||||
final MultiActionAssignEvent remoteAssignEventProtoStuff = createProtoStuffEvent(assignEvent);
|
|
||||||
assertThat(assignEvent).isEqualTo(remoteAssignEventProtoStuff);
|
|
||||||
assertThat(remoteAssignEventProtoStuff.getControllerIds()).containsExactlyElementsOf(controllerIds);
|
|
||||||
|
|
||||||
final MultiActionAssignEvent remoteAssignEventJackson = createJacksonEvent(assignEvent);
|
|
||||||
assertThat(assignEvent).isEqualTo(remoteAssignEventJackson);
|
|
||||||
assertThat(remoteAssignEventJackson.getControllerIds()).containsExactlyElementsOf(controllerIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verifies that a MultiActionCancelEvent can be properly serialized and deserialized
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void testMultiActionCancelEvent() {
|
|
||||||
final List<String> controllerIds = List.of("id0", "id1", "id2", "id3", "id4loooooooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnnng");
|
|
||||||
final List<Action> actions = controllerIds.stream().map(this::createAction).toList();
|
|
||||||
|
|
||||||
final MultiActionCancelEvent cancelEvent = new MultiActionCancelEvent(TENANT_DEFAULT, actions);
|
|
||||||
|
|
||||||
final MultiActionCancelEvent remoteCancelEventProtoStuff = createProtoStuffEvent(cancelEvent);
|
|
||||||
assertThat(cancelEvent).isEqualTo(remoteCancelEventProtoStuff);
|
|
||||||
assertThat(remoteCancelEventProtoStuff.getControllerIds()).containsExactlyElementsOf(controllerIds);
|
|
||||||
|
|
||||||
final MultiActionCancelEvent remoteCancelEventJackson = createJacksonEvent(cancelEvent);
|
|
||||||
assertThat(cancelEvent).isEqualTo(remoteCancelEventJackson);
|
|
||||||
assertThat(remoteCancelEventJackson.getControllerIds()).containsExactlyElementsOf(controllerIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies that a DownloadProgressEvent can be properly serialized and deserialized
|
* Verifies that a DownloadProgressEvent can be properly serialized and deserialized
|
||||||
*/
|
*/
|
||||||
@@ -135,15 +97,6 @@ class RemoteTenantEventTest extends AbstractRemoteEventTest {
|
|||||||
assertCancelTargetAssignmentEvent(action, remoteEventJackson);
|
assertCancelTargetAssignmentEvent(action, remoteEventJackson);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Action createAction(final String controllerId) {
|
|
||||||
final JpaAction generateAction = new JpaAction();
|
|
||||||
generateAction.setId(1L);
|
|
||||||
generateAction.setActionType(ActionType.FORCED);
|
|
||||||
generateAction.setTarget(testdataFactory.createTarget(controllerId));
|
|
||||||
generateAction.setStatus(Status.RUNNING);
|
|
||||||
return generateAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertTargetAssignDistributionSetEvent(final Action action, final TargetAssignDistributionSetEvent underTest) {
|
private void assertTargetAssignDistributionSetEvent(final Action action, final TargetAssignDistributionSetEvent underTest) {
|
||||||
assertThat(underTest.getActions()).hasSize(1);
|
assertThat(underTest.getActions()).hasSize(1);
|
||||||
final ActionProperties actionProperties = underTest.getActions().get(action.getTarget().getControllerId());
|
final ActionProperties actionProperties = underTest.getActions().get(action.getTarget().getControllerId());
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import static org.mockito.Mockito.mock;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.event.EventPublisherHolder;
|
import org.eclipse.hawkbit.repository.event.EventPublisherHolder;
|
||||||
@@ -25,7 +24,6 @@ import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
|||||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.CancelTargetAssignmentServiceEvent;
|
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.TargetAssignDistributionSetServiceEvent;
|
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.TargetAttributesRequestedServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.TargetCreatedServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.TargetCreatedServiceEvent;
|
||||||
@@ -79,8 +77,6 @@ class ServiceEventsTest {
|
|||||||
TargetAssignDistributionSetEvent.class,
|
TargetAssignDistributionSetEvent.class,
|
||||||
CancelTargetAssignmentEvent.class,
|
CancelTargetAssignmentEvent.class,
|
||||||
TargetAttributesRequestedEvent.class,
|
TargetAttributesRequestedEvent.class,
|
||||||
MultiActionAssignEvent.class,
|
|
||||||
MultiActionCancelEvent.class,
|
|
||||||
ActionCreatedEvent.class,
|
ActionCreatedEvent.class,
|
||||||
ActionUpdatedEvent.class
|
ActionUpdatedEvent.class
|
||||||
);
|
);
|
||||||
@@ -124,16 +120,6 @@ class ServiceEventsTest {
|
|||||||
verify(streamBridge).send(eq("group"), any(TargetAttributesRequestedServiceEvent.class));
|
verify(streamBridge).send(eq("group"), any(TargetAttributesRequestedServiceEvent.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void testProcessingMultiActionAssignmentEventIsSent() {
|
|
||||||
MultiActionAssignEvent event = new MultiActionAssignEvent("testtenant", List.of(mockAction()));
|
|
||||||
|
|
||||||
publisher.publishEvent(event);
|
|
||||||
|
|
||||||
verify(streamBridge).send("fanout", event);
|
|
||||||
verify(streamBridge).send(eq("group"), any(MultiActionAssignServiceEvent.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCancelTargetAssignmentEventIsSent() {
|
void testCancelTargetAssignmentEventIsSent() {
|
||||||
CancelTargetAssignmentEvent event = new CancelTargetAssignmentEvent(mockAction());
|
CancelTargetAssignmentEvent event = new CancelTargetAssignmentEvent(mockAction());
|
||||||
|
|||||||
@@ -64,37 +64,6 @@ class ConfirmationManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
.allMatch(action -> action.getStatus() == Status.WAIT_FOR_CONFIRMATION);
|
.allMatch(action -> action.getStatus() == Status.WAIT_FOR_CONFIRMATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify 'findActiveActionsWaitingConfirmation' method is filtering like expected with multi assignment active
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void retrieveActionsWithConfirmationStateInMultiAssignment() {
|
|
||||||
enableMultiAssignments();
|
|
||||||
enableConfirmationFlow();
|
|
||||||
|
|
||||||
final String controllerId = testdataFactory.createTarget().getControllerId();
|
|
||||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
|
||||||
|
|
||||||
final List<Action> actions = assignDistributionSet(dsId, controllerId).getAssignedEntity();
|
|
||||||
assertThat(actions).hasSize(1);
|
|
||||||
|
|
||||||
assertThat(confirmationManagement.findActiveActionsWaitingConfirmation(controllerId)).hasSize(1)
|
|
||||||
.allMatch(action -> action.getStatus() == Status.WAIT_FOR_CONFIRMATION);
|
|
||||||
|
|
||||||
final Long dsId2 = testdataFactory.createDistributionSet().getId();
|
|
||||||
assignDistributionSet(dsId2, controllerId);
|
|
||||||
|
|
||||||
assertThat(confirmationManagement.findActiveActionsWaitingConfirmation(controllerId)).hasSize(2)
|
|
||||||
.allMatch(action -> action.getStatus() == Status.WAIT_FOR_CONFIRMATION);
|
|
||||||
|
|
||||||
confirmationManagement.confirmAction(actions.get(0).getId(), null, null);
|
|
||||||
|
|
||||||
assertThat(confirmationManagement.findActiveActionsWaitingConfirmation(controllerId)).hasSize(1)
|
|
||||||
.allMatch(action -> action.getStatus() == Status.WAIT_FOR_CONFIRMATION
|
|
||||||
&& Objects.equals(action.getDistributionSet().getId(), dsId2));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify confirming an action will put it to the running state
|
* Verify confirming an action will put it to the running state
|
||||||
*/
|
*/
|
||||||
@@ -191,34 +160,6 @@ class ConfirmationManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
.noneMatch(status -> status.getStatus() == Status.RUNNING);
|
.noneMatch(status -> status.getStatus() == Status.RUNNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify multiple actions in WFC state will be transferred in RUNNING state in case auto-confirmation is activated.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void activateAutoConfirmationInMultiAssignment() {
|
|
||||||
enableMultiAssignments();
|
|
||||||
enableConfirmationFlow();
|
|
||||||
|
|
||||||
final String controllerId = testdataFactory.createTarget().getControllerId();
|
|
||||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
|
||||||
final Long dsId2 = testdataFactory.createDistributionSet().getId();
|
|
||||||
|
|
||||||
final List<Action> actions = assignDistributionSets(
|
|
||||||
Arrays.asList(toDeploymentRequest(controllerId, dsId), toDeploymentRequest(controllerId, dsId2)))
|
|
||||||
.stream().flatMap(s -> s.getAssignedEntity().stream()).toList();
|
|
||||||
assertThat(actions).hasSize(2);
|
|
||||||
|
|
||||||
assertThat(confirmationManagement.findActiveActionsWaitingConfirmation(controllerId)).hasSize(2)
|
|
||||||
.allMatch(action -> action.getStatus() == Status.WAIT_FOR_CONFIRMATION);
|
|
||||||
|
|
||||||
confirmationManagement.activateAutoConfirmation(controllerId, null, null);
|
|
||||||
|
|
||||||
assertThat(confirmationManagement.findActiveActionsWaitingConfirmation(controllerId)).isEmpty();
|
|
||||||
|
|
||||||
assertThat(deploymentManagement.findActionsByTarget(controllerId, PAGE).getContent()).hasSize(2)
|
|
||||||
.allMatch(action -> action.getStatus() == Status.RUNNING);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify action in WFC state will be transferred in RUNNING state in case auto-confirmation is activated.
|
* Verify action in WFC state will be transferred in RUNNING state in case auto-confirmation is activated.
|
||||||
*/
|
*/
|
||||||
@@ -324,10 +265,6 @@ class ConfirmationManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
Arguments.of(null, null));
|
Arguments.of(null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DeploymentRequest toDeploymentRequest(final String controllerId, final Long distributionSetId) {
|
|
||||||
return DeploymentRequest.builder(controllerId, distributionSetId).confirmationRequired(true).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyAutoConfirmationIsDisabled(final String controllerId) {
|
private void verifyAutoConfirmationIsDisabled(final String controllerId) {
|
||||||
assertThat(targetManagement.getWithAutoConfigurationStatus(controllerId).getAutoConfirmationStatus()).isNull();
|
assertThat(targetManagement.getWithAutoConfigurationStatus(controllerId).getAutoConfirmationStatus()).isNull();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1582,41 +1582,6 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
assertNoActiveActionsExistsForControllerId(DEFAULT_CONTROLLER_ID);
|
assertNoActiveActionsExistsForControllerId(DEFAULT_CONTROLLER_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Actions are exposed according to thier weight in multi assignment mode.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void actionsAreExposedAccordingToTheirWeight() {
|
|
||||||
final String targetId = testdataFactory.createTarget().getControllerId();
|
|
||||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
|
||||||
final Long actionWeightNull = assignDistributionSet(ds.getId(), targetId).getAssignedEntity().get(0).getId();
|
|
||||||
enableMultiAssignments();
|
|
||||||
final Long actionWeight500old = assignDistributionSet(ds.getId(), targetId, 500).getAssignedEntity().get(0)
|
|
||||||
.getId();
|
|
||||||
final Long actionWeight500new = assignDistributionSet(ds.getId(), targetId, 500).getAssignedEntity().get(0)
|
|
||||||
.getId();
|
|
||||||
final Long actionWeight1000 = assignDistributionSet(ds.getId(), targetId, 1000).getAssignedEntity().get(0)
|
|
||||||
.getId();
|
|
||||||
|
|
||||||
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId())
|
|
||||||
.isEqualTo(actionWeightNull);
|
|
||||||
controllerManagement
|
|
||||||
.addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionWeightNull).status(Status.FINISHED).build());
|
|
||||||
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId())
|
|
||||||
.isEqualTo(actionWeight1000);
|
|
||||||
controllerManagement
|
|
||||||
.addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionWeight1000).status(Status.FINISHED).build());
|
|
||||||
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId())
|
|
||||||
.isEqualTo(actionWeight500old);
|
|
||||||
controllerManagement
|
|
||||||
.addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionWeight500old).status(Status.FINISHED).build());
|
|
||||||
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId())
|
|
||||||
.isEqualTo(actionWeight500new);
|
|
||||||
controllerManagement
|
|
||||||
.addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionWeight500new).status(Status.FINISHED).build());
|
|
||||||
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId)).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a target on requested target deletion from client side
|
* Delete a target on requested target deletion from client side
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
|||||||
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
|
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
|
||||||
import org.eclipse.hawkbit.repository.Identifiable;
|
import org.eclipse.hawkbit.repository.Identifiable;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
|
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.TargetAssignDistributionSetEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
||||||
@@ -50,13 +48,18 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
|||||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.TenantConfigurationCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.TenantConfigurationCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.TenantConfigurationUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.TenantConfigurationUpdatedEvent;
|
||||||
|
import org.eclipse.hawkbit.repository.event.remote.service.ActionCreatedServiceEvent;
|
||||||
|
import org.eclipse.hawkbit.repository.event.remote.service.ActionUpdatedServiceEvent;
|
||||||
|
import org.eclipse.hawkbit.repository.event.remote.service.CancelTargetAssignmentServiceEvent;
|
||||||
|
import org.eclipse.hawkbit.repository.event.remote.service.TargetAssignDistributionSetServiceEvent;
|
||||||
|
import org.eclipse.hawkbit.repository.event.remote.service.TargetUpdatedServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||||
import org.eclipse.hawkbit.repository.exception.ForceQuitActionNotAllowedException;
|
import org.eclipse.hawkbit.repository.exception.ForceQuitActionNotAllowedException;
|
||||||
import org.eclipse.hawkbit.repository.exception.IncompatibleTargetTypeException;
|
import org.eclipse.hawkbit.repository.exception.IncompatibleTargetTypeException;
|
||||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||||
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
|
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
|
||||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
import org.eclipse.hawkbit.repository.exception.MultiAssignmentException;
|
||||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
||||||
@@ -208,19 +211,22 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void assertMaxActionsPerTargetQuotaIsEnforced() {
|
void assertMaxActionsPerTargetQuotaIsEnforced() {
|
||||||
enableMultiAssignments();
|
|
||||||
|
|
||||||
final int maxActions = quotaManagement.getMaxActionsPerTarget();
|
final int maxActions = quotaManagement.getMaxActionsPerTarget();
|
||||||
final Target testTarget = testdataFactory.createTarget();
|
final Target testTarget = testdataFactory.createTarget();
|
||||||
final Long ds1Id = testdataFactory.createDistributionSet("ds1").getId();
|
final List<Long> dsIds = new ArrayList<>();
|
||||||
|
for (int i = 0; i < maxActions; i++) {
|
||||||
|
dsIds.add(testdataFactory.createDistributionSet("ds" + i).getId());
|
||||||
|
}
|
||||||
|
|
||||||
final String controllerId = testTarget.getControllerId();
|
final String controllerId = testTarget.getControllerId();
|
||||||
for (int i = 0; i < maxActions; i++) {
|
for (int i = 0; i < maxActions; i++) {
|
||||||
deploymentManagement.offlineAssignedDistributionSets(List.of(new SimpleEntry<>(controllerId, ds1Id)));
|
deploymentManagement.offlineAssignedDistributionSets(List.of(new SimpleEntry<>(controllerId, dsIds.get(i))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final long dsIdThatShouldNotBeAssigned = testdataFactory.createDistributionSet("shouldNotBeAssigned").getId();
|
||||||
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
||||||
.isThrownBy(() -> assignDistributionSet(ds1Id, controllerId, 77));
|
.isThrownBy(() -> assignDistributionSet(dsIdThatShouldNotBeAssigned, controllerId, 77));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -539,44 +545,6 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
.allMatch(target -> target.getLastModifiedAt() == target.getInstallationDate());
|
.allMatch(target -> target.getLastModifiedAt() == target.getInstallationDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Offline assign multiple DSs to a single Target in multiassignment mode.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
@ExpectEvents({
|
|
||||||
@Expect(type = TargetCreatedEvent.class, count = 1),
|
|
||||||
@Expect(type = TargetUpdatedEvent.class, count = 4),
|
|
||||||
@Expect(type = ActionCreatedEvent.class, count = 4),
|
|
||||||
@Expect(type = DistributionSetCreatedEvent.class, count = 4),
|
|
||||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 12),
|
|
||||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 4), // implicit lock
|
|
||||||
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 12), // implicit lock
|
|
||||||
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
|
|
||||||
void multiOfflineAssignment() {
|
|
||||||
final List<String> targetIds = testdataFactory.createTargets(1).stream().map(Target::getControllerId).toList();
|
|
||||||
final List<Long> dsIds = testdataFactory.createDistributionSets(4).stream().map(DistributionSet::getId).toList();
|
|
||||||
|
|
||||||
enableMultiAssignments();
|
|
||||||
final List<Entry<String, Long>> offlineAssignments = new ArrayList<>();
|
|
||||||
targetIds.forEach(targetId -> dsIds.forEach(dsId -> offlineAssignments.add(new SimpleEntry<>(targetId, dsId))));
|
|
||||||
final List<DistributionSetAssignmentResult> assignmentResults = deploymentManagement
|
|
||||||
.offlineAssignedDistributionSets(offlineAssignments);
|
|
||||||
|
|
||||||
assertThat(getResultingActionCount(assignmentResults)).isEqualTo(4);
|
|
||||||
targetIds.forEach(controllerId -> {
|
|
||||||
final List<Long> assignedDsIds = deploymentManagement.findActionsByTarget(controllerId, PAGE).stream()
|
|
||||||
.map(a -> {
|
|
||||||
// don't use peek since it is by documentation mainly for debugging and could be skipped in some cases
|
|
||||||
assertThat(a.getInitiatedBy())
|
|
||||||
.as("Actions should be initiated by current user")
|
|
||||||
.isEqualTo(AccessContext.actor());
|
|
||||||
return a;
|
|
||||||
})
|
|
||||||
.map(action -> action.getDistributionSet().getId()).toList();
|
|
||||||
assertThat(assignedDsIds).containsExactlyInAnyOrderElementsOf(dsIds);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies that if an account is set to action autoclose running actions in case of a new assigned set get closed and set to CANCELED.
|
* Verifies that if an account is set to action autoclose running actions in case of a new assigned set get closed and set to CANCELED.
|
||||||
*/
|
*/
|
||||||
@@ -620,118 +588,11 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If multi-assignment is enabled, verify that the previous Distribution Set assignment is not canceled when a new one is assigned.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
@ExpectEvents({
|
|
||||||
@Expect(type = TargetCreatedEvent.class, count = 10),
|
|
||||||
@Expect(type = TargetUpdatedEvent.class, count = 20),
|
|
||||||
@Expect(type = ActionCreatedEvent.class, count = 20),
|
|
||||||
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
|
|
||||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6),
|
|
||||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 2), // implicit lock
|
|
||||||
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6), // implicit lock
|
|
||||||
@Expect(type = MultiActionAssignEvent.class, count = 2),
|
|
||||||
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
|
|
||||||
void previousAssignmentsAreNotCanceledInMultiAssignMode() {
|
|
||||||
enableMultiAssignments();
|
|
||||||
final List<Target> targets = testdataFactory.createTargets(10);
|
|
||||||
final List<String> targetIds = targets.stream().map(Target::getControllerId).toList();
|
|
||||||
|
|
||||||
// First assignment
|
|
||||||
final DistributionSet ds1 = testdataFactory.createDistributionSet("Multi-assign-1");
|
|
||||||
assignDistributionSet(ds1.getId(), targetIds, 77);
|
|
||||||
|
|
||||||
assertDsExclusivelyAssignedToTargets(targets, ds1.getId(), STATE_ACTIVE, RUNNING);
|
|
||||||
|
|
||||||
// Second assignment
|
|
||||||
final DistributionSet ds2 = testdataFactory.createDistributionSet("Multi-assign-2");
|
|
||||||
assignDistributionSet(ds2.getId(), targetIds, 45);
|
|
||||||
|
|
||||||
assertDsExclusivelyAssignedToTargets(targets, ds2.getId(), STATE_ACTIVE, RUNNING);
|
|
||||||
assertDsExclusivelyAssignedToTargets(targets, ds1.getId(), STATE_ACTIVE, RUNNING);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assign multiple DSs to a single Target in one request in multiassignment mode.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
@ExpectEvents({
|
|
||||||
@Expect(type = TargetCreatedEvent.class, count = 1),
|
|
||||||
@Expect(type = TargetUpdatedEvent.class, count = 4),
|
|
||||||
@Expect(type = ActionCreatedEvent.class, count = 4),
|
|
||||||
@Expect(type = DistributionSetCreatedEvent.class, count = 4),
|
|
||||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 12),
|
|
||||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 4), // implicit lock
|
|
||||||
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 12), // implicit lock
|
|
||||||
@Expect(type = MultiActionAssignEvent.class, count = 1),
|
|
||||||
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
|
|
||||||
void multiAssignmentInOneRequest() {
|
|
||||||
final List<Target> targets = testdataFactory.createTargets(1);
|
|
||||||
final List<DistributionSet> distributionSets = testdataFactory.createDistributionSets(4);
|
|
||||||
final List<DeploymentRequest> deploymentRequests = createAssignmentRequests(distributionSets, targets, 34);
|
|
||||||
|
|
||||||
enableMultiAssignments();
|
|
||||||
final List<DistributionSetAssignmentResult> results = deploymentManagement.assignDistributionSets(deploymentRequests, null);
|
|
||||||
|
|
||||||
assertThat(getResultingActionCount(results)).isEqualTo(deploymentRequests.size());
|
|
||||||
final List<Long> dsIds = distributionSets.stream().map(DistributionSet::getId).toList();
|
|
||||||
targets.forEach(target -> {
|
|
||||||
final List<Long> assignedDsIds = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE)
|
|
||||||
.stream()
|
|
||||||
.map(a -> {
|
|
||||||
// don't use peek since it is by documentation mainly for debugging and could be skipped in some cases
|
|
||||||
assertThat(a.getInitiatedBy()).as("Initiated by current user")
|
|
||||||
.isEqualTo(AccessContext.actor());
|
|
||||||
return a;
|
|
||||||
})
|
|
||||||
.map(action -> action.getDistributionSet().getId()).toList();
|
|
||||||
assertThat(assignedDsIds).containsExactlyInAnyOrderElementsOf(dsIds);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assign multiple DSs to single Target in one request in multiAssignment mode and cancel each created action afterwards.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
@ExpectEvents({
|
|
||||||
@Expect(type = TargetCreatedEvent.class, count = 1),
|
|
||||||
@Expect(type = TargetUpdatedEvent.class, count = 4),
|
|
||||||
@Expect(type = ActionCreatedEvent.class, count = 4),
|
|
||||||
@Expect(type = DistributionSetCreatedEvent.class, count = 4),
|
|
||||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 12),
|
|
||||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 4), // implicit lock
|
|
||||||
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 12), // implicit lock
|
|
||||||
@Expect(type = MultiActionAssignEvent.class, count = 1),
|
|
||||||
@Expect(type = MultiActionCancelEvent.class, count = 4),
|
|
||||||
@Expect(type = ActionUpdatedEvent.class, count = 4),
|
|
||||||
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
|
|
||||||
void cancelMultiAssignmentActions() {
|
|
||||||
final List<Target> targets = testdataFactory.createTargets(1);
|
|
||||||
final List<DistributionSet> distributionSets = testdataFactory.createDistributionSets(4);
|
|
||||||
final List<DeploymentRequest> deploymentRequests = createAssignmentRequests(distributionSets, targets, 34, false);
|
|
||||||
|
|
||||||
enableMultiAssignments();
|
|
||||||
final List<DistributionSetAssignmentResult> results = deploymentManagement.assignDistributionSets(deploymentRequests, null);
|
|
||||||
|
|
||||||
assertThat(getResultingActionCount(results)).isEqualTo(deploymentRequests.size());
|
|
||||||
|
|
||||||
final List<Long> dsIds = distributionSets.stream().map(DistributionSet::getId).toList();
|
|
||||||
targets.forEach(target ->
|
|
||||||
deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).forEach(action -> {
|
|
||||||
assertThat(action.getDistributionSet().getId()).isIn(dsIds);
|
|
||||||
assertThat(action.getInitiatedBy())
|
|
||||||
.as("Should be Initiated by current user").isEqualTo(AccessContext.actor());
|
|
||||||
deploymentManagement.cancelAction(action.getId());
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Request resulting in multiple assignments to a single target is only allowed when multiassignment is enabled.
|
* A Request resulting in multiple assignments to a single target is only allowed when multiassignment is enabled.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void multipleAssignmentsToTargetOnlyAllowedInMultiAssignMode() {
|
void multipleAssignmentsToTargetNotAllowed() {
|
||||||
final Target target = testdataFactory.createTarget();
|
final Target target = testdataFactory.createTarget();
|
||||||
final List<DistributionSet> distributionSets = testdataFactory.createDistributionSets(2);
|
final List<DistributionSet> distributionSets = testdataFactory.createDistributionSets(2);
|
||||||
|
|
||||||
@@ -742,11 +603,9 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
.builder(target.getControllerId(), distributionSets.get(1).getId()).weight(565).build();
|
.builder(target.getControllerId(), distributionSets.get(1).getId()).weight(565).build();
|
||||||
|
|
||||||
final List<DeploymentRequest> deploymentRequests = List.of(targetToDS0, targetToDS1);
|
final List<DeploymentRequest> deploymentRequests = List.of(targetToDS0, targetToDS1);
|
||||||
Assertions.assertThatExceptionOfType(MultiAssignmentIsNotEnabledException.class)
|
Assertions.assertThatExceptionOfType(MultiAssignmentException.class)
|
||||||
.isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequests, null));
|
.isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequests, null));
|
||||||
|
|
||||||
enableMultiAssignments();
|
|
||||||
assertThat(getResultingActionCount(deploymentManagement.assignDistributionSets(List.of(targetToDS0, targetToDS1), null))).isEqualTo(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -912,77 +771,46 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Duplicate Assignments are removed from a request when multi-assignment is disabled, otherwise not
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
@ExpectEvents({
|
|
||||||
@Expect(type = TargetCreatedEvent.class, count = 1),
|
|
||||||
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
|
|
||||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
|
|
||||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
|
|
||||||
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 3), // implicit lock
|
|
||||||
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
|
|
||||||
@Expect(type = ActionCreatedEvent.class, count = 2),
|
|
||||||
@Expect(type = TargetUpdatedEvent.class, count = 2),
|
|
||||||
@Expect(type = MultiActionAssignEvent.class, count = 1),
|
|
||||||
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
|
|
||||||
void duplicateAssignmentsInRequestAreRemovedIfMultiassignmentEnabled() {
|
|
||||||
final String targetId = testdataFactory.createTarget().getControllerId();
|
|
||||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
|
||||||
final List<DeploymentRequest> twoEqualAssignments = Collections.nCopies(2, DeploymentRequest.builder(targetId, dsId).build());
|
|
||||||
assertThat(getResultingActionCount(deploymentManagement.assignDistributionSets(twoEqualAssignments, null))).isEqualTo(1);
|
|
||||||
|
|
||||||
enableMultiAssignments();
|
|
||||||
final List<DeploymentRequest> twoEqualAssignmentsWithWeight = Collections.nCopies(
|
|
||||||
2, DeploymentRequest.builder(targetId, dsId).weight(555).build());
|
|
||||||
|
|
||||||
assertThat(getResultingActionCount(deploymentManagement.assignDistributionSets(twoEqualAssignmentsWithWeight, null))).isEqualTo(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An assignment request is not accepted if it would lead to a target exceeding the max actions per target quota.
|
* An assignment request is not accepted if it would lead to a target exceeding the max actions per target quota.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@ExpectEvents({
|
@ExpectEvents({
|
||||||
@Expect(type = TargetCreatedEvent.class, count = 1),
|
@Expect(type = TargetCreatedEvent.class, count = 1),
|
||||||
|
@Expect(type = TargetUpdatedEvent.class, count = 20),
|
||||||
|
@Expect(type = TargetUpdatedServiceEvent.class, count = 20),
|
||||||
|
@Expect(type = TargetAssignDistributionSetEvent.class, count = 20),
|
||||||
|
@Expect(type = CancelTargetAssignmentEvent.class, count = 19),
|
||||||
|
@Expect(type = CancelTargetAssignmentServiceEvent.class, count = 19),
|
||||||
@Expect(type = DistributionSetCreatedEvent.class, count = 21), // max actions per target are 20 for test
|
@Expect(type = DistributionSetCreatedEvent.class, count = 21), // max actions per target are 20 for test
|
||||||
|
@Expect(type = DistributionSetUpdatedEvent.class, count = 20),
|
||||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3 * 21),
|
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3 * 21),
|
||||||
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
|
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 3 * 20),
|
||||||
|
@Expect(type = ActionUpdatedEvent.class, count = 19),
|
||||||
|
@Expect(type = ActionCreatedEvent.class, count = 20),
|
||||||
|
@Expect(type = ActionCreatedServiceEvent.class, count = 20),
|
||||||
|
@Expect(type = TargetAssignDistributionSetEvent.class, count = 20),
|
||||||
|
})
|
||||||
void maxActionsPerTargetIsCheckedBeforeAssignmentExecution() {
|
void maxActionsPerTargetIsCheckedBeforeAssignmentExecution() {
|
||||||
final int maxActions = quotaManagement.getMaxActionsPerTarget();
|
final int maxActions = quotaManagement.getMaxActionsPerTarget();
|
||||||
assertThat(maxActions)
|
assertThat(maxActions)
|
||||||
.as("Expect 20 as maxActionPerTarget. If not the case change @Expect counts for " +
|
.as("Expect 20 as maxActionPerTarget. If not the case change @Expect counts for " +
|
||||||
"DistributionSetCreatedEvent and SoftwareModuleCreatedEvent accordingly!")
|
"DistributionSetCreatedEvent and SoftwareModuleCreatedEvent accordingly!")
|
||||||
.isEqualTo(20);
|
.isEqualTo(20);
|
||||||
final int size = maxActions + 1;
|
|
||||||
final String controllerId = testdataFactory.createTarget().getControllerId();
|
final String controllerId = testdataFactory.createTarget().getControllerId();
|
||||||
|
|
||||||
final List<DeploymentRequest> deploymentRequests = new ArrayList<>();
|
for (int i = 0; i < maxActions; i++) {
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
final Long dsId = testdataFactory.createDistributionSet().getId();
|
||||||
deploymentRequests.add(DeploymentRequest.builder(controllerId, dsId).weight(24).build());
|
deploymentManagement.assignDistributionSets(
|
||||||
|
List.of(DeploymentRequest.builder(controllerId, dsId).weight(24).build()), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
enableMultiAssignments();
|
final Long dsId = testdataFactory.createDistributionSet().getId();
|
||||||
|
final List<DeploymentRequest> deploymentRequests = List.of(DeploymentRequest.builder(controllerId, dsId).weight(24).build());
|
||||||
Assertions.assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
Assertions.assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
||||||
.isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequests, null));
|
.isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequests, null));
|
||||||
assertThat(actionRepository.countByTargetControllerId(controllerId)).isZero();
|
assertThat(actionRepository.countByTargetControllerId(controllerId)).isEqualTo(20L);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An assignment request without a weight is ok when multi assignment in enabled.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void weightNotRequiredInMultiAssignmentMode() {
|
|
||||||
final String targetId = testdataFactory.createTarget().getControllerId();
|
|
||||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
|
||||||
|
|
||||||
final DeploymentRequest assignWithoutWeight = DeploymentRequest.builder(targetId, dsId).build();
|
|
||||||
final DeploymentRequest assignWithWeight = DeploymentRequest.builder(targetId, dsId).weight(567).build();
|
|
||||||
|
|
||||||
enableMultiAssignments();
|
|
||||||
assertThat(deploymentManagement.assignDistributionSets(List.of(assignWithoutWeight, assignWithWeight), null)).isNotNull();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1003,22 +831,28 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
@ExpectEvents({
|
@ExpectEvents({
|
||||||
@Expect(type = TargetCreatedEvent.class, count = 1),
|
@Expect(type = TargetCreatedEvent.class, count = 1),
|
||||||
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
|
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
|
||||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
|
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6),
|
||||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
|
@Expect(type = DistributionSetUpdatedEvent.class, count = 2), // implicit lock
|
||||||
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 3), // implicit lock
|
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6), // implicit lock
|
||||||
@Expect(type = ActionCreatedEvent.class, count = 2),
|
@Expect(type = ActionCreatedEvent.class, count = 2),
|
||||||
|
@Expect(type = ActionUpdatedEvent.class, count = 1),
|
||||||
|
@Expect(type = ActionUpdatedServiceEvent.class, count = 1),
|
||||||
@Expect(type = TargetUpdatedEvent.class, count = 2),
|
@Expect(type = TargetUpdatedEvent.class, count = 2),
|
||||||
@Expect(type = MultiActionAssignEvent.class, count = 2),
|
@Expect(type = TargetAssignDistributionSetEvent.class, count = 2),
|
||||||
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
|
@Expect(type = TargetAssignDistributionSetServiceEvent.class, count = 2),
|
||||||
|
@Expect(type = CancelTargetAssignmentEvent.class, count = 1),
|
||||||
|
@Expect(type = CancelTargetAssignmentServiceEvent.class, count = 1)
|
||||||
|
})
|
||||||
void weightValidatedAndSaved() {
|
void weightValidatedAndSaved() {
|
||||||
final String targetId = testdataFactory.createTarget().getControllerId();
|
final String targetId = testdataFactory.createTarget().getControllerId();
|
||||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
final Long dsId1 = testdataFactory.createDistributionSet().getId();
|
||||||
final DeploymentRequest validRequest1 = DeploymentRequest.builder(targetId, dsId).weight(Action.WEIGHT_MAX).build();
|
final Long dsId2 = testdataFactory.createDistributionSet().getId();
|
||||||
final DeploymentRequest validRequest2 = DeploymentRequest.builder(targetId, dsId).weight(Action.WEIGHT_MIN).build();
|
final DeploymentRequest validRequest1 = DeploymentRequest.builder(targetId, dsId1).weight(Action.WEIGHT_MAX).build();
|
||||||
final DeploymentRequest weightTooLow = DeploymentRequest.builder(targetId, dsId).weight(Action.WEIGHT_MIN - 1).build();
|
final DeploymentRequest validRequest2 = DeploymentRequest.builder(targetId, dsId2).weight(Action.WEIGHT_MIN).build();
|
||||||
final DeploymentRequest weightTooHigh = DeploymentRequest.builder(targetId, dsId).weight(Action.WEIGHT_MAX + 1).build();
|
final DeploymentRequest weightTooLow = DeploymentRequest.builder(targetId, dsId1).weight(Action.WEIGHT_MIN - 1).build();
|
||||||
enableMultiAssignments();
|
final DeploymentRequest weightTooHigh = DeploymentRequest.builder(targetId, dsId1).weight(Action.WEIGHT_MAX + 1).build();
|
||||||
|
|
||||||
final List<DeploymentRequest> deploymentRequestsTooLow = Collections.singletonList(weightTooLow);
|
final List<DeploymentRequest> deploymentRequestsTooLow = Collections.singletonList(weightTooLow);
|
||||||
Assertions.assertThatExceptionOfType(ConstraintViolationException.class)
|
Assertions.assertThatExceptionOfType(ConstraintViolationException.class)
|
||||||
.isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequestsTooLow, null));
|
.isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequestsTooLow, null));
|
||||||
@@ -1027,9 +861,11 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
() -> deploymentManagement.assignDistributionSets(deploymentRequestsTooHigh, null));
|
() -> deploymentManagement.assignDistributionSets(deploymentRequestsTooHigh, null));
|
||||||
final Long validActionId1 = getFirstAssignedAction(
|
final Long validActionId1 = getFirstAssignedAction(
|
||||||
deploymentManagement.assignDistributionSets(Collections.singletonList(validRequest1), null).get(0)).getId();
|
deploymentManagement.assignDistributionSets(Collections.singletonList(validRequest1), null).get(0)).getId();
|
||||||
final Long validActionId2 = getFirstAssignedAction(
|
|
||||||
deploymentManagement.assignDistributionSets(Collections.singletonList(validRequest2), null).get(0)).getId();
|
|
||||||
assertThat(actionRepository.findById(validActionId1).get().getWeight()).get().isEqualTo(Action.WEIGHT_MAX);
|
assertThat(actionRepository.findById(validActionId1).get().getWeight()).get().isEqualTo(Action.WEIGHT_MAX);
|
||||||
|
DistributionSetAssignmentResult assignmentResult = deploymentManagement.assignDistributionSets(Collections.singletonList(validRequest2), null).get(0);
|
||||||
|
System.out.println(assignmentResult.getAssignedEntity().toString());
|
||||||
|
|
||||||
|
final Long validActionId2 = getFirstAssignedAction(assignmentResult).getId();
|
||||||
assertThat(actionRepository.findById(validActionId2).get().getWeight()).get().isEqualTo(Action.WEIGHT_MIN);
|
assertThat(actionRepository.findById(validActionId2).get().getWeight()).get().isEqualTo(Action.WEIGHT_MIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1720,20 +1556,6 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<DeploymentRequest> createAssignmentRequests(
|
|
||||||
final Collection<DistributionSet> distributionSets, final Collection<Target> targets, final int weight) {
|
|
||||||
return createAssignmentRequests(distributionSets, targets, weight, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<DeploymentRequest> createAssignmentRequests(final Collection<DistributionSet> distributionSets,
|
|
||||||
final Collection<Target> targets, final int weight, final boolean confirmationRequired) {
|
|
||||||
final List<DeploymentRequest> deploymentRequests = new ArrayList<>();
|
|
||||||
distributionSets.forEach(ds -> targets.forEach(target -> deploymentRequests.add(
|
|
||||||
DeploymentRequest.builder(target.getControllerId(), ds.getId())
|
|
||||||
.weight(weight).confirmationRequired(confirmationRequired).build())));
|
|
||||||
return deploymentRequests;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JpaAction assignSet(final Target target, final DistributionSet ds) {
|
private JpaAction assignSet(final Target target, final DistributionSet ds) {
|
||||||
assignDistributionSet(ds.getId(), target.getControllerId());
|
assignDistributionSet(ds.getId(), target.getControllerId());
|
||||||
implicitLock(ds);
|
implicitLock(ds);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import java.util.stream.Stream;
|
|||||||
import jakarta.validation.ConstraintViolationException;
|
import jakarta.validation.ConstraintViolationException;
|
||||||
import jakarta.validation.ValidationException;
|
import jakarta.validation.ValidationException;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.assertj.core.api.Assertions;
|
import org.assertj.core.api.Assertions;
|
||||||
import org.assertj.core.api.Condition;
|
import org.assertj.core.api.Condition;
|
||||||
import org.eclipse.hawkbit.auth.SpPermission;
|
import org.eclipse.hawkbit.auth.SpPermission;
|
||||||
@@ -1994,18 +1995,6 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
assertThat(rolloutsOrderedByName).containsSubsequence(List.of(rolloutRunning, rolloutReady));
|
assertThat(rolloutsOrderedByName).containsSubsequence(List.of(rolloutRunning, rolloutReady));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creating a rollout without weight value when multi assignment in enabled.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void weightNotRequiredInMultiAssignmentMode() {
|
|
||||||
enableMultiAssignments();
|
|
||||||
final Rollout rollout = testdataFactory.createSimpleTestRolloutWithTargetsAndDistributionSet(10, 10, 2, "50",
|
|
||||||
"80",
|
|
||||||
ActionType.FORCED, null);
|
|
||||||
assertThat(rollout).isNotNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creating a rollout with a weight causes an error when multi assignment in disabled.
|
* Creating a rollout with a weight causes an error when multi assignment in disabled.
|
||||||
*/
|
*/
|
||||||
@@ -2024,7 +2013,6 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
void weightValidatedAndSaved() {
|
void weightValidatedAndSaved() {
|
||||||
final String targetPrefix = UUID.randomUUID().toString();
|
final String targetPrefix = UUID.randomUUID().toString();
|
||||||
testdataFactory.createTargets(4, targetPrefix);
|
testdataFactory.createTargets(4, targetPrefix);
|
||||||
enableMultiAssignments();
|
|
||||||
|
|
||||||
final String rolloutName = UUID.randomUUID().toString();
|
final String rolloutName = UUID.randomUUID().toString();
|
||||||
final String targetPrefixName = UUID.randomUUID().toString();
|
final String targetPrefixName = UUID.randomUUID().toString();
|
||||||
@@ -2054,7 +2042,6 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
void actionsWithWeightAreCreated() {
|
void actionsWithWeightAreCreated() {
|
||||||
final int amountOfTargets = 5;
|
final int amountOfTargets = 5;
|
||||||
final int weight = 99;
|
final int weight = 99;
|
||||||
enableMultiAssignments();
|
|
||||||
final Long rolloutId = testdataFactory
|
final Long rolloutId = testdataFactory
|
||||||
.createSimpleTestRolloutWithTargetsAndDistributionSet(amountOfTargets, 2, amountOfTargets,
|
.createSimpleTestRolloutWithTargetsAndDistributionSet(amountOfTargets, 2, amountOfTargets,
|
||||||
"80", "50", null, weight).getId();
|
"80", "50", null, weight).getId();
|
||||||
@@ -2066,24 +2053,6 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
.allMatch(action -> action.getWeight().get() == weight);
|
.allMatch(action -> action.getWeight().get() == weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Rollout can be created without weight in single assignment and be started in multi assignment
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void createInSingleStartInMultiassignMode() {
|
|
||||||
final int amountOfTargets = 5;
|
|
||||||
final Long rolloutId = testdataFactory.createSimpleTestRolloutWithTargetsAndDistributionSet(amountOfTargets, 2,
|
|
||||||
amountOfTargets,
|
|
||||||
"80", "50", null, null).getId();
|
|
||||||
|
|
||||||
enableMultiAssignments();
|
|
||||||
rolloutManagement.start(rolloutId);
|
|
||||||
rolloutHandler.handleAll();
|
|
||||||
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
|
|
||||||
// wight replaced with default
|
|
||||||
assertThat(actions).hasSize(5).allMatch(action -> action.getWeight().isPresent());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies that an exception is thrown when trying to create a rollout with an invalidated distribution set.
|
* Verifies that an exception is thrown when trying to create a rollout with an invalidated distribution set.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -244,23 +244,6 @@ class TargetFilterQueryManagementTest extends AbstractRepositoryManagementTest<T
|
|||||||
verifyFindForAllWithAutoAssignDs(tfq, tfq2);
|
verifyFindForAllWithAutoAssignDs(tfq, tfq2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creating or updating a target filter query with autoassignment and no-value weight when multi assignment in enabled.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void weightNotRequiredInMultiAssignmentMode() {
|
|
||||||
enableMultiAssignments();
|
|
||||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
|
||||||
final Long filterId = targetFilterQueryManagement.create(Create.builder().name("a").query("name==*").build()).getId();
|
|
||||||
|
|
||||||
assertThat(
|
|
||||||
targetFilterQueryManagement.create(Create.builder().name("b").query("name==*").autoAssignDistributionSet(ds).build()))
|
|
||||||
.isNotNull();
|
|
||||||
assertThat(
|
|
||||||
targetFilterQueryManagement.updateAutoAssignDS(new AutoAssignDistributionSetUpdate(filterId).ds(ds.getId())))
|
|
||||||
.isNotNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creating or updating a target filter query with autoassignment with a weight causes an error when multi assignment in disabled.
|
* Creating or updating a target filter query with autoassignment with a weight causes an error when multi assignment in disabled.
|
||||||
*/
|
*/
|
||||||
@@ -279,23 +262,8 @@ class TargetFilterQueryManagementTest extends AbstractRepositoryManagementTest<T
|
|||||||
.isNotNull();
|
.isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Auto assignment can be removed from filter when multi assignment in enabled.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void removeDsFromFilterWhenMultiAssignmentModeNotEnabled() {
|
|
||||||
enableMultiAssignments();
|
|
||||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
|
||||||
final Long filterId = targetFilterQueryManagement.create(
|
|
||||||
Create.builder().name("a").query("name==*").autoAssignDistributionSet(ds).autoAssignWeight(23).build()).getId();
|
|
||||||
assertThat(targetFilterQueryManagement.updateAutoAssignDS(
|
|
||||||
new AutoAssignDistributionSetUpdate(filterId).ds(null).weight(null)))
|
|
||||||
.isNotNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void weightValidatedAndSaved() {
|
void weightValidatedAndSaved() {
|
||||||
enableMultiAssignments();
|
|
||||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||||
|
|
||||||
final Create targetFilterQueryCreate = Create.builder().name("a")
|
final Create targetFilterQueryCreate = Create.builder().name("a")
|
||||||
|
|||||||
@@ -328,7 +328,6 @@ class AutoAssignHandlerIntTest extends AbstractJpaIntegrationTest {
|
|||||||
final int amountOfTargets = 5;
|
final int amountOfTargets = 5;
|
||||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||||
final int weight = 32;
|
final int weight = 32;
|
||||||
enableMultiAssignments();
|
|
||||||
|
|
||||||
targetFilterQueryManagement.create(Create.builder()
|
targetFilterQueryManagement.create(Create.builder()
|
||||||
.name("a").query("name==*").autoAssignDistributionSet(ds).autoAssignWeight(weight)
|
.name("a").query("name==*").autoAssignDistributionSet(ds).autoAssignWeight(weight)
|
||||||
@@ -342,25 +341,6 @@ class AutoAssignHandlerIntTest extends AbstractJpaIntegrationTest {
|
|||||||
.allMatch(action -> action.getWeight().get() == weight);
|
.allMatch(action -> action.getWeight().get() == weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* An auto assignment target filter without weight still works after multi assignment is enabled
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void filterWithoutWeightWorksInMultiAssignmentMode() {
|
|
||||||
final int amountOfTargets = 5;
|
|
||||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
|
||||||
targetFilterQueryManagement.create(Create.builder().name("a").query("name==*").autoAssignDistributionSet(ds).build());
|
|
||||||
enableMultiAssignments();
|
|
||||||
|
|
||||||
testdataFactory.createTargets(amountOfTargets);
|
|
||||||
autoAssignChecker.handleAll();
|
|
||||||
|
|
||||||
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
|
|
||||||
assertThat(actions)
|
|
||||||
.hasSize(amountOfTargets)
|
|
||||||
.allMatch(action -> action.getWeight().isPresent());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies an auto assignment only creates actions for compatible targets
|
* Verifies an auto assignment only creates actions for compatible targets
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -34,8 +34,6 @@ import org.awaitility.Awaitility;
|
|||||||
import org.awaitility.core.ConditionTimeoutException;
|
import org.awaitility.core.ConditionTimeoutException;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.AbstractRemoteEvent;
|
import org.eclipse.hawkbit.repository.event.remote.AbstractRemoteEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
|
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.RemoteIdEvent;
|
import org.eclipse.hawkbit.repository.event.remote.RemoteIdEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.RemoteTenantAwareEvent;
|
import org.eclipse.hawkbit.repository.event.remote.RemoteTenantAwareEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
||||||
@@ -48,8 +46,6 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
|||||||
import org.eclipse.hawkbit.repository.event.remote.service.ActionCreatedServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.ActionCreatedServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.ActionUpdatedServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.ActionUpdatedServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.CancelTargetAssignmentServiceEvent;
|
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.TargetAssignDistributionSetServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.TargetAttributesRequestedServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.TargetAttributesRequestedServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.TargetCreatedServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.TargetCreatedServiceEvent;
|
||||||
@@ -177,10 +173,6 @@ public class EventVerifier extends AbstractTestExecutionListener {
|
|||||||
modifiedEvents.add(new DynamicExpect(TargetDeletedServiceEvent.class, event.count()));
|
modifiedEvents.add(new DynamicExpect(TargetDeletedServiceEvent.class, event.count()));
|
||||||
} else if (type.isAssignableFrom(TargetAssignDistributionSetEvent.class)) {
|
} else if (type.isAssignableFrom(TargetAssignDistributionSetEvent.class)) {
|
||||||
modifiedEvents.add(new DynamicExpect(TargetAssignDistributionSetServiceEvent.class, event.count()));
|
modifiedEvents.add(new DynamicExpect(TargetAssignDistributionSetServiceEvent.class, event.count()));
|
||||||
} else if (type.isAssignableFrom(MultiActionAssignEvent.class)) {
|
|
||||||
modifiedEvents.add(new DynamicExpect(MultiActionAssignServiceEvent.class, event.count()));
|
|
||||||
} else if (type.isAssignableFrom(MultiActionCancelEvent.class)) {
|
|
||||||
modifiedEvents.add(new DynamicExpect(MultiActionCancelServiceEvent.class, event.count()));
|
|
||||||
} else if (type.isAssignableFrom(TargetAttributesRequestedEvent.class)) {
|
} else if (type.isAssignableFrom(TargetAttributesRequestedEvent.class)) {
|
||||||
modifiedEvents.add(new DynamicExpect(TargetAttributesRequestedServiceEvent.class, event.count()));
|
modifiedEvents.add(new DynamicExpect(TargetAttributesRequestedServiceEvent.class, event.count()));
|
||||||
} else if (type.isAssignableFrom(CancelTargetAssignmentEvent.class)) {
|
} else if (type.isAssignableFrom(CancelTargetAssignmentEvent.class)) {
|
||||||
|
|||||||
@@ -409,10 +409,6 @@ public abstract class AbstractIntegrationTest {
|
|||||||
return assignDistributionSet(dsId, Collections.singletonList(targetId), weight);
|
return assignDistributionSet(dsId, Collections.singletonList(targetId), weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void enableMultiAssignments() {
|
|
||||||
tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void enableConfirmationFlow() {
|
protected void enableConfirmationFlow() {
|
||||||
tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.USER_CONFIRMATION_FLOW_ENABLED, true);
|
tenantConfigurationManagement().addOrUpdateConfiguration(TenantConfigurationKey.USER_CONFIRMATION_FLOW_ENABLED, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ public class RestConfiguration {
|
|||||||
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_REPO_AUTO_CONFIRMATION_ALREADY_ACTIVE, CONFLICT);
|
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_REPO_AUTO_CONFIRMATION_ALREADY_ACTIVE, CONFLICT);
|
||||||
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_AUTO_ASSIGN_ACTION_TYPE_INVALID, BAD_REQUEST);
|
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_AUTO_ASSIGN_ACTION_TYPE_INVALID, BAD_REQUEST);
|
||||||
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_CONFIGURATION_VALUE_CHANGE_NOT_ALLOWED, FORBIDDEN);
|
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_CONFIGURATION_VALUE_CHANGE_NOT_ALLOWED, FORBIDDEN);
|
||||||
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_MULTIASSIGNMENT_NOT_ENABLED, BAD_REQUEST);
|
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_MULTIASSIGNMENT, BAD_REQUEST);
|
||||||
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_NO_WEIGHT_PROVIDED_IN_MULTIASSIGNMENT_MODE, BAD_REQUEST);
|
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_NO_WEIGHT_PROVIDED_IN_MULTIASSIGNMENT_MODE, BAD_REQUEST);
|
||||||
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_TARGET_TYPE_IN_USE, CONFLICT);
|
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_TARGET_TYPE_IN_USE, CONFLICT);
|
||||||
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_TARGET_TYPE_INCOMPATIBLE, BAD_REQUEST);
|
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_TARGET_TYPE_INCOMPATIBLE, BAD_REQUEST);
|
||||||
|
|||||||
Reference in New Issue
Block a user