Skip to content

Commit 28a993f

Browse files
Infer single conversion pool for VMware import
1 parent a0aafe2 commit 28a993f

3 files changed

Lines changed: 108 additions & 9 deletions

File tree

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,6 +1679,7 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster
16791679
ApiConstants.FORCE_MS_TO_IMPORT_VM_FILES, ApiConstants.USE_VDDK));
16801680
}
16811681

1682+
convertStoragePoolId = resolveImplicitConversionStoragePoolId(destinationCluster, convertStoragePoolId, forceConvertToPool);
16821683
checkConversionStoragePool(convertStoragePoolId, forceConvertToPool);
16831684
validateSelectedConversionStoragePoolForVddk(useVddk, convertStoragePoolId, serviceOffering, dataDiskOfferingMap);
16841685

@@ -1816,6 +1817,45 @@ protected void checkConversionStoragePool(Long convertStoragePoolId, boolean for
18161817
}
18171818
}
18181819

1820+
protected Long resolveImplicitConversionStoragePoolId(Cluster destinationCluster, Long convertStoragePoolId,
1821+
boolean forceConvertToPool) {
1822+
if (!forceConvertToPool || convertStoragePoolId != null) {
1823+
return convertStoragePoolId;
1824+
}
1825+
1826+
List<StoragePoolVO> candidatePools = getImplicitForceConvertToPoolStoragePools(destinationCluster);
1827+
if (candidatePools.isEmpty()) {
1828+
logFailureAndThrowException(String.format("The parameter forceconverttopool is set to true, but no suitable primary storage pool was found in cluster %s",
1829+
destinationCluster.getName()));
1830+
}
1831+
if (candidatePools.size() > 1) {
1832+
logFailureAndThrowException(String.format("The parameter forceconverttopool is set to true, but multiple suitable primary storage pools were found in cluster %s. Please provide convertinstancepoolid.",
1833+
destinationCluster.getName()));
1834+
}
1835+
1836+
StoragePoolVO implicitPool = candidatePools.get(0);
1837+
logger.debug("The parameter forceconverttopool is set to true and no conversion storage pool was provided; using the only suitable primary storage pool [{}].",
1838+
implicitPool.getName());
1839+
return implicitPool.getId();
1840+
}
1841+
1842+
private List<StoragePoolVO> getImplicitForceConvertToPoolStoragePools(Cluster destinationCluster) {
1843+
Set<StoragePoolVO> pools = new HashSet<>();
1844+
for (Storage.StoragePoolType poolType : forceConvertToPoolAllowedTypes) {
1845+
List<StoragePoolVO> clusterPools = primaryDataStoreDao.findClusterWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getId(),
1846+
Hypervisor.HypervisorType.KVM, poolType);
1847+
if (clusterPools != null) {
1848+
pools.addAll(clusterPools);
1849+
}
1850+
List<StoragePoolVO> zonePools = primaryDataStoreDao.findZoneWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getDataCenterId(),
1851+
Hypervisor.HypervisorType.KVM, poolType);
1852+
if (zonePools != null) {
1853+
pools.addAll(zonePools);
1854+
}
1855+
}
1856+
return new ArrayList<>(pools);
1857+
}
1858+
18191859
protected void validateSelectedConversionStoragePoolForVddk(boolean useVddk, Long convertStoragePoolId,
18201860
ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap) {
18211861
if (!useVddk || convertStoragePoolId == null) {

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,6 +1405,46 @@ public void testCheckConversionStoragePoolTemporarySecondaryStorageForceConvertT
14051405
unmanagedVMsManager.checkConversionStoragePool(null, true);
14061406
}
14071407

1408+
@Test
1409+
public void testResolveImplicitConversionStoragePoolIdUsesSingleSuitablePoolWhenForceConvertToPool() {
1410+
ClusterVO cluster = getClusterForTests();
1411+
StoragePoolVO storagePool = mock(StoragePoolVO.class);
1412+
when(storagePool.getId()).thenReturn(42L);
1413+
when(primaryDataStoreDao.findClusterWideStoragePoolsByHypervisorAndPoolType(cluster.getId(),
1414+
Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem))
1415+
.thenReturn(List.of(storagePool));
1416+
1417+
Long storagePoolId = unmanagedVMsManager.resolveImplicitConversionStoragePoolId(cluster, null, true);
1418+
1419+
Assert.assertEquals(Long.valueOf(42L), storagePoolId);
1420+
}
1421+
1422+
@Test
1423+
public void testResolveImplicitConversionStoragePoolIdKeepsExplicitPoolWhenForceConvertToPool() {
1424+
ClusterVO cluster = getClusterForTests();
1425+
1426+
Long storagePoolId = unmanagedVMsManager.resolveImplicitConversionStoragePoolId(cluster, 42L, true);
1427+
1428+
Assert.assertEquals(Long.valueOf(42L), storagePoolId);
1429+
Mockito.verifyNoInteractions(primaryDataStoreDao);
1430+
}
1431+
1432+
@Test(expected = CloudRuntimeException.class)
1433+
public void testResolveImplicitConversionStoragePoolIdFailsWhenMultiplePoolsFound() {
1434+
ClusterVO cluster = getClusterForTests();
1435+
when(cluster.getName()).thenReturn("cluster-1");
1436+
StoragePoolVO firstStoragePool = mock(StoragePoolVO.class);
1437+
StoragePoolVO secondStoragePool = mock(StoragePoolVO.class);
1438+
when(primaryDataStoreDao.findClusterWideStoragePoolsByHypervisorAndPoolType(cluster.getId(),
1439+
Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem))
1440+
.thenReturn(List.of(firstStoragePool));
1441+
when(primaryDataStoreDao.findZoneWideStoragePoolsByHypervisorAndPoolType(cluster.getDataCenterId(),
1442+
Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem))
1443+
.thenReturn(List.of(secondStoragePool));
1444+
1445+
unmanagedVMsManager.resolveImplicitConversionStoragePoolId(cluster, null, true);
1446+
}
1447+
14081448
@Test
14091449
public void testCheckConversionStoragePoolPrimaryStagingPool() {
14101450
StoragePoolVO destPool = mock(StoragePoolVO.class);

ui/src/views/tools/ImportUnmanagedInstance.vue

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,11 +1085,7 @@ export default {
10851085
}
10861086
getAPI('listStoragePools', params).then(json => {
10871087
this.storagePoolsForConversion = json.liststoragepoolsresponse.storagepool || []
1088-
// Keep selected pool state aligned when the value is auto-populated by v-model.
1089-
if (this.form.convertstoragepoolid) {
1090-
const poolExists = this.storagePoolsForConversion.some(pool => pool.id === this.form.convertstoragepoolid)
1091-
this.selectedStoragePoolForConversion = poolExists ? this.form.convertstoragepoolid : null
1092-
}
1088+
this.syncSelectedStoragePoolForConversion()
10931089
})
10941090
} else if (this.selectedStorageOptionForConversion === 'local') {
10951091
const kvmHost = this.kvmHostsForConversion.filter(x => x.id === this.selectedKvmHostForConversion)[0]
@@ -1099,13 +1095,25 @@ export default {
10991095
status: 'Up'
11001096
}).then(json => {
11011097
this.storagePoolsForConversion = json.liststoragepoolsresponse.storagepool || []
1102-
if (this.form.convertstoragepoolid) {
1103-
const poolExists = this.storagePoolsForConversion.some(pool => pool.id === this.form.convertstoragepoolid)
1104-
this.selectedStoragePoolForConversion = poolExists ? this.form.convertstoragepoolid : null
1105-
}
1098+
this.syncSelectedStoragePoolForConversion()
11061099
})
11071100
}
11081101
},
1102+
syncSelectedStoragePoolForConversion () {
1103+
if (this.form.convertstoragepoolid) {
1104+
const poolExists = this.storagePoolsForConversion.some(pool => pool.id === this.form.convertstoragepoolid)
1105+
if (poolExists) {
1106+
this.selectedStoragePoolForConversion = this.form.convertstoragepoolid
1107+
return
1108+
}
1109+
this.form.convertstoragepoolid = null
1110+
this.selectedStoragePoolForConversion = null
1111+
}
1112+
if (this.storagePoolsForConversion.length === 1) {
1113+
this.form.convertstoragepoolid = this.storagePoolsForConversion[0].id
1114+
this.selectedStoragePoolForConversion = this.form.convertstoragepoolid
1115+
}
1116+
},
11091117
updateSelectedKvmHostForImporting (clusterid, checked, value) {
11101118
if (checked) {
11111119
this.selectedKvmHostForImporting = value
@@ -1162,6 +1170,9 @@ export default {
11621170
this.selectedStoragePoolForConversion = null
11631171
this.showStoragePoolsForConversion = false
11641172
this.resetStorageOptionsForConversion()
1173+
if (val) {
1174+
this.selectPrimaryStorageForForcedConversion()
1175+
}
11651176
},
11661177
onUseVddkChange (val, isUserChange = true) {
11671178
if (isUserChange) {
@@ -1186,6 +1197,14 @@ export default {
11861197
this.fetchKvmHostsForConversion()
11871198
}
11881199
this.resetStorageOptionsForConversion()
1200+
if (val) {
1201+
this.selectPrimaryStorageForForcedConversion()
1202+
}
1203+
},
1204+
selectPrimaryStorageForForcedConversion () {
1205+
this.selectedStorageOptionForConversion = 'primary'
1206+
this.showStoragePoolsForConversion = true
1207+
this.fetchStoragePoolsForConversion()
11891208
},
11901209
updateSelectedRootDisk () {
11911210
var rootDisk = this.resource.disk[this.selectedRootDiskIndex]

0 commit comments

Comments
 (0)