diff --git a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/StorageVMSnapshotStrategy.java b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/StorageVMSnapshotStrategy.java index ec73246851c..e33edc9ce80 100644 --- a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/StorageVMSnapshotStrategy.java +++ b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/StorageVMSnapshotStrategy.java @@ -181,7 +181,7 @@ public class StorageVMSnapshotStrategy extends DefaultVMSnapshotStrategy { thawAnswer = (FreezeThawVMAnswer) agentMgr.send(hostId, thawCmd); if (thawAnswer != null && thawAnswer.getResult()) { logger.info(String.format( - "Virtual machne is thawed. The freeze of virtual machine took %s milliseconds.", + "Virtual machine is thawed. The freeze of virtual machine took %s milliseconds.", TimeUnit.MILLISECONDS.convert(elapsedTime(startFreeze), TimeUnit.NANOSECONDS))); } } else { @@ -427,9 +427,14 @@ public class StorageVMSnapshotStrategy extends DefaultVMSnapshotStrategy { String snapshotName = vmSnapshot.getId() + "_" + vol.getUuid(); SnapshotVO snapshot = new SnapshotVO(vol.getDataCenterId(), vol.getAccountId(), vol.getDomainId(), vol.getId(), vol.getDiskOfferingId(), snapshotName, (short) Snapshot.Type.GROUP.ordinal(), Snapshot.Type.GROUP.name(), vol.getSize(), vol.getMinIops(), vol.getMaxIops(), Hypervisor.HypervisorType.KVM, null); + VMSnapshotOptions options = ((VMSnapshotVO) vmSnapshot).getOptions(); + boolean quiescevm = false; + if (options != null) { + quiescevm = options.needQuiesceVM(); + } snapshot = snapshotDao.persist(snapshot); - vol.addPayload(setPayload(vol, snapshot)); + vol.addPayload(setPayload(vol, snapshot, quiescevm)); SnapshotInfo snapshotInfo = snapshotDataFactory.getSnapshot(snapshot.getId(), vol.getDataStore()); snapshotInfo.addPayload(vol.getpayload()); SnapshotStrategy snapshotStrategy = storageStrategyFactory.getSnapshotStrategy(snapshotInfo, SnapshotOperation.TAKE); @@ -447,14 +452,14 @@ public class StorageVMSnapshotStrategy extends DefaultVMSnapshotStrategy { return snapshotInfo; } - protected CreateSnapshotPayload setPayload(VolumeInfo vol, SnapshotVO snapshotCreate) { + protected CreateSnapshotPayload setPayload(VolumeInfo vol, SnapshotVO snapshotCreate, boolean quiescevm) { CreateSnapshotPayload payload = new CreateSnapshotPayload(); payload.setSnapshotId(snapshotCreate.getId()); payload.setSnapshotPolicyId(SnapshotVO.MANUAL_POLICY_ID); payload.setLocationType(snapshotCreate.getLocationType()); payload.setAccount(accountService.getAccount(vol.getAccountId())); payload.setAsyncBackup(false); - payload.setQuiescevm(false); + payload.setQuiescevm(quiescevm); return payload; } } diff --git a/engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotStrategyKVMTest.java b/engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotStrategyKVMTest.java index 6aab8d32384..609a1225118 100644 --- a/engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotStrategyKVMTest.java +++ b/engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotStrategyKVMTest.java @@ -37,6 +37,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy.SnapshotOperation; import org.apache.cloudstack.engine.subsystem.api.storage.StorageStrategyFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VMSnapshotOptions; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; @@ -151,7 +152,7 @@ public class VMSnapshotStrategyKVMTest extends TestCase{ @Test public void testCreateDiskSnapshotBasedOnStrategy() throws Exception { - VMSnapshot vmSnapshot = Mockito.mock(VMSnapshot.class); + VMSnapshotVO vmSnapshot = Mockito.mock(VMSnapshotVO.class); List forRollback = new ArrayList<>(); VolumeInfo vol = Mockito.mock(VolumeInfo.class); SnapshotInfo snapshotInfo = Mockito.mock(SnapshotInfo.class); @@ -162,6 +163,7 @@ public class VMSnapshotStrategyKVMTest extends TestCase{ SnapshotVO snapshot = new SnapshotVO(vol.getDataCenterId(), vol.getAccountId(), vol.getDomainId(), vol.getId(),vol.getDiskOfferingId(), vmUuid + "_" + volUuid,(short) SnapshotVO.MANUAL_POLICY_ID, "MANUAL",vol.getSize(),vol.getMinIops(),vol.getMaxIops(), Hypervisor.HypervisorType.KVM, null); + when(vmSnapshot.getOptions()).thenReturn(new VMSnapshotOptions(true)); when(vmSnapshot.getUuid()).thenReturn(vmUuid); when(vol.getUuid()).thenReturn(volUuid); when(_snapshotDao.persist(any())).thenReturn(snapshot); diff --git a/test/integration/smoke/test_vm_strict_host_tags.py b/test/integration/smoke/test_vm_strict_host_tags.py index 163869c8fae..2377e9a7618 100644 --- a/test/integration/smoke/test_vm_strict_host_tags.py +++ b/test/integration/smoke/test_vm_strict_host_tags.py @@ -190,7 +190,7 @@ class TestVMDeploymentPlannerStrictTags(cloudstackTestCase): self.cleanup.append(vm) self.fail("VM should not be deployed") except Exception as e: - self.assertTrue("No suitable host found for vm " in str(e)) + self.assertTrue("No destination found for a deployment for VM instance" in str(e)) class TestScaleVMStrictTags(cloudstackTestCase): @@ -310,7 +310,7 @@ class TestScaleVMStrictTags(cloudstackTestCase): vm.start(self.apiclient) self.fail("VM should not be be able scale and start") except Exception as e: - self.assertTrue("No suitable host found for vm " in str(e)) + self.assertTrue("Unable to orchestrate the start of VM instance" in str(e)) class TestRestoreVMStrictTags(cloudstackTestCase): @@ -423,7 +423,7 @@ class TestRestoreVMStrictTags(cloudstackTestCase): vm.restore(self.apiclient, templateid=self.template_t2.id, expunge=True) self.fail("VM should not be restored") except Exception as e: - self.assertTrue("No suitable host found for vm " in str(e)) + self.assertTrue("Unable to start VM with specified id" in str(e)) class TestMigrateVMStrictTags(cloudstackTestCase): diff --git a/ui/src/config/section/compute.js b/ui/src/config/section/compute.js index 65fbcee52b7..5b7bd0f8b9b 100644 --- a/ui/src/config/section/compute.js +++ b/ui/src/config/section/compute.js @@ -190,7 +190,13 @@ export default { label: 'label.action.vmsnapshot.create', docHelp: 'adminguide/virtual_machines.html#virtual-machine-snapshots', dataView: true, - args: ['virtualmachineid', 'name', 'description', 'snapshotmemory', 'quiescevm'], + args: (record, store) => { + var args = ['virtualmachineid', 'name', 'description', 'snapshotmemory'] + if (['KVM', 'VMware'].includes(record.hypervisor)) { + args.push('quiescevm') + } + return args + }, show: (record) => { return (((['Running'].includes(record.state) && record.hypervisor !== 'LXC') || (['Stopped'].includes(record.state) && ((record.hypervisor !== 'KVM' && record.hypervisor !== 'LXC') || diff --git a/ui/src/views/compute/CreateSnapshotWizard.vue b/ui/src/views/compute/CreateSnapshotWizard.vue index 0da42990efa..d19208a1808 100644 --- a/ui/src/views/compute/CreateSnapshotWizard.vue +++ b/ui/src/views/compute/CreateSnapshotWizard.vue @@ -55,13 +55,13 @@ v-model:value="form.name" :placeholder="apiParams.name.description"/> - + - + @@ -98,6 +98,7 @@ export default { return { loading: false, isQuiesceVm: false, + hypervisorSupportsQuiesceVm: false, supportsStorageSnapshot: false, listVolumes: [] } @@ -119,6 +120,9 @@ export default { }, fetchData () { this.loading = true + if (['KVM', 'VMware'].includes(this.resource.hypervisor)) { + this.hypervisorSupportsQuiesceVm = true + } api('listVolumes', { virtualMachineId: this.resource.id, listall: true }) .then(json => { @@ -141,7 +145,10 @@ export default { if (values.asyncbackup) { params.asyncbackup = values.asyncbackup } - params.quiescevm = values.quiescevm + params.quiescevm = false + if (values.quiescevm) { + params.quiescevm = values.quiescevm + } const title = this.$t('label.action.vmstoragesnapshot.create') const description = values.name || values.volumeid diff --git a/ui/src/views/storage/TakeSnapshot.vue b/ui/src/views/storage/TakeSnapshot.vue index ee0eafbb56a..e378664d7fb 100644 --- a/ui/src/views/storage/TakeSnapshot.vue +++ b/ui/src/views/storage/TakeSnapshot.vue @@ -66,10 +66,10 @@ - + - + @@ -152,6 +152,7 @@ export default { return { actionLoading: false, quiescevm: false, + hypervisorSupportsQuiesceVm: false, supportsStorageSnapshot: false, inputValue: '', inputKey: '', @@ -168,6 +169,10 @@ export default { created () { this.initForm() this.quiescevm = this.resource.quiescevm + if (['KVM', 'VMware'].includes(this.resource.hypervisor)) { + this.hypervisorSupportsQuiesceVm = true + } + this.supportsStorageSnapshot = this.resource.supportsstoragesnapshot this.fetchZoneData() },