From a4d8215ebba6009fc4b17ef7b61ff51238f0f404 Mon Sep 17 00:00:00 2001 From: Anshul Gangwar Date: Thu, 9 Oct 2014 10:37:21 +0530 Subject: [PATCH] CLOUDSTACK-7688, CLOUDSTACK-7747: restricted various operations for VM with VM snapshots which breaks VM snapshots. Now they are informed that they cannot perform the operation. To perform operation they have to remove VM snapshots of VM. --- .../cloud/storage/VolumeApiServiceImpl.java | 22 +++++- .../src/com/cloud/vm/UserVmManagerImpl.java | 77 +++++++++++-------- .../vm/snapshot/VMSnapshotManagerImpl.java | 12 +++ 3 files changed, 78 insertions(+), 33 deletions(-) diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java index b70d753ac442..07f62c362329 100644 --- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java @@ -707,6 +707,13 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep /* Does the caller have authority to act on this volume? */ _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, volume); + if(volume.getInstanceId() != null) { + // Check that Vm to which this volume is attached does not have VM Snapshots + if (_vmSnapshotDao.findByVm(volume.getInstanceId()).size() > 0) { + throw new InvalidParameterValueException("Volume cannot be resized which is attached to VM with VM Snapshots"); + } + } + DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId()); DiskOfferingVO newDiskOffering = null; @@ -977,7 +984,7 @@ private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long n StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId()); if (storagePool.isManaged() && storagePool.getHypervisor() == HypervisorType.Any && hosts != null && hosts.length > 0) { - HostVO host = this._hostDao.findById(hosts[0]); + HostVO host = _hostDao.findById(hosts[0]); if (currentSize != newSize && host.getHypervisorType() == HypervisorType.XenServer && !userVm.getState().equals(State.Stopped)) { throw new InvalidParameterValueException(errorMsg); @@ -1503,7 +1510,6 @@ public Volume detachVolumeFromVM(DetachVolumeCmd cmmd) { // Permissions check _accountMgr.checkAccess(caller, null, true, volume); - // Check that the volume is currently attached to a VM if (vmId == null) { throw new InvalidParameterValueException("The specified volume is not attached to a VM."); @@ -1693,6 +1699,11 @@ public Volume migrateVolume(MigrateVolumeCmd cmd) { vm = _vmInstanceDao.findById(instanceId); } + // Check that Vm to which this volume is attached does not have VM Snapshots + if (vm != null && _vmSnapshotDao.findByVm(vm.getId()).size() > 0) { + throw new InvalidParameterValueException("Volume cannot be migrated, please remove all VM snapshots for VM to which this volume is attached"); + } + if (vm != null && vm.getState() == State.Running) { // Check if the VM is GPU enabled. if(_serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) { @@ -1926,6 +1937,13 @@ public Snapshot allocSnapshot(Long volumeId, Long policyId) throws ResourceAlloc throw new InvalidParameterValueException("Can't find zone by id " + volume.getDataCenterId()); } + if (volume.getInstanceId() != null) { + // Check that Vm to which this volume is attached does not have VM Snapshots + if (_vmSnapshotDao.findByVm(volume.getInstanceId()).size() > 0) { + throw new InvalidParameterValueException("Volume snapshot is not allowed, please detach it from VM with VM Snapshots"); + } + } + if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getId())) { throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zone.getName()); } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 7fe1c2c5731a..609f781131bd 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -35,8 +35,6 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; @@ -89,6 +87,8 @@ import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; @@ -276,7 +276,6 @@ import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; -import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.VMSnapshotManager; import com.cloud.vm.snapshot.VMSnapshotVO; import com.cloud.vm.snapshot.dao.VMSnapshotDao; @@ -822,6 +821,12 @@ public UserVm upgradeVirtualMachine(UpgradeVMCmd cmd) throws ResourceAllocationE + "; make sure the virtual machine is stopped"); } + // If target VM has associated VM snapshots then don't allow upgrading of VM + List vmSnapshots = _vmSnapshotDao.findByVm(vmId); + if (vmSnapshots.size() > 0) { + throw new InvalidParameterValueException("Unable to change service offering for VM, please remove VM snapshots before changing service offering of VM"); + } + _accountMgr.checkAccess(caller, null, true, vmInstance); // Check resource limits for CPU and Memory. @@ -849,19 +854,6 @@ public UserVm upgradeVirtualMachine(UpgradeVMCmd cmd) throws ResourceAllocationE // Check that the specified service offering ID is valid _itMgr.checkIfCanUpgrade(vmInstance, newServiceOffering); - // remove diskAndMemory VM snapshots - List vmSnapshots = _vmSnapshotDao.findByVm(vmId); - for (VMSnapshotVO vmSnapshotVO : vmSnapshots) { - if (vmSnapshotVO.getType() == VMSnapshot.Type.DiskAndMemory) { - if (!_vmSnapshotMgr.deleteAllVMSnapshots(vmId, VMSnapshot.Type.DiskAndMemory)) { - String errMsg = "Failed to remove VM snapshot during upgrading, snapshot id " + vmSnapshotVO.getId(); - s_logger.debug(errMsg); - throw new CloudRuntimeException(errMsg); - } - - } - } - _itMgr.upgradeVmDb(vmId, svcOffId); if (newServiceOffering.isDynamic()) { //save the custom values to the database. @@ -962,19 +954,6 @@ private UserVm upgradeStoppedVirtualMachine(Long vmId, Long svcOffId, Map vmSnapshots = _vmSnapshotDao.findByVm(vmId); - for (VMSnapshotVO vmSnapshotVO : vmSnapshots) { - if (vmSnapshotVO.getType() == VMSnapshot.Type.DiskAndMemory) { - if (!_vmSnapshotMgr.deleteAllVMSnapshots(vmId, VMSnapshot.Type.DiskAndMemory)) { - String errMsg = "Failed to remove VM snapshot during upgrading, snapshot id " + vmSnapshotVO.getId(); - s_logger.debug(errMsg); - throw new CloudRuntimeException(errMsg); - } - - } - } - _itMgr.upgradeVmDb(vmId, svcOffId); if (newServiceOffering.isDynamic()) { //save the custom values to the database. @@ -1012,6 +991,12 @@ public UserVm addNicToVirtualMachine(AddNicToVMCmd cmd) throws InvalidParameterV if (vmInstance == null) { throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmId); } + + // Check that Vm does not have VM Snapshots + if (_vmSnapshotDao.findByVm(vmId).size() > 0) { + throw new InvalidParameterValueException("NIC cannot be added to VM with VM Snapshots"); + } + NetworkVO network = _networkDao.findById(networkId); if (network == null) { throw new InvalidParameterValueException("unable to find a network with id " + networkId); @@ -1096,6 +1081,12 @@ public UserVm removeNicFromVirtualMachine(RemoveNicFromVMCmd cmd) throws Invalid if (vmInstance == null) { throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmId); } + + // Check that Vm does not have VM Snapshots + if (_vmSnapshotDao.findByVm(vmId).size() > 0) { + throw new InvalidParameterValueException("NIC cannot be removed from VM with VM Snapshots"); + } + NicVO nic = _nicDao.findById(nicId); if (nic == null) { throw new InvalidParameterValueException("unable to find a nic with id " + nicId); @@ -1153,6 +1144,12 @@ public UserVm updateDefaultNicForVirtualMachine(UpdateDefaultNicForVMCmd cmd) th if (vmInstance == null) { throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmId); } + + // Check that Vm does not have VM Snapshots + if (_vmSnapshotDao.findByVm(vmId).size() > 0) { + throw new InvalidParameterValueException("NIC cannot be updated for VM with VM Snapshots"); + } + NicVO nic = _nicDao.findById(nicId); if (nic == null) { throw new InvalidParameterValueException("unable to find a nic with id " + nicId); @@ -1325,6 +1322,14 @@ public boolean upgradeVirtualMachine(Long vmId, Long newServiceOfferingId, Map vmSnapshots = _vmSnapshotDao.findByVm(vmId); + if (vmSnapshots.size() > 0) { + throw new InvalidParameterValueException("Unable to scale VM, please remove VM snapshots before scaling VM"); + } + } + if (vmInstance.getState().equals(State.Stopped)) { upgradeStoppedVirtualMachine(vmId, newServiceOfferingId, customParameters); return true; @@ -3813,6 +3818,11 @@ public VirtualMachine vmStorageMigration(Long vmId, StoragePool destPool) { throw new InvalidParameterValueException("Data disks attached to the vm, can not migrate. Need to dettach data disks at first"); } + // Check that Vm does not have VM Snapshots + if (_vmSnapshotDao.findByVm(vmId).size() > 0) { + throw new InvalidParameterValueException("VM's disk cannot be migrated, please remove all the VM Snapshots for this VM"); + } + HypervisorType destHypervisorType = destPool.getHypervisor(); if (destHypervisorType == null) { destHypervisorType = _clusterDao.findById( @@ -4231,6 +4241,11 @@ public VirtualMachine migrateVirtualMachineWithVolume(Long vmId, Host destinatio + destinationHost.getResourceState()); } + // Check that Vm does not have VM Snapshots + if (_vmSnapshotDao.findByVm(vmId).size() > 0) { + throw new InvalidParameterValueException("VM with VM Snapshots cannot be migrated with storage, please remove all VM snapshots"); + } + List vmVolumes = _volsDao.findUsableVolumesForInstance(vm.getId()); Map volToPoolObjectMap = new HashMap(); if (!isVMUsingLocalStorage(vm) && destinationHost.getClusterId().equals(srcHost.getClusterId())) { @@ -4697,8 +4712,8 @@ public UserVm restoreVMInternal(Account caller, UserVmVO vm, Long newTemplateId) // If target VM has associated VM snapshots then don't allow restore of VM List vmSnapshots = _vmSnapshotDao.findByVm(vmId); - if (vmSnapshots.size() > 0 && vm.getHypervisorType() == HypervisorType.VMware) { - throw new InvalidParameterValueException("Unable to restore VM, please specify a VM that does not have VM snapshots"); + if (vmSnapshots.size() > 0) { + throw new InvalidParameterValueException("Unable to restore VM, please remove VM snapshots before restoring VM"); } VMTemplateVO template = null; diff --git a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java index 46eb5da301c7..c30dc29de713 100644 --- a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java +++ b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java @@ -261,6 +261,11 @@ public VMSnapshot allocVMSnapshot(Long vmId, String vsDisplayName, String vsDesc throw new InvalidParameterValueException("Creating VM snapshot failed due to VM:" + vmId + " is a system VM or does not exist"); } + if (_snapshotDao.listByInstanceId(vmId, Snapshot.State.BackedUp).size() > 0) { + throw new InvalidParameterValueException( + "VM snapshot for this VM is not allowed. This VM has volumes attached which has snapshots, please remove all snapshots before taking VM snapshot"); + } + // VM snapshot with memory is not supported for VGPU Vms if (snapshotMemory && _serviceOfferingDetailsDao.findDetail(userVmVo.getServiceOfferingId(), GPU.Keys.vgpuType.toString()) != null) { throw new InvalidParameterValueException("VM snapshot with MEMORY is not supported for vGPU enabled VMs."); @@ -571,6 +576,13 @@ public UserVm revertToSnapshot(Long vmSnapshotId) throws InsufficientCapacityExc "VM Snapshot reverting failed due to vm is not in the state of Running or Stopped."); } + if (userVm.getState() == VirtualMachine.State.Running && vmSnapshotVo.getType() == VMSnapshot.Type.Disk || userVm.getState() == VirtualMachine.State.Stopped + && vmSnapshotVo.getType() == VMSnapshot.Type.DiskAndMemory) { + throw new InvalidParameterValueException( + "VM Snapshot revert not allowed. This will result in VM state change. You can revert running VM to disk and memory type snapshot and stopped VM to disk type" + + " snapshot"); + } + // if snapshot is not created, error out if (vmSnapshotVo.getState() != VMSnapshot.State.Ready) { throw new InvalidParameterValueException(