From 907fb77c642a2f86857a21bd46381b53430afaa6 Mon Sep 17 00:00:00 2001 From: sjyu1 <93505580+sjyu1@users.noreply.github.com> Date: Fri, 13 Feb 2026 14:28:55 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=EC=99=B8=EB=B6=80=EC=9D=B8=EC=8A=A4?= =?UTF-8?q?=ED=84=B4=EC=8A=A4=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vm/UnmanagedVMsManagerImpl.java | 46 +++++++++++++++---- .../views/tools/ImportUnmanagedInstance.vue | 8 +++- 2 files changed, 44 insertions(+), 10 deletions(-) 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 b6cb759495a6..9cd3cd36a402 100644 --- a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java @@ -105,6 +105,7 @@ import com.cloud.storage.VolumeApiService; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.StoragePoolTagsDao; import com.cloud.storage.dao.GuestOSDao; import com.cloud.storage.dao.GuestOSHypervisorDao; import com.cloud.storage.dao.SnapshotDao; @@ -250,6 +251,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { @Inject private DiskOfferingDao diskOfferingDao; @Inject + private StoragePoolTagsDao storagePoolTagsDao; + @Inject private ResourceManager resourceManager; @Inject private ResourceLimitService resourceLimitService; @@ -2201,16 +2204,43 @@ private List findInstanceConversionDestinationStoragePoolsInClust Cluster destinationCluster, ServiceOfferingVO serviceOffering, Map dataDiskOfferingMap, DataStoreTO temporaryConvertLocation, boolean forceConvertToPool) { - List poolsList; + List poolsList = new ArrayList<>(); if (!forceConvertToPool) { - Set pools = new HashSet<>(primaryDataStoreDao.findClusterWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem)); - pools.addAll(primaryDataStoreDao.findZoneWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getDataCenterId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem)); - if (pools.isEmpty()) { - String msg = String.format("Cannot find suitable storage pools in the cluster %s for the conversion", destinationCluster.getName()); - logger.error(msg); - throw new CloudRuntimeException(msg); + // Try to find pools based on disk offering tags + Set candidatePoolIds = new HashSet<>(); + if (serviceOffering.getDiskOfferingId() != null) { + DiskOfferingVO diskOffering = diskOfferingDao.findById(serviceOffering.getDiskOfferingId()); + if (diskOffering != null && StringUtils.isNotBlank(diskOffering.getTags())) { + String tag = diskOffering.getTags(); + List ids = storagePoolTagsDao.listPoolIdsByTag(tag); + if (ids != null) { + candidatePoolIds.addAll(ids); + } + } + } + + if (!candidatePoolIds.isEmpty()) { + for (Long poolid : candidatePoolIds) { + StoragePoolVO pool = primaryDataStoreDao.findById(poolid); + if (pool == null) { + continue; + } + poolsList.add(pool); + } + } + logger.info("find poolsList : " + poolsList); + + // Fallback to previous behavior if no tagged pools found + if (poolsList.isEmpty()) { + Set pools = new HashSet<>(primaryDataStoreDao.listPoolsByCluster(destinationCluster.getId())); + pools.addAll(primaryDataStoreDao.findZoneWideStoragePoolsByHypervisor(destinationCluster.getDataCenterId(), Hypervisor.HypervisorType.KVM)); + if (pools.isEmpty()) { + String msg = String.format("Cannot find suitable storage pools in the cluster %s for the conversion", destinationCluster.getName()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + poolsList.addAll(pools); } - poolsList = new ArrayList<>(pools); } else { DataStore dataStore = dataStoreManager.getDataStore(temporaryConvertLocation.getUuid(), temporaryConvertLocation.getRole()); poolsList = Collections.singletonList(primaryDataStoreDao.findById(dataStore.getId())); diff --git a/ui/src/views/tools/ImportUnmanagedInstance.vue b/ui/src/views/tools/ImportUnmanagedInstance.vue index fcb92f30bcd1..fbc6a8bff605 100644 --- a/ui/src/views/tools/ImportUnmanagedInstance.vue +++ b/ui/src/views/tools/ImportUnmanagedInstance.vue @@ -801,11 +801,15 @@ export default { }, getMinCpu () { console.log('this.resource.cpunumber :>> ', this.resource.cpunumber) - console.log('this.computeOffering.serviceofferingdetails.mincpunumber :>> ', this.computeOffering.serviceofferingdetails.mincpunumber) + // console.log('this.computeOffering.serviceofferingdetails.mincpunumber :>> ', this.computeOffering.serviceofferingdetails.mincpunumber) if (this.isVmRunning) { return this.resource.cpunumber } - return 'serviceofferingdetails' in this.computeOffering ? this.computeOffering.serviceofferingdetails.mincpunumber * 1 : 1 + if (this.computeOffering && 'serviceofferingdetails' in this.computeOffering && + this.computeOffering.serviceofferingdetails && 'mincpunumber' in this.computeOffering.serviceofferingdetails) { + return this.computeOffering.serviceofferingdetails.mincpunumber * 1 + } + return this.resource.cpunumber || 1 }, getMinMemory () { if (this.isVmRunning) { From 959d5323e097cbd38303dcbb99b248effe130ced Mon Sep 17 00:00:00 2001 From: sjyu1 <93505580+sjyu1@users.noreply.github.com> Date: Fri, 13 Feb 2026 15:43:44 +0900 Subject: [PATCH 2/3] Update ImportUnmanagedInstance.vue --- ui/src/views/tools/ImportUnmanagedInstance.vue | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ui/src/views/tools/ImportUnmanagedInstance.vue b/ui/src/views/tools/ImportUnmanagedInstance.vue index fbc6a8bff605..fcb92f30bcd1 100644 --- a/ui/src/views/tools/ImportUnmanagedInstance.vue +++ b/ui/src/views/tools/ImportUnmanagedInstance.vue @@ -801,15 +801,11 @@ export default { }, getMinCpu () { console.log('this.resource.cpunumber :>> ', this.resource.cpunumber) - // console.log('this.computeOffering.serviceofferingdetails.mincpunumber :>> ', this.computeOffering.serviceofferingdetails.mincpunumber) + console.log('this.computeOffering.serviceofferingdetails.mincpunumber :>> ', this.computeOffering.serviceofferingdetails.mincpunumber) if (this.isVmRunning) { return this.resource.cpunumber } - if (this.computeOffering && 'serviceofferingdetails' in this.computeOffering && - this.computeOffering.serviceofferingdetails && 'mincpunumber' in this.computeOffering.serviceofferingdetails) { - return this.computeOffering.serviceofferingdetails.mincpunumber * 1 - } - return this.resource.cpunumber || 1 + return 'serviceofferingdetails' in this.computeOffering ? this.computeOffering.serviceofferingdetails.mincpunumber * 1 : 1 }, getMinMemory () { if (this.isVmRunning) { From 46d2fa57473debc30de0cb99445109fb2ce25e64 Mon Sep 17 00:00:00 2001 From: sjyu1 <93505580+sjyu1@users.noreply.github.com> Date: Wed, 25 Feb 2026 15:09:37 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=EA=B0=80=EC=83=81=EB=A8=B8=EC=8B=A0=20?= =?UTF-8?q?=EB=B3=B5=EC=A0=9C=20=EC=98=A4=EB=A5=98=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kvm/storage/KVMStorageProcessor.java | 15 +++++++++++++-- .../main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java index eff149d32f1f..44493a186816 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java @@ -2695,8 +2695,19 @@ public Answer createVolumeFromSnapshot(final CopyCommand cmd) { final String snapshotFullPath = snapshot.getPath(); final int index = snapshotFullPath.lastIndexOf("/"); - final String snapshotPath = snapshotFullPath.substring(0, index); - final String snapshotName = snapshotFullPath.substring(index + 1); + final String snapshotPath; + final String snapshotName; + if (index >= 0) { + snapshotPath = snapshotFullPath.substring(0, index); + snapshotName = snapshotFullPath.substring(index + 1); + } else { + if (pool.getPoolType() == StoragePoolType.SharedMountPoint) { + snapshotPath = pool.getPath(); + snapshotName = snapshotFullPath; + } else { + throw new CloudRuntimeException("Invalid snapshot path format: " + snapshotFullPath); + } + } KVMPhysicalDisk disk = null; if (imageStore instanceof NfsTO) { disk = createVolumeFromSnapshotOnNFS(cmd, pool, imageStore, volume, snapshotPath, snapshotName); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 2e86b8fb7c26..d96ac303d46a 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -10698,7 +10698,7 @@ public Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceAlloc throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create vm snapshot: " + e.getMessage(), e); } - List listSnapshots = vmSnapshotDetailsDao.findDetails(vmSnapshot.getId(), "kvmStorageSnapshot"); + List listSnapshots = vmSnapshotDetailsDao.findDetails(vmSnapshot.getId(), "kvmFileBasedStorageSnapshot"); Integer countOfCloneVM = cmd.getCount(); for (int cnt = 1; cnt <= countOfCloneVM; cnt++) {