Trigger next rollout group - backend and management API implementatio… (#1294)
* Trigger next rollout group - backend and management API implementations. Backend and management API tests. * Trigger next rollout group - Fixed resource documentation test. * Trigger next rollout group - Fixed resource documentation test. * add rest docs * Trigger next rollout group - UI changes. New button for trigger next rollout group in rollout view. * add error test for rest api * Trigger next rollout group - Added test for triggering next group for all rollout states. * add confirm * fix test * replace DB calls * fix translation * fix error message Signed-off-by: Dimitar Shterev <dimitar.shterev@bosch.io> Signed-off-by: Stefan Klotz <stefan.klotz@bosch.io> Co-authored-by: Stefan Klotz <stefan.klotz@bosch.io>
This commit is contained in:
@@ -463,4 +463,20 @@ public interface RolloutManagement {
|
|||||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_UPDATE)
|
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_UPDATE)
|
||||||
void cancelRolloutsForDistributionSet(DistributionSet set);
|
void cancelRolloutsForDistributionSet(DistributionSet set);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers next group of a rollout for processing even success threshold
|
||||||
|
* isn't met yet. Current running groups will not change their status.
|
||||||
|
*
|
||||||
|
* @param rolloutId
|
||||||
|
* the rollout to be paused.
|
||||||
|
*
|
||||||
|
* @throws EntityNotFoundException
|
||||||
|
* if rollout or group with given ID does not exist
|
||||||
|
* @throws RolloutIllegalStateException
|
||||||
|
* if given rollout is not in {@link RolloutStatus#RUNNING}.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_UPDATE)
|
||||||
|
void triggerNextGroup(long rolloutId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import static org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupCreate.a
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -48,6 +49,7 @@ import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecuto
|
|||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout_;
|
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.rsql.RSQLUtility;
|
||||||
import org.eclipse.hawkbit.repository.jpa.specifications.RolloutSpecification;
|
import org.eclipse.hawkbit.repository.jpa.specifications.RolloutSpecification;
|
||||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||||
@@ -128,6 +130,9 @@ public class JpaRolloutManagement implements RolloutManagement {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private RolloutStatusCache rolloutStatusCache;
|
private RolloutStatusCache rolloutStatusCache;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private StartNextGroupRolloutGroupSuccessAction startNextRolloutGroupAction;
|
||||||
|
|
||||||
private final TargetManagement targetManagement;
|
private final TargetManagement targetManagement;
|
||||||
private final DistributionSetManagement distributionSetManagement;
|
private final DistributionSetManagement distributionSetManagement;
|
||||||
private final VirtualPropertyReplacer virtualPropertyReplacer;
|
private final VirtualPropertyReplacer virtualPropertyReplacer;
|
||||||
@@ -746,4 +751,30 @@ public class JpaRolloutManagement implements RolloutManagement {
|
|||||||
baseFilter, totalTargets, dsTypeId));
|
baseFilter, totalTargets, dsTypeId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Retryable(include = {
|
||||||
|
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||||
|
public void triggerNextGroup(final long rolloutId) {
|
||||||
|
final JpaRollout rollout = getRolloutAndThrowExceptionIfNotFound(rolloutId);
|
||||||
|
if (RolloutStatus.RUNNING != rollout.getStatus()) {
|
||||||
|
throw new RolloutIllegalStateException("Rollout is not in running state");
|
||||||
|
}
|
||||||
|
final List<RolloutGroup> groups = rollout.getRolloutGroups();
|
||||||
|
|
||||||
|
final boolean isNextGroupTriggerable = groups.stream()
|
||||||
|
.anyMatch(g -> RolloutGroupStatus.SCHEDULED.equals(g.getStatus()));
|
||||||
|
|
||||||
|
if (!isNextGroupTriggerable) {
|
||||||
|
throw new RolloutIllegalStateException("Rollout does not have any groups left to be triggered");
|
||||||
|
}
|
||||||
|
|
||||||
|
final RolloutGroup latestRunning = groups.stream()
|
||||||
|
.sorted(Comparator.comparingLong(RolloutGroup::getId).reversed())
|
||||||
|
.filter(g -> RolloutGroupStatus.RUNNING.equals(g.getStatus())).findFirst()
|
||||||
|
.orElseThrow(() -> new RolloutIllegalStateException("No group is running"));
|
||||||
|
|
||||||
|
startNextRolloutGroupAction.eval(rollout, latestRunning, latestRunning.getSuccessActionExp());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,5 +173,4 @@ public interface RolloutGroupRepository
|
|||||||
@Modifying
|
@Modifying
|
||||||
@Query("DELETE FROM JpaRolloutGroup g where g.id in :rolloutGroupIds")
|
@Query("DELETE FROM JpaRolloutGroup g where g.id in :rolloutGroupIds")
|
||||||
void deleteByIds(@Param("rolloutGroupIds") List<Long> rolloutGroups);
|
void deleteByIds(@Param("rolloutGroupIds") List<Long> rolloutGroups);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
verifyThrownExceptionBy(() -> rolloutManagement.update(entityFactory.rollout().update(NOT_EXIST_IDL)),
|
verifyThrownExceptionBy(() -> rolloutManagement.update(entityFactory.rollout().update(NOT_EXIST_IDL)),
|
||||||
"Rollout");
|
"Rollout");
|
||||||
|
verifyThrownExceptionBy(() -> rolloutManagement.triggerNextGroup(NOT_EXIST_IDL), "Rollout");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -2070,4 +2071,94 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
() -> rolloutManagement.get(myRolloutId).orElseThrow(NoSuchElementException::new))
|
() -> rolloutManagement.get(myRolloutId).orElseThrow(NoSuchElementException::new))
|
||||||
.getStatus().equals(RolloutStatus.RUNNING));
|
.getStatus().equals(RolloutStatus.RUNNING));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Verifying that next group is started on manual trigger next group.")
|
||||||
|
void checkRunningRolloutsManualTriggerNextGroup() {
|
||||||
|
|
||||||
|
final int amountTargetsForRollout = 15;
|
||||||
|
final int amountOtherTargets = 0;
|
||||||
|
final int amountGroups = 3;
|
||||||
|
final String successCondition = "100";
|
||||||
|
final String errorCondition = "80";
|
||||||
|
|
||||||
|
final Rollout createdRollout = createAndStartRollout(amountTargetsForRollout, amountOtherTargets, amountGroups,
|
||||||
|
successCondition, errorCondition);
|
||||||
|
|
||||||
|
// triggers next group
|
||||||
|
rolloutManagement.triggerNextGroup(createdRollout.getId());
|
||||||
|
|
||||||
|
// second group should in running state
|
||||||
|
List<RolloutGroup> rolloutGroups = rolloutGroupManagement
|
||||||
|
.findByRollout(new OffsetBasedPageRequest(0, 10, Sort.by(Direction.ASC, "id")), createdRollout.getId())
|
||||||
|
.getContent();
|
||||||
|
assertThat(rolloutGroups.get(0).getStatus()).isEqualTo(RolloutGroupStatus.RUNNING);
|
||||||
|
assertThat(rolloutGroups.get(1).getStatus()).isEqualTo(RolloutGroupStatus.RUNNING);
|
||||||
|
assertThat(rolloutGroups.get(2).getStatus()).isEqualTo(RolloutGroupStatus.SCHEDULED);
|
||||||
|
|
||||||
|
// triggers next group
|
||||||
|
rolloutManagement.triggerNextGroup(createdRollout.getId());
|
||||||
|
|
||||||
|
// third group should be in running state
|
||||||
|
rolloutGroups = rolloutGroupManagement
|
||||||
|
.findByRollout(new OffsetBasedPageRequest(0, 10, Sort.by(Direction.ASC, "id")), createdRollout.getId())
|
||||||
|
.getContent();
|
||||||
|
assertThat(rolloutGroups.get(0).getStatus()).isEqualTo(RolloutGroupStatus.RUNNING);
|
||||||
|
assertThat(rolloutGroups.get(1).getStatus()).isEqualTo(RolloutGroupStatus.RUNNING);
|
||||||
|
assertThat(rolloutGroups.get(2).getStatus()).isEqualTo(RolloutGroupStatus.RUNNING);
|
||||||
|
|
||||||
|
// finish action of all groups and verify rollout
|
||||||
|
final Slice<JpaAction> runningActionsSlice = actionRepository.findByRolloutIdAndStatus(PAGE,
|
||||||
|
createdRollout.getId(), Status.RUNNING);
|
||||||
|
runningActionsSlice.getContent().forEach(this::finishAction);
|
||||||
|
|
||||||
|
verifyRolloutAndAllGroupsAreFinished(createdRollout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Trigger next rollout group if rollout is in wrong state")
|
||||||
|
void triggeringNextGroupRolloutWrongState() {
|
||||||
|
|
||||||
|
final int amountTargetsForRollout = 15;
|
||||||
|
final int amountOtherTargets = 0;
|
||||||
|
final int amountGroups = 3;
|
||||||
|
final String successCondition = "100";
|
||||||
|
final String errorCondition = "80";
|
||||||
|
|
||||||
|
final String errorMessage = "Rollout is not in running state";
|
||||||
|
|
||||||
|
final Rollout createdRollout = createSimpleTestRolloutWithTargetsAndDistributionSet(amountTargetsForRollout,
|
||||||
|
amountOtherTargets, amountGroups, successCondition, errorCondition);
|
||||||
|
|
||||||
|
// check CREATING state
|
||||||
|
assertThatExceptionOfType(RolloutIllegalStateException.class)
|
||||||
|
.isThrownBy(() -> rolloutManagement.triggerNextGroup(createdRollout.getId()))
|
||||||
|
.withMessageContaining(errorMessage);
|
||||||
|
|
||||||
|
rolloutManagement.start(createdRollout.getId());
|
||||||
|
// check STARTING state
|
||||||
|
assertThatExceptionOfType(RolloutIllegalStateException.class)
|
||||||
|
.isThrownBy(() -> rolloutManagement.triggerNextGroup(createdRollout.getId()))
|
||||||
|
.withMessageContaining(errorMessage);
|
||||||
|
|
||||||
|
// Run here, because scheduler is disabled during tests
|
||||||
|
rolloutManagement.handleRollouts();
|
||||||
|
final Rollout rollout = reloadRollout(createdRollout);
|
||||||
|
|
||||||
|
rolloutManagement.pauseRollout(rollout.getId());
|
||||||
|
|
||||||
|
// check STOPPED state
|
||||||
|
assertThatExceptionOfType(RolloutIllegalStateException.class)
|
||||||
|
.isThrownBy(() -> rolloutManagement.triggerNextGroup(createdRollout.getId()))
|
||||||
|
.withMessageContaining(errorMessage);
|
||||||
|
|
||||||
|
final Slice<JpaAction> runningActionsSlice = actionRepository.findByRolloutIdAndStatus(PAGE,
|
||||||
|
createdRollout.getId(), Status.RUNNING);
|
||||||
|
runningActionsSlice.getContent().forEach(this::finishAction);
|
||||||
|
|
||||||
|
// check FINISHED state
|
||||||
|
assertThatExceptionOfType(RolloutIllegalStateException.class)
|
||||||
|
.isThrownBy(() -> rolloutManagement.triggerNextGroup(createdRollout.getId()))
|
||||||
|
.withMessageContaining(errorMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -236,4 +236,16 @@ public interface MgmtRolloutRestApi {
|
|||||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) int pagingLimitParam,
|
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) int pagingLimitParam,
|
||||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) String sortParam,
|
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) String sortParam,
|
||||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) String rsqlParam);
|
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) String rsqlParam);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the POST request to force trigger processing next group of a rollout even success threshold isn't yet met
|
||||||
|
*
|
||||||
|
* @param rolloutId
|
||||||
|
* the ID of the rollout to trigger next group.
|
||||||
|
* @return OK response (200). In case of any
|
||||||
|
* exception the corresponding errors occur.
|
||||||
|
*/
|
||||||
|
@PostMapping(value = "/{rolloutId}/triggerNextGroup", produces = { MediaTypes.HAL_JSON_VALUE,
|
||||||
|
MediaType.APPLICATION_JSON_VALUE })
|
||||||
|
ResponseEntity<Void> triggerNextGroup(@PathVariable("rolloutId") Long rolloutId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ final class MgmtRolloutMapper {
|
|||||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).start(rollout.getId())).withRel("start"));
|
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).start(rollout.getId())).withRel("start"));
|
||||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).pause(rollout.getId())).withRel("pause"));
|
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).pause(rollout.getId())).withRel("pause"));
|
||||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).resume(rollout.getId())).withRel("resume"));
|
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).resume(rollout.getId())).withRel("resume"));
|
||||||
|
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).triggerNextGroup(rollout.getId())).withRel("triggerNextGroup"));
|
||||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).approve(rollout.getId(), null)).withRel("approve"));
|
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).approve(rollout.getId(), null)).withRel("approve"));
|
||||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).deny(rollout.getId(), null)).withRel("deny"));
|
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).deny(rollout.getId(), null)).withRel("deny"));
|
||||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRolloutGroups(rollout.getId(),
|
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRolloutGroups(rollout.getId(),
|
||||||
|
|||||||
@@ -254,4 +254,10 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi {
|
|||||||
final List<MgmtTarget> rest = MgmtTargetMapper.toResponse(rolloutGroupTargets.getContent());
|
final List<MgmtTarget> rest = MgmtTargetMapper.toResponse(rolloutGroupTargets.getContent());
|
||||||
return ResponseEntity.ok(new PagedList<>(rest, rolloutGroupTargets.getTotalElements()));
|
return ResponseEntity.ok(new PagedList<>(rest, rolloutGroupTargets.getTotalElements()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Void> triggerNextGroup(@PathVariable("rolloutId") final Long rolloutId) {
|
||||||
|
this.rolloutManagement.triggerNextGroup(rolloutId);
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.awaitility.Awaitility;
|
import org.awaitility.Awaitility;
|
||||||
import org.awaitility.Duration;
|
import org.awaitility.Duration;
|
||||||
@@ -36,13 +37,16 @@ import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
|||||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
|
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||||
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
|
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
|
||||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||||
|
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus;
|
||||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
|
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
|
||||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
|
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
|
||||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
|
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
|
||||||
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
|
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
|
||||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||||
import org.eclipse.hawkbit.rest.util.JsonBuilder;
|
import org.eclipse.hawkbit.rest.util.JsonBuilder;
|
||||||
@@ -52,6 +56,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Sort.Direction;
|
import org.springframework.data.domain.Sort.Direction;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.web.servlet.ResultMatcher;
|
||||||
|
|
||||||
import io.qameta.allure.Description;
|
import io.qameta.allure.Description;
|
||||||
import io.qameta.allure.Feature;
|
import io.qameta.allure.Feature;
|
||||||
@@ -386,6 +391,8 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
|
|||||||
.andExpect(jsonPath("$._links.pause.href", allOf(startsWith(HREF_ROLLOUT_PREFIX), endsWith("/pause"))))
|
.andExpect(jsonPath("$._links.pause.href", allOf(startsWith(HREF_ROLLOUT_PREFIX), endsWith("/pause"))))
|
||||||
.andExpect(
|
.andExpect(
|
||||||
jsonPath("$._links.resume.href", allOf(startsWith(HREF_ROLLOUT_PREFIX), endsWith("/resume"))))
|
jsonPath("$._links.resume.href", allOf(startsWith(HREF_ROLLOUT_PREFIX), endsWith("/resume"))))
|
||||||
|
.andExpect(jsonPath("$._links.triggerNextGroup.href",
|
||||||
|
allOf(startsWith(HREF_ROLLOUT_PREFIX), endsWith("/triggerNextGroup"))))
|
||||||
.andExpect(jsonPath("$._links.groups.href",
|
.andExpect(jsonPath("$._links.groups.href",
|
||||||
allOf(startsWith(HREF_ROLLOUT_PREFIX), containsString("/deploygroups"))))
|
allOf(startsWith(HREF_ROLLOUT_PREFIX), containsString("/deploygroups"))))
|
||||||
.andExpect(jsonPath("$.deleted", equalTo(false)));
|
.andExpect(jsonPath("$.deleted", equalTo(false)));
|
||||||
@@ -1033,14 +1040,95 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
|
|||||||
|
|
||||||
private Rollout createRollout(final String name, final int amountGroups, final long distributionSetId,
|
private Rollout createRollout(final String name, final int amountGroups, final long distributionSetId,
|
||||||
final String targetFilterQuery) {
|
final String targetFilterQuery) {
|
||||||
final Rollout rollout = rolloutManagement.create(
|
final Rollout rollout = createRolloutInCreatingSatate(name, amountGroups, distributionSetId, targetFilterQuery);
|
||||||
entityFactory.rollout().create().name(name).set(distributionSetId).targetFilterQuery(targetFilterQuery),
|
|
||||||
amountGroups, new RolloutGroupConditionBuilder().withDefaults()
|
|
||||||
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
|
|
||||||
|
|
||||||
// Run here, because Scheduler is disabled during tests
|
// Run here, because Scheduler is disabled during tests
|
||||||
rolloutManagement.handleRollouts();
|
rolloutManagement.handleRollouts();
|
||||||
|
|
||||||
return rolloutManagement.get(rollout.getId()).orElseThrow(NoSuchElementException::new);
|
return rolloutManagement.get(rollout.getId()).orElseThrow(NoSuchElementException::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Rollout createRolloutInCreatingSatate(final String name, final int amountGroups,
|
||||||
|
final long distributionSetId, final String targetFilterQuery) {
|
||||||
|
return rolloutManagement.create(
|
||||||
|
entityFactory.rollout().create().name(name).set(distributionSetId).targetFilterQuery(targetFilterQuery),
|
||||||
|
amountGroups, new RolloutGroupConditionBuilder().withDefaults()
|
||||||
|
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Trigger next rollout group")
|
||||||
|
void triggeringNextGroupRollout() throws Exception {
|
||||||
|
// setup
|
||||||
|
final int amountTargets = 20;
|
||||||
|
testdataFactory.createTargets(amountTargets, "rollout", "rollout");
|
||||||
|
final DistributionSet dsA = testdataFactory.createDistributionSet("");
|
||||||
|
|
||||||
|
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*");
|
||||||
|
rolloutManagement.start(rollout.getId());
|
||||||
|
rolloutManagement.handleRollouts();
|
||||||
|
|
||||||
|
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/triggerNextGroup", rollout.getId()))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||||
|
|
||||||
|
final List<RolloutGroupStatus> groupStatus = rolloutGroupManagement.findByRollout(PAGE, rollout.getId())
|
||||||
|
.getContent().stream().map(RolloutGroup::getStatus).collect(Collectors.toList());
|
||||||
|
assertThat(groupStatus).containsExactly(RolloutGroupStatus.RUNNING, RolloutGroupStatus.RUNNING,
|
||||||
|
RolloutGroupStatus.SCHEDULED, RolloutGroupStatus.SCHEDULED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Trigger next rollout group if rollout is in wrong state")
|
||||||
|
void triggeringNextGroupRolloutWrongState() throws Exception {
|
||||||
|
final int amountTargets = 2;
|
||||||
|
final List<Target> targets = testdataFactory.createTargets(amountTargets, "rollout");
|
||||||
|
final DistributionSet dsA = testdataFactory.createDistributionSet("");
|
||||||
|
|
||||||
|
// CREATING state
|
||||||
|
final Rollout rollout = createRolloutInCreatingSatate("rollout1", 3, dsA.getId(), "controllerId==rollout*");
|
||||||
|
triggerNextGroupAndExpect(rollout, status().isBadRequest());
|
||||||
|
|
||||||
|
// READY state
|
||||||
|
rolloutManagement.handleRollouts();
|
||||||
|
triggerNextGroupAndExpect(rollout, status().isBadRequest());
|
||||||
|
|
||||||
|
// STARTING state
|
||||||
|
rolloutManagement.start(rollout.getId());
|
||||||
|
triggerNextGroupAndExpect(rollout, status().isBadRequest());
|
||||||
|
|
||||||
|
// RUNNING state
|
||||||
|
rolloutManagement.handleRollouts();
|
||||||
|
triggerNextGroupAndExpect(rollout, status().isOk());
|
||||||
|
|
||||||
|
// PAUSED state
|
||||||
|
rolloutManagement.pauseRollout(rollout.getId());
|
||||||
|
triggerNextGroupAndExpect(rollout, status().isBadRequest());
|
||||||
|
|
||||||
|
rolloutManagement.resumeRollout(rollout.getId());
|
||||||
|
triggerNextGroupAndExpect(rollout, status().isOk());
|
||||||
|
|
||||||
|
// last group already running
|
||||||
|
triggerNextGroupAndExpect(rollout, status().isBadRequest());
|
||||||
|
|
||||||
|
// FINISHED state
|
||||||
|
setTargetsStatus(targets, Status.FINISHED);
|
||||||
|
rolloutManagement.handleRollouts();
|
||||||
|
triggerNextGroupAndExpect(rollout, status().isBadRequest());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTargetsStatus(final List<Target> targets, final Status status) {
|
||||||
|
for (final Target target : targets) {
|
||||||
|
final Long action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).toList().get(0)
|
||||||
|
.getId();
|
||||||
|
controllerManagement
|
||||||
|
.addUpdateActionStatus(entityFactory.actionStatus().create(action).status(status).message("test"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -356,6 +356,39 @@ include::../errors/406.adoc[]
|
|||||||
include::../errors/429.adoc[]
|
include::../errors/429.adoc[]
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
== POST /rest/v1/rollouts/{rolloutId}/triggerNextGroup
|
||||||
|
|
||||||
|
=== Implementation Notes
|
||||||
|
Handles the POST request of triggering the next group of a rollout within Hawkbit. Required Permission: UPDATE_ROLLOUT
|
||||||
|
|
||||||
|
=== Trigger next group
|
||||||
|
|
||||||
|
|
||||||
|
==== CURL
|
||||||
|
|
||||||
|
include::{snippets}/rollouts/trigger-next-group/curl-request.adoc[]
|
||||||
|
|
||||||
|
|
||||||
|
==== Request URL
|
||||||
|
|
||||||
|
include::{snippets}/rollouts/trigger-next-group/http-request.adoc[]
|
||||||
|
|
||||||
|
==== Response example
|
||||||
|
|
||||||
|
include::{snippets}/rollouts/trigger-next-group/http-response.adoc[]
|
||||||
|
|
||||||
|
=== Error responses
|
||||||
|
|
||||||
|
|===
|
||||||
|
| HTTP Status Code | Reason | Response Model
|
||||||
|
include::../errors/400.adoc[]
|
||||||
|
include::../errors/401.adoc[]
|
||||||
|
include::../errors/403.adoc[]
|
||||||
|
include::../errors/405.adoc[]
|
||||||
|
include::../errors/406.adoc[]
|
||||||
|
include::../errors/429.adoc[]
|
||||||
|
|===
|
||||||
|
|
||||||
== DELETE /rest/v1/rollouts/{rolloutId}
|
== DELETE /rest/v1/rollouts/{rolloutId}
|
||||||
|
|
||||||
=== Implementation Notes
|
=== Implementation Notes
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ public final class MgmtApiModelProperties {
|
|||||||
public static final String ROLLOUT_LINKS_START_SYNC = "Link to start the rollout in sync mode";
|
public static final String ROLLOUT_LINKS_START_SYNC = "Link to start the rollout in sync mode";
|
||||||
public static final String ROLLOUT_LINKS_START_ASYNC = "Link to start the rollout in async mode";
|
public static final String ROLLOUT_LINKS_START_ASYNC = "Link to start the rollout in async mode";
|
||||||
public static final String ROLLOUT_LINKS_PAUSE = "Link to pause a running rollout";
|
public static final String ROLLOUT_LINKS_PAUSE = "Link to pause a running rollout";
|
||||||
|
public static final String ROLLOUT_LINKS_TRIGGER_NEXT_GROUP = "Link for triggering next rollout group on a running rollout";
|
||||||
public static final String ROLLOUT_LINKS_RESUME = "Link to resume a paused rollout";
|
public static final String ROLLOUT_LINKS_RESUME = "Link to resume a paused rollout";
|
||||||
public static final String ROLLOUT_LINKS_APPROVE = "Link to approve a rollout";
|
public static final String ROLLOUT_LINKS_APPROVE = "Link to approve a rollout";
|
||||||
public static final String ROLLOUT_LINKS_DENY = "Link to deny a rollout";
|
public static final String ROLLOUT_LINKS_DENY = "Link to deny a rollout";
|
||||||
|
|||||||
@@ -147,6 +147,8 @@ public class RolloutResourceDocumentationTest extends AbstractApiRestDocumentati
|
|||||||
.description(MgmtApiModelProperties.ROLLOUT_LINKS_START_SYNC));
|
.description(MgmtApiModelProperties.ROLLOUT_LINKS_START_SYNC));
|
||||||
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.pause")
|
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.pause")
|
||||||
.description(MgmtApiModelProperties.ROLLOUT_LINKS_PAUSE));
|
.description(MgmtApiModelProperties.ROLLOUT_LINKS_PAUSE));
|
||||||
|
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.triggerNextGroup")
|
||||||
|
.description(MgmtApiModelProperties.ROLLOUT_LINKS_TRIGGER_NEXT_GROUP));
|
||||||
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.resume")
|
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.resume")
|
||||||
.description(MgmtApiModelProperties.ROLLOUT_LINKS_RESUME));
|
.description(MgmtApiModelProperties.ROLLOUT_LINKS_RESUME));
|
||||||
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.groups")
|
allFieldDescriptor.add(fieldWithPath(arrayPrefix + "_links.groups")
|
||||||
@@ -444,6 +446,23 @@ public class RolloutResourceDocumentationTest extends AbstractApiRestDocumentati
|
|||||||
pathParameters(parameterWithName("rolloutId").description(ApiModelPropertiesGeneric.ITEM_ID))));
|
pathParameters(parameterWithName("rolloutId").description(ApiModelPropertiesGeneric.ITEM_ID))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Handles the POST request of triggering the next group of a rollout. Required Permission: "
|
||||||
|
+ SpPermission.UPDATE_ROLLOUT)
|
||||||
|
public void triggerNextGroup() throws Exception {
|
||||||
|
final Rollout rollout = createRolloutEntity();
|
||||||
|
rolloutManagement.start(rollout.getId());
|
||||||
|
|
||||||
|
// Run here, because scheduler is disabled during tests
|
||||||
|
rolloutManagement.handleRollouts();
|
||||||
|
|
||||||
|
mockMvc.perform(
|
||||||
|
post(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}/triggerNextGroup", rollout.getId())
|
||||||
|
.accept(MediaTypes.HAL_JSON_VALUE))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andDo(this.document.document(
|
||||||
|
pathParameters(parameterWithName("rolloutId").description(ApiModelPropertiesGeneric.ITEM_ID))));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Handles the GET request of retrieving the deploy groups of a rollout. Required Permission: "
|
@Description("Handles the GET request of retrieving the deploy groups of a rollout. Required Permission: "
|
||||||
+ SpPermission.READ_ROLLOUT)
|
+ SpPermission.READ_ROLLOUT)
|
||||||
|
|||||||
@@ -19,12 +19,15 @@ import java.util.stream.Collectors;
|
|||||||
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
||||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||||
|
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
|
||||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||||
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
|
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
|
||||||
|
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
|
||||||
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus.Status;
|
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus.Status;
|
||||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||||
|
import org.eclipse.hawkbit.ui.common.ConfirmationDialog;
|
||||||
import org.eclipse.hawkbit.ui.common.builder.GridComponentBuilder;
|
import org.eclipse.hawkbit.ui.common.builder.GridComponentBuilder;
|
||||||
import org.eclipse.hawkbit.ui.common.builder.StatusIconBuilder.ActionTypeIconSupplier;
|
import org.eclipse.hawkbit.ui.common.builder.StatusIconBuilder.ActionTypeIconSupplier;
|
||||||
import org.eclipse.hawkbit.ui.common.builder.StatusIconBuilder.RolloutStatusIconSupplier;
|
import org.eclipse.hawkbit.ui.common.builder.StatusIconBuilder.RolloutStatusIconSupplier;
|
||||||
@@ -54,6 +57,8 @@ import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
|
|||||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||||
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
|
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
|
||||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.cronutils.utils.StringUtils;
|
import com.cronutils.utils.StringUtils;
|
||||||
import com.google.common.base.Predicates;
|
import com.google.common.base.Predicates;
|
||||||
@@ -70,6 +75,8 @@ import com.vaadin.ui.renderers.HtmlRenderer;
|
|||||||
* Rollout list grid component.
|
* Rollout list grid component.
|
||||||
*/
|
*/
|
||||||
public class RolloutGrid extends AbstractGrid<ProxyRollout, String> {
|
public class RolloutGrid extends AbstractGrid<ProxyRollout, String> {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(RolloutGrid.class);
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final String ROLLOUT_CAPTION_MSG_KEY = "caption.rollout";
|
private static final String ROLLOUT_CAPTION_MSG_KEY = "caption.rollout";
|
||||||
|
|
||||||
@@ -88,6 +95,7 @@ public class RolloutGrid extends AbstractGrid<ProxyRollout, String> {
|
|||||||
private static final String APPROVE_BUTTON_ID = "approve";
|
private static final String APPROVE_BUTTON_ID = "approve";
|
||||||
private static final String RUN_BUTTON_ID = "run";
|
private static final String RUN_BUTTON_ID = "run";
|
||||||
private static final String PAUSE_BUTTON_ID = "pause";
|
private static final String PAUSE_BUTTON_ID = "pause";
|
||||||
|
private static final String TRIGGER_NEXT_GROUP_BUTTON_ID = "triggerNextGroup";
|
||||||
private static final String UPDATE_BUTTON_ID = "update";
|
private static final String UPDATE_BUTTON_ID = "update";
|
||||||
private static final String COPY_BUTTON_ID = "copy";
|
private static final String COPY_BUTTON_ID = "copy";
|
||||||
private static final String DELETE_BUTTON_ID = "delete";
|
private static final String DELETE_BUTTON_ID = "delete";
|
||||||
@@ -226,6 +234,11 @@ public class RolloutGrid extends AbstractGrid<ProxyRollout, String> {
|
|||||||
return RolloutStatus.RUNNING == status;
|
return RolloutStatus.RUNNING == status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isTriggerNextGroupAllowed(final ProxyRollout rollout) {
|
||||||
|
final Long scheduled = rollout.getStatusTotalCountMap().get(TotalTargetCountStatus.Status.SCHEDULED);
|
||||||
|
return RolloutStatus.RUNNING == rollout.getStatus() && scheduled != null && scheduled > 0;
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isApprovingAllowed(final RolloutStatus status) {
|
private static boolean isApprovingAllowed(final RolloutStatus status) {
|
||||||
return RolloutStatus.WAITING_FOR_APPROVAL == status;
|
return RolloutStatus.WAITING_FOR_APPROVAL == status;
|
||||||
}
|
}
|
||||||
@@ -335,6 +348,15 @@ public class RolloutGrid extends AbstractGrid<ProxyRollout, String> {
|
|||||||
permissionChecker.hasRolloutHandlePermission() && isPausingAllowed(rollout.getStatus()));
|
permissionChecker.hasRolloutHandlePermission() && isPausingAllowed(rollout.getStatus()));
|
||||||
actionColumns.add(GridComponentBuilder.addIconColumn(this, pauseButton, PAUSE_BUTTON_ID, null));
|
actionColumns.add(GridComponentBuilder.addIconColumn(this, pauseButton, PAUSE_BUTTON_ID, null));
|
||||||
|
|
||||||
|
final ValueProvider<ProxyRollout, Button> triggerNextGroupButton = rollout -> GridComponentBuilder
|
||||||
|
.buildActionButton(i18n, clickEvent -> triggerNextRolloutGroup(rollout.getId(), rollout.getStatus()),
|
||||||
|
VaadinIcons.STEP_FORWARD, UIMessageIdProvider.TOOLTIP_ROLLOUT_TRIGGER_NEXT_GROUP,
|
||||||
|
SPUIStyleDefinitions.STATUS_ICON_NEUTRAL,
|
||||||
|
UIComponentIdProvider.ROLLOUT_TRIGGER_NEXT_GROUP_BUTTON_ID + "." + rollout.getId(),
|
||||||
|
permissionChecker.hasRolloutUpdatePermission() && isTriggerNextGroupAllowed(rollout));
|
||||||
|
actionColumns.add(
|
||||||
|
GridComponentBuilder.addIconColumn(this, triggerNextGroupButton, TRIGGER_NEXT_GROUP_BUTTON_ID, null));
|
||||||
|
|
||||||
final ValueProvider<ProxyRollout, Button> updateButton = rollout -> GridComponentBuilder.buildActionButton(i18n,
|
final ValueProvider<ProxyRollout, Button> updateButton = rollout -> GridComponentBuilder.buildActionButton(i18n,
|
||||||
clickEvent -> updateRollout(rollout), VaadinIcons.EDIT, UIMessageIdProvider.TOOLTIP_ROLLOUT_UPDATE,
|
clickEvent -> updateRollout(rollout), VaadinIcons.EDIT, UIMessageIdProvider.TOOLTIP_ROLLOUT_UPDATE,
|
||||||
SPUIStyleDefinitions.STATUS_ICON_NEUTRAL,
|
SPUIStyleDefinitions.STATUS_ICON_NEUTRAL,
|
||||||
@@ -488,4 +510,30 @@ public class RolloutGrid extends AbstractGrid<ProxyRollout, String> {
|
|||||||
}
|
}
|
||||||
return tooltipText.toString();
|
return tooltipText.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void triggerNextRolloutGroup(final Long rolloutId, final RolloutStatus rolloutStatus) {
|
||||||
|
if (RolloutStatus.RUNNING != rolloutStatus) {
|
||||||
|
uiNotification.displayValidationError(i18n.getMessage("message.rollout.trigger.next.group.not.running"));
|
||||||
|
} else {
|
||||||
|
final ConfirmationDialog triggerNextDialog = createTriggerNextGroupDialog(rolloutId);
|
||||||
|
UI.getCurrent().addWindow(triggerNextDialog.getWindow());
|
||||||
|
triggerNextDialog.getWindow().bringToFront();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConfirmationDialog createTriggerNextGroupDialog(final Long rolloutId) {
|
||||||
|
final String caption = i18n.getMessage("caption.rollout.confirm.trigger.next");
|
||||||
|
final String question = i18n.getMessage("message.rollout.confirm.trigger.next");
|
||||||
|
return new ConfirmationDialog(i18n, caption, question, ok -> {
|
||||||
|
if (Boolean.TRUE.equals(ok)) {
|
||||||
|
try {
|
||||||
|
rolloutManagement.triggerNextGroup(rolloutId);
|
||||||
|
uiNotification.displaySuccess(i18n.getMessage("message.rollout.trigger.next.group.success"));
|
||||||
|
} catch (final RolloutIllegalStateException e) {
|
||||||
|
LOGGER.warn("Error on manually triggering next rollout group: {}", e.getMessage());
|
||||||
|
uiNotification.displayValidationError(i18n.getMessage("message.rollout.trigger.next.group.error"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, UIComponentIdProvider.ROLLOUT_TRIGGER_NEXT_CONFIRMATION_DIALOG);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1154,6 +1154,11 @@ public final class UIComponentIdProvider {
|
|||||||
*/
|
*/
|
||||||
public static final String ROLLOUT_PAUSE_BUTTON_ID = ROLLOUT_ACTION_ID + ".7";
|
public static final String ROLLOUT_PAUSE_BUTTON_ID = ROLLOUT_ACTION_ID + ".7";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rollout trigger next group button id.
|
||||||
|
*/
|
||||||
|
public static final String ROLLOUT_TRIGGER_NEXT_GROUP_BUTTON_ID = ROLLOUT_ACTION_ID + ".13";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rollout update button id.
|
* Rollout update button id.
|
||||||
*/
|
*/
|
||||||
@@ -1465,6 +1470,11 @@ public final class UIComponentIdProvider {
|
|||||||
*/
|
*/
|
||||||
public static final String ROLLOUT_DELETE_CONFIRMATION_DIALOG = "rollout.delete.confirmation.window";
|
public static final String ROLLOUT_DELETE_CONFIRMATION_DIALOG = "rollout.delete.confirmation.window";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Id of the rollout 'trigger next group' confirmation window
|
||||||
|
*/
|
||||||
|
public static final String ROLLOUT_TRIGGER_NEXT_CONFIRMATION_DIALOG = "rollout.triggernext.confirmation.window";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Id of the target filter deletion confirmation window
|
* Id of the target filter deletion confirmation window
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -351,6 +351,8 @@ public final class UIMessageIdProvider {
|
|||||||
|
|
||||||
public static final String TOOLTIP_UPLOAD_STATUS_PREFIX = "tooltip.upload.status.";
|
public static final String TOOLTIP_UPLOAD_STATUS_PREFIX = "tooltip.upload.status.";
|
||||||
|
|
||||||
|
public static final String TOOLTIP_ROLLOUT_TRIGGER_NEXT_GROUP = "tooltip.rollout.triggernextgroup";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private Constructor.
|
* Private Constructor.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -336,6 +336,7 @@ tooltip.active.action.status.inactiveerror=In-active Error
|
|||||||
tooltip.rollout.run = Run
|
tooltip.rollout.run = Run
|
||||||
tooltip.rollout.approve = Approve
|
tooltip.rollout.approve = Approve
|
||||||
tooltip.rollout.pause = Pause
|
tooltip.rollout.pause = Pause
|
||||||
|
tooltip.rollout.triggernextgroup = Trigger next group
|
||||||
tooltip.rollout.update = Edit..
|
tooltip.rollout.update = Edit..
|
||||||
tooltip.rollout.copy = Copy..
|
tooltip.rollout.copy = Copy..
|
||||||
tooltip.delete = Delete..
|
tooltip.delete = Delete..
|
||||||
@@ -773,6 +774,9 @@ message.rollout.max.group.size.exceeded.advanced = The maximum size of {0} targe
|
|||||||
message.rollout.approval.required = You should approve or reject the Rollout
|
message.rollout.approval.required = You should approve or reject the Rollout
|
||||||
message.rollout.started = Rollout {0} started successfully
|
message.rollout.started = Rollout {0} started successfully
|
||||||
message.rollout.paused = Rollout {0} paused successfully
|
message.rollout.paused = Rollout {0} paused successfully
|
||||||
|
message.rollout.trigger.next.group.not.running = Rollout is not in RUNNING state
|
||||||
|
message.rollout.trigger.next.group.success = Next group successfully triggered
|
||||||
|
message.rollout.trigger.next.group.error = Could not trigger next group
|
||||||
message.rollout.resumed = Rollout {0} resumed successfully
|
message.rollout.resumed = Rollout {0} resumed successfully
|
||||||
message.rollout.deleted = Rollout {0} deleted successfully
|
message.rollout.deleted = Rollout {0} deleted successfully
|
||||||
message.rollout.noofgroups.or.targetfilter.missing = Please enter number of groups and select target filter
|
message.rollout.noofgroups.or.targetfilter.missing = Please enter number of groups and select target filter
|
||||||
@@ -808,6 +812,10 @@ caption.rollout.start.auto.desc = The rollout is started as soon as it is create
|
|||||||
caption.rollout.start.scheduled = Scheduled
|
caption.rollout.start.scheduled = Scheduled
|
||||||
caption.rollout.start.scheduled.desc = The rollout starts as soon as it is ready and the set time has passed.
|
caption.rollout.start.scheduled.desc = The rollout starts as soon as it is ready and the set time has passed.
|
||||||
label.rollout.calculating = Calculating groups ...
|
label.rollout.calculating = Calculating groups ...
|
||||||
|
|
||||||
|
caption.rollout.confirm.trigger.next = Trigger next rollout group
|
||||||
|
message.rollout.confirm.trigger.next = You are about to trigger the next rollout group.\nAre you sure?
|
||||||
|
|
||||||
#rollout - end
|
#rollout - end
|
||||||
|
|
||||||
#Menu
|
#Menu
|
||||||
|
|||||||
Reference in New Issue
Block a user