Arik Hadas has uploaded a new change for review. Change subject: core: save memory state on live snapshot with memory ......................................................................
core: save memory state on live snapshot with memory On creation of live snapshot with memory, we create two volumes, one for the memory dump and one for the vm configuration at the moment of the snapshot creation (that vdsm saves). Those volumes are stored on the snapshot entity in a similar way to how the hibernation volumes which are created on suspend VM command are stored, and they are passed to the live snapshot verb in vdsm. Change-Id: Ic7ceb07bf73e722bf4566989446e7dbba78a2ccb Bug-Url: https://bugzilla.redhat.com/960931 Signed-off-by: Arik Hadas <[email protected]> --- M backend/manager/dbscripts/snapshots_sp.sql M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/CreateAllSnapshotsFromVmCommand.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/HibernateVmCommand.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/lsm/LiveMigrateDiskCommand.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/lsm/LiveMigrateVmDisksCommand.java A backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/DefaultMemoryImageBuilder.java A backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/MemoryImageBuilder.java A backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/NullableMemoryImageBuilder.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/snapshots/SnapshotsManager.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/tasks/TaskHandlerCommand.java M backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/CreateAllSnapshotsFromVmCommandTest.java M backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/CreateAllSnapshotsFromVmParameters.java M backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllMessages.java M backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDao.java M backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDaoDbFacadeImpl.java M backend/manager/modules/dal/src/main/resources/bundles/AppErrors.properties M backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/SnapshotDaoTest.java M frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java M frontend/webadmin/modules/userportal-gwtp/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties M frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties 20 files changed, 442 insertions(+), 61 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/08/15608/1 diff --git a/backend/manager/dbscripts/snapshots_sp.sql b/backend/manager/dbscripts/snapshots_sp.sql index 0392b17..6ea0304 100644 --- a/backend/manager/dbscripts/snapshots_sp.sql +++ b/backend/manager/dbscripts/snapshots_sp.sql @@ -154,6 +154,24 @@ LANGUAGE plpgsql; +Create or replace FUNCTION GetSnapshotByVmIdAndTypeAndStatus( + v_vm_id UUID, + v_snapshot_type VARCHAR(32), + v_status VARCHAR(32)) +RETURNS SETOF snapshots +AS $procedure$ +BEGIN + RETURN QUERY + SELECT * + FROM snapshots + WHERE vm_id = v_vm_id + AND snapshot_type = v_snapshot_type + AND status = v_status + ORDER BY creation_date ASC + LIMIT 1; +END; $procedure$ +LANGUAGE plpgsql; + diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/CreateAllSnapshotsFromVmCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/CreateAllSnapshotsFromVmCommand.java index fa24e0b..10f6832 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/CreateAllSnapshotsFromVmCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/CreateAllSnapshotsFromVmCommand.java @@ -7,17 +7,23 @@ import java.util.Map; import org.apache.commons.lang.exception.ExceptionUtils; +import org.ovirt.engine.core.bll.job.ExecutionContext; import org.ovirt.engine.core.bll.job.ExecutionHandler; +import org.ovirt.engine.core.bll.memory.DefaultMemoryImageBuilder; +import org.ovirt.engine.core.bll.memory.MemoryImageBuilder; +import org.ovirt.engine.core.bll.memory.NullableMemoryImageBuilder; 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.snapshots.SnapshotsManager; import org.ovirt.engine.core.bll.snapshots.SnapshotsValidator; import org.ovirt.engine.core.bll.storage.StoragePoolValidator; +import org.ovirt.engine.core.bll.tasks.TaskHandlerCommand; import org.ovirt.engine.core.bll.validator.DiskImagesValidator; import org.ovirt.engine.core.bll.validator.MultipleStorageDomainsValidator; import org.ovirt.engine.core.bll.validator.VmValidator; import org.ovirt.engine.core.common.AuditLogType; +import org.ovirt.engine.core.common.FeatureSupported; import org.ovirt.engine.core.common.VdcObjectType; import org.ovirt.engine.core.common.action.CreateAllSnapshotsFromVmParameters; import org.ovirt.engine.core.common.action.ImagesActionsParametersBase; @@ -25,24 +31,27 @@ import org.ovirt.engine.core.common.action.VdcActionParametersBase; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.action.VdcReturnValueBase; +import org.ovirt.engine.core.common.asynctasks.AsyncTaskCreationInfo; import org.ovirt.engine.core.common.businessentities.Disk; import org.ovirt.engine.core.common.businessentities.DiskImage; import org.ovirt.engine.core.common.businessentities.Snapshot; import org.ovirt.engine.core.common.businessentities.Snapshot.SnapshotStatus; import org.ovirt.engine.core.common.businessentities.Snapshot.SnapshotType; +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.businessentities.VmExitStatus; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.common.errors.VdcBLLException; -import org.ovirt.engine.core.common.locks.LockingGroup; import org.ovirt.engine.core.common.errors.VdcBllMessages; +import org.ovirt.engine.core.common.locks.LockingGroup; import org.ovirt.engine.core.common.utils.Pair; import org.ovirt.engine.core.common.validation.group.CreateEntity; import org.ovirt.engine.core.common.vdscommands.SnapshotVDSCommandParameters; 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.compat.TransactionScopeOption; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector; @@ -51,10 +60,14 @@ import org.ovirt.engine.core.utils.transaction.TransactionSupport; @DisableInPrepareMode -@LockIdNameAttribute -public class CreateAllSnapshotsFromVmCommand<T extends CreateAllSnapshotsFromVmParameters> extends VmCommand<T> implements QuotaStorageDependent { +@LockIdNameAttribute(isReleaseAtEndOfExecute = false) +public class CreateAllSnapshotsFromVmCommand<T extends CreateAllSnapshotsFromVmParameters> extends VmCommand<T> implements QuotaStorageDependent, TaskHandlerCommand<CreateAllSnapshotsFromVmParameters> { - List<DiskImage> selectedActiveDisks; + private List<DiskImage> cachedSelectedActiveDisks; + private Guid cachedStorageDomainId = Guid.Empty; + /** flag that indicates whether memory snapshot is about to be created */ + private boolean prepareForMemorySnapshot; + private String cachedSnapshotIsBeingTakenMessage; protected CreateAllSnapshotsFromVmCommand(Guid commandId) { super(commandId); @@ -81,12 +94,12 @@ * @return list of disks to be snapshot. */ protected List<DiskImage> getDisksList() { - if (selectedActiveDisks == null) { - selectedActiveDisks = ImagesHandler.filterImageDisks(DbFacade.getInstance().getDiskDao().getAllForVm(getVmId()), + if (cachedSelectedActiveDisks == null) { + cachedSelectedActiveDisks = ImagesHandler.filterImageDisks(DbFacade.getInstance().getDiskDao().getAllForVm(getVmId()), true, true); } - return selectedActiveDisks; + return cachedSelectedActiveDisks; } private void incrementVmGeneration() { @@ -104,33 +117,55 @@ setActionReturnValue(createdSnapshotId); - addSnapshotToDB(createdSnapshotId); + MemoryImageBuilder memoryImageBuilder = createMemoryImageBuilder(); + addSnapshotToDB(createdSnapshotId, memoryImageBuilder); createSnapshotsForDisks(newActiveSnapshotId); + memoryImageBuilder.build(); if (getTaskIdList().isEmpty()) { getParameters().setTaskGroupSuccess(true); incrementVmGeneration(); } + + if (!prepareForMemorySnapshot) { + freeLock(); + } + setSucceeded(true); } - private Snapshot addSnapshotToDB(Guid snapshotId) { - if (getDisksList().isEmpty()) { - return new SnapshotsManager().addSnapshot(snapshotId, - getParameters().getDescription(), - SnapshotStatus.OK, - getParameters().getSnapshotType(), - getVm(), - true, - getCompensationContext()); + public Guid getStorageDomainIdForVmMemory() { + if (cachedStorageDomainId.equals(Guid.Empty) && getVm() != null) { + long sizeNeeded = getVm().getTotalMemorySizeInBytes() / BYTES_IN_GB; + StorageDomain storageDomain = VmHandler.findStorageDomainForMemory(getVm().getStoragePoolId(), sizeNeeded); + if (storageDomain != null) { + cachedStorageDomainId = storageDomain.getId(); + } + } + return cachedStorageDomainId; + } + + private MemoryImageBuilder createMemoryImageBuilder() { + if (FeatureSupported.memorySnapshot(getVm().getVdsGroupCompatibilityVersion()) + && getParameters().isSaveMemory() && isLiveSnapshotApplicable()) { + prepareForMemorySnapshot = true; + return new DefaultMemoryImageBuilder(getVm(), getStorageDomainIdForVmMemory(), getStoragePool(), this); } else { - return new SnapshotsManager().addSnapshot(snapshotId, - getParameters().getDescription(), - getParameters().getSnapshotType(), - getVm(), - getCompensationContext()); + return new NullableMemoryImageBuilder(); } + } + + private Snapshot addSnapshotToDB(Guid snapshotId, MemoryImageBuilder memoryImageBuilder) { + boolean taskExists = !getDisksList().isEmpty() || memoryImageBuilder.isCreateTasks(); + return new SnapshotsManager().addSnapshot(snapshotId, + getParameters().getDescription(), + taskExists ? SnapshotStatus.LOCKED : SnapshotStatus.OK, + getParameters().getSnapshotType(), + getVm(), + true, + memoryImageBuilder.getVolumeStringRepresentation(), + getCompensationContext()); } private void createSnapshotsForDisks(Guid vmSnapshotId) { @@ -145,7 +180,7 @@ getTaskIdList().addAll(vdcReturnValue.getInternalTaskIdList()); } else { throw new VdcBLLException(vdcReturnValue.getFault().getError(), - "CreateAllSnapshotsFromVmCommand::executeVmCommand: Failed to create snapshot!"); + "Failed to create snapshot!"); } } } @@ -181,17 +216,17 @@ @Override public Void runInTransaction() { final boolean taskGroupSucceeded = getParameters().getTaskGroupSuccess(); - Guid createdSnapshotId = - getSnapshotDao().getId(getVmId(), getParameters().getSnapshotType(), SnapshotStatus.LOCKED); + Snapshot createdSnapshot = getSnapshotDao().get(getVmId(), getParameters().getSnapshotType(), SnapshotStatus.LOCKED); if (taskGroupSucceeded) { - getSnapshotDao().updateStatus(createdSnapshotId, SnapshotStatus.OK); + getSnapshotDao().updateStatus(createdSnapshot.getId(), SnapshotStatus.OK); - if (getParameters().getParentCommand() != VdcActionType.RunVm && getVm() != null && getVm().isRunning() - && getVm().getRunOnVds() != null) { - performLiveSnapshot(createdSnapshotId); + if (isLiveSnapshotApplicable()) { + performLiveSnapshot(createdSnapshot); } + // TODO: else remove the memory image if exists } else { - revertToActiveSnapshot(createdSnapshotId); + revertToActiveSnapshot(createdSnapshot.getId()); + // TODO: remove the memory image if exists } incrementVmGeneration(); @@ -211,6 +246,11 @@ new RunVmParams(getVmId()), ExecutionHandler.createInternalJobContext()); } + } + + private boolean isLiveSnapshotApplicable() { + return getParameters().getParentCommand() != VdcActionType.RunVm && getVm() != null + && getVm().isRunning() && getVm().getRunOnVds() != null; } @Override @@ -243,22 +283,36 @@ * @param createdSnapshotId * Snapshot to revert to being active, in case of rollback. */ - protected void performLiveSnapshot(Guid createdSnapshotId) { + protected void performLiveSnapshot(final Snapshot snapshot) { try { TransactionSupport.executeInScope(TransactionScopeOption.Suppress, new TransactionMethod<Void>() { @Override public Void runInTransaction() { - List<Disk> pluggedDisks = getDiskDao().getAllForVm(getVm().getId(), true); - runVdsCommand(VDSCommandType.Snapshot, - new SnapshotVDSCommandParameters(getVm().getRunOnVds().getValue(), - getVm().getId(), - ImagesHandler.filterImageDisks(pluggedDisks, false, true))); + + runVdsCommand(VDSCommandType.Snapshot, buildLiveSnapshotParameters(snapshot)); + return null; } }); } catch (VdcBLLException e) { handleVdsLiveSnapshotFailure(e); + } + } + + private SnapshotVDSCommandParameters buildLiveSnapshotParameters(Snapshot snapshot) { + List<Disk> pluggedDisks = getDiskDao().getAllForVm(getVm().getId(), true); + List<DiskImage> filteredPluggedDisks = ImagesHandler.filterImageDisks(pluggedDisks, false, true); + if (FeatureSupported.memorySnapshot(getVm().getVdsGroupCompatibilityVersion())) { + return new SnapshotVDSCommandParameters(getVm().getRunOnVds().getValue(), + getVm().getId(), + filteredPluggedDisks, + snapshot.getMemoryVolume()); + } + else { + return new SnapshotVDSCommandParameters(getVm().getRunOnVds().getValue(), + getVm().getId(), + filteredPluggedDisks); } } @@ -332,6 +386,11 @@ return false; } } + + if (getParameters().isSaveMemory() && Guid.Empty.equals(getStorageDomainIdForVmMemory())) { + return failCanDoAction(VdcBllMessages.ACTION_TYPE_FAILED_NO_SUITABLE_DOMAIN_FOUND); + } + return true; } @@ -401,8 +460,19 @@ protected Map<String, Pair<String, String>> getExclusiveLocks() { return getParameters().isNeedsLocking() ? Collections.singletonMap(getVmId().toString(), - LockMessagesMatchUtil.makeLockingPair(LockingGroup.VM, VdcBllMessages.ACTION_TYPE_FAILED_OBJECT_LOCKED)) + LockMessagesMatchUtil.makeLockingPair(LockingGroup.VM, getSnapshotIsBeingTakenForVmMessage())) : null; + } + + private String getSnapshotIsBeingTakenForVmMessage() { + if (cachedSnapshotIsBeingTakenMessage == null) { + StringBuilder builder = new StringBuilder(VdcBllMessages.ACTION_TYPE_FAILED_SNAPSHOT_IS_BEING_TAKEN_FOR_VM.name()); + if (getVmName() != null) { + builder.append(String.format("$VmName %1$s", getVmName())); + } + cachedSnapshotIsBeingTakenMessage = builder.toString(); + } + return cachedSnapshotIsBeingTakenMessage; } @Override @@ -419,4 +489,48 @@ return list; } + + ///////////////////////////////////////// + /// 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 preventRollback() { + throw new NotImplementedException(); + } + + public void setExecutionContext(ExecutionContext executionContext) { + super.setExecutionContext(executionContext); + } + + public Guid createTask(AsyncTaskCreationInfo asyncTaskCreationInfo, + VdcActionType parentCommand, + VdcObjectType entityType, + Guid... entityIds) { + return super.createTask(asyncTaskCreationInfo, parentCommand, + entityType, entityIds); + } + + public Guid createTask(AsyncTaskCreationInfo asyncTaskCreationInfo, VdcActionType parentCommand) { + return super.createTask(asyncTaskCreationInfo, parentCommand); + } + + public ArrayList<Guid> getTaskIdList() { + return super.getTaskIdList(); + } } diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/HibernateVmCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/HibernateVmCommand.java index 147b1c6..c3214c0 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/HibernateVmCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/HibernateVmCommand.java @@ -37,6 +37,11 @@ @NonTransactiveCommandAttribute(forceCompensation = true) public class HibernateVmCommand<T extends HibernateVmParameters> extends VmOperationCommandBase<T> { private boolean isHibernateVdsProblematic = false; + + /** The size for the snapshot's meta data which is vm related properties at the + * time the snapshot was taken */ + public static final long META_DATA_SIZE_IN_BYTES = 10 * 1024; + /** * Constructor for command creation when compensation is applied on startup * @@ -66,7 +71,7 @@ public NGuid getStorageDomainId() { if (_storageDomainId.equals(Guid.Empty) && getVm() != null) { long sizeNeeded = (getVm().getTotalMemorySizeInBytes() - + getMetaDataSizeInBytes()) / BYTES_IN_GB; + + META_DATA_SIZE_IN_BYTES) / BYTES_IN_GB; StorageDomain storageDomain = VmHandler.findStorageDomainForMemory(getVm().getStoragePoolId(), sizeNeeded); if (storageDomain != null) { _storageDomainId = storageDomain.getId(); @@ -156,7 +161,7 @@ getStorageDomainId() .getValue(), image2GroupId, - getMetaDataSizeInBytes(), + META_DATA_SIZE_IN_BYTES, VolumeType.Sparse, VolumeFormat.COW, hiberVol2, @@ -248,7 +253,7 @@ return failCanDoAction(VdcBllMessages.VM_CANNOT_SUSPEND_VM_FROM_POOL); } if (getStorageDomainId().equals(Guid.Empty)) { - return failCanDoAction(VdcBllMessages.VM_CANNOT_SUSPEND_NO_SUITABLE_DOMAIN_FOUND); + return failCanDoAction(VdcBllMessages.ACTION_TYPE_FAILED_NO_SUITABLE_DOMAIN_FOUND); } return true; } @@ -368,15 +373,6 @@ private VolumeType getVolumeType() { return (getStoragePool().getstorage_pool_type().isFileDomain()) ? VolumeType.Sparse : VolumeType.Preallocated; - } - - /** - * Returns the meta data that should be allocated when saving state of image. - * - * @return - Meta data size for allocation in bytes. - */ - private long getMetaDataSizeInBytes() { - return (long) 10 * 1024; } private static Log log = LogFactory.getLog(HibernateVmCommand.class); diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/lsm/LiveMigrateDiskCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/lsm/LiveMigrateDiskCommand.java index 679005f..dee577b 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/lsm/LiveMigrateDiskCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/lsm/LiveMigrateDiskCommand.java @@ -1,5 +1,6 @@ package org.ovirt.engine.core.bll.lsm; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -88,6 +89,16 @@ } @Override + public Guid createTask(AsyncTaskCreationInfo asyncTaskCreationInfo, VdcActionType parentCommand) { + return super.createTask(asyncTaskCreationInfo, parentCommand); + } + + @Override + public ArrayList<Guid> getTaskIdList() { + return super.getTaskIdList(); + } + + @Override protected void endSuccessfully() { super.endSuccessfully(); if (isLastTaskHandler()) { diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/lsm/LiveMigrateVmDisksCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/lsm/LiveMigrateVmDisksCommand.java index 79c2eb3..9df32ce 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/lsm/LiveMigrateVmDisksCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/lsm/LiveMigrateVmDisksCommand.java @@ -89,6 +89,16 @@ } @Override + public Guid createTask(AsyncTaskCreationInfo asyncTaskCreationInfo, VdcActionType parentCommand) { + return super.createTask(asyncTaskCreationInfo, parentCommand); + } + + @Override + public ArrayList<Guid> getTaskIdList() { + return super.getTaskIdList(); + } + + @Override public List<PermissionSubject> getPermissionCheckSubjects() { List<PermissionSubject> permissionList = new ArrayList<PermissionSubject>(); diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/DefaultMemoryImageBuilder.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/DefaultMemoryImageBuilder.java new file mode 100644 index 0000000..add296c --- /dev/null +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/DefaultMemoryImageBuilder.java @@ -0,0 +1,121 @@ +package org.ovirt.engine.core.bll.memory; + +import org.ovirt.engine.core.bll.Backend; +import org.ovirt.engine.core.bll.HibernateVmCommand; +import org.ovirt.engine.core.bll.tasks.TaskHandlerCommand; +import org.ovirt.engine.core.common.VdcObjectType; +import org.ovirt.engine.core.common.businessentities.StoragePool; +import org.ovirt.engine.core.common.businessentities.VM; +import org.ovirt.engine.core.common.businessentities.VolumeFormat; +import org.ovirt.engine.core.common.businessentities.VolumeType; +import org.ovirt.engine.core.common.errors.VdcBLLException; +import org.ovirt.engine.core.common.errors.VdcBllErrors; +import org.ovirt.engine.core.common.vdscommands.CreateImageVDSCommandParameters; +import org.ovirt.engine.core.common.vdscommands.VDSCommandType; +import org.ovirt.engine.core.common.vdscommands.VDSReturnValue; +import org.ovirt.engine.core.compat.Guid; + +/** + * This builder creates the memory images for live snapshots with memory operation + */ +public class DefaultMemoryImageBuilder implements MemoryImageBuilder { + private Guid storageDomainId; + private Guid memoryDumpImageGroupId; + private Guid memoryDumpVolumeId; + private Guid vmConfImageGroupId; + private Guid vmConfVolumeId; + private VM vm; + private TaskHandlerCommand<?> enclosingCommand; + private StoragePool storagePool; + + public DefaultMemoryImageBuilder(VM vm, Guid storageDomainId, + StoragePool storagePool, TaskHandlerCommand<?> enclosingCommand) { + this.vm = vm; + this.enclosingCommand = enclosingCommand; + this.storageDomainId = storageDomainId; + this.storagePool = storagePool; + this.memoryDumpImageGroupId = Guid.NewGuid(); + this.memoryDumpVolumeId = Guid.NewGuid(); + this.vmConfImageGroupId = Guid.NewGuid(); + this.vmConfVolumeId = Guid.NewGuid(); + } + + public void build() { + createImageForVmMetaData(); + createImageForMemoryDump(); + } + + private void createImageForVmMetaData() { + VDSReturnValue retVal = + Backend + .getInstance() + .getResourceManager() + .RunVdsCommand( + VDSCommandType.CreateImage, + new CreateImageVDSCommandParameters(vm.getStoragePoolId(), + storageDomainId, + vmConfImageGroupId, + HibernateVmCommand.META_DATA_SIZE_IN_BYTES, + VolumeType.Sparse, + VolumeFormat.COW, + vmConfVolumeId, + "", + storagePool.getcompatibility_version() + .toString())); + + if (!retVal.getSucceeded()) { + throw new VdcBLLException(VdcBllErrors.VolumeCreationError, + "Failed to create image for vm configuration!"); + } + + Guid guid = enclosingCommand.createTask( + retVal.getCreationInfo(), + enclosingCommand.getActionType()); + enclosingCommand.getTaskIdList().add(guid); + } + + private void createImageForMemoryDump() { + VDSReturnValue retVal = + Backend + .getInstance() + .getResourceManager() + .RunVdsCommand( + VDSCommandType.CreateImage, + new CreateImageVDSCommandParameters( + storagePool.getId(), + storageDomainId, + memoryDumpImageGroupId, + vm.getTotalMemorySizeInBytes(), + VolumeType.Preallocated, + VolumeFormat.RAW, + memoryDumpVolumeId, + "", + storagePool.getcompatibility_version().toString())); + + if (!retVal.getSucceeded()) { + throw new VdcBLLException(VdcBllErrors.VolumeCreationError, + "Failed to create image for memory!"); + } + + Guid guid = + enclosingCommand.createTask(retVal.getCreationInfo(), + enclosingCommand.getActionType(), + VdcObjectType.Storage, + storageDomainId); + enclosingCommand.getTaskIdList().add(guid); + } + + public String getVolumeStringRepresentation() { + return String.format("%1$s,%2$s,%3$s,%4$s,%5$s,%6$s", + storageDomainId, + storagePool.getId(), + memoryDumpImageGroupId, + memoryDumpVolumeId, + vmConfImageGroupId, + vmConfVolumeId); + } + + public boolean isCreateTasks() { + return true; + } +} diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/MemoryImageBuilder.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/MemoryImageBuilder.java new file mode 100644 index 0000000..d5b7da5 --- /dev/null +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/MemoryImageBuilder.java @@ -0,0 +1,20 @@ +package org.ovirt.engine.core.bll.memory; + +public interface MemoryImageBuilder { + /** + * Create the images + */ + void build(); + + /** + * Return the string representation of the memory volumes + * @return string representation of the memory volumes + */ + String getVolumeStringRepresentation(); + + /** + * Return whether this builder creates tasks in {@link #build()} + * @return true if tasks are created in {@link #build()}, false otherwise + */ + boolean isCreateTasks(); +} diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/NullableMemoryImageBuilder.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/NullableMemoryImageBuilder.java new file mode 100644 index 0000000..929c729 --- /dev/null +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/memory/NullableMemoryImageBuilder.java @@ -0,0 +1,21 @@ +package org.ovirt.engine.core.bll.memory; + +import org.apache.commons.lang.StringUtils; + +/** + * This builder is used when no memory image should be created + */ +public class NullableMemoryImageBuilder implements MemoryImageBuilder { + + public void build() { + //no op + } + + public String getVolumeStringRepresentation() { + return StringUtils.EMPTY; + } + + public boolean isCreateTasks() { + return false; + } +} diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/snapshots/SnapshotsManager.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/snapshots/SnapshotsManager.java index 7135408..5428bfe 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/snapshots/SnapshotsManager.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/snapshots/SnapshotsManager.java @@ -95,6 +95,7 @@ SnapshotType.ACTIVE, vm, false, + StringUtils.EMPTY, compensationContext); } @@ -120,7 +121,8 @@ SnapshotType snapshotType, VM vm, final CompensationContext compensationContext) { - return addSnapshot(snapshotId, description, SnapshotStatus.LOCKED, snapshotType, vm, true, compensationContext); + return addSnapshot(snapshotId, description, SnapshotStatus.LOCKED, + snapshotType, vm, true, StringUtils.EMPTY, compensationContext); } /** @@ -148,6 +150,7 @@ SnapshotType snapshotType, VM vm, boolean saveVmConfiguration, + String memoryVolume, final CompensationContext compensationContext) { final Snapshot snapshot = new Snapshot(snapshotId, snapshotStatus, @@ -157,7 +160,7 @@ description, new Date(), vm.getAppList(), - StringUtils.EMPTY); + memoryVolume); getSnapshotDao().save(snapshot); compensationContext.snapshotNewEntity(snapshot); diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/tasks/TaskHandlerCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/tasks/TaskHandlerCommand.java index d7ee09b..162be43 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/tasks/TaskHandlerCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/tasks/TaskHandlerCommand.java @@ -1,5 +1,7 @@ package org.ovirt.engine.core.bll.tasks; +import java.util.ArrayList; + import org.ovirt.engine.core.bll.job.ExecutionContext; import org.ovirt.engine.core.common.VdcObjectType; import org.ovirt.engine.core.common.action.VdcActionParametersBase; @@ -27,4 +29,8 @@ VdcObjectType entityType, Guid... entityIds); + Guid createTask(AsyncTaskCreationInfo asyncTaskCreationInfo, + VdcActionType parentCommand); + + ArrayList<Guid> getTaskIdList(); } diff --git a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/CreateAllSnapshotsFromVmCommandTest.java b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/CreateAllSnapshotsFromVmCommandTest.java index c14b5e1..d0c3733 100644 --- a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/CreateAllSnapshotsFromVmCommandTest.java +++ b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/CreateAllSnapshotsFromVmCommandTest.java @@ -68,6 +68,7 @@ public void testPositiveCanDoActionWithNoDisks() { setUpGeneralValidations(); doReturn(getEmptyDiskList()).when(cmd).getDisksList(); + doReturn(Guid.NewGuid()).when(cmd).getStorageDomainId(); assertTrue(cmd.canDoAction()); assertTrue(cmd.getReturnValue().getCanDoActionMessages().isEmpty()); } @@ -169,6 +170,7 @@ setUpGeneralValidations(); setUpDiskValidations(); doReturn(getNonEmptyDiskList()).when(cmd).getDisksList(); + doReturn(Guid.NewGuid()).when(cmd).getStorageDomainId(); assertTrue(cmd.canDoAction()); assertTrue(cmd.getReturnValue().getCanDoActionMessages().isEmpty()); } diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/CreateAllSnapshotsFromVmParameters.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/CreateAllSnapshotsFromVmParameters.java index f6cc9eb..2af5311 100644 --- a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/CreateAllSnapshotsFromVmParameters.java +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/CreateAllSnapshotsFromVmParameters.java @@ -18,7 +18,7 @@ @ValidDescription(message = "VALIDATION.DISK_IMAGE.DESCRIPTION.INVALID", groups = { CreateEntity.class }) @Size(max = BusinessEntitiesDefinitions.GENERAL_MAX_SIZE, groups = { CreateEntity.class}, message = "VALIDATION_DISK_IMAGE_DESCRIPTION_MAX") - private String _description; + private String description; private boolean needsLocking = true; /** Used to store the vm status when the command start, will be used to check if the vm went down during the execution */ @@ -27,16 +27,24 @@ /** Used to indicate the type of snapshot to take */ private SnapshotType snapshotType; + /** Used to indicate whether the memory should be saved as part of this snapshot or not */ + private boolean saveMemory; + public CreateAllSnapshotsFromVmParameters() { } public CreateAllSnapshotsFromVmParameters(Guid vmId, String description) { super(vmId); - _description = description; + this.description = description; + } + + public CreateAllSnapshotsFromVmParameters(Guid vmId, String description, boolean saveMemory) { + this(vmId, description); + this.saveMemory = saveMemory; } public String getDescription() { - return _description; + return description; } public SnapshotType getSnapshotType() { @@ -59,6 +67,14 @@ this.snapshotType = snapshotType; } + public boolean isSaveMemory() { + return saveMemory; + } + + public void setSaveMemory(boolean saveMemory) { + this.saveMemory = saveMemory; + } + public boolean isNeedsLocking() { return needsLocking; } diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllMessages.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllMessages.java index 4617e4d..6010280 100644 --- a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllMessages.java +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllMessages.java @@ -275,7 +275,7 @@ VM_CANNOT_IMPORT_VM_NAME_EXISTS(ErrorType.CONFLICT), VM_CANNOT_SUSPEND_STATELESS_VM(ErrorType.CONFLICT), VM_CANNOT_SUSPEND_VM_FROM_POOL(ErrorType.CONFLICT), - VM_CANNOT_SUSPEND_NO_SUITABLE_DOMAIN_FOUND(ErrorType.CONFLICT), + ACTION_TYPE_FAILED_NO_SUITABLE_DOMAIN_FOUND(ErrorType.CONFLICT), VM_CANNOT_SUSPEND_VM_WITHOUT_IMAGE_DISKS(ErrorType.CONFLICT), // internal const string VMT_CANNOT_REMOVE_DETECTED_DERIVED_VM = // "Cannot delete the template, there are desktop(s) created from template"; @@ -484,6 +484,7 @@ @Deprecated ACTION_TYPE_FAILED_OBJECT_LOCKED(ErrorType.CONFLICT), ACTION_TYPE_FAILED_TEMPLATE_IS_USED_FOR_CREATE_VM(ErrorType.CONFLICT), + ACTION_TYPE_FAILED_SNAPSHOT_IS_BEING_TAKEN_FOR_VM(ErrorType.CONFLICT), ACTION_TYPE_FAILED_DISK_IS_USED_FOR_CREATE_VM(ErrorType.CONFLICT), ACTION_TYPE_FAILED_DISK_IS_BEING_REMOVED(ErrorType.CONFLICT), ACTION_TYPE_FAILED_TEMPLATE_IS_BEING_EXPORTED(ErrorType.CONFLICT), diff --git a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDao.java b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDao.java index 08d2d30..200a0cb 100644 --- a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDao.java +++ b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDao.java @@ -61,6 +61,20 @@ */ Snapshot get(Guid vmId, SnapshotType type); + /** + * Return the <b>first</b> {@link Snapshot} that matches the given parameters.<br> + * <b>Note:</b> If more than one snapshot answers to the parameters, only the first will be returned (oldest by + * creation date). + * + * @param vmId + * The id of the VM to check for. + * @param type + * The type of snapshot. + * @param status + * The status of the snapshot. + * @return The snapshot, or <code>null</code> if it doesn't exist. + */ + Snapshot get(Guid vmId, SnapshotType type, SnapshotStatus status); /** * Return the {@link Snapshot} <b>first</b> id that matches the given parameters.<br> diff --git a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDaoDbFacadeImpl.java b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDaoDbFacadeImpl.java index 9474508..b90e975 100644 --- a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDaoDbFacadeImpl.java +++ b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDaoDbFacadeImpl.java @@ -86,6 +86,18 @@ } @Override + public Snapshot get(Guid vmId, SnapshotType type, SnapshotStatus status) { + MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource() + .addValue("vm_id", vmId) + .addValue("snapshot_type", EnumUtils.nameOrNull(type)) + .addValue("status", EnumUtils.nameOrNull(status)); + + return getCallsHandler().executeRead("GetSnapshotByVmIdAndTypeAndStatus", + createEntityRowMapper(), + parameterSource); + } + + @Override public List<Snapshot> getAllWithConfiguration(Guid vmId) { return getAll(vmId, null, false, true); } diff --git a/backend/manager/modules/dal/src/main/resources/bundles/AppErrors.properties b/backend/manager/modules/dal/src/main/resources/bundles/AppErrors.properties index fe4344b..5e8ad36 100644 --- a/backend/manager/modules/dal/src/main/resources/bundles/AppErrors.properties +++ b/backend/manager/modules/dal/src/main/resources/bundles/AppErrors.properties @@ -318,7 +318,7 @@ VM_CANNOT_SUSPENDE_HAS_RUNNING_TASKS=Cannot suspend VM. VM has asynchronous running tasks, please retry later. VM_CANNOT_SUSPEND_STATELESS_VM=Cannot suspend VM, VM is stateless. VM_CANNOT_SUSPEND_VM_FROM_POOL=Cannot suspend VM that belongs to a VM-Pool. -VM_CANNOT_SUSPEND_NO_SUITABLE_DOMAIN_FOUND=Cannot suspend VM. No active data Storage Domain with enough storage was found in the Data Center. +ACTION_TYPE_FAILED_NO_SUITABLE_DOMAIN_FOUND=Cannot ${action} ${type}. No active data Storage Domain with enough storage was found in the Data Center. USER_NOT_AUTHORIZED_TO_PERFORM_ACTION=User is not authorized to perform this action. ERROR_CANNOT_REMOVE_ROLE_ATTACHED_TO_PERMISSION=One or more Permissions is still associated with Role.\n\ - Please remove all Permissions first. @@ -508,6 +508,7 @@ NETWORK_ADDR_MANDATORY_IN_STATIC_IP=Network address must be specified when using static IP ACTION_TYPE_FAILED_OBJECT_LOCKED=Cannot ${action} ${type}. Related operation is currently in progress. Please try again later. ACTION_TYPE_FAILED_TEMPLATE_IS_USED_FOR_CREATE_VM=Cannot ${action} ${type}. This template is currently in use to create VM ${VmName}. +ACTION_TYPE_FAILED_SNAPSHOT_IS_BEING_TAKEN_FOR_VM=Cannot ${action} ${type}. Snapshot is currently being created for VM ${VmName}. ACTION_TYPE_FAILED_DISK_IS_USED_FOR_CREATE_VM=Cannot ${action} ${type}. This disk is currently in use to create VM ${VmName}. ACTION_TYPE_FAILED_DISK_IS_BEING_REMOVED=Cannot ${action} ${type}. Disk ${DiskName} is being removed. ACTION_TYPE_FAILED_TEMPLATE_IS_BEING_EXPORTED=Cannot ${action} ${type}. Template ${TemplateName} is being exported. diff --git a/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/SnapshotDaoTest.java b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/SnapshotDaoTest.java index 7b99bdf..a166856 100644 --- a/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/SnapshotDaoTest.java +++ b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/SnapshotDaoTest.java @@ -114,6 +114,16 @@ } @Test + public void getSnaphsotByTypeAndStatusForExistingEntity() throws Exception { + assertEquals(existingEntity, dao.get(EXISTING_VM_ID, SnapshotType.REGULAR, SnapshotStatus.OK)); + } + + @Test + public void getSnaphsotByTypeAndStatusForNonExistingEntity() throws Exception { + assertNull(dao.get(EXISTING_VM_ID, SnapshotType.REGULAR, SnapshotStatus.LOCKED)); + } + + @Test public void getIdByTypeReturnsIdForExistingByTypeAndStatus() throws Exception { assertEquals(getExistingEntityId(), dao.getId(EXISTING_VM_ID, SnapshotType.REGULAR)); } diff --git a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java index cf837f7..d56c16c 100644 --- a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java +++ b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java @@ -901,9 +901,6 @@ @DefaultStringValue("Cannot suspend VM that belongs to a VM-Pool.") String VM_CANNOT_SUSPEND_VM_FROM_POOL(); - @DefaultStringValue("Cannot suspend VM. No active data Storage Domain with enough storage was found in the Data Center.") - String VM_CANNOT_SUSPEND_NO_SUITABLE_DOMAIN_FOUND(); - @DefaultStringValue("User is not authorized to perform this action.") String USER_NOT_AUTHORIZED_TO_PERFORM_ACTION(); @@ -963,6 +960,9 @@ @DefaultStringValue("Cannot ${action} ${type}. Storage connection doesn't exist.") String ACTION_TYPE_FAILED_STORAGE_CONNECTION_NOT_EXIST(); + + @DefaultStringValue("Cannot ${action} ${type}. No active data Storage Domain with enough storage was found in the Data Center.") + String ACTION_TYPE_FAILED_NO_SUITABLE_DOMAIN_FOUND(); @DefaultStringValue("Cannot ${action} ${type}. Storage connection already exists.") String ACTION_TYPE_FAILED_STORAGE_CONNECTION_ALREADY_EXISTS(); @@ -1363,6 +1363,9 @@ @DefaultStringValue("Cannot ${action} ${type}. This template is currently in use to create VM ${VmName}.") String ACTION_TYPE_FAILED_TEMPLATE_IS_USED_FOR_CREATE_VM(); + @DefaultStringValue("Cannot ${action} ${type}. Snapshot is currently being created for VM ${VmName}.") + String ACTION_TYPE_FAILED_SNAPSHOT_IS_BEING_TAKEN_FOR_VM(); + @DefaultStringValue("Cannot ${action} ${type}. This disk is currently in use to create VM ${VmName}.") String ACTION_TYPE_FAILED_DISK_IS_USED_FOR_CREATE_VM(); diff --git a/frontend/webadmin/modules/userportal-gwtp/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties b/frontend/webadmin/modules/userportal-gwtp/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties index c958c03..51fb626 100644 --- a/frontend/webadmin/modules/userportal-gwtp/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties +++ b/frontend/webadmin/modules/userportal-gwtp/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties @@ -313,7 +313,7 @@ VM_CANNOT_SUSPENDE_HAS_RUNNING_TASKS=Cannot suspend VM. VM has asynchronous running tasks, please retry later. VM_CANNOT_SUSPEND_STATELESS_VM=Cannot suspend VM, VM is stateless. VM_CANNOT_SUSPEND_VM_FROM_POOL=Cannot suspend VM that belongs to a VM-Pool. -VM_CANNOT_SUSPEND_NO_SUITABLE_DOMAIN_FOUND=Cannot suspend VM. No active data Storage Domain with enough storage was found in the Data Center. +ACTION_TYPE_FAILED_NO_SUITABLE_DOMAIN_FOUND=Cannot ${action} ${type}. No active data Storage Domain with enough storage was found in the Data Center. USER_NOT_AUTHORIZED_TO_PERFORM_ACTION=User is not authorized to perform this action. ERROR_CANNOT_REMOVE_ROLE_ATTACHED_TO_PERMISSION=One or more Permissions is still associated with Role.\n\ - Please remove all Permissions first. @@ -505,6 +505,7 @@ NETWORK_ADDR_MANDATORY_IN_STATIC_IP=Network address must be specified when using static ip ACTION_TYPE_FAILED_OBJECT_LOCKED=Cannot ${action} ${type}. Related operation is currently in progress. Please try again later. ACTION_TYPE_FAILED_TEMPLATE_IS_USED_FOR_CREATE_VM=Cannot ${action} ${type}. This template is currently in use to create VM ${VmName}. +ACTION_TYPE_FAILED_SNAPSHOT_IS_BEING_TAKEN_FOR_VM=Cannot ${action} ${type}. Snapshot is currently being created for VM ${VmName}. ACTION_TYPE_FAILED_DISK_IS_USED_FOR_CREATE_VM=Cannot ${action} ${type}. This disk is currently in use to create VM ${VmName}. ACTION_TYPE_FAILED_DISK_IS_BEING_REMOVED=Cannot ${action} ${type}. Disk ${DiskName} is being removed. ACTION_TYPE_FAILED_TEMPLATE_IS_BEING_EXPORTED=Cannot ${action} ${type}. Template ${TemplateName} is being exported. diff --git a/frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties b/frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties index dc68e5b..9baf22d 100644 --- a/frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties +++ b/frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties @@ -321,7 +321,7 @@ VM_CANNOT_SUSPENDE_HAS_RUNNING_TASKS=Cannot suspend VM. VM has asynchronous running tasks, please retry later. VM_CANNOT_SUSPEND_STATELESS_VM=Cannot suspend VM, VM is stateless. VM_CANNOT_SUSPEND_VM_FROM_POOL=Cannot suspend VM that belongs to a VM-Pool. -VM_CANNOT_SUSPEND_NO_SUITABLE_DOMAIN_FOUND=Cannot suspend VM. No active data Storage Domain with enough storage was found in the Data Center. +ACTION_TYPE_FAILED_NO_SUITABLE_DOMAIN_FOUND=Cannot ${action} ${type}. No active data Storage Domain with enough storage was found in the Data Center. USER_NOT_AUTHORIZED_TO_PERFORM_ACTION=User is not authorized to perform this action. ERROR_CANNOT_REMOVE_ROLE_ATTACHED_TO_PERMISSION=One or more Permissions is still associated with Role.\n\ - Please remove all Permissions first. @@ -512,6 +512,7 @@ NETWORK_ADDR_MANDATORY_IN_STATIC_IP=Network address must be specified when using static ip ACTION_TYPE_FAILED_OBJECT_LOCKED=Cannot ${action} ${type}. Related operation is currently in progress. Please try again later. ACTION_TYPE_FAILED_TEMPLATE_IS_USED_FOR_CREATE_VM=Cannot ${action} ${type}. This template is currently in use to create VM ${VmName}. +ACTION_TYPE_FAILED_SNAPSHOT_IS_BEING_TAKEN_FOR_VM=Cannot ${action} ${type}. Snapshot is currently being created for VM ${VmName}. ACTION_TYPE_FAILED_DISK_IS_USED_FOR_CREATE_VM=Cannot ${action} ${type}. This disk is currently in use to create VM ${VmName}. ACTION_TYPE_FAILED_DISK_IS_BEING_REMOVED=Cannot ${action} ${type}. Disk ${DiskName} is being removed. ACTION_TYPE_FAILED_TEMPLATE_IS_BEING_EXPORTED=Cannot ${action} ${type}. Template ${TemplateName} is being exported. -- To view, visit http://gerrit.ovirt.org/15608 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ic7ceb07bf73e722bf4566989446e7dbba78a2ccb Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Arik Hadas <[email protected]> _______________________________________________ Engine-patches mailing list [email protected] http://lists.ovirt.org/mailman/listinfo/engine-patches
