Greg Padgett has uploaded a new change for review. Change subject: [WIP] core: introduce RemoveSnapshotSingleDiskLive BLL command ......................................................................
[WIP] core: introduce RemoveSnapshotSingleDiskLive BLL command Backend command to merge snapshots while a VM is running. Change-Id: Ic47eb91a0ea1fe150e3b2152e2c9d5f1f2eb3678 Bug-Url: https://bugzilla.redhat.com/?????? Signed-off-by: Greg Padgett <gpadg...@redhat.com> --- M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotCommand.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotSingleDiskCommand.java A backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotSingleDiskCommandBase.java A backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotSingleDiskLiveCommand.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/validator/VmValidator.java M backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/RemoveSnapshotCommandTest.java M backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/VdcActionType.java M backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VM.java M backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VMStatus.java M backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllErrors.java M backend/manager/modules/dal/src/main/resources/bundles/VdsmErrors.properties 11 files changed, 303 insertions(+), 91 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/09/26909/1 diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotCommand.java index da927b9..0d00468 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotCommand.java @@ -29,7 +29,6 @@ import org.ovirt.engine.core.common.businessentities.Snapshot.SnapshotStatus; import org.ovirt.engine.core.common.businessentities.StorageDomain; import org.ovirt.engine.core.common.businessentities.VM; -import org.ovirt.engine.core.common.businessentities.VMStatus; import org.ovirt.engine.core.common.errors.VdcBLLException; import org.ovirt.engine.core.common.errors.VdcBllErrors; import org.ovirt.engine.core.common.errors.VdcBllMessages; @@ -41,11 +40,13 @@ import org.ovirt.engine.core.utils.transaction.TransactionMethod; import org.ovirt.engine.core.utils.transaction.TransactionSupport; +/** + * Merges snapshots either live or non-live based on VM status + */ @DisableInPrepareMode @LockIdNameAttribute public class RemoveSnapshotCommand<T extends RemoveSnapshotParameters> extends VmCommand<T> implements QuotaStorageDependent { - private List<DiskImage> _sourceImages = null; public RemoveSnapshotCommand(T parameters) { @@ -85,9 +86,9 @@ @Override protected void executeCommand() { - if (getVm().getStatus() != VMStatus.Down) { - log.error("Cannot remove VM snapshot. Vm is not Down"); - throw new VdcBLLException(VdcBllErrors.IRS_IMAGE_STATUS_ILLEGAL); + if (!getVm().isQualifiedForSnapshotMerge()) { + log.error("Cannot remove VM snapshot. Vm is not Down, Up or Paused"); + throw new VdcBLLException(VdcBllErrors.VM_NOT_QUALIFIED_FOR_SNAPSHOT_MERGE); } final Snapshot snapshot = getSnapshotDao().get(getParameters().getSnapshotId()); @@ -143,7 +144,7 @@ DiskImage dest = getDiskImageDao().getAllSnapshotsForParent(source.getImageId()).get(0); VdcReturnValueBase vdcReturnValue = getBackend().runInternalAction( - VdcActionType.RemoveSnapshotSingleDisk, + getSnapshotActionType(), buildRemoveSnapshotSingleDiskParameters(source, dest), ExecutionHandler.createDefaultContexForTasks(getExecutionContext())); @@ -180,6 +181,8 @@ parameters.setEntityInfo(getParameters().getEntityInfo()); parameters.setParentParameters(getParameters()); parameters.setParentCommand(getActionType()); + parameters.setCommandType(getSnapshotActionType()); + parameters.setVdsId(getVm().getRunOnVds()); return parameters; } @@ -221,7 +224,7 @@ !validateVmNotDuringSnapshot() || !validateVmNotInPreview() || !validateSnapshotExists() || - !validate(vmValidator.vmDown()) || + !validate(vmValidator.vmQualifiedForSnapshotMerge()) || !validate(vmValidator.vmNotHavingDeviceSnapshotsAttachedToOtherVms(false))) { return false; } @@ -338,10 +341,10 @@ protected SnapshotsValidator createSnapshotValidator() { return new SnapshotsValidator(); } + protected VmValidator createVmValidator(VM vm) { return new VmValidator(vm); } - @Override public AuditLogType getAuditLogTypeValue() { @@ -360,7 +363,12 @@ @Override protected VdcActionType getChildActionType() { - return VdcActionType.RemoveSnapshotSingleDisk; + // TODO GP verify this isn't called, then remove it + return VdcActionType.Unknown; + } + + private VdcActionType getSnapshotActionType() { + return getVm().isDown() ? VdcActionType.RemoveSnapshotSingleDisk : VdcActionType.RemoveSnapshotSingleDiskLive; } @Override diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotSingleDiskCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotSingleDiskCommand.java index d9b3da7..aa0f214 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotSingleDiskCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotSingleDiskCommand.java @@ -1,118 +1,45 @@ package org.ovirt.engine.core.bll; -import java.util.Collections; -import java.util.Map; - import org.ovirt.engine.core.common.VdcObjectType; import org.ovirt.engine.core.common.action.ImagesContainterParametersBase; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.asynctasks.AsyncTaskType; -import org.ovirt.engine.core.common.businessentities.DiskImage; import org.ovirt.engine.core.common.job.StepEnum; -import org.ovirt.engine.core.common.vdscommands.GetImageInfoVDSCommandParameters; import org.ovirt.engine.core.common.vdscommands.MergeSnapshotsVDSCommandParameters; import org.ovirt.engine.core.common.vdscommands.VDSCommandType; import org.ovirt.engine.core.common.vdscommands.VDSReturnValue; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.job.ExecutionMessageDirector; -import org.springframework.util.CollectionUtils; @InternalCommandAttribute -public class RemoveSnapshotSingleDiskCommand<T extends ImagesContainterParametersBase> extends BaseImagesCommand<T> { +public class RemoveSnapshotSingleDiskCommand<T extends ImagesContainterParametersBase> extends RemoveSnapshotSingleDiskCommandBase { public RemoveSnapshotSingleDiskCommand(T parameters) { super(parameters); } @Override - protected void executeCommand() { - Guid storagePoolId = (getDiskImage().getStoragePoolId() != null) ? - getDiskImage().getStoragePoolId() : Guid.Empty; - - Guid storageDomainId = !CollectionUtils.isEmpty(getDiskImage().getStorageIds()) ? - getDiskImage().getStorageIds().get(0) : Guid.Empty; - - Guid taskId = persistAsyncTaskPlaceHolder(VdcActionType.RemoveSnapshot); - VDSReturnValue vdsReturnValue = mergeSnapshots(storagePoolId, storageDomainId); - if (vdsReturnValue != null && vdsReturnValue.getCreationInfo() != null) { - getReturnValue().getInternalVdsmTaskIdList().add(createTask(taskId, vdsReturnValue, storageDomainId)); - setSucceeded(vdsReturnValue.getSucceeded()); - } else { - setSucceeded(false); - } + protected VdcActionType getParentActionType() { + return VdcActionType.RemoveSnapshot; } - private VDSReturnValue mergeSnapshots(Guid storagePoolId, Guid storageDomainId) { + @Override + protected VDSReturnValue mergeSnapshots(Guid storagePoolId, Guid storageDomainId) { MergeSnapshotsVDSCommandParameters params = new MergeSnapshotsVDSCommandParameters(storagePoolId, storageDomainId, getVmId(), getDiskImage().getId(), getDiskImage().getImageId(), getDestinationDiskImage().getImageId(), getDiskImage().isWipeAfterDelete()); - return runVdsCommand(VDSCommandType.MergeSnapshots, params); } - private Guid createTask(Guid taskId, VDSReturnValue vdsReturnValue, Guid storageDomainId) { + @Override + protected Guid createTask(Guid taskId, VDSReturnValue vdsReturnValue, Guid storageDomainId) { String message = ExecutionMessageDirector.resolveStepMessage(StepEnum.MERGE_SNAPSHOTS, getJobMessageProperties()); - return super.createTask(taskId, vdsReturnValue.getCreationInfo(), VdcActionType.RemoveSnapshot, message, VdcObjectType.Storage, storageDomainId); } @Override - public Map<String, String> getJobMessageProperties() { - return Collections.singletonMap(VdcObjectType.Disk.name().toLowerCase(), getDiskImage().getDiskAlias()); - } - - @Override protected AsyncTaskType getTaskType() { return AsyncTaskType.mergeSnapshots; - } - - @Override - protected void endSuccessfully() { - // NOTE: The removal of the images from DB is done here - // assuming that there might be situation (related to - // tasks failures) in which we will want to preserve the - // original state (before the merge-attempt). - if (getDestinationDiskImage() != null) { - DiskImage curr = getDestinationDiskImage(); - while (!curr.getParentId().equals(getDiskImage().getParentId())) { - curr = getDiskImageDao().getSnapshotById(curr.getParentId()); - getImageDao().remove(curr.getImageId()); - } - getDestinationDiskImage().setvolumeFormat(curr.getVolumeFormat()); - getDestinationDiskImage().setVolumeType(curr.getVolumeType()); - getDestinationDiskImage().setParentId(getDiskImage().getParentId()); - getBaseDiskDao().update(curr); - getImageDao().update(getDestinationDiskImage().getImage()); - updateDiskImageDynamic(); - } - - setSucceeded(true); - } - - private void updateDiskImageDynamic() { - VDSReturnValue ret = runVdsCommand( - VDSCommandType.GetImageInfo, - new GetImageInfoVDSCommandParameters(getDestinationDiskImage().getStoragePoolId(), - getDestinationDiskImage().getStorageIds().get(0), - getDestinationDiskImage().getId(), - getDestinationDiskImage().getImageId())); - - // Update image's actual size in DB - DiskImage imageFromIRS = (DiskImage) ret.getReturnValue(); - if (imageFromIRS != null) { - completeImageData(imageFromIRS); - } else { - log.warnFormat("Could not update DiskImage's size with ID {0}", - getDestinationDiskImage().getImageId()); - } - } - - @Override - protected void endWithFailure() { - // TODO: FILL! We should determine what to do in case of - // failure (is everything rolled-backed? rolled-forward? - // some and some?). - setSucceeded(true); } } diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotSingleDiskCommandBase.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotSingleDiskCommandBase.java new file mode 100644 index 0000000..213a505 --- /dev/null +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotSingleDiskCommandBase.java @@ -0,0 +1,99 @@ +package org.ovirt.engine.core.bll; + +import java.util.Collections; +import java.util.Map; + +import org.ovirt.engine.core.common.VdcObjectType; +import org.ovirt.engine.core.common.action.ImagesContainterParametersBase; +import org.ovirt.engine.core.common.action.VdcActionType; +import org.ovirt.engine.core.common.businessentities.DiskImage; +import org.ovirt.engine.core.common.vdscommands.GetImageInfoVDSCommandParameters; +import org.ovirt.engine.core.common.vdscommands.VDSCommandType; +import org.ovirt.engine.core.common.vdscommands.VDSReturnValue; +import org.ovirt.engine.core.compat.Guid; +import org.springframework.util.CollectionUtils; + +public abstract class RemoveSnapshotSingleDiskCommandBase<T extends ImagesContainterParametersBase> extends BaseImagesCommand<T> { + public RemoveSnapshotSingleDiskCommandBase(T parameters) { + super(parameters); + } + + @Override + protected void executeCommand() { + Guid storagePoolId = (getDiskImage().getStoragePoolId() != null) ? + getDiskImage().getStoragePoolId() : Guid.Empty; + + Guid storageDomainId = !CollectionUtils.isEmpty(getDiskImage().getStorageIds()) ? + getDiskImage().getStorageIds().get(0) : Guid.Empty; + + Guid taskId = persistAsyncTaskPlaceHolder(getParentActionType()); + VDSReturnValue vdsReturnValue = mergeSnapshots(storagePoolId, storageDomainId); + if (vdsReturnValue != null && vdsReturnValue.getCreationInfo() != null) { + getReturnValue().getInternalVdsmTaskIdList().add(createTask(taskId, vdsReturnValue, storageDomainId)); + setSucceeded(vdsReturnValue.getSucceeded()); + } else { + setSucceeded(false); + } + } + + protected abstract VdcActionType getParentActionType(); + + protected abstract VDSReturnValue mergeSnapshots(Guid storagePoolId, Guid storageDomainId); + + protected abstract Guid createTask(Guid taskId, VDSReturnValue vdsReturnValue, Guid storageDomainId); + + @Override + public Map<String, String> getJobMessageProperties() { + return Collections.singletonMap(VdcObjectType.Disk.name().toLowerCase(), getDiskImage().getDiskAlias()); + } + + @Override + protected void endSuccessfully() { + // NOTE: The removal of the images from DB is done here + // assuming that there might be situation (related to + // tasks failures) in which we will want to preserve the + // original state (before the merge-attempt). + if (getDestinationDiskImage() != null) { + DiskImage curr = getDestinationDiskImage(); + while (!curr.getParentId().equals(getDiskImage().getParentId())) { + curr = getDiskImageDao().getSnapshotById(curr.getParentId()); + getImageDao().remove(curr.getImageId()); + } + getDestinationDiskImage().setvolumeFormat(curr.getVolumeFormat()); + getDestinationDiskImage().setVolumeType(curr.getVolumeType()); + getDestinationDiskImage().setParentId(getDiskImage().getParentId()); + getBaseDiskDao().update(curr); + getImageDao().update(getDestinationDiskImage().getImage()); + updateDiskImageDynamic(); + } + + setSucceeded(true); + } + + private void updateDiskImageDynamic() { + VDSReturnValue ret = runVdsCommand( + VDSCommandType.GetImageInfo, + new GetImageInfoVDSCommandParameters(getDestinationDiskImage().getStoragePoolId(), + getDestinationDiskImage().getStorageIds().get(0), + getDestinationDiskImage().getId(), + getDestinationDiskImage().getImageId())); + + // Update image's actual size in DB + DiskImage imageFromIRS = (DiskImage) ret.getReturnValue(); + if (imageFromIRS != null) { + completeImageData(imageFromIRS); + } else { + log.warnFormat("Could not update DiskImage's size with ID {0}", + getDestinationDiskImage().getImageId()); + } + } + + @Override + protected void endWithFailure() { + // TODO: FILL! We should determine what to do in case of + // failure (is everything rolled-backed? rolled-forward? + // some and some?). + // TODO GP need to unlock image? + setSucceeded(true); + } +} diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotSingleDiskLiveCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotSingleDiskLiveCommand.java new file mode 100644 index 0000000..7627fc4 --- /dev/null +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotSingleDiskLiveCommand.java @@ -0,0 +1,135 @@ +package org.ovirt.engine.core.bll; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.ovirt.engine.core.common.VdcObjectType; +import org.ovirt.engine.core.common.action.ImagesContainterParametersBase; +import org.ovirt.engine.core.common.action.VdcActionType; +import org.ovirt.engine.core.common.asynctasks.AsyncTaskType; +import org.ovirt.engine.core.common.businessentities.AsyncTaskResultEnum; +import org.ovirt.engine.core.common.businessentities.DiskImage; +import org.ovirt.engine.core.common.businessentities.Snapshot; +import org.ovirt.engine.core.common.businessentities.VmJob; +import org.ovirt.engine.core.common.job.StepEnum; +import org.ovirt.engine.core.common.vdscommands.GetVolumeChainVDSCommandParameters; +import org.ovirt.engine.core.common.vdscommands.MergeVDSCommandParameters; +import org.ovirt.engine.core.common.vdscommands.VDSCommandType; +import org.ovirt.engine.core.common.vdscommands.VDSReturnValue; +import org.ovirt.engine.core.compat.Guid; +import org.ovirt.engine.core.dal.dbbroker.DbFacade; +import org.ovirt.engine.core.dal.job.ExecutionMessageDirector; + +@InternalCommandAttribute +public class RemoveSnapshotSingleDiskLiveCommand<T extends ImagesContainterParametersBase> + extends RemoveSnapshotSingleDiskCommandBase + implements CommandCallback { + + public RemoveSnapshotSingleDiskLiveCommand(T parameters) { + super(parameters); + } + + @Override + protected VdcActionType getParentActionType() { + return VdcActionType.RemoveSnapshot; + } + + @Override + protected VDSReturnValue mergeSnapshots(Guid storagePoolId, Guid storageDomainId) { + Guid snapshotId = getSnapshotDao().getId(getVmId(), Snapshot.SnapshotType.ACTIVE); + DiskImage activeImage = getDiskImageDao().getDiskSnapshotForVmSnapshot(getDiskImage().getId(), snapshotId); + + MergeVDSCommandParameters params = new MergeVDSCommandParameters(getVdsId(), getVmId(), + storagePoolId, + storageDomainId, + activeImage.getImageId(), + getDestinationDiskImage().getImageId(), + getDiskImage().getImageId(), + getDestinationDiskImage().getImageId(), + 0); + return runVdsCommand(VDSCommandType.Merge, params); + } + + @Override + protected Guid createTask(Guid taskId, VDSReturnValue vdsReturnValue, Guid storageDomainId) { + String message = ExecutionMessageDirector.resolveStepMessage(StepEnum.MERGE_SNAPSHOTS, + getJobMessageProperties()); + + return super.createTask(taskId, vdsReturnValue.getCreationInfo(), VdcActionType.RemoveSnapshot, + message, VdcObjectType.Storage, storageDomainId); + } + + @Override + protected AsyncTaskType getTaskType() { + return AsyncTaskType.liveMerge; + } + + @Override + public boolean isActive(Guid taskId) { + // TODO GP check generation id, assume true if stats not yet collected + List<VmJob> vmJobs = DbFacade.getInstance().getVmJobDao().getAllForVmDisk(getVmId(), getImageGroupId()); + for (VmJob vmJob : vmJobs) { + if (vmJob.getId().equals(taskId)) { + return true; + } + } + return false; + } + + @Override + public AsyncTaskResultEnum getFinalStatus(Guid taskId) { + VDSReturnValue vdsReturnValue = runVdsCommand(VDSCommandType.GetVolumeChain, + new GetVolumeChainVDSCommandParameters(getVdsId(), getVmId(), + getDiskImage().getStoragePoolId(), + getDiskImage().getStorageIds().get(0), + getDiskImage().getId(), + getDiskImage().getImageId())); + // TODO GP which image do we look for? If active layer was merged, we need the full + // TODO GP chain based on the base image id, else we have to assume failure to retrieve + // TODO GP the chain is success, which isn't safe. + + if (vdsReturnValue == null) { + return AsyncTaskResultEnum.failure; + } + + Set<Guid> images = new HashSet<>((Set<Guid>) vdsReturnValue.getReturnValue()); + images.retainAll(getImagesToRemove()); + if (!images.isEmpty()) { + // TODO GP test msg, or try: Arrays.toString(images.toArray()) + log.errorFormat("Failed to live merge, snapshots still in volume chain: {0}", images.toString()); + return AsyncTaskResultEnum.failure; + } else { + return AsyncTaskResultEnum.success; + } + } + + private Set<Guid> getImagesToRemove() { + Set<Guid> removedImages = new HashSet<>(); + DiskImage curr = getDestinationDiskImage(); + removedImages.add(curr.getImageId()); + while (!curr.getParentId().equals(getDiskImage().getParentId())) { + curr = getDiskImageDao().getSnapshotById(curr.getParentId()); + removedImages.add(curr.getImageId()); + } + return removedImages; + } + + @Override + public void stopTask(Guid taskId) { + // TODO GP constant + throw new UnsupportedOperationException("Can't stop live merge"); //$NON-NLS-1$ + } + + @Override + protected void endSuccessfully() { + // TODO GP finish: delete the now-unused volume, sync the volume chain, unlock image (done in VmCommand?) + super.endSuccessfully(); + } + + @Override + protected void endWithFailure() { + // TODO GP finish: unlock image (done in VmCommand?) + super.endWithFailure(); + } +} diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/validator/VmValidator.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/validator/VmValidator.java index 52e51ec..1c3ef6f 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/validator/VmValidator.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/validator/VmValidator.java @@ -50,6 +50,17 @@ return ValidationResult.VALID; } + /** @return Validation result that indicates if the VM is qualified to have its snapshots merged. */ + public ValidationResult vmQualifiedForSnapshotMerge() { + for (VM vm : vms) { + if (!vm.isQualifiedForSnapshotMerge()) { + return new ValidationResult(VdcBllMessages.ACTION_TYPE_FAILED_VM_IS_NOT_DOWN_OR_UP); + } + } + + return ValidationResult.VALID; + } + public ValidationResult vmNotLocked() { for (VM vm : vms) { if (vm.getStatus() == VMStatus.ImageLocked) { diff --git a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/RemoveSnapshotCommandTest.java b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/RemoveSnapshotCommandTest.java index 9ba25ff..3140f08 100644 --- a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/RemoveSnapshotCommandTest.java +++ b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/RemoveSnapshotCommandTest.java @@ -233,10 +233,24 @@ public void testCanDoActionVmUp() { prepareForVmValidatorTests(); cmd.getVm().setStatus(VMStatus.Up); - CanDoActionTestUtils.runAndAssertCanDoActionFailure(cmd, VdcBllMessages.ACTION_TYPE_FAILED_VM_IS_NOT_DOWN); + CanDoActionTestUtils.runAndAssertCanDoActionSuccess(cmd); } @Test + public void testCanDoActionVmDown() { + prepareForVmValidatorTests(); + cmd.getVm().setStatus(VMStatus.Down); + CanDoActionTestUtils.runAndAssertCanDoActionSuccess(cmd); + } + + @Test + public void testCanDoActionVmMigrating() { + prepareForVmValidatorTests(); + cmd.getVm().setStatus(VMStatus.MigratingTo); + CanDoActionTestUtils.runAndAssertCanDoActionFailure(cmd, + VdcBllMessages.ACTION_TYPE_FAILED_VM_IS_NOT_DOWN_OR_UP); + } + @Test public void vmHasPluggedDdeviceSnapshotsAttachedToOtherVms() { prepareForVmValidatorTests(); doReturn(new ValidationResult(VdcBllMessages.ACTION_TYPE_FAILED_VM_DISK_SNAPSHOT_IS_ATTACHED_TO_ANOTHER_VM)).when(vmValidator) diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/VdcActionType.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/VdcActionType.java index 872b6c5..8d94bea 100644 --- a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/VdcActionType.java +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/VdcActionType.java @@ -139,6 +139,7 @@ GetDiskAlignment(232, QuotaDependency.NONE), RemoveVmHibernationVolumes(233, QuotaDependency.NONE), RemoveMemoryVolumes(234, QuotaDependency.NONE), + RemoveSnapshotSingleDiskLive(235, QuotaDependency.STORAGE), // VmPoolCommands AddVmPool(301, QuotaDependency.NONE), AddVmPoolWithVms(304, ActionGroup.CREATE_VM_POOL, QuotaDependency.BOTH), diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VM.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VM.java index 8f529ac..06ed95b 100644 --- a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VM.java +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VM.java @@ -1595,6 +1595,10 @@ return getStatus().isQualifyToMigrate(); } + public boolean isQualifiedForSnapshotMerge() { + return getStatus().isQualifiedForSnapshotMerge(); + } + public boolean isRunningAndQualifyForDisksMigration() { return getStatus().isUpOrPaused() && getRunOnVds() != null && !getRunOnVds().equals(Guid.Empty); } diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VMStatus.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VMStatus.java index c608f84..dd19052 100644 --- a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VMStatus.java +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VMStatus.java @@ -66,6 +66,17 @@ } /** + * This method reflects whether the VM is qualified to have its snapshots merged. For + * this to be true, the VM must up with qemu in a non-transient state, or down. + * + * @return true if this status indicates that the VM status indicates that snapshot merge + * may be possible, otherwise false + */ + public boolean isQualifiedForSnapshotMerge() { + return this == Up || this == PoweringUp || this == Paused || this == RebootInProgress || this == Down; + } + + /** * This method reflects whether the VM is surely running or paused in this status * * @see #isRunning() diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllErrors.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllErrors.java index c64ab25..bd5cd51 100644 --- a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllErrors.java +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllErrors.java @@ -428,6 +428,7 @@ PROVIDER_FAILURE(5050), PROVIDER_IMPORT_CERTIFICATE_CHAIN_ERROR(5051), PROVIDER_SSL_FAILURE(5052), + VM_NOT_QUALIFIED_FOR_SNAPSHOT_MERGE(5053), // Network Labels LABELED_NETWORK_INTERFACE_NOT_FOUND(5200), diff --git a/backend/manager/modules/dal/src/main/resources/bundles/VdsmErrors.properties b/backend/manager/modules/dal/src/main/resources/bundles/VdsmErrors.properties index eb15c33..68024bc 100644 --- a/backend/manager/modules/dal/src/main/resources/bundles/VdsmErrors.properties +++ b/backend/manager/modules/dal/src/main/resources/bundles/VdsmErrors.properties @@ -385,6 +385,7 @@ PROVIDER_FAILURE=Failed to communicate with the external provider. PROVIDER_IMPORT_CERTIFICATE_CHAIN_ERROR=Failed to import provider certificate chain. PROVIDER_SSL_FAILURE=SSL problem while trying to connect to the external provider. +VM_NOT_QUALIFIED_FOR_SNAPSHOT_MERGE=To merge snapshots, a VM must be Down, Up or Paused. MIGRATION_DEST_INVALID_HOSTNAME=Migration destination has an invalid hostname MIGRATION_CANCEL_ERROR=Migration not in progress MIGRATION_CANCEL_ERROR_NO_VM=Cancel migration has failed. Please try again in a few moments and track the VM's event log for details. @@ -406,4 +407,4 @@ VolumeResizeValueError=Incorrect size value for volume resize ResizeErr=Wrong resize disk parameter UpdateDevice=Failed to update device -SETUP_NETWORKS_ROLLBACK=Reverting back to last known saved configuration. \ No newline at end of file +SETUP_NETWORKS_ROLLBACK=Reverting back to last known saved configuration. -- To view, visit http://gerrit.ovirt.org/26909 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ic47eb91a0ea1fe150e3b2152e2c9d5f1f2eb3678 Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Greg Padgett <gpadg...@redhat.com> _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches