From 3d0b4fca8475ce38b430bbd55fec9f825d8c5e38 Mon Sep 17 00:00:00 2001 From: Nicolas Vazquez Date: Thu, 2 Jan 2025 12:20:04 +0100 Subject: [PATCH 1/3] UI: Add cluster arch type to the zone creation wizard (#10080) * UI: Add cluster arch type to the zone creation wizard * Remove unused field * Fix github lint action * Remove unused option key --- ui/src/views/infra/zone/ZoneWizardAddResources.vue | 14 ++++++++++++++ ui/src/views/infra/zone/ZoneWizardLaunchZone.vue | 1 + 2 files changed, 15 insertions(+) diff --git a/ui/src/views/infra/zone/ZoneWizardAddResources.vue b/ui/src/views/infra/zone/ZoneWizardAddResources.vue index ef2cba1c3d9..00811ed3a10 100644 --- a/ui/src/views/infra/zone/ZoneWizardAddResources.vue +++ b/ui/src/views/infra/zone/ZoneWizardAddResources.vue @@ -192,6 +192,13 @@ export default { placeHolder: 'message.error.cluster.name', required: true }, + { + title: 'label.arch', + key: 'arch', + required: false, + select: true, + options: this.architectureTypes + }, { title: 'label.vcenter.host', key: 'vCenterHost', @@ -846,6 +853,13 @@ export default { primaryStorageScopes: [], primaryStorageProtocols: [], primaryStorageProviders: [], + architectureTypes: [{ + id: 'x86_64', + description: 'AMD 64 bits (x86_64)' + }, { + id: 'aarch64', + description: 'ARM 64 bits (aarch64)' + }], storageProviders: [], currentStep: null, options: ['primaryStorageScope', 'primaryStorageProtocol', 'provider', 'primaryStorageProvider'] diff --git a/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue b/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue index e562fb33d72..01006cd0c72 100644 --- a/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue +++ b/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue @@ -1283,6 +1283,7 @@ export default { if (this.isEdgeZone) { clusterName = 'Cluster-' + this.stepData.zoneReturned.name } + params.arch = this.prefillContent?.arch || null if (hypervisor === 'VMware') { params.username = this.prefillContent?.vCenterUsername || null From d8c321d57aec526241939dae8553301140142c73 Mon Sep 17 00:00:00 2001 From: Vishesh Date: Fri, 3 Jan 2025 13:35:54 +0530 Subject: [PATCH 2/3] check tags while fetching storage pool for importing vm (#9764) --- .../vm/UnmanagedVMsManagerImpl.java | 134 +++++++++++++----- .../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 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 convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster); + List convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster, serviceOffering, dataDiskOfferingMap); long importStartTime = System.currentTimeMillis(); Pair 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 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(); @@ -1912,16 +1918,16 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { } private UnmanagedInstanceTO convertVmwareInstanceToKVMWithOVFOnConvertLocation( - String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, - HostVO convertHost, HostVO importHost, - List convertStoragePools, 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()); + 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; @@ -1932,16 +1938,17 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { } private UnmanagedInstanceTO convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation( - String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, - HostVO convertHost, HostVO importHost, List convertStoragePools, - 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()); + 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; @@ -2004,12 +2011,31 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { return ((ImportConvertedInstanceAnswer) importAnswer).getConvertedInstance(); } - private List findInstanceConversionStoragePoolsInCluster(Cluster destinationCluster) { + 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); - pools.addAll(clusterPools); - List 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 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 selectInstanceConversionStoragePools(List pools, List disks) { + 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 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 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 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); From cfafcaeb01bda2effeef8ebc3044404d42019181 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Fri, 3 Jan 2025 10:16:44 +0100 Subject: [PATCH 3/3] log name change after merge forward --- .../org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 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 8c98456f1cc..13919b04f61 100644 --- a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java @@ -2071,7 +2071,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { DiskOfferingVO diskOffering = diskOfferingDao.findById(diskOfferingId); if (diskOffering == null) { String msg = String.format("Cannot find disk offering with ID %s", diskOfferingId); - LOGGER.error(msg); + logger.error(msg); throw new CloudRuntimeException(msg); } diskOfferingTags.add(diskOffering.getTags()); @@ -2107,7 +2107,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { } if (!tagsMatched) { String msg = String.format("Cannot find suitable storage pools for the conversion with disk offering tags %s", tags); - LOGGER.error(msg); + logger.error(msg); throw new CloudRuntimeException(msg); } }