From 6556c98594947edb862a3109ece1ce99a4d6f51b Mon Sep 17 00:00:00 2001 From: Vishesh Date: Thu, 3 Oct 2024 19:11:05 +0530 Subject: [PATCH 1/4] check tags while fetching storage pool for importing vm --- .../cloudstack/vm/UnmanagedVMsManagerImpl.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 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 67139120fa08..d83ed6ca835e 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 @@ private Map getNicIpAddresses(final List 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 @@ private StoragePool getStoragePool(final UnmanagedInstanceTO.Disk disk, final Da 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,7 @@ private void checkUnmanagedDiskAndOfferingForImport(String instanceName, Unmanag 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); + 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 +860,7 @@ private Pair importDisk(UnmanagedInstanceTO.Disk disk, 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); From 1779a33b123c1a26b6632924d74ae1d2249cbba0 Mon Sep 17 00:00:00 2001 From: Vishesh Date: Fri, 4 Oct 2024 01:29:35 +0530 Subject: [PATCH 2/4] Fix unit tests --- .../org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java | 3 +++ 1 file changed, 3 insertions(+) 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 e9a587608286..f9d6e0d8c2a5 100644 --- a/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java +++ b/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java @@ -423,6 +423,7 @@ public void importUnmanagedInstanceTest() { 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 ignored = Mockito.mockStatic(UsageEventUtils.class)) { unmanagedVMsManager.importUnmanagedInstance(importUnmanageInstanceCmd); } @@ -780,11 +781,13 @@ public void testImportVmFromVmwareToKvmExistingVcenter() throws OperationTimedou @Test public void testImportVmFromVmwareToKvmExistingVcenterSetConvertHost() throws OperationTimedoutException, AgentUnavailableException { + when(volumeApiService.doesTargetStorageSupportDiskOffering(any(StoragePool.class), any())).thenReturn(true); baseTestImportVmFromVmwareToKvm(VcenterParameter.EXISTING, true, false); } @Test public void testImportVmFromVmwareToKvmExistingVcenterSetConvertHostAndTemporaryStorage() throws OperationTimedoutException, AgentUnavailableException { + when(volumeApiService.doesTargetStorageSupportDiskOffering(any(StoragePool.class), any())).thenReturn(true); baseTestImportVmFromVmwareToKvm(VcenterParameter.EXISTING, true, true); } From 8e473f3bfa427f057fd2d2aebddb3e9533f8eef2 Mon Sep 17 00:00:00 2001 From: Vishesh Date: Tue, 24 Dec 2024 17:18:11 +0530 Subject: [PATCH 3/4] Check disk offering tags before importing --- .../vm/UnmanagedVMsManagerImpl.java | 75 +++++++++++++++---- .../vm/UnmanagedVMsManagerImplTest.java | 4 +- 2 files changed, 62 insertions(+), 17 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 d83ed6ca835e..afe49c74e6d8 100644 --- a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java @@ -1614,7 +1614,7 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster temporaryConvertLocation = selectInstanceConversionTemporaryLocation( destinationCluster, convertHost, convertStoragePoolId); - List convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster); + List convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster, dataDiskOfferingMap); long importStartTime = System.currentTimeMillis(); Pair sourceInstanceDetails = getSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password, clusterName, sourceHostName, sourceVMName); sourceVMwareInstance = sourceInstanceDetails.first(); @@ -1633,13 +1633,14 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster 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, + dataDiskOfferingMap, temporaryConvertLocation, ovfTemplateOnConvertLocation); } else { // Uses KVM Host for OVF export to temporary conversion location, through ovftool convertedInstance = convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation( - sourceVMName, sourceVMwareInstance, convertHost, importHost, convertStoragePools, - temporaryConvertLocation, vcenter, username, password, datacenterName); + sourceVMName, sourceVMwareInstance, convertHost, importHost, + convertStoragePools, dataDiskOfferingMap, temporaryConvertLocation, vcenter, + username, password, datacenterName); } sanitizeConvertedInstance(convertedInstance, sourceVMwareInstance); @@ -1916,14 +1917,14 @@ private CheckConvertInstanceAnswer checkConversionSupportOnHost(HostVO convertHo private UnmanagedInstanceTO convertVmwareInstanceToKVMWithOVFOnConvertLocation( String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost, HostVO importHost, - List convertStoragePools, DataStoreTO temporaryConvertLocation, + List convertStoragePools, Map 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 destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks()); + List destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks(), dataDiskOfferingMap); ConvertInstanceCommand cmd = new ConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM, temporaryConvertLocation, ovfTemplateDirConvertLocation, false, false); int timeoutSeconds = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60; @@ -1936,14 +1937,14 @@ private UnmanagedInstanceTO convertVmwareInstanceToKVMWithOVFOnConvertLocation( private UnmanagedInstanceTO convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation( String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost, HostVO importHost, List convertStoragePools, - DataStoreTO temporaryConvertLocation, String vcenterHost, + Map 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 destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks()); + List destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks(), dataDiskOfferingMap); ConvertInstanceCommand cmd = new ConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM, temporaryConvertLocation, null, false, true); int timeoutSeconds = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60; @@ -2006,12 +2007,46 @@ private UnmanagedInstanceTO convertAndImportToKVM(ConvertInstanceCommand convert return ((ImportConvertedInstanceAnswer) importAnswer).getConvertedInstance(); } - private List findInstanceConversionStoragePoolsInCluster(Cluster destinationCluster) { + private List findInstanceConversionStoragePoolsInCluster(Cluster destinationCluster, Map dataDiskOfferingMap) { List pools = new ArrayList<>(); List clusterPools = primaryDataStoreDao.findClusterWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem); - pools.addAll(clusterPools); List zonePools = primaryDataStoreDao.findZoneWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getDataCenterId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem); - pools.addAll(zonePools); + List 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 (dataDiskOfferingMap.isEmpty()) { + pools.addAll(clusterPools); + pools.addAll(zonePools); + } else { + for (String tags : diskOfferingTags) { + boolean tagsMatched = false; + for (StoragePoolVO pool : clusterPools) { + if (volumeApiService.doesTargetStorageSupportDiskOffering(pool, tags)) { + pools.add(pool); + tagsMatched = true; + } + } + for (StoragePoolVO pool : zonePools) { + if (volumeApiService.doesTargetStorageSupportDiskOffering(pool, tags)) { + pools.add(pool); + tagsMatched = true; + } + } + if (!tagsMatched) { + String msg = String.format("Cannot find suitable storage pools in cluster %s for the conversion with disk offering tags %s", + destinationCluster, tags); + LOGGER.error(msg); + throw new CloudRuntimeException(msg); + } + } + } if (pools.isEmpty()) { String msg = String.format("Cannot find suitable storage pools in cluster %s for the conversion", destinationCluster.getName()); LOGGER.error(msg); @@ -2020,12 +2055,22 @@ private List findInstanceConversionStoragePoolsInCluster(Cluster return pools; } - private List selectInstanceConversionStoragePools(List pools, List disks) { + private List selectInstanceConversionStoragePools(List pools, List disks, Map dataDiskOfferingMap) { List storagePools = new ArrayList<>(disks.size()); //TODO: Choose pools by capacity for (UnmanagedInstanceTO.Disk disk : disks) { - Long capacity = disk.getCapacity(); - storagePools.add(pools.get(0).getUuid()); + Long diskOfferingId = dataDiskOfferingMap.get(disk.getDiskId()); + if (diskOfferingId == null) { + storagePools.add(pools.get(0).getUuid()); + } else { + DiskOfferingVO diskOffering = diskOfferingDao.findById(diskOfferingId); + for (StoragePoolVO pool : pools) { + if (volumeApiService.doesTargetStorageSupportDiskOffering(pool, diskOffering.getTags())) { + storagePools.add(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 f9d6e0d8c2a5..b502c42fd065 100644 --- a/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java +++ b/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java @@ -703,6 +703,8 @@ private void baseTestImportVmFromVmwareToKvm(VcenterParameter vcenterParameter, 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); @@ -781,13 +783,11 @@ public void testImportVmFromVmwareToKvmExistingVcenter() throws OperationTimedou @Test public void testImportVmFromVmwareToKvmExistingVcenterSetConvertHost() throws OperationTimedoutException, AgentUnavailableException { - when(volumeApiService.doesTargetStorageSupportDiskOffering(any(StoragePool.class), any())).thenReturn(true); baseTestImportVmFromVmwareToKvm(VcenterParameter.EXISTING, true, false); } @Test public void testImportVmFromVmwareToKvmExistingVcenterSetConvertHostAndTemporaryStorage() throws OperationTimedoutException, AgentUnavailableException { - when(volumeApiService.doesTargetStorageSupportDiskOffering(any(StoragePool.class), any())).thenReturn(true); baseTestImportVmFromVmwareToKvm(VcenterParameter.EXISTING, true, true); } From 5e3c0f5da3982cdcf28422011c90f005b83be1f9 Mon Sep 17 00:00:00 2001 From: Vishesh Date: Tue, 31 Dec 2024 11:26:42 +0530 Subject: [PATCH 4/4] add checks for storage tags and fix ordering of destination storage pools --- .../vm/UnmanagedVMsManagerImpl.java | 121 ++++++++++-------- .../vm/UnmanagedVMsManagerImplTest.java | 1 + 2 files changed, 72 insertions(+), 50 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 afe49c74e6d8..187afece84fc 100644 --- a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java @@ -623,6 +623,7 @@ private void checkUnmanagedDiskAndOfferingForImport(String instanceName, Unmanag 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)))); } + 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())); @@ -1614,7 +1615,7 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster temporaryConvertLocation = selectInstanceConversionTemporaryLocation( destinationCluster, convertHost, convertStoragePoolId); - List convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster, dataDiskOfferingMap); + List convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster, serviceOffering, dataDiskOfferingMap); long importStartTime = System.currentTimeMillis(); Pair sourceInstanceDetails = getSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password, clusterName, sourceHostName, sourceVMName); sourceVMwareInstance = sourceInstanceDetails.first(); @@ -1630,17 +1631,19 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster 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, - dataDiskOfferingMap, temporaryConvertLocation, ovfTemplateOnConvertLocation); + serviceOffering, dataDiskOfferingMap, temporaryConvertLocation, + ovfTemplateOnConvertLocation); } else { // Uses KVM Host for OVF export to temporary conversion location, through ovftool convertedInstance = convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation( sourceVMName, sourceVMwareInstance, convertHost, importHost, - convertStoragePools, dataDiskOfferingMap, temporaryConvertLocation, vcenter, - username, password, datacenterName); + convertStoragePools, serviceOffering, dataDiskOfferingMap, + temporaryConvertLocation, vcenter, username, password, datacenterName); } sanitizeConvertedInstance(convertedInstance, sourceVMwareInstance); @@ -1729,9 +1732,9 @@ private void sanitizeConvertedInstance(UnmanagedInstanceTO convertedInstance, Un convertedInstance.setPowerState(UnmanagedInstanceTO.PowerState.PowerOff); List convertedInstanceDisks = convertedInstance.getDisks(); List 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 convertedInstanceNics = convertedInstance.getNics(); List sourceVMwareInstanceNics = sourceVMwareInstance.getNics(); @@ -1915,16 +1918,16 @@ private CheckConvertInstanceAnswer checkConversionSupportOnHost(HostVO convertHo } private UnmanagedInstanceTO convertVmwareInstanceToKVMWithOVFOnConvertLocation( - String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, - HostVO convertHost, HostVO importHost, - List convertStoragePools, Map dataDiskOfferingMap, DataStoreTO temporaryConvertLocation, - String ovfTemplateDirConvertLocation + String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost, + HostVO importHost, List convertStoragePools, + ServiceOfferingVO serviceOffering, Map 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 destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks(), dataDiskOfferingMap); + List 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; @@ -1935,16 +1938,17 @@ private UnmanagedInstanceTO convertVmwareInstanceToKVMWithOVFOnConvertLocation( } private UnmanagedInstanceTO convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation( - String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, - HostVO convertHost, HostVO importHost, List convertStoragePools, - Map dataDiskOfferingMap, DataStoreTO temporaryConvertLocation, String vcenterHost, - String vcenterUsername, String vcenterPassword, String datacenterName + String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost, + HostVO importHost, List convertStoragePools, + ServiceOfferingVO serviceOffering, Map 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 destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks(), dataDiskOfferingMap); + List 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; @@ -2007,10 +2011,13 @@ private UnmanagedInstanceTO convertAndImportToKVM(ConvertInstanceCommand convert return ((ImportConvertedInstanceAnswer) importAnswer).getConvertedInstance(); } - private List findInstanceConversionStoragePoolsInCluster(Cluster destinationCluster, Map dataDiskOfferingMap) { + private List findInstanceConversionStoragePoolsInCluster( + Cluster destinationCluster, ServiceOfferingVO serviceOffering, + Map dataDiskOfferingMap + ) { List pools = new ArrayList<>(); - List clusterPools = primaryDataStoreDao.findClusterWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem); - List zonePools = primaryDataStoreDao.findZoneWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getDataCenterId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem); + 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 diskOfferingTags = new ArrayList<>(); for (Long diskOfferingId : dataDiskOfferingMap.values()) { DiskOfferingVO diskOffering = diskOfferingDao.findById(diskOfferingId); @@ -2021,32 +2028,14 @@ private List findInstanceConversionStoragePoolsInCluster(Cluster } diskOfferingTags.add(diskOffering.getTags()); } - if (dataDiskOfferingMap.isEmpty()) { - pools.addAll(clusterPools); - pools.addAll(zonePools); - } else { - for (String tags : diskOfferingTags) { - boolean tagsMatched = false; - for (StoragePoolVO pool : clusterPools) { - if (volumeApiService.doesTargetStorageSupportDiskOffering(pool, tags)) { - pools.add(pool); - tagsMatched = true; - } - } - for (StoragePoolVO pool : zonePools) { - if (volumeApiService.doesTargetStorageSupportDiskOffering(pool, tags)) { - pools.add(pool); - tagsMatched = true; - } - } - if (!tagsMatched) { - String msg = String.format("Cannot find suitable storage pools in cluster %s for the conversion with disk offering tags %s", - destinationCluster, tags); - LOGGER.error(msg); - throw new CloudRuntimeException(msg); - } + 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); @@ -2055,18 +2044,50 @@ private List findInstanceConversionStoragePoolsInCluster(Cluster return pools; } - private List selectInstanceConversionStoragePools(List pools, List disks, Map dataDiskOfferingMap) { + private List getPoolsWithMatchingTags(List pools, List diskOfferingTags) { + if (diskOfferingTags.isEmpty()) { + return pools; + } + List 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 selectInstanceConversionStoragePools( + List pools, List disks, + ServiceOfferingVO serviceOffering, Map dataDiskOfferingMap + ) { List storagePools = new ArrayList<>(disks.size()); - //TODO: Choose pools by capacity + for (int i = 0; i < disks.size(); i++) { + storagePools.add(null); + } + Set dataDiskIds = dataDiskOfferingMap.keySet(); for (UnmanagedInstanceTO.Disk disk : disks) { 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.add(pools.get(0).getUuid()); + 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.add(pool.getUuid()); + storagePools.set(disk.getPosition(), pool.getUuid()); break; } } 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 b502c42fd065..85402c0e2548 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 void setUp() throws Exception { List 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");