Arik Hadas has uploaded a new change for review. Change subject: core: handle 'image does not exists' error on remove hibernation vols ......................................................................
core: handle 'image does not exists' error on remove hibernation vols Introducing HibernationVolumesRemover class which is responsible for removing hibernation volumes, with proper handling of 'image does not exists' error which is not really an error, because the result is that the images don't exists, as we wanted. HibernationVolumesRemover is now being used by the stop VM commands (stop and shutdown) and by run VM, fixing the race described in bz 952603. Change-Id: Ief52a20315b29660c7038eab1cc8dbbb4c4ded3e Bug-Url: https://bugzilla.redhat.com/952603 Signed-off-by: Arik Hadas <aha...@redhat.com> --- M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RunVmCommandBase.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/StopVmCommandBase.java A backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/HibernationVolumesRemover.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/MemoryImageRemover.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/MemoryImageRemoverFromExportDomain.java 5 files changed, 215 insertions(+), 10 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/74/17474/1 diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RunVmCommandBase.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RunVmCommandBase.java index 45fcb80..024532d 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RunVmCommandBase.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RunVmCommandBase.java @@ -15,10 +15,16 @@ import org.ovirt.engine.core.bll.job.ExecutionContext.ExecutionMethod; import org.ovirt.engine.core.bll.job.ExecutionHandler; import org.ovirt.engine.core.bll.job.JobRepositoryFactory; +import org.ovirt.engine.core.bll.memory.HibernationVolumesRemover; import org.ovirt.engine.core.bll.scheduling.RunVmDelayer; import org.ovirt.engine.core.bll.snapshots.SnapshotsValidator; import org.ovirt.engine.core.bll.storage.StorageHelperDirector; +import org.ovirt.engine.core.bll.tasks.TaskHandlerCommand; +import org.ovirt.engine.core.common.VdcObjectType; +import org.ovirt.engine.core.common.action.VdcActionType; +import org.ovirt.engine.core.common.action.VdcReturnValueBase; import org.ovirt.engine.core.common.action.VmOperationParameterBase; +import org.ovirt.engine.core.common.asynctasks.AsyncTaskCreationInfo; import org.ovirt.engine.core.common.businessentities.IVdsAsyncCommand; import org.ovirt.engine.core.common.businessentities.LUNs; import org.ovirt.engine.core.common.businessentities.LunDisk; @@ -36,6 +42,7 @@ import org.ovirt.engine.core.common.vdscommands.UpdateVmDynamicDataVDSCommandParameters; import org.ovirt.engine.core.common.vdscommands.VDSCommandType; import org.ovirt.engine.core.compat.Guid; +import org.ovirt.engine.core.compat.NotImplementedException; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.utils.log.Log; import org.ovirt.engine.core.utils.log.LogFactory; @@ -47,7 +54,7 @@ * Base class for asynchronous running process handling */ public abstract class RunVmCommandBase<T extends VmOperationParameterBase> extends VmCommand<T> implements - IVdsAsyncCommand, RunVmDelayer { + IVdsAsyncCommand, RunVmDelayer, TaskHandlerCommand<T> { private static Log log = LogFactory.getLog(RunVmCommandBase.class); protected static final HashMap<Guid, Integer> _vds_pending_vm_count = new HashMap<Guid, Integer>(); @@ -162,7 +169,9 @@ getVm().setLastVdsRunOn(getCurrentVdsId()); } if (StringUtils.isNotEmpty(getVm().getHibernationVolHandle())) { - removeMemoryVolumes(getVm().getHibernationVolHandle(), getActionType(), true); + new HibernationVolumesRemover(getVm().getHibernationVolHandle(), + getVmId(), this, true).remove(); + // In order to prevent a race where VdsUpdateRuntimeInfo saves the Vm Dynamic as UP prior to execution of // this method (which is a part of the cached VM command, // so the state this method is aware to is RESTORING, in case of RunVmCommand after the VM got suspended. @@ -318,4 +327,59 @@ return Collections.singletonMap(getVmId().toString(), LockMessagesMatchUtil.makeLockingPair(LockingGroup.VM, VdcBllMessages.ACTION_TYPE_FAILED_OBJECT_LOCKED)); } + + /////////////////////////////////////// + // TaskHandlerCommand Implementation // + /////////////////////////////////////// + + public T getParameters() { + return super.getParameters(); + } + + public VdcActionType getActionType() { + return super.getActionType(); + } + + public VdcReturnValueBase getReturnValue() { + return super.getReturnValue(); + } + + public ExecutionContext getExecutionContext() { + return super.getExecutionContext(); + } + + public void setExecutionContext(ExecutionContext executionContext) { + super.setExecutionContext(executionContext); + } + + public Guid createTask(Guid taskId, + AsyncTaskCreationInfo asyncTaskCreationInfo, + VdcActionType parentCommand, + VdcObjectType entityType, + Guid... entityIds) { + return super.createTaskInCurrentTransaction(taskId, asyncTaskCreationInfo, parentCommand, entityType, entityIds); + } + + public Guid createTask(Guid taskId, + AsyncTaskCreationInfo asyncTaskCreationInfo, + VdcActionType parentCommand) { + return super.createTask(taskId, asyncTaskCreationInfo, parentCommand); + } + + public ArrayList<Guid> getTaskIdList() { + return super.getTaskIdList(); + } + + public void preventRollback() { + throw new NotImplementedException(); + } + + public Guid persistAsyncTaskPlaceHolder() { + return super.persistAsyncTaskPlaceHolder(getActionType()); + } + + public Guid persistAsyncTaskPlaceHolder(String taskKey) { + return super.persistAsyncTaskPlaceHolder(getActionType(), taskKey); + } + } diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/StopVmCommandBase.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/StopVmCommandBase.java index 235bb5a..c2a364e 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/StopVmCommandBase.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/StopVmCommandBase.java @@ -4,14 +4,20 @@ import java.util.List; import org.apache.commons.lang.StringUtils; +import org.ovirt.engine.core.bll.job.ExecutionContext; +import org.ovirt.engine.core.bll.memory.HibernationVolumesRemover; import org.ovirt.engine.core.bll.quota.QuotaConsumptionParameter; import org.ovirt.engine.core.bll.quota.QuotaStorageConsumptionParameter; import org.ovirt.engine.core.bll.quota.QuotaStorageDependent; import org.ovirt.engine.core.bll.quota.QuotaVdsDependent; import org.ovirt.engine.core.bll.quota.QuotaVdsGroupConsumptionParameter; +import org.ovirt.engine.core.bll.tasks.TaskHandlerCommand; import org.ovirt.engine.core.bll.utils.PermissionSubject; import org.ovirt.engine.core.common.VdcObjectType; +import org.ovirt.engine.core.common.action.VdcActionType; +import org.ovirt.engine.core.common.action.VdcReturnValueBase; import org.ovirt.engine.core.common.action.VmOperationParameterBase; +import org.ovirt.engine.core.common.asynctasks.AsyncTaskCreationInfo; import org.ovirt.engine.core.common.asynctasks.EntityInfo; import org.ovirt.engine.core.common.businessentities.DiskImage; import org.ovirt.engine.core.common.businessentities.VMStatus; @@ -21,13 +27,14 @@ import org.ovirt.engine.core.common.vdscommands.UpdateVmDynamicDataVDSCommandParameters; import org.ovirt.engine.core.common.vdscommands.VDSCommandType; import org.ovirt.engine.core.compat.Guid; +import org.ovirt.engine.core.compat.NotImplementedException; import org.ovirt.engine.core.utils.log.Log; import org.ovirt.engine.core.utils.log.LogFactory; import org.ovirt.engine.core.utils.transaction.TransactionMethod; import org.ovirt.engine.core.utils.transaction.TransactionSupport; public abstract class StopVmCommandBase<T extends VmOperationParameterBase> extends VmOperationCommandBase<T> - implements QuotaVdsDependent, QuotaStorageDependent { + implements QuotaVdsDependent, QuotaStorageDependent, TaskHandlerCommand<T> { private boolean suspendedVm; protected StopVmCommandBase(Guid guid) { @@ -83,11 +90,25 @@ boolean removedHibernationVolumes = false; if (StringUtils.isNotEmpty(getVm().getHibernationVolHandle())) { removedHibernationVolumes = removeHibernationVolumes(); + + if (!removedHibernationVolumes) { + log.errorFormat("Could not remove hibernation volumes {0}, when stoping VM {1} ({2})", + getVm().getHibernationVolHandle(), + getVm().getName(), + getVm().getId()); + } } if (getVm().getStatus() == VMStatus.Suspended) { suspendedVm = true; + setSucceeded(removedHibernationVolumes); + + // it is possible that no task was created and the hibernation volumes removal + // was succeeded, in case the hibernation images don't exist + if (getSucceeded() && getTaskIdList().isEmpty()) { + endVmCommand(); + } } else { super.executeVmCommand(); @@ -114,9 +135,15 @@ // Set the VM to image locked to decrease race condition. updateVmStatus(VMStatus.ImageLocked); - // We call removeMemoryVolumes with startPollingTasks = false because this call - // is part of the exeuction stage so the task polling will be made anyway.. - if (!removeMemoryVolumes(getVm().getHibernationVolHandle(), getActionType(), false)) { + // We don't need the remover to poll the tasks because we are in the execution + // method so the task polling will be made later anyway.. + HibernationVolumesRemover hibernationVolumesRemover = + new HibernationVolumesRemover( + getVm().getHibernationVolHandle(), + getVmId(), + this); + + if (!hibernationVolumesRemover.remove()) { updateVmStatus(vmStatus); return false; } @@ -210,4 +237,58 @@ public void addQuotaPermissionSubject(List<PermissionSubject> quotaPermissionList) { // } + + /////////////////////////////////////// + // TaskHandlerCommand Implementation // + /////////////////////////////////////// + + public T getParameters() { + return super.getParameters(); + } + + public VdcActionType getActionType() { + return super.getActionType(); + } + + public VdcReturnValueBase getReturnValue() { + return super.getReturnValue(); + } + + public ExecutionContext getExecutionContext() { + return super.getExecutionContext(); + } + + public void setExecutionContext(ExecutionContext executionContext) { + super.setExecutionContext(executionContext); + } + + public Guid createTask(Guid taskId, + AsyncTaskCreationInfo asyncTaskCreationInfo, + VdcActionType parentCommand, + VdcObjectType entityType, + Guid... entityIds) { + return super.createTaskInCurrentTransaction(taskId, asyncTaskCreationInfo, parentCommand, entityType, entityIds); + } + + public Guid createTask(Guid taskId, + AsyncTaskCreationInfo asyncTaskCreationInfo, + VdcActionType parentCommand) { + return super.createTask(taskId, asyncTaskCreationInfo, parentCommand); + } + + public ArrayList<Guid> getTaskIdList() { + return super.getTaskIdList(); + } + + public void preventRollback() { + throw new NotImplementedException(); + } + + public Guid persistAsyncTaskPlaceHolder() { + return super.persistAsyncTaskPlaceHolder(getActionType()); + } + + public Guid persistAsyncTaskPlaceHolder(String taskKey) { + return super.persistAsyncTaskPlaceHolder(getActionType(), taskKey); + } } diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/HibernationVolumesRemover.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/HibernationVolumesRemover.java new file mode 100644 index 0000000..206d4dc --- /dev/null +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/HibernationVolumesRemover.java @@ -0,0 +1,59 @@ +package org.ovirt.engine.core.bll.memory; + +import java.util.List; + +import org.ovirt.engine.core.bll.tasks.TaskHandlerCommand; +import org.ovirt.engine.core.common.businessentities.Disk; +import org.ovirt.engine.core.common.vdscommands.DeleteImageGroupVDSCommandParameters; +import org.ovirt.engine.core.compat.Guid; +import org.ovirt.engine.core.dal.dbbroker.DbFacade; + +public class HibernationVolumesRemover extends MemoryImageRemover { + + private Boolean cachedPostZero; + private Guid vmId; + private String memoryState; + + public HibernationVolumesRemover(String memoryState, Guid vmId, + TaskHandlerCommand<?> enclosingCommand) { + this(memoryState, vmId, enclosingCommand, false); + } + + public HibernationVolumesRemover(String memoryState, Guid vmId, + TaskHandlerCommand<?> enclosingCommand, boolean startPollingTasks) { + super(enclosingCommand, startPollingTasks); + this.memoryState = memoryState; + this.vmId = vmId; + } + + public boolean remove() { + return removeMemoryVolume(memoryState); + } + + @Override + protected DeleteImageGroupVDSCommandParameters buildDeleteMemoryImageParams(List<Guid> guids) { + return new DeleteImageGroupVDSCommandParameters( + guids.get(1), guids.get(0), guids.get(2), isPostZero(), false); + } + + @Override + protected DeleteImageGroupVDSCommandParameters buildDeleteMemoryConfParams(List<Guid> guids) { + return new DeleteImageGroupVDSCommandParameters( + guids.get(1), guids.get(0), guids.get(4), isPostZero(), false); + } + + protected boolean isPostZero() { + if (cachedPostZero == null) { + // check if one of the disks is marked with wipe_after_delete + cachedPostZero = + DbFacade.getInstance().getDiskDao().getAllForVm(vmId).contains( + new Object() { + @Override + public boolean equals(Object obj) { + return ((Disk) obj).isWipeAfterDelete(); + } + }); + } + return cachedPostZero; + } +} diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/MemoryImageRemover.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/MemoryImageRemover.java index b203311..50080fa 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/MemoryImageRemover.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/MemoryImageRemover.java @@ -45,10 +45,11 @@ return !memoryVolume.isEmpty(); } - protected void removeMemoryVolume(String memoryVolumes) { + protected boolean removeMemoryVolume(String memoryVolumes) { if (isMemoryStateRemovable(memoryVolumes)) { - removeMemoryVolumes(memoryVolumes); + return removeMemoryVolumes(memoryVolumes); } + return true; } protected void removeMemoryVolumes(Set<String> memoryVolumes) { diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/MemoryImageRemoverFromExportDomain.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/MemoryImageRemoverFromExportDomain.java index 32b5145..57195a7 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/MemoryImageRemoverFromExportDomain.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/MemoryImageRemoverFromExportDomain.java @@ -28,8 +28,8 @@ } @Override - protected void removeMemoryVolume(String memoryVolumes) { - super.removeMemoryVolume( + protected boolean removeMemoryVolume(String memoryVolumes) { + return super.removeMemoryVolume( MemoryUtils.changeStorageDomainAndPoolInMemoryState( memoryVolumes, storageDomainId, storagePoolId)); } -- To view, visit http://gerrit.ovirt.org/17474 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ief52a20315b29660c7038eab1cc8dbbb4c4ded3e Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Arik Hadas <aha...@redhat.com> _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches