From c147ff621b96e9775b88b120d59daefedc4d0bb6 Mon Sep 17 00:00:00 2001 From: Rakesh Venkatesh Date: Mon, 1 Mar 2021 14:43:19 +0100 Subject: [PATCH] Allow creating snapshot from VM snapshot If `kvm.snapshot.enabled` is set to false then we cant create snapshot from VM snapshot. With this change, its possible to create snapshot from VM snapshot even when the global setting is set to false. Note that you still cant directly create a snapshot from volume though --- .../storage/snapshot/SnapshotApiService.java | 4 ++++ .../com/cloud/storage/VolumeApiServiceImpl.java | 4 ++-- .../storage/snapshot/SnapshotManagerImpl.java | 15 ++++++++++----- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/com/cloud/storage/snapshot/SnapshotApiService.java b/api/src/main/java/com/cloud/storage/snapshot/SnapshotApiService.java index cb67ba75caa7..38e5e105a483 100644 --- a/api/src/main/java/com/cloud/storage/snapshot/SnapshotApiService.java +++ b/api/src/main/java/com/cloud/storage/snapshot/SnapshotApiService.java @@ -88,6 +88,10 @@ public interface SnapshotApiService { Snapshot allocSnapshot(Long volumeId, Long policyId, String snapshotName, Snapshot.LocationType locationType) throws ResourceAllocationException; + Snapshot allocSnapshot(Long volumeId, Long policyId, String snapshotName, Snapshot.LocationType locationType, Boolean isFromVmSnapshot) + throws ResourceAllocationException; + + /** * Create a snapshot of a volume * diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java index b573af7dba1b..a31304aa5ae9 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -3289,7 +3289,7 @@ public Snapshot allocSnapshot(Long volumeId, Long policyId, String snapshotName, throw new InvalidParameterValueException("VolumeId: " + volumeId + " please attach this volume to a VM before create snapshot for it"); } - return snapshotMgr.allocSnapshot(volumeId, policyId, snapshotName, locationType); + return snapshotMgr.allocSnapshot(volumeId, policyId, snapshotName, locationType, false); } @Override @@ -3345,7 +3345,7 @@ public Snapshot allocSnapshotForVm(Long vmId, Long volumeId, String snapshotName throw new InvalidParameterValueException("Cannot perform this operation, unsupported on storage pool type " + storagePool.getPoolType()); } - return snapshotMgr.allocSnapshot(volumeId, Snapshot.MANUAL_POLICY_ID, snapshotName, null); + return snapshotMgr.allocSnapshot(volumeId, Snapshot.MANUAL_POLICY_ID, snapshotName, null, true); } @Override diff --git a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 049754a04d83..112cf3799b54 100755 --- a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -1124,7 +1124,7 @@ private Type getSnapshotType(IntervalType intvType) { return null; } - private boolean hostSupportSnapsthotForVolume(HostVO host, VolumeInfo volume) { + private boolean hostSupportsSnapsthotForVolume(HostVO host, VolumeInfo volume, boolean isFromVmSnapshot) { if (host.getHypervisorType() != HypervisorType.KVM) { return true; } @@ -1136,7 +1136,7 @@ private boolean hostSupportSnapsthotForVolume(HostVO host, VolumeInfo volume) { VMInstanceVO vm = _vmDao.findById(vmId); if (vm.getState() != VirtualMachine.State.Stopped && vm.getState() != VirtualMachine.State.Destroyed) { boolean snapshotEnabled = Boolean.parseBoolean(_configDao.getValue("kvm.snapshot.enabled")); - if (!snapshotEnabled) { + if (!snapshotEnabled && !isFromVmSnapshot) { s_logger.debug("Snapshot is not supported on host " + host + " for the volume " + volume + " attached to the vm " + vm); return false; } @@ -1157,7 +1157,7 @@ private boolean hostSupportSnapsthotForVolume(HostVO host, VolumeInfo volume) { return false; } - private boolean supportedByHypervisor(VolumeInfo volume) { + private boolean supportedByHypervisor(VolumeInfo volume, boolean isFromVmSnapshot) { HypervisorType hypervisorType; StoragePoolVO storagePool = _storagePoolDao.findById(volume.getDataStore().getId()); ScopeType scope = storagePool.getScope(); @@ -1181,7 +1181,7 @@ private boolean supportedByHypervisor(VolumeInfo volume) { } if (hosts != null && !hosts.isEmpty()) { HostVO host = hosts.get(0); - if (!hostSupportSnapsthotForVolume(host, volume)) { + if (!hostSupportsSnapsthotForVolume(host, volume, isFromVmSnapshot)) { throw new CloudRuntimeException( "KVM Snapshot is not supported for Running VMs. It is disabled by default due to a possible volume corruption in certain cases. To enable it set global settings kvm.snapshot.enabled to True. See the documentation for more details."); } @@ -1489,9 +1489,14 @@ public void cleanupSnapshotsByVolume(Long volumeId) { @Override public Snapshot allocSnapshot(Long volumeId, Long policyId, String snapshotName, Snapshot.LocationType locationType) throws ResourceAllocationException { + return allocSnapshot(volumeId, policyId, snapshotName, locationType, false); + } + + @Override + public Snapshot allocSnapshot(Long volumeId, Long policyId, String snapshotName, Snapshot.LocationType locationType, Boolean isFromVmSnapshot) throws ResourceAllocationException { Account caller = CallContext.current().getCallingAccount(); VolumeInfo volume = volFactory.getVolume(volumeId); - supportedByHypervisor(volume); + supportedByHypervisor(volume, isFromVmSnapshot); // Verify permissions _accountMgr.checkAccess(caller, null, true, volume);