From e93ae1a4f455a0dff010db673b47b913220f9037 Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Tue, 17 Mar 2026 20:04:34 +0530 Subject: [PATCH] New config key "allow.import.volume.with.backing.file" to skip volume backing (#12809) * Added support for skipping volume backing when importing unmanaged volumes and VMs. This allows users to import volumes and VMs without creating a backing volume, which can be useful in certain scenarios where the backing volume is not needed or desired. * cleanup conflicting key * move configkey into VolumeImportUnmanageService --------- Co-authored-by: rajujith --- .../volume/VolumeImportUnmanageService.java | 13 ++++++++++++- .../volume/VolumeImportUnmanageManagerImpl.java | 15 ++++++++++++++- .../cloudstack/vm/UnmanagedVMsManagerImpl.java | 3 ++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/storage/volume/VolumeImportUnmanageService.java b/api/src/main/java/org/apache/cloudstack/storage/volume/VolumeImportUnmanageService.java index 5f69f3e46e7..78c598272e0 100644 --- a/api/src/main/java/org/apache/cloudstack/storage/volume/VolumeImportUnmanageService.java +++ b/api/src/main/java/org/apache/cloudstack/storage/volume/VolumeImportUnmanageService.java @@ -25,11 +25,13 @@ import org.apache.cloudstack.api.command.admin.volume.ImportVolumeCmd; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.VolumeForImportResponse; import org.apache.cloudstack.api.response.VolumeResponse; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; import java.util.Arrays; import java.util.List; -public interface VolumeImportUnmanageService extends PluggableService { +public interface VolumeImportUnmanageService extends PluggableService, Configurable { List SUPPORTED_HYPERVISORS = Arrays.asList(Hypervisor.HypervisorType.KVM, Hypervisor.HypervisorType.VMware); @@ -37,6 +39,15 @@ public interface VolumeImportUnmanageService extends PluggableService { List SUPPORTED_STORAGE_POOL_TYPES_FOR_KVM = Arrays.asList(Storage.StoragePoolType.NetworkFilesystem, Storage.StoragePoolType.Filesystem, Storage.StoragePoolType.RBD); + ConfigKey AllowImportVolumeWithBackingFile = new ConfigKey<>(Boolean.class, + "allow.import.volume.with.backing.file", + "Advanced", + "false", + "If enabled, allows QCOW2 volumes with backing files to be imported or unmanaged", + true, + ConfigKey.Scope.Global, + null); + ListResponse listVolumesForImport(ListVolumesForImportCmd cmd); VolumeResponse importVolume(ImportVolumeCmd cmd); diff --git a/server/src/main/java/org/apache/cloudstack/storage/volume/VolumeImportUnmanageManagerImpl.java b/server/src/main/java/org/apache/cloudstack/storage/volume/VolumeImportUnmanageManagerImpl.java index 383644f9aa2..62b5ac38ee2 100644 --- a/server/src/main/java/org/apache/cloudstack/storage/volume/VolumeImportUnmanageManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/storage/volume/VolumeImportUnmanageManagerImpl.java @@ -68,6 +68,7 @@ import org.apache.cloudstack.api.response.VolumeForImportResponse; import org.apache.cloudstack.api.response.VolumeResponse; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; +import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; @@ -394,7 +395,7 @@ public class VolumeImportUnmanageManagerImpl implements VolumeImportUnmanageServ Map volumeDetails = volume.getDetails(); if (volumeDetails != null && volumeDetails.containsKey(VolumeOnStorageTO.Detail.BACKING_FILE)) { String backingFile = volumeDetails.get(VolumeOnStorageTO.Detail.BACKING_FILE); - if (StringUtils.isNotBlank(backingFile)) { + if (StringUtils.isNotBlank(backingFile) && !AllowImportVolumeWithBackingFile.value()) { logFailureAndThrowException("Volume with backing file cannot be imported or unmanaged."); } } @@ -513,4 +514,16 @@ public class VolumeImportUnmanageManagerImpl implements VolumeImportUnmanageServ volume.setRemoved(new Date()); volumeDao.update(volume.getId(), volume); } + + @Override + public String getConfigComponentName() { + return VolumeImportUnmanageManagerImpl.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[]{ + AllowImportVolumeWithBackingFile + }; + } } diff --git a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java index 13fa2608016..8bc710d113f 100644 --- a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java @@ -195,6 +195,7 @@ import java.util.stream.Collectors; import static org.apache.cloudstack.api.ApiConstants.MAX_IOPS; import static org.apache.cloudstack.api.ApiConstants.MIN_IOPS; +import static org.apache.cloudstack.storage.volume.VolumeImportUnmanageService.AllowImportVolumeWithBackingFile; import static org.apache.cloudstack.vm.ImportVmTask.Step.CloningInstance; import static org.apache.cloudstack.vm.ImportVmTask.Step.Completed; import static org.apache.cloudstack.vm.ImportVmTask.Step.ConvertingInstance; @@ -2908,7 +2909,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { } if (volumeDetails.containsKey(VolumeOnStorageTO.Detail.BACKING_FILE)) { String backingFile = volumeDetails.get(VolumeOnStorageTO.Detail.BACKING_FILE); - if (StringUtils.isNotBlank(backingFile)) { + if (StringUtils.isNotBlank(backingFile) && !AllowImportVolumeWithBackingFile.value()) { logFailureAndThrowException("Volume with backing file cannot be imported or unmanaged."); } }