Rollout retry (#1454)
* Rollout retry mechanism initial commit Signed-off-by: Stanislav Trailov <Stanislav.Trailov@bosch.io> * Remove test target fields for filter query Signed-off-by: Stanislav Trailov <Stanislav.Trailov@bosch.io> * minor refactoring Signed-off-by: Stanislav Trailov <Stanislav.Trailov@bosch.io> * Fixes after review Signed-off-by: Stanislav Trailov <Stanislav.Trailov@bosch.io> * more refactoring after review Signed-off-by: Stanislav Trailov <Stanislav.Trailov@bosch.io> * skip compatibility check of dstype for retried rollout Signed-off-by: Stanislav Trailov <Stanislav.Trailov@bosch.io> * remove dsType from javadoc Signed-off-by: Stanislav Trailov <Stanislav.Trailov@bosch.io> --------- Signed-off-by: Stanislav Trailov <Stanislav.Trailov@bosch.io>
This commit is contained in:
committed by
GitHub
parent
22ce1c27a4
commit
44e7a72be3
@@ -132,6 +132,18 @@ final class MgmtRolloutMapper {
|
||||
.weight(restRequest.getWeight());
|
||||
}
|
||||
|
||||
static RolloutCreate fromRetriedRollout(final EntityFactory entityFactory, final Rollout rollout) {
|
||||
return entityFactory.rollout().create()
|
||||
.name(rollout.getName().concat("_retry"))
|
||||
.description(rollout.getDescription())
|
||||
.set(rollout.getDistributionSet())
|
||||
.targetFilterQuery("failedrollout==".concat(String.valueOf(rollout.getId())))
|
||||
.actionType(rollout.getActionType())
|
||||
.forcedTime(rollout.getForcedTime())
|
||||
.startAt(rollout.getStartAt())
|
||||
.weight(null);
|
||||
}
|
||||
|
||||
static RolloutGroupCreate fromRequest(final EntityFactory entityFactory, final MgmtRolloutGroup restRequest) {
|
||||
|
||||
return entityFactory.rolloutGroup().create().name(restRequest.getName())
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
|
||||
@@ -39,6 +40,7 @@ import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
@@ -47,7 +49,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -311,6 +312,28 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi {
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtRolloutResponseBody> retryRollout(final String rolloutId) {
|
||||
final Rollout rolloutForRetry = this.rolloutManagement.get(Long.parseLong(rolloutId))
|
||||
.orElseThrow(EntityNotFoundException::new);
|
||||
|
||||
if (rolloutForRetry.isDeleted()) {
|
||||
throw new EntityNotFoundException(Rollout.class, rolloutId);
|
||||
}
|
||||
|
||||
if (!rolloutForRetry.getStatus().equals(Rollout.RolloutStatus.FINISHED)) {
|
||||
throw new ValidationException("Rollout must be finished in order to be retried!");
|
||||
}
|
||||
|
||||
final RolloutCreate create = MgmtRolloutMapper.fromRetriedRollout(entityFactory, rolloutForRetry);
|
||||
final RolloutGroupConditions groupConditions = new RolloutGroupConditionBuilder().withDefaults().build();
|
||||
|
||||
final Rollout retriedRollout = rolloutManagement.create(create, 1, false,
|
||||
groupConditions);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(MgmtRolloutMapper.toResponseRollout(retriedRollout, true));
|
||||
}
|
||||
|
||||
private static MgmtRepresentationMode parseRepresentationMode(final String representationModeParam) {
|
||||
return MgmtRepresentationMode.fromValue(representationModeParam).orElseGet(() -> {
|
||||
// no need for a 400, just apply a safe fallback
|
||||
|
||||
@@ -25,6 +25,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
@@ -55,6 +56,7 @@ import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.eclipse.hawkbit.rest.util.JsonBuilder;
|
||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
@@ -1577,6 +1579,99 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Retry rollout test scenario")
|
||||
public void retryRolloutTest() throws Exception {
|
||||
|
||||
final DistributionSet dsA = testdataFactory.createDistributionSet("");
|
||||
final List<Target> successTargets = testdataFactory.createTargets("retryRolloutTargetSuccess-", 6);
|
||||
final List<Target> failedTargets = testdataFactory.createTargets("retryRolloutTargetFailed-", 4);
|
||||
|
||||
final List<Target> allTargets = new ArrayList<>(successTargets);
|
||||
allTargets.addAll(failedTargets);
|
||||
|
||||
postRollout("rolloutToBeRetried", 1, dsA.getId(), "id==retryRolloutTarget*", 10, Action.ActionType.FORCED);
|
||||
|
||||
Rollout rollout = rolloutManagement.getByName("rolloutToBeRetried").orElseThrow();
|
||||
|
||||
// no scheduler so invoke here
|
||||
rolloutHandler.handleAll();
|
||||
rolloutManagement.start(rollout.getId());
|
||||
// no scheduler so invoke here
|
||||
rolloutHandler.handleAll();
|
||||
|
||||
|
||||
testdataFactory.sendUpdateActionStatusToTargets(successTargets, Status.FINISHED, "Finished successfully!");
|
||||
testdataFactory.sendUpdateActionStatusToTargets(failedTargets, Status.ERROR, "Finished error!");
|
||||
|
||||
rolloutHandler.handleAll();
|
||||
|
||||
for (Target target : allTargets) {
|
||||
final List<Action> actions = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent();
|
||||
for (Action action : actions) {
|
||||
if (action.getTarget().getControllerId().startsWith("retryRolloutTargetFailed")) {
|
||||
Assertions.assertEquals(Status.ERROR, action.getStatus());
|
||||
} else {
|
||||
Assertions.assertEquals(Status.FINISHED, action.getStatus());
|
||||
}
|
||||
Assertions.assertEquals(rollout.getId(), action.getRollout().getId());
|
||||
}
|
||||
}
|
||||
|
||||
//retry rollout
|
||||
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/retry", rollout.getId())).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().is(201));
|
||||
|
||||
//search for _retried suffix
|
||||
Rollout retriedRollout = rolloutManagement.getByName(rollout.getName() + "_retry").orElseThrow();
|
||||
//assert 4 targets involved
|
||||
rolloutHandler.handleAll();
|
||||
|
||||
rolloutManagement.start(retriedRollout.getId());
|
||||
rolloutHandler.handleAll();
|
||||
|
||||
for (Target target : failedTargets) {
|
||||
// for failed targets - check for 2 actions - one from old rollout and one from the retried
|
||||
List<Action> actions = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent();
|
||||
Assertions.assertEquals(2, actions.size());
|
||||
Assertions.assertEquals(Status.ERROR, actions.get(0).getStatus());
|
||||
Assertions.assertEquals(rollout.getId(), actions.get(0).getRollout().getId());
|
||||
Assertions.assertEquals(Status.RUNNING, actions.get(1).getStatus());
|
||||
Assertions.assertEquals(retriedRollout.getId(), actions.get(1).getRollout().getId());
|
||||
}
|
||||
|
||||
for (Target target : successTargets) {
|
||||
//ensure no other actions from the success targets are created
|
||||
List<Action> actions = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).getContent();
|
||||
Assertions.assertEquals(1, actions.size());
|
||||
Assertions.assertEquals(rollout.getId(), actions.get(0).getRollout().getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Retrying a running rollout should not be allowed.")
|
||||
public void retryNotFinishedRolloutShouldNotBeAllowed() throws Exception {
|
||||
final DistributionSet dsA = testdataFactory.createDistributionSet("");
|
||||
testdataFactory.createTargets("retryRolloutTarget-", 10);
|
||||
postRollout("rolloutToBeRetried", 1, dsA.getId(), "id==retryRolloutTarget*", 10, Action.ActionType.FORCED);
|
||||
Rollout rollout = rolloutManagement.getByName("rolloutToBeRetried").orElseThrow();
|
||||
// no scheduler so invoke here
|
||||
rolloutHandler.handleAll();
|
||||
rolloutManagement.start(rollout.getId());
|
||||
// no scheduler so invoke here
|
||||
rolloutHandler.handleAll();
|
||||
|
||||
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/retry", rollout.getId())).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Retrying a non-existing rollout should lead to NOT FOUND.")
|
||||
public void retryNonExistingRolloutShouldLeadToNotFound() throws Exception {
|
||||
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/retry", 6782623)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
private void triggerNextGroupAndExpect(final Rollout rollout, final ResultMatcher expect) throws Exception {
|
||||
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/triggerNextGroup", rollout.getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(expect);
|
||||
@@ -1596,6 +1691,10 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
|
||||
retrieveAndCompareRolloutsContent(dsA, urlTemplate, isFullRepresentation, false, null, null);
|
||||
}
|
||||
|
||||
private Rollout getRollout(final long rolloutId) {
|
||||
return rolloutManagement.get(rolloutId).orElseThrow(NoSuchElementException::new);
|
||||
}
|
||||
|
||||
private void retrieveAndCompareRolloutsContent(final DistributionSet dsA, final String urlTemplate,
|
||||
final boolean isFullRepresentation, final boolean isStartTypeScheduled, final Long startAt,
|
||||
final Long forcetime) throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user