Skip to content

Commit 30b2588

Browse files
committed
Merge release branch 4.20 to main
* 4.20: log name change after merge forward check tags while fetching storage pool for importing vm (#9764) UI: Add cluster arch type to the zone creation wizard (#10080)
2 parents 5bae118 + cfafcae commit 30b2588

File tree

4 files changed

+120
-33
lines changed

4 files changed

+120
-33
lines changed

server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java

+101-33
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ private Map<String, Network.IpAddresses> getNicIpAddresses(final List<UnmanagedI
538538
return nicIpAddresses;
539539
}
540540

541-
private StoragePool getStoragePool(final UnmanagedInstanceTO.Disk disk, final DataCenter zone, final Cluster cluster) {
541+
private StoragePool getStoragePool(final UnmanagedInstanceTO.Disk disk, final DataCenter zone, final Cluster cluster, String diskOfferingTags) {
542542
StoragePool storagePool = null;
543543
final String dsHost = disk.getDatastoreHost();
544544
final String dsPath = disk.getDatastorePath();
@@ -548,7 +548,8 @@ private StoragePool getStoragePool(final UnmanagedInstanceTO.Disk disk, final Da
548548
List<StoragePoolVO> pools = primaryDataStoreDao.listPoolByHostPath(dsHost, dsPath);
549549
for (StoragePool pool : pools) {
550550
if (pool.getDataCenterId() == zone.getId() &&
551-
(pool.getClusterId() == null || pool.getClusterId().equals(cluster.getId()))) {
551+
(pool.getClusterId() == null || pool.getClusterId().equals(cluster.getId())) &&
552+
volumeApiService.doesTargetStorageSupportDiskOffering(pool, diskOfferingTags)) {
552553
storagePool = pool;
553554
break;
554555
}
@@ -560,7 +561,8 @@ private StoragePool getStoragePool(final UnmanagedInstanceTO.Disk disk, final Da
560561
pools.addAll(primaryDataStoreDao.listByDataCenterId(zone.getId()));
561562
for (StoragePool pool : pools) {
562563
String searchPoolParam = StringUtils.isNotBlank(dsPath) ? dsPath : dsName;
563-
if (StringUtils.contains(pool.getPath(), searchPoolParam)) {
564+
if (StringUtils.contains(pool.getPath(), searchPoolParam) &&
565+
volumeApiService.doesTargetStorageSupportDiskOffering(pool, diskOfferingTags)) {
564566
storagePool = pool;
565567
break;
566568
}
@@ -623,7 +625,8 @@ private void checkUnmanagedDiskAndOfferingForImport(String instanceName, Unmanag
623625
if (diskOffering != null && !diskOffering.isCustomized() && diskOffering.getDiskSize() < disk.getCapacity()) {
624626
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))));
625627
}
626-
StoragePool storagePool = getStoragePool(disk, zone, cluster);
628+
diskOffering = diskOffering != null ? diskOffering : diskOfferingDao.findById(serviceOffering.getDiskOfferingId());
629+
StoragePool storagePool = getStoragePool(disk, zone, cluster, diskOffering != null ? diskOffering.getTags() : null);
627630
if (diskOffering != null && !migrateAllowed && !storagePoolSupportsDiskOffering(storagePool, diskOffering)) {
628631
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()));
629632
}
@@ -860,7 +863,7 @@ private Pair<DiskProfile, StoragePool> importDisk(UnmanagedInstanceTO.Disk disk,
860863
diskInfo.setDiskChain(new String[]{disk.getImagePath()});
861864
chainInfo = gson.toJson(diskInfo);
862865
}
863-
StoragePool storagePool = getStoragePool(disk, zone, cluster);
866+
StoragePool storagePool = getStoragePool(disk, zone, cluster, diskOffering != null ? diskOffering.getTags() : null);
864867
DiskProfile profile = volumeManager.importVolume(type, name, diskOffering, diskSize,
865868
minIops, maxIops, vm.getDataCenterId(), vm.getHypervisorType(), vm, template, owner, deviceId, storagePool.getId(), path, chainInfo);
866869

@@ -1645,7 +1648,7 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster
16451648

16461649
temporaryConvertLocation = selectInstanceConversionTemporaryLocation(
16471650
destinationCluster, convertHost, convertStoragePoolId);
1648-
List<StoragePoolVO> convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster);
1651+
List<StoragePoolVO> convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster, serviceOffering, dataDiskOfferingMap);
16491652
long importStartTime = System.currentTimeMillis();
16501653
Pair<UnmanagedInstanceTO, Boolean> sourceInstanceDetails = getSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password, clusterName, sourceHostName, sourceVMName);
16511654
sourceVMwareInstance = sourceInstanceDetails.first();
@@ -1661,15 +1664,18 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster
16611664
if (cmd.getForceMsToImportVmFiles() || !conversionSupportAnswer.isOvfExportSupported()) {
16621665
// Uses MS for OVF export to temporary conversion location
16631666
int noOfThreads = UnmanagedVMsManager.ThreadsOnMSToImportVMwareVMFiles.value();
1664-
ovfTemplateOnConvertLocation = createOvfTemplateOfSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password,
1665-
clusterName, sourceHostName, sourceVMwareInstance.getName(), temporaryConvertLocation, noOfThreads);
1667+
ovfTemplateOnConvertLocation = createOvfTemplateOfSourceVmwareUnmanagedInstance(
1668+
vcenter, datacenterName, username, password, clusterName, sourceHostName,
1669+
sourceVMwareInstance.getName(), temporaryConvertLocation, noOfThreads);
16661670
convertedInstance = convertVmwareInstanceToKVMWithOVFOnConvertLocation(sourceVMName,
1667-
sourceVMwareInstance, convertHost, importHost, convertStoragePools,
1668-
temporaryConvertLocation, ovfTemplateOnConvertLocation);
1671+
sourceVMwareInstance, convertHost, importHost, convertStoragePools,
1672+
serviceOffering, dataDiskOfferingMap, temporaryConvertLocation,
1673+
ovfTemplateOnConvertLocation);
16691674
} else {
16701675
// Uses KVM Host for OVF export to temporary conversion location, through ovftool
16711676
convertedInstance = convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(
1672-
sourceVMName, sourceVMwareInstance, convertHost, importHost, convertStoragePools,
1677+
sourceVMName, sourceVMwareInstance, convertHost, importHost,
1678+
convertStoragePools, serviceOffering, dataDiskOfferingMap,
16731679
temporaryConvertLocation, vcenter, username, password, datacenterName);
16741680
}
16751681

@@ -1759,9 +1765,9 @@ private void sanitizeConvertedInstance(UnmanagedInstanceTO convertedInstance, Un
17591765
convertedInstance.setPowerState(UnmanagedInstanceTO.PowerState.PowerOff);
17601766
List<UnmanagedInstanceTO.Disk> convertedInstanceDisks = convertedInstance.getDisks();
17611767
List<UnmanagedInstanceTO.Disk> sourceVMwareInstanceDisks = sourceVMwareInstance.getDisks();
1762-
for (int i = 0; i < convertedInstanceDisks.size(); i++) {
1763-
UnmanagedInstanceTO.Disk disk = convertedInstanceDisks.get(i);
1764-
disk.setDiskId(sourceVMwareInstanceDisks.get(i).getDiskId());
1768+
for (UnmanagedInstanceTO.Disk sourceVMwareInstanceDisk : sourceVMwareInstanceDisks) {
1769+
UnmanagedInstanceTO.Disk convertedDisk = convertedInstanceDisks.get(sourceVMwareInstanceDisk.getPosition());
1770+
convertedDisk.setDiskId(sourceVMwareInstanceDisk.getDiskId());
17651771
}
17661772
List<UnmanagedInstanceTO.Nic> convertedInstanceNics = convertedInstance.getNics();
17671773
List<UnmanagedInstanceTO.Nic> sourceVMwareInstanceNics = sourceVMwareInstance.getNics();
@@ -1945,16 +1951,16 @@ private CheckConvertInstanceAnswer checkConversionSupportOnHost(HostVO convertHo
19451951
}
19461952

19471953
private UnmanagedInstanceTO convertVmwareInstanceToKVMWithOVFOnConvertLocation(
1948-
String sourceVM, UnmanagedInstanceTO sourceVMwareInstance,
1949-
HostVO convertHost, HostVO importHost,
1950-
List<StoragePoolVO> convertStoragePools, DataStoreTO temporaryConvertLocation,
1951-
String ovfTemplateDirConvertLocation
1954+
String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost,
1955+
HostVO importHost, List<StoragePoolVO> convertStoragePools,
1956+
ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap,
1957+
DataStoreTO temporaryConvertLocation, String ovfTemplateDirConvertLocation
19521958
) {
19531959
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",
19541960
sourceVM, convertHost.getId(), convertHost.getName(), ovfTemplateDirConvertLocation));
19551961

19561962
RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(sourceVM);
1957-
List<String> destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks());
1963+
List<String> destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks(), serviceOffering, dataDiskOfferingMap);
19581964
ConvertInstanceCommand cmd = new ConvertInstanceCommand(remoteInstanceTO,
19591965
Hypervisor.HypervisorType.KVM, destinationStoragePools, temporaryConvertLocation, ovfTemplateDirConvertLocation, false, false);
19601966
int timeoutSeconds = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60;
@@ -1980,16 +1986,17 @@ private UnmanagedInstanceTO convertVmwareInstanceToKVMWithOVFOnConvertLocation(
19801986
}
19811987

19821988
private UnmanagedInstanceTO convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(
1983-
String sourceVM, UnmanagedInstanceTO sourceVMwareInstance,
1984-
HostVO convertHost, HostVO importHost, List<StoragePoolVO> convertStoragePools,
1985-
DataStoreTO temporaryConvertLocation, String vcenterHost,
1986-
String vcenterUsername, String vcenterPassword, String datacenterName
1989+
String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost,
1990+
HostVO importHost, List<StoragePoolVO> convertStoragePools,
1991+
ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap,
1992+
DataStoreTO temporaryConvertLocation, String vcenterHost, String vcenterUsername,
1993+
String vcenterPassword, String datacenterName
19871994
) {
19881995
logger.debug(String.format("Delegating the conversion of instance %s from VMware to KVM to the host %s (%s) after OVF export through ovftool",
19891996
sourceVM, convertHost.getId(), convertHost.getName()));
19901997

19911998
RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(sourceVMwareInstance.getName(), vcenterHost, vcenterUsername, vcenterPassword, datacenterName);
1992-
List<String> destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks());
1999+
List<String> destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks(), serviceOffering, dataDiskOfferingMap);
19932000
ConvertInstanceCommand cmd = new ConvertInstanceCommand(remoteInstanceTO,
19942001
Hypervisor.HypervisorType.KVM, destinationStoragePools, temporaryConvertLocation, null, false, true);
19952002
int timeoutSeconds = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60;
@@ -2052,12 +2059,31 @@ private UnmanagedInstanceTO convertAndImportToKVM(ConvertInstanceCommand convert
20522059
return ((ImportConvertedInstanceAnswer) importAnswer).getConvertedInstance();
20532060
}
20542061

2055-
private List<StoragePoolVO> findInstanceConversionStoragePoolsInCluster(Cluster destinationCluster) {
2062+
private List<StoragePoolVO> findInstanceConversionStoragePoolsInCluster(
2063+
Cluster destinationCluster, ServiceOfferingVO serviceOffering,
2064+
Map<String, Long> dataDiskOfferingMap
2065+
) {
20562066
List<StoragePoolVO> pools = new ArrayList<>();
2057-
List<StoragePoolVO> clusterPools = primaryDataStoreDao.findClusterWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem);
2058-
pools.addAll(clusterPools);
2059-
List<StoragePoolVO> zonePools = primaryDataStoreDao.findZoneWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getDataCenterId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem);
2060-
pools.addAll(zonePools);
2067+
pools.addAll(primaryDataStoreDao.findClusterWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem));
2068+
pools.addAll(primaryDataStoreDao.findZoneWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getDataCenterId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem));
2069+
List<String> diskOfferingTags = new ArrayList<>();
2070+
for (Long diskOfferingId : dataDiskOfferingMap.values()) {
2071+
DiskOfferingVO diskOffering = diskOfferingDao.findById(diskOfferingId);
2072+
if (diskOffering == null) {
2073+
String msg = String.format("Cannot find disk offering with ID %s", diskOfferingId);
2074+
logger.error(msg);
2075+
throw new CloudRuntimeException(msg);
2076+
}
2077+
diskOfferingTags.add(diskOffering.getTags());
2078+
}
2079+
if (serviceOffering.getDiskOfferingId() != null) {
2080+
DiskOfferingVO diskOffering = diskOfferingDao.findById(serviceOffering.getDiskOfferingId());
2081+
if (diskOffering != null) {
2082+
diskOfferingTags.add(diskOffering.getTags());
2083+
}
2084+
}
2085+
2086+
pools = getPoolsWithMatchingTags(pools, diskOfferingTags);
20612087
if (pools.isEmpty()) {
20622088
String msg = String.format("Cannot find suitable storage pools in cluster %s for the conversion", destinationCluster.getName());
20632089
logger.error(msg);
@@ -2066,12 +2092,54 @@ private List<StoragePoolVO> findInstanceConversionStoragePoolsInCluster(Cluster
20662092
return pools;
20672093
}
20682094

2069-
private List<String> selectInstanceConversionStoragePools(List<StoragePoolVO> pools, List<UnmanagedInstanceTO.Disk> disks) {
2095+
private List<StoragePoolVO> getPoolsWithMatchingTags(List<StoragePoolVO> pools, List<String> diskOfferingTags) {
2096+
if (diskOfferingTags.isEmpty()) {
2097+
return pools;
2098+
}
2099+
List<StoragePoolVO> poolsSupportingTags = new ArrayList<>(pools);
2100+
for (String tags : diskOfferingTags) {
2101+
boolean tagsMatched = false;
2102+
for (StoragePoolVO pool : pools) {
2103+
if (volumeApiService.doesTargetStorageSupportDiskOffering(pool, tags)) {
2104+
poolsSupportingTags.add(pool);
2105+
tagsMatched = true;
2106+
}
2107+
}
2108+
if (!tagsMatched) {
2109+
String msg = String.format("Cannot find suitable storage pools for the conversion with disk offering tags %s", tags);
2110+
logger.error(msg);
2111+
throw new CloudRuntimeException(msg);
2112+
}
2113+
}
2114+
return poolsSupportingTags;
2115+
}
2116+
2117+
private List<String> selectInstanceConversionStoragePools(
2118+
List<StoragePoolVO> pools, List<UnmanagedInstanceTO.Disk> disks,
2119+
ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap
2120+
) {
20702121
List<String> storagePools = new ArrayList<>(disks.size());
2071-
//TODO: Choose pools by capacity
2122+
for (int i = 0; i < disks.size(); i++) {
2123+
storagePools.add(null);
2124+
}
2125+
Set<String> dataDiskIds = dataDiskOfferingMap.keySet();
20722126
for (UnmanagedInstanceTO.Disk disk : disks) {
2073-
Long capacity = disk.getCapacity();
2074-
storagePools.add(pools.get(0).getUuid());
2127+
Long diskOfferingId = dataDiskOfferingMap.get(disk.getDiskId());
2128+
if (diskOfferingId == null && !dataDiskIds.contains(disk.getDiskId())) {
2129+
diskOfferingId = serviceOffering.getDiskOfferingId();
2130+
}
2131+
//TODO: Choose pools by capacity
2132+
if (diskOfferingId == null) {
2133+
storagePools.set(disk.getPosition(), pools.get(0).getUuid());
2134+
} else {
2135+
DiskOfferingVO diskOffering = diskOfferingDao.findById(diskOfferingId);
2136+
for (StoragePoolVO pool : pools) {
2137+
if (volumeApiService.doesTargetStorageSupportDiskOffering(pool, diskOffering.getTags())) {
2138+
storagePools.set(disk.getPosition(), pool.getUuid());
2139+
break;
2140+
}
2141+
}
2142+
}
20752143
}
20762144
return storagePools;
20772145
}

server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java

+4
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ public void setUp() throws Exception {
279279
List<UnmanagedInstanceTO.Disk> instanceDisks = new ArrayList<>();
280280
UnmanagedInstanceTO.Disk instanceDisk = new UnmanagedInstanceTO.Disk();
281281
instanceDisk.setDiskId("1000-1");
282+
instanceDisk.setPosition(0);
282283
instanceDisk.setLabel("DiskLabel");
283284
instanceDisk.setController("scsi");
284285
instanceDisk.setImagePath("[b6ccf44a1fa13e29b3667b4954fa10ee] TestInstance/ROOT-1.vmdk");
@@ -424,6 +425,7 @@ public void importUnmanagedInstanceTest() {
424425
ImportUnmanagedInstanceCmd importUnmanageInstanceCmd = Mockito.mock(ImportUnmanagedInstanceCmd.class);
425426
when(importUnmanageInstanceCmd.getName()).thenReturn("TestInstance");
426427
when(importUnmanageInstanceCmd.getDomainId()).thenReturn(null);
428+
when(volumeApiService.doesTargetStorageSupportDiskOffering(any(StoragePool.class), any())).thenReturn(true);
427429
try (MockedStatic<UsageEventUtils> ignored = Mockito.mockStatic(UsageEventUtils.class)) {
428430
unmanagedVMsManager.importUnmanagedInstance(importUnmanageInstanceCmd);
429431
}
@@ -703,6 +705,8 @@ private void baseTestImportVmFromVmwareToKvm(VcenterParameter vcenterParameter,
703705
when(agentManager.send(Mockito.eq(convertHostId), Mockito.any(CheckConvertInstanceCommand.class))).thenReturn(checkConvertInstanceAnswer);
704706
}
705707

708+
when(volumeApiService.doesTargetStorageSupportDiskOffering(any(StoragePool.class), any())).thenReturn(true);
709+
706710
ConvertInstanceAnswer convertInstanceAnswer = mock(ConvertInstanceAnswer.class);
707711
ImportConvertedInstanceAnswer convertImportedInstanceAnswer = mock(ImportConvertedInstanceAnswer.class);
708712
when(convertInstanceAnswer.getConvertedInstance()).thenReturn(instance);

ui/src/views/infra/zone/ZoneWizardAddResources.vue

+14
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,13 @@ export default {
192192
placeHolder: 'message.error.cluster.name',
193193
required: true
194194
},
195+
{
196+
title: 'label.arch',
197+
key: 'arch',
198+
required: false,
199+
select: true,
200+
options: this.architectureTypes
201+
},
195202
{
196203
title: 'label.vcenter.host',
197204
key: 'vCenterHost',
@@ -846,6 +853,13 @@ export default {
846853
primaryStorageScopes: [],
847854
primaryStorageProtocols: [],
848855
primaryStorageProviders: [],
856+
architectureTypes: [{
857+
id: 'x86_64',
858+
description: 'AMD 64 bits (x86_64)'
859+
}, {
860+
id: 'aarch64',
861+
description: 'ARM 64 bits (aarch64)'
862+
}],
849863
storageProviders: [],
850864
currentStep: null,
851865
options: ['primaryStorageScope', 'primaryStorageProtocol', 'provider', 'primaryStorageProvider']

ui/src/views/infra/zone/ZoneWizardLaunchZone.vue

+1
Original file line numberDiff line numberDiff line change
@@ -1283,6 +1283,7 @@ export default {
12831283
if (this.isEdgeZone) {
12841284
clusterName = 'Cluster-' + this.stepData.zoneReturned.name
12851285
}
1286+
params.arch = this.prefillContent?.arch || null
12861287
12871288
if (hypervisor === 'VMware') {
12881289
params.username = this.prefillContent?.vCenterUsername || null

0 commit comments

Comments
 (0)