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;
|
||||
Reference in New Issue
Block a user