This is an automated email from the ASF dual-hosted git repository.
dahn pushed a commit to branch 4.19
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.19 by this push:
new 37eec061669 Allow VMWare import via another host (#9787)
37eec061669 is described below
commit 37eec061669ff63488bc2fa522806b367e47cb48
Author: Vishesh <[email protected]>
AuthorDate: Thu Nov 28 22:20:08 2024 +0530
Allow VMWare import via another host (#9787)
Co-authored-by: Suresh Kumar Anaparti <[email protected]>
---
.../org/apache/cloudstack/api/ApiConstants.java | 1 +
.../api/command/admin/vm/ImportVmCmd.java | 12 +-
.../com/cloud/agent/api/ConvertInstanceAnswer.java | 17 +-
.../cloud/agent/api/ConvertInstanceCommand.java | 11 +-
...wer.java => ImportConvertedInstanceAnswer.java} | 8 +-
.../agent/api/ImportConvertedInstanceCommand.java | 63 +++++
.../LibvirtConvertInstanceCommandWrapper.java | 235 ++---------------
...virtImportConvertedInstanceCommandWrapper.java} | 163 +-----------
.../LibvirtConvertInstanceCommandWrapperTest.java | 118 ---------
...ImportConvertedInstanceCommandWrapperTest.java} | 114 +++-----
.../cloudstack/vm/UnmanagedVMsManagerImpl.java | 183 ++++++++++---
.../cloudstack/vm/UnmanagedVMsManagerImplTest.java | 288 ++++++++++++++++++++-
ui/public/locales/en.json | 6 +-
ui/src/views/tools/ImportUnmanagedInstance.vue | 59 ++++-
ui/src/views/tools/ManageInstances.vue | 3 +-
15 files changed, 619 insertions(+), 662 deletions(-)
diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
index d6099ac4717..b9a4938b5b2 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -225,6 +225,7 @@ public class ApiConstants {
public static final String ICMP_TYPE = "icmptype";
public static final String ID = "id";
public static final String IDS = "ids";
+ public static final String IMPORT_INSTANCE_HOST_ID =
"importinstancehostid";
public static final String INDEX = "index";
public static final String INSTANCES_DISKS_STATS_RETENTION_ENABLED =
"instancesdisksstatsretentionenabled";
public static final String INSTANCES_DISKS_STATS_RETENTION_TIME =
"instancesdisksstatsretentiontime";
diff --git
a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportVmCmd.java
b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportVmCmd.java
index 945f861cd3e..5c82e5bbd97 100644
---
a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportVmCmd.java
+++
b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportVmCmd.java
@@ -146,15 +146,19 @@ public class ImportVmCmd extends
ImportUnmanagedInstanceCmd {
private String clusterName;
@Parameter(name = ApiConstants.CONVERT_INSTANCE_HOST_ID, type =
CommandType.UUID, entityType = HostResponse.class,
- description = "(only for importing VMs from VMware to KVM)
optional - the host to perform the virt-v2v migration from VMware to KVM.")
+ description = "(only for importing VMs from VMware to KVM)
optional - the host to perform the virt-v2v conversion from VMware to KVM.")
private Long convertInstanceHostId;
+ @Parameter(name = ApiConstants.IMPORT_INSTANCE_HOST_ID, type =
CommandType.UUID, entityType = HostResponse.class, since = "4.19.2",
+ description = "(only for importing VMs from VMware to KVM)
optional - the host to import the converted instance from VMware to KVM.")
+ private Long importInstanceHostId;
+
@Parameter(name = ApiConstants.CONVERT_INSTANCE_STORAGE_POOL_ID, type =
CommandType.UUID, entityType = StoragePoolResponse.class,
description = "(only for importing VMs from VMware to KVM)
optional - the temporary storage pool to perform the virt-v2v migration from
VMware to KVM.")
private Long convertStoragePoolId;
@Parameter(name = ApiConstants.FORCE_MS_TO_IMPORT_VM_FILES, type =
CommandType.BOOLEAN,
- description = "(only for importing VMs from VMware to KVM)
optional - if true, forces MS to import VM file(s) to temporary storage, else
uses KVM Host if ovftool is available, falls back to MS if not.")
+ description = "(only for importing VMs from VMware to KVM)
optional - if true, forces MS to export OVF from VMware to temporary storage,
else uses KVM Host if ovftool is available, falls back to MS if not.")
private Boolean forceMsToImportVmFiles;
/////////////////////////////////////////////////////
@@ -201,6 +205,10 @@ public class ImportVmCmd extends
ImportUnmanagedInstanceCmd {
return convertInstanceHostId;
}
+ public Long getImportInstanceHostId() {
+ return importInstanceHostId;
+ }
+
public Long getConvertStoragePoolId() {
return convertStoragePoolId;
}
diff --git a/core/src/main/java/com/cloud/agent/api/ConvertInstanceAnswer.java
b/core/src/main/java/com/cloud/agent/api/ConvertInstanceAnswer.java
index 829888570a6..8092ab9b43f 100644
--- a/core/src/main/java/com/cloud/agent/api/ConvertInstanceAnswer.java
+++ b/core/src/main/java/com/cloud/agent/api/ConvertInstanceAnswer.java
@@ -16,25 +16,20 @@
// under the License.
package com.cloud.agent.api;
-import org.apache.cloudstack.vm.UnmanagedInstanceTO;
-
public class ConvertInstanceAnswer extends Answer {
+ private String temporaryConvertUuid;
+
public ConvertInstanceAnswer() {
super();
}
- private UnmanagedInstanceTO convertedInstance;
-
- public ConvertInstanceAnswer(Command command, boolean success, String
details) {
- super(command, success, details);
- }
- public ConvertInstanceAnswer(Command command, UnmanagedInstanceTO
convertedInstance) {
+ public ConvertInstanceAnswer(Command command, String temporaryConvertUuid)
{
super(command, true, "");
- this.convertedInstance = convertedInstance;
+ this.temporaryConvertUuid = temporaryConvertUuid;
}
- public UnmanagedInstanceTO getConvertedInstance() {
- return convertedInstance;
+ public String getTemporaryConvertUuid() {
+ return temporaryConvertUuid;
}
}
diff --git a/core/src/main/java/com/cloud/agent/api/ConvertInstanceCommand.java
b/core/src/main/java/com/cloud/agent/api/ConvertInstanceCommand.java
index b8250903f85..f938d0ac55d 100644
--- a/core/src/main/java/com/cloud/agent/api/ConvertInstanceCommand.java
+++ b/core/src/main/java/com/cloud/agent/api/ConvertInstanceCommand.java
@@ -20,13 +20,10 @@ import com.cloud.agent.api.to.DataStoreTO;
import com.cloud.agent.api.to.RemoteInstanceTO;
import com.cloud.hypervisor.Hypervisor;
-import java.util.List;
-
public class ConvertInstanceCommand extends Command {
private RemoteInstanceTO sourceInstance;
private Hypervisor.HypervisorType destinationHypervisorType;
- private List<String> destinationStoragePools;
private DataStoreTO conversionTemporaryLocation;
private String templateDirOnConversionLocation;
private boolean checkConversionSupport;
@@ -36,12 +33,10 @@ public class ConvertInstanceCommand extends Command {
public ConvertInstanceCommand() {
}
- public ConvertInstanceCommand(RemoteInstanceTO sourceInstance,
Hypervisor.HypervisorType destinationHypervisorType,
- List<String> destinationStoragePools,
DataStoreTO conversionTemporaryLocation,
+ public ConvertInstanceCommand(RemoteInstanceTO sourceInstance,
Hypervisor.HypervisorType destinationHypervisorType, DataStoreTO
conversionTemporaryLocation,
String templateDirOnConversionLocation,
boolean checkConversionSupport, boolean exportOvfToConversionLocation) {
this.sourceInstance = sourceInstance;
this.destinationHypervisorType = destinationHypervisorType;
- this.destinationStoragePools = destinationStoragePools;
this.conversionTemporaryLocation = conversionTemporaryLocation;
this.templateDirOnConversionLocation = templateDirOnConversionLocation;
this.checkConversionSupport = checkConversionSupport;
@@ -56,10 +51,6 @@ public class ConvertInstanceCommand extends Command {
return destinationHypervisorType;
}
- public List<String> getDestinationStoragePools() {
- return destinationStoragePools;
- }
-
public DataStoreTO getConversionTemporaryLocation() {
return conversionTemporaryLocation;
}
diff --git a/core/src/main/java/com/cloud/agent/api/ConvertInstanceAnswer.java
b/core/src/main/java/com/cloud/agent/api/ImportConvertedInstanceAnswer.java
similarity index 80%
copy from core/src/main/java/com/cloud/agent/api/ConvertInstanceAnswer.java
copy to
core/src/main/java/com/cloud/agent/api/ImportConvertedInstanceAnswer.java
index 829888570a6..2a8f8704e3f 100644
--- a/core/src/main/java/com/cloud/agent/api/ConvertInstanceAnswer.java
+++ b/core/src/main/java/com/cloud/agent/api/ImportConvertedInstanceAnswer.java
@@ -18,18 +18,18 @@ package com.cloud.agent.api;
import org.apache.cloudstack.vm.UnmanagedInstanceTO;
-public class ConvertInstanceAnswer extends Answer {
+public class ImportConvertedInstanceAnswer extends Answer {
- public ConvertInstanceAnswer() {
+ public ImportConvertedInstanceAnswer() {
super();
}
private UnmanagedInstanceTO convertedInstance;
- public ConvertInstanceAnswer(Command command, boolean success, String
details) {
+ public ImportConvertedInstanceAnswer(Command command, boolean success,
String details) {
super(command, success, details);
}
- public ConvertInstanceAnswer(Command command, UnmanagedInstanceTO
convertedInstance) {
+ public ImportConvertedInstanceAnswer(Command command, UnmanagedInstanceTO
convertedInstance) {
super(command, true, "");
this.convertedInstance = convertedInstance;
}
diff --git
a/core/src/main/java/com/cloud/agent/api/ImportConvertedInstanceCommand.java
b/core/src/main/java/com/cloud/agent/api/ImportConvertedInstanceCommand.java
new file mode 100644
index 00000000000..9d50e852ced
--- /dev/null
+++ b/core/src/main/java/com/cloud/agent/api/ImportConvertedInstanceCommand.java
@@ -0,0 +1,63 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.agent.api;
+
+import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.RemoteInstanceTO;
+
+import java.util.List;
+
+public class ImportConvertedInstanceCommand extends Command {
+
+ private RemoteInstanceTO sourceInstance;
+ private List<String> destinationStoragePools;
+ private DataStoreTO conversionTemporaryLocation;
+ private String temporaryConvertUuid;
+
+ public ImportConvertedInstanceCommand() {
+ }
+
+ public ImportConvertedInstanceCommand(RemoteInstanceTO sourceInstance,
+ List<String> destinationStoragePools,
+ DataStoreTO
conversionTemporaryLocation, String temporaryConvertUuid) {
+ this.sourceInstance = sourceInstance;
+ this.destinationStoragePools = destinationStoragePools;
+ this.conversionTemporaryLocation = conversionTemporaryLocation;
+ this.temporaryConvertUuid = temporaryConvertUuid;
+ }
+
+ public RemoteInstanceTO getSourceInstance() {
+ return sourceInstance;
+ }
+
+ public List<String> getDestinationStoragePools() {
+ return destinationStoragePools;
+ }
+
+ public DataStoreTO getConversionTemporaryLocation() {
+ return conversionTemporaryLocation;
+ }
+
+ public String getTemporaryConvertUuid() {
+ return temporaryConvertUuid;
+ }
+
+ @Override
+ public boolean executeInSequence() {
+ return false;
+ }
+}
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapper.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapper.java
index f6f6ea1082d..e6654b1ffc5 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapper.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapper.java
@@ -18,44 +18,29 @@
//
package com.cloud.hypervisor.kvm.resource.wrapper;
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.Charset;
-import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
-import java.util.stream.Collectors;
+import com.cloud.agent.api.ConvertInstanceAnswer;
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
-import org.apache.cloudstack.vm.UnmanagedInstanceTO;
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import com.cloud.agent.api.Answer;
-import com.cloud.agent.api.ConvertInstanceAnswer;
import com.cloud.agent.api.ConvertInstanceCommand;
import com.cloud.agent.api.to.DataStoreTO;
import com.cloud.agent.api.to.NfsTO;
import com.cloud.agent.api.to.RemoteInstanceTO;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
-import com.cloud.hypervisor.kvm.resource.LibvirtDomainXMLParser;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef;
-import com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk;
import com.cloud.hypervisor.kvm.storage.KVMStoragePool;
import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager;
import com.cloud.resource.CommandWrapper;
import com.cloud.resource.ResourceWrapper;
-import com.cloud.storage.Storage;
import com.cloud.utils.FileUtil;
-import com.cloud.utils.Pair;
-import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.OutputInterpreter;
import com.cloud.utils.script.Script;
@@ -73,7 +58,6 @@ public class LibvirtConvertInstanceCommandWrapper extends
CommandWrapper<Convert
Hypervisor.HypervisorType sourceHypervisorType =
sourceInstance.getHypervisorType();
String sourceInstanceName = sourceInstance.getInstanceName();
Hypervisor.HypervisorType destinationHypervisorType =
cmd.getDestinationHypervisorType();
- List<String> destinationStoragePools =
cmd.getDestinationStoragePools();
DataStoreTO conversionTemporaryLocation =
cmd.getConversionTemporaryLocation();
long timeout = (long) cmd.getWait() * 1000;
@@ -81,7 +65,7 @@ public class LibvirtConvertInstanceCommandWrapper extends
CommandWrapper<Convert
String msg = String.format("Cannot convert the instance %s from
VMware as the virt-v2v binary is not found. " +
"Please install virt-v2v%s on the host before attempting
the instance conversion.", sourceInstanceName, serverResource.isUbuntuHost()?
", nbdkit" : "");
s_logger.info(msg);
- return new ConvertInstanceAnswer(cmd, false, msg);
+ return new Answer(cmd, false, msg);
}
if (!areSourceAndDestinationHypervisorsSupported(sourceHypervisorType,
destinationHypervisorType)) {
@@ -89,7 +73,7 @@ public class LibvirtConvertInstanceCommandWrapper extends
CommandWrapper<Convert
String.format("The destination hypervisor type is %s, KVM
was expected, cannot handle it", destinationHypervisorType) :
String.format("The source hypervisor type %s is not
supported for KVM conversion", sourceHypervisorType);
s_logger.error(err);
- return new ConvertInstanceAnswer(cmd, false, err);
+ return new Answer(cmd, false, err);
}
final KVMStoragePoolManager storagePoolMgr =
serverResource.getStoragePoolMgr();
@@ -104,7 +88,7 @@ public class LibvirtConvertInstanceCommandWrapper extends
CommandWrapper<Convert
if (StringUtils.isBlank(exportInstanceOVAUrl)) {
String err = String.format("Couldn't export OVA for the VM %s,
due to empty url", sourceInstanceName);
s_logger.error(err);
- return new ConvertInstanceAnswer(cmd, false, err);
+ return new Answer(cmd, false, err);
}
int noOfThreads = cmd.getThreadsCountToExportOvf();
@@ -118,7 +102,7 @@ public class LibvirtConvertInstanceCommandWrapper extends
CommandWrapper<Convert
if (!ovfExported) {
String err = String.format("Export OVA for the VM %s failed",
sourceInstanceName);
s_logger.error(err);
- return new ConvertInstanceAnswer(cmd, false, err);
+ return new Answer(cmd, false, err);
}
sourceOVFDirPath = String.format("%s%s/", sourceOVFDirPath,
sourceInstanceName);
} else {
@@ -130,42 +114,33 @@ public class LibvirtConvertInstanceCommandWrapper extends
CommandWrapper<Convert
final String temporaryConvertUuid = UUID.randomUUID().toString();
boolean verboseModeEnabled =
serverResource.isConvertInstanceVerboseModeEnabled();
+ boolean cleanupSecondaryStorage = false;
try {
boolean result = performInstanceConversion(sourceOVFDirPath,
temporaryConvertPath, temporaryConvertUuid,
timeout, verboseModeEnabled);
if (!result) {
- String err = String.format("The virt-v2v conversion for the
OVF %s failed. " +
- "Please check the agent logs for the virt-v2v
output", ovfTemplateDirOnConversionLocation);
+ String err = String.format(
+ "The virt-v2v conversion for the OVF %s failed. Please
check the agent logs " +
+ "for the virt-v2v output. Please try on a
different kvm host which " +
+ "has a different virt-v2v version.",
+ ovfTemplateDirOnConversionLocation);
s_logger.error(err);
- return new ConvertInstanceAnswer(cmd, false, err);
+ return new Answer(cmd, false, err);
}
- String convertedBasePath = String.format("%s/%s",
temporaryConvertPath, temporaryConvertUuid);
- LibvirtDomainXMLParser xmlParser =
parseMigratedVMXmlDomain(convertedBasePath);
-
- List<KVMPhysicalDisk> temporaryDisks = xmlParser == null ?
-
getTemporaryDisksWithPrefixFromTemporaryPool(temporaryStoragePool,
temporaryConvertPath, temporaryConvertUuid) :
- getTemporaryDisksFromParsedXml(temporaryStoragePool,
xmlParser, convertedBasePath);
-
- List<KVMPhysicalDisk> destinationDisks =
moveTemporaryDisksToDestination(temporaryDisks,
- destinationStoragePools, storagePoolMgr);
-
- cleanupDisksAndDomainFromTemporaryLocation(temporaryDisks,
temporaryStoragePool, temporaryConvertUuid);
-
- UnmanagedInstanceTO convertedInstanceTO =
getConvertedUnmanagedInstance(temporaryConvertUuid,
- destinationDisks, xmlParser);
- return new ConvertInstanceAnswer(cmd, convertedInstanceTO);
+ return new ConvertInstanceAnswer(cmd, temporaryConvertUuid);
} catch (Exception e) {
String error = String.format("Error converting instance %s from
%s, due to: %s",
sourceInstanceName, sourceHypervisorType, e.getMessage());
s_logger.error(error, e);
- return new ConvertInstanceAnswer(cmd, false, error);
+ cleanupSecondaryStorage = true;
+ return new Answer(cmd, false, error);
} finally {
if (ovfExported &&
StringUtils.isNotBlank(ovfTemplateDirOnConversionLocation)) {
String sourceOVFDir = String.format("%s/%s",
temporaryConvertPath, ovfTemplateDirOnConversionLocation);
s_logger.debug("Cleaning up exported OVA at dir " +
sourceOVFDir);
FileUtil.deletePath(sourceOVFDir);
}
- if (conversionTemporaryLocation instanceof NfsTO) {
+ if (cleanupSecondaryStorage && conversionTemporaryLocation
instanceof NfsTO) {
s_logger.debug("Cleaning up secondary storage temporary
location");
storagePoolMgr.deleteStoragePool(temporaryStoragePool.getType(),
temporaryStoragePool.getUuid());
}
@@ -209,55 +184,6 @@ public class LibvirtConvertInstanceCommandWrapper extends
CommandWrapper<Convert
encodedUsername, encodedPassword, vcenter, datacenter, vm);
}
- protected List<KVMPhysicalDisk>
getTemporaryDisksFromParsedXml(KVMStoragePool pool, LibvirtDomainXMLParser
xmlParser, String convertedBasePath) {
- List<LibvirtVMDef.DiskDef> disksDefs = xmlParser.getDisks();
- disksDefs = disksDefs.stream().filter(x -> x.getDiskType() ==
LibvirtVMDef.DiskDef.DiskType.FILE &&
- x.getDeviceType() ==
LibvirtVMDef.DiskDef.DeviceType.DISK).collect(Collectors.toList());
- if (CollectionUtils.isEmpty(disksDefs)) {
- String err = String.format("Cannot find any disk defined on the
converted XML domain %s.xml", convertedBasePath);
- s_logger.error(err);
- throw new CloudRuntimeException(err);
- }
- sanitizeDisksPath(disksDefs);
- return getPhysicalDisksFromDefPaths(disksDefs, pool);
- }
-
- private List<KVMPhysicalDisk>
getPhysicalDisksFromDefPaths(List<LibvirtVMDef.DiskDef> disksDefs,
KVMStoragePool pool) {
- List<KVMPhysicalDisk> disks = new ArrayList<>();
- for (LibvirtVMDef.DiskDef diskDef : disksDefs) {
- KVMPhysicalDisk physicalDisk =
pool.getPhysicalDisk(diskDef.getDiskPath());
- disks.add(physicalDisk);
- }
- return disks;
- }
-
- protected List<KVMPhysicalDisk>
getTemporaryDisksWithPrefixFromTemporaryPool(KVMStoragePool pool, String path,
String prefix) {
- String msg = String.format("Could not parse correctly the converted
XML domain, checking for disks on %s with prefix %s", path, prefix);
- s_logger.info(msg);
- pool.refresh();
- List<KVMPhysicalDisk> disksWithPrefix = pool.listPhysicalDisks()
- .stream()
- .filter(x -> x.getName().startsWith(prefix) &&
!x.getName().endsWith(".xml"))
- .collect(Collectors.toList());
- if (CollectionUtils.isEmpty(disksWithPrefix)) {
- msg = String.format("Could not find any converted disk with prefix
%s on temporary location %s", prefix, path);
- s_logger.error(msg);
- throw new CloudRuntimeException(msg);
- }
- return disksWithPrefix;
- }
-
- private void
cleanupDisksAndDomainFromTemporaryLocation(List<KVMPhysicalDisk> disks,
- KVMStoragePool
temporaryStoragePool,
- String
temporaryConvertUuid) {
- for (KVMPhysicalDisk disk : disks) {
- s_logger.info(String.format("Cleaning up temporary disk %s after
conversion from temporary location", disk.getName()));
- temporaryStoragePool.deletePhysicalDisk(disk.getName(),
Storage.ImageFormat.QCOW2);
- }
- s_logger.info(String.format("Cleaning up temporary domain %s after
conversion from temporary location", temporaryConvertUuid));
- FileUtil.deleteFiles(temporaryStoragePool.getLocalPath(),
temporaryConvertUuid, ".xml");
- }
-
protected void sanitizeDisksPath(List<LibvirtVMDef.DiskDef> disks) {
for (LibvirtVMDef.DiskDef disk : disks) {
String[] diskPathParts = disk.getDiskPath().split("/");
@@ -266,114 +192,6 @@ public class LibvirtConvertInstanceCommandWrapper extends
CommandWrapper<Convert
}
}
- protected List<KVMPhysicalDisk>
moveTemporaryDisksToDestination(List<KVMPhysicalDisk> temporaryDisks,
- List<String>
destinationStoragePools,
-
KVMStoragePoolManager storagePoolMgr) {
- List<KVMPhysicalDisk> targetDisks = new ArrayList<>();
- if (temporaryDisks.size() != destinationStoragePools.size()) {
- String warn = String.format("Discrepancy between the converted
instance disks (%s) " +
- "and the expected number of disks (%s)",
temporaryDisks.size(), destinationStoragePools.size());
- s_logger.warn(warn);
- }
- for (int i = 0; i < temporaryDisks.size(); i++) {
- String poolPath = destinationStoragePools.get(i);
- KVMStoragePool destinationPool =
storagePoolMgr.getStoragePool(Storage.StoragePoolType.NetworkFilesystem,
poolPath);
- if (destinationPool == null) {
- String err = String.format("Could not find a storage pool by
URI: %s", poolPath);
- s_logger.error(err);
- continue;
- }
- if (destinationPool.getType() !=
Storage.StoragePoolType.NetworkFilesystem) {
- String err = String.format("Storage pool by URI: %s is not an
NFS storage", poolPath);
- s_logger.error(err);
- continue;
- }
- KVMPhysicalDisk sourceDisk = temporaryDisks.get(i);
- if (s_logger.isDebugEnabled()) {
- String msg = String.format("Trying to copy converted instance
disk number %s from the temporary location %s" +
- " to destination storage pool %s", i,
sourceDisk.getPool().getLocalPath(), destinationPool.getUuid());
- s_logger.debug(msg);
- }
-
- String destinationName = UUID.randomUUID().toString();
-
- KVMPhysicalDisk destinationDisk =
storagePoolMgr.copyPhysicalDisk(sourceDisk, destinationName, destinationPool,
7200 * 1000);
- targetDisks.add(destinationDisk);
- }
- return targetDisks;
- }
-
- private UnmanagedInstanceTO getConvertedUnmanagedInstance(String baseName,
-
List<KVMPhysicalDisk> vmDisks,
-
LibvirtDomainXMLParser xmlParser) {
- UnmanagedInstanceTO instanceTO = new UnmanagedInstanceTO();
- instanceTO.setName(baseName);
- instanceTO.setDisks(getUnmanagedInstanceDisks(vmDisks, xmlParser));
- instanceTO.setNics(getUnmanagedInstanceNics(xmlParser));
- return instanceTO;
- }
-
- private List<UnmanagedInstanceTO.Nic>
getUnmanagedInstanceNics(LibvirtDomainXMLParser xmlParser) {
- List<UnmanagedInstanceTO.Nic> nics = new ArrayList<>();
- if (xmlParser != null) {
- List<LibvirtVMDef.InterfaceDef> interfaces =
xmlParser.getInterfaces();
- for (LibvirtVMDef.InterfaceDef interfaceDef : interfaces) {
- UnmanagedInstanceTO.Nic nic = new UnmanagedInstanceTO.Nic();
- nic.setMacAddress(interfaceDef.getMacAddress());
- nic.setNicId(interfaceDef.getBrName());
- nic.setAdapterType(interfaceDef.getModel().toString());
- nics.add(nic);
- }
- }
- return nics;
- }
-
- protected List<UnmanagedInstanceTO.Disk>
getUnmanagedInstanceDisks(List<KVMPhysicalDisk> vmDisks, LibvirtDomainXMLParser
xmlParser) {
- List<UnmanagedInstanceTO.Disk> instanceDisks = new ArrayList<>();
- List<LibvirtVMDef.DiskDef> diskDefs = xmlParser != null ?
xmlParser.getDisks() : null;
- for (int i = 0; i< vmDisks.size(); i++) {
- KVMPhysicalDisk physicalDisk = vmDisks.get(i);
- KVMStoragePool storagePool = physicalDisk.getPool();
- UnmanagedInstanceTO.Disk disk = new UnmanagedInstanceTO.Disk();
- disk.setPosition(i);
- Pair<String, String> storagePoolHostAndPath =
getNfsStoragePoolHostAndPath(storagePool);
- disk.setDatastoreHost(storagePoolHostAndPath.first());
- disk.setDatastorePath(storagePoolHostAndPath.second());
- disk.setDatastoreName(storagePool.getUuid());
- disk.setDatastoreType(storagePool.getType().name());
- disk.setCapacity(physicalDisk.getVirtualSize());
- disk.setFileBaseName(physicalDisk.getName());
- if (CollectionUtils.isNotEmpty(diskDefs)) {
- LibvirtVMDef.DiskDef diskDef = diskDefs.get(i);
- disk.setController(diskDef.getBusType() != null ?
diskDef.getBusType().toString() :
LibvirtVMDef.DiskDef.DiskBus.VIRTIO.toString());
- } else {
- // If the job is finished but we cannot parse the XML, the
guest VM can use the virtio driver
-
disk.setController(LibvirtVMDef.DiskDef.DiskBus.VIRTIO.toString());
- }
- instanceDisks.add(disk);
- }
- return instanceDisks;
- }
-
- protected Pair<String, String> getNfsStoragePoolHostAndPath(KVMStoragePool
storagePool) {
- String sourceHostIp = null;
- String sourcePath = null;
- List<String[]> commands = new ArrayList<>();
- commands.add(new String[]{Script.getExecutableAbsolutePath("mount")});
- commands.add(new String[]{Script.getExecutableAbsolutePath("grep"),
storagePool.getLocalPath()});
- String storagePoolMountPoint = Script.executePipedCommands(commands,
0).second();
- s_logger.debug(String.format("NFS Storage pool: %s - local path: %s,
mount point: %s", storagePool.getUuid(), storagePool.getLocalPath(),
storagePoolMountPoint));
- if (StringUtils.isNotEmpty(storagePoolMountPoint)) {
- String[] res = storagePoolMountPoint.strip().split(" ");
- res = res[0].split(":");
- if (res.length > 1) {
- sourceHostIp = res[0].strip();
- sourcePath = res[1].strip();
- }
- }
- return new Pair<>(sourceHostIp, sourcePath);
- }
-
private boolean exportOVAFromVMOnVcenter(String vmExportUrl,
String targetOvfDir,
int noOfThreads,
@@ -416,27 +234,6 @@ public class LibvirtConvertInstanceCommandWrapper extends
CommandWrapper<Convert
return exitValue == 0;
}
- protected LibvirtDomainXMLParser parseMigratedVMXmlDomain(String
installPath) throws IOException {
- String xmlPath = String.format("%s.xml", installPath);
- if (!new File(xmlPath).exists()) {
- String err = String.format("Conversion failed. Unable to find the
converted XML domain, expected %s", xmlPath);
- s_logger.error(err);
- throw new CloudRuntimeException(err);
- }
- InputStream is = new BufferedInputStream(new FileInputStream(xmlPath));
- String xml = IOUtils.toString(is, Charset.defaultCharset());
- final LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
- try {
- parser.parseDomainXML(xml);
- return parser;
- } catch (RuntimeException e) {
- String err = String.format("Error parsing the converted instance
XML domain at %s: %s", xmlPath, e.getMessage());
- s_logger.error(err, e);
- s_logger.debug(xml);
- return null;
- }
- }
-
protected String encodeUsername(String username) {
return URLEncoder.encode(username, Charset.defaultCharset());
}
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapper.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtImportConvertedInstanceCommandWrapper.java
similarity index 64%
copy from
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapper.java
copy to
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtImportConvertedInstanceCommandWrapper.java
index f6f6ea1082d..3af41253b92 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapper.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtImportConvertedInstanceCommandWrapper.java
@@ -23,7 +23,6 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
@@ -38,8 +37,8 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import com.cloud.agent.api.Answer;
-import com.cloud.agent.api.ConvertInstanceAnswer;
-import com.cloud.agent.api.ConvertInstanceCommand;
+import com.cloud.agent.api.ImportConvertedInstanceAnswer;
+import com.cloud.agent.api.ImportConvertedInstanceCommand;
import com.cloud.agent.api.to.DataStoreTO;
import com.cloud.agent.api.to.NfsTO;
import com.cloud.agent.api.to.RemoteInstanceTO;
@@ -56,89 +55,27 @@ import com.cloud.storage.Storage;
import com.cloud.utils.FileUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException;
-import com.cloud.utils.script.OutputInterpreter;
import com.cloud.utils.script.Script;
-@ResourceWrapper(handles = ConvertInstanceCommand.class)
-public class LibvirtConvertInstanceCommandWrapper extends
CommandWrapper<ConvertInstanceCommand, Answer, LibvirtComputingResource> {
+@ResourceWrapper(handles = ImportConvertedInstanceCommand.class)
+public class LibvirtImportConvertedInstanceCommandWrapper extends
CommandWrapper<ImportConvertedInstanceCommand, Answer,
LibvirtComputingResource> {
- private static final Logger s_logger =
Logger.getLogger(LibvirtConvertInstanceCommandWrapper.class);
-
- private static final List<Hypervisor.HypervisorType>
supportedInstanceConvertSourceHypervisors =
- List.of(Hypervisor.HypervisorType.VMware);
+ private static final Logger s_logger =
Logger.getLogger(LibvirtImportConvertedInstanceCommandWrapper.class);
@Override
- public Answer execute(ConvertInstanceCommand cmd, LibvirtComputingResource
serverResource) {
+ public Answer execute(ImportConvertedInstanceCommand cmd,
LibvirtComputingResource serverResource) {
RemoteInstanceTO sourceInstance = cmd.getSourceInstance();
Hypervisor.HypervisorType sourceHypervisorType =
sourceInstance.getHypervisorType();
String sourceInstanceName = sourceInstance.getInstanceName();
- Hypervisor.HypervisorType destinationHypervisorType =
cmd.getDestinationHypervisorType();
List<String> destinationStoragePools =
cmd.getDestinationStoragePools();
DataStoreTO conversionTemporaryLocation =
cmd.getConversionTemporaryLocation();
- long timeout = (long) cmd.getWait() * 1000;
-
- if (cmd.getCheckConversionSupport() &&
!serverResource.hostSupportsInstanceConversion()) {
- String msg = String.format("Cannot convert the instance %s from
VMware as the virt-v2v binary is not found. " +
- "Please install virt-v2v%s on the host before attempting
the instance conversion.", sourceInstanceName, serverResource.isUbuntuHost()?
", nbdkit" : "");
- s_logger.info(msg);
- return new ConvertInstanceAnswer(cmd, false, msg);
- }
-
- if (!areSourceAndDestinationHypervisorsSupported(sourceHypervisorType,
destinationHypervisorType)) {
- String err = destinationHypervisorType !=
Hypervisor.HypervisorType.KVM ?
- String.format("The destination hypervisor type is %s, KVM
was expected, cannot handle it", destinationHypervisorType) :
- String.format("The source hypervisor type %s is not
supported for KVM conversion", sourceHypervisorType);
- s_logger.error(err);
- return new ConvertInstanceAnswer(cmd, false, err);
- }
+ final String temporaryConvertUuid = cmd.getTemporaryConvertUuid();
final KVMStoragePoolManager storagePoolMgr =
serverResource.getStoragePoolMgr();
KVMStoragePool temporaryStoragePool =
getTemporaryStoragePool(conversionTemporaryLocation, storagePoolMgr);
final String temporaryConvertPath =
temporaryStoragePool.getLocalPath();
- String ovfTemplateDirOnConversionLocation;
- String sourceOVFDirPath;
- boolean ovfExported = false;
- if (cmd.getExportOvfToConversionLocation()) {
- String exportInstanceOVAUrl =
getExportInstanceOVAUrl(sourceInstance);
- if (StringUtils.isBlank(exportInstanceOVAUrl)) {
- String err = String.format("Couldn't export OVA for the VM %s,
due to empty url", sourceInstanceName);
- s_logger.error(err);
- return new ConvertInstanceAnswer(cmd, false, err);
- }
-
- int noOfThreads = cmd.getThreadsCountToExportOvf();
- if (noOfThreads > 1 &&
!serverResource.ovfExportToolSupportsParallelThreads()) {
- noOfThreads = 0;
- }
- ovfTemplateDirOnConversionLocation = UUID.randomUUID().toString();
-
temporaryStoragePool.createFolder(ovfTemplateDirOnConversionLocation);
- sourceOVFDirPath = String.format("%s/%s/", temporaryConvertPath,
ovfTemplateDirOnConversionLocation);
- ovfExported = exportOVAFromVMOnVcenter(exportInstanceOVAUrl,
sourceOVFDirPath, noOfThreads, timeout);
- if (!ovfExported) {
- String err = String.format("Export OVA for the VM %s failed",
sourceInstanceName);
- s_logger.error(err);
- return new ConvertInstanceAnswer(cmd, false, err);
- }
- sourceOVFDirPath = String.format("%s%s/", sourceOVFDirPath,
sourceInstanceName);
- } else {
- ovfTemplateDirOnConversionLocation =
cmd.getTemplateDirOnConversionLocation();
- sourceOVFDirPath = String.format("%s/%s/", temporaryConvertPath,
ovfTemplateDirOnConversionLocation);
- }
-
- s_logger.info(String.format("Attempting to convert the OVF %s of the
instance %s from %s to KVM", ovfTemplateDirOnConversionLocation,
sourceInstanceName, sourceHypervisorType));
- final String temporaryConvertUuid = UUID.randomUUID().toString();
- boolean verboseModeEnabled =
serverResource.isConvertInstanceVerboseModeEnabled();
-
try {
- boolean result = performInstanceConversion(sourceOVFDirPath,
temporaryConvertPath, temporaryConvertUuid,
- timeout, verboseModeEnabled);
- if (!result) {
- String err = String.format("The virt-v2v conversion for the
OVF %s failed. " +
- "Please check the agent logs for the virt-v2v
output", ovfTemplateDirOnConversionLocation);
- s_logger.error(err);
- return new ConvertInstanceAnswer(cmd, false, err);
- }
String convertedBasePath = String.format("%s/%s",
temporaryConvertPath, temporaryConvertUuid);
LibvirtDomainXMLParser xmlParser =
parseMigratedVMXmlDomain(convertedBasePath);
@@ -153,18 +90,13 @@ public class LibvirtConvertInstanceCommandWrapper extends
CommandWrapper<Convert
UnmanagedInstanceTO convertedInstanceTO =
getConvertedUnmanagedInstance(temporaryConvertUuid,
destinationDisks, xmlParser);
- return new ConvertInstanceAnswer(cmd, convertedInstanceTO);
+ return new ImportConvertedInstanceAnswer(cmd, convertedInstanceTO);
} catch (Exception e) {
String error = String.format("Error converting instance %s from
%s, due to: %s",
sourceInstanceName, sourceHypervisorType, e.getMessage());
s_logger.error(error, e);
- return new ConvertInstanceAnswer(cmd, false, error);
+ return new ImportConvertedInstanceAnswer(cmd, false, error);
} finally {
- if (ovfExported &&
StringUtils.isNotBlank(ovfTemplateDirOnConversionLocation)) {
- String sourceOVFDir = String.format("%s/%s",
temporaryConvertPath, ovfTemplateDirOnConversionLocation);
- s_logger.debug("Cleaning up exported OVA at dir " +
sourceOVFDir);
- FileUtil.deletePath(sourceOVFDir);
- }
if (conversionTemporaryLocation instanceof NfsTO) {
s_logger.debug("Cleaning up secondary storage temporary
location");
storagePoolMgr.deleteStoragePool(temporaryStoragePool.getType(),
temporaryStoragePool.getUuid());
@@ -182,33 +114,6 @@ public class LibvirtConvertInstanceCommandWrapper extends
CommandWrapper<Convert
}
}
- protected boolean
areSourceAndDestinationHypervisorsSupported(Hypervisor.HypervisorType
sourceHypervisorType,
-
Hypervisor.HypervisorType destinationHypervisorType) {
- return destinationHypervisorType == Hypervisor.HypervisorType.KVM &&
-
supportedInstanceConvertSourceHypervisors.contains(sourceHypervisorType);
- }
-
- private String getExportInstanceOVAUrl(RemoteInstanceTO sourceInstance) {
- String url = null;
- if (sourceInstance.getHypervisorType() ==
Hypervisor.HypervisorType.VMware) {
- url = getExportOVAUrlFromRemoteInstance(sourceInstance);
- }
- return url;
- }
-
- private String getExportOVAUrlFromRemoteInstance(RemoteInstanceTO
vmwareInstance) {
- String vcenter = vmwareInstance.getVcenterHost();
- String username = vmwareInstance.getVcenterUsername();
- String password = vmwareInstance.getVcenterPassword();
- String datacenter = vmwareInstance.getDatacenterName();
- String vm = vmwareInstance.getInstanceName();
-
- String encodedUsername = encodeUsername(username);
- String encodedPassword = encodeUsername(password);
- return String.format("vi://%s:%s@%s/%s/vm/%s",
- encodedUsername, encodedPassword, vcenter, datacenter, vm);
- }
-
protected List<KVMPhysicalDisk>
getTemporaryDisksFromParsedXml(KVMStoragePool pool, LibvirtDomainXMLParser
xmlParser, String convertedBasePath) {
List<LibvirtVMDef.DiskDef> disksDefs = xmlParser.getDisks();
disksDefs = disksDefs.stream().filter(x -> x.getDiskType() ==
LibvirtVMDef.DiskDef.DiskType.FILE &&
@@ -267,8 +172,8 @@ public class LibvirtConvertInstanceCommandWrapper extends
CommandWrapper<Convert
}
protected List<KVMPhysicalDisk>
moveTemporaryDisksToDestination(List<KVMPhysicalDisk> temporaryDisks,
- List<String>
destinationStoragePools,
-
KVMStoragePoolManager storagePoolMgr) {
+
List<String> destinationStoragePools,
+
KVMStoragePoolManager storagePoolMgr) {
List<KVMPhysicalDisk> targetDisks = new ArrayList<>();
if (temporaryDisks.size() != destinationStoragePools.size()) {
String warn = String.format("Discrepancy between the converted
instance disks (%s) " +
@@ -374,48 +279,6 @@ public class LibvirtConvertInstanceCommandWrapper extends
CommandWrapper<Convert
return new Pair<>(sourceHostIp, sourcePath);
}
- private boolean exportOVAFromVMOnVcenter(String vmExportUrl,
- String targetOvfDir,
- int noOfThreads,
- long timeout) {
- Script script = new Script("ovftool", timeout, s_logger);
- script.add("--noSSLVerify");
- if (noOfThreads > 1) {
- script.add(String.format("--parallelThreads=%s", noOfThreads));
- }
- script.add(vmExportUrl);
- script.add(targetOvfDir);
-
- String logPrefix = "export ovf";
- OutputInterpreter.LineByLineOutputLogger outputLogger = new
OutputInterpreter.LineByLineOutputLogger(s_logger, logPrefix);
- script.execute(outputLogger);
- int exitValue = script.getExitValue();
- return exitValue == 0;
- }
-
- protected boolean performInstanceConversion(String sourceOVFDirPath,
- String temporaryConvertFolder,
- String temporaryConvertUuid,
- long timeout, boolean
verboseModeEnabled) {
- Script script = new Script("virt-v2v", timeout, s_logger);
- script.add("--root", "first");
- script.add("-i", "ova");
- script.add(sourceOVFDirPath);
- script.add("-o", "local");
- script.add("-os", temporaryConvertFolder);
- script.add("-of", "qcow2");
- script.add("-on", temporaryConvertUuid);
- if (verboseModeEnabled) {
- script.add("-v");
- }
-
- String logPrefix = String.format("virt-v2v ovf source: %s progress",
sourceOVFDirPath);
- OutputInterpreter.LineByLineOutputLogger outputLogger = new
OutputInterpreter.LineByLineOutputLogger(s_logger, logPrefix);
- script.execute(outputLogger);
- int exitValue = script.getExitValue();
- return exitValue == 0;
- }
-
protected LibvirtDomainXMLParser parseMigratedVMXmlDomain(String
installPath) throws IOException {
String xmlPath = String.format("%s.xml", installPath);
if (!new File(xmlPath).exists()) {
@@ -436,8 +299,4 @@ public class LibvirtConvertInstanceCommandWrapper extends
CommandWrapper<Convert
return null;
}
}
-
- protected String encodeUsername(String username) {
- return URLEncoder.encode(username, Charset.defaultCharset());
- }
}
diff --git
a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapperTest.java
b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapperTest.java
index 1cc2a60e380..b369cf25f3d 100644
---
a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapperTest.java
+++
b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapperTest.java
@@ -18,12 +18,10 @@
//
package com.cloud.hypervisor.kvm.resource.wrapper;
-import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
-import org.apache.cloudstack.vm.UnmanagedInstanceTO;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -41,13 +39,10 @@ import com.cloud.agent.api.to.NfsTO;
import com.cloud.agent.api.to.RemoteInstanceTO;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
-import com.cloud.hypervisor.kvm.resource.LibvirtDomainXMLParser;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef;
import com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk;
import com.cloud.hypervisor.kvm.storage.KVMStoragePool;
import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager;
-import com.cloud.storage.Storage;
-import com.cloud.utils.Pair;
import com.cloud.utils.script.Script;
@RunWith(MockitoJUnitRunner.class)
@@ -80,7 +75,6 @@ public class LibvirtConvertInstanceCommandWrapperTest {
Mockito.when(storagePoolManager.getStoragePoolByURI(secondaryPoolUrl)).thenReturn(temporaryPool);
KVMPhysicalDisk physicalDisk1 = Mockito.mock(KVMPhysicalDisk.class);
KVMPhysicalDisk physicalDisk2 = Mockito.mock(KVMPhysicalDisk.class);
-
Mockito.when(temporaryPool.listPhysicalDisks()).thenReturn(Arrays.asList(physicalDisk1,
physicalDisk2));
}
@Test
@@ -107,51 +101,6 @@ public class LibvirtConvertInstanceCommandWrapperTest {
Assert.assertNotNull(temporaryStoragePool);
}
- @Test
- public void testGetTemporaryDisksWithPrefixFromTemporaryPool() {
- String convertPath = "/xyz";
- String convertPrefix = UUID.randomUUID().toString();
- KVMPhysicalDisk physicalDisk1 = Mockito.mock(KVMPhysicalDisk.class);
- Mockito.when(physicalDisk1.getName()).thenReturn("disk1");
- KVMPhysicalDisk physicalDisk2 = Mockito.mock(KVMPhysicalDisk.class);
- Mockito.when(physicalDisk2.getName()).thenReturn("disk2");
-
- KVMPhysicalDisk convertedDisk1 = Mockito.mock(KVMPhysicalDisk.class);
-
Mockito.when(convertedDisk1.getName()).thenReturn(String.format("%s-sda",
convertPrefix));
- KVMPhysicalDisk convertedDisk2 = Mockito.mock(KVMPhysicalDisk.class);
-
Mockito.when(convertedDisk2.getName()).thenReturn(String.format("%s-sdb",
convertPrefix));
- KVMPhysicalDisk convertedXml = Mockito.mock(KVMPhysicalDisk.class);
-
Mockito.when(convertedXml.getName()).thenReturn(String.format("%s.xml",
convertPrefix));
-
Mockito.when(temporaryPool.listPhysicalDisks()).thenReturn(Arrays.asList(physicalDisk1,
physicalDisk2,
- convertedDisk1, convertedDisk2, convertedXml));
-
- List<KVMPhysicalDisk> convertedDisks =
convertInstanceCommandWrapper.getTemporaryDisksWithPrefixFromTemporaryPool(temporaryPool,
convertPath, convertPrefix);
- Assert.assertEquals(2, convertedDisks.size());
- }
-
- @Test
- public void testGetTemporaryDisksFromParsedXml() {
- String relativePath = UUID.randomUUID().toString();
- String fullPath = String.format("/mnt/xyz/%s", relativePath);
-
- LibvirtVMDef.DiskDef diskDef = new LibvirtVMDef.DiskDef();
- LibvirtVMDef.DiskDef.DiskBus bus = LibvirtVMDef.DiskDef.DiskBus.VIRTIO;
- LibvirtVMDef.DiskDef.DiskFmtType type =
LibvirtVMDef.DiskDef.DiskFmtType.QCOW2;
- diskDef.defFileBasedDisk(fullPath, "test", bus, type);
-
- LibvirtDomainXMLParser parser =
Mockito.mock(LibvirtDomainXMLParser.class);
- Mockito.when(parser.getDisks()).thenReturn(List.of(diskDef));
-
- KVMPhysicalDisk convertedDisk1 = Mockito.mock(KVMPhysicalDisk.class);
- Mockito.when(convertedDisk1.getName()).thenReturn("disk1");
-
Mockito.when(temporaryPool.getPhysicalDisk(relativePath)).thenReturn(convertedDisk1);
-
- List<KVMPhysicalDisk> disks =
convertInstanceCommandWrapper.getTemporaryDisksFromParsedXml(temporaryPool,
parser, "");
-
Mockito.verify(convertInstanceCommandWrapper).sanitizeDisksPath(List.of(diskDef));
- Assert.assertEquals(1, disks.size());
- Assert.assertEquals("disk1", disks.get(0).getName());
- }
-
@Test
public void testSanitizeDisksPath() {
String relativePath = UUID.randomUUID().toString();
@@ -165,73 +114,6 @@ public class LibvirtConvertInstanceCommandWrapperTest {
Assert.assertEquals(relativePath, diskDef.getDiskPath());
}
- @Test
- public void testMoveTemporaryDisksToDestination() {
- KVMPhysicalDisk sourceDisk = Mockito.mock(KVMPhysicalDisk.class);
- Mockito.when(sourceDisk.getPool()).thenReturn(temporaryPool);
- List<KVMPhysicalDisk> disks = List.of(sourceDisk);
- String destinationPoolUuid = UUID.randomUUID().toString();
- List<String> destinationPools = List.of(destinationPoolUuid);
-
- KVMPhysicalDisk destDisk = Mockito.mock(KVMPhysicalDisk.class);
- Mockito.when(destDisk.getPath()).thenReturn("xyz");
-
Mockito.when(storagePoolManager.getStoragePool(Storage.StoragePoolType.NetworkFilesystem,
destinationPoolUuid))
- .thenReturn(destinationPool);
-
Mockito.when(destinationPool.getType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem);
-
Mockito.when(storagePoolManager.copyPhysicalDisk(Mockito.eq(sourceDisk),
Mockito.anyString(), Mockito.eq(destinationPool), Mockito.anyInt()))
- .thenReturn(destDisk);
-
- List<KVMPhysicalDisk> movedDisks =
convertInstanceCommandWrapper.moveTemporaryDisksToDestination(disks,
destinationPools, storagePoolManager);
- Assert.assertEquals(1, movedDisks.size());
- Assert.assertEquals("xyz", movedDisks.get(0).getPath());
- }
-
- @Test
- public void testGetUnmanagedInstanceDisks() {
- try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class)) {
- String relativePath = UUID.randomUUID().toString();
- LibvirtVMDef.DiskDef diskDef = new LibvirtVMDef.DiskDef();
- LibvirtVMDef.DiskDef.DiskBus bus =
LibvirtVMDef.DiskDef.DiskBus.IDE;
- LibvirtVMDef.DiskDef.DiskFmtType type =
LibvirtVMDef.DiskDef.DiskFmtType.QCOW2;
- diskDef.defFileBasedDisk(relativePath, relativePath, bus, type);
-
- KVMPhysicalDisk sourceDisk = Mockito.mock(KVMPhysicalDisk.class);
-
Mockito.when(sourceDisk.getName()).thenReturn(UUID.randomUUID().toString());
- Mockito.when(sourceDisk.getPool()).thenReturn(destinationPool);
-
Mockito.when(destinationPool.getType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem);
- List<KVMPhysicalDisk> disks = List.of(sourceDisk);
-
- LibvirtDomainXMLParser parser =
Mockito.mock(LibvirtDomainXMLParser.class);
- Mockito.when(parser.getDisks()).thenReturn(List.of(diskDef));
- Mockito.doReturn(new Pair<String, String>(null,
null)).when(convertInstanceCommandWrapper).getNfsStoragePoolHostAndPath(destinationPool);
-
- Mockito.when(Script.executePipedCommands(Mockito.anyList(),
Mockito.anyLong()))
- .thenReturn(new Pair<>(0, null));
-
- List<UnmanagedInstanceTO.Disk> unmanagedInstanceDisks =
convertInstanceCommandWrapper.getUnmanagedInstanceDisks(disks, parser);
- Assert.assertEquals(1, unmanagedInstanceDisks.size());
- UnmanagedInstanceTO.Disk disk = unmanagedInstanceDisks.get(0);
- Assert.assertEquals(LibvirtVMDef.DiskDef.DiskBus.IDE.toString(),
disk.getController());
- }
- }
-
- @Test
- public void testGetNfsStoragePoolHostAndPath() {
- try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class)) {
- String localMountPoint = "/mnt/xyz";
- String host = "192.168.1.2";
- String path = "/secondary";
- String mountOutput = String.format("%s:%s on %s type nfs (...)",
host, path, localMountPoint);
-
Mockito.when(temporaryPool.getLocalPath()).thenReturn(localMountPoint);
- Mockito.when(Script.executePipedCommands(Mockito.anyList(),
Mockito.anyLong()))
- .thenReturn(new Pair<>(0, mountOutput));
-
- Pair<String, String> pair =
convertInstanceCommandWrapper.getNfsStoragePoolHostAndPath(temporaryPool);
- Assert.assertEquals(host, pair.first());
- Assert.assertEquals(path, pair.second());
- }
- }
-
private RemoteInstanceTO getRemoteInstanceTO(Hypervisor.HypervisorType
hypervisorType) {
RemoteInstanceTO remoteInstanceTO =
Mockito.mock(RemoteInstanceTO.class);
Mockito.when(remoteInstanceTO.getHypervisorType()).thenReturn(hypervisorType);
diff --git
a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapperTest.java
b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtImportConvertedInstanceCommandWrapperTest.java
similarity index 69%
copy from
plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapperTest.java
copy to
plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtImportConvertedInstanceCommandWrapperTest.java
index 1cc2a60e380..55789a837b2 100644
---
a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtConvertInstanceCommandWrapperTest.java
+++
b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtImportConvertedInstanceCommandWrapperTest.java
@@ -18,25 +18,8 @@
//
package com.cloud.hypervisor.kvm.resource.wrapper;
-import java.util.Arrays;
-import java.util.List;
-import java.util.UUID;
-
-import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
-import org.apache.cloudstack.vm.UnmanagedInstanceTO;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockedConstruction;
-import org.mockito.MockedStatic;
-import org.mockito.Mockito;
-import org.mockito.Spy;
-import org.mockito.junit.MockitoJUnitRunner;
-
import com.cloud.agent.api.Answer;
-import com.cloud.agent.api.ConvertInstanceCommand;
+import com.cloud.agent.api.ImportConvertedInstanceCommand;
import com.cloud.agent.api.to.NfsTO;
import com.cloud.agent.api.to.RemoteInstanceTO;
import com.cloud.hypervisor.Hypervisor;
@@ -49,12 +32,28 @@ import
com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager;
import com.cloud.storage.Storage;
import com.cloud.utils.Pair;
import com.cloud.utils.script.Script;
+import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
+import org.apache.cloudstack.vm.UnmanagedInstanceTO;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
@RunWith(MockitoJUnitRunner.class)
-public class LibvirtConvertInstanceCommandWrapperTest {
+public class LibvirtImportConvertedInstanceCommandWrapperTest {
@Spy
- private LibvirtConvertInstanceCommandWrapper convertInstanceCommandWrapper
= Mockito.spy(LibvirtConvertInstanceCommandWrapper.class);
+ private LibvirtImportConvertedInstanceCommandWrapper
importInstanceCommandWrapper =
+ Mockito.spy(LibvirtImportConvertedInstanceCommandWrapper.class);
@Mock
private LibvirtComputingResource libvirtComputingResourceMock;
@@ -83,27 +82,9 @@ public class LibvirtConvertInstanceCommandWrapperTest {
Mockito.when(temporaryPool.listPhysicalDisks()).thenReturn(Arrays.asList(physicalDisk1,
physicalDisk2));
}
- @Test
- public void testAreSourceAndDestinationHypervisorsSupported() {
- boolean supported =
convertInstanceCommandWrapper.areSourceAndDestinationHypervisorsSupported(Hypervisor.HypervisorType.VMware,
Hypervisor.HypervisorType.KVM);
- Assert.assertTrue(supported);
- }
-
- @Test
- public void
testAreSourceAndDestinationHypervisorsSupportedUnsupportedSource() {
- boolean supported =
convertInstanceCommandWrapper.areSourceAndDestinationHypervisorsSupported(Hypervisor.HypervisorType.XenServer,
Hypervisor.HypervisorType.KVM);
- Assert.assertFalse(supported);
- }
-
- @Test
- public void
testAreSourceAndDestinationHypervisorsSupportedUnsupportedDestination() {
- boolean supported =
convertInstanceCommandWrapper.areSourceAndDestinationHypervisorsSupported(Hypervisor.HypervisorType.VMware,
Hypervisor.HypervisorType.VMware);
- Assert.assertFalse(supported);
- }
-
@Test
public void testGetTemporaryStoragePool() {
- KVMStoragePool temporaryStoragePool =
convertInstanceCommandWrapper.getTemporaryStoragePool(secondaryDataStore,
libvirtComputingResourceMock.getStoragePoolMgr());
+ KVMStoragePool temporaryStoragePool =
importInstanceCommandWrapper.getTemporaryStoragePool(secondaryDataStore,
libvirtComputingResourceMock.getStoragePoolMgr());
Assert.assertNotNull(temporaryStoragePool);
}
@@ -125,7 +106,7 @@ public class LibvirtConvertInstanceCommandWrapperTest {
Mockito.when(temporaryPool.listPhysicalDisks()).thenReturn(Arrays.asList(physicalDisk1,
physicalDisk2,
convertedDisk1, convertedDisk2, convertedXml));
- List<KVMPhysicalDisk> convertedDisks =
convertInstanceCommandWrapper.getTemporaryDisksWithPrefixFromTemporaryPool(temporaryPool,
convertPath, convertPrefix);
+ List<KVMPhysicalDisk> convertedDisks =
importInstanceCommandWrapper.getTemporaryDisksWithPrefixFromTemporaryPool(temporaryPool,
convertPath, convertPrefix);
Assert.assertEquals(2, convertedDisks.size());
}
@@ -146,8 +127,8 @@ public class LibvirtConvertInstanceCommandWrapperTest {
Mockito.when(convertedDisk1.getName()).thenReturn("disk1");
Mockito.when(temporaryPool.getPhysicalDisk(relativePath)).thenReturn(convertedDisk1);
- List<KVMPhysicalDisk> disks =
convertInstanceCommandWrapper.getTemporaryDisksFromParsedXml(temporaryPool,
parser, "");
-
Mockito.verify(convertInstanceCommandWrapper).sanitizeDisksPath(List.of(diskDef));
+ List<KVMPhysicalDisk> disks =
importInstanceCommandWrapper.getTemporaryDisksFromParsedXml(temporaryPool,
parser, "");
+
Mockito.verify(importInstanceCommandWrapper).sanitizeDisksPath(List.of(diskDef));
Assert.assertEquals(1, disks.size());
Assert.assertEquals("disk1", disks.get(0).getName());
}
@@ -161,7 +142,7 @@ public class LibvirtConvertInstanceCommandWrapperTest {
LibvirtVMDef.DiskDef.DiskFmtType type =
LibvirtVMDef.DiskDef.DiskFmtType.QCOW2;
diskDef.defFileBasedDisk(fullPath, "test", bus, type);
- convertInstanceCommandWrapper.sanitizeDisksPath(List.of(diskDef));
+ importInstanceCommandWrapper.sanitizeDisksPath(List.of(diskDef));
Assert.assertEquals(relativePath, diskDef.getDiskPath());
}
@@ -181,7 +162,7 @@ public class LibvirtConvertInstanceCommandWrapperTest {
Mockito.when(storagePoolManager.copyPhysicalDisk(Mockito.eq(sourceDisk),
Mockito.anyString(), Mockito.eq(destinationPool), Mockito.anyInt()))
.thenReturn(destDisk);
- List<KVMPhysicalDisk> movedDisks =
convertInstanceCommandWrapper.moveTemporaryDisksToDestination(disks,
destinationPools, storagePoolManager);
+ List<KVMPhysicalDisk> movedDisks =
importInstanceCommandWrapper.moveTemporaryDisksToDestination(disks,
destinationPools, storagePoolManager);
Assert.assertEquals(1, movedDisks.size());
Assert.assertEquals("xyz", movedDisks.get(0).getPath());
}
@@ -203,12 +184,12 @@ public class LibvirtConvertInstanceCommandWrapperTest {
LibvirtDomainXMLParser parser =
Mockito.mock(LibvirtDomainXMLParser.class);
Mockito.when(parser.getDisks()).thenReturn(List.of(diskDef));
- Mockito.doReturn(new Pair<String, String>(null,
null)).when(convertInstanceCommandWrapper).getNfsStoragePoolHostAndPath(destinationPool);
+ Mockito.doReturn(new Pair<String, String>(null,
null)).when(importInstanceCommandWrapper).getNfsStoragePoolHostAndPath(destinationPool);
Mockito.when(Script.executePipedCommands(Mockito.anyList(),
Mockito.anyLong()))
.thenReturn(new Pair<>(0, null));
- List<UnmanagedInstanceTO.Disk> unmanagedInstanceDisks =
convertInstanceCommandWrapper.getUnmanagedInstanceDisks(disks, parser);
+ List<UnmanagedInstanceTO.Disk> unmanagedInstanceDisks =
importInstanceCommandWrapper.getUnmanagedInstanceDisks(disks, parser);
Assert.assertEquals(1, unmanagedInstanceDisks.size());
UnmanagedInstanceTO.Disk disk = unmanagedInstanceDisks.get(0);
Assert.assertEquals(LibvirtVMDef.DiskDef.DiskBus.IDE.toString(),
disk.getController());
@@ -226,7 +207,7 @@ public class LibvirtConvertInstanceCommandWrapperTest {
Mockito.when(Script.executePipedCommands(Mockito.anyList(),
Mockito.anyLong()))
.thenReturn(new Pair<>(0, mountOutput));
- Pair<String, String> pair =
convertInstanceCommandWrapper.getNfsStoragePoolHostAndPath(temporaryPool);
+ Pair<String, String> pair =
importInstanceCommandWrapper.getNfsStoragePoolHostAndPath(temporaryPool);
Assert.assertEquals(host, pair.first());
Assert.assertEquals(path, pair.second());
}
@@ -239,53 +220,26 @@ public class LibvirtConvertInstanceCommandWrapperTest {
return remoteInstanceTO;
}
- private ConvertInstanceCommand getConvertInstanceCommand(RemoteInstanceTO
remoteInstanceTO, Hypervisor.HypervisorType hypervisorType, boolean
checkConversionSupport) {
- ConvertInstanceCommand cmd =
Mockito.mock(ConvertInstanceCommand.class);
+ private ImportConvertedInstanceCommand
getImportConvertedInstanceCommand(RemoteInstanceTO remoteInstanceTO) {
+ ImportConvertedInstanceCommand cmd =
Mockito.mock(ImportConvertedInstanceCommand.class);
Mockito.when(cmd.getSourceInstance()).thenReturn(remoteInstanceTO);
-
Mockito.when(cmd.getDestinationHypervisorType()).thenReturn(hypervisorType);
- Mockito.when(cmd.getWait()).thenReturn(14400);
Mockito.when(cmd.getConversionTemporaryLocation()).thenReturn(secondaryDataStore);
-
Mockito.when(cmd.getCheckConversionSupport()).thenReturn(checkConversionSupport);
return cmd;
}
@Test
public void testExecuteConvertUnsupportedOnTheHost() {
RemoteInstanceTO remoteInstanceTO =
getRemoteInstanceTO(Hypervisor.HypervisorType.VMware);
-
Mockito.when(libvirtComputingResourceMock.hostSupportsInstanceConversion()).thenReturn(false);
- ConvertInstanceCommand cmd =
getConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM,
true);
- Answer answer = convertInstanceCommandWrapper.execute(cmd,
libvirtComputingResourceMock);
+ ImportConvertedInstanceCommand cmd =
getImportConvertedInstanceCommand(remoteInstanceTO);
+ Answer answer = importInstanceCommandWrapper.execute(cmd,
libvirtComputingResourceMock);
Assert.assertFalse(answer.getResult());
}
@Test
public void testExecuteConvertUnsupportedHypervisors() {
RemoteInstanceTO remoteInstanceTO =
getRemoteInstanceTO(Hypervisor.HypervisorType.XenServer);
-
Mockito.when(libvirtComputingResourceMock.hostSupportsInstanceConversion()).thenReturn(true);
- ConvertInstanceCommand cmd =
getConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM,
true);
- Answer answer = convertInstanceCommandWrapper.execute(cmd,
libvirtComputingResourceMock);
+ ImportConvertedInstanceCommand cmd =
getImportConvertedInstanceCommand(remoteInstanceTO);
+ Answer answer = importInstanceCommandWrapper.execute(cmd,
libvirtComputingResourceMock);
Assert.assertFalse(answer.getResult());
}
-
- @Test
- public void testExecuteConvertFailure() {
- RemoteInstanceTO remoteInstanceTO =
getRemoteInstanceTO(Hypervisor.HypervisorType.VMware);
- ConvertInstanceCommand cmd =
getConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM,
true);
- String localMountPoint = "/mnt/xyz";
- Mockito.when(temporaryPool.getLocalPath()).thenReturn(localMountPoint);
-
- try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class);
- MockedConstruction<Script> ignored2 =
Mockito.mockConstruction(Script.class, (mock, context) -> {
- Mockito.when(mock.execute()).thenReturn("");
- Mockito.when(mock.getExitValue()).thenReturn(1);
- })
- ) {
-
Mockito.when(libvirtComputingResourceMock.hostSupportsInstanceConversion()).thenReturn(true);
-
- Answer answer = convertInstanceCommandWrapper.execute(cmd,
libvirtComputingResourceMock);
- Assert.assertFalse(answer.getResult());
-
Mockito.verify(convertInstanceCommandWrapper).performInstanceConversion(Mockito.anyString(),
- Mockito.anyString(), Mockito.anyString(),
Mockito.anyLong(), Mockito.anyBoolean());
- }
- }
}
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 aa216fbfec2..67139120fa0 100644
--- a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java
+++ b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java
@@ -31,6 +31,8 @@ import com.cloud.agent.api.GetRemoteVmsAnswer;
import com.cloud.agent.api.GetRemoteVmsCommand;
import com.cloud.agent.api.GetUnmanagedInstancesAnswer;
import com.cloud.agent.api.GetUnmanagedInstancesCommand;
+import com.cloud.agent.api.ImportConvertedInstanceAnswer;
+import com.cloud.agent.api.ImportConvertedInstanceCommand;
import com.cloud.agent.api.PrepareUnmanageVMInstanceAnswer;
import com.cloud.agent.api.PrepareUnmanageVMInstanceCommand;
import com.cloud.agent.api.to.DataStoreTO;
@@ -1304,6 +1306,10 @@ public class UnmanagedVMsManagerImpl implements
UnmanagedVMsManager {
Long clusterId = cmd.getClusterId();
Cluster cluster = basicAccessChecks(clusterId);
+ if
(!cluster.getAllocationState().equals(Cluster.AllocationState.Enabled)) {
+ throw new InvalidParameterValueException(String.format("Cluster
[%s] is not enabled.", cluster));
+ }
+
final Account caller = CallContext.current().getCallingAccount();
final DataCenter zone =
dataCenterDao.findById(cluster.getDataCenterId());
final Account owner =
accountService.getActiveAccountById(cmd.getEntityOwnerId());
@@ -1568,6 +1574,7 @@ public class UnmanagedVMsManagerImpl implements
UnmanagedVMsManager {
String clusterName = cmd.getClusterName();
String sourceHostName = cmd.getHostIp();
Long convertInstanceHostId = cmd.getConvertInstanceHostId();
+ Long importInstanceHostId = cmd.getImportInstanceHostId();
Long convertStoragePoolId = cmd.getConvertStoragePoolId();
if ((existingVcenterId == null && vcenter == null) ||
(existingVcenterId != null && vcenter != null)) {
@@ -1597,12 +1604,14 @@ public class UnmanagedVMsManagerImpl implements
UnmanagedVMsManager {
DataStoreTO temporaryConvertLocation = null;
String ovfTemplateOnConvertLocation = null;
try {
- HostVO convertHost =
selectInstanceConversionKVMHostInCluster(destinationCluster,
convertInstanceHostId);
+ HostVO convertHost =
selectKVMHostForConversionInCluster(destinationCluster, convertInstanceHostId);
+ HostVO importHost =
selectKVMHostForImportingInCluster(destinationCluster, importInstanceHostId);
CheckConvertInstanceAnswer conversionSupportAnswer =
checkConversionSupportOnHost(convertHost, sourceVMName, false);
LOGGER.debug(String.format("The host %s (%s) is selected to
execute the conversion of the instance %s" +
" from VMware to KVM ", convertHost.getId(),
convertHost.getName(), sourceVMName));
- temporaryConvertLocation =
selectInstanceConversionTemporaryLocation(destinationCluster,
convertStoragePoolId);
+ temporaryConvertLocation =
selectInstanceConversionTemporaryLocation(
+ destinationCluster, convertHost, convertStoragePoolId);
List<StoragePoolVO> convertStoragePools =
findInstanceConversionStoragePoolsInCluster(destinationCluster);
long importStartTime = System.currentTimeMillis();
Pair<UnmanagedInstanceTO, Boolean> sourceInstanceDetails =
getSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password,
clusterName, sourceHostName, sourceVMName);
@@ -1621,11 +1630,13 @@ public class UnmanagedVMsManagerImpl implements
UnmanagedVMsManager {
int noOfThreads =
UnmanagedVMsManager.ThreadsOnMSToImportVMwareVMFiles.value();
ovfTemplateOnConvertLocation =
createOvfTemplateOfSourceVmwareUnmanagedInstance(vcenter, datacenterName,
username, password,
clusterName, sourceHostName,
sourceVMwareInstance.getName(), temporaryConvertLocation, noOfThreads);
- convertedInstance =
convertVmwareInstanceToKVMWithOVFOnConvertLocation(sourceVMName,
sourceVMwareInstance, convertHost, convertStoragePools,
+ convertedInstance =
convertVmwareInstanceToKVMWithOVFOnConvertLocation(sourceVMName,
+ sourceVMwareInstance, convertHost, importHost,
convertStoragePools,
temporaryConvertLocation,
ovfTemplateOnConvertLocation);
} else {
// Uses KVM Host for OVF export to temporary conversion
location, through ovftool
- convertedInstance =
convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(sourceVMName,
sourceVMwareInstance, convertHost, convertStoragePools,
+ convertedInstance =
convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(
+ sourceVMName, sourceVMwareInstance, convertHost,
importHost, convertStoragePools,
temporaryConvertLocation, vcenter, username, password,
datacenterName);
}
@@ -1781,20 +1792,77 @@ public class UnmanagedVMsManagerImpl implements
UnmanagedVMsManager {
return params;
}
- private HostVO selectInstanceConversionKVMHostInCluster(Cluster
destinationCluster, Long convertInstanceHostId) {
+ HostVO selectKVMHostForImportingInCluster(Cluster destinationCluster, Long
importInstanceHostId) {
+ if (importInstanceHostId != null) {
+ String err = null;
+ HostVO selectedHost = hostDao.findById(importInstanceHostId);
+ if (selectedHost == null) {
+ err = String.format("Cannot find host with ID %s to import the
instance",
+ importInstanceHostId);
+ } else if (selectedHost.getResourceState() !=
ResourceState.Enabled) {
+ err = String.format(
+ "Cannot import the converted instance on the host %s
as it is not in Enabled state",
+ selectedHost.getName());
+ } else if (selectedHost.getStatus() != Status.Up) {
+ err = String.format(
+ "Cannot import the converted instance on the host %s
as it is not running",
+ selectedHost.getName());
+ } else if (selectedHost.getType() != Host.Type.Routing) {
+ err = String.format(
+ "Cannot import the converted instance on the host %s
as it is not a routing host",
+ selectedHost.getName());
+ } else if (destinationCluster.getId() !=
selectedHost.getClusterId()) {
+ err = String.format(
+ "Cannot import the converted instance on the host %s
as it is not in the same cluster as the destination cluster",
+ selectedHost.getName());
+ }
+
+ if (err != null) {
+ LOGGER.error(err);
+ throw new CloudRuntimeException(err);
+ }
+ return selectedHost;
+ }
+
+ List<HostVO> hosts =
hostDao.listByClusterAndHypervisorType(destinationCluster.getId(),
destinationCluster.getHypervisorType());
+ if (CollectionUtils.isNotEmpty(hosts)) {
+ return hosts.get(new Random().nextInt(hosts.size()));
+ }
+
+ String err = String.format(
+ "Could not find any suitable %s host in cluster %s to import
the converted instance",
+ destinationCluster.getHypervisorType(),
destinationCluster.getName());
+ LOGGER.error(err);
+ throw new CloudRuntimeException(err);
+ }
+
+ HostVO selectKVMHostForConversionInCluster(Cluster destinationCluster,
Long convertInstanceHostId) {
if (convertInstanceHostId != null) {
HostVO selectedHost = hostDao.findById(convertInstanceHostId);
+ String err = null;
if (selectedHost == null) {
- String msg = String.format("Cannot find host with ID %s",
convertInstanceHostId);
- LOGGER.error(msg);
- throw new CloudRuntimeException(msg);
- }
- if (selectedHost.getResourceState() != ResourceState.Enabled ||
- selectedHost.getStatus() != Status.Up ||
selectedHost.getType() != Host.Type.Routing ||
- selectedHost.getClusterId() != destinationCluster.getId())
{
- String msg = String.format("Cannot perform the conversion on
the host %s as it is not a running and Enabled host", selectedHost.getName());
- LOGGER.error(msg);
- throw new CloudRuntimeException(msg);
+ err = String.format("Cannot find host with ID %s for
conversion",
+ convertInstanceHostId);
+ } else if (!List.of(ResourceState.Enabled,
ResourceState.Disabled).contains(selectedHost.getResourceState())) {
+ err = String.format(
+ "Cannot perform the conversion on the host %s as the
host is in %s state",
+ selectedHost.getName(),
selectedHost.getResourceState());
+ } else if (selectedHost.getStatus() != Status.Up) {
+ err = String.format(
+ "Cannot perform the conversion on the host %s as it is
not running",
+ selectedHost.getName());
+ } else if (selectedHost.getType() != Host.Type.Routing) {
+ err = String.format(
+ "Cannot perform the conversion on the host %s as it is
not a routing host",
+ selectedHost.getName());
+ } else if (destinationCluster.getDataCenterId() !=
selectedHost.getDataCenterId()) {
+ err = String.format(
+ "Cannot perform the conversion on the host %s as it is
not in the same zone as the destination cluster",
+ selectedHost.getName());
+ }
+ if (err != null) {
+ LOGGER.error(err);
+ throw new CloudRuntimeException(err);
}
return selectedHost;
}
@@ -1843,48 +1911,39 @@ public class UnmanagedVMsManagerImpl implements
UnmanagedVMsManager {
return checkConvertInstanceAnswer;
}
- private UnmanagedInstanceTO
convertVmwareInstanceToKVMWithOVFOnConvertLocation(String sourceVM,
UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost,
-
List<StoragePoolVO> convertStoragePools, DataStoreTO
temporaryConvertLocation,
-
String ovfTemplateDirConvertLocation) {
+ private UnmanagedInstanceTO
convertVmwareInstanceToKVMWithOVFOnConvertLocation(
+ String sourceVM, UnmanagedInstanceTO sourceVMwareInstance,
+ HostVO convertHost, HostVO importHost,
+ List<StoragePoolVO> convertStoragePools, 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<String> destinationStoragePools =
selectInstanceConversionStoragePools(convertStoragePools,
sourceVMwareInstance.getDisks());
ConvertInstanceCommand cmd = new
ConvertInstanceCommand(remoteInstanceTO,
- Hypervisor.HypervisorType.KVM, destinationStoragePools,
temporaryConvertLocation, ovfTemplateDirConvertLocation, false, false);
+ Hypervisor.HypervisorType.KVM, temporaryConvertLocation,
ovfTemplateDirConvertLocation, false, false);
int timeoutSeconds =
UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60;
cmd.setWait(timeoutSeconds);
- Answer convertAnswer;
- try {
- convertAnswer = agentManager.send(convertHost.getId(), cmd);
- } catch (AgentUnavailableException | OperationTimedoutException e) {
- String err = String.format("Could not send the convert instance
command to host %s (%s) due to: %s",
- convertHost.getId(), convertHost.getName(),
e.getMessage());
- LOGGER.error(err, e);
- throw new CloudRuntimeException(err);
- }
-
- if (!convertAnswer.getResult()) {
- String err = String.format("The convert process failed for
instance %s from VMware to KVM on host %s: %s",
- sourceVM, convertHost.getName(),
convertAnswer.getDetails());
- LOGGER.error(err);
- throw new CloudRuntimeException(err);
- }
- return ((ConvertInstanceAnswer) convertAnswer).getConvertedInstance();
+ return convertAndImportToKVM(cmd, convertHost, importHost, sourceVM,
+ remoteInstanceTO, destinationStoragePools,
temporaryConvertLocation);
}
- private UnmanagedInstanceTO
convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(String sourceVM,
UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost,
-
List<StoragePoolVO> convertStoragePools, DataStoreTO
temporaryConvertLocation,
-
String vcenterHost, String vcenterUsername, String
vcenterPassword, String datacenterName) {
+ private UnmanagedInstanceTO
convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(
+ String sourceVM, UnmanagedInstanceTO sourceVMwareInstance,
+ HostVO convertHost, HostVO importHost, List<StoragePoolVO>
convertStoragePools,
+ 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<String> destinationStoragePools =
selectInstanceConversionStoragePools(convertStoragePools,
sourceVMwareInstance.getDisks());
ConvertInstanceCommand cmd = new
ConvertInstanceCommand(remoteInstanceTO,
- Hypervisor.HypervisorType.KVM, destinationStoragePools,
temporaryConvertLocation, null, false, true);
+ Hypervisor.HypervisorType.KVM, temporaryConvertLocation, null,
false, true);
int timeoutSeconds =
UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60;
cmd.setWait(timeoutSeconds);
int noOfThreads =
UnmanagedVMsManager.ThreadsOnKVMHostToImportVMwareVMFiles.value();
@@ -1894,9 +1953,18 @@ public class UnmanagedVMsManagerImpl implements
UnmanagedVMsManager {
}
cmd.setThreadsCountToExportOvf(noOfThreads);
+ return convertAndImportToKVM(cmd, convertHost, importHost, sourceVM,
+ remoteInstanceTO, destinationStoragePools,
temporaryConvertLocation);
+ }
+
+ private UnmanagedInstanceTO convertAndImportToKVM(ConvertInstanceCommand
convertInstanceCommand, HostVO convertHost, HostVO importHost,
+ String sourceVM,
+ RemoteInstanceTO
remoteInstanceTO,
+ List<String>
destinationStoragePools,
+ DataStoreTO
temporaryConvertLocation) {
Answer convertAnswer;
try {
- convertAnswer = agentManager.send(convertHost.getId(), cmd);
+ convertAnswer = agentManager.send(convertHost.getId(),
convertInstanceCommand);
} catch (AgentUnavailableException | OperationTimedoutException e) {
String err = String.format("Could not send the convert instance
command to host %s (%s) due to: %s",
convertHost.getId(), convertHost.getName(),
e.getMessage());
@@ -1910,7 +1978,30 @@ public class UnmanagedVMsManagerImpl implements
UnmanagedVMsManager {
LOGGER.error(err);
throw new CloudRuntimeException(err);
}
- return ((ConvertInstanceAnswer) convertAnswer).getConvertedInstance();
+
+ Answer importAnswer;
+ try {
+ ImportConvertedInstanceCommand importCmd = new
ImportConvertedInstanceCommand(
+ remoteInstanceTO, destinationStoragePools,
temporaryConvertLocation,
+
((ConvertInstanceAnswer)convertAnswer).getTemporaryConvertUuid());
+ importAnswer = agentManager.send(importHost.getId(), importCmd);
+ } catch (AgentUnavailableException | OperationTimedoutException e) {
+ String err = String.format(
+ "Could not send the import converted instance command to
host %d (%s) due to: %s",
+ importHost.getId(), importHost.getName(), e.getMessage());
+ LOGGER.error(err, e);
+ throw new CloudRuntimeException(err);
+ }
+
+ if (!importAnswer.getResult()) {
+ String err = String.format(
+ "The import process failed for instance %s from VMware to
KVM on host %s: %s",
+ sourceVM, importHost.getName(), importAnswer.getDetails());
+ LOGGER.error(err);
+ throw new CloudRuntimeException(err);
+ }
+
+ return ((ImportConvertedInstanceAnswer)
importAnswer).getConvertedInstance();
}
private List<StoragePoolVO>
findInstanceConversionStoragePoolsInCluster(Cluster destinationCluster) {
@@ -1942,7 +2033,9 @@ public class UnmanagedVMsManagerImpl implements
UnmanagedVMsManager {
throw new CloudRuntimeException(msg);
}
- protected DataStoreTO selectInstanceConversionTemporaryLocation(Cluster
destinationCluster, Long convertStoragePoolId) {
+ protected DataStoreTO selectInstanceConversionTemporaryLocation(Cluster
destinationCluster,
+ HostVO
convertHost,
+ Long
convertStoragePoolId) {
if (convertStoragePoolId != null) {
StoragePoolVO selectedStoragePool =
primaryDataStoreDao.findById(convertStoragePoolId);
if (selectedStoragePool == null) {
@@ -1953,6 +2046,10 @@ public class UnmanagedVMsManagerImpl implements
UnmanagedVMsManager {
logFailureAndThrowException(String.format("Cannot use the
storage pool %s for the instance conversion as " +
"it is not in the scope of the cluster %s",
selectedStoragePool.getName(), destinationCluster.getName()));
}
+ if (convertHost != null && selectedStoragePool.getScope() ==
ScopeType.CLUSTER &&
!selectedStoragePool.getClusterId().equals(convertHost.getClusterId())) {
+ 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) {
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 9e96d74ea4b..e9a58760828 100644
---
a/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java
+++
b/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java
@@ -31,6 +31,8 @@ import com.cloud.agent.api.GetRemoteVmsAnswer;
import com.cloud.agent.api.GetRemoteVmsCommand;
import com.cloud.agent.api.GetUnmanagedInstancesAnswer;
import com.cloud.agent.api.GetUnmanagedInstancesCommand;
+import com.cloud.agent.api.ImportConvertedInstanceAnswer;
+import com.cloud.agent.api.ImportConvertedInstanceCommand;
import com.cloud.agent.api.to.DataStoreTO;
import com.cloud.configuration.Resource;
import com.cloud.dc.ClusterVO;
@@ -63,6 +65,7 @@ import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkVO;
import com.cloud.offering.NetworkOffering;
import com.cloud.offering.ServiceOffering;
+import com.cloud.org.Grouping;
import com.cloud.resource.ResourceManager;
import com.cloud.resource.ResourceState;
import com.cloud.service.ServiceOfferingVO;
@@ -370,7 +373,7 @@ public class UnmanagedVMsManagerImplTest {
doNothing().when(networkModel).checkNetworkPermissions(Mockito.any(Account.class),
Mockito.any(Network.class));
NicProfile profile = Mockito.mock(NicProfile.class);
Integer deviceId = 100;
- Pair<NicProfile, Integer> pair = new Pair<NicProfile,
Integer>(profile, deviceId);
+ Pair<NicProfile, Integer> pair = new Pair<>(profile, deviceId);
when(networkOrchestrationService.importNic(nullable(String.class),
nullable(Integer.class), nullable(Network.class), nullable(Boolean.class),
nullable(VirtualMachine.class), nullable(Network.IpAddresses.class),
nullable(DataCenter.class), Mockito.anyBoolean())).thenReturn(pair);
when(volumeDao.findByInstance(Mockito.anyLong())).thenReturn(volumes);
List<UserVmResponse> userVmResponses = new ArrayList<>();
@@ -596,6 +599,7 @@ public class UnmanagedVMsManagerImplTest {
ClusterVO cluster = mock(ClusterVO.class);
when(cluster.getId()).thenReturn(clusterId);
+
when(cluster.getAllocationState()).thenReturn(Grouping.AllocationState.Enabled);
when(cluster.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
when(cluster.getDataCenterId()).thenReturn(zoneId);
when(clusterDao.findById(clusterId)).thenReturn(cluster);
@@ -609,6 +613,7 @@ public class UnmanagedVMsManagerImplTest {
when(importVmCmd.getHostIp()).thenReturn(host);
when(importVmCmd.getNicNetworkList()).thenReturn(Map.of("NIC 1",
networkId));
when(importVmCmd.getConvertInstanceHostId()).thenReturn(null);
+ when(importVmCmd.getImportInstanceHostId()).thenReturn(null);
when(importVmCmd.getConvertStoragePoolId()).thenReturn(null);
NetworkVO networkVO = Mockito.mock(NetworkVO.class);
@@ -630,10 +635,14 @@ public class UnmanagedVMsManagerImplTest {
when(convertHost.getId()).thenReturn(convertHostId);
when(convertHost.getName()).thenReturn("KVM-Convert-Host");
when(convertHost.getType()).thenReturn(Host.Type.Routing);
+ when(convertHost.getDataCenterId()).thenReturn(zoneId);
when(convertHost.getClusterId()).thenReturn(clusterId);
if (selectConvertHost) {
when(importVmCmd.getConvertInstanceHostId()).thenReturn(convertHostId);
+
when(importVmCmd.getImportInstanceHostId()).thenReturn(convertHostId);
when(hostDao.findById(convertHostId)).thenReturn(convertHost);
+ } else {
+ when(hostDao.listByClusterAndHypervisorType(clusterId,
Hypervisor.HypervisorType.KVM)).thenReturn(List.of(convertHost));
}
DataStoreTO dataStoreTO = mock(DataStoreTO.class);
@@ -694,10 +703,13 @@ public class UnmanagedVMsManagerImplTest {
}
ConvertInstanceAnswer convertInstanceAnswer =
mock(ConvertInstanceAnswer.class);
+ ImportConvertedInstanceAnswer convertImportedInstanceAnswer =
mock(ImportConvertedInstanceAnswer.class);
when(convertInstanceAnswer.getResult()).thenReturn(vcenterParameter !=
VcenterParameter.CONVERT_FAILURE);
-
when(convertInstanceAnswer.getConvertedInstance()).thenReturn(instance);
+
when(convertImportedInstanceAnswer.getConvertedInstance()).thenReturn(instance);
+
when(convertImportedInstanceAnswer.getResult()).thenReturn(vcenterParameter !=
VcenterParameter.CONVERT_FAILURE);
if (VcenterParameter.AGENT_UNAVAILABLE != vcenterParameter) {
when(agentManager.send(Mockito.eq(convertHostId),
Mockito.any(ConvertInstanceCommand.class))).thenReturn(convertInstanceAnswer);
+ when(agentManager.send(Mockito.eq(convertHostId),
Mockito.any(ImportConvertedInstanceCommand.class))).thenReturn(convertImportedInstanceAnswer);
}
try (MockedStatic<UsageEventUtils> ignored =
Mockito.mockStatic(UsageEventUtils.class)) {
@@ -761,6 +773,7 @@ public class UnmanagedVMsManagerImplTest {
}
}
+ @Test
public void testImportVmFromVmwareToKvmExistingVcenter() throws
OperationTimedoutException, AgentUnavailableException {
baseTestImportVmFromVmwareToKvm(VcenterParameter.EXISTING, false,
false);
}
@@ -813,7 +826,7 @@ public class UnmanagedVMsManagerImplTest {
long poolId = 1L;
when(primaryDataStoreDao.findById(poolId)).thenReturn(null);
- unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster,
poolId);
+ unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster,
null, poolId);
}
@Test(expected = CloudRuntimeException.class)
@@ -821,20 +834,35 @@ public class UnmanagedVMsManagerImplTest {
ClusterVO cluster = getClusterForTests();
long poolId = 1L;
StoragePoolVO pool = mock(StoragePoolVO.class);
- Mockito.when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
- Mockito.when(pool.getClusterId()).thenReturn(100L);
+ when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
+ when(pool.getClusterId()).thenReturn(100L);
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
- unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster,
poolId);
+ unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster,
null, poolId);
}
+
+ @Test(expected = CloudRuntimeException.class)
+ public void
testSelectInstanceConversionTemporaryLocationPoolConvertHostDifferentCluster() {
+ ClusterVO cluster = getClusterForTests();
+ long poolId = 1L;
+ StoragePoolVO pool = mock(StoragePoolVO.class);
+ when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
+ when(pool.getClusterId()).thenReturn(1L);
+ HostVO host = mock(HostVO.class);
+ when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
+ when(host.getClusterId()).thenReturn(2L);
+ unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster,
host, poolId);
+ }
+
+
@Test(expected = CloudRuntimeException.class)
public void
testSelectInstanceConversionTemporaryLocationLocalStoragePoolInvalid() {
ClusterVO cluster = getClusterForTests();
long poolId = 1L;
StoragePoolVO pool = mock(StoragePoolVO.class);
- Mockito.when(pool.getScope()).thenReturn(ScopeType.HOST);
+ when(pool.getScope()).thenReturn(ScopeType.HOST);
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
- unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster,
poolId);
+ unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster,
null, poolId);
}
@Test(expected = CloudRuntimeException.class)
@@ -842,17 +870,249 @@ public class UnmanagedVMsManagerImplTest {
ClusterVO cluster = getClusterForTests();
long poolId = 1L;
StoragePoolVO pool = mock(StoragePoolVO.class);
- Mockito.when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
- Mockito.when(pool.getClusterId()).thenReturn(1L);
+ when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
+ when(pool.getClusterId()).thenReturn(1L);
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
-
Mockito.when(pool.getPoolType()).thenReturn(Storage.StoragePoolType.RBD);
- unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster,
poolId);
+ when(pool.getPoolType()).thenReturn(Storage.StoragePoolType.RBD);
+ unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster,
null, poolId);
}
@Test(expected = CloudRuntimeException.class)
public void testSelectInstanceConversionTemporaryLocationNoPoolAvailable()
{
ClusterVO cluster = getClusterForTests();
- Mockito.when(imageStoreDao.findOneByZoneAndProtocol(anyLong(),
anyString())).thenReturn(null);
- unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster,
null);
+ when(imageStoreDao.findOneByZoneAndProtocol(anyLong(),
anyString())).thenReturn(null);
+ unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster,
null, null);
+ }
+
+ @Test
+ public void
testSelectKVMHostForImportingInClusterWithImportInstanceIdSuccess() {
+ Long hostId = 1L;
+ ClusterVO cluster = getClusterForTests();
+ HostVO host = Mockito.mock(HostVO.class);
+ when(host.getResourceState()).thenReturn(ResourceState.Enabled);
+ when(host.getStatus()).thenReturn(Status.Up);
+ when(host.getType()).thenReturn(Host.Type.Routing);
+ when(host.getClusterId()).thenReturn(1L);
+
+ when(hostDao.findById(hostId)).thenReturn(host);
+
+ HostVO returnedHost =
unmanagedVMsManager.selectKVMHostForImportingInCluster(cluster, hostId);
+ Assert.assertEquals(host, returnedHost);
+ }
+
+ @Test
+ public void
testSelectKVMHostForImportingInClusterWithNullImportInstanceIdSuccess() {
+ ClusterVO cluster = getClusterForTests();
+ HostVO host = Mockito.mock(HostVO.class);
+ when(hostDao.listByClusterAndHypervisorType(cluster.getId(),
cluster.getHypervisorType())).thenReturn(List.of(host));
+
+ HostVO returnedHost =
unmanagedVMsManager.selectKVMHostForImportingInCluster(cluster, null);
+ Assert.assertEquals(host, returnedHost);
+ }
+
+ @Test(expected = CloudRuntimeException.class)
+ public void testSelectKVMHostForImportingInClusterFailure() {
+ ClusterVO cluster = getClusterForTests();
+ when(hostDao.listByClusterAndHypervisorType(cluster.getId(),
cluster.getHypervisorType())).thenReturn(List.of());
+
+ unmanagedVMsManager.selectKVMHostForImportingInCluster(cluster, null);
+ }
+
+ @Test(expected = CloudRuntimeException.class)
+ public void
testSelectKVMHostForImportingInClusterWithImportInstanceIdInvalidCluster() {
+ Long hostId = 1L;
+ ClusterVO cluster = getClusterForTests();
+ HostVO host = Mockito.mock(HostVO.class);
+ when(host.getResourceState()).thenReturn(ResourceState.Enabled);
+ when(host.getStatus()).thenReturn(Status.Up);
+ when(host.getType()).thenReturn(Host.Type.Routing);
+ when(host.getClusterId()).thenReturn(2L);
+
+ when(hostDao.findById(hostId)).thenReturn(host);
+
+ unmanagedVMsManager.selectKVMHostForImportingInCluster(cluster,
hostId);
+ }
+
+ @Test(expected = CloudRuntimeException.class)
+ public void
testSelectKVMHostForImportingInClusterWithImportInstanceIdInvalidType() {
+ Long hostId = 1L;
+ ClusterVO cluster = getClusterForTests();
+ HostVO host = Mockito.mock(HostVO.class);
+ when(host.getResourceState()).thenReturn(ResourceState.Enabled);
+ when(host.getStatus()).thenReturn(Status.Up);
+ when(host.getType()).thenReturn(Host.Type.Storage);
+
+ when(hostDao.findById(hostId)).thenReturn(host);
+
+ unmanagedVMsManager.selectKVMHostForImportingInCluster(cluster,
hostId);
+ }
+
+ @Test(expected = CloudRuntimeException.class)
+ public void
testSelectKVMHostForImportingInClusterWithImportInstanceIdInvalidStatus() {
+ Long hostId = 1L;
+ ClusterVO cluster = getClusterForTests();
+ HostVO host = Mockito.mock(HostVO.class);
+ when(host.getResourceState()).thenReturn(ResourceState.Enabled);
+ when(host.getStatus()).thenReturn(Status.Alert);
+
+ when(hostDao.findById(hostId)).thenReturn(host);
+
+ unmanagedVMsManager.selectKVMHostForImportingInCluster(cluster,
hostId);
+ }
+
+ @Test(expected = CloudRuntimeException.class)
+ public void
testSelectKVMHostForImportingInClusterWithImportInstanceIdInvalidResourceState()
{
+ Long hostId = 1L;
+ ClusterVO cluster = getClusterForTests();
+ HostVO host = Mockito.mock(HostVO.class);
+ when(host.getResourceState()).thenReturn(ResourceState.Disabled);
+
+ when(hostDao.findById(hostId)).thenReturn(host);
+
+ unmanagedVMsManager.selectKVMHostForImportingInCluster(cluster,
hostId);
+ }
+
+ @Test(expected = CloudRuntimeException.class)
+ public void
testSelectKVMHostForImportingInClusterWithImportInstanceIdInvalidHostId() {
+ Long hostId = 1L;
+ ClusterVO cluster = getClusterForTests();
+
+ when(hostDao.findById(hostId)).thenReturn(null);
+
+ unmanagedVMsManager.selectKVMHostForImportingInCluster(cluster,
hostId);
+ }
+
+ @Test
+ public void
testSelectKVMHostForConversionInClusterWithImportInstanceIdEnabledHost() {
+ Long hostId = 1L;
+ ClusterVO cluster = getClusterForTests();
+ HostVO host = Mockito.mock(HostVO.class);
+ when(host.getResourceState()).thenReturn(ResourceState.Enabled);
+ when(host.getStatus()).thenReturn(Status.Up);
+ when(host.getType()).thenReturn(Host.Type.Routing);
+ when(host.getDataCenterId()).thenReturn(1L);
+
+ when(hostDao.findById(hostId)).thenReturn(host);
+
+ HostVO returnedHost =
unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster, hostId);
+ Assert.assertEquals(host, returnedHost);
+ }
+
+ @Test
+ public void
testSelectKVMHostForConversionInClusterWithImportInstanceIdDisabledHost() {
+ Long hostId = 1L;
+ ClusterVO cluster = getClusterForTests();
+ HostVO host = Mockito.mock(HostVO.class);
+ when(host.getResourceState()).thenReturn(ResourceState.Disabled);
+ when(host.getStatus()).thenReturn(Status.Up);
+ when(host.getType()).thenReturn(Host.Type.Routing);
+ when(host.getDataCenterId()).thenReturn(1L);
+
+ when(hostDao.findById(hostId)).thenReturn(host);
+
+ HostVO returnedHost =
unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster, hostId);
+ Assert.assertEquals(host, returnedHost);
+ }
+
+ @Test
+ public void
testSelectKVMHostForConversionInClusterWithImportInstanceIdSuccessCompatible() {
+ ClusterVO cluster = getClusterForTests();
+ HostVO host = Mockito.mock(HostVO.class);
+
+
when(hostDao.listByClusterHypervisorTypeAndHostCapability(cluster.getId(),
+ cluster.getHypervisorType(),
Host.HOST_INSTANCE_CONVERSION)).thenReturn(List.of(host));
+
+ HostVO returnedHost =
unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster, null);
+ Assert.assertEquals(host, returnedHost);
+ }
+
+ @Test
+ public void
testSelectKVMHostForConversionInClusterWithImportInstanceIdSuccessNonCompatible()
{
+ ClusterVO cluster = getClusterForTests();
+ HostVO host = Mockito.mock(HostVO.class);
+
+
when(hostDao.listByClusterHypervisorTypeAndHostCapability(cluster.getId(),
+ cluster.getHypervisorType(),
Host.HOST_INSTANCE_CONVERSION)).thenReturn(List.of());
+
+ when(hostDao.listByClusterAndHypervisorType(cluster.getId(),
cluster.getHypervisorType())).thenReturn(List.of(host));
+
+ HostVO returnedHost =
unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster, null);
+ Assert.assertEquals(host, returnedHost);
+ }
+
+ @Test(expected = CloudRuntimeException.class)
+ public void
testSelectKVMHostForConversionInClusterWithImportInstanceIdFailure() {
+ ClusterVO cluster = getClusterForTests();
+
+
when(hostDao.listByClusterHypervisorTypeAndHostCapability(cluster.getId(),
+ cluster.getHypervisorType(),
Host.HOST_INSTANCE_CONVERSION)).thenReturn(List.of());
+
+ when(hostDao.listByClusterAndHypervisorType(cluster.getId(),
cluster.getHypervisorType())).thenReturn(List.of());
+
+ unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster, null);
+ }
+
+ @Test(expected = CloudRuntimeException.class)
+ public void
testSelectKVMHostForConversionInClusterWithImportInstanceIdInvalidZone() {
+ Long hostId = 1L;
+ ClusterVO cluster = getClusterForTests();
+ HostVO host = Mockito.mock(HostVO.class);
+ when(host.getResourceState()).thenReturn(ResourceState.Enabled);
+ when(host.getStatus()).thenReturn(Status.Up);
+ when(host.getType()).thenReturn(Host.Type.Routing);
+ when(host.getDataCenterId()).thenReturn(2L);
+
+ when(hostDao.findById(hostId)).thenReturn(host);
+
+ unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster,
hostId);
+ }
+
+ @Test(expected = CloudRuntimeException.class)
+ public void
testSelectKVMHostForConversionInClusterWithImportInstanceIdInvalidType() {
+ Long hostId = 1L;
+ ClusterVO cluster = getClusterForTests();
+ HostVO host = Mockito.mock(HostVO.class);
+ when(host.getResourceState()).thenReturn(ResourceState.Enabled);
+ when(host.getStatus()).thenReturn(Status.Up);
+ when(host.getType()).thenReturn(Host.Type.SecondaryStorage);
+
+ when(hostDao.findById(hostId)).thenReturn(host);
+
+ unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster,
hostId);
+ }
+
+ @Test(expected = CloudRuntimeException.class)
+ public void
testSelectKVMHostForConversionInClusterWithImportInstanceIdInvalidStatus() {
+ Long hostId = 1L;
+ ClusterVO cluster = getClusterForTests();
+ HostVO host = Mockito.mock(HostVO.class);
+ when(host.getResourceState()).thenReturn(ResourceState.Enabled);
+ when(host.getStatus()).thenReturn(Status.Down);
+
+ when(hostDao.findById(hostId)).thenReturn(host);
+
+ unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster,
hostId);
+ }
+
+ @Test(expected = CloudRuntimeException.class)
+ public void
testSelectKVMHostForConversionInClusterWithImportInstanceIdInvalidResourceState()
{
+ Long hostId = 1L;
+ ClusterVO cluster = getClusterForTests();
+ HostVO host = Mockito.mock(HostVO.class);
+ when(host.getResourceState()).thenReturn(ResourceState.Maintenance);
+
+ when(hostDao.findById(hostId)).thenReturn(host);
+
+ unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster,
hostId);
+ }
+
+ @Test(expected = CloudRuntimeException.class)
+ public void
testSelectKVMHostForConversionInClusterWithImportInstanceIdInvalidHostId() {
+ Long hostId = 1L;
+ ClusterVO cluster = getClusterForTests();
+
+ when(hostDao.findById(hostId)).thenReturn(null);
+
+ unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster,
hostId);
}
}
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 9e507a82023..48f78f598eb 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -923,7 +923,7 @@
"label.for": "for",
"label.forbidden": "Forbidden",
"label.forced": "Force",
-"label.force.ms.to.import.vm.files": "Force MS to import VM file(s) to
temporary storage",
+"label.force.ms.to.import.vm.files": "Force MS to export OVF from VMware to
temporary storage",
"label.force.stop": "Force stop",
"label.force.reboot": "Force reboot",
"label.forceencap": "Force UDP encapsulation of ESP packets",
@@ -1456,6 +1456,7 @@
"label.noselect": "No thanks",
"label.not.found": "Not found",
"label.not.suitable": "Not suitable",
+"label.not.supported": "Not supported",
"label.notifications": "Notifications",
"label.num.cpu.cores": "# of CPU cores",
"label.number": "#Rule",
@@ -3132,7 +3133,8 @@
"message.select.destination.image.stores": "Please select Image Store(s) to
which data is to be migrated to",
"message.select.disk.offering": "Please select a disk offering for disk",
"message.select.end.date.and.time": "Select an end date & time.",
-"message.select.kvm.host.instance.conversion": "(Optional) Select a KVM host
in the cluster to perform the instance conversion through virt-v2v",
+"message.select.kvm.host.instance.conversion": "(Optional) Select a KVM host
in the zone to perform the instance conversion through virt-v2v",
+"message.select.kvm.host.instance.import": "(Optional) Select a KVM host in
the cluster to perform the importing of the converted instance",
"message.select.load.balancer.rule": "Please select a load balancer rule for
your AutoScale Instance group.",
"message.select.migration.policy": "Please select a migration policy.",
"message.select.nic.network": "Please select a Network for NIC",
diff --git a/ui/src/views/tools/ImportUnmanagedInstance.vue
b/ui/src/views/tools/ImportUnmanagedInstance.vue
index 66efb764f0c..50a0d631808 100644
--- a/ui/src/views/tools/ImportUnmanagedInstance.vue
+++ b/ui/src/views/tools/ImportUnmanagedInstance.vue
@@ -164,6 +164,18 @@
@handle-checkselectpair-change="updateSelectedKvmHostForConversion"
/>
</a-form-item>
+ <a-form-item name="importhostid" ref="importhostid">
+ <check-box-select-pair
+ layout="vertical"
+ v-if="cluster.hypervisortype === 'KVM' &&
selectedVmwareVcenter"
+ :resourceKey="cluster.id"
+ :selectOptions="kvmHostsForImporting"
+
:checkBoxLabel="$t('message.select.kvm.host.instance.import')"
+ :defaultCheckBoxValue="false"
+ :reversed="false"
+
@handle-checkselectpair-change="updateSelectedKvmHostForImporting"
+ />
+ </a-form-item>
<a-form-item name="convertstorageoption"
ref="convertstorageoption">
<check-box-select-pair
layout="vertical"
@@ -494,7 +506,9 @@ export default {
switches: {},
loading: false,
kvmHostsForConversion: [],
+ kvmHostsForImporting: [],
selectedKvmHostForConversion: null,
+ selectedKvmHostForImporting: null,
storageOptionsForConversion: [
{
id: 'secondary',
@@ -730,6 +744,7 @@ export default {
page: 1
})
this.fetchKvmHostsForConversion()
+ this.fetchKvmHostsForImporting()
if (this.resource?.disk?.length > 1) {
this.updateSelectedRootDisk()
}
@@ -915,26 +930,47 @@ export default {
},
fetchKvmHostsForConversion () {
api('listHosts', {
- clusterid: this.cluster.id,
+ zoneid: this.zoneid,
hypervisor: this.cluster.hypervisortype,
type: 'Routing',
- state: 'Up',
- resourcestate: 'Enabled'
+ state: 'Up'
}).then(json => {
this.kvmHostsForConversion = json.listhostsresponse.host || []
+ this.kvmHostsForConversion = this.kvmHostsForConversion.filter(host =>
['Enabled', 'Disabled'].includes(host.resourcestate))
this.kvmHostsForConversion.map(host => {
+ host.name = host.name + ' [Pod=' + host.podname + '] [Cluster=' +
host.clustername + ']'
if (host.instanceconversionsupported !== null &&
host.instanceconversionsupported !== undefined &&
host.instanceconversionsupported) {
host.name = host.name + ' (' + this.$t('label.supported') + ')'
+ } else {
+ host.name = host.name + ' (' + this.$t('label.not.supported') + ')'
}
})
})
},
+ fetchKvmHostsForImporting () {
+ api('listHosts', {
+ clusterid: this.cluster.id,
+ hypervisor: this.cluster.hypervisortype,
+ type: 'Routing',
+ state: 'Up',
+ resourcestate: 'Enabled'
+ }).then(json => {
+ this.kvmHostsForImporting = json.listhostsresponse.host || []
+ })
+ },
fetchStoragePoolsForConversion () {
if (this.selectedStorageOptionForConversion === 'primary') {
- api('listStoragePools', {
- zoneid: this.cluster.zoneid,
+ const params = {
+ clusterid: this.cluster.id,
status: 'Up'
- }).then(json => {
+ }
+ if (this.selectedKvmHostForConversion) {
+ const kvmHost = this.kvmHostsForConversion.filter(x => x.id ===
this.selectedKvmHostForConversion)[0]
+ if (kvmHost.clusterid !== this.cluster.id) {
+ params.scope = 'ZONE'
+ }
+ }
+ api('listStoragePools', params).then(json => {
this.storagePoolsForConversion =
json.liststoragepoolsresponse.storagepool || []
})
} else if (this.selectedStorageOptionForConversion === 'local') {
@@ -948,6 +984,14 @@ export default {
})
}
},
+ updateSelectedKvmHostForImporting (clusterid, checked, value) {
+ if (checked) {
+ this.selectedKvmHostForImporting = value
+ } else {
+ this.selectedKvmHostForImporting = null
+ this.resetStorageOptionsForConversion()
+ }
+ },
updateSelectedKvmHostForConversion (clusterid, checked, value) {
if (checked) {
this.selectedKvmHostForConversion = value
@@ -1099,6 +1143,9 @@ export default {
if (this.selectedKvmHostForConversion) {
params.convertinstancehostid = this.selectedKvmHostForConversion
}
+ if (this.selectedKvmHostForImporting) {
+ params.importinstancehostid = this.selectedKvmHostForImporting
+ }
if (this.selectedStoragePoolForConversion) {
params.convertinstancepoolid =
this.selectedStoragePoolForConversion
}
diff --git a/ui/src/views/tools/ManageInstances.vue
b/ui/src/views/tools/ManageInstances.vue
index b61c8a9efa5..2ff9052d8b9 100644
--- a/ui/src/views/tools/ManageInstances.vue
+++ b/ui/src/views/tools/ManageInstances.vue
@@ -826,7 +826,8 @@ export default {
options: {
zoneid: _.get(this.zone, 'id'),
podid: this.podId,
- hypervisor: this.destinationHypervisor
+ hypervisor: this.destinationHypervisor,
+ allocationstate: 'Enabled'
},
field: 'clusterid'
},