Fix circular rollout dependencies (#1337)

* Do some refactoring to fix dependencies between rollout management, executor and evaluator beans.
* Move rollout retrieving in same transaction as execution.
* Do some refactoring. Extend logging and exception handling.
* Remove unnecessary transactional and validation annotations.
* remove catching never thrown bean
* Fix new rollout handling API
This commit is contained in:
Michael Herdt
2023-04-03 09:13:00 +02:00
committed by GitHub
parent 17bf633df9
commit fbda9764b1
29 changed files with 537 additions and 352 deletions

View File

@@ -460,15 +460,11 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpSer
return ds.getModules().stream().map(SoftwareModule::getId).collect(Collectors.toSet());
}
private Rollout createAndStartRollout(final DistributionSet ds, final String filterQuery) {
return createAndStartRollout(ds, filterQuery, null);
}
private Rollout createAndStartRollout(final DistributionSet ds, final String filterQuery, final Integer weight) {
final Rollout rollout = testdataFactory.createRolloutByVariables(UUID.randomUUID().toString(), "", 1,
filterQuery, ds, "50", "5", ActionType.FORCED, weight, false);
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
return rollout;
}

View File

@@ -0,0 +1,52 @@
/**
* Copyright (c) 2023 Bosch.IO 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;
import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.Target;
import org.springframework.security.access.prepost.PreAuthorize;
/**
* Represents the handler service for creating, deleting, and starting a Rollout
*/
@FunctionalInterface
public interface RolloutHandler {
/**
* Process rollout based on its current {@link Rollout#getStatus()}.
*
* For {@link Rollout.RolloutStatus#CREATING} that means creating the
* {@link RolloutGroup}s with {@link Target}s and when finished switch to
* {@link Rollout.RolloutStatus#READY}.
*
* For {@link Rollout.RolloutStatus#READY} that means switching to
* {@link Rollout.RolloutStatus#STARTING} if the {@link Rollout#getStartAt()} is
* set and time of calling this method is beyond this point in time. This auto
* start mechanism is optional. Call {@link RolloutManagement#start(long)} otherwise.
*
* For {@link Rollout.RolloutStatus#STARTING} that means starting the first
* {@link RolloutGroup}s in line and when finished switch to
* {@link Rollout.RolloutStatus#RUNNING}.
*
* For {@link Rollout.RolloutStatus#RUNNING} that means checking to activate
* further groups based on the defined thresholds. Switched to
* {@link Rollout.RolloutStatus#FINISHED} is all groups are finished.
*
* For {@link Rollout.RolloutStatus#DELETING} that means either soft delete in
* case rollout was already {@link Rollout.RolloutStatus#RUNNING} which results
* in status change {@link Rollout.RolloutStatus#DELETED} or hard delete from
* the persistence otherwise.
*
*/
@PreAuthorize(SpringEvalExpressions.IS_SYSTEM_CODE)
void handleAll();
}

View File

@@ -33,7 +33,6 @@ import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
import org.eclipse.hawkbit.repository.model.RolloutGroupsValidation;
import org.eclipse.hawkbit.repository.model.Target;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
@@ -48,37 +47,7 @@ import org.springframework.util.concurrent.ListenableFuture;
public interface RolloutManagement {
/**
* Process rollout based on its current {@link Rollout#getStatus()}.
*
* For {@link RolloutStatus#CREATING} that means creating the
* {@link RolloutGroup}s with {@link Target}s and when finished switch to
* {@link RolloutStatus#READY}.
*
* For {@link RolloutStatus#READY} that means switching to
* {@link RolloutStatus#STARTING} if the {@link Rollout#getStartAt()} is set
* and time of calling this method is beyond this point in time. This auto
* start mechanism is optional. Call {@link #start(Long)} otherwise.
*
* For {@link RolloutStatus#STARTING} that means starting the first
* {@link RolloutGroup}s in line and when finished switch to
* {@link RolloutStatus#RUNNING}.
*
* For {@link RolloutStatus#RUNNING} that means checking to activate further
* groups based on the defined thresholds. Switched to
* {@link RolloutStatus#FINISHED} is all groups are finished.
*
* For {@link RolloutStatus#DELETING} that means either soft delete in case
* rollout was already {@link RolloutStatus#RUNNING} which results in status
* change {@link RolloutStatus#DELETED} or hard delete from the persistence
* otherwise.
*
*/
@PreAuthorize(SpringEvalExpressions.IS_SYSTEM_CODE)
void handleRollouts();
/**
* Counts all {@link Rollout}s in the repository that are not marked as
* deleted.
* Counts all {@link Rollout}s in the repository that are not marked as deleted.
*
* @return number of roll outs
*/
@@ -267,6 +236,14 @@ public interface RolloutManagement {
Slice<Rollout> findByFiltersWithDetailedStatus(@NotNull Pageable pageable, @NotEmpty String searchText,
boolean deleted);
/**
* Find rollouts which are still active and needs to be handled.
*
* @return a list of active rollouts
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ)
List<Long> findActiveRollouts();
/**
* Retrieves a specific rollout by its ID.
*

View File

@@ -157,40 +157,14 @@ public interface RolloutGroup extends NamedEntity {
* The condition to evaluate if an group is success state.
*/
enum RolloutGroupSuccessCondition {
THRESHOLD("thresholdRolloutGroupSuccessCondition");
private final String beanName;
RolloutGroupSuccessCondition(final String beanName) {
this.beanName = beanName;
}
/**
* @return the beanName
*/
public String getBeanName() {
return beanName;
}
THRESHOLD
}
/**
* The condition to evaluate if an group is in error state.
*/
enum RolloutGroupErrorCondition {
THRESHOLD("thresholdRolloutGroupErrorCondition");
private final String beanName;
RolloutGroupErrorCondition(final String beanName) {
this.beanName = beanName;
}
/**
* @return the beanName
*/
public String getBeanName() {
return beanName;
}
THRESHOLD
}
/**
@@ -198,20 +172,7 @@ public interface RolloutGroup extends NamedEntity {
* hit.
*/
enum RolloutGroupErrorAction {
PAUSE("pauseRolloutGroupAction");
private final String beanName;
RolloutGroupErrorAction(final String beanName) {
this.beanName = beanName;
}
/**
* @return the beanName
*/
public String getBeanName() {
return beanName;
}
PAUSE
}
/**
@@ -219,19 +180,6 @@ public interface RolloutGroup extends NamedEntity {
* is hit.
*/
enum RolloutGroupSuccessAction {
NEXTGROUP("startNextRolloutGroupAction");
private final String beanName;
RolloutGroupSuccessAction(final String beanName) {
this.beanName = beanName;
}
/**
* @return the beanName
*/
public String getBeanName() {
return beanName;
}
NEXTGROUP
}
}

View File

@@ -34,8 +34,8 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup;
import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupActionEvaluator;
import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupConditionEvaluator;
import org.eclipse.hawkbit.repository.jpa.rollout.condition.EvaluatorNotConfiguredException;
import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupEvaluationManager;
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
import org.eclipse.hawkbit.repository.model.Action;
@@ -53,8 +53,6 @@ import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
@@ -105,8 +103,9 @@ public class JpaRolloutExecutor implements RolloutExecutor {
private final EventPublisherHolder eventPublisherHolder;
private final PlatformTransactionManager txManager;
private final RolloutApprovalStrategy rolloutApprovalStrategy;
private final ApplicationContext context;
private final RolloutGroupEvaluationManager evaluationManager;
private final RolloutManagement rolloutManagement;
/**
* Constructor
*/
@@ -117,7 +116,8 @@ public class JpaRolloutExecutor implements RolloutExecutor {
final RolloutGroupManagement rolloutGroupManagement, final QuotaManagement quotaManagement,
final DeploymentManagement deploymentManagement, final TargetManagement targetManagement,
final EventPublisherHolder eventPublisherHolder, final PlatformTransactionManager txManager,
final RolloutApprovalStrategy rolloutApprovalStrategy, final ApplicationContext context) {
final RolloutApprovalStrategy rolloutApprovalStrategy,
final RolloutGroupEvaluationManager evaluationManager, final RolloutManagement rolloutManagement) {
this.rolloutTargetGroupRepository = rolloutTargetGroupRepository;
this.entityManager = entityManager;
this.rolloutRepository = rolloutRepository;
@@ -132,7 +132,8 @@ public class JpaRolloutExecutor implements RolloutExecutor {
this.eventPublisherHolder = eventPublisherHolder;
this.txManager = txManager;
this.rolloutApprovalStrategy = rolloutApprovalStrategy;
this.context = context;
this.evaluationManager = evaluationManager;
this.rolloutManagement = rolloutManagement;
}
@Override
@@ -285,7 +286,7 @@ public class JpaRolloutExecutor implements RolloutExecutor {
LOGGER.debug(
"handleReadyRollout called for rollout {} with autostart beyond define time. Switch to STARTING",
rollout.getId());
context.getBean(RolloutManagement.class).start(rollout.getId());
rolloutManagement.start(rollout.getId());
}
}
@@ -417,11 +418,10 @@ public class JpaRolloutExecutor implements RolloutExecutor {
private void callErrorAction(final Rollout rollout, final RolloutGroup rolloutGroup) {
try {
context.getBean(rolloutGroup.getErrorAction().getBeanName(), RolloutGroupActionEvaluator.class)
.eval(rollout, rolloutGroup, rolloutGroup.getErrorActionExp());
} catch (final BeansException e) {
LOGGER.error("Something bad happend when accessing the error action bean {}",
rolloutGroup.getErrorAction().getBeanName(), e);
evaluationManager.getErrorActionEvaluator(rolloutGroup.getErrorAction()).exec(rollout, rolloutGroup);
} catch (final EvaluatorNotConfiguredException e) {
LOGGER.error("Something bad happened when accessing the error action bean {}",
rolloutGroup.getErrorAction().name(), e);
}
}
@@ -443,11 +443,10 @@ public class JpaRolloutExecutor implements RolloutExecutor {
return false;
}
try {
return context.getBean(errorCondition.getBeanName(), RolloutGroupConditionEvaluator.class).eval(rollout,
rolloutGroup, rolloutGroup.getErrorConditionExp());
} catch (final BeansException e) {
LOGGER.error("Something bad happend when accessing the error condition bean {}",
errorCondition.getBeanName(), e);
return evaluationManager.getErrorConditionEvaluator(errorCondition).eval(rollout, rolloutGroup,
rolloutGroup.getErrorConditionExp());
} catch (final EvaluatorNotConfiguredException e) {
LOGGER.error("Something bad happened when accessing the error condition bean {}", errorCondition.name(), e);
return false;
}
}
@@ -456,9 +455,8 @@ public class JpaRolloutExecutor implements RolloutExecutor {
final RolloutGroupSuccessCondition finishCondition) {
LOGGER.trace("Checking finish condition {} on rolloutgroup {}", finishCondition, rolloutGroup);
try {
final boolean isFinished = context
.getBean(finishCondition.getBeanName(), RolloutGroupConditionEvaluator.class)
.eval(rollout, rolloutGroup, rolloutGroup.getSuccessConditionExp());
final boolean isFinished = evaluationManager.getSuccessConditionEvaluator(finishCondition).eval(rollout,
rolloutGroup, rolloutGroup.getSuccessConditionExp());
if (isFinished) {
LOGGER.debug("Rolloutgroup {} is finished, starting next group", rolloutGroup);
executeRolloutGroupSuccessAction(rollout, rolloutGroup);
@@ -466,16 +464,15 @@ public class JpaRolloutExecutor implements RolloutExecutor {
LOGGER.debug("Rolloutgroup {} is still running", rolloutGroup);
}
return isFinished;
} catch (final BeansException e) {
LOGGER.error("Something bad happend when accessing the finish condition bean {}",
finishCondition.getBeanName(), e);
} catch (final EvaluatorNotConfiguredException e) {
LOGGER.error("Something bad happened when accessing the finish condition or success action bean {}",
finishCondition.name(), e);
return false;
}
}
private void executeRolloutGroupSuccessAction(final Rollout rollout, final RolloutGroup rolloutGroup) {
context.getBean(rolloutGroup.getSuccessAction().getBeanName(), RolloutGroupActionEvaluator.class).eval(rollout,
rolloutGroup, rolloutGroup.getSuccessActionExp());
evaluationManager.getSuccessActionEvaluator(rolloutGroup.getSuccessAction()).exec(rollout, rolloutGroup);
}
private void startFirstRolloutGroup(final Rollout rollout) {

View File

@@ -0,0 +1,109 @@
/**
* Copyright (c) 2023 Bosch.IO 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.List;
import java.util.Objects;
import java.util.concurrent.locks.Lock;
import org.eclipse.hawkbit.repository.RolloutExecutor;
import org.eclipse.hawkbit.repository.RolloutHandler;
import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.integration.support.locks.LockRegistry;
import org.springframework.transaction.PlatformTransactionManager;
/**
* JPA implementation of {@link RolloutHandler}.
*/
public class JpaRolloutHandler implements RolloutHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(JpaRolloutHandler.class);
private final TenantAware tenantAware;
private final RolloutManagement rolloutManagement;
private final RolloutExecutor rolloutExecutor;
private final LockRegistry lockRegistry;
private final PlatformTransactionManager txManager;
/**
* Constructor
*
* @param tenantAware
* the {@link TenantAware} bean holding the tenant information
* @param rolloutManagement
* to fetch rollout related information from the datasource
* @param rolloutExecutor
* to trigger executions for a specific rollout
* @param lockRegistry
* to lock processes
* @param txManager
* transaction manager interface
*/
public JpaRolloutHandler(final TenantAware tenantAware, final RolloutManagement rolloutManagement,
final RolloutExecutor rolloutExecutor, final LockRegistry lockRegistry,
final PlatformTransactionManager txManager) {
this.tenantAware = tenantAware;
this.rolloutManagement = rolloutManagement;
this.rolloutExecutor = rolloutExecutor;
this.lockRegistry = lockRegistry;
this.txManager = txManager;
}
@Override
public void handleAll() {
final List<Long> rollouts = rolloutManagement.findActiveRollouts();
if (rollouts.isEmpty()) {
return;
}
final String handlerId = createRolloutLockKey(tenantAware.getCurrentTenant());
final Lock lock = lockRegistry.obtain(handlerId);
if (!lock.tryLock()) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Could not perform lock {}", lock);
}
return;
}
try {
LOGGER.trace("Trigger handling {} rollouts.", rollouts.size());
rollouts.forEach(rolloutId -> handleRolloutInNewTransaction(rolloutId, handlerId));
} finally {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Unlock lock {}", lock);
}
lock.unlock();
}
}
private static String createRolloutLockKey(final String tenant) {
return tenant + "-rollout";
}
private void handleRolloutInNewTransaction(final long rolloutId, final String handlerId) {
DeploymentHelper.runInNewTransaction(txManager, handlerId + "-" + rolloutId, status -> {
rolloutManagement.get(rolloutId).ifPresentOrElse(
rollout -> runInUserContext(rollout, () -> rolloutExecutor.execute(rollout)),
() -> LOGGER.error("Could not retrieve rollout with id {}. Will not continue with execution.",
rolloutId));
return 0L;
});
}
private void runInUserContext(final BaseEntity rollout, final Runnable handler) {
DeploymentHelper.runInNonSystemContext(handler, () -> Objects.requireNonNull(rollout.getCreatedBy()),
tenantAware);
}
}

View File

@@ -16,9 +16,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.locks.Lock;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -28,7 +26,6 @@ import javax.validation.ValidationException;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.QuotaManagement;
import org.eclipse.hawkbit.repository.RolloutApprovalStrategy;
import org.eclipse.hawkbit.repository.RolloutExecutor;
import org.eclipse.hawkbit.repository.RolloutFields;
import org.eclipse.hawkbit.repository.RolloutHelper;
import org.eclipse.hawkbit.repository.RolloutManagement;
@@ -52,10 +49,8 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaRollout_;
import org.eclipse.hawkbit.repository.jpa.rollout.condition.StartNextGroupRolloutGroupSuccessAction;
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
import org.eclipse.hawkbit.repository.jpa.specifications.RolloutSpecification;
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.model.BaseEntity;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.Rollout;
@@ -70,8 +65,6 @@ 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.eclipse.hawkbit.utils.TenantConfigHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -82,14 +75,11 @@ import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.integration.support.locks.LockRegistry;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.concurrent.ListenableFuture;
@@ -137,35 +127,26 @@ public class JpaRolloutManagement implements RolloutManagement {
private final TargetManagement targetManagement;
private final DistributionSetManagement distributionSetManagement;
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final PlatformTransactionManager txManager;
private final TenantAware tenantAware;
private final LockRegistry lockRegistry;
private final RolloutApprovalStrategy rolloutApprovalStrategy;
private final TenantConfigurationManagement tenantConfigurationManagement;
private final SystemSecurityContext systemSecurityContext;
private final RolloutExecutor rolloutExecutor;
private final EventPublisherHolder eventPublisherHolder;
private final Database database;
public JpaRolloutManagement(final TargetManagement targetManagement,
final DistributionSetManagement distributionSetManagement, final EventPublisherHolder eventPublisherHolder,
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
final TenantAware tenantAware, final LockRegistry lockRegistry, final Database database,
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database,
final RolloutApprovalStrategy rolloutApprovalStrategy,
final TenantConfigurationManagement tenantConfigurationManagement,
final SystemSecurityContext systemSecurityContext, final RolloutExecutor rolloutExecutor) {
final SystemSecurityContext systemSecurityContext) {
this.targetManagement = targetManagement;
this.distributionSetManagement = distributionSetManagement;
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.txManager = txManager;
this.tenantAware = tenantAware;
this.lockRegistry = lockRegistry;
this.rolloutApprovalStrategy = rolloutApprovalStrategy;
this.tenantConfigurationManagement = tenantConfigurationManagement;
this.systemSecurityContext = systemSecurityContext;
this.eventPublisherHolder = eventPublisherHolder;
this.database = database;
this.rolloutExecutor = rolloutExecutor;
}
@Override
@@ -435,43 +416,10 @@ public class JpaRolloutManagement implements RolloutManagement {
rolloutRepository.save(rollout);
}
@Override
// No transaction, will be created per handled rollout
@Transactional(propagation = Propagation.NEVER)
public void handleRollouts() {
final List<Long> rollouts = rolloutRepository.findByStatusIn(ACTIVE_ROLLOUTS);
if (rollouts.isEmpty()) {
return;
}
final String tenant = tenantAware.getCurrentTenant();
final String handlerId = createRolloutLockKey(tenant);
final Lock lock = lockRegistry.obtain(handlerId);
if (!lock.tryLock()) {
return;
}
try {
rollouts.forEach(rolloutId -> DeploymentHelper.runInNewTransaction(txManager, handlerId + "-" + rolloutId,
status -> handleRollout(rolloutId)));
} finally {
lock.unlock();
}
}
public static String createRolloutLockKey(final String tenant) {
return tenant + "-rollout";
}
private long handleRollout(final long rolloutId) {
final JpaRollout rollout = rolloutRepository.findById(rolloutId)
.orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId));
runInUserContext(rollout, () -> rolloutExecutor.execute(rollout));
return 0;
}
@Override
@Transactional
@Retryable(include = {
@@ -517,6 +465,11 @@ public class JpaRolloutManagement implements RolloutManagement {
return findAll;
}
@Override
public List<Long> findActiveRollouts() {
return rolloutRepository.findByStatusIn(ACTIVE_ROLLOUTS);
}
@Override
public Optional<Rollout> getByName(final String rolloutName) {
return rolloutRepository.findByName(rolloutName);
@@ -649,11 +602,6 @@ public class JpaRolloutManagement implements RolloutManagement {
QuotaHelper.assertAssignmentQuota(requested, quota, Target.class, RolloutGroup.class);
}
private void runInUserContext(final BaseEntity rollout, final Runnable handler) {
DeploymentHelper.runInNonSystemContext(handler, () -> Objects.requireNonNull(rollout.getCreatedBy()),
tenantAware);
}
@Override
@Transactional
public void cancelRolloutsForDistributionSet(final DistributionSet set) {
@@ -778,7 +726,7 @@ public class JpaRolloutManagement implements RolloutManagement {
.filter(g -> RolloutGroupStatus.RUNNING.equals(g.getStatus())).findFirst()
.orElseThrow(() -> new RolloutIllegalStateException("No group is running"));
startNextRolloutGroupAction.eval(rollout, latestRunning, latestRunning.getSuccessActionExp());
startNextRolloutGroupAction.exec(rollout, latestRunning);
}
}

View File

@@ -36,6 +36,7 @@ import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.RolloutApprovalStrategy;
import org.eclipse.hawkbit.repository.RolloutExecutor;
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
import org.eclipse.hawkbit.repository.RolloutHandler;
import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.RolloutStatusCache;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
@@ -84,6 +85,9 @@ import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHol
import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder;
import org.eclipse.hawkbit.repository.jpa.rollout.RolloutScheduler;
import org.eclipse.hawkbit.repository.jpa.rollout.condition.PauseRolloutGroupAction;
import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupActionEvaluator;
import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupConditionEvaluator;
import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupEvaluationManager;
import org.eclipse.hawkbit.repository.jpa.rollout.condition.StartNextGroupRolloutGroupSuccessAction;
import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupErrorCondition;
import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupSuccessCondition;
@@ -92,6 +96,7 @@ import org.eclipse.hawkbit.repository.jpa.rsql.RsqlParserValidationOracle;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
@@ -119,7 +124,6 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@@ -195,6 +199,16 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
return new ThresholdRolloutGroupSuccessCondition(actionRepository);
}
@Bean
RolloutGroupEvaluationManager evaluationManager(
final List<RolloutGroupConditionEvaluator<RolloutGroup.RolloutGroupErrorCondition>> errorConditionEvaluators,
final List<RolloutGroupConditionEvaluator<RolloutGroup.RolloutGroupSuccessCondition>> successConditionEvaluators,
final List<RolloutGroupActionEvaluator<RolloutGroup.RolloutGroupErrorAction>> errorActionEvaluators,
final List<RolloutGroupActionEvaluator<RolloutGroup.RolloutGroupSuccessAction>> successActionEvaluators) {
return new RolloutGroupEvaluationManager(errorConditionEvaluators, successConditionEvaluators,
errorActionEvaluators, successActionEvaluators);
}
@Bean
@ConditionalOnMissingBean
SystemManagementCacheKeyGenerator systemManagementCacheKeyGenerator() {
@@ -660,6 +674,14 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
return new JpaSoftwareModuleTypeManagement(distributionSetTypeRepository, softwareModuleTypeRepository,
virtualPropertyReplacer, softwareModuleRepository, properties.getDatabase());
}
@Bean
@ConditionalOnMissingBean
RolloutHandler rolloutHandler(final TenantAware tenantAware, final RolloutManagement rolloutManagement,
final RolloutExecutor rolloutExecutor, final LockRegistry lockRegistry,
final PlatformTransactionManager txManager) {
return new JpaRolloutHandler(tenantAware, rolloutManagement, rolloutExecutor, lockRegistry, txManager);
}
@Bean
@ConditionalOnMissingBean
@@ -670,25 +692,25 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
final RolloutGroupManagement rolloutGroupManagement, final QuotaManagement quotaManagement,
final DeploymentManagement deploymentManagement, final TargetManagement targetManagement,
final EventPublisherHolder eventPublisherHolder, final PlatformTransactionManager txManager,
final RolloutApprovalStrategy rolloutApprovalStrategy, final ApplicationContext context) {
final RolloutApprovalStrategy rolloutApprovalStrategy,
final RolloutGroupEvaluationManager evaluationManager, final RolloutManagement rolloutManagement) {
return new JpaRolloutExecutor(rolloutTargetGroupRepository, entityManager, rolloutRepository, actionRepository,
rolloutGroupRepository, afterCommit, tenantAware, rolloutGroupManagement, quotaManagement,
deploymentManagement, targetManagement, eventPublisherHolder, txManager, rolloutApprovalStrategy,
context);
evaluationManager, rolloutManagement);
}
@Bean
@ConditionalOnMissingBean
RolloutManagement rolloutManagement(final TargetManagement targetManagement,
final DistributionSetManagement distributionSetManagement, final EventPublisherHolder eventPublisherHolder,
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
final TenantAware tenantAware, final LockRegistry lockRegistry, final JpaProperties properties,
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties,
final RolloutApprovalStrategy rolloutApprovalStrategy,
final TenantConfigurationManagement tenantConfigurationManagement,
final SystemSecurityContext systemSecurityContext, final RolloutExecutor rolloutExecutor) {
final SystemSecurityContext systemSecurityContext) {
return new JpaRolloutManagement(targetManagement, distributionSetManagement, eventPublisherHolder,
virtualPropertyReplacer, txManager, tenantAware, lockRegistry, properties.getDatabase(),
rolloutApprovalStrategy, tenantConfigurationManagement, systemSecurityContext, rolloutExecutor);
virtualPropertyReplacer, properties.getDatabase(), rolloutApprovalStrategy,
tenantConfigurationManagement, systemSecurityContext);
}
/**
@@ -913,7 +935,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
*
* @param systemManagement
* to find all tenants
* @param rolloutManagement
* @param rolloutHandler
* to run the rollout handler
* @param systemSecurityContext
* to run as system
@@ -924,8 +946,8 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
@Profile("!test")
@ConditionalOnProperty(prefix = "hawkbit.rollout.scheduler", name = "enabled", matchIfMissing = true)
RolloutScheduler rolloutScheduler(final TenantAware tenantAware, final SystemManagement systemManagement,
final RolloutManagement rolloutManagement, final SystemSecurityContext systemSecurityContext) {
return new RolloutScheduler(systemManagement, rolloutManagement, systemSecurityContext);
final RolloutHandler rolloutHandler, final SystemSecurityContext systemSecurityContext) {
return new RolloutScheduler(systemManagement, rolloutHandler, systemSecurityContext);
}
/**

View File

@@ -8,7 +8,7 @@
*/
package org.eclipse.hawkbit.repository.jpa.rollout;
import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.RolloutHandler;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.slf4j.Logger;
@@ -16,8 +16,8 @@ import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
/**
* Scheduler to schedule the {@link RolloutManagement#handleRollouts()}. The
* delay between the checks be be configured using the property from
* Scheduler to schedule the {@link RolloutHandler#handleAll()}. The
* delay between the checks be configured using the property from
* {#PROP_SCHEDULER_DELAY_PLACEHOLDER}.
*/
public class RolloutScheduler {
@@ -28,7 +28,7 @@ public class RolloutScheduler {
private final SystemManagement systemManagement;
private final RolloutManagement rolloutManagement;
private final RolloutHandler rolloutHandler;
private final SystemSecurityContext systemSecurityContext;
@@ -37,22 +37,22 @@ public class RolloutScheduler {
*
* @param systemManagement
* to find all tenants
* @param rolloutManagement
* @param rolloutHandler
* to run the rollout handler
* @param systemSecurityContext
* to run as system
*/
public RolloutScheduler(final SystemManagement systemManagement, final RolloutManagement rolloutManagement,
public RolloutScheduler(final SystemManagement systemManagement, final RolloutHandler rolloutHandler,
final SystemSecurityContext systemSecurityContext) {
this.systemManagement = systemManagement;
this.rolloutManagement = rolloutManagement;
this.rolloutHandler = rolloutHandler;
this.systemSecurityContext = systemSecurityContext;
}
/**
* Scheduler method called by the spring-async mechanism. Retrieves all
* tenants from the {@link SystemManagement#findTenants()} and runs for each
* tenant the {@link RolloutManagement#handleRollouts()} in the
* tenants from the {@link SystemManagement#findTenants} and runs for each
* tenant the {@link RolloutHandler#handleAll()} in the
* {@link SystemSecurityContext}.
*/
@Scheduled(initialDelayString = PROP_SCHEDULER_DELAY_PLACEHOLDER, fixedDelayString = PROP_SCHEDULER_DELAY_PLACEHOLDER)
@@ -63,13 +63,13 @@ public class RolloutScheduler {
// permission to query and create entities.
systemSecurityContext.runAsSystem(() -> {
// workaround eclipselink that is currently not possible to
// execute a query without multitenancy if MultiTenant
// execute a query without multi-tenancy if MultiTenant
// annotation is used.
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=355458. So
// iterate through all tenants and execute the rollout check for
// each tenant seperately.
systemManagement.forEachTenant(tenant -> rolloutManagement.handleRollouts());
systemManagement.forEachTenant(tenant -> rolloutHandler.handleAll());
return null;
});

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2023 Bosch.IO 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.rollout.condition;
/**
* Exception indicating that a specific evaluator is missing in the application
* context.
*/
public class EvaluatorNotConfiguredException extends RuntimeException {
private static final String MESSAGE_FORMAT = "Cannot find any configured evaluator for action/condition '%s'. Please ensure to configure one in the application context to make use of it.";
/**
* Constructor
*
* @param s
* the action/condition to evaluate
*/
public EvaluatorNotConfiguredException(final String s) {
super(String.format(MESSAGE_FORMAT, s));
}
}

View File

@@ -20,7 +20,7 @@ import org.eclipse.hawkbit.security.SystemSecurityContext;
* Error action evaluator which pauses the whole {@link Rollout} and sets the
* current {@link RolloutGroup} to error.
*/
public class PauseRolloutGroupAction implements RolloutGroupActionEvaluator {
public class PauseRolloutGroupAction implements RolloutGroupActionEvaluator<RolloutGroup.RolloutGroupErrorAction> {
private final RolloutManagement rolloutManagement;
@@ -36,12 +36,12 @@ public class PauseRolloutGroupAction implements RolloutGroupActionEvaluator {
}
@Override
public boolean verifyExpression(final String expression) {
return true;
public RolloutGroup.RolloutGroupErrorAction getAction() {
return RolloutGroup.RolloutGroupErrorAction.PAUSE;
}
@Override
public void eval(final Rollout rollout, final RolloutGroup rolloutG, final String expression) {
public void exec(final Rollout rollout, final RolloutGroup rolloutG) {
final JpaRolloutGroup rolloutGroup = (JpaRolloutGroup) rolloutG;
systemSecurityContext.runAsSystem(() -> {

View File

@@ -12,11 +12,11 @@ import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
/**
*
* Interface to define a specific execution for an action
*/
public interface RolloutGroupActionEvaluator {
public interface RolloutGroupActionEvaluator<T> {
boolean verifyExpression(final String expression);
T getAction();
void eval(Rollout rollout, RolloutGroup rolloutGroup, final String expression);
void exec(Rollout rollout, RolloutGroup rolloutGroup);
}

View File

@@ -12,20 +12,11 @@ import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
/**
* Verifies {@link RolloutGroup#getErrorConditionExp()}.
* Interface for evaluate conditions define for a {@link RolloutGroup} based on a given expression
*/
@FunctionalInterface
public interface RolloutGroupConditionEvaluator {
public interface RolloutGroupConditionEvaluator<T> {
default boolean verifyExpression(final String expression) {
// percentage value between 0 and 100
try {
final Integer value = Integer.valueOf(expression);
return value >= 0 && value <= 100;
} catch (final NumberFormatException e) {
return false;
}
}
T getCondition();
boolean eval(Rollout rollout, RolloutGroup rolloutGroup, final String expression);
}

View File

@@ -0,0 +1,98 @@
/**
* Copyright (c) 2023 Bosch.IO 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.rollout.condition;
import java.util.List;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Manager class to collect all instances of
* {@link RolloutGroupConditionEvaluator} and
* {@link RolloutGroupActionEvaluator} for specific conditions and actions. The
* corresponding instance can be fetched by providing the action/condition.
*/
public class RolloutGroupEvaluationManager {
private static final Logger LOGGER = LoggerFactory.getLogger(RolloutGroupEvaluationManager.class);
private final List<RolloutGroupConditionEvaluator<RolloutGroup.RolloutGroupErrorCondition>> errorConditionEvaluators;
private final List<RolloutGroupConditionEvaluator<RolloutGroup.RolloutGroupSuccessCondition>> successConditionEvaluators;
private final List<RolloutGroupActionEvaluator<RolloutGroup.RolloutGroupErrorAction>> errorActionEvaluators;
private final List<RolloutGroupActionEvaluator<RolloutGroup.RolloutGroupSuccessAction>> successActionEvaluators;
/**
* Constructor
*
* @param errorConditionEvaluators
* evaluators for instances of {@link RolloutGroupConditionEvaluator}
* handling the {@link RolloutGroup.RolloutGroupErrorCondition}
* @param successConditionEvaluators
* evaluators for instances of {@link RolloutGroupConditionEvaluator}
* handling the {@link RolloutGroup.RolloutGroupSuccessCondition}
* @param errorActionEvaluators
* evaluators for instances of {@link RolloutGroupActionEvaluator}
* handling the {@link RolloutGroup.RolloutGroupErrorAction}
* @param successActionEvaluators
* evaluators for instances of {@link RolloutGroupActionEvaluator}
* handling the {@link RolloutGroup.RolloutGroupSuccessAction}
*/
public RolloutGroupEvaluationManager(
final List<RolloutGroupConditionEvaluator<RolloutGroup.RolloutGroupErrorCondition>> errorConditionEvaluators,
final List<RolloutGroupConditionEvaluator<RolloutGroup.RolloutGroupSuccessCondition>> successConditionEvaluators,
final List<RolloutGroupActionEvaluator<RolloutGroup.RolloutGroupErrorAction>> errorActionEvaluators,
final List<RolloutGroupActionEvaluator<RolloutGroup.RolloutGroupSuccessAction>> successActionEvaluators) {
this.errorConditionEvaluators = errorConditionEvaluators;
this.successConditionEvaluators = successConditionEvaluators;
this.errorActionEvaluators = errorActionEvaluators;
this.successActionEvaluators = successActionEvaluators;
}
public RolloutGroupActionEvaluator<RolloutGroup.RolloutGroupErrorAction> getErrorActionEvaluator(
final RolloutGroup.RolloutGroupErrorAction errorAction) {
return findFirstActionEvaluator(errorActionEvaluators, errorAction);
}
public RolloutGroupActionEvaluator<RolloutGroup.RolloutGroupSuccessAction> getSuccessActionEvaluator(
final RolloutGroup.RolloutGroupSuccessAction successAction) {
return findFirstActionEvaluator(successActionEvaluators, successAction);
}
public RolloutGroupConditionEvaluator<RolloutGroup.RolloutGroupErrorCondition> getErrorConditionEvaluator(
final RolloutGroup.RolloutGroupErrorCondition errorCondition) {
return findFirstConditionEvaluator(errorConditionEvaluators, errorCondition);
}
public RolloutGroupConditionEvaluator<RolloutGroup.RolloutGroupSuccessCondition> getSuccessConditionEvaluator(
final RolloutGroup.RolloutGroupSuccessCondition successCondition) {
return findFirstConditionEvaluator(successConditionEvaluators, successCondition);
}
private static <T extends Enum<T>> RolloutGroupActionEvaluator<T> findFirstActionEvaluator(
final List<RolloutGroupActionEvaluator<T>> evaluators, final T action) {
return evaluators.stream().filter(evaluator -> evaluator.getAction() == action).findFirst().orElseThrow(() -> {
LOGGER.warn("Could not find suitable evaluator for the '{}' action.", action.name());
throw new EvaluatorNotConfiguredException(action.name());
});
}
private static <T extends Enum<T>> RolloutGroupConditionEvaluator<T> findFirstConditionEvaluator(
final List<RolloutGroupConditionEvaluator<T>> evaluators, final T condition) {
return evaluators.stream().filter(evaluator -> evaluator.getCondition() == condition).findFirst()
.orElseThrow(() -> {
LOGGER.warn("Could not find suitable evaluator for the '{}' condition.", condition.name());
throw new EvaluatorNotConfiguredException(condition.name());
});
}
}

View File

@@ -23,7 +23,7 @@ import org.slf4j.LoggerFactory;
/**
* Success action which starts the next following {@link RolloutGroup}.
*/
public class StartNextGroupRolloutGroupSuccessAction implements RolloutGroupActionEvaluator {
public class StartNextGroupRolloutGroupSuccessAction implements RolloutGroupActionEvaluator<RolloutGroup.RolloutGroupSuccessAction> {
private static final Logger logger = LoggerFactory.getLogger(StartNextGroupRolloutGroupSuccessAction.class);
@@ -41,12 +41,12 @@ public class StartNextGroupRolloutGroupSuccessAction implements RolloutGroupActi
}
@Override
public boolean verifyExpression(final String expression) {
return true;
public RolloutGroup.RolloutGroupSuccessAction getAction() {
return RolloutGroup.RolloutGroupSuccessAction.NEXTGROUP;
}
@Override
public void eval(final Rollout rollout, final RolloutGroup rolloutGroup, final String expression) {
public void exec(final Rollout rollout, final RolloutGroup rolloutGroup) {
systemSecurityContext.runAsSystem(() -> {
startNextGroup(rollout, rolloutGroup);
return null;

View File

@@ -18,9 +18,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* Evaluates if the {@link RolloutGroup#getErrorConditionExp()} is reached.
*/
public class ThresholdRolloutGroupErrorCondition implements RolloutGroupConditionEvaluator {
public class ThresholdRolloutGroupErrorCondition
implements RolloutGroupConditionEvaluator<RolloutGroup.RolloutGroupErrorCondition> {
private static final Logger LOGGER = LoggerFactory.getLogger(ThresholdRolloutGroupErrorCondition.class);
@@ -30,6 +31,11 @@ public class ThresholdRolloutGroupErrorCondition implements RolloutGroupConditio
this.actionRepository = actionRepository;
}
@Override
public RolloutGroup.RolloutGroupErrorCondition getCondition() {
return RolloutGroup.RolloutGroupErrorCondition.THRESHOLD;
}
@Override
public boolean eval(final Rollout rollout, final RolloutGroup rolloutGroup, final String expression) {
final Long totalGroup = actionRepository.countByRolloutAndRolloutGroup((JpaRollout) rollout,

View File

@@ -16,10 +16,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Threshold to calculate if rollout group success condition is reached and the
* Threshold to calculate if the {@link RolloutGroup#getSuccessConditionExp()} is reached and the
* next rollout group can get started.
*/
public class ThresholdRolloutGroupSuccessCondition implements RolloutGroupConditionEvaluator {
public class ThresholdRolloutGroupSuccessCondition
implements RolloutGroupConditionEvaluator<RolloutGroup.RolloutGroupSuccessCondition> {
private static final Logger LOGGER = LoggerFactory.getLogger(ThresholdRolloutGroupSuccessCondition.class);
private final ActionRepository actionRepository;
@@ -28,6 +29,11 @@ public class ThresholdRolloutGroupSuccessCondition implements RolloutGroupCondit
this.actionRepository = actionRepository;
}
@Override
public RolloutGroup.RolloutGroupSuccessCondition getCondition() {
return RolloutGroup.RolloutGroupSuccessCondition.THRESHOLD;
}
@Override
public boolean eval(final Rollout rollout, final RolloutGroup rolloutGroup, final String expression) {
@@ -44,7 +50,7 @@ public class ThresholdRolloutGroupSuccessCondition implements RolloutGroupCondit
final long finished = this.actionRepository.countByRolloutIdAndRolloutGroupIdAndStatus(rollout.getId(),
rolloutGroup.getId(), completeActionStatus);
try {
final Integer threshold = Integer.valueOf(expression);
final int threshold = Integer.parseInt(expression);
// calculate threshold
return ((float) finished / (float) totalGroup) >= ((float) threshold / 100F);

View File

@@ -8,9 +8,15 @@
*/
package org.eclipse.hawkbit.repository.jpa;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.AdditionalAnswers.delegatesTo;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import org.awaitility.Awaitility;
import org.awaitility.Duration;
import org.eclipse.hawkbit.repository.exception.StopRolloutException;
@@ -32,14 +38,9 @@ import org.springframework.context.annotation.Primary;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.AdditionalAnswers.delegatesTo;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
/**
* Test class testing the invalidation of a {@link DistributionSet} while the
@@ -87,7 +88,7 @@ public class ConcurrentDistributionSetInvalidationTest extends AbstractJpaIntegr
// run in new Thread so that the invalidation can be executed in
// parallel
new Thread(() -> systemSecurityContext.runAsSystemAsTenant(() -> {
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
return 0;
}, tenant)).start();

View File

@@ -58,7 +58,7 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
assertDistributionSetInvalidationCount(distributionSetInvalidationCount, 1, 0, 0);
distributionSetInvalidationManagement.invalidateDistributionSet(distributionSetInvalidation);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
assertThat(targetFilterQueryManagement.get(invalidationTestData.getTargetFilterQuery().getId()).get()
.getAutoAssignDistributionSet()).isNull();
@@ -87,7 +87,7 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
assertDistributionSetInvalidationCount(distributionSetInvalidationCount, 1, 0, 1);
distributionSetInvalidationManagement.invalidateDistributionSet(distributionSetInvalidation);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
assertThat(targetFilterQueryManagement.get(invalidationTestData.getTargetFilterQuery().getId()).get()
.getAutoAssignDistributionSet()).isNull();
@@ -119,7 +119,7 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
assertDistributionSetInvalidationCount(distributionSetInvalidationCount, 1, 5, 1);
distributionSetInvalidationManagement.invalidateDistributionSet(distributionSetInvalidation);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
assertThat(targetFilterQueryManagement.get(invalidationTestData.getTargetFilterQuery().getId()).get()
.getAutoAssignDistributionSet()).isNull();

View File

@@ -92,7 +92,7 @@ class RolloutGroupManagementTest extends AbstractJpaIntegrationTest {
.getContent();
final RolloutGroup rolloutGroup = rolloutGroups.get(0);
rolloutManagement.pauseRollout(rollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final List<Target> targets = rolloutGroupManagement.findTargetsOfRolloutGroup(PAGE, rolloutGroup.getId())
.getContent();
Target targetCancelled = targets.get(0);
@@ -195,7 +195,7 @@ class RolloutGroupManagementTest extends AbstractJpaIntegrationTest {
final Rollout rollout = testdataFactory.createRollout();
final List<RolloutGroup> rolloutGroups = rolloutGroupManagement.findByRollout(PAGE, rollout.getId())
.getContent();
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// check query when no actions exist
final List<TargetWithActionStatus> targetsWithActionStatus = rolloutGroupManagement
@@ -208,7 +208,7 @@ class RolloutGroupManagementTest extends AbstractJpaIntegrationTest {
assertTargetNotNullAndActionStatusNullAndActionStatusCode(targetsWithActionStatus, null);
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// check query when no action status code exist
final List<Action> scheduledActions = findActionsByRolloutAndStatus(rollout, Status.SCHEDULED);

View File

@@ -126,7 +126,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final Rollout rollout = testdataFactory.createRolloutByVariables("rolloutNotCancelRunningAction", "description",
1, "name==*", knownDistributionSet, "50", "5");
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// verify that manually created action is still running and action
// created from rollout is finished
@@ -163,7 +163,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final Rollout rollout = testdataFactory.createRolloutByVariables("rolloutNotCancelRunningAction", "description",
1, "name==*", knownDistributionSet, "50", "5", confirmationRequired);
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// verify that manually created action is still running and action
// created from rollout is finished
@@ -201,7 +201,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final Rollout rollout = testdataFactory.createRolloutByVariables("rolloutNotCancelRunningAction",
"description", 1, "name==*", secondDistributionSet, "50", "5");
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// verify that manually created action is canceled and action
// created from rollout is running
@@ -333,7 +333,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// check running rollouts again, now the finish condition should be hit
// and should start the next group
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// verify that now the first and the second group are in running state
final List<RolloutGroup> runningRolloutGroups = rolloutGroupManagement
@@ -395,7 +395,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
@Step("Check the status of the rollout groups, second group should be in running status")
private void checkSecondGroupStatusIsRunning(final Rollout createdRollout) {
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final List<RolloutGroup> runningRolloutGroups = rolloutGroupManagement
.findByRollout(new OffsetBasedPageRequest(0, 10, Sort.by(Direction.ASC, "id")), createdRollout.getId())
.getContent();
@@ -428,7 +428,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
@Step("Check the status of the rollout groups and the rollout")
private void verifyRolloutAndAllGroupsAreFinished(final Rollout createdRollout) {
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final List<RolloutGroup> runningRolloutGroups = rolloutGroupManagement
.findByRollout(PAGE, createdRollout.getId()).getContent();
assertThat(runningRolloutGroups.get(0).getStatus()).isEqualTo(RolloutGroupStatus.FINISHED);
@@ -467,7 +467,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// check running rollouts again, now the error condition should be hit
// and should execute the error action
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final Rollout rollout = reloadRollout(createdRollout);
// the rollout itself should be in paused based on the error action
@@ -510,7 +510,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// check running rollouts again, now the error condition should be hit
// and should execute the error action
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final Rollout rollout = reloadRollout(createdRollout);
// the rollout itself should be in paused based on the error action
@@ -529,7 +529,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
assertThat(reloadRollout(createdRollout).getStatus()).isEqualTo(RolloutStatus.RUNNING);
// checking rollouts again
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// next group should be running again after resuming the rollout
final List<RolloutGroup> resumedGroups = rolloutGroupManagement
@@ -557,7 +557,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// calculate the rest of the groups and finish them
for (int groupsLeft = amountGroups - 1; groupsLeft >= 1; groupsLeft--) {
// next check and start next group
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// finish running actions, 2 actions should be finished
assertThat(changeStatusForAllRunningActions(createdRollout, Status.FINISHED)).isEqualTo(2);
assertThat(getRollout(createdRollout.getId()).getStatus()).isEqualTo(RolloutStatus.RUNNING);
@@ -565,7 +565,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
}
// check rollout to see that all actions and all groups are finished and
// so can go to FINISHED state of the rollout
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// verify all groups are in finished state
rolloutGroupManagement
@@ -598,7 +598,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
rolloutManagement.start(createdRollout.getId());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// 6 targets are ready and 2 are running
validationMap = createInitStatusMap();
@@ -607,7 +607,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
validateRolloutActionStatus(createdRollout.getId(), validationMap);
changeStatusForAllRunningActions(createdRollout, Status.FINISHED);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// 4 targets are ready, 2 are finished and 2 are running
validationMap = createInitStatusMap();
validationMap.put(TotalTargetCountStatus.Status.SCHEDULED, 4L);
@@ -616,7 +616,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
validateRolloutActionStatus(createdRollout.getId(), validationMap);
changeStatusForAllRunningActions(createdRollout, Status.FINISHED);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// 2 targets are ready, 4 are finished and 2 are running
validationMap = createInitStatusMap();
validationMap.put(TotalTargetCountStatus.Status.SCHEDULED, 2L);
@@ -625,7 +625,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
validateRolloutActionStatus(createdRollout.getId(), validationMap);
changeStatusForAllRunningActions(createdRollout, Status.FINISHED);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// 0 targets are ready, 6 are finished and 2 are running
validationMap = createInitStatusMap();
validationMap.put(TotalTargetCountStatus.Status.FINISHED, 6L);
@@ -633,7 +633,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
validateRolloutActionStatus(createdRollout.getId(), validationMap);
changeStatusForAllRunningActions(createdRollout, Status.FINISHED);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// 0 targets are ready, 8 are finished and 0 are running
validationMap = createInitStatusMap();
validationMap.put(TotalTargetCountStatus.Status.FINISHED, 8L);
@@ -662,7 +662,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
rolloutManagement.start(createdRollout.getId());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// 6 targets are ready and 2 are running
validationMap = createInitStatusMap();
@@ -671,7 +671,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
validateRolloutActionStatus(createdRollout.getId(), validationMap);
changeStatusForAllRunningActions(createdRollout, Status.DOWNLOADED);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// 4 targets are ready, 2 are finished(with DOWNLOADED action status)
// and 2 are running
validationMap = createInitStatusMap();
@@ -681,7 +681,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
validateRolloutActionStatus(createdRollout.getId(), validationMap);
changeStatusForAllRunningActions(createdRollout, Status.DOWNLOADED);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// 2 targets are ready, 4 are finished(with DOWNLOADED action status)
// and 2 are running
validationMap = createInitStatusMap();
@@ -691,7 +691,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
validateRolloutActionStatus(createdRollout.getId(), validationMap);
changeStatusForAllRunningActions(createdRollout, Status.DOWNLOADED);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// 0 targets are ready, 6 are finished(with DOWNLOADED action status)
// and 2 are running
validationMap = createInitStatusMap();
@@ -700,7 +700,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
validateRolloutActionStatus(createdRollout.getId(), validationMap);
changeStatusForAllRunningActions(createdRollout, Status.FINISHED);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// 0 targets are ready, 6 are finished(with DOWNLOADED action status), 2
// are finished and 0 are running
validationMap = createInitStatusMap();
@@ -730,7 +730,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
rolloutManagement.start(createdRollout.getId());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// 6 targets are ready and 2 are running
validationMap = createInitStatusMap();
@@ -739,7 +739,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
validateRolloutActionStatus(createdRollout.getId(), validationMap);
changeStatusForAllRunningActions(createdRollout, Status.ERROR);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// 6 targets are ready and 2 are error
validationMap = createInitStatusMap();
validationMap.put(TotalTargetCountStatus.Status.SCHEDULED, 6L);
@@ -761,7 +761,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
successCondition, errorCondition);
changeStatusForAllRunningActions(createdRollout, Status.FINISHED);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// round(9/4)=2 targets finished (Group 1)
// round(7/3)=2 targets running (Group 3)
@@ -853,7 +853,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final Rollout rolloutTwo = testdataFactory.createRolloutByVariables("rolloutTwo",
"This is the description for rollout two", 1, "controllerId==rollout-*", dsForRolloutTwo, "50", "80");
changeStatusForAllRunningActions(rolloutOne, Status.FINISHED);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// Verify that 5 targets are finished, 5 are running and 5 are ready.
Map<TotalTargetCountStatus.Status, Long> expectedTargetCountStatus = createInitStatusMap();
expectedTargetCountStatus.put(TotalTargetCountStatus.Status.RUNNING, 5L);
@@ -864,7 +864,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
rolloutManagement.start(rolloutTwo.getId());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// Verify that 5 targets are finished, 5 are still running and 5 are
// cancelled.
@@ -892,13 +892,13 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
rolloutOne = reloadRollout(rolloutOne);
changeStatusForRunningActions(rolloutOne, Status.ERROR, 2);
changeStatusForRunningActions(rolloutOne, Status.FINISHED, 3);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
changeStatusForRunningActions(rolloutOne, Status.ERROR, 2);
changeStatusForRunningActions(rolloutOne, Status.FINISHED, 3);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
changeStatusForRunningActions(rolloutOne, Status.ERROR, 2);
changeStatusForRunningActions(rolloutOne, Status.FINISHED, 3);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// 9 targets are finished and 6 have error
Map<TotalTargetCountStatus.Status, Long> expectedTargetCountStatus = createInitStatusMap();
@@ -917,7 +917,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
rolloutManagement.start(rolloutTwo.getId());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
rolloutTwo = reloadRollout(rolloutTwo);
// 6 error targets are now running
@@ -950,7 +950,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
rolloutOne = reloadRollout(rolloutOne);
changeStatusForRunningActions(rolloutOne, Status.ERROR, 2);
changeStatusForRunningActions(rolloutOne, Status.FINISHED, 3);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// verify: 40% error but 60% finished -> should move to next group
final List<RolloutGroup> rolloutGroups = rolloutGroupManagement.findByRollout(PAGE, rolloutOne.getId())
.getContent();
@@ -976,7 +976,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
rolloutOne = reloadRollout(rolloutOne);
changeStatusForRunningActions(rolloutOne, Status.ERROR, 2);
changeStatusForRunningActions(rolloutOne, Status.FINISHED, 3);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// verify: 40% error and 60% finished -> should not move to next group
// because successCondition 80%
final List<RolloutGroup> rolloutGruops = rolloutGroupManagement.findByRollout(PAGE, rolloutOne.getId())
@@ -1002,7 +1002,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
rolloutOne = reloadRollout(rolloutOne);
changeStatusForRunningActions(rolloutOne, Status.ERROR, 2);
changeStatusForRunningActions(rolloutOne, Status.FINISHED, 3);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// verify: 40% error -> should pause because errorCondition is 20%
rolloutOne = reloadRollout(rolloutOne);
assertThat(rolloutOne.getStatus()).isEqualTo(RolloutStatus.PAUSED);
@@ -1019,39 +1019,39 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final Rollout rolloutA = createTestRolloutWithTargetsAndDistributionSet(amountTargetsForRollout, amountGroups,
successCondition, errorCondition, "RolloutA", "RolloutA");
rolloutManagement.start(rolloutA.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final int amountTargetsForRollout2 = 10;
final int amountGroups2 = 2;
final Rollout rolloutB = createTestRolloutWithTargetsAndDistributionSet(amountTargetsForRollout2, amountGroups2,
successCondition, errorCondition, "RolloutB", "RolloutB");
rolloutManagement.start(rolloutB.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
changeStatusForAllRunningActions(rolloutB, Status.FINISHED);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final int amountTargetsForRollout3 = 10;
final int amountGroups3 = 2;
final Rollout rolloutC = createTestRolloutWithTargetsAndDistributionSet(amountTargetsForRollout3, amountGroups3,
successCondition, errorCondition, "RolloutC", "RolloutC");
rolloutManagement.start(rolloutC.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
changeStatusForAllRunningActions(rolloutC, Status.ERROR);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final int amountTargetsForRollout4 = 15;
final int amountGroups4 = 3;
final Rollout rolloutD = createTestRolloutWithTargetsAndDistributionSet(amountTargetsForRollout4, amountGroups4,
successCondition, errorCondition, "RolloutD", "RolloutD");
rolloutManagement.start(rolloutD.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
changeStatusForRunningActions(rolloutD, Status.ERROR, 1);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
changeStatusForAllRunningActions(rolloutD, Status.FINISHED);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final Slice<Rollout> rolloutPage = rolloutManagement
.findAllWithDetailedStatus(new OffsetBasedPageRequest(0, 100, Sort.by(Direction.ASC, "name")), false);
@@ -1181,10 +1181,10 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
rolloutManagement.start(myRollout.getId());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
changeStatusForRunningActions(myRollout, Status.FINISHED, 2);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
myRollout = reloadRollout(myRollout);
float percent = rolloutGroupManagement
@@ -1194,7 +1194,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
assertThat(percent).isEqualTo(40);
changeStatusForRunningActions(myRollout, Status.FINISHED, 3);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
percent = rolloutGroupManagement
.getWithDetailedStatus(
@@ -1204,7 +1204,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
changeStatusForRunningActions(myRollout, Status.FINISHED, 4);
changeStatusForAllRunningActions(myRollout, Status.ERROR);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
percent = rolloutGroupManagement
.getWithDetailedStatus(
@@ -1233,7 +1233,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
rolloutManagement.start(myRollout.getId());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final Condition<String> targetBelongsInRollout = new Condition<>(s -> s.startsWith(rolloutName),
"Target belongs into rollout");
@@ -1336,7 +1336,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
rolloutManagement.start(myRolloutId);
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
awaitRunningState(myRolloutId);
@@ -1365,7 +1365,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.READY);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final Long myRolloutId = myRollout.getId();
myRollout = getRollout(myRolloutId);
@@ -1374,7 +1374,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
rolloutManagement.start(myRolloutId);
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
awaitRunningState(myRolloutId);
@@ -1487,7 +1487,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final Long myRolloutId = myRollout.getId();
rolloutManagement
.update(entityFactory.rollout().update(myRolloutId).startAt(System.currentTimeMillis() + 60000));
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// rollout should not have been started
myRollout = getRollout(myRolloutId);
@@ -1495,13 +1495,13 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// schedule to now
rolloutManagement.update(entityFactory.rollout().update(myRolloutId).startAt(System.currentTimeMillis()));
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
myRollout = getRollout(myRolloutId);
assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.STARTING);
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
awaitRunningState(myRolloutId);
@@ -1562,7 +1562,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
TimeUnit.SECONDS.sleep(1);
testdataFactory.createTargets(10, rolloutName + "-notIn-", rolloutName);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
myRollout = getRollout(myRollout.getId());
assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.READY);
@@ -1613,7 +1613,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
});
// first handle iteration will put rollout in ready state
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
assertThat(getRollout(rolloutId)).satisfies(rollout -> {
assertThat(rollout.getStatus()).isEqualTo(RolloutStatus.READY);
@@ -1629,7 +1629,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// start rollout
rolloutManagement.start(rolloutId);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// verify rollout started. Check groups are in right state.
// Group 1 should be in WFC state, since confirmation is required here.
@@ -1641,7 +1641,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// cancel execution of all action of group 1 to trigger second group
forceQuitAllActionsOfRolloutGroup(rolloutGroupIds.get(0));
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
assertRolloutGroup(rolloutGroupIds.get(0), RolloutGroupStatus.FINISHED, true, amountTargetsInGroup1,
Status.CANCELED);
assertRolloutGroup(rolloutGroupIds.get(1), RolloutGroupStatus.SCHEDULED, false, amountTargetsInGroup2,
@@ -1649,7 +1649,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// verify actions of second rule are directly in RUNNING state, since
// confirmation is not required for this group
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
assertRolloutGroup(rolloutGroupIds.get(0), RolloutGroupStatus.FINISHED, true, amountTargetsInGroup1,
Status.CANCELED);
assertRolloutGroup(rolloutGroupIds.get(1), RolloutGroupStatus.RUNNING, false, amountTargetsInGroup2,
@@ -1855,7 +1855,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// test
rolloutManagement.delete(createdRollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// verify
final Optional<JpaRollout> deletedRollout = rolloutRepository.findById(createdRollout.getId());
@@ -1889,7 +1889,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// start the rollout, so it has active running actions and a group which
// has been started
rolloutManagement.start(createdRollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// verify we have running actions
assertThat(actionRepository.findByRolloutIdAndStatus(PAGE, createdRollout.getId(), Status.RUNNING)
@@ -1897,7 +1897,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// test
rolloutManagement.delete(createdRollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// verify
final JpaRollout deletedRollout = rolloutRepository.findById(createdRollout.getId()).get();
@@ -1941,11 +1941,11 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
Rollout rolloutRunning = rolloutManagement.create(rolloutRunningCreate, 1, false, conditions);
// Let the executor handle created Rollout
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// start the rollout, so it has active running actions and a group which
// has been started
rolloutManagement.start(rolloutRunning.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
rolloutRunning = reloadRollout(rolloutRunning);
final String prefixRolloutReady = randomString + "2";
@@ -1953,7 +1953,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
.name(prefixRolloutReady + "-testRollout").targetFilterQuery("name==" + randomString + "*").set(testDs);
Rollout rolloutReady = rolloutManagement.create(rolloutReadyCreate, 1, false, conditions);
// Let the executor handle created Rollout
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
rolloutReady = reloadRollout(rolloutReady);
final List<Rollout> rolloutsOrderedByStatus = rolloutManagement
@@ -2017,7 +2017,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
.createSimpleTestRolloutWithTargetsAndDistributionSet(amountOfTargets, 2, amountOfTargets,
"80", "50", null, weight).getId();
rolloutManagement.start(rolloutId);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
assertThat(actions) //
.hasSize(amountOfTargets) //
@@ -2034,7 +2034,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
enableMultiAssignments();
rolloutManagement.start(rolloutId);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final List<Action> actions = deploymentManagement.findActionsAll(PAGE).getContent();
assertThat(actions).hasSize(amountOfTargets).allMatch(action -> !action.getWeight().isPresent());
}
@@ -2114,7 +2114,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final Rollout createdRollout = rolloutManagement.create(rolloutToCreate, 1, false, conditions);
// Let the executor handle created Rollout
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final Rollout testRollout = reloadRollout(createdRollout);
final List<RolloutGroup> rolloutGroups = rolloutGroupManagement
@@ -2175,8 +2175,6 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
}
}
private Rollout createTestRolloutWithTargetsAndDistributionSet(final int amountTargetsForRollout,
final int groupSize, final String successCondition, final String errorCondition, final String rolloutName,
final String targetPrefixName) {
@@ -2300,7 +2298,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
.withMessageContaining(errorMessage);
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final Rollout rollout = reloadRollout(createdRollout);
rolloutManagement.pauseRollout(rollout.getId());

View File

@@ -142,7 +142,7 @@ public class RepositoryEntityEventTest extends AbstractJpaIntegrationTest {
"controllerId==" + targetPrefixName + "-*", distributionSet, successCondition, errorCondition);
rolloutManagement.delete(createdRollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final RolloutDeletedEvent rolloutDeletedEvent = eventListener.waitForEvent(RolloutDeletedEvent.class);
assertThat(rolloutDeletedEvent).isNotNull();

View File

@@ -39,6 +39,7 @@ import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.QuotaManagement;
import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
import org.eclipse.hawkbit.repository.RolloutHandler;
import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
@@ -181,6 +182,9 @@ public abstract class AbstractIntegrationTest {
@Autowired
protected RolloutManagement rolloutManagement;
@Autowired
protected RolloutHandler rolloutHandler;
@Autowired
protected RolloutGroupManagement rolloutGroupManagement;

View File

@@ -36,6 +36,7 @@ import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.QuotaManagement;
import org.eclipse.hawkbit.repository.RolloutHandler;
import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
@@ -177,6 +178,9 @@ public class TestdataFactory {
@Autowired
private RolloutManagement rolloutManagement;
@Autowired
private RolloutHandler rolloutHandler;
@Autowired
private QuotaManagement quotaManagement;
@@ -1202,7 +1206,7 @@ public class TestdataFactory {
groupSize, confirmationRequired, conditions);
// Run here, because Scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
return rolloutManagement.get(rollout.getId()).get();
}
@@ -1253,7 +1257,7 @@ public class TestdataFactory {
rolloutManagement.start(rollout.getId());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
return reloadRollout(rollout);
}
@@ -1350,9 +1354,9 @@ public class TestdataFactory {
public Rollout createSoftDeletedRollout(final String prefix) {
final Rollout newRollout = createRollout(prefix);
rolloutManagement.start(newRollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
rolloutManagement.delete(newRollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
return newRollout;
}

View File

@@ -207,7 +207,7 @@ class MgmtActionResourceTest extends AbstractManagementApiIntegrationTest {
final Rollout rollout = testdataFactory.createRolloutByVariables("TestRollout", "TestDesc", 1,
"name==" + target1.getName(), ds, "50", "5");
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final String rsqlRolloutName = "rollout.name==" + rollout.getName();
final String rsqlRolloutId = "rollout.id==" + rollout.getId();

View File

@@ -301,9 +301,9 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
4, false, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// request the list of rollouts with full representation
mvc.perform(get("/rest/v1/rollouts?representation=full").accept(MediaType.APPLICATION_JSON))
@@ -458,7 +458,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
@Step
private void retrieveAndVerifyRolloutInRunning(final Rollout rollout) throws Exception {
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
mvc.perform(get("/rest/v1/rollouts/" + rollout.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
@@ -494,7 +494,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
@Step
private void retrieveAndVerifyRolloutInReady(final Rollout rollout) throws Exception {
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
mvc.perform(get("/rest/v1/rollouts/" + rollout.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
@@ -556,7 +556,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
postRollout("rollout2", 5, dsA.getId(), "id==target-0001*", 10, Action.ActionType.FORCED);
// Run here, because Scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
mvc.perform(get("/rest/v1/rollouts").accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
@@ -598,7 +598,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
startAt, forcetime);
// Run here, because Scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
retrieveAndCompareRolloutsContent(dsA, "/rest/v1/rollouts", false, true, startAt, forcetime);
retrieveAndCompareRolloutsContent(dsA, "/rest/v1/rollouts?representation=full", true, true, startAt, forcetime);
@@ -616,7 +616,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
postRollout("rollout2", 5, dsA.getId(), "id==target-0001*", 10, Action.ActionType.FORCED);
// Run here, because Scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
retrieveAndCompareRolloutsContent(dsA, "/rest/v1/rollouts", false);
retrieveAndCompareRolloutsContent(dsA, "/rest/v1/rollouts?representation=full", true);
@@ -634,7 +634,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
postRollout("rollout2", 5, dsA.getId(), "id==target*", 20, Action.ActionType.FORCED);
// Run here, because Scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
mvc.perform(get("/rest/v1/rollouts?limit=1").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
@@ -707,7 +707,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
.andExpect(jsonPath("status", equalTo("starting")));
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// check rollout is in running state
mvc.perform(get("/rest/v1/rollouts/{rolloutId}", rollout.getId()).accept(MediaType.APPLICATION_JSON))
@@ -733,7 +733,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
.andExpect(status().isOk());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// pausing rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/pause", rollout.getId())).andDo(MockMvcResultPrinter.print())
@@ -763,7 +763,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
.andExpect(status().isOk());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// pausing rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/pause", rollout.getId())).andDo(MockMvcResultPrinter.print())
@@ -797,7 +797,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
.andExpect(status().isOk());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// starting rollout - already started should lead into bad request
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId())).andDo(MockMvcResultPrinter.print())
@@ -838,7 +838,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
.andExpect(status().isOk());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// retrieve rollout groups from created rollout - 2 groups exists
// (amountTargets / groupSize = 2)
@@ -891,7 +891,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final RolloutGroup firstGroup, final RolloutGroup secondGroup, final boolean confirmationFlowEnabled,
final boolean confirmationRequired) throws Exception {
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups/{groupId}", rollout.getId(), firstGroup.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
@@ -923,7 +923,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
@Step
private void retrieveAndVerifyRolloutGroupInReady(final Rollout rollout, final RolloutGroup firstGroup)
throws Exception {
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups/{groupId}", rollout.getId(), firstGroup.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
@@ -1034,7 +1034,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
rolloutManagement.start(rollout.getId());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
final RolloutGroup firstGroup = rolloutGroupManagement
.findByRollout(PageRequest.of(0, 1, Direction.ASC, "id"), rollout.getId()).getContent().get(0);
@@ -1064,7 +1064,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
.andExpect(status().isOk());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// check if running
awaitRunningState(rollout.getId());
@@ -1280,7 +1280,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
// Run here, because Scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
return rolloutManagement.get(rollout.getId()).orElseThrow(NoSuchElementException::new);
}
@@ -1295,7 +1295,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*");
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/triggerNextGroup", rollout.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
@@ -1318,7 +1318,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
triggerNextGroupAndExpect(rollout, status().isBadRequest());
// READY state
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
triggerNextGroupAndExpect(rollout, status().isBadRequest());
// STARTING state
@@ -1326,7 +1326,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
triggerNextGroupAndExpect(rollout, status().isBadRequest());
// RUNNING state
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
triggerNextGroupAndExpect(rollout, status().isOk());
// PAUSED state
@@ -1341,7 +1341,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
// FINISHED state
setTargetsStatus(targets, Status.FINISHED);
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
triggerNextGroupAndExpect(rollout, status().isBadRequest());
}

View File

@@ -2118,7 +2118,7 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
final Rollout rollout = testdataFactory.createRolloutByVariables("My Rollout", "My Rollout Description", 1,
"name==trg*", ds, "50", "5");
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
// get all actions for the first target
final Target target = targets.get(0);

View File

@@ -196,7 +196,7 @@ public abstract class AbstractApiRestDocumentation extends AbstractRestIntegrati
// start the rollout and handle it
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
updatedTargets = Collections.singletonList(savedTarget);

View File

@@ -416,7 +416,7 @@ public class RolloutResourceDocumentationTest extends AbstractApiRestDocumentati
rolloutManagement.start(rollout.getId());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
mockMvc.perform(post(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}/pause", rollout.getId())
.accept(MediaTypes.HAL_JSON_VALUE)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
@@ -431,7 +431,7 @@ public class RolloutResourceDocumentationTest extends AbstractApiRestDocumentati
rolloutManagement.start(rollout.getId());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
rolloutManagement.pauseRollout(rollout.getId());
mockMvc.perform(post(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}/resume", rollout.getId())
@@ -471,7 +471,7 @@ public class RolloutResourceDocumentationTest extends AbstractApiRestDocumentati
rolloutManagement.start(rollout.getId());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
mockMvc.perform(
post(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}/triggerNextGroup", rollout.getId())
@@ -692,7 +692,7 @@ public class RolloutResourceDocumentationTest extends AbstractApiRestDocumentati
.withDefaults().successCondition(RolloutGroupSuccessCondition.THRESHOLD, "10").build());
// Run here, because Scheduler is disabled during tests
rolloutManagement.handleRollouts();
rolloutHandler.handleAll();
return rolloutManagement
.update(entityFactory.rollout().update(rollout.getId()).startAt(System.currentTimeMillis() + 1000).description("exampleDescription"));