Prioritisation of assignments via mgmt-API (#895)
* Updating the schema for targetfilterquery and rollout * Updating the weight validation logic and tests * Make weight optional * Fix existing multi assignment tests by adding weight, remove weight from TargetFilterQuery * Add weight validation tests, fix tests * Add mgmt api tests for assignment and getting action with weight * Add management layer validation and tests for creating rollouts with weight * Fix amqp test, add repo level validation to resource tests * Add weight to rollout mgmt-api and tests * Add weight to mgmt api target Filter create and update * Add target filter auto assign weight. disable enforcement of setting a weight in multiassign mode * Remove ignored tests, fix api doc * Fix minor findings * Fix findings * Remove hardcoded min weight * Add docu text, fix findings * Fix api documentation * Expose weight via DMF * Expose actions according to weight via ddi * Fix documentation * Add method to get actions ordered by weight to deploymentManagement * Updating the schema for targetfilterquery and rollout * Updated the indentation * Updated the helper class, fixed the randomUID in test factory * Updated the class name with prefix JPA * Adding the missing License for WeightValidationHelper class * Adding documentation to the dmf api on weight * Removed the merger markers * Updated the class name * Removed the redundant method * Addressed final PR comments * Updated the missing testcase with latest default weight value * Reverting the default value of weight back to 1000 and updated tests Signed-off-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com> Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>
This commit is contained in:
committed by
Stefan Behl
parent
09f2d8a481
commit
9cb5d31396
@@ -212,6 +212,7 @@ public abstract class AbstractDsAssignmentStrategy {
|
||||
final JpaAction actionForTarget = new JpaAction();
|
||||
actionForTarget.setActionType(targetWithActionType.getActionType());
|
||||
actionForTarget.setForcedTime(targetWithActionType.getForceTime());
|
||||
actionForTarget.setWeight(targetWithActionType.getWeight());
|
||||
actionForTarget.setActive(true);
|
||||
actionForTarget.setTarget(target);
|
||||
actionForTarget.setDistributionSet(set);
|
||||
|
||||
@@ -28,7 +28,6 @@ import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.repository.EntityGraph;
|
||||
import org.springframework.data.jpa.repository.EntityGraph.EntityGraphType;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
@@ -101,20 +100,33 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
List<Action> findByTargetAndActiveOrderByIdAsc(JpaTarget target, boolean active);
|
||||
|
||||
/**
|
||||
* Retrieves the oldest {@link Action} that is active and referring to the
|
||||
* given {@link Target}.
|
||||
*
|
||||
* @param sort
|
||||
* order
|
||||
* Retrieves the active {@link Action}s with the highest weights that refer
|
||||
* to the given {@link Target}. If {@link Action}s have the same weight they
|
||||
* are ordered ascending by ID (oldest ones first).
|
||||
*
|
||||
* @param pageable
|
||||
* pageable
|
||||
* @param controllerId
|
||||
* the target to find assigned actions
|
||||
* @param active
|
||||
* the action active flag
|
||||
*
|
||||
* @return the found {@link Action}
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
@EntityGraph(value = "Action.ds", type = EntityGraphType.LOAD)
|
||||
Optional<Action> findFirstByTargetControllerIdAndActive(Sort sort, String controllerId, boolean active);
|
||||
Page<Action> findByTargetControllerIdAndActiveIsTrueAndWeightIsNotNullOrderByWeightDescIdAsc(Pageable pageable,
|
||||
String controllerId);
|
||||
|
||||
/**
|
||||
* Retrieves the active {@link Action}s with the lowest IDs (the oldest one)
|
||||
* whose weight is null and that that refers to the given {@link Target}.
|
||||
*
|
||||
* @param pageable
|
||||
* pageable
|
||||
* @param controllerId
|
||||
* the target to find assigned actions
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
@EntityGraph(value = "Action.ds", type = EntityGraphType.LOAD)
|
||||
Page<Action> findByTargetControllerIdAndActiveIsTrueAndWeightIsNullOrderByIdAsc(Pageable pageable,
|
||||
String controllerId);
|
||||
|
||||
/**
|
||||
* Checks if an active action exists for given
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
|
||||
/**
|
||||
* Implements utility methods for managing {@link Action}s
|
||||
*/
|
||||
public class JpaActionManagement {
|
||||
|
||||
protected final ActionRepository actionRepository;
|
||||
protected final RepositoryProperties repositoryProperties;
|
||||
|
||||
protected JpaActionManagement(final ActionRepository actionRepository,
|
||||
final RepositoryProperties repositoryProperties) {
|
||||
this.actionRepository = actionRepository;
|
||||
this.repositoryProperties = repositoryProperties;
|
||||
}
|
||||
|
||||
protected List<Action> findActiveActionsWithHighestWeightConsideringDefault(final String controllerId,
|
||||
final int maxActionCount) {
|
||||
if (!actionRepository.activeActionExistsForControllerId(controllerId)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final List<Action> actions = new ArrayList<>();
|
||||
final PageRequest pageable = PageRequest.of(0, maxActionCount);
|
||||
actions.addAll(actionRepository
|
||||
.findByTargetControllerIdAndActiveIsTrueAndWeightIsNotNullOrderByWeightDescIdAsc(pageable, controllerId)
|
||||
.getContent());
|
||||
actions.addAll(actionRepository
|
||||
.findByTargetControllerIdAndActiveIsTrueAndWeightIsNullOrderByIdAsc(pageable, controllerId)
|
||||
.getContent());
|
||||
final Comparator<Action> actionImportance = Comparator.comparingInt(this::getWeightConsideringDefault)
|
||||
.reversed().thenComparing(Action::getId);
|
||||
return actions.stream().sorted(actionImportance).limit(maxActionCount).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
protected int getWeightConsideringDefault(final Action action) {
|
||||
return action.getWeight().orElse(repositoryProperties.getActionWeightIfAbsent());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -110,7 +110,7 @@ import com.google.common.collect.Sets;
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
public class JpaControllerManagement implements ControllerManagement {
|
||||
public class JpaControllerManagement extends JpaActionManagement implements ControllerManagement {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JpaControllerManagement.class);
|
||||
|
||||
private final BlockingDeque<TargetPoll> queue;
|
||||
@@ -118,9 +118,6 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Autowired
|
||||
private ActionRepository actionRepository;
|
||||
|
||||
@Autowired
|
||||
private TargetRepository targetRepository;
|
||||
|
||||
@@ -157,10 +154,9 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
@Autowired
|
||||
private TenantAware tenantAware;
|
||||
|
||||
private final RepositoryProperties repositoryProperties;
|
||||
|
||||
JpaControllerManagement(final ScheduledExecutorService executorService,
|
||||
final RepositoryProperties repositoryProperties) {
|
||||
final RepositoryProperties repositoryProperties, final ActionRepository actionRepository) {
|
||||
super(actionRepository, repositoryProperties);
|
||||
|
||||
if (!repositoryProperties.isEagerPollPersistence()) {
|
||||
executorService.scheduleWithFixedDelay(this::flushUpdateQueue,
|
||||
@@ -171,8 +167,6 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
} else {
|
||||
queue = null;
|
||||
}
|
||||
|
||||
this.repositoryProperties = repositoryProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -346,23 +340,19 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Action> findOldestActiveActionByTarget(final String controllerId) {
|
||||
if (!actionRepository.activeActionExistsForControllerId(controllerId)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// used in favorite to findFirstByTargetAndActiveOrderByIdAsc due to
|
||||
// DATAJPA-841 issue.
|
||||
return actionRepository.findFirstByTargetControllerIdAndActive(new Sort(Direction.ASC, "id"), controllerId,
|
||||
true);
|
||||
public Optional<Action> findActiveActionWithHighestWeight(final String controllerId) {
|
||||
return findActiveActionsWithHighestWeight(controllerId, 1).stream().findFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Action> findActiveActionsByTarget(final Pageable pageable, final String controllerId) {
|
||||
if (!actionRepository.activeActionExistsForControllerId(controllerId)) {
|
||||
return Page.empty();
|
||||
}
|
||||
return actionRepository.findByActiveAndTarget(pageable, controllerId, true);
|
||||
public List<Action> findActiveActionsWithHighestWeight(final String controllerId,
|
||||
final int maxActionCount) {
|
||||
return findActiveActionsWithHighestWeightConsideringDefault(controllerId, maxActionCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWeightConsideringDefault(final Action action) {
|
||||
return super.getWeightConsideringDefault(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -376,7 +366,7 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteExistingTarget(@NotEmpty String controllerId) {
|
||||
public void deleteExistingTarget(@NotEmpty final String controllerId) {
|
||||
final Target target = targetRepository.findByControllerId(controllerId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
|
||||
targetRepository.deleteById(target.getId());
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
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 java.io.Serializable;
|
||||
@@ -38,6 +37,7 @@ import org.eclipse.hawkbit.repository.ActionFields;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryConstants;
|
||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
||||
@@ -57,6 +57,8 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.TenantConfigHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.WeightValidationHelper;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
@@ -103,7 +105,7 @@ import com.google.common.collect.Lists;
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
public class JpaDeploymentManagement extends JpaActionManagement implements DeploymentManagement {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JpaDeploymentManagement.class);
|
||||
|
||||
@@ -124,7 +126,6 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
}
|
||||
|
||||
private final EntityManager entityManager;
|
||||
private final ActionRepository actionRepository;
|
||||
private final DistributionSetRepository distributionSetRepository;
|
||||
private final TargetRepository targetRepository;
|
||||
private final ActionStatusRepository actionStatusRepository;
|
||||
@@ -146,9 +147,10 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
final EventPublisherHolder eventPublisherHolder, final AfterTransactionCommitExecutor afterCommit,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final Database database) {
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final Database database,
|
||||
final RepositoryProperties repositoryProperties) {
|
||||
super(actionRepository, repositoryProperties);
|
||||
this.entityManager = entityManager;
|
||||
this.actionRepository = actionRepository;
|
||||
this.distributionSetRepository = distributionSetRepository;
|
||||
this.targetRepository = targetRepository;
|
||||
this.actionStatusRepository = actionStatusRepository;
|
||||
@@ -194,6 +196,8 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
@Transactional(isolation = Isolation.READ_COMMITTED)
|
||||
public List<DistributionSetAssignmentResult> assignDistributionSets(
|
||||
final List<DeploymentRequest> deploymentRequests, final String actionMessage) {
|
||||
WeightValidationHelper.usingContext(systemSecurityContext, tenantConfigurationManagement)
|
||||
.validate(deploymentRequests);
|
||||
return assignDistributionSets(deploymentRequests, actionMessage, onlineDsAssignmentStrategy);
|
||||
}
|
||||
|
||||
@@ -275,8 +279,8 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
final AbstractDsAssignmentStrategy assignmentStrategy) {
|
||||
|
||||
final JpaDistributionSet distributionSetEntity = getAndValidateDsById(dsID);
|
||||
final List<String> targetIds = targetsWithActionType.stream().map(TargetWithActionType::getControllerId).distinct()
|
||||
.collect(Collectors.toList());
|
||||
final List<String> targetIds = targetsWithActionType.stream().map(TargetWithActionType::getControllerId)
|
||||
.distinct().collect(Collectors.toList());
|
||||
|
||||
final List<JpaTarget> targetEntities = assignmentStrategy.findTargetsForAssignment(targetIds,
|
||||
distributionSetEntity.getId());
|
||||
@@ -285,8 +289,8 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
return allTargetsAlreadyAssignedResult(distributionSetEntity, targetsWithActionType.size());
|
||||
}
|
||||
|
||||
final List<JpaAction> assignedActions = doAssignDistributionSetToTargets(targetsWithActionType,
|
||||
actionMessage, assignmentStrategy, distributionSetEntity, targetEntities);
|
||||
final List<JpaAction> assignedActions = doAssignDistributionSetToTargets(targetsWithActionType, actionMessage,
|
||||
assignmentStrategy, distributionSetEntity, targetEntities);
|
||||
return buildAssignmentResult(distributionSetEntity, assignedActions, targetsWithActionType.size());
|
||||
}
|
||||
|
||||
@@ -659,6 +663,16 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
return actionRepository.findByActiveAndTarget(pageable, controllerId, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> findActiveActionsWithHighestWeight(final String controllerId, final int maxActionCount) {
|
||||
return findActiveActionsWithHighestWeightConsideringDefault(controllerId, maxActionCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWeightConsideringDefault(final Action action) {
|
||||
return super.getWeightConsideringDefault(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countActionsByTarget(final String controllerId) {
|
||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||
@@ -823,7 +837,8 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
}
|
||||
|
||||
private boolean isMultiAssignmentsEnabled() {
|
||||
return getConfigValue(MULTI_ASSIGNMENTS_ENABLED, Boolean.class);
|
||||
return TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement)
|
||||
.isMultiAssignmentsEnabled();
|
||||
}
|
||||
|
||||
private <T extends Serializable> T getConfigValue(final String key, final Class<T> valueType) {
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.eclipse.hawkbit.repository.RolloutHelper;
|
||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutStatusCache;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericRolloutUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
|
||||
@@ -43,6 +44,8 @@ import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupCreatedEve
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
||||
import org.eclipse.hawkbit.repository.exception.NoWeightProvidedInMultiAssignmentModeException;
|
||||
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
@@ -57,6 +60,8 @@ import org.eclipse.hawkbit.repository.jpa.specifications.RolloutSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.WeightValidationHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.TenantConfigHelper;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
@@ -74,6 +79,7 @@ import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
|
||||
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -165,9 +171,12 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
final DistributionSetManagement distributionSetManagement, final ApplicationContext context,
|
||||
final EventPublisherHolder eventPublisherHolder, final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final PlatformTransactionManager txManager, final TenantAware tenantAware, final LockRegistry lockRegistry,
|
||||
final Database database, final RolloutApprovalStrategy rolloutApprovalStrategy) {
|
||||
final Database database, final RolloutApprovalStrategy rolloutApprovalStrategy,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
super(targetManagement, deploymentManagement, rolloutGroupManagement, distributionSetManagement, context,
|
||||
virtualPropertyReplacer, txManager, tenantAware, lockRegistry, rolloutApprovalStrategy);
|
||||
virtualPropertyReplacer, txManager, tenantAware, lockRegistry, rolloutApprovalStrategy,
|
||||
tenantConfigurationManagement, systemSecurityContext);
|
||||
this.eventPublisherHolder = eventPublisherHolder;
|
||||
this.database = database;
|
||||
}
|
||||
@@ -226,7 +235,7 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
}
|
||||
|
||||
private JpaRollout createRollout(final JpaRollout rollout) {
|
||||
|
||||
WeightValidationHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).validate(rollout);
|
||||
final Long totalTargets = targetManagement.countByRsql(rollout.getTargetFilterQuery());
|
||||
if (totalTargets == 0) {
|
||||
throw new ValidationException("Rollout does not match any existing targets");
|
||||
@@ -618,6 +627,7 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
action.setStatus(Status.SCHEDULED);
|
||||
action.setRollout(rollout);
|
||||
action.setRolloutGroup(rolloutGroup);
|
||||
rollout.getWeight().ifPresent(action::setWeight);
|
||||
actionRepository.save(action);
|
||||
});
|
||||
}
|
||||
@@ -1008,6 +1018,7 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
update.getDescription().ifPresent(rollout::setDescription);
|
||||
update.getActionType().ifPresent(rollout::setActionType);
|
||||
update.getForcedTime().ifPresent(rollout::setForcedTime);
|
||||
update.getWeight().ifPresent(rollout::setWeight);
|
||||
update.getStartAt().ifPresent(rollout::setStartAt);
|
||||
update.getSet().ifPresent(setId -> {
|
||||
final DistributionSet set = distributionSetManagement.get(setId)
|
||||
@@ -1136,5 +1147,4 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
QuotaHelper.assertAssignmentQuota(target.getId(), requested, quota, Action.class, Target.class,
|
||||
actionRepository::countByTargetId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFields;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryFields;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericTargetFilterQueryUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryUpdate;
|
||||
@@ -32,11 +34,14 @@ import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetFilterQuerySpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.WeightValidationHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.TenantConfigHelper;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
@@ -67,19 +72,24 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
private final QuotaManagement quotaManagement;
|
||||
private final TenantConfigurationManagement tenantConfigurationManagement;
|
||||
private final SystemSecurityContext systemSecurityContext;
|
||||
|
||||
private final Database database;
|
||||
|
||||
JpaTargetFilterQueryManagement(final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
final TargetRepository targetRepository, final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final DistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement,
|
||||
final Database database) {
|
||||
final Database database, final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
this.targetFilterQueryRepository = targetFilterQueryRepository;
|
||||
this.targetRepository = targetRepository;
|
||||
this.virtualPropertyReplacer = virtualPropertyReplacer;
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
this.quotaManagement = quotaManagement;
|
||||
this.database = database;
|
||||
this.tenantConfigurationManagement = tenantConfigurationManagement;
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,6 +102,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
// enforce the 'max targets per auto assign' quota right here even if
|
||||
// the result of the filter query can vary over time
|
||||
if (create.getAutoAssignDistributionSetId().isPresent()) {
|
||||
WeightValidationHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).validate(create);
|
||||
create.getQuery().ifPresent(this::assertMaxTargetsQuota);
|
||||
}
|
||||
|
||||
@@ -222,30 +233,26 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public TargetFilterQuery updateAutoAssignDSWithActionType(final long queryId, final Long dsId,
|
||||
final ActionType actionType) {
|
||||
final JpaTargetFilterQuery targetFilterQuery = findTargetFilterQueryOrThrowExceptionIfNotFound(queryId);
|
||||
|
||||
if (dsId == null) {
|
||||
public TargetFilterQuery updateAutoAssignDS(final AutoAssignDistributionSetUpdate update) {
|
||||
final JpaTargetFilterQuery targetFilterQuery = findTargetFilterQueryOrThrowExceptionIfNotFound(
|
||||
update.getTargetFilterId());
|
||||
if (update.getDsId() == null) {
|
||||
targetFilterQuery.setAutoAssignDistributionSet(null);
|
||||
targetFilterQuery.setAutoAssignActionType(null);
|
||||
targetFilterQuery.setAutoAssignWeight(null);
|
||||
} else {
|
||||
WeightValidationHelper.usingContext(systemSecurityContext, tenantConfigurationManagement).validate(update);
|
||||
// we cannot be sure that the quota was enforced at creation time
|
||||
// because the Target Filter Query REST API does not allow to
|
||||
// specify an
|
||||
// auto-assign distribution set when creating a target filter query
|
||||
assertMaxTargetsQuota(targetFilterQuery.getQuery());
|
||||
|
||||
final JpaDistributionSet distributionSetToAutoAssign = findDistributionSetAndThrowExceptionIfNotFound(dsId);
|
||||
// must be completed and not soft deleted
|
||||
verifyDistributionSetAndThrowExceptionIfNotValid(distributionSetToAutoAssign);
|
||||
|
||||
targetFilterQuery.setAutoAssignDistributionSet(distributionSetToAutoAssign);
|
||||
// the action type is set to FORCED per default (when not explicitly
|
||||
// specified)
|
||||
targetFilterQuery.setAutoAssignActionType(sanitizeAutoAssignActionType(actionType));
|
||||
final JpaDistributionSet ds = findDistributionSetAndThrowExceptionIfNotFound(update.getDsId());
|
||||
verifyDistributionSetAndThrowExceptionIfNotValid(ds);
|
||||
targetFilterQuery.setAutoAssignDistributionSet(ds);
|
||||
targetFilterQuery.setAutoAssignActionType(sanitizeAutoAssignActionType(update.getActionType()));
|
||||
targetFilterQuery.setAutoAssignWeight(update.getWeight());
|
||||
}
|
||||
|
||||
return targetFilterQueryRepository.save(targetFilterQuery);
|
||||
}
|
||||
|
||||
@@ -288,5 +295,4 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
targetRepository.count(RSQLUtility.parse(query, TargetFields.class, virtualPropertyReplacer, database)),
|
||||
quotaManagement.getMaxTargetsPerAutoAssignment(), Target.class, TargetFilterQuery.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -541,9 +541,11 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository, final TargetRepository targetRepository,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final DistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement,
|
||||
final JpaProperties properties) {
|
||||
final JpaProperties properties, final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
return new JpaTargetFilterQueryManagement(targetFilterQueryRepository, targetRepository,
|
||||
virtualPropertyReplacer, distributionSetManagement, quotaManagement, properties.getDatabase());
|
||||
virtualPropertyReplacer, distributionSetManagement, quotaManagement, properties.getDatabase(),
|
||||
tenantConfigurationManagement, systemSecurityContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -620,10 +622,13 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
final DistributionSetManagement distributionSetManagement, final ApplicationContext context,
|
||||
final EventPublisherHolder eventPublisherHolder, final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final PlatformTransactionManager txManager, final TenantAware tenantAware, final LockRegistry lockRegistry,
|
||||
final JpaProperties properties, final RolloutApprovalStrategy rolloutApprovalStrategy) {
|
||||
final JpaProperties properties, final RolloutApprovalStrategy rolloutApprovalStrategy,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
return new JpaRolloutManagement(targetManagement, deploymentManagement, rolloutGroupManagement,
|
||||
distributionSetManagement, context, eventPublisherHolder, virtualPropertyReplacer, txManager,
|
||||
tenantAware, lockRegistry, properties.getDatabase(), rolloutApprovalStrategy);
|
||||
tenantAware, lockRegistry, properties.getDatabase(), rolloutApprovalStrategy,
|
||||
tenantConfigurationManagement, systemSecurityContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -671,11 +676,11 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
final PlatformTransactionManager txManager,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware,
|
||||
final JpaProperties properties) {
|
||||
final JpaProperties properties, final RepositoryProperties repositoryProperties) {
|
||||
return new JpaDeploymentManagement(entityManager, actionRepository, distributionSetRepository, targetRepository,
|
||||
actionStatusRepository, auditorProvider, eventPublisherHolder, afterCommit, virtualPropertyReplacer,
|
||||
txManager, tenantConfigurationManagement, quotaManagement, systemSecurityContext, tenantAware,
|
||||
properties.getDatabase());
|
||||
properties.getDatabase(), repositoryProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -686,8 +691,8 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ControllerManagement controllerManagement(final ScheduledExecutorService executorService,
|
||||
final RepositoryProperties repositoryProperties) {
|
||||
return new JpaControllerManagement(executorService, repositoryProperties);
|
||||
final RepositoryProperties repositoryProperties, final ActionRepository actionRepository) {
|
||||
return new JpaControllerManagement(executorService, repositoryProperties, actionRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -97,6 +97,8 @@ public class AutoAssignChecker {
|
||||
|
||||
final Page<TargetFilterQuery> filterQueries = targetFilterQueryManagement.findWithAutoAssignDS(pageRequest);
|
||||
|
||||
// we should ensure that the filter queries are executed
|
||||
// in the order of weights
|
||||
for (final TargetFilterQuery filterQuery : filterQueries) {
|
||||
checkByTargetFilterQueryAndAssignDS(filterQuery);
|
||||
}
|
||||
@@ -143,7 +145,8 @@ public class AutoAssignChecker {
|
||||
return DeploymentHelper.runInNewTransaction(transactionManager, "autoAssignDSToTargets",
|
||||
Isolation.READ_COMMITTED.value(), status -> {
|
||||
final List<DeploymentRequest> deploymentRequests = createAssignmentRequests(
|
||||
targetFilterQuery.getQuery(), dsId, targetFilterQuery.getAutoAssignActionType(), PAGE_SIZE);
|
||||
targetFilterQuery.getQuery(), dsId, targetFilterQuery.getAutoAssignActionType(),
|
||||
targetFilterQuery.getAutoAssignWeight().orElse(null), PAGE_SIZE);
|
||||
final int count = deploymentRequests.size();
|
||||
if (count > 0) {
|
||||
deploymentManagement.assignDistributionSets(deploymentRequests, actionMessage);
|
||||
@@ -168,17 +171,15 @@ public class AutoAssignChecker {
|
||||
* @return list of targets with action type
|
||||
*/
|
||||
private List<DeploymentRequest> createAssignmentRequests(final String targetFilterQuery, final Long dsId,
|
||||
final ActionType type, final int count) {
|
||||
final ActionType type, final Integer weight, final int count) {
|
||||
final Page<Target> targets = targetManagement.findByTargetFilterQueryAndNonDS(PageRequest.of(0, count), dsId,
|
||||
targetFilterQuery);
|
||||
// the action type is set to FORCED per default (when not explicitly
|
||||
// specified)
|
||||
final ActionType autoAssignActionType = type == null ? ActionType.FORCED : type;
|
||||
|
||||
return targets.getContent().stream()
|
||||
.map(t -> DeploymentManagement.deploymentRequest(t.getControllerId(), dsId)
|
||||
.setActionType(autoAssignActionType).build())
|
||||
.collect(Collectors.toList());
|
||||
return targets.getContent().stream().map(t -> DeploymentManagement.deploymentRequest(t.getControllerId(), dsId)
|
||||
.setActionType(autoAssignActionType).setWeight(weight).build()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ public class JpaRolloutCreate extends AbstractRolloutUpdateCreate<RolloutCreate>
|
||||
rollout.setDistributionSet(findDistributionSetAndThrowExceptionIfNotFound(set));
|
||||
rollout.setTargetFilterQuery(targetFilterQuery);
|
||||
rollout.setStartAt(startAt);
|
||||
rollout.setWeight(weight);
|
||||
|
||||
if (actionType != null) {
|
||||
rollout.setActionType(actionType);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package org.eclipse.hawkbit.repository.jpa.builder;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericTargetFilterQueryUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryBuilder;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryCreate;
|
||||
@@ -36,4 +37,9 @@ public class JpaTargetFilterQueryBuilder implements TargetFilterQueryBuilder {
|
||||
return new JpaTargetFilterQueryCreate(distributionSetManagement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AutoAssignDistributionSetUpdate updateAutoAssign(final long id) {
|
||||
return new AutoAssignDistributionSetUpdate(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,8 @@ public class JpaTargetFilterQueryCreate extends AbstractTargetFilterQueryUpdateC
|
||||
|
||||
return new JpaTargetFilterQuery(name, query,
|
||||
getAutoAssignDistributionSetId().map(this::findDistributionSetAndThrowExceptionIfNotFound).orElse(null),
|
||||
getAutoAssignActionType().filter(JpaTargetFilterQueryCreate::isAutoAssignActionTypeValid).orElse(null));
|
||||
getAutoAssignActionType().filter(JpaTargetFilterQueryCreate::isAutoAssignActionTypeValid).orElse(null),
|
||||
weight);
|
||||
}
|
||||
|
||||
private DistributionSet findDistributionSetAndThrowExceptionIfNotFound(final Long setId) {
|
||||
|
||||
@@ -28,6 +28,8 @@ import javax.persistence.NamedEntityGraphs;
|
||||
import javax.persistence.NamedSubgraph;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper;
|
||||
@@ -89,6 +91,11 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
@Column(name = "forced_time")
|
||||
private long forcedTime;
|
||||
|
||||
@Column(name = "weight")
|
||||
@Min(Action.WEIGHT_MIN)
|
||||
@Max(Action.WEIGHT_MAX)
|
||||
private Integer weight;
|
||||
|
||||
@Column(name = "status", nullable = false)
|
||||
@ObjectTypeConverter(name = "status", objectType = Action.Status.class, dataType = Integer.class, conversionValues = {
|
||||
@ConversionValue(objectValue = "FINISHED", dataValue = "0"),
|
||||
@@ -126,7 +133,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
|
||||
@Column(name = "maintenance_time_zone", updatable = false, length = Action.MAINTENANCE_WINDOW_TIMEZONE_LENGTH)
|
||||
private String maintenanceWindowTimeZone;
|
||||
|
||||
|
||||
@Column(name = "external_ref", length = Action.EXTERNAL_REF_MAX_LENGTH)
|
||||
private String externalRef;
|
||||
|
||||
@@ -192,6 +199,15 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
this.forcedTime = forcedTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> getWeight() {
|
||||
return Optional.ofNullable(weight);
|
||||
}
|
||||
|
||||
public void setWeight(final Integer weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RolloutGroup getRolloutGroup() {
|
||||
return rolloutGroup;
|
||||
@@ -213,8 +229,8 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JpaAction [distributionSet=" + distributionSet.getId() + ", version=" + getOptLockRevision() + ", id="
|
||||
+ getId() + ", actionType=" + getActionType() + ", isActive=" + isActive() + ", createdAt="
|
||||
+ getCreatedAt() + ", lastModifiedAt=" + getLastModifiedAt() + "]";
|
||||
+ getId() + ", actionType=" + getActionType() + ", weight=" + getWeight() + ", isActive=" + isActive()
|
||||
+ ", createdAt=" + getCreatedAt() + ", lastModifiedAt=" + getLastModifiedAt() + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -337,7 +353,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExternalRef(String externalRef) {
|
||||
public void setExternalRef(final String externalRef) {
|
||||
this.externalRef = externalRef;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.jpa.model;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.Column;
|
||||
@@ -23,6 +24,8 @@ import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
@@ -90,7 +93,7 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
|
||||
@ConversionValue(objectValue = "DELETING", dataValue = "9"),
|
||||
@ConversionValue(objectValue = "DELETED", dataValue = "10"),
|
||||
@ConversionValue(objectValue = "WAITING_FOR_APPROVAL", dataValue = "11"),
|
||||
@ConversionValue(objectValue = "APPROVAL_DENIED", dataValue = "12")})
|
||||
@ConversionValue(objectValue = "APPROVAL_DENIED", dataValue = "12") })
|
||||
@Convert("rolloutstatus")
|
||||
@NotNull
|
||||
private RolloutStatus status = RolloutStatus.CREATING;
|
||||
@@ -131,6 +134,11 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
|
||||
@Size(max = Rollout.APPROVAL_REMARK_MAX_SIZE)
|
||||
private String approvalRemark;
|
||||
|
||||
@Column(name = "weight")
|
||||
@Min(Action.WEIGHT_MIN)
|
||||
@Max(Action.WEIGHT_MAX)
|
||||
private Integer weight;
|
||||
|
||||
@Transient
|
||||
private transient TotalTargetCountStatus totalTargetCountStatus;
|
||||
|
||||
@@ -204,6 +212,15 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
|
||||
this.forcedTime = forcedTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> getWeight() {
|
||||
return Optional.ofNullable(weight);
|
||||
}
|
||||
|
||||
public void setWeight(final Integer weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalTargets() {
|
||||
return totalTargets;
|
||||
@@ -299,5 +316,4 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
|
||||
public void setApprovalRemark(final String approvalRemark) {
|
||||
this.approvalRemark = approvalRemark;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.model;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ConstraintMode;
|
||||
import javax.persistence.Entity;
|
||||
@@ -66,11 +68,15 @@ public class JpaTargetFilterQuery extends AbstractJpaTenantAwareBaseEntity
|
||||
@ObjectTypeConverter(name = "autoAssignActionType", objectType = Action.ActionType.class, dataType = Integer.class, conversionValues = {
|
||||
@ConversionValue(objectValue = "FORCED", dataValue = "0"),
|
||||
@ConversionValue(objectValue = "SOFT", dataValue = "1"),
|
||||
// Conversion for 'TIMEFORCED' is disabled because it is not permitted in autoAssignment
|
||||
@ConversionValue(objectValue = "DOWNLOAD_ONLY", dataValue = "3")})
|
||||
// Conversion for 'TIMEFORCED' is disabled because it is not
|
||||
// permitted in autoAssignment
|
||||
@ConversionValue(objectValue = "DOWNLOAD_ONLY", dataValue = "3") })
|
||||
@Convert("autoAssignActionType")
|
||||
private ActionType autoAssignActionType;
|
||||
|
||||
@Column(name = "auto_assign_weight", nullable = true)
|
||||
private Integer autoAssignWeight;
|
||||
|
||||
public JpaTargetFilterQuery() {
|
||||
// Default constructor for JPA.
|
||||
}
|
||||
@@ -86,13 +92,16 @@ public class JpaTargetFilterQuery extends AbstractJpaTenantAwareBaseEntity
|
||||
* of the {@link TargetFilterQuery}.
|
||||
* @param autoAssignActionType
|
||||
* of the {@link TargetFilterQuery}.
|
||||
* @param autoAssignWeight
|
||||
* of the {@link TargetFilterQuery}.
|
||||
*/
|
||||
public JpaTargetFilterQuery(final String name, final String query, final DistributionSet autoAssignDistributionSet,
|
||||
final ActionType autoAssignActionType) {
|
||||
final ActionType autoAssignActionType, final Integer autoAssignWeight) {
|
||||
this.name = name;
|
||||
this.query = query;
|
||||
this.autoAssignDistributionSet = (JpaDistributionSet) autoAssignDistributionSet;
|
||||
this.autoAssignActionType = autoAssignActionType;
|
||||
this.autoAssignWeight = autoAssignWeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -131,6 +140,15 @@ public class JpaTargetFilterQuery extends AbstractJpaTenantAwareBaseEntity
|
||||
this.autoAssignActionType = actionType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> getAutoAssignWeight() {
|
||||
return Optional.ofNullable(autoAssignWeight);
|
||||
}
|
||||
|
||||
public void setAutoAssignWeight(final Integer weight) {
|
||||
this.autoAssignWeight = weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireCreateEvent(final DescriptorEvent descriptorEvent) {
|
||||
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.utils;
|
||||
|
||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED;
|
||||
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
|
||||
/**
|
||||
* A collection of static helper methods for the tenant configuration
|
||||
*/
|
||||
public final class TenantConfigHelper {
|
||||
|
||||
private final TenantConfigurationManagement tenantConfigurationManagement;
|
||||
private final SystemSecurityContext systemSecurityContext;
|
||||
|
||||
private TenantConfigHelper(final SystemSecurityContext systemSecurityContext,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
this.tenantConfigurationManagement = tenantConfigurationManagement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting the context of the tenant.
|
||||
*
|
||||
* @param systemSecurityContext
|
||||
* Security context used to get the tenant and for execution
|
||||
* @param tenantConfigurationManagement
|
||||
* to get the value from
|
||||
* @return is active
|
||||
*/
|
||||
public static TenantConfigHelper usingContext(final SystemSecurityContext systemSecurityContext,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
return new TenantConfigHelper(systemSecurityContext, tenantConfigurationManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is multi-assignments enabled for the current tenant
|
||||
*
|
||||
* @return is active
|
||||
*/
|
||||
public boolean isMultiAssignmentsEnabled() {
|
||||
return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement
|
||||
.getConfigurationValue(MULTI_ASSIGNMENTS_ENABLED, Boolean.class).getValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.utils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
||||
import org.eclipse.hawkbit.repository.exception.NoWeightProvidedInMultiAssignmentModeException;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetFilterQueryCreate;
|
||||
import org.eclipse.hawkbit.repository.model.DeploymentRequest;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
|
||||
/**
|
||||
* Utility class to handle weight validation in Rollout, Auto Assignments, and
|
||||
* Online Assignment.
|
||||
*/
|
||||
public final class WeightValidationHelper {
|
||||
|
||||
private final TenantConfigurationManagement tenantConfigurationManagement;
|
||||
private final SystemSecurityContext systemSecurityContext;
|
||||
|
||||
private WeightValidationHelper(final SystemSecurityContext systemSecurityContext,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
this.tenantConfigurationManagement = tenantConfigurationManagement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting the context of the tenant
|
||||
*
|
||||
* @param systemSecurityContext
|
||||
* security context used to get the tenant and for execution
|
||||
* @param tenantConfigurationManagement
|
||||
* to get the value from
|
||||
*/
|
||||
public static WeightValidationHelper usingContext(final SystemSecurityContext systemSecurityContext,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
return new WeightValidationHelper(systemSecurityContext, tenantConfigurationManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validating weights associated with all the {@link DeploymentRequest}s
|
||||
*
|
||||
* @param deploymentRequests
|
||||
* the {@linkplain List} of {@link DeploymentRequest}s
|
||||
*/
|
||||
public void validate(final List<DeploymentRequest> deploymentRequests) {
|
||||
final long assignmentsWithWeight = deploymentRequests.stream()
|
||||
.filter(request -> request.getTargetWithActionType().getWeight() != null).count();
|
||||
final boolean containsAssignmentWithWeight = assignmentsWithWeight > 0;
|
||||
final boolean containsAssignmentWithoutWeight = assignmentsWithWeight < deploymentRequests.size();
|
||||
|
||||
validateWeight(containsAssignmentWithWeight, containsAssignmentWithoutWeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validating weight associated with the {@link Rollout}
|
||||
*
|
||||
* @param rollout
|
||||
* the {@linkplain Rollout}
|
||||
*/
|
||||
public void validate(final Rollout rollout) {
|
||||
validateWeight(rollout.getWeight().orElse(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validating weight associated with the target filter query
|
||||
*
|
||||
* @param targetFilterQueryCreate
|
||||
* the target filter query
|
||||
*/
|
||||
public void validate(final JpaTargetFilterQueryCreate targetFilterQueryCreate) {
|
||||
validateWeight(targetFilterQueryCreate.getAutoAssignWeight().orElse(null));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validating weight associated with the auto assignment
|
||||
*
|
||||
* @param autoAssignDistributionSetUpdate
|
||||
* the auto assignment distribution set update
|
||||
*/
|
||||
public void validate(final AutoAssignDistributionSetUpdate autoAssignDistributionSetUpdate) {
|
||||
validateWeight(autoAssignDistributionSetUpdate.getWeight());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the weight is valid
|
||||
*
|
||||
* @param weight
|
||||
* weight tied to the rollout, auto assignment, or online
|
||||
* assignment.
|
||||
*/
|
||||
public void validateWeight(final Integer weight) {
|
||||
final boolean hasWeight = weight != null;
|
||||
validateWeight(hasWeight, !hasWeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the weight is valid with the multi-assignments being turned
|
||||
* off/on.
|
||||
*
|
||||
* @param hasWeight
|
||||
* indicator of the weight if it has numerical value
|
||||
* @param hasNoWeight
|
||||
* indicator of the weight if it doesn't have a numerical value
|
||||
*/
|
||||
public void validateWeight(final boolean hasWeight, final boolean hasNoWeight) {
|
||||
// remove bypassing the weight enforcement as soon as weight can be set
|
||||
// via UI
|
||||
final boolean bypassWeightEnforcement = true;
|
||||
final boolean multiAssignmentsEnabled = TenantConfigHelper
|
||||
.usingContext(systemSecurityContext, tenantConfigurationManagement).isMultiAssignmentsEnabled();
|
||||
if (!multiAssignmentsEnabled && hasWeight) {
|
||||
throw new MultiAssignmentIsNotEnabledException();
|
||||
} else if (bypassWeightEnforcement) {
|
||||
return;
|
||||
} else if (multiAssignmentsEnabled && hasNoWeight) {
|
||||
throw new NoWeightProvidedInMultiAssignmentModeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE sp_action ADD weight INT;
|
||||
ALTER TABLE sp_rollout ADD weight INT;
|
||||
ALTER TABLE sp_target_filter_query ADD auto_assign_weight INT;
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE sp_action ADD weight INT;
|
||||
ALTER TABLE sp_rollout ADD weight INT;
|
||||
ALTER TABLE sp_target_filter_query ADD auto_assign_weight INT;
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE sp_action ADD weight INT;
|
||||
ALTER TABLE sp_rollout ADD weight INT;
|
||||
ALTER TABLE sp_target_filter_query ADD auto_assign_weight INT;
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE sp_action ADD weight INT;
|
||||
ALTER TABLE sp_rollout ADD weight INT;
|
||||
ALTER TABLE sp_target_filter_query ADD auto_assign_weight INT;
|
||||
@@ -105,5 +105,4 @@ public class RemoteIdEventTest extends AbstractRemoteEventTest {
|
||||
// gets added because events inherit from of java.util.EventObject
|
||||
assertThat(underTestCreatedEvent).isEqualToIgnoringGivenFields(event, "source");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -98,5 +98,4 @@ public class RemoteTenantAwareEventTest extends AbstractRemoteEventTest {
|
||||
assertThat(actionProperties).isEqualToComparingFieldByField(new ActionProperties(action));
|
||||
assertThat(underTest.getDistributionSetId()).isEqualTo(action.getDistributionSet().getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(controllerManagement.getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(),
|
||||
module.getId())).isNotPresent();
|
||||
|
||||
assertThat(controllerManagement.findOldestActiveActionByTarget(NOT_EXIST_ID)).isNotPresent();
|
||||
assertThat(controllerManagement.findActiveActionWithHighestWeight(NOT_EXIST_ID)).isNotPresent();
|
||||
|
||||
assertThat(controllerManagement.hasTargetArtifactAssigned(target.getControllerId(), "XXX")).isFalse();
|
||||
assertThat(controllerManagement.hasTargetArtifactAssigned(target.getId(), "XXX")).isFalse();
|
||||
@@ -457,7 +457,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
.getContent();
|
||||
assertThat(actionStatusList.get(actionStatusList.size() - 1).getStatus()).isEqualTo(expectedActionStatus);
|
||||
if (actionActive) {
|
||||
assertThat(controllerManagement.findOldestActiveActionByTarget(controllerId).get().getId())
|
||||
assertThat(controllerManagement.findActiveActionWithHighestWeight(controllerId).get().getId())
|
||||
.isEqualTo(actionId);
|
||||
}
|
||||
}
|
||||
@@ -501,7 +501,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
@Description("Register a controller which does not exist")
|
||||
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetPollEvent.class, count = 2)})
|
||||
@Expect(type = TargetPollEvent.class, count = 2) })
|
||||
public void findOrRegisterTargetIfItDoesNotExist() {
|
||||
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST);
|
||||
assertThat(target).as("target should not be null").isNotNull();
|
||||
@@ -517,7 +517,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Expect(type = TargetPollEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 1) })
|
||||
public void findOrRegisterTargetIfItDoesNotExistWithName() {
|
||||
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName");
|
||||
final Target sameTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST,
|
||||
final Target sameTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST,
|
||||
"ChangedTestName");
|
||||
assertThat(target.getId()).as("Target should be the equals").isEqualTo(sameTarget.getId());
|
||||
assertThat(target.getName()).as("Taget names should be different").isNotEqualTo(sameTarget.getName());
|
||||
@@ -560,8 +560,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST));
|
||||
|
||||
verify(mockTargetRepository, times(TX_RT_MAX)).findOne(any());
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
// revert
|
||||
((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository);
|
||||
}
|
||||
@@ -597,22 +596,23 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
@Description("Register a controller which does not exist, then update the controller twice, first time by providing a name property and second time without a new name")
|
||||
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetPollEvent.class, count = 3) ,
|
||||
@Expect(type = TargetUpdatedEvent.class, count = 1)})
|
||||
@Expect(type = TargetPollEvent.class, count = 3), @Expect(type = TargetUpdatedEvent.class, count = 1) })
|
||||
public void findOrRegisterTargetIfItDoesNotExistDoesUpdateNameOnExistingTargetProperly() {
|
||||
|
||||
String controllerId = "12345";
|
||||
String targetName = "UpdatedName";
|
||||
final String controllerId = "12345";
|
||||
final String targetName = "UpdatedName";
|
||||
|
||||
final Target newTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId, LOCALHOST);
|
||||
final Target newTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId, LOCALHOST);
|
||||
assertThat(newTarget.getName()).isEqualTo(controllerId);
|
||||
|
||||
|
||||
Target firstTimeUpdatedTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId, LOCALHOST, targetName);
|
||||
final Target firstTimeUpdatedTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId,
|
||||
LOCALHOST, targetName);
|
||||
assertThat(firstTimeUpdatedTarget.getName()).isEqualTo(targetName);
|
||||
|
||||
//Name should not change to default (name=targetId) if target is updated without new name provided
|
||||
Target secondTimeUpdatedTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId, LOCALHOST);
|
||||
// Name should not change to default (name=targetId) if target is
|
||||
// updated without new name provided
|
||||
final Target secondTimeUpdatedTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId,
|
||||
LOCALHOST);
|
||||
assertThat(secondTimeUpdatedTarget.getName()).isEqualTo(targetName);
|
||||
}
|
||||
|
||||
@@ -633,8 +633,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist("1234", LOCALHOST));
|
||||
verify(mockTargetRepository, times(1)).findOne(any());
|
||||
verify(mockTargetRepository, times(1)).save(any());
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
// revert
|
||||
((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository);
|
||||
}
|
||||
@@ -651,13 +650,11 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
when(mockTargetRepository.findOne(any())).thenThrow(RuntimeException.class);
|
||||
|
||||
try {
|
||||
assertThatExceptionOfType(RuntimeException.class)
|
||||
.as("Expected a RuntimeException to be thrown!")
|
||||
assertThatExceptionOfType(RuntimeException.class).as("Expected a RuntimeException to be thrown!")
|
||||
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist("aControllerId",
|
||||
LOCALHOST));
|
||||
verify(mockTargetRepository, times(1)).findOne(any());
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
// revert
|
||||
((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository);
|
||||
}
|
||||
@@ -1054,9 +1051,8 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
Collections.singletonMap(keyValid, valueTooLong), null));
|
||||
|
||||
assertThatExceptionOfType(InvalidTargetAttributeException.class)
|
||||
.as("Attribute with key NULL should not be created")
|
||||
.isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId,
|
||||
Collections.singletonMap(keyNull, valueValid), null));
|
||||
.as("Attribute with key NULL should not be created").isThrownBy(() -> controllerManagement
|
||||
.updateControllerAttributes(controllerId, Collections.singletonMap(keyNull, valueValid), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1298,9 +1294,9 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(actionId).isNotNull();
|
||||
|
||||
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
||||
.as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates")
|
||||
.isThrownBy(() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement
|
||||
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))));
|
||||
.as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates").isThrownBy(
|
||||
() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement.addUpdateActionStatus(
|
||||
entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))));
|
||||
|
||||
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
||||
.as("No QuotaExceededException thrown for too many ERROR updateActionStatus updates")
|
||||
@@ -1326,18 +1322,18 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(actionId).isNotNull();
|
||||
|
||||
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
||||
.as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates")
|
||||
.isThrownBy( ()-> IntStream.range(0, maxMessages).forEach(i -> controllerManagement
|
||||
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))));
|
||||
.as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates").isThrownBy(
|
||||
() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement.addUpdateActionStatus(
|
||||
entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))));
|
||||
|
||||
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
||||
.as("No QuotaExceededException thrown for too many ERROR updateActionStatus updates")
|
||||
.isThrownBy(()->IntStream.range(0, maxMessages).forEach(i -> controllerManagement
|
||||
.isThrownBy(() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement
|
||||
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.ERROR))));
|
||||
|
||||
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
||||
.as("No QuotaExceededException thrown for too many FINISHED updateActionStatus updates")
|
||||
.isThrownBy(()->IntStream.range(0, maxMessages).forEach(i -> controllerManagement
|
||||
.isThrownBy(() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement
|
||||
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.FINISHED))));
|
||||
}
|
||||
|
||||
@@ -1472,6 +1468,39 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertActionStatus(actionId, controllerId, TargetUpdateStatus.IN_SYNC, actionStatus, actionStatus, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Actions are exposed according to thier weight in multi assignment mode.")
|
||||
public 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(entityFactory.actionStatus().create(actionWeightNull).status(Status.FINISHED));
|
||||
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId())
|
||||
.isEqualTo(actionWeight1000);
|
||||
controllerManagement
|
||||
.addUpdateActionStatus(entityFactory.actionStatus().create(actionWeight1000).status(Status.FINISHED));
|
||||
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId())
|
||||
.isEqualTo(actionWeight500old);
|
||||
controllerManagement
|
||||
.addUpdateActionStatus(entityFactory.actionStatus().create(actionWeight500old).status(Status.FINISHED));
|
||||
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId())
|
||||
.isEqualTo(actionWeight500new);
|
||||
controllerManagement
|
||||
.addUpdateActionStatus(entityFactory.actionStatus().create(actionWeight500new).status(Status.FINISHED));
|
||||
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId)).isEmpty();
|
||||
}
|
||||
|
||||
private void assertAssignedDistributionSetId(final String controllerId, final Long dsId) {
|
||||
final Optional<Target> target = controllerManagement.getByControllerId(controllerId);
|
||||
assertThat(target).isPresent();
|
||||
@@ -1494,12 +1523,10 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(actionRepository.activeActionExistsForControllerId(controllerId)).isEqualTo(false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@Description("Delete a target on requested target deletion from client side")
|
||||
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetPollEvent.class, count = 1),
|
||||
@Expect(type = TargetDeletedEvent.class, count = 1)})
|
||||
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetPollEvent.class, count = 1), @Expect(type = TargetDeletedEvent.class, count = 1) })
|
||||
public void deleteTargetWithValidThingId() {
|
||||
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST);
|
||||
assertThat(target).as("target should not be null").isNotNull();
|
||||
@@ -1512,7 +1539,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Description("Delete a target with a non existing thingId")
|
||||
@ExpectEvents({@Expect(type = TargetDeletedEvent.class, count = 0)})
|
||||
@ExpectEvents({ @Expect(type = TargetDeletedEvent.class, count = 0) })
|
||||
public void deleteTargetWithInvalidThingId() {
|
||||
assertThatExceptionOfType(EntityNotFoundException.class)
|
||||
.as("No EntityNotFoundException thrown when deleting a non-existing target")
|
||||
@@ -1522,9 +1549,8 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Description("Delete a target after it has been deleted already")
|
||||
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetPollEvent.class, count = 1),
|
||||
@Expect(type = TargetDeletedEvent.class, count = 1)})
|
||||
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetPollEvent.class, count = 1), @Expect(type = TargetDeletedEvent.class, count = 1) })
|
||||
public void deleteTargetAfterItWasDeleted() {
|
||||
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST);
|
||||
assertThat(target).as("target should not be null").isNotNull();
|
||||
|
||||
@@ -22,6 +22,8 @@ import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.eclipse.hawkbit.repository.ActionStatusFields;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
@@ -171,7 +173,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
||||
.isThrownBy(() -> assignDistributionSet(ds1, Collections.singletonList(testTarget)));
|
||||
.isThrownBy(() -> assignDistributionSet(ds1.getId(), testTarget.getControllerId(), 77));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -563,16 +565,17 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
public void previousAssignmentsAreNotCanceledInMultiAssignMode() {
|
||||
enableMultiAssignments();
|
||||
final List<Target> targets = testdataFactory.createTargets(10);
|
||||
final List<String> targetIds = targets.stream().map(Target::getControllerId).collect(Collectors.toList());
|
||||
|
||||
// First assignment
|
||||
final DistributionSet ds1 = testdataFactory.createDistributionSet("Multi-assign-1");
|
||||
assignDistributionSet(ds1, targets);
|
||||
assignDistributionSet(ds1.getId(), targetIds, 77);
|
||||
|
||||
assertDsExclusivelyAssignedToTargets(targets, ds1.getId(), STATE_ACTIVE, Status.RUNNING);
|
||||
|
||||
// Second assignment
|
||||
final DistributionSet ds2 = testdataFactory.createDistributionSet("Multi-assign-2");
|
||||
assignDistributionSet(ds2, targets);
|
||||
assignDistributionSet(ds2.getId(), targetIds, 45);
|
||||
|
||||
assertDsExclusivelyAssignedToTargets(targets, ds2.getId(), STATE_ACTIVE, Status.RUNNING);
|
||||
assertDsExclusivelyAssignedToTargets(targets, ds1.getId(), STATE_ACTIVE, Status.RUNNING);
|
||||
@@ -601,7 +604,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
public void multiassignmentInOneRequest() {
|
||||
final List<Target> targets = testdataFactory.createTargets(2);
|
||||
final List<DistributionSet> distributionSets = testdataFactory.createDistributionSets(2);
|
||||
final List<DeploymentRequest> deploymentRequests = createAssignmentRequests(distributionSets, targets);
|
||||
final List<DeploymentRequest> deploymentRequests = createAssignmentRequests(distributionSets, targets, 34);
|
||||
|
||||
enableMultiAssignments();
|
||||
final List<DistributionSetAssignmentResult> results = deploymentManagement
|
||||
@@ -614,7 +617,14 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
.stream().map(action -> action.getDistributionSet().getId()).collect(Collectors.toList());
|
||||
assertThat(assignedDsIds).containsExactlyInAnyOrderElementsOf(dsIds);
|
||||
});
|
||||
}
|
||||
|
||||
protected List<DeploymentRequest> createAssignmentRequests(final Collection<DistributionSet> distributionSets,
|
||||
final Collection<Target> targets, final int weight) {
|
||||
final List<DeploymentRequest> deploymentRequests = new ArrayList<>();
|
||||
distributionSets.forEach(ds -> targets.forEach(target -> deploymentRequests.add(DeploymentManagement
|
||||
.deploymentRequest(target.getControllerId(), ds.getId()).setWeight(weight).build())));
|
||||
return deploymentRequests;
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -624,9 +634,10 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
final List<DistributionSet> distributionSets = testdataFactory.createDistributionSets(2);
|
||||
|
||||
final DeploymentRequest targetToDS0 = DeploymentManagement
|
||||
.deploymentRequest(target.getControllerId(), distributionSets.get(0).getId()).build();
|
||||
.deploymentRequest(target.getControllerId(), distributionSets.get(0).getId()).setWeight(78).build();
|
||||
|
||||
final DeploymentRequest targetToDS1 = DeploymentManagement
|
||||
.deploymentRequest(target.getControllerId(), distributionSets.get(1).getId()).build();
|
||||
.deploymentRequest(target.getControllerId(), distributionSets.get(1).getId()).setWeight(565).build();
|
||||
|
||||
Assertions.assertThatExceptionOfType(MultiAssignmentIsNotEnabledException.class)
|
||||
.isThrownBy(() -> deploymentManagement.assignDistributionSets(Arrays.asList(targetToDS0, targetToDS1)));
|
||||
@@ -638,17 +649,26 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Description("Duplicate Assignments are removed from a request when multiassignment is disabled, otherwise not")
|
||||
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
|
||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
|
||||
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
|
||||
@Expect(type = ActionCreatedEvent.class, count = 3), @Expect(type = TargetUpdatedEvent.class, count = 2),
|
||||
@Expect(type = MultiActionEvent.class, count = 1) })
|
||||
public void duplicateAssignmentsInRequestAreOnlyRemovedIfMultiassignmentDisabled() {
|
||||
final Target target = testdataFactory.createTarget();
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||
final String targetId = testdataFactory.createTarget().getControllerId();
|
||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
||||
final List<DeploymentRequest> twoEqualAssignments = Collections.nCopies(2,
|
||||
DeploymentManagement.deploymentRequest(target.getControllerId(), ds.getId()).build());
|
||||
DeploymentManagement.deploymentRequest(targetId, dsId).build());
|
||||
|
||||
assertThat(getResultingActionCount(deploymentManagement.assignDistributionSets(twoEqualAssignments)))
|
||||
.isEqualTo(1);
|
||||
|
||||
enableMultiAssignments();
|
||||
assertThat(getResultingActionCount(deploymentManagement.assignDistributionSets(twoEqualAssignments)))
|
||||
final List<DeploymentRequest> twoEqualAssignmentsWithWeight = Collections.nCopies(2,
|
||||
DeploymentManagement.deploymentRequest(targetId, dsId).setWeight(555).build());
|
||||
|
||||
assertThat(getResultingActionCount(deploymentManagement.assignDistributionSets(twoEqualAssignmentsWithWeight)))
|
||||
.isEqualTo(2);
|
||||
}
|
||||
|
||||
@@ -668,7 +688,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
||||
|
||||
final List<DeploymentRequest> deploymentRequests = Collections.nCopies(maxActions + 1,
|
||||
DeploymentManagement.deploymentRequest(controllerId, dsId).build());
|
||||
DeploymentManagement.deploymentRequest(controllerId, dsId).setWeight(24).build());
|
||||
|
||||
enableMultiAssignments();
|
||||
Assertions.assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
||||
@@ -676,6 +696,67 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(actionRepository.countByTargetControllerId(controllerId)).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("An assignment request without a weight is ok when multi assignment in enabled.")
|
||||
public void weightNotRequiredInMultiAssignmentMode() {
|
||||
final String targetId = testdataFactory.createTarget().getControllerId();
|
||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
||||
|
||||
final DeploymentRequest assignWithoutWeight = DeploymentManagement.deploymentRequest(targetId, dsId).build();
|
||||
final DeploymentRequest assignWithWeight = DeploymentManagement.deploymentRequest(targetId, dsId).setWeight(567)
|
||||
.build();
|
||||
|
||||
enableMultiAssignments();
|
||||
deploymentManagement.assignDistributionSets(Arrays.asList(assignWithoutWeight, assignWithWeight));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("An assignment request containing a weight causes an error when multi assignment in disabled.")
|
||||
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
|
||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3) })
|
||||
public void weightNotAllowedWhenMultiAssignmentModeNotEnabled() {
|
||||
final String targetId = testdataFactory.createTarget().getControllerId();
|
||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
||||
|
||||
final DeploymentRequest assignWithoutWeight = DeploymentManagement.deploymentRequest(targetId, dsId)
|
||||
.setWeight(456).build();
|
||||
|
||||
Assertions.assertThatExceptionOfType(MultiAssignmentIsNotEnabledException.class).isThrownBy(
|
||||
() -> deploymentManagement.assignDistributionSets(Collections.singletonList(assignWithoutWeight)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Weights are validated and contained in the resulting Action.")
|
||||
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
|
||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
|
||||
@Expect(type = ActionCreatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 2),
|
||||
@Expect(type = MultiActionEvent.class, count = 2) })
|
||||
public void weightValidatedAndSaved() {
|
||||
final String targetId = testdataFactory.createTarget().getControllerId();
|
||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
||||
final DeploymentRequest valideRequest1 = DeploymentManagement.deploymentRequest(targetId, dsId)
|
||||
.setWeight(Action.WEIGHT_MAX).build();
|
||||
final DeploymentRequest valideRequest2 = DeploymentManagement.deploymentRequest(targetId, dsId)
|
||||
.setWeight(Action.WEIGHT_MIN).build();
|
||||
final DeploymentRequest weightTooLow = DeploymentManagement.deploymentRequest(targetId, dsId)
|
||||
.setWeight(Action.WEIGHT_MIN - 1).build();
|
||||
final DeploymentRequest weightTooHigh = DeploymentManagement.deploymentRequest(targetId, dsId)
|
||||
.setWeight(Action.WEIGHT_MAX + 1).build();
|
||||
enableMultiAssignments();
|
||||
Assertions.assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.isThrownBy(() -> deploymentManagement.assignDistributionSets(Collections.singletonList(weightTooLow)));
|
||||
Assertions.assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(
|
||||
() -> deploymentManagement.assignDistributionSets(Collections.singletonList(weightTooHigh)));
|
||||
final Long valideActionId1 = getFirstAssignedAction(
|
||||
deploymentManagement.assignDistributionSets(Collections.singletonList(valideRequest1)).get(0)).getId();
|
||||
final Long valideActionId2 = getFirstAssignedAction(
|
||||
deploymentManagement.assignDistributionSets(Collections.singletonList(valideRequest2)).get(0)).getId();
|
||||
assertThat(actionRepository.getById(valideActionId1).get().getWeight()).get().isEqualTo(Action.WEIGHT_MAX);
|
||||
assertThat(actionRepository.getById(valideActionId2).get().getWeight()).get().isEqualTo(Action.WEIGHT_MIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* test a simple deployment by calling the
|
||||
* {@link TargetRepository#assignDistributionSet(DistributionSet, Iterable)}
|
||||
@@ -1143,13 +1224,15 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Description("Tests the computation of already assigned entities returned as a result of an assignment")
|
||||
public void testAlreadyAssignedAndAssignedActionsInAssignmentResult(){
|
||||
// create target1, distributionSet, assign ds to target1 and finish update (close all actions)
|
||||
public void testAlreadyAssignedAndAssignedActionsInAssignmentResult() {
|
||||
// create target1, distributionSet, assign ds to target1 and finish
|
||||
// update (close all actions)
|
||||
final Action action = prepareFinishedUpdate("target1", "ds", false);
|
||||
final Target target2 = testdataFactory.createTarget("target2");
|
||||
final Target target3 = testdataFactory.createTarget("target3");
|
||||
|
||||
// assign ds to target2, but don't finish update (actions should be still open)
|
||||
// assign ds to target2, but don't finish update (actions should be
|
||||
// still open)
|
||||
assignDistributionSet(action.getDistributionSet().getId(), target2.getControllerId());
|
||||
|
||||
final DistributionSetAssignmentResult assignmentResult = assignDistributionSet(
|
||||
@@ -1283,7 +1366,5 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
public List<Long> getUndeployedTargetIDs() {
|
||||
return undeployedTargetIDs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,12 +17,15 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import javax.validation.ValidationException;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.api.Condition;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
|
||||
@@ -42,6 +45,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
@@ -126,7 +130,6 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
final Action rolloutCreatedAction = actionsByKnownTarget.stream()
|
||||
.filter(action -> !action.getId().equals(manuallyAssignedActionId)).findAny().get();
|
||||
assertThat(rolloutCreatedAction.getStatus()).isEqualTo(Status.FINISHED);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -599,7 +602,7 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
final String successCondition = "50";
|
||||
final String errorCondition = "80";
|
||||
final Rollout createdRollout = createSimpleTestRolloutWithTargetsAndDistributionSet(amountTargetsForRollout,
|
||||
amountOtherTargets, amountGroups, successCondition, errorCondition, ActionType.DOWNLOAD_ONLY);
|
||||
amountOtherTargets, amountGroups, successCondition, errorCondition, ActionType.DOWNLOAD_ONLY, null);
|
||||
|
||||
// targets have not started
|
||||
Map<TotalTargetCountStatus.Status, Long> validationMap = createInitStatusMap();
|
||||
@@ -619,7 +622,8 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
changeStatusForAllRunningActions(createdRollout, Status.DOWNLOADED);
|
||||
rolloutManagement.handleRollouts();
|
||||
// 4 targets are ready, 2 are finished(with DOWNLOADED action status) and 2 are running
|
||||
// 4 targets are ready, 2 are finished(with DOWNLOADED action status)
|
||||
// and 2 are running
|
||||
validationMap = createInitStatusMap();
|
||||
validationMap.put(TotalTargetCountStatus.Status.SCHEDULED, 4L);
|
||||
validationMap.put(TotalTargetCountStatus.Status.FINISHED, 2L);
|
||||
@@ -628,7 +632,8 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
changeStatusForAllRunningActions(createdRollout, Status.DOWNLOADED);
|
||||
rolloutManagement.handleRollouts();
|
||||
// 2 targets are ready, 4 are finished(with DOWNLOADED action status) and 2 are running
|
||||
// 2 targets are ready, 4 are finished(with DOWNLOADED action status)
|
||||
// and 2 are running
|
||||
validationMap = createInitStatusMap();
|
||||
validationMap.put(TotalTargetCountStatus.Status.SCHEDULED, 2L);
|
||||
validationMap.put(TotalTargetCountStatus.Status.FINISHED, 4L);
|
||||
@@ -637,7 +642,8 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
changeStatusForAllRunningActions(createdRollout, Status.DOWNLOADED);
|
||||
rolloutManagement.handleRollouts();
|
||||
// 0 targets are ready, 6 are finished(with DOWNLOADED action status) and 2 are running
|
||||
// 0 targets are ready, 6 are finished(with DOWNLOADED action status)
|
||||
// and 2 are running
|
||||
validationMap = createInitStatusMap();
|
||||
validationMap.put(TotalTargetCountStatus.Status.FINISHED, 6L);
|
||||
validationMap.put(TotalTargetCountStatus.Status.RUNNING, 2L);
|
||||
@@ -645,7 +651,8 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
changeStatusForAllRunningActions(createdRollout, Status.FINISHED);
|
||||
rolloutManagement.handleRollouts();
|
||||
// 0 targets are ready, 6 are finished(with DOWNLOADED action status), 2 are finished and 0 are running
|
||||
// 0 targets are ready, 6 are finished(with DOWNLOADED action status), 2
|
||||
// are finished and 0 are running
|
||||
validationMap = createInitStatusMap();
|
||||
validationMap.put(TotalTargetCountStatus.Status.FINISHED, 8L);
|
||||
validateRolloutActionStatus(createdRollout.getId(), validationMap);
|
||||
@@ -1745,14 +1752,80 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
// verify that all running actions keep running
|
||||
assertThat(actionRepository.findByRolloutIdAndStatus(PAGE, deletedRollout.getId(), Status.RUNNING)
|
||||
.getNumberOfElements()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Creating a rollout without weight value when multi assignment in enabled.")
|
||||
public void weightNotRequiredInMultiAssignmentMode() {
|
||||
enableMultiAssignments();
|
||||
createSimpleTestRolloutWithTargetsAndDistributionSet(10, 10, 2, "50", "80", ActionType.FORCED, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Creating a rollout with a weight causes an error when multi assignment in disabled.")
|
||||
public void weightNotAllowedWhenMultiAssignmentModeNotEnabled() {
|
||||
Assertions.assertThatExceptionOfType(MultiAssignmentIsNotEnabledException.class)
|
||||
.isThrownBy(() -> createSimpleTestRolloutWithTargetsAndDistributionSet(10, 10, 2, "50", "80",
|
||||
ActionType.FORCED, 66));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Weight is validated and saved to the Rollout.")
|
||||
public void weightValidatedAndSaved() {
|
||||
final String targetPrefix = UUID.randomUUID().toString();
|
||||
testdataFactory.createTargets(4, targetPrefix);
|
||||
enableMultiAssignments();
|
||||
|
||||
Assertions.assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.isThrownBy(() -> createTestRolloutWithTargetsAndDistributionSet(4, 2, "50", "80",
|
||||
UUID.randomUUID().toString(), UUID.randomUUID().toString(), Action.WEIGHT_MAX + 1));
|
||||
Assertions.assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.isThrownBy(() -> createTestRolloutWithTargetsAndDistributionSet(4, 2, "50", "80",
|
||||
UUID.randomUUID().toString(), UUID.randomUUID().toString(), Action.WEIGHT_MIN - 1));
|
||||
final Rollout createdRollout1 = createTestRolloutWithTargetsAndDistributionSet(4, 2, "50", "80",
|
||||
UUID.randomUUID().toString(), UUID.randomUUID().toString(), Action.WEIGHT_MAX);
|
||||
final Rollout createdRollout2 = createTestRolloutWithTargetsAndDistributionSet(4, 2, "50", "80",
|
||||
UUID.randomUUID().toString(), UUID.randomUUID().toString(), Action.WEIGHT_MIN);
|
||||
assertThat(rolloutRepository.findById(createdRollout1.getId()).get().getWeight()).get()
|
||||
.isEqualTo(Action.WEIGHT_MAX);
|
||||
assertThat(rolloutRepository.findById(createdRollout2.getId()).get().getWeight()).get()
|
||||
.isEqualTo(Action.WEIGHT_MIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("A Rollout with weight creats actions with weights")
|
||||
public void actionsWithWeightAreCreated() {
|
||||
final int amountOfTargets = 5;
|
||||
final int weight = 99;
|
||||
enableMultiAssignments();
|
||||
final Long rolloutId = createSimpleTestRolloutWithTargetsAndDistributionSet(amountOfTargets, 2, amountOfTargets,
|
||||
"80", "50", null, weight).getId();
|
||||
rolloutManagement.start(rolloutId);
|
||||
rolloutManagement.handleRollouts();
|
||||
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
|
||||
assertThat(actions).hasSize(amountOfTargets);
|
||||
assertThat(actions).allMatch(action -> action.getWeight().get() == weight);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Rollout can be created without weight in single assignment and be started in multi assignment")
|
||||
public void createInSingleStartInMultiassigMode() {
|
||||
final int amountOfTargets = 5;
|
||||
final Long rolloutId = createSimpleTestRolloutWithTargetsAndDistributionSet(amountOfTargets, 2, amountOfTargets,
|
||||
"80", "50", null, null).getId();
|
||||
|
||||
enableMultiAssignments();
|
||||
rolloutManagement.start(rolloutId);
|
||||
rolloutManagement.handleRollouts();
|
||||
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
|
||||
assertThat(actions).hasSize(amountOfTargets);
|
||||
assertThat(actions).allMatch(action -> !action.getWeight().isPresent());
|
||||
}
|
||||
|
||||
private RolloutGroupCreate generateRolloutGroup(final int index, final Integer percentage,
|
||||
final String targetFilter) {
|
||||
return entityFactory.rolloutGroup().create().name("Group" + index).description("Group" + index + "desc")
|
||||
.targetPercentage(Float.valueOf(percentage)).targetFilterQuery(targetFilter);
|
||||
|
||||
}
|
||||
|
||||
private RolloutCreate generateTargetsAndRollout(final String rolloutName, final int amountTargetsForRollout) {
|
||||
@@ -1790,27 +1863,35 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
final int amountOtherTargets, final int groupSize, final String successCondition,
|
||||
final String errorCondition) {
|
||||
return createSimpleTestRolloutWithTargetsAndDistributionSet(amountTargetsForRollout, amountOtherTargets,
|
||||
groupSize, successCondition, errorCondition, ActionType.FORCED);
|
||||
groupSize, successCondition, errorCondition, ActionType.FORCED, null);
|
||||
}
|
||||
|
||||
private Rollout createSimpleTestRolloutWithTargetsAndDistributionSet(final int amountTargetsForRollout,
|
||||
final int amountOtherTargets, final int groupSize, final String successCondition,
|
||||
final String errorCondition, final ActionType actionType) {
|
||||
final String errorCondition, final ActionType actionType, final Integer weight) {
|
||||
final DistributionSet rolloutDS = testdataFactory.createDistributionSet("rolloutDS");
|
||||
testdataFactory.createTargets(amountTargetsForRollout, "rollout-", "rollout");
|
||||
testdataFactory.createTargets(amountOtherTargets, "others-", "rollout");
|
||||
final String filterQuery = "controllerId==rollout-*";
|
||||
return testdataFactory.createRolloutByVariables("test-rollout-name-1", "test-rollout-description-1", groupSize,
|
||||
filterQuery, rolloutDS, successCondition, errorCondition, actionType);
|
||||
filterQuery, rolloutDS, successCondition, errorCondition, actionType, weight);
|
||||
}
|
||||
|
||||
private Rollout createTestRolloutWithTargetsAndDistributionSet(final int amountTargetsForRollout,
|
||||
final int groupSize, final String successCondition, final String errorCondition, final String rolloutName,
|
||||
final String targetPrefixName) {
|
||||
return createTestRolloutWithTargetsAndDistributionSet(amountTargetsForRollout, groupSize, successCondition,
|
||||
errorCondition, rolloutName, targetPrefixName, null);
|
||||
}
|
||||
|
||||
private Rollout createTestRolloutWithTargetsAndDistributionSet(final int amountTargetsForRollout,
|
||||
final int groupSize, final String successCondition, final String errorCondition, final String rolloutName,
|
||||
final String targetPrefixName, final Integer weight) {
|
||||
final DistributionSet dsForRolloutTwo = testdataFactory.createDistributionSet("dsFor" + rolloutName);
|
||||
testdataFactory.createTargets(amountTargetsForRollout, targetPrefixName + "-", targetPrefixName);
|
||||
return testdataFactory.createRolloutByVariables(rolloutName, rolloutName + "description", groupSize,
|
||||
"controllerId==" + targetPrefixName + "-*", dsForRolloutTwo, successCondition, errorCondition);
|
||||
"controllerId==" + targetPrefixName + "-*", dsForRolloutTwo, successCondition, errorCondition,
|
||||
Action.ActionType.FORCED, weight);
|
||||
}
|
||||
|
||||
private int changeStatusForAllRunningActions(final Rollout rollout, final Status status) {
|
||||
|
||||
@@ -20,6 +20,9 @@ import static org.junit.Assert.fail;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||
@@ -28,8 +31,10 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetFilterQueryCreat
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
@@ -82,13 +87,18 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
|
||||
verifyThrownExceptionBy(
|
||||
() -> targetFilterQueryManagement.update(entityFactory.targetFilterQuery().update(NOT_EXIST_IDL)),
|
||||
"TargetFilterQuery");
|
||||
verifyThrownExceptionBy(
|
||||
() -> targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(), NOT_EXIST_IDL),
|
||||
|
||||
verifyThrownExceptionBy(() -> targetFilterQueryManagement.updateAutoAssignDS(
|
||||
entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId()).ds(NOT_EXIST_IDL)),
|
||||
"DistributionSet");
|
||||
verifyThrownExceptionBy(() -> targetFilterQueryManagement.updateAutoAssignDS(NOT_EXIST_IDL, set.getId()),
|
||||
"TargetFilterQuery");
|
||||
|
||||
verifyThrownExceptionBy(
|
||||
() -> targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(), NOT_EXIST_IDL),
|
||||
() -> targetFilterQueryManagement.updateAutoAssignDS(
|
||||
entityFactory.targetFilterQuery().updateAutoAssign(NOT_EXIST_IDL).ds(set.getId())),
|
||||
"TargetFilterQuery");
|
||||
|
||||
verifyThrownExceptionBy(() -> targetFilterQueryManagement.updateAutoAssignDS(
|
||||
entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId()).ds(NOT_EXIST_IDL)),
|
||||
"DistributionSet");
|
||||
}
|
||||
|
||||
@@ -208,23 +218,26 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
|
||||
@Step
|
||||
private void verifyAutoAssignmentWithDefaultActionType(final String filterName,
|
||||
final TargetFilterQuery targetFilterQuery, final DistributionSet distributionSet) {
|
||||
targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(), distributionSet.getId());
|
||||
targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
|
||||
.updateAutoAssign(targetFilterQuery.getId()).ds(distributionSet.getId()));
|
||||
verifyAutoAssignDsAndActionType(filterName, distributionSet, ActionType.FORCED);
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyAutoAssignmentWithSoftActionType(final String filterName,
|
||||
final TargetFilterQuery targetFilterQuery, final DistributionSet distributionSet) {
|
||||
targetFilterQueryManagement.updateAutoAssignDSWithActionType(targetFilterQuery.getId(), distributionSet.getId(),
|
||||
ActionType.SOFT);
|
||||
targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
|
||||
.updateAutoAssign(targetFilterQuery.getId()).ds(distributionSet.getId()).actionType(ActionType.SOFT));
|
||||
verifyAutoAssignDsAndActionType(filterName, distributionSet, ActionType.SOFT);
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyAutoAssignmentWithDownloadOnlyActionType(final String filterName,
|
||||
final TargetFilterQuery targetFilterQuery, final DistributionSet distributionSet) {
|
||||
targetFilterQueryManagement.updateAutoAssignDSWithActionType(targetFilterQuery.getId(), distributionSet.getId(),
|
||||
ActionType.DOWNLOAD_ONLY);
|
||||
targetFilterQueryManagement
|
||||
.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId())
|
||||
.ds(distributionSet.getId()).actionType(ActionType.DOWNLOAD_ONLY));
|
||||
|
||||
verifyAutoAssignDsAndActionType(filterName, distributionSet, ActionType.DOWNLOAD_ONLY);
|
||||
}
|
||||
|
||||
@@ -233,9 +246,11 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
|
||||
final DistributionSet distributionSet) {
|
||||
// assigning a distribution set with TIMEFORCED action is supposed to
|
||||
// fail as only FORCED and SOFT action types are allowed
|
||||
assertThatExceptionOfType(InvalidAutoAssignActionTypeException.class).isThrownBy(
|
||||
() -> targetFilterQueryManagement.updateAutoAssignDSWithActionType(targetFilterQuery.getId(),
|
||||
distributionSet.getId(), ActionType.TIMEFORCED));
|
||||
|
||||
assertThatExceptionOfType(InvalidAutoAssignActionTypeException.class)
|
||||
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(
|
||||
entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId())
|
||||
.ds(distributionSet.getId()).actionType(ActionType.TIMEFORCED)));
|
||||
}
|
||||
|
||||
@Step
|
||||
@@ -245,8 +260,8 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
|
||||
.type(testdataFactory.findOrCreateDefaultTestDsType()));
|
||||
|
||||
assertThatExceptionOfType(InvalidAutoAssignDistributionSetException.class)
|
||||
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(),
|
||||
incompleteDistributionSet.getId()));
|
||||
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
|
||||
.updateAutoAssign(targetFilterQuery.getId()).ds(incompleteDistributionSet.getId())));
|
||||
}
|
||||
|
||||
@Step
|
||||
@@ -255,8 +270,9 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
|
||||
assignDistributionSet(softDeletedDs, testdataFactory.createTarget("forSoftDeletedDs"));
|
||||
distributionSetManagement.delete(softDeletedDs.getId());
|
||||
|
||||
assertThatExceptionOfType(InvalidAutoAssignDistributionSetException.class).isThrownBy(
|
||||
() -> targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(), softDeletedDs.getId()));
|
||||
assertThatExceptionOfType(InvalidAutoAssignDistributionSetException.class)
|
||||
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
|
||||
.updateAutoAssign(targetFilterQuery.getId()).ds(softDeletedDs.getId())));
|
||||
}
|
||||
|
||||
private void verifyAutoAssignDsAndActionType(final String filterName, final DistributionSet distributionSet,
|
||||
@@ -282,8 +298,10 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
|
||||
|
||||
// assigning a distribution set is supposed to fail as the query
|
||||
// addresses too many targets
|
||||
assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> targetFilterQueryManagement
|
||||
.updateAutoAssignDS(targetFilterQuery.getId(), distributionSet.getId()));
|
||||
|
||||
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
|
||||
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
|
||||
.updateAutoAssign(targetFilterQuery.getId()).ds(distributionSet.getId())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -313,7 +331,8 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
|
||||
|
||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
|
||||
|
||||
targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(), distributionSet.getId());
|
||||
targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
|
||||
.updateAutoAssign(targetFilterQuery.getId()).ds(distributionSet.getId()));
|
||||
|
||||
// Check if target filter query is there
|
||||
TargetFilterQuery tfq = targetFilterQueryManagement.getByName(filterName).get();
|
||||
@@ -340,9 +359,11 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
|
||||
// later step
|
||||
assignDistributionSet(distributionSet.getId(), target.getControllerId());
|
||||
|
||||
targetFilterQueryManagement.updateAutoAssignDS(targetFilterQueryManagement
|
||||
final Long filterId = targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name(filterName).query("name==PendingTargets001"))
|
||||
.getId(), distributionSet.getId());
|
||||
.getId();
|
||||
targetFilterQueryManagement.updateAutoAssignDS(
|
||||
entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(distributionSet.getId()));
|
||||
|
||||
// Check if target filter query is there with the distribution set
|
||||
TargetFilterQuery tfq = targetFilterQueryManagement.getByName(filterName).get();
|
||||
@@ -372,20 +393,18 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
|
||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
|
||||
final DistributionSet distributionSet2 = testdataFactory.createDistributionSet("2");
|
||||
|
||||
final TargetFilterQuery tfq = targetFilterQueryManagement.updateAutoAssignDSWithActionType(
|
||||
targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name("c").query("name==x")).getId(),
|
||||
distributionSet.getId(), ActionType.SOFT);
|
||||
final TargetFilterQuery tfq2 = targetFilterQueryManagement.updateAutoAssignDS(
|
||||
targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name(filterName).query("name==z*")).getId(),
|
||||
distributionSet2.getId());
|
||||
final TargetFilterQuery tfq = targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name("c").query("name==x")
|
||||
.autoAssignDistributionSet(distributionSet).autoAssignActionType(ActionType.SOFT));
|
||||
final TargetFilterQuery tfq2 = targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create()
|
||||
.name(filterName).query("name==z*").autoAssignDistributionSet(distributionSet2));
|
||||
assertEquals(4L, targetFilterQueryManagement.count());
|
||||
|
||||
// check if find works
|
||||
verifyFindByDistributionSetAndRsql(distributionSet, null, tfq);
|
||||
|
||||
targetFilterQueryManagement.updateAutoAssignDS(tfq2.getId(), distributionSet.getId());
|
||||
targetFilterQueryManagement.updateAutoAssignDS(
|
||||
entityFactory.targetFilterQuery().updateAutoAssign(tfq2.getId()).ds(distributionSet.getId()));
|
||||
|
||||
// check if find works for two
|
||||
verifyFindByDistributionSetAndRsql(distributionSet, null, tfq, tfq2);
|
||||
@@ -421,4 +440,73 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
|
||||
|
||||
verifyExpectedFilterQueriesInList(tfqList, expectedFilterQueries);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Creating or updating a target filter query with autoassignment and no-value weight when multi assignment in enabled.")
|
||||
public void weightNotRequiredInMultiAssignmentMode() {
|
||||
enableMultiAssignments();
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||
final Long filterId = targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name("a").query("name==*")).getId();
|
||||
|
||||
targetFilterQueryManagement.create(
|
||||
entityFactory.targetFilterQuery().create().name("b").query("name==*").autoAssignDistributionSet(ds));
|
||||
targetFilterQueryManagement
|
||||
.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(ds.getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Creating or updating a target filter query with autoassignment with a weight causes an error when multi assignment in disabled.")
|
||||
public void weightNotAllowedWhenMultiAssignmentModeNotEnabled() {
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||
final Long filterId = targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name("a").query("name==*")).getId();
|
||||
|
||||
Assertions.assertThatExceptionOfType(MultiAssignmentIsNotEnabledException.class)
|
||||
.isThrownBy(() -> targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create()
|
||||
.name("b").query("name==*").autoAssignDistributionSet(ds).autoAssignWeight(342)));
|
||||
Assertions.assertThatExceptionOfType(MultiAssignmentIsNotEnabledException.class)
|
||||
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(
|
||||
entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(ds.getId()).weight(343)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Auto assignment can be removed from filter when multi assignment in enabled.")
|
||||
public void removeDsFromFilterWhenMultiAssignmentModeNotEnabled() {
|
||||
enableMultiAssignments();
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||
final Long filterId = targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name("a")
|
||||
.query("name==*").autoAssignDistributionSet(ds).autoAssignWeight(23)).getId();
|
||||
targetFilterQueryManagement
|
||||
.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(null).weight(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Weight is validated and saved to the Filter.")
|
||||
public void weightValidatedAndSaved() {
|
||||
enableMultiAssignments();
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||
|
||||
Assertions.assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(
|
||||
() -> targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name("a")
|
||||
.query("name==*").autoAssignDistributionSet(ds).autoAssignWeight(Action.WEIGHT_MAX + 1)));
|
||||
|
||||
final Long filterId = targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name("a")
|
||||
.query("name==*").autoAssignDistributionSet(ds).autoAssignWeight(Action.WEIGHT_MAX)).getId();
|
||||
assertThat(targetFilterQueryManagement.get(filterId).get().getAutoAssignWeight().get())
|
||||
.isEqualTo(Action.WEIGHT_MAX);
|
||||
|
||||
Assertions.assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
|
||||
.updateAutoAssign(filterId).ds(ds.getId()).weight(Action.WEIGHT_MAX + 1)));
|
||||
Assertions.assertThatExceptionOfType(ConstraintViolationException.class)
|
||||
.isThrownBy(() -> targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
|
||||
.updateAutoAssign(filterId).ds(ds.getId()).weight(Action.WEIGHT_MIN - 1)));
|
||||
targetFilterQueryManagement.updateAutoAssignDS(
|
||||
entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(ds.getId()).weight(Action.WEIGHT_MAX));
|
||||
targetFilterQueryManagement.updateAutoAssignDS(
|
||||
entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(ds.getId()).weight(Action.WEIGHT_MIN));
|
||||
assertThat(targetFilterQueryManagement.get(filterId).get().getAutoAssignWeight().get())
|
||||
.isEqualTo(Action.WEIGHT_MIN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,8 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
// try to find several targets with different filter settings
|
||||
verifyThat1TargetHasNameAndId("targ-A-special", targSpecialName.getControllerId());
|
||||
verifyThat1TargetHasAttributeValue("%c-attribute%", targAttribute.getControllerId());
|
||||
verifyThat1TargetHasAttributeValue("%" + targAttributeId.getControllerId() + "%", targAttributeId.getControllerId());
|
||||
verifyThat1TargetHasAttributeValue("%" + targAttributeId.getControllerId() + "%",
|
||||
targAttributeId.getControllerId());
|
||||
verifyThatRepositoryContains400Targets();
|
||||
verifyThat200TargetsHaveTagD(targTagW, concat(targBs, targCs));
|
||||
verifyThat100TargetsContainsGivenTextAndHaveTagAssigned(targTagY, targTagW, targBs);
|
||||
|
||||
@@ -63,8 +63,8 @@ public class AutoAssignCheckerTest extends AbstractJpaIntegrationTest {
|
||||
// target filter query that matches all targets
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name("filterA").query("name==*"));
|
||||
targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(), secondDistributionSet.getId());
|
||||
|
||||
targetFilterQueryManagement.updateAutoAssignDS(entityFactory.targetFilterQuery()
|
||||
.updateAutoAssign(targetFilterQuery.getId()).ds(secondDistributionSet.getId()));
|
||||
// Run the check
|
||||
autoAssignChecker.check();
|
||||
|
||||
@@ -101,7 +101,8 @@ public class AutoAssignCheckerTest extends AbstractJpaIntegrationTest {
|
||||
// target filter query that matches all targets
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name("filterA").query("name==*"));
|
||||
targetFilterQueryManagement.updateAutoAssignDS(targetFilterQuery.getId(), setA.getId());
|
||||
targetFilterQueryManagement.updateAutoAssignDS(
|
||||
entityFactory.targetFilterQuery().updateAutoAssign(targetFilterQuery.getId()).ds(setA.getId()));
|
||||
|
||||
final String targetDsAIdPref = "targ";
|
||||
final List<Target> targets = testdataFactory.createTargets(100, targetDsAIdPref,
|
||||
@@ -150,18 +151,16 @@ public class AutoAssignCheckerTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
// target filter query that matches first bunch of targets, that should
|
||||
// fail
|
||||
assertThatExceptionOfType(
|
||||
InvalidAutoAssignDistributionSetException.class)
|
||||
.isThrownBy(
|
||||
() -> targetFilterQueryManagement.updateAutoAssignDS(
|
||||
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create()
|
||||
.name("filterA").query("id==" + targetDsFIdPref + "*")).getId(),
|
||||
setF.getId()));
|
||||
|
||||
assertThatExceptionOfType(InvalidAutoAssignDistributionSetException.class).isThrownBy(() -> {
|
||||
final Long filterId = targetFilterQueryManagement.create(
|
||||
entityFactory.targetFilterQuery().create().name("filterA").query("id==" + targetDsFIdPref + "*"))
|
||||
.getId();
|
||||
targetFilterQueryManagement
|
||||
.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(setF.getId()));
|
||||
});
|
||||
// target filter query that matches failed bunch of targets
|
||||
targetFilterQueryManagement.updateAutoAssignDS(targetFilterQueryManagement.create(
|
||||
entityFactory.targetFilterQuery().create().name("filterB").query("id==" + targetDsAIdPref + "*"))
|
||||
.getId(), setA.getId());
|
||||
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name("filterB")
|
||||
.query("id==" + targetDsAIdPref + "*").autoAssignDistributionSet(setA.getId()));
|
||||
|
||||
final List<Target> targetsF = testdataFactory.createTargets(10, targetDsFIdPref,
|
||||
targetDsFIdPref.concat(" description"));
|
||||
@@ -243,12 +242,10 @@ public class AutoAssignCheckerTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
final List<Target> targets = testdataFactory.createTargets(targetCount, "target" + prefix,
|
||||
prefix.concat(" description"));
|
||||
targetFilterQueryManagement.create(
|
||||
entityFactory.targetFilterQuery().create().name("filter" + prefix).query("id==target" + prefix + "*")
|
||||
.autoAssignDistributionSet(distributionSet).autoAssignActionType(actionType));
|
||||
|
||||
targetFilterQueryManagement
|
||||
.updateAutoAssignDSWithActionType(
|
||||
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create()
|
||||
.name("filter" + prefix).query("id==target" + prefix + "*")).getId(),
|
||||
distributionSet.getId(), actionType);
|
||||
return targets;
|
||||
}
|
||||
|
||||
@@ -262,4 +259,38 @@ public class AutoAssignCheckerTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(actions).allMatch(action -> action.getActionType().equals(actionType));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("An auto assignment target filter with weight creats actions with weights")
|
||||
public void actionsWithWeightAreCreated() throws Exception {
|
||||
final int amountOfTargets = 5;
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||
final int weight = 32;
|
||||
enableMultiAssignments();
|
||||
|
||||
targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name("a").query("name==*")
|
||||
.autoAssignDistributionSet(ds).autoAssignWeight(weight));
|
||||
testdataFactory.createTargets(amountOfTargets);
|
||||
autoAssignChecker.check();
|
||||
|
||||
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
|
||||
assertThat(actions).hasSize(amountOfTargets);
|
||||
assertThat(actions).allMatch(action -> action.getWeight().get() == weight);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("An auto assignment target filter without weight still works after multi assignment is enabled")
|
||||
public void filterWithoutWeightWorksInMultiAssignmentMode() throws Exception {
|
||||
final int amountOfTargets = 5;
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||
targetFilterQueryManagement.create(
|
||||
entityFactory.targetFilterQuery().create().name("a").query("name==*").autoAssignDistributionSet(ds));
|
||||
enableMultiAssignments();
|
||||
|
||||
testdataFactory.createTargets(amountOfTargets);
|
||||
autoAssignChecker.check();
|
||||
|
||||
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
|
||||
assertThat(actions).hasSize(amountOfTargets);
|
||||
assertThat(actions).allMatch(action -> !action.getWeight().isPresent());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ public class RSQLActionFieldsTest extends AbstractJpaIntegrationTest {
|
||||
action.setDistributionSet(dsA);
|
||||
action.setTarget(target);
|
||||
action.setStatus(Status.RUNNING);
|
||||
action.setWeight(45);
|
||||
target.addAction(action);
|
||||
|
||||
actionRepository.save(action);
|
||||
@@ -56,6 +57,7 @@ public class RSQLActionFieldsTest extends AbstractJpaIntegrationTest {
|
||||
newAction.setActive(i % 2 == 0);
|
||||
newAction.setStatus(Status.RUNNING);
|
||||
newAction.setTarget(target);
|
||||
newAction.setWeight(45);
|
||||
actionRepository.save(newAction);
|
||||
target.addAction(newAction);
|
||||
}
|
||||
|
||||
@@ -41,14 +41,10 @@ public class RSQLTargetFilterQueryFieldsTest extends AbstractJpaIntegrationTest
|
||||
final DistributionSet ds1 = testdataFactory.createDistributionSet("AutoAssignedDs_1");
|
||||
final DistributionSet ds2 = testdataFactory.createDistributionSet("AutoAssignedDs_2");
|
||||
|
||||
filter1 = targetFilterQueryManagement.updateAutoAssignDSWithActionType(
|
||||
targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name(filterName1).query("name==*")).getId(),
|
||||
ds1.getId(), ActionType.SOFT);
|
||||
filter2 = targetFilterQueryManagement.updateAutoAssignDS(
|
||||
targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name(filterName2).query("name==*")).getId(),
|
||||
ds2.getId());
|
||||
filter1 = targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name(filterName1)
|
||||
.query("name==*").autoAssignDistributionSet(ds1).autoAssignActionType(ActionType.SOFT));
|
||||
filter2 = targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name(filterName2)
|
||||
.query("name==*").autoAssignDistributionSet(ds2));
|
||||
targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name(filterName3).query("name==*"));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user