This is an automated email from the ASF dual-hosted git repository. dahn pushed a commit to branch 4.19 in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.19 by this push: new d8c321d57ae check tags while fetching storage pool for importing vm (#9764) d8c321d57ae is described below commit d8c321d57aec526241939dae8553301140142c73 Author: Vishesh <vishes...@gmail.com> AuthorDate: Fri Jan 3 13:35:54 2025 +0530 check tags while fetching storage pool for importing vm (#9764) --- .../cloudstack/vm/UnmanagedVMsManagerImpl.java | 134 ++++++++++++++++----- .../cloudstack/vm/UnmanagedVMsManagerImplTest.java | 4 + 2 files changed, 105 insertions(+), 33 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 67139120fa0..187afece84f 100644 --- a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java @@ -536,7 +536,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { return nicIpAddresses; } - private StoragePool getStoragePool(final UnmanagedInstanceTO.Disk disk, final DataCenter zone, final Cluster cluster) { + private StoragePool getStoragePool(final UnmanagedInstanceTO.Disk disk, final DataCenter zone, final Cluster cluster, String diskOfferingTags) { StoragePool storagePool = null; final String dsHost = disk.getDatastoreHost(); final String dsPath = disk.getDatastorePath(); @@ -546,7 +546,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { List<StoragePoolVO> pools = primaryDataStoreDao.listPoolByHostPath(dsHost, dsPath); for (StoragePool pool : pools) { if (pool.getDataCenterId() == zone.getId() && - (pool.getClusterId() == null || pool.getClusterId().equals(cluster.getId()))) { + (pool.getClusterId() == null || pool.getClusterId().equals(cluster.getId())) && + volumeApiService.doesTargetStorageSupportDiskOffering(pool, diskOfferingTags)) { storagePool = pool; break; } @@ -558,7 +559,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { pools.addAll(primaryDataStoreDao.listByDataCenterId(zone.getId())); for (StoragePool pool : pools) { String searchPoolParam = StringUtils.isNotBlank(dsPath) ? dsPath : dsName; - if (StringUtils.contains(pool.getPath(), searchPoolParam)) { + if (StringUtils.contains(pool.getPath(), searchPoolParam) && + volumeApiService.doesTargetStorageSupportDiskOffering(pool, diskOfferingTags)) { storagePool = pool; break; } @@ -621,7 +623,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { if (diskOffering != null && !diskOffering.isCustomized() && diskOffering.getDiskSize() < disk.getCapacity()) { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Size of disk offering(ID: %s) %dGB is found less than the size of disk(ID: %s) %dGB during VM import", diskOffering.getUuid(), (diskOffering.getDiskSize() / Resource.ResourceType.bytesToGiB), disk.getDiskId(), (disk.getCapacity() / (Resource.ResourceType.bytesToGiB)))); } - StoragePool storagePool = getStoragePool(disk, zone, cluster); + diskOffering = diskOffering != null ? diskOffering : diskOfferingDao.findById(serviceOffering.getDiskOfferingId()); + StoragePool storagePool = getStoragePool(disk, zone, cluster, diskOffering != null ? diskOffering.getTags() : null); if (diskOffering != null && !migrateAllowed && !storagePoolSupportsDiskOffering(storagePool, diskOffering)) { throw new InvalidParameterValueException(String.format("Disk offering: %s is not compatible with storage pool: %s of unmanaged disk: %s", diskOffering.getUuid(), storagePool.getUuid(), disk.getDiskId())); } @@ -858,7 +861,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { diskInfo.setDiskChain(new String[]{disk.getImagePath()}); chainInfo = gson.toJson(diskInfo); } - StoragePool storagePool = getStoragePool(disk, zone, cluster); + StoragePool storagePool = getStoragePool(disk, zone, cluster, diskOffering != null ? diskOffering.getTags() : null); DiskProfile profile = volumeManager.importVolume(type, name, diskOffering, diskSize, minIops, maxIops, vm.getDataCenterId(), vm.getHypervisorType(), vm, template, owner, deviceId, storagePool.getId(), path, chainInfo); @@ -1612,7 +1615,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { temporaryConvertLocation = selectInstanceConversionTemporaryLocation( destinationCluster, convertHost, convertStoragePoolId); - List<StoragePoolVO> convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster); + List<StoragePoolVO> convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster, serviceOffering, dataDiskOfferingMap); long importStartTime = System.currentTimeMillis(); Pair<UnmanagedInstanceTO, Boolean> sourceInstanceDetails = getSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password, clusterName, sourceHostName, sourceVMName); sourceVMwareInstance = sourceInstanceDetails.first(); @@ -1628,15 +1631,18 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { if (cmd.getForceMsToImportVmFiles() || !conversionSupportAnswer.isOvfExportSupported()) { // Uses MS for OVF export to temporary conversion location int noOfThreads = UnmanagedVMsManager.ThreadsOnMSToImportVMwareVMFiles.value(); - ovfTemplateOnConvertLocation = createOvfTemplateOfSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password, - clusterName, sourceHostName, sourceVMwareInstance.getName(), temporaryConvertLocation, noOfThreads); + ovfTemplateOnConvertLocation = createOvfTemplateOfSourceVmwareUnmanagedInstance( + vcenter, datacenterName, username, password, clusterName, sourceHostName, + sourceVMwareInstance.getName(), temporaryConvertLocation, noOfThreads); convertedInstance = convertVmwareInstanceToKVMWithOVFOnConvertLocation(sourceVMName, - sourceVMwareInstance, convertHost, importHost, convertStoragePools, - temporaryConvertLocation, ovfTemplateOnConvertLocation); + sourceVMwareInstance, convertHost, importHost, convertStoragePools, + serviceOffering, dataDiskOfferingMap, temporaryConvertLocation, + ovfTemplateOnConvertLocation); } else { // Uses KVM Host for OVF export to temporary conversion location, through ovftool convertedInstance = convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation( - sourceVMName, sourceVMwareInstance, convertHost, importHost, convertStoragePools, + sourceVMName, sourceVMwareInstance, convertHost, importHost, + convertStoragePools, serviceOffering, dataDiskOfferingMap, temporaryConvertLocation, vcenter, username, password, datacenterName); } @@ -1726,9 +1732,9 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { convertedInstance.setPowerState(UnmanagedInstanceTO.PowerState.PowerOff); List<UnmanagedInstanceTO.Disk> convertedInstanceDisks = convertedInstance.getDisks(); List<UnmanagedInstanceTO.Disk> sourceVMwareInstanceDisks = sourceVMwareInstance.getDisks(); - for (int i = 0; i < convertedInstanceDisks.size(); i++) { - UnmanagedInstanceTO.Disk disk = convertedInstanceDisks.get(i); - disk.setDiskId(sourceVMwareInstanceDisks.get(i).getDiskId()); + for (UnmanagedInstanceTO.Disk sourceVMwareInstanceDisk : sourceVMwareInstanceDisks) { + UnmanagedInstanceTO.Disk convertedDisk = convertedInstanceDisks.get(sourceVMwareInstanceDisk.getPosition()); + convertedDisk.setDiskId(sourceVMwareInstanceDisk.getDiskId()); } List<UnmanagedInstanceTO.Nic> convertedInstanceNics = convertedInstance.getNics(); List<UnmanagedInstanceTO.Nic> sourceVMwareInstanceNics = sourceVMwareInstance.getNics(); @@ -1912,16 +1918,16 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { } private UnmanagedInstanceTO convertVmwareInstanceToKVMWithOVFOnConvertLocation( - String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, - HostVO convertHost, HostVO importHost, - List<StoragePoolVO> convertStoragePools, DataStoreTO temporaryConvertLocation, - String ovfTemplateDirConvertLocation + String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost, + HostVO importHost, List<StoragePoolVO> convertStoragePools, + ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap, + DataStoreTO temporaryConvertLocation, String ovfTemplateDirConvertLocation ) { LOGGER.debug(String.format("Delegating the conversion of instance %s from VMware to KVM to the host %s (%s) using OVF %s on conversion datastore", sourceVM, convertHost.getId(), convertHost.getName(), ovfTemplateDirConvertLocation)); RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(sourceVM); - List<String> destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks()); + List<String> destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks(), serviceOffering, dataDiskOfferingMap); ConvertInstanceCommand cmd = new ConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM, temporaryConvertLocation, ovfTemplateDirConvertLocation, false, false); int timeoutSeconds = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60; @@ -1932,16 +1938,17 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { } private UnmanagedInstanceTO convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation( - String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, - HostVO convertHost, HostVO importHost, List<StoragePoolVO> convertStoragePools, - DataStoreTO temporaryConvertLocation, String vcenterHost, - String vcenterUsername, String vcenterPassword, String datacenterName + String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost, + HostVO importHost, List<StoragePoolVO> convertStoragePools, + ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap, + DataStoreTO temporaryConvertLocation, String vcenterHost, String vcenterUsername, + String vcenterPassword, String datacenterName ) { LOGGER.debug(String.format("Delegating the conversion of instance %s from VMware to KVM to the host %s (%s) after OVF export through ovftool", sourceVM, convertHost.getId(), convertHost.getName())); RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(sourceVMwareInstance.getName(), vcenterHost, vcenterUsername, vcenterPassword, datacenterName); - List<String> destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks()); + List<String> destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks(), serviceOffering, dataDiskOfferingMap); ConvertInstanceCommand cmd = new ConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM, temporaryConvertLocation, null, false, true); int timeoutSeconds = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60; @@ -2004,12 +2011,31 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { return ((ImportConvertedInstanceAnswer) importAnswer).getConvertedInstance(); } - private List<StoragePoolVO> findInstanceConversionStoragePoolsInCluster(Cluster destinationCluster) { + private List<StoragePoolVO> findInstanceConversionStoragePoolsInCluster( + Cluster destinationCluster, ServiceOfferingVO serviceOffering, + Map<String, Long> dataDiskOfferingMap + ) { List<StoragePoolVO> pools = new ArrayList<>(); - List<StoragePoolVO> clusterPools = primaryDataStoreDao.findClusterWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem); - pools.addAll(clusterPools); - List<StoragePoolVO> zonePools = primaryDataStoreDao.findZoneWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getDataCenterId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem); - pools.addAll(zonePools); + pools.addAll(primaryDataStoreDao.findClusterWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem)); + pools.addAll(primaryDataStoreDao.findZoneWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getDataCenterId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem)); + List<String> diskOfferingTags = new ArrayList<>(); + for (Long diskOfferingId : dataDiskOfferingMap.values()) { + DiskOfferingVO diskOffering = diskOfferingDao.findById(diskOfferingId); + if (diskOffering == null) { + String msg = String.format("Cannot find disk offering with ID %s", diskOfferingId); + LOGGER.error(msg); + throw new CloudRuntimeException(msg); + } + diskOfferingTags.add(diskOffering.getTags()); + } + if (serviceOffering.getDiskOfferingId() != null) { + DiskOfferingVO diskOffering = diskOfferingDao.findById(serviceOffering.getDiskOfferingId()); + if (diskOffering != null) { + diskOfferingTags.add(diskOffering.getTags()); + } + } + + pools = getPoolsWithMatchingTags(pools, diskOfferingTags); if (pools.isEmpty()) { String msg = String.format("Cannot find suitable storage pools in cluster %s for the conversion", destinationCluster.getName()); LOGGER.error(msg); @@ -2018,12 +2044,54 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { return pools; } - private List<String> selectInstanceConversionStoragePools(List<StoragePoolVO> pools, List<UnmanagedInstanceTO.Disk> disks) { + private List<StoragePoolVO> getPoolsWithMatchingTags(List<StoragePoolVO> pools, List<String> diskOfferingTags) { + if (diskOfferingTags.isEmpty()) { + return pools; + } + List<StoragePoolVO> poolsSupportingTags = new ArrayList<>(pools); + for (String tags : diskOfferingTags) { + boolean tagsMatched = false; + for (StoragePoolVO pool : pools) { + if (volumeApiService.doesTargetStorageSupportDiskOffering(pool, tags)) { + poolsSupportingTags.add(pool); + tagsMatched = true; + } + } + if (!tagsMatched) { + String msg = String.format("Cannot find suitable storage pools for the conversion with disk offering tags %s", tags); + LOGGER.error(msg); + throw new CloudRuntimeException(msg); + } + } + return poolsSupportingTags; + } + + private List<String> selectInstanceConversionStoragePools( + List<StoragePoolVO> pools, List<UnmanagedInstanceTO.Disk> disks, + ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap + ) { List<String> storagePools = new ArrayList<>(disks.size()); - //TODO: Choose pools by capacity + for (int i = 0; i < disks.size(); i++) { + storagePools.add(null); + } + Set<String> dataDiskIds = dataDiskOfferingMap.keySet(); for (UnmanagedInstanceTO.Disk disk : disks) { - Long capacity = disk.getCapacity(); - storagePools.add(pools.get(0).getUuid()); + Long diskOfferingId = dataDiskOfferingMap.get(disk.getDiskId()); + if (diskOfferingId == null && !dataDiskIds.contains(disk.getDiskId())) { + diskOfferingId = serviceOffering.getDiskOfferingId(); + } + //TODO: Choose pools by capacity + if (diskOfferingId == null) { + storagePools.set(disk.getPosition(), pools.get(0).getUuid()); + } else { + DiskOfferingVO diskOffering = diskOfferingDao.findById(diskOfferingId); + for (StoragePoolVO pool : pools) { + if (volumeApiService.doesTargetStorageSupportDiskOffering(pool, diskOffering.getTags())) { + storagePools.set(disk.getPosition(), pool.getUuid()); + break; + } + } + } } return storagePools; } diff --git a/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java b/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java index e9a58760828..85402c0e254 100644 --- a/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java +++ b/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java @@ -277,6 +277,7 @@ public class UnmanagedVMsManagerImplTest { List<UnmanagedInstanceTO.Disk> instanceDisks = new ArrayList<>(); UnmanagedInstanceTO.Disk instanceDisk = new UnmanagedInstanceTO.Disk(); instanceDisk.setDiskId("1000-1"); + instanceDisk.setPosition(0); instanceDisk.setLabel("DiskLabel"); instanceDisk.setController("scsi"); instanceDisk.setImagePath("[b6ccf44a1fa13e29b3667b4954fa10ee] TestInstance/ROOT-1.vmdk"); @@ -423,6 +424,7 @@ public class UnmanagedVMsManagerImplTest { ImportUnmanagedInstanceCmd importUnmanageInstanceCmd = Mockito.mock(ImportUnmanagedInstanceCmd.class); when(importUnmanageInstanceCmd.getName()).thenReturn("TestInstance"); when(importUnmanageInstanceCmd.getDomainId()).thenReturn(null); + when(volumeApiService.doesTargetStorageSupportDiskOffering(any(StoragePool.class), any())).thenReturn(true); try (MockedStatic<UsageEventUtils> ignored = Mockito.mockStatic(UsageEventUtils.class)) { unmanagedVMsManager.importUnmanagedInstance(importUnmanageInstanceCmd); } @@ -702,6 +704,8 @@ public class UnmanagedVMsManagerImplTest { when(agentManager.send(Mockito.eq(convertHostId), Mockito.any(CheckConvertInstanceCommand.class))).thenReturn(checkConvertInstanceAnswer); } + when(volumeApiService.doesTargetStorageSupportDiskOffering(any(StoragePool.class), any())).thenReturn(true); + ConvertInstanceAnswer convertInstanceAnswer = mock(ConvertInstanceAnswer.class); ImportConvertedInstanceAnswer convertImportedInstanceAnswer = mock(ImportConvertedInstanceAnswer.class); when(convertInstanceAnswer.getResult()).thenReturn(vcenterParameter != VcenterParameter.CONVERT_FAILURE);