Skip to content

Commit c3b06da

Browse files
committed
Add Force converting directly to storage pool option
1 parent 9200dd0 commit c3b06da

File tree

7 files changed

+91
-42
lines changed

7 files changed

+91
-42
lines changed

api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportVmCmd.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
165165
description = "(VMware to KVM only) extra parameters to be passed on the virt-v2v command, if allowed by the administrator")
166166
private String extraParams;
167167

168+
@Parameter(name = "forceconverttopool", type = CommandType.BOOLEAN,
169+
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).")
170+
private Boolean forceConvertToPool;
171+
168172
/////////////////////////////////////////////////////
169173
/////////////////// Accessors ///////////////////////
170174
/////////////////////////////////////////////////////
@@ -258,6 +262,10 @@ public String getExtraParams() {
258262
return extraParams;
259263
}
260264

265+
public boolean getForceConvertToPool() {
266+
return BooleanUtils.toBooleanDefaultIfNull(forceConvertToPool, false);
267+
}
268+
261269
@Override
262270
public String getEventDescription() {
263271
String vmName = getName();

core/src/main/java/com/cloud/agent/api/ImportConvertedInstanceCommand.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,20 @@ public class ImportConvertedInstanceCommand extends Command {
2727
private List<String> destinationStoragePools;
2828
private DataStoreTO conversionTemporaryLocation;
2929
private String temporaryConvertUuid;
30+
private boolean forceConvertToPool;
3031

3132
public ImportConvertedInstanceCommand() {
3233
}
3334

3435
public ImportConvertedInstanceCommand(RemoteInstanceTO sourceInstance,
3536
List<String> destinationStoragePools,
36-
DataStoreTO conversionTemporaryLocation, String temporaryConvertUuid) {
37+
DataStoreTO conversionTemporaryLocation, String temporaryConvertUuid,
38+
boolean forceConvertToPool) {
3739
this.sourceInstance = sourceInstance;
3840
this.destinationStoragePools = destinationStoragePools;
3941
this.conversionTemporaryLocation = conversionTemporaryLocation;
4042
this.temporaryConvertUuid = temporaryConvertUuid;
43+
this.forceConvertToPool = forceConvertToPool;
4144
}
4245

4346
public RemoteInstanceTO getSourceInstance() {
@@ -56,6 +59,10 @@ public String getTemporaryConvertUuid() {
5659
return temporaryConvertUuid;
5760
}
5861

62+
public boolean isForceConvertToPool() {
63+
return forceConvertToPool;
64+
}
65+
5966
@Override
6067
public boolean executeInSequence() {
6168
return false;

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtImportConvertedInstanceCommandWrapper.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public Answer execute(ImportConvertedInstanceCommand cmd, LibvirtComputingResour
6767
List<String> destinationStoragePools = cmd.getDestinationStoragePools();
6868
DataStoreTO conversionTemporaryLocation = cmd.getConversionTemporaryLocation();
6969
final String temporaryConvertUuid = cmd.getTemporaryConvertUuid();
70+
final boolean forceConvertToPool = cmd.isForceConvertToPool();
7071

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

83-
List<KVMPhysicalDisk> destinationDisks = moveTemporaryDisksToDestination(temporaryDisks,
84-
destinationStoragePools, storagePoolMgr);
85-
86-
cleanupDisksAndDomainFromTemporaryLocation(temporaryDisks, temporaryStoragePool, temporaryConvertUuid);
84+
List<KVMPhysicalDisk> disks = null;
85+
if (forceConvertToPool) {
86+
// Force flag to use the conversion path, no need to move disks
87+
disks = temporaryDisks;
88+
} else {
89+
disks = moveTemporaryDisksToDestination(temporaryDisks,
90+
destinationStoragePools, storagePoolMgr);
91+
cleanupDisksAndDomainFromTemporaryLocation(temporaryDisks, temporaryStoragePool, temporaryConvertUuid);
92+
}
8793

8894
UnmanagedInstanceTO convertedInstanceTO = getConvertedUnmanagedInstance(temporaryConvertUuid,
89-
destinationDisks, xmlParser);
95+
disks, xmlParser);
9096
return new ImportConvertedInstanceAnswer(cmd, convertedInstanceTO);
9197
} catch (Exception e) {
9298
String error = String.format("Error converting instance %s from %s, due to: %s",

plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapperTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public void testExecuteConvertFailure() {
167167
Answer answer = convertInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
168168
Assert.assertFalse(answer.getResult());
169169
Mockito.verify(convertInstanceCommandWrapper).performInstanceConversion(Mockito.anyString(), Mockito.anyString(),
170-
Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyBoolean(), null);
170+
Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyBoolean(), Mockito.nullable(String.class));
171171
}
172172
}
173173
}

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

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,7 +1407,6 @@ private UserVmResponse baseImportInstance(ImportUnmanagedInstanceCmd cmd) {
14071407
throw new CloudRuntimeException("Please provide an import source for importing the VM");
14081408
}
14091409
String source = importVmCmd.getImportSource().toUpperCase();
1410-
String extraParams = ((ImportVmCmd) cmd).getExtraParams();
14111410
ImportSource importSource = Enum.valueOf(ImportSource.class, source);
14121411
if (ImportSource.VMWARE == importSource) {
14131412
userVm = importUnmanagedInstanceFromVmwareToKvm(zone, cluster,
@@ -1703,6 +1702,7 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster
17031702
Long importInstanceHostId = cmd.getImportInstanceHostId();
17041703
Long convertStoragePoolId = cmd.getConvertStoragePoolId();
17051704
String extraParams = cmd.getExtraParams();
1705+
boolean forceConvertToPool = cmd.getForceConvertToPool();
17061706

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

17431743
temporaryConvertLocation = selectInstanceConversionTemporaryLocation(
1744-
destinationCluster, convertHost, convertStoragePoolId);
1744+
destinationCluster, convertHost, convertStoragePoolId, forceConvertToPool);
17451745
List<StoragePoolVO> convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster, serviceOffering, dataDiskOfferingMap);
17461746
long importStartTime = System.currentTimeMillis();
17471747
importVMTaskVO = createImportVMTaskRecord(zone, owner, userId, displayName, vcenter, datacenterName, sourceVMName,
@@ -1768,14 +1768,14 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster
17681768
convertedInstance = convertVmwareInstanceToKVMWithOVFOnConvertLocation(sourceVMName,
17691769
sourceVMwareInstance, convertHost, importHost, convertStoragePools,
17701770
serviceOffering, dataDiskOfferingMap, temporaryConvertLocation,
1771-
ovfTemplateOnConvertLocation, extraParams);
1771+
ovfTemplateOnConvertLocation, forceConvertToPool, extraParams);
17721772
} else {
17731773
// Uses KVM Host for OVF export to temporary conversion location, through ovftool
17741774
updateImportVMTaskStep(importVMTaskVO, zone, owner, convertHost, importHost, ConvertingInstance);
17751775
convertedInstance = convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(
17761776
sourceVMName, sourceVMwareInstance, convertHost, importHost,
17771777
convertStoragePools, serviceOffering, dataDiskOfferingMap,
1778-
temporaryConvertLocation, vcenter, username, password, datacenterName, extraParams);
1778+
temporaryConvertLocation, vcenter, username, password, datacenterName, forceConvertToPool, extraParams);
17791779
}
17801780

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

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

20742076
return convertAndImportToKVM(cmd, convertHost, importHost, sourceVM,
2075-
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation);
2077+
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation, forceConvertToPool);
20762078
}
20772079

20782080
private UnmanagedInstanceTO convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(
20792081
String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost,
20802082
HostVO importHost, List<StoragePoolVO> convertStoragePools,
20812083
ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap,
20822084
DataStoreTO temporaryConvertLocation, String vcenterHost, String vcenterUsername,
2083-
String vcenterPassword, String datacenterName, String extraParams) {
2085+
String vcenterPassword, String datacenterName, boolean forceConvertToPool, String extraParams) {
20842086
logger.debug("Delegating the conversion of instance {} from VMware to KVM to the host {} after OVF export through ovftool", sourceVM, convertHost);
20852087

20862088
RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(sourceVMwareInstance.getName(), sourceVMwareInstance.getPath(), vcenterHost, vcenterUsername, vcenterPassword, datacenterName);
@@ -2099,14 +2101,15 @@ private UnmanagedInstanceTO convertVmwareInstanceToKVMAfterExportingOVFToConvert
20992101
cmd.setExtraParams(extraParams);
21002102
}
21012103
return convertAndImportToKVM(cmd, convertHost, importHost, sourceVM,
2102-
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation);
2104+
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation, forceConvertToPool);
21032105
}
21042106

21052107
private UnmanagedInstanceTO convertAndImportToKVM(ConvertInstanceCommand convertInstanceCommand, HostVO convertHost, HostVO importHost,
21062108
String sourceVM,
21072109
RemoteInstanceTO remoteInstanceTO,
21082110
List<String> destinationStoragePools,
2109-
DataStoreTO temporaryConvertLocation) {
2111+
DataStoreTO temporaryConvertLocation,
2112+
boolean forceConvertToPool) {
21102113
Answer convertAnswer;
21112114
try {
21122115
convertAnswer = agentManager.send(convertHost.getId(), convertInstanceCommand);
@@ -2128,7 +2131,7 @@ private UnmanagedInstanceTO convertAndImportToKVM(ConvertInstanceCommand convert
21282131
try {
21292132
ImportConvertedInstanceCommand importCmd = new ImportConvertedInstanceCommand(
21302133
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation,
2131-
((ConvertInstanceAnswer)convertAnswer).getTemporaryConvertUuid());
2134+
((ConvertInstanceAnswer)convertAnswer).getTemporaryConvertUuid(), forceConvertToPool);
21322135
importAnswer = agentManager.send(importHost.getId(), importCmd);
21332136
} catch (AgentUnavailableException | OperationTimedoutException e) {
21342137
String err = String.format(
@@ -2237,7 +2240,7 @@ private void logFailureAndThrowException(String msg) {
22372240

22382241
protected DataStoreTO selectInstanceConversionTemporaryLocation(Cluster destinationCluster,
22392242
HostVO convertHost,
2240-
Long convertStoragePoolId) {
2243+
Long convertStoragePoolId, boolean forceConvertToPool) {
22412244
if (convertStoragePoolId != null) {
22422245
StoragePoolVO selectedStoragePool = primaryDataStoreDao.findById(convertStoragePoolId);
22432246
if (selectedStoragePool == null) {
@@ -2252,10 +2255,12 @@ protected DataStoreTO selectInstanceConversionTemporaryLocation(Cluster destinat
22522255
logFailureAndThrowException(String.format("Cannot use the storage pool %s for the instance conversion as " +
22532256
"the host %s for conversion is in a different cluster", selectedStoragePool.getName(), convertHost.getName()));
22542257
}
2255-
if (selectedStoragePool.getScope() == ScopeType.HOST) {
2256-
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()));
2257-
} else if (selectedStoragePool.getPoolType() != Storage.StoragePoolType.NetworkFilesystem) {
2258-
logFailureAndThrowException(String.format("The storage pool %s is not supported for temporary conversion location, only NFS storage pools are supported", selectedStoragePool.getName()));
2258+
if (!forceConvertToPool) {
2259+
if (selectedStoragePool.getScope() == ScopeType.HOST) {
2260+
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()));
2261+
} else if (selectedStoragePool.getPoolType() != Storage.StoragePoolType.NetworkFilesystem) {
2262+
logFailureAndThrowException(String.format("The storage pool %s is not supported for temporary conversion location, only NFS storage pools are supported", selectedStoragePool.getName()));
2263+
}
22592264
}
22602265
return dataStoreManager.getPrimaryDataStore(convertStoragePoolId).getTO();
22612266
} else {

0 commit comments

Comments
 (0)