Add REST method for update rollout (#1749)

* adds PUT method for updating name and description of a rollout
* restrict RolloutUpdate to changing only name and description
* small refactoring

Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2024-06-24 09:16:39 +03:00
committed by GitHub
parent 297775f539
commit 40f99962d2
20 changed files with 321 additions and 343 deletions

View File

@@ -9,18 +9,122 @@
*/
package org.eclipse.hawkbit.repository.jpa.builder;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.builder.AbstractRolloutUpdateCreate;
import org.eclipse.hawkbit.repository.ValidString;
import org.eclipse.hawkbit.repository.builder.AbstractNamedEntityBuilder;
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.springframework.util.StringUtils;
import java.util.Optional;
public class JpaRolloutCreate extends AbstractNamedEntityBuilder<RolloutCreate> implements RolloutCreate {
public class JpaRolloutCreate extends AbstractRolloutUpdateCreate<RolloutCreate> implements RolloutCreate {
private final DistributionSetManagement distributionSetManagement;
protected Long distributionSetId;
@ValidString
protected String targetFilterQuery;
protected Action.ActionType actionType;
protected Long forcedTime;
protected Long startAt;
@Min(Action.WEIGHT_MIN)
@Max(Action.WEIGHT_MAX)
protected Integer weight;
private boolean dynamic;
JpaRolloutCreate(final DistributionSetManagement distributionSetManagement) {
this.distributionSetManagement = distributionSetManagement;
}
/**
* {@link DistributionSet} of rollout
*
* @param distributionSetId ID of the distributionSetId
* @return this builder
*/
public RolloutCreate distributionSetId(final long distributionSetId) {
this.distributionSetId = distributionSetId;
return this;
}
/**
* Filter of the rollout
*
* @param targetFilterQuery query
* @return this builder
*/
public RolloutCreate targetFilterQuery(final String targetFilterQuery) {
this.targetFilterQuery = StringUtils.trimWhitespace(targetFilterQuery);
return this;
}
/**
* {@link Action.ActionType} used for {@link Action}s
*
* @param actionType type
* @return this builder
*/
public RolloutCreate actionType(final Action.ActionType actionType) {
this.actionType = actionType;
return this;
}
/**
* forcedTime used for {@link Action}s
*
* @param forcedTime time
* @return this builder
*/
public RolloutCreate forcedTime(final Long forcedTime) {
this.forcedTime = forcedTime;
return this;
}
/**
* weight used for {@link Action}s
*
* @param weight weight
* @return this builder
*/
public RolloutCreate weight(final Integer weight) {
this.weight = weight;
return this;
}
/**
* Set start of the Rollout
*
* @param startAt start time point
* @return this builder
*/
public RolloutCreate startAt(final Long startAt) {
this.startAt = startAt;
return this;
}
public Optional<Long> getDistributionSetId() {
return Optional.ofNullable(distributionSetId);
}
public Optional<Action.ActionType> getActionType() {
return Optional.ofNullable(actionType);
}
public Optional<Long> getForcedTime() {
return Optional.ofNullable(forcedTime);
}
public Optional<Integer> getWeight() {
return Optional.ofNullable(weight);
}
public Optional<Long> getStartAt() {
return Optional.ofNullable(startAt);
}
public RolloutCreate dynamic(final boolean dynamic) {
this.dynamic = dynamic;
@@ -33,7 +137,7 @@ public class JpaRolloutCreate extends AbstractRolloutUpdateCreate<RolloutCreate>
rollout.setName(name);
rollout.setDescription(description);
rollout.setDistributionSet(distributionSetManagement.getValidAndComplete(set));
rollout.setDistributionSet(distributionSetManagement.getValidAndComplete(distributionSetId));
rollout.setTargetFilterQuery(targetFilterQuery);
rollout.setStartAt(startAt);
rollout.setWeight(weight);
@@ -49,4 +153,4 @@ public class JpaRolloutCreate extends AbstractRolloutUpdateCreate<RolloutCreate>
return rollout;
}
}
}

View File

@@ -58,7 +58,6 @@ import org.eclipse.hawkbit.repository.jpa.repository.RolloutRepository;
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.DistributionSet;
@@ -523,24 +522,9 @@ public class JpaRolloutManagement implements RolloutManagement {
final JpaRollout rollout = getRolloutAndThrowExceptionIfNotFound(update.getId());
checkIfDeleted(update.getId(), rollout.getStatus());
update.getName().ifPresent(rollout::setName);
update.getDescription().ifPresent(rollout::setDescription);
update.getActionType().ifPresent(rollout::setActionType);
update.getForcedTime().ifPresent(rollout::setForcedTime);
update.getWeight().ifPresent(rollout::setWeight);
// resetting back to manual start is done by setting start at time to
// null
rollout.setStartAt(update.getStartAt().orElse(null));
update.getSet().ifPresent(setId -> {
final DistributionSet set = distributionSetManagement.getValidAndComplete(setId);
rollout.setDistributionSet(set);
});
if (rolloutApprovalStrategy.isApprovalNeeded(rollout)) {
rollout.setStatus(RolloutStatus.WAITING_FOR_APPROVAL);
rollout.setApprovalDecidedBy(null);
rollout.setApprovalRemark(null);
}
return rolloutRepository.save(rollout);
}

View File

@@ -45,9 +45,8 @@ public class RolloutEventTest extends AbstractRemoteEntityEventTest<Rollout> {
.type("os").modules(Collections.singletonList(module.getId())));
return rolloutManagement.create(
entityFactory.rollout().create().name("exampleRollout").targetFilterQuery("controllerId==*").set(ds), 5,
entityFactory.rollout().create().name("exampleRollout").targetFilterQuery("controllerId==*").distributionSetId(ds), 5,
false, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "10").build());
}
}
}

View File

@@ -85,11 +85,10 @@ public class RolloutGroupEventTest extends AbstractRemoteEntityEventTest<Rollout
.type("os").modules(Collections.singletonList(module.getId())));
final Rollout entity = rolloutManagement.create(
entityFactory.rollout().create().name("exampleRollout").targetFilterQuery("controllerId==*").set(ds), 5,
entityFactory.rollout().create().name("exampleRollout").targetFilterQuery("controllerId==*").distributionSetId(ds), 5,
false, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "10").build());
return rolloutGroupManagement.findByRollout(PAGE, entity.getId()).getContent().get(0);
}
}
}

View File

@@ -119,7 +119,7 @@ public class ConcurrentDistributionSetInvalidationTest extends AbstractJpaIntegr
return rolloutManagement.create(entityFactory.rollout().create()
.name("verifyInvalidateDistributionSetWithLargeRolloutThrowsException").description("desc")
.targetFilterQuery("name==*").set(distributionSet).actionType(ActionType.FORCED),
.targetFilterQuery("name==*").distributionSetId(distributionSet).actionType(ActionType.FORCED),
quotaManagement.getMaxRolloutGroupsPerRollout(), false, conditions);
}

View File

@@ -58,7 +58,6 @@ import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
@@ -1408,7 +1407,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
.errorAction(RolloutGroupErrorAction.PAUSE, null).build();
final RolloutCreate rollout = entityFactory.rollout().create().name(rolloutName).description(rolloutName)
.targetFilterQuery("controllerId==" + targetPrefixName + "-*").set(distributionSet);
.targetFilterQuery("controllerId==" + targetPrefixName + "-*").distributionSetId(distributionSet);
assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> rolloutManagement.create(rollout, amountGroups, false, conditions));
@@ -1436,7 +1435,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// group1 exceeds the quota
assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> rolloutManagement.create(
entityFactory.rollout().create().name(rolloutName).description(rolloutName)
.targetFilterQuery("controllerId==" + rolloutName + "-*").set(distributionSet),
.targetFilterQuery("controllerId==" + rolloutName + "-*").distributionSetId(distributionSet),
Arrays.asList(group1, group2), conditions));
// create group definitions
@@ -1448,7 +1447,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// group4 exceeds the quota
assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> rolloutManagement.create(
entityFactory.rollout().create().name(rolloutName).description(rolloutName)
.targetFilterQuery("controllerId==" + rolloutName + "-*").set(distributionSet),
.targetFilterQuery("controllerId==" + rolloutName + "-*").distributionSetId(distributionSet),
Arrays.asList(group3, group4), conditions));
// create group definitions
@@ -1462,15 +1461,14 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// should work fine
assertThat(rolloutManagement.create(
entityFactory.rollout().create().name(rolloutName).description(rolloutName)
.targetFilterQuery("controllerId==" + rolloutName + "-*").set(distributionSet),
.targetFilterQuery("controllerId==" + rolloutName + "-*").distributionSetId(distributionSet),
Arrays.asList(group5, group6, group7), conditions)).isNotNull();
}
@Test
@Description("Verify the creation and the automatic start of a rollout.")
void createAndAutoStartRollout() {
@Description("Verify the update of a rollout")
void updateRollout() {
final int amountTargetsForRollout = 50;
final int amountGroups = 5;
final String successCondition = "50";
@@ -1487,31 +1485,13 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// schedule rollout auto start into the future
final Long myRolloutId = myRollout.getId();
rolloutManagement
.update(entityFactory.rollout().update(myRolloutId).startAt(System.currentTimeMillis() + 60000));
.update(entityFactory.rollout().update(myRolloutId).name("newName").description("newDesc"));
rolloutHandler.handleAll();
// rollout should not have been started
myRollout = getRollout(myRolloutId);
assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.READY);
// schedule to now
rolloutManagement.update(entityFactory.rollout().update(myRolloutId).startAt(System.currentTimeMillis()));
rolloutHandler.handleAll();
myRollout = getRollout(myRolloutId);
assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.STARTING);
// Run here, because scheduler is disabled during tests
rolloutHandler.handleAll();
awaitRunningState(myRolloutId);
myRollout = getRollout(myRolloutId);
assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.RUNNING);
final Map<TotalTargetCountStatus.Status, Long> expectedTargetCountStatus = createInitStatusMap();
expectedTargetCountStatus.put(TotalTargetCountStatus.Status.RUNNING, 10L);
expectedTargetCountStatus.put(TotalTargetCountStatus.Status.SCHEDULED, 40L);
validateRolloutActionStatus(myRolloutId, expectedTargetCountStatus);
assertThat(myRollout.getName()).isEqualTo("newName");
assertThat(myRollout.getDescription()).isEqualTo("newDesc");
}
private Rollout reloadRollout(final Rollout r) {
@@ -1766,7 +1746,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
.errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition)
.errorAction(RolloutGroupErrorAction.PAUSE, null).build();
final RolloutCreate rolloutToCreate = entityFactory.rollout().create().name(rolloutName)
.description("some description").targetFilterQuery("id==" + rolloutName + "-*").set(distributionSet);
.description("some description").targetFilterQuery("id==" + rolloutName + "-*").distributionSetId(distributionSet);
Rollout myRollout = rolloutManagement.create(rolloutToCreate, amountGroups, false, conditions);
myRollout = getRollout(myRollout.getId());
@@ -1942,7 +1922,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final String prefixRolloutRunning = randomString + "1";
final RolloutCreate rolloutRunningCreate = entityFactory.rollout().create()
.name(prefixRolloutRunning + "-testRollout").targetFilterQuery("name==" + randomString + "*")
.set(testDs);
.distributionSetId(testDs);
Rollout rolloutRunning = rolloutManagement.create(rolloutRunningCreate, 1, false, conditions);
// Let the executor handle created Rollout
@@ -1955,7 +1935,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final String prefixRolloutReady = randomString + "2";
final RolloutCreate rolloutReadyCreate = entityFactory.rollout().create()
.name(prefixRolloutReady + "-testRollout").targetFilterQuery("name==" + randomString + "*").set(testDs);
.name(prefixRolloutReady + "-testRollout").targetFilterQuery("name==" + randomString + "*").distributionSetId(testDs);
Rollout rolloutReady = rolloutManagement.create(rolloutReadyCreate, 1, false, conditions);
// Let the executor handle created Rollout
rolloutHandler.handleAll();
@@ -2066,34 +2046,6 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
"desc", 2, "name==*", distributionSet, "50", "80"));
}
@Test
@Description("Verifies that an exception is thrown when trying to update a rollout with an invalidated distribution set.")
void updateRolloutWithInvalidDistributionSet() {
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
testdataFactory.createTarget();
final Rollout rollout = testdataFactory.createRolloutByVariables("updateRolloutWithInvalidDistributionSet",
"desc", 2, "name==*", distributionSet, "50", "80");
final DistributionSet invalidDistributionSet = testdataFactory.createAndInvalidateDistributionSet();
assertThatExceptionOfType(InvalidDistributionSetException.class)
.as("Invalid distributionSet should throw an exception").isThrownBy(() -> rolloutManagement
.update(entityFactory.rollout().update(rollout.getId()).set(invalidDistributionSet.getId())));
}
@Test
@Description("Verifies that an exception is thrown when trying to update a rollout with an incomplete distribution set.")
void updateRolloutWithIncompleteDistributionSet() {
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
testdataFactory.createTarget();
final Rollout rollout = testdataFactory.createRolloutByVariables("updateRolloutWithIncompleteDistributionSet",
"desc", 2, "name==*", distributionSet, "50", "80");
final DistributionSet incompleteDistributionSet = testdataFactory.createIncompleteDistributionSet();
assertThatExceptionOfType(IncompleteDistributionSetException.class)
.as("Incomplete distributionSet should throw an exception").isThrownBy(() -> rolloutManagement.update(
entityFactory.rollout().update(rollout.getId()).set(incompleteDistributionSet.getId())));
}
@Test
@Description("Verify the that only compatible targets are part of a Rollout.")
void createAndStartRolloutWithTargetTypes() {
@@ -2114,7 +2066,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build();
final RolloutCreate rolloutToCreate = entityFactory.rollout().create().name(rolloutName)
.targetFilterQuery("name==*").set(testDs);
.targetFilterQuery("name==*").distributionSetId(testDs);
final Rollout createdRollout = rolloutManagement.create(rolloutToCreate, 1, false, conditions);
@@ -2156,7 +2108,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
return entityFactory.rollout().create().name(rolloutName)
.description("This is a test description for the rollout")
.targetFilterQuery("controllerId==" + rolloutName + "-*").set(distributionSet);
.targetFilterQuery("controllerId==" + rolloutName + "-*").distributionSetId(distributionSet);
}
private void validateRolloutGroupActionStatus(final RolloutGroup rolloutGroup,

View File

@@ -98,9 +98,9 @@ public class RSQLRolloutGroupFieldTest extends AbstractJpaIntegrationTest {
private Rollout createRollout(final String name, final int amountGroups, final long distributionSetId,
final String targetFilterQuery) {
return rolloutManagement.create(
entityFactory.rollout().create().set(distributionSetManagement.get(distributionSetId).get()).name(name)
entityFactory.rollout().create().distributionSetId(distributionSetManagement.get(distributionSetId).get()).name(name)
.targetFilterQuery(targetFilterQuery),
amountGroups, false, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
}
}
}