Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3b1ab6f
Add source VM name on virt-v2v migration log entries
nvazquez Sep 5, 2025
e194ba9
Improve the feedback by displaying the running importing tasks
nvazquez Sep 7, 2025
83fd30d
Add source VM name prefix on more conversion logs
nvazquez Sep 8, 2025
f9e9466
Improve listing and also list completed tasks
nvazquez Sep 14, 2025
9200dd0
Pass extra parameters to virt-v2v if administrator allows via global …
nvazquez Sep 14, 2025
c3b06da
Add Force converting directly to storage pool option
nvazquez Sep 19, 2025
e9176ee
Refactor based on review comments
nvazquez Sep 19, 2025
2a92813
Add properties for env vars for the instance conversion
nvazquez Sep 20, 2025
2f08049
Add separate component for Import VM Tasks
nvazquez Sep 20, 2025
6493720
applying copilot suggestions from code review
shwstppr Sep 22, 2025
1ba03c0
Merge branch 'main' into 422-vmware-to-kvm-improvements
sureshanaparti Sep 26, 2025
7196e09
Fix importing unmanaged instances due to incorrect internal name
nvazquez Sep 29, 2025
03ed3cf
Add VM prefix on each log operation for conversion
nvazquez Sep 30, 2025
f952e76
Log the original VM name instead of the cloned VM in case of cloning
nvazquez Oct 1, 2025
b981367
Allow searching storage pool by UUID after conversion to support Shar…
nvazquez Oct 2, 2025
b1012d2
Fix search pools logic
nvazquez Oct 3, 2025
63c0eac
Improve UI and add checks for force convert to pool parameter
nvazquez Oct 7, 2025
0638763
Merge branch 'main' into 422-vmware-to-kvm-improvements
nvazquez Oct 8, 2025
2c52bfa
Support Local storage when forceconverttopool is set to true
nvazquez Oct 8, 2025
977f6b6
Merge branch 'main' into 422-vmware-to-kvm-improvements
nvazquez Oct 8, 2025
c506ee8
Merge branch 'main' into 422-vmware-to-kvm-improvements
nvazquez Oct 9, 2025
4c5b87d
Add config key to for allowed extra params and add validation
nvazquez Oct 9, 2025
4f73495
Fix params lists
nvazquez Oct 10, 2025
9431b9d
Fix compile error
nvazquez Oct 10, 2025
83c6585
Remove extra stubbings
nvazquez Oct 10, 2025
d9c0f74
Merge branch 'main' into 422-vmware-to-kvm-improvements
nvazquez Oct 10, 2025
dac73f4
Fix extra params execution
nvazquez Oct 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add Force converting directly to storage pool option
  • Loading branch information
nvazquez committed Sep 19, 2025
commit c3b06da6e24b5a511c668aa5dd06ea84f2ceabf7
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
description = "(VMware to KVM only) extra parameters to be passed on the virt-v2v command, if allowed by the administrator")
private String extraParams;

@Parameter(name = "forceconverttopool", type = CommandType.BOOLEAN,
description = "(only for importing VMs from VMware to KVM) optional - if true, forces virt-v2v conversions to write directly on the provided storage pool (avoid using temporary conversion pool).")
private Boolean forceConvertToPool;

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
Expand Down Expand Up @@ -258,6 +262,10 @@ public String getExtraParams() {
return extraParams;
}

public boolean getForceConvertToPool() {
return BooleanUtils.toBooleanDefaultIfNull(forceConvertToPool, false);
}

@Override
public String getEventDescription() {
String vmName = getName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,20 @@ public class ImportConvertedInstanceCommand extends Command {
private List<String> destinationStoragePools;
private DataStoreTO conversionTemporaryLocation;
private String temporaryConvertUuid;
private boolean forceConvertToPool;

public ImportConvertedInstanceCommand() {
}

public ImportConvertedInstanceCommand(RemoteInstanceTO sourceInstance,
List<String> destinationStoragePools,
DataStoreTO conversionTemporaryLocation, String temporaryConvertUuid) {
DataStoreTO conversionTemporaryLocation, String temporaryConvertUuid,
boolean forceConvertToPool) {
this.sourceInstance = sourceInstance;
this.destinationStoragePools = destinationStoragePools;
this.conversionTemporaryLocation = conversionTemporaryLocation;
this.temporaryConvertUuid = temporaryConvertUuid;
this.forceConvertToPool = forceConvertToPool;
}

public RemoteInstanceTO getSourceInstance() {
Expand All @@ -56,6 +59,10 @@ public String getTemporaryConvertUuid() {
return temporaryConvertUuid;
}

public boolean isForceConvertToPool() {
return forceConvertToPool;
}

@Override
public boolean executeInSequence() {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public Answer execute(ImportConvertedInstanceCommand cmd, LibvirtComputingResour
List<String> destinationStoragePools = cmd.getDestinationStoragePools();
DataStoreTO conversionTemporaryLocation = cmd.getConversionTemporaryLocation();
final String temporaryConvertUuid = cmd.getTemporaryConvertUuid();
final boolean forceConvertToPool = cmd.isForceConvertToPool();

final KVMStoragePoolManager storagePoolMgr = serverResource.getStoragePoolMgr();
KVMStoragePool temporaryStoragePool = getTemporaryStoragePool(conversionTemporaryLocation, storagePoolMgr);
Expand All @@ -80,13 +81,18 @@ public Answer execute(ImportConvertedInstanceCommand cmd, LibvirtComputingResour
getTemporaryDisksWithPrefixFromTemporaryPool(temporaryStoragePool, temporaryConvertPath, temporaryConvertUuid) :
getTemporaryDisksFromParsedXml(temporaryStoragePool, xmlParser, convertedBasePath);

List<KVMPhysicalDisk> destinationDisks = moveTemporaryDisksToDestination(temporaryDisks,
destinationStoragePools, storagePoolMgr);

cleanupDisksAndDomainFromTemporaryLocation(temporaryDisks, temporaryStoragePool, temporaryConvertUuid);
List<KVMPhysicalDisk> disks = null;
if (forceConvertToPool) {
// Force flag to use the conversion path, no need to move disks
disks = temporaryDisks;
} else {
disks = moveTemporaryDisksToDestination(temporaryDisks,
destinationStoragePools, storagePoolMgr);
cleanupDisksAndDomainFromTemporaryLocation(temporaryDisks, temporaryStoragePool, temporaryConvertUuid);
}

UnmanagedInstanceTO convertedInstanceTO = getConvertedUnmanagedInstance(temporaryConvertUuid,
destinationDisks, xmlParser);
disks, xmlParser);
return new ImportConvertedInstanceAnswer(cmd, convertedInstanceTO);
} catch (Exception e) {
String error = String.format("Error converting instance %s from %s, due to: %s",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public void testExecuteConvertFailure() {
Answer answer = convertInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
Assert.assertFalse(answer.getResult());
Mockito.verify(convertInstanceCommandWrapper).performInstanceConversion(Mockito.anyString(), Mockito.anyString(),
Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyBoolean(), null);
Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyBoolean(), Mockito.nullable(String.class));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1407,7 +1407,6 @@ private UserVmResponse baseImportInstance(ImportUnmanagedInstanceCmd cmd) {
throw new CloudRuntimeException("Please provide an import source for importing the VM");
}
String source = importVmCmd.getImportSource().toUpperCase();
String extraParams = ((ImportVmCmd) cmd).getExtraParams();
ImportSource importSource = Enum.valueOf(ImportSource.class, source);
if (ImportSource.VMWARE == importSource) {
userVm = importUnmanagedInstanceFromVmwareToKvm(zone, cluster,
Expand Down Expand Up @@ -1703,6 +1702,7 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster
Long importInstanceHostId = cmd.getImportInstanceHostId();
Long convertStoragePoolId = cmd.getConvertStoragePoolId();
String extraParams = cmd.getExtraParams();
boolean forceConvertToPool = cmd.getForceConvertToPool();

if ((existingVcenterId == null && vcenter == null) || (existingVcenterId != null && vcenter != null)) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
Expand Down Expand Up @@ -1741,7 +1741,7 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster
"instance {} from VMware to KVM ", convertHost, sourceVMName);

temporaryConvertLocation = selectInstanceConversionTemporaryLocation(
destinationCluster, convertHost, convertStoragePoolId);
destinationCluster, convertHost, convertStoragePoolId, forceConvertToPool);
List<StoragePoolVO> convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster, serviceOffering, dataDiskOfferingMap);
long importStartTime = System.currentTimeMillis();
importVMTaskVO = createImportVMTaskRecord(zone, owner, userId, displayName, vcenter, datacenterName, sourceVMName,
Expand All @@ -1768,14 +1768,14 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster
convertedInstance = convertVmwareInstanceToKVMWithOVFOnConvertLocation(sourceVMName,
sourceVMwareInstance, convertHost, importHost, convertStoragePools,
serviceOffering, dataDiskOfferingMap, temporaryConvertLocation,
ovfTemplateOnConvertLocation, extraParams);
ovfTemplateOnConvertLocation, forceConvertToPool, extraParams);
} else {
// Uses KVM Host for OVF export to temporary conversion location, through ovftool
updateImportVMTaskStep(importVMTaskVO, zone, owner, convertHost, importHost, ConvertingInstance);
convertedInstance = convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(
sourceVMName, sourceVMwareInstance, convertHost, importHost,
convertStoragePools, serviceOffering, dataDiskOfferingMap,
temporaryConvertLocation, vcenter, username, password, datacenterName, extraParams);
temporaryConvertLocation, vcenter, username, password, datacenterName, forceConvertToPool, extraParams);
}

sanitizeConvertedInstance(convertedInstance, sourceVMwareInstance);
Expand Down Expand Up @@ -2057,9 +2057,11 @@ private UnmanagedInstanceTO convertVmwareInstanceToKVMWithOVFOnConvertLocation(
String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost,
HostVO importHost, List<StoragePoolVO> convertStoragePools,
ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap,
DataStoreTO temporaryConvertLocation, String ovfTemplateDirConvertLocation, String extraParams) {
logger.debug("Delegating the conversion of instance {} from VMware to KVM to the host {} using OVF {} on conversion datastore",
sourceVM, convertHost, ovfTemplateDirConvertLocation);
DataStoreTO temporaryConvertLocation, String ovfTemplateDirConvertLocation,
boolean forceConvertToPool, String extraParams) {

logger.debug("Delegating the conversion of instance {} from VMware to KVM to the host {} using OVF {} on conversion datastore",
sourceVM, convertHost, ovfTemplateDirConvertLocation);

RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(sourceVM);
List<String> destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks(), serviceOffering, dataDiskOfferingMap);
Expand All @@ -2072,15 +2074,15 @@ private UnmanagedInstanceTO convertVmwareInstanceToKVMWithOVFOnConvertLocation(
cmd.setWait(timeoutSeconds);

return convertAndImportToKVM(cmd, convertHost, importHost, sourceVM,
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation);
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation, forceConvertToPool);
}

private UnmanagedInstanceTO convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(
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, String extraParams) {
String vcenterPassword, String datacenterName, boolean forceConvertToPool, String extraParams) {
logger.debug("Delegating the conversion of instance {} from VMware to KVM to the host {} after OVF export through ovftool", sourceVM, convertHost);

RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(sourceVMwareInstance.getName(), sourceVMwareInstance.getPath(), vcenterHost, vcenterUsername, vcenterPassword, datacenterName);
Expand All @@ -2099,14 +2101,15 @@ private UnmanagedInstanceTO convertVmwareInstanceToKVMAfterExportingOVFToConvert
cmd.setExtraParams(extraParams);
}
return convertAndImportToKVM(cmd, convertHost, importHost, sourceVM,
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation);
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation, forceConvertToPool);
}

private UnmanagedInstanceTO convertAndImportToKVM(ConvertInstanceCommand convertInstanceCommand, HostVO convertHost, HostVO importHost,
String sourceVM,
RemoteInstanceTO remoteInstanceTO,
List<String> destinationStoragePools,
DataStoreTO temporaryConvertLocation) {
DataStoreTO temporaryConvertLocation,
boolean forceConvertToPool) {
Answer convertAnswer;
try {
convertAnswer = agentManager.send(convertHost.getId(), convertInstanceCommand);
Expand All @@ -2128,7 +2131,7 @@ private UnmanagedInstanceTO convertAndImportToKVM(ConvertInstanceCommand convert
try {
ImportConvertedInstanceCommand importCmd = new ImportConvertedInstanceCommand(
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation,
((ConvertInstanceAnswer)convertAnswer).getTemporaryConvertUuid());
((ConvertInstanceAnswer)convertAnswer).getTemporaryConvertUuid(), forceConvertToPool);
importAnswer = agentManager.send(importHost.getId(), importCmd);
} catch (AgentUnavailableException | OperationTimedoutException e) {
String err = String.format(
Expand Down Expand Up @@ -2237,7 +2240,7 @@ private void logFailureAndThrowException(String msg) {

protected DataStoreTO selectInstanceConversionTemporaryLocation(Cluster destinationCluster,
HostVO convertHost,
Long convertStoragePoolId) {
Long convertStoragePoolId, boolean forceConvertToPool) {
if (convertStoragePoolId != null) {
StoragePoolVO selectedStoragePool = primaryDataStoreDao.findById(convertStoragePoolId);
if (selectedStoragePool == null) {
Expand All @@ -2252,10 +2255,12 @@ protected DataStoreTO selectInstanceConversionTemporaryLocation(Cluster destinat
logFailureAndThrowException(String.format("Cannot use the storage pool %s for the instance conversion as " +
"the host %s for conversion is in a different cluster", selectedStoragePool.getName(), convertHost.getName()));
}
if (selectedStoragePool.getScope() == ScopeType.HOST) {
logFailureAndThrowException(String.format("The storage pool %s is a local storage pool and not supported for temporary conversion location, cluster and zone wide NFS storage pools are supported", selectedStoragePool.getName()));
} else if (selectedStoragePool.getPoolType() != Storage.StoragePoolType.NetworkFilesystem) {
logFailureAndThrowException(String.format("The storage pool %s is not supported for temporary conversion location, only NFS storage pools are supported", selectedStoragePool.getName()));
if (!forceConvertToPool) {
if (selectedStoragePool.getScope() == ScopeType.HOST) {
logFailureAndThrowException(String.format("The storage pool %s is a local storage pool and not supported for temporary conversion location, cluster and zone wide NFS storage pools are supported", selectedStoragePool.getName()));
} else if (selectedStoragePool.getPoolType() != Storage.StoragePoolType.NetworkFilesystem) {
logFailureAndThrowException(String.format("The storage pool %s is not supported for temporary conversion location, only NFS storage pools are supported", selectedStoragePool.getName()));
}
}
return dataStoreManager.getPrimaryDataStore(convertStoragePoolId).getTO();
} else {
Expand Down
Loading
Loading