Introduce Stop of a rollout (#2595)

* Stop of a rollout feature

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>

* remove some test comments

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>

* make stop transactional

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>

* attempt to fix hibernate failed tests

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>

* fix some sonar issues

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>

* changes after review

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>

* fix build

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>

* fixes after review

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>

* finish all rollout groups on deletion of rollout

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>

* refactor finishing groups

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>

* fix RolloutManagementTest

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>

---------

Signed-off-by: strailov <Stanislav.Trailov@bosch.io>
This commit is contained in:
Stanislav Trailov
2025-08-12 17:13:50 +03:00
committed by GitHub
parent 4566702030
commit 45cd012532
25 changed files with 581 additions and 140 deletions

View File

@@ -1685,7 +1685,7 @@ class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegrationTe
* Verify invalidation of distribution sets that removes distribution sets from auto assignments, stops rollouts and cancels assignments
*/
@Test
void invalidateDistributionSet() throws Exception {
void softInvalidateDistributionSet() throws Exception {
DistributionSet distributionSet = testdataFactory.createDistributionSet();
final List<Target> targets = testdataFactory.createTargets(5, "invalidateDistributionSet");
// the distribution set is locked and the old instance become stale
@@ -1697,7 +1697,6 @@ class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegrationTe
final JSONObject jsonObject = new JSONObject();
jsonObject.put("actionCancelationType", "soft");
jsonObject.put("cancelRollouts", true);
mvc.perform(post("/rest/v1/distributionsets/{ds}/invalidate", distributionSet.getId())
.content(jsonObject.toString()).contentType(MediaType.APPLICATION_JSON))
@@ -1706,7 +1705,11 @@ class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegrationTe
assertThat(targetFilterQueryManagement.get(targetFilterQuery.getId()).get().getAutoAssignDistributionSet())
.isNull();
assertThat(rolloutManagement.get(rollout.getId()).get().getStatus()).isIn(RolloutStatus.STOPPING,
RolloutStatus.FINISHED);
RolloutStatus.STOPPED);
//then enforce executor to stop the rollout and check
rolloutHandler.handleAll();
assertThat(rolloutManagement.get(rollout.getId()).get().getStatus()).isIn(RolloutStatus.STOPPED);
for (final Target target : targets) {
assertThat(targetManagement.get(target.getId()).get().getUpdateStatus())
.isEqualTo(TargetUpdateStatus.PENDING);
@@ -1717,6 +1720,69 @@ class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegrationTe
}
}
@Test
void forceInvalidateDistributionSet() throws Exception {
DistributionSet distributionSet = testdataFactory.createDistributionSet();
final List<Target> targets = testdataFactory.createTargets(5, "invalidateDistributionSet");
distributionSet = assignDistributionSet(distributionSet, targets).getDistributionSet();
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement.create(
Create.builder().name("invalidateDistributionSet").query("name==*").autoAssignDistributionSet(distributionSet).build());
final Rollout rollout = testdataFactory.createRolloutByVariables("invalidateDistributionSet", "desc", 2,
"name==*", distributionSet, "50", "80");
final JSONObject jsonObject = new JSONObject();
jsonObject.put("actionCancelationType", "force");
mvc.perform(post("/rest/v1/distributionsets/{ds}/invalidate", distributionSet.getId())
.content(jsonObject.toString()).contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
assertThat(targetFilterQueryManagement.get(targetFilterQuery.getId()).get().getAutoAssignDistributionSet())
.isNull();
assertThat(rolloutManagement.get(rollout.getId()).get().getStatus()).isIn(RolloutStatus.DELETING,
RolloutStatus.DELETED);
//then enforce executor to stop the rollout and check
rolloutHandler.handleAll();
// assert rollout is deleted
assertThat(rolloutManagement.get(rollout.getId())).isEmpty();
for (final Target target : targets) {
assertThat(targetManagement.get(target.getId()).get().getUpdateStatus())
.isEqualTo(TargetUpdateStatus.IN_SYNC);
assertThat(deploymentManagement.findActionsByTarget(target.getControllerId(), PageRequest.of(0, 100))
.getNumberOfElements()).isEqualTo(1);
assertThat(deploymentManagement.findActionsByTarget(target.getControllerId(), PageRequest.of(0, 100))
.getContent().get(0).getStatus()).isEqualTo(Status.CANCELED);
}
}
@Test
void invalidateDistributionSetWithNoneCancellation() throws Exception {
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
final List<Target> targets = testdataFactory.createTargets(5, "invalidateDistributionSet");
Rollout rollout = testdataFactory.createRolloutByVariables("invalidateDistributionSet", "desc", 1,
"name==*", distributionSet, "50", "80");
rollout = testdataFactory.startRollout(rollout);
final JSONObject jsonObject = new JSONObject();
jsonObject.put("actionCancelationType", "none");
mvc.perform(post("/rest/v1/distributionsets/{ds}/invalidate", distributionSet.getId())
.content(jsonObject.toString()).contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
assertThat(rolloutManagement.get(rollout.getId()).get().getStatus()).isIn(RolloutStatus.RUNNING);
for (final Target target : targets) {
assertThat(targetManagement.get(target.getId()).get().getUpdateStatus())
.isEqualTo(TargetUpdateStatus.PENDING);
assertThat(deploymentManagement.findActionsByTarget(target.getControllerId(), PageRequest.of(0, 100))
.getNumberOfElements()).isEqualTo(1);
assertThat(deploymentManagement.findActionsByTarget(target.getControllerId(), PageRequest.of(0, 100))
.getContent().get(0).getStatus()).isEqualTo(Status.RUNNING);
}
}
/**
* Tests the lock. It is verified that the distribution set can be marked as locked through update operation.
*/

View File

@@ -31,6 +31,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import org.awaitility.Awaitility;
@@ -1461,6 +1462,55 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
.andExpect(jsonPath("$.deleted", equalTo(true)));
assertStatusIs(rollout, RolloutStatus.DELETED);
List<Action> rolloutActions =
deploymentManagement.findActions("rollout.id==" + rollout.getId(), PAGE).getContent();
for (Action action : rolloutActions) {
Assertions.assertEquals(Status.CANCELED, action.getStatus());
}
// ensure groups are in final state
List<RolloutGroup> groups = rolloutGroupManagement.findByRollout(rollout.getId(), PAGE).getContent();
for (RolloutGroup rolloutGroup : groups) {
Assertions.assertEquals(RolloutGroupStatus.FINISHED, rolloutGroup.getStatus());
}
}
@Test
void stopRunningRollout() throws Exception {
final Rollout rollout = testdataFactory.createAndStartRollout();
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/stop", rollout.getId()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
mvc.perform(get("/rest/v1/rollouts/{rolloutid}", rollout.getId()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.status", equalTo("stopping")));
// force executor to retrigger
rolloutHandler.handleAll();
List<Action> rolloutActions =
deploymentManagement.findActions("rollout.id==" + rollout.getId(), PAGE).getContent();
for (Action action : rolloutActions) {
Awaitility.await()
.atMost(30, TimeUnit.SECONDS)
.untilAsserted(() -> Assertions.assertEquals(Status.CANCELING, action.getStatus()));
}
// assume that the targets have agreed to cancel the actions
rolloutActions.forEach(action -> controllerManagement.addCancelActionStatus(
Action.ActionStatusCreate.builder().actionId(action.getId()).status(Status.CANCELED).build()
));
// force executor to retrigger
rolloutHandler.handleAll();
// rollout should be in stopped state after all actions are cancelled
mvc.perform(get("/rest/v1/rollouts/{rolloutid}", rollout.getId()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.status", equalTo("stopped")));
}
/**