Deleted rollouts are immutable (#475)

* Update throws read only exception if rollout is in deleting or deleted
state.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix typo.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
Kai Zimmermann
2017-04-05 17:15:59 +02:00
committed by GitHub
parent 6f0b25fb44
commit a5a505024b
4 changed files with 40 additions and 13 deletions

View File

@@ -19,6 +19,7 @@ import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
import org.eclipse.hawkbit.repository.builder.RolloutUpdate; import org.eclipse.hawkbit.repository.builder.RolloutUpdate;
import org.eclipse.hawkbit.repository.exception.ConstraintViolationException; import org.eclipse.hawkbit.repository.exception.ConstraintViolationException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException; import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
@@ -371,6 +372,9 @@ public interface RolloutManagement {
* *
* @throws EntityNotFoundException * @throws EntityNotFoundException
* if rollout or DS with given IDs do not exist * if rollout or DS with given IDs do not exist
* @throws EntityReadOnlyException
* if rollout is in soft deleted state, i.e. only kept as
* reference
* *
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE)

View File

@@ -36,6 +36,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.RolloutUpdatedEvent;
import org.eclipse.hawkbit.repository.exception.ConstraintViolationException; import org.eclipse.hawkbit.repository.exception.ConstraintViolationException;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException; import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
@@ -895,6 +896,8 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
final GenericRolloutUpdate update = (GenericRolloutUpdate) u; final GenericRolloutUpdate update = (GenericRolloutUpdate) u;
final JpaRollout rollout = getRolloutAndThrowExceptionIfNotFound(update.getId()); final JpaRollout rollout = getRolloutAndThrowExceptionIfNotFound(update.getId());
checkIfDeleted(update.getId(), rollout.getStatus());
update.getName().ifPresent(rollout::setName); update.getName().ifPresent(rollout::setName);
update.getDescription().ifPresent(rollout::setDescription); update.getDescription().ifPresent(rollout::setDescription);
update.getActionType().ifPresent(rollout::setActionType); update.getActionType().ifPresent(rollout::setActionType);
@@ -910,6 +913,12 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
return rolloutRepository.save(rollout); return rolloutRepository.save(rollout);
} }
private static void checkIfDeleted(final Long rolloutId, final RolloutStatus status) {
if (RolloutStatus.DELETING.equals(status) || RolloutStatus.DELETED.equals(status)) {
throw new EntityReadOnlyException("Rollout " + rolloutId + " is soft deleted and cannot be changed");
}
}
private JpaRollout getRolloutAndThrowExceptionIfNotFound(final Long rolloutId) { private JpaRollout getRolloutAndThrowExceptionIfNotFound(final Long rolloutId) {
return rolloutRepository.findById(rolloutId) return rolloutRepository.findById(rolloutId)
.orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId)); .orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId));

View File

@@ -9,6 +9,7 @@
package org.eclipse.hawkbit.repository.jpa; package org.eclipse.hawkbit.repository.jpa;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.Assertions.fail;
import java.util.ArrayList; import java.util.ArrayList;
@@ -36,6 +37,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.exception.ConstraintViolationException; import org.eclipse.hawkbit.repository.exception.ConstraintViolationException;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException; import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout; import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
@@ -1519,7 +1521,13 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
// verify // verify
final JpaRollout deletedRollout = rolloutRepository.findOne(createdRollout.getId()); final JpaRollout deletedRollout = rolloutRepository.findOne(createdRollout.getId());
assertThat(deletedRollout).isNotNull(); assertThat(deletedRollout).isNotNull();
assertThat(deletedRollout.getStatus()).isEqualTo(RolloutStatus.DELETED); assertThat(deletedRollout.getStatus()).isEqualTo(RolloutStatus.DELETED);
assertThatExceptionOfType(EntityReadOnlyException.class)
.isThrownBy(() -> rolloutManagement
.updateRollout(entityFactory.rollout().update(createdRollout.getId()).description("test")))
.withMessageContaining("" + createdRollout.getId());
assertThat(rolloutManagement.findAll(pageReq, true).getContent()).hasSize(1); assertThat(rolloutManagement.findAll(pageReq, true).getContent()).hasSize(1);
assertThat(rolloutManagement.findAll(pageReq, false).getContent()).hasSize(0); assertThat(rolloutManagement.findAll(pageReq, false).getContent()).hasSize(0);
assertThat(rolloutGroupManagement.findAllRolloutGroupsWithDetailedStatus(createdRollout.getId(), pageReq) assertThat(rolloutGroupManagement.findAllRolloutGroupsWithDetailedStatus(createdRollout.getId(), pageReq)

View File

@@ -25,6 +25,7 @@ import org.eclipse.hawkbit.repository.builder.RolloutCreate;
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate; import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
import org.eclipse.hawkbit.repository.builder.RolloutUpdate; import org.eclipse.hawkbit.repository.builder.RolloutUpdate;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.RepositoryModelConstants; import org.eclipse.hawkbit.repository.model.RepositoryModelConstants;
import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout;
@@ -51,13 +52,13 @@ import org.eclipse.hawkbit.ui.management.footer.ActionTypeOptionGroupLayout.Acti
import org.eclipse.hawkbit.ui.rollout.event.RolloutEvent; import org.eclipse.hawkbit.ui.rollout.event.RolloutEvent;
import org.eclipse.hawkbit.ui.rollout.groupschart.GroupsPieChart; import org.eclipse.hawkbit.ui.rollout.groupschart.GroupsPieChart;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil; import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; 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.UINotification; import org.eclipse.hawkbit.ui.utils.UINotification;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@@ -161,7 +162,8 @@ public class AddUpdateRolloutWindowLayout extends GridLayout {
AddUpdateRolloutWindowLayout(final RolloutManagement rolloutManagement, final TargetManagement targetManagement, AddUpdateRolloutWindowLayout(final RolloutManagement rolloutManagement, final TargetManagement targetManagement,
final UINotification uiNotification, final UiProperties uiProperties, final EntityFactory entityFactory, final UINotification uiNotification, final UiProperties uiProperties, final EntityFactory entityFactory,
final VaadinMessageSource i18n, final UIEventBus eventBus, final TargetFilterQueryManagement targetFilterQueryManagement) { final VaadinMessageSource i18n, final UIEventBus eventBus,
final TargetFilterQueryManagement targetFilterQueryManagement) {
actionTypeOptionGroupLayout = new ActionTypeOptionGroupLayout(i18n); actionTypeOptionGroupLayout = new ActionTypeOptionGroupLayout(i18n);
autoStartOptionGroupLayout = new AutoStartOptionGroupLayout(i18n); autoStartOptionGroupLayout = new AutoStartOptionGroupLayout(i18n);
this.rolloutManagement = rolloutManagement; this.rolloutManagement = rolloutManagement;
@@ -215,7 +217,8 @@ public class AddUpdateRolloutWindowLayout extends GridLayout {
private boolean duplicateCheck() { private boolean duplicateCheck() {
if (rolloutManagement.findRolloutByName(getRolloutName()).isPresent()) { if (rolloutManagement.findRolloutByName(getRolloutName()).isPresent()) {
uiNotification.displayValidationError(i18n.getMessage("message.rollout.duplicate.check", getRolloutName())); uiNotification
.displayValidationError(i18n.getMessage("message.rollout.duplicate.check", getRolloutName()));
return false; return false;
} }
return true; return true;
@@ -242,7 +245,7 @@ public class AddUpdateRolloutWindowLayout extends GridLayout {
Rollout updatedRollout; Rollout updatedRollout;
try { try {
updatedRollout = rolloutManagement.updateRollout(rolloutUpdate); updatedRollout = rolloutManagement.updateRollout(rolloutUpdate);
} catch (final EntityNotFoundException e) { } catch (final EntityNotFoundException | EntityReadOnlyException e) {
LOGGER.warn("Rollout was deleted. Redirect to Rollouts overview.", e); LOGGER.warn("Rollout was deleted. Redirect to Rollouts overview.", e);
uiNotification.displayWarning( uiNotification.displayWarning(
"Rollout with name " + rolloutName.getValue() + " was deleted. Update is not poosible"); "Rollout with name " + rolloutName.getValue() + " was deleted. Update is not poosible");
@@ -258,7 +261,8 @@ public class AddUpdateRolloutWindowLayout extends GridLayout {
final String rolloutNameVal = getRolloutName(); final String rolloutNameVal = getRolloutName();
if (!rollout.getName().equals(rolloutNameVal) if (!rollout.getName().equals(rolloutNameVal)
&& rolloutManagement.findRolloutByName(rolloutNameVal).isPresent()) { && rolloutManagement.findRolloutByName(rolloutNameVal).isPresent()) {
uiNotification.displayValidationError(i18n.getMessage("message.rollout.duplicate.check", rolloutNameVal)); uiNotification
.displayValidationError(i18n.getMessage("message.rollout.duplicate.check", rolloutNameVal));
return false; return false;
} }
return true; return true;
@@ -342,8 +346,8 @@ public class AddUpdateRolloutWindowLayout extends GridLayout {
} }
private CommonDialogWindow createWindow() { private CommonDialogWindow createWindow() {
return new WindowBuilder(SPUIDefinitions.CREATE_UPDATE_WINDOW).caption(i18n.getMessage("caption.configure.rollout")) return new WindowBuilder(SPUIDefinitions.CREATE_UPDATE_WINDOW)
.content(this).layout(this).i18n(i18n) .caption(i18n.getMessage("caption.configure.rollout")).content(this).layout(this).i18n(i18n)
.helpLink(uiProperties.getLinks().getDocumentation().getRolloutView()) .helpLink(uiProperties.getLinks().getDocumentation().getRolloutView())
.saveDialogCloseListener(new SaveOnDialogCloseListener()).buildCommonDialogWindow(); .saveDialogCloseListener(new SaveOnDialogCloseListener()).buildCommonDialogWindow();
} }
@@ -533,7 +537,8 @@ public class AddUpdateRolloutWindowLayout extends GridLayout {
i18n.getMessage("caption.rollout.tabs.simple")); i18n.getMessage("caption.rollout.tabs.simple"));
simpleTab.setId(UIComponentIdProvider.ROLLOUT_SIMPLE_TAB); simpleTab.setId(UIComponentIdProvider.ROLLOUT_SIMPLE_TAB);
final TabSheet.Tab advancedTab = tabSheet.addTab(defineGroupsLayout, i18n.getMessage("caption.rollout.tabs.advanced")); final TabSheet.Tab advancedTab = tabSheet.addTab(defineGroupsLayout,
i18n.getMessage("caption.rollout.tabs.advanced"));
advancedTab.setId(UIComponentIdProvider.ROLLOUT_ADVANCED_TAB); advancedTab.setId(UIComponentIdProvider.ROLLOUT_ADVANCED_TAB);
tabSheet.addSelectedTabChangeListener(event -> validateGroups()); tabSheet.addSelectedTabChangeListener(event -> validateGroups());
@@ -693,8 +698,8 @@ public class AddUpdateRolloutWindowLayout extends GridLayout {
private ComboBox createTargetFilterQueryCombo() { private ComboBox createTargetFilterQueryCombo() {
return new ComboBoxBuilder().setValueChangeListener(this::onTargetFilterChange) return new ComboBoxBuilder().setValueChangeListener(this::onTargetFilterChange)
.setPrompt(i18n.getMessage("prompt.target.filter")).setId(UIComponentIdProvider.ROLLOUT_TARGET_FILTER_COMBO_ID) .setPrompt(i18n.getMessage("prompt.target.filter"))
.buildCombBox(); .setId(UIComponentIdProvider.ROLLOUT_TARGET_FILTER_COMBO_ID).buildCombBox();
} }
private void onTargetFilterChange(final ValueChangeEvent event) { private void onTargetFilterChange(final ValueChangeEvent event) {
@@ -833,12 +838,13 @@ public class AddUpdateRolloutWindowLayout extends GridLayout {
@Override @Override
public void validate(final Object value) { public void validate(final Object value) {
if (isNoOfGroupsOrTargetFilterEmpty()) { if (isNoOfGroupsOrTargetFilterEmpty()) {
uiNotification.displayValidationError(i18n.getMessage("message.rollout.noofgroups.or.targetfilter.missing")); uiNotification
.displayValidationError(i18n.getMessage("message.rollout.noofgroups.or.targetfilter.missing"));
} else { } else {
if (value != null) { if (value != null) {
final int groupSize = getGroupSize(); final int groupSize = getGroupSize();
new IntegerRangeValidator(i18n.getMessage(MESSAGE_ROLLOUT_FIELD_VALUE_RANGE, 0, groupSize), 0, groupSize) new IntegerRangeValidator(i18n.getMessage(MESSAGE_ROLLOUT_FIELD_VALUE_RANGE, 0, groupSize), 0,
.validate(Integer.valueOf(value.toString())); groupSize).validate(Integer.valueOf(value.toString()));
} }
} }
} }