mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Improve migration of external VMware VMs into KVM cluster (#8815)
* Create/Export OVA file of the VM on external vCenter host, to temporary conversion location (NFS) * Fixed ova issue on untar/extract ovf from ova file "tar -xf" cmd on ova fails with "ovf: Not found in archive" while extracting ovf file * Updated VMware to KVM instance migration using OVA * Refactoring and cleanup * test fixes * Consider zone wide pools in the destination cluster for instance conversion * Remove local storage pool support as temporary conversion location - OVA export not possible as the pool is not accessible outside host, NFS pools are supported. * cleanup unused code * some improvements, and refactoring * import nic unit tests * vmware guru unit tests * Separate clone VM and create template file for VMware migration - Export OVA (of the cloned VM) to the conversion location takes time. - Do any validations with cloned VM before creating the template (and fail early). - Updated unit tests. * Check conversion support on host before clone vm / create template on vmware (and fail early) * minor code improvements * Auto select the host with instance conversion capability * Skip instance conversion supported response param for non-KVM hosts * Show supported conversion hosts in the UI * Skip persistence map update if network doesn't exist * Added support to export OVA from KVM host, through ovftool (when installed in KVM host) * Updated importvm api param 'usemsforovaexport' to 'forcemstodownloadvmfiles', to be generic * Updated hardcoded UI messages with message labels * Updated UI to support importvm api param - forcemstodownloadvmfiles * Improved instance conversion support checks on ubuntu hosts, and for windows guest vms * Use OVF template (VM disks and spec files) for instance conversion from VMware, instead of OVA file - this would further increase the migration performance (as it reduces the time for OVA preparation / archiving of the VM files into a single file) * OVF export tool parallel threads code improvements * Updated 'convert.vmware.instance.to.kvm.timeout' config default value to 3 hrs * Config values check & code improvements * Updated import log, with time taken and vm details * Support for parallel downloads of VMware VM disk files while exporting OVF from MS, and other changes below. - Skip clone for powered off VMs - Fixes to support standalone host (with its default datacenter) - Some code improvements * rebase fixes * rebase fixes * minor improvement * code improvements - threads configuration, and api parameter changes to import vm files * typo fix in error msg
This commit is contained in:
parent
23f8856c7d
commit
46f672563e
@ -751,7 +751,7 @@ public class AgentProperties{
|
|||||||
public static final Property<Integer> IOTHREADS = new Property<>("iothreads", 1);
|
public static final Property<Integer> IOTHREADS = new Property<>("iothreads", 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable verbose mode for virt-v2v Instance Conversion from Vmware to KVM
|
* Enable verbose mode for virt-v2v Instance Conversion from VMware to KVM
|
||||||
* Data type: Boolean.<br>
|
* Data type: Boolean.<br>
|
||||||
* Default value: <code>false</code>
|
* Default value: <code>false</code>
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -18,40 +18,39 @@
|
|||||||
*/
|
*/
|
||||||
package com.cloud.agent.api.to;
|
package com.cloud.agent.api.to;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
import com.cloud.agent.api.LogLevel;
|
import com.cloud.agent.api.LogLevel;
|
||||||
import com.cloud.hypervisor.Hypervisor;
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
public class RemoteInstanceTO implements Serializable {
|
public class RemoteInstanceTO implements Serializable {
|
||||||
|
|
||||||
private Hypervisor.HypervisorType hypervisorType;
|
private Hypervisor.HypervisorType hypervisorType;
|
||||||
private String hostName;
|
|
||||||
private String instanceName;
|
private String instanceName;
|
||||||
|
|
||||||
// Vmware Remote Instances parameters
|
// VMware Remote Instances parameters (required for exporting OVA through ovftool)
|
||||||
// TODO: cloud.agent.transport.Request#getCommands() cannot handle gsoc decode for polymorphic classes
|
// TODO: cloud.agent.transport.Request#getCommands() cannot handle gsoc decode for polymorphic classes
|
||||||
private String vcenterUsername;
|
private String vcenterUsername;
|
||||||
@LogLevel(LogLevel.Log4jLevel.Off)
|
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||||
private String vcenterPassword;
|
private String vcenterPassword;
|
||||||
private String vcenterHost;
|
private String vcenterHost;
|
||||||
private String datacenterName;
|
private String datacenterName;
|
||||||
private String clusterName;
|
|
||||||
|
|
||||||
public RemoteInstanceTO() {
|
public RemoteInstanceTO() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public RemoteInstanceTO(String hostName, String instanceName, String vcenterHost,
|
public RemoteInstanceTO(String instanceName) {
|
||||||
String datacenterName, String clusterName,
|
this.hypervisorType = Hypervisor.HypervisorType.VMware;
|
||||||
String vcenterUsername, String vcenterPassword) {
|
this.instanceName = instanceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RemoteInstanceTO(String instanceName, String vcenterHost, String vcenterUsername, String vcenterPassword, String datacenterName) {
|
||||||
this.hypervisorType = Hypervisor.HypervisorType.VMware;
|
this.hypervisorType = Hypervisor.HypervisorType.VMware;
|
||||||
this.hostName = hostName;
|
|
||||||
this.instanceName = instanceName;
|
this.instanceName = instanceName;
|
||||||
this.vcenterHost = vcenterHost;
|
this.vcenterHost = vcenterHost;
|
||||||
this.datacenterName = datacenterName;
|
|
||||||
this.clusterName = clusterName;
|
|
||||||
this.vcenterUsername = vcenterUsername;
|
this.vcenterUsername = vcenterUsername;
|
||||||
this.vcenterPassword = vcenterPassword;
|
this.vcenterPassword = vcenterPassword;
|
||||||
|
this.datacenterName = datacenterName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Hypervisor.HypervisorType getHypervisorType() {
|
public Hypervisor.HypervisorType getHypervisorType() {
|
||||||
@ -62,10 +61,6 @@ public class RemoteInstanceTO implements Serializable {
|
|||||||
return this.instanceName;
|
return this.instanceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHostName() {
|
|
||||||
return this.hostName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVcenterUsername() {
|
public String getVcenterUsername() {
|
||||||
return vcenterUsername;
|
return vcenterUsername;
|
||||||
}
|
}
|
||||||
@ -81,8 +76,4 @@ public class RemoteInstanceTO implements Serializable {
|
|||||||
public String getDatacenterName() {
|
public String getDatacenterName() {
|
||||||
return datacenterName;
|
return datacenterName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getClusterName() {
|
|
||||||
return clusterName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,6 +54,7 @@ public interface Host extends StateObject<Status>, Identity, Partition, HAResour
|
|||||||
}
|
}
|
||||||
public static final String HOST_UEFI_ENABLE = "host.uefi.enable";
|
public static final String HOST_UEFI_ENABLE = "host.uefi.enable";
|
||||||
public static final String HOST_VOLUME_ENCRYPTION = "host.volume.encryption";
|
public static final String HOST_VOLUME_ENCRYPTION = "host.volume.encryption";
|
||||||
|
public static final String HOST_INSTANCE_CONVERSION = "host.instance.conversion";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return name of the machine.
|
* @return name of the machine.
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import org.apache.cloudstack.backup.Backup;
|
|||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
|
|
||||||
import com.cloud.agent.api.Command;
|
import com.cloud.agent.api.Command;
|
||||||
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
import com.cloud.agent.api.to.NicTO;
|
import com.cloud.agent.api.to.NicTO;
|
||||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
@ -101,21 +102,20 @@ public interface HypervisorGuru extends Adapter {
|
|||||||
* Will generate commands to migrate a vm to a pool. For now this will only work for stopped VMs on Vmware.
|
* Will generate commands to migrate a vm to a pool. For now this will only work for stopped VMs on Vmware.
|
||||||
*
|
*
|
||||||
* @param vm the stopped vm to migrate
|
* @param vm the stopped vm to migrate
|
||||||
* @param destination the primary storage pool to migrate to
|
* @param volumeToPool the primary storage pools to migrate to
|
||||||
* @return a list of commands to perform for a successful migration
|
* @return a list of commands to perform for a successful migration
|
||||||
*/
|
*/
|
||||||
List<Command> finalizeMigrate(VirtualMachine vm, Map<Volume, StoragePool> volumeToPool);
|
List<Command> finalizeMigrate(VirtualMachine vm, Map<Volume, StoragePool> volumeToPool);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will perform a clone of a VM on an external host (if the guru can handle)
|
* Will return the hypervisor VM (clone VM for PowerOn VMs), performs a clone of a VM if required on an external host (if the guru can handle)
|
||||||
* @param hostIp VM's source host IP
|
* @param hostIp VM's source host IP
|
||||||
* @param vmName name of the source VM to clone from
|
* @param vmName name of the source VM (clone VM name if cloned)
|
||||||
* @param params hypervisor specific additional parameters
|
* @param params hypervisor specific additional parameters
|
||||||
* @return a reference to the cloned VM
|
* @return a reference to the hypervisor or cloned VM, and cloned flag
|
||||||
*/
|
*/
|
||||||
UnmanagedInstanceTO cloneHypervisorVMOutOfBand(String hostIp, String vmName,
|
Pair<UnmanagedInstanceTO, Boolean> getHypervisorVMOutOfBandAndCloneIfRequired(String hostIp, String vmName, Map<String, String> params);
|
||||||
Map<String, String> params);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a VM created as a clone of a VM on an external host
|
* Removes a VM created as a clone of a VM on an external host
|
||||||
@ -124,6 +124,23 @@ public interface HypervisorGuru extends Adapter {
|
|||||||
* @param params hypervisor specific additional parameters
|
* @param params hypervisor specific additional parameters
|
||||||
* @return true if the operation succeeds, false if not
|
* @return true if the operation succeeds, false if not
|
||||||
*/
|
*/
|
||||||
boolean removeClonedHypervisorVMOutOfBand(String hostIp, String vmName,
|
boolean removeClonedHypervisorVMOutOfBand(String hostIp, String vmName, Map<String, String> params);
|
||||||
Map<String, String> params);
|
|
||||||
|
/**
|
||||||
|
* Create an OVA/OVF template of a VM on an external host (if the guru can handle)
|
||||||
|
* @param hostIp VM's source host IP
|
||||||
|
* @param vmName name of the source VM to create template from
|
||||||
|
* @param params hypervisor specific additional parameters
|
||||||
|
* @param templateLocation datastore to create the template file
|
||||||
|
* @return the created template dir/name
|
||||||
|
*/
|
||||||
|
String createVMTemplateOutOfBand(String hostIp, String vmName, Map<String, String> params, DataStoreTO templateLocation, int threadsCountToExportOvf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the template on the location
|
||||||
|
* @param templateLocation datastore to remove the template file
|
||||||
|
* @param templateDir the template dir to remove from datastore
|
||||||
|
* @return true if the operation succeeds, false if not
|
||||||
|
*/
|
||||||
|
boolean removeVMTemplateOutOfBand(DataStoreTO templateLocation, String templateDir);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -189,6 +189,7 @@ public class ApiConstants {
|
|||||||
public static final String FORCED = "forced";
|
public static final String FORCED = "forced";
|
||||||
public static final String FORCED_DESTROY_LOCAL_STORAGE = "forcedestroylocalstorage";
|
public static final String FORCED_DESTROY_LOCAL_STORAGE = "forcedestroylocalstorage";
|
||||||
public static final String FORCE_DELETE_HOST = "forcedeletehost";
|
public static final String FORCE_DELETE_HOST = "forcedeletehost";
|
||||||
|
public static final String FORCE_MS_TO_IMPORT_VM_FILES = "forcemstoimportvmfiles";
|
||||||
public static final String FORMAT = "format";
|
public static final String FORMAT = "format";
|
||||||
public static final String FOR_VIRTUAL_NETWORK = "forvirtualnetwork";
|
public static final String FOR_VIRTUAL_NETWORK = "forvirtualnetwork";
|
||||||
public static final String FOR_SYSTEM_VMS = "forsystemvms";
|
public static final String FOR_SYSTEM_VMS = "forsystemvms";
|
||||||
@ -236,6 +237,7 @@ public class ApiConstants {
|
|||||||
public static final String NEXT_ACL_RULE_ID = "nextaclruleid";
|
public static final String NEXT_ACL_RULE_ID = "nextaclruleid";
|
||||||
public static final String MOVE_ACL_CONSISTENCY_HASH = "aclconsistencyhash";
|
public static final String MOVE_ACL_CONSISTENCY_HASH = "aclconsistencyhash";
|
||||||
public static final String IMAGE_PATH = "imagepath";
|
public static final String IMAGE_PATH = "imagepath";
|
||||||
|
public static final String INSTANCE_CONVERSION_SUPPORTED = "instanceconversionsupported";
|
||||||
public static final String INTERNAL_DNS1 = "internaldns1";
|
public static final String INTERNAL_DNS1 = "internaldns1";
|
||||||
public static final String INTERNAL_DNS2 = "internaldns2";
|
public static final String INTERNAL_DNS2 = "internaldns2";
|
||||||
public static final String INTERNET_PROTOCOL = "internetprotocol";
|
public static final String INTERNET_PROTOCOL = "internetprotocol";
|
||||||
|
|||||||
@ -37,6 +37,7 @@ import org.apache.cloudstack.api.response.UserVmResponse;
|
|||||||
import org.apache.cloudstack.api.response.VmwareDatacenterResponse;
|
import org.apache.cloudstack.api.response.VmwareDatacenterResponse;
|
||||||
import org.apache.cloudstack.api.response.ZoneResponse;
|
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||||
import org.apache.cloudstack.vm.VmImportService;
|
import org.apache.cloudstack.vm.VmImportService;
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
@ -118,40 +119,44 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
|
|||||||
description = "Temp Path on external host for disk image copy" )
|
description = "Temp Path on external host for disk image copy" )
|
||||||
private String tmpPath;
|
private String tmpPath;
|
||||||
|
|
||||||
// Import from Vmware to KVM migration parameters
|
// Import from VMware to KVM migration parameters
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.EXISTING_VCENTER_ID,
|
@Parameter(name = ApiConstants.EXISTING_VCENTER_ID,
|
||||||
type = CommandType.UUID,
|
type = CommandType.UUID,
|
||||||
entityType = VmwareDatacenterResponse.class,
|
entityType = VmwareDatacenterResponse.class,
|
||||||
description = "(only for importing migrated VMs from Vmware to KVM) UUID of a linked existing vCenter")
|
description = "(only for importing VMs from VMware to KVM) UUID of a linked existing vCenter")
|
||||||
private Long existingVcenterId;
|
private Long existingVcenterId;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.HOST_IP,
|
@Parameter(name = ApiConstants.HOST_IP,
|
||||||
type = BaseCmd.CommandType.STRING,
|
type = BaseCmd.CommandType.STRING,
|
||||||
description = "(only for importing migrated VMs from Vmware to KVM) VMware ESXi host IP/Name.")
|
description = "(only for importing VMs from VMware to KVM) VMware ESXi host IP/Name.")
|
||||||
private String hostip;
|
private String hostip;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.VCENTER,
|
@Parameter(name = ApiConstants.VCENTER,
|
||||||
type = CommandType.STRING,
|
type = CommandType.STRING,
|
||||||
description = "(only for importing migrated VMs from Vmware to KVM) The name/ip of vCenter. Make sure it is IP address or full qualified domain name for host running vCenter server.")
|
description = "(only for importing VMs from VMware to KVM) The name/ip of vCenter. Make sure it is IP address or full qualified domain name for host running vCenter server.")
|
||||||
private String vcenter;
|
private String vcenter;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.DATACENTER_NAME, type = CommandType.STRING,
|
@Parameter(name = ApiConstants.DATACENTER_NAME, type = CommandType.STRING,
|
||||||
description = "(only for importing migrated VMs from Vmware to KVM) Name of VMware datacenter.")
|
description = "(only for importing VMs from VMware to KVM) Name of VMware datacenter.")
|
||||||
private String datacenterName;
|
private String datacenterName;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.CLUSTER_NAME, type = CommandType.STRING,
|
@Parameter(name = ApiConstants.CLUSTER_NAME, type = CommandType.STRING,
|
||||||
description = "(only for importing migrated VMs from Vmware to KVM) Name of VMware cluster.")
|
description = "(only for importing VMs from VMware to KVM) Name of VMware cluster.")
|
||||||
private String clusterName;
|
private String clusterName;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.CONVERT_INSTANCE_HOST_ID, type = CommandType.UUID, entityType = HostResponse.class,
|
@Parameter(name = ApiConstants.CONVERT_INSTANCE_HOST_ID, type = CommandType.UUID, entityType = HostResponse.class,
|
||||||
description = "(only for importing migrated 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 migration from VMware to KVM.")
|
||||||
private Long convertInstanceHostId;
|
private Long convertInstanceHostId;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.CONVERT_INSTANCE_STORAGE_POOL_ID, type = CommandType.UUID, entityType = StoragePoolResponse.class,
|
@Parameter(name = ApiConstants.CONVERT_INSTANCE_STORAGE_POOL_ID, type = CommandType.UUID, entityType = StoragePoolResponse.class,
|
||||||
description = "(only for importing migrated VMs from Vmware to KVM) optional - the temporary storage pool to perform the virt-v2v migration from VMware to KVM.")
|
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;
|
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.")
|
||||||
|
private Boolean forceMsToImportVmFiles;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -200,6 +205,10 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
|
|||||||
return convertStoragePoolId;
|
return convertStoragePoolId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getForceMsToImportVmFiles() {
|
||||||
|
return BooleanUtils.toBooleanDefaultIfNull(forceMsToImportVmFiles, false);
|
||||||
|
}
|
||||||
|
|
||||||
public String getHypervisor() {
|
public String getHypervisor() {
|
||||||
return hypervisor;
|
return hypervisor;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement;
|
|||||||
|
|
||||||
import com.cloud.host.Host;
|
import com.cloud.host.Host;
|
||||||
import com.cloud.host.Status;
|
import com.cloud.host.Status;
|
||||||
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
import com.cloud.serializer.Param;
|
import com.cloud.serializer.Param;
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
@ -277,6 +278,10 @@ public class HostResponse extends BaseResponseWithAnnotations {
|
|||||||
@Param(description = "true if the host supports encryption", since = "4.18")
|
@Param(description = "true if the host supports encryption", since = "4.18")
|
||||||
private Boolean encryptionSupported;
|
private Boolean encryptionSupported;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.INSTANCE_CONVERSION_SUPPORTED)
|
||||||
|
@Param(description = "true if the host supports instance conversion (using virt-v2v)", since = "4.19.1")
|
||||||
|
private Boolean instanceConversionSupported;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getObjectId() {
|
public String getObjectId() {
|
||||||
return this.getId();
|
return this.getId();
|
||||||
@ -526,7 +531,7 @@ public class HostResponse extends BaseResponseWithAnnotations {
|
|||||||
this.username = username;
|
this.username = username;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDetails(Map details) {
|
public void setDetails(Map details, Hypervisor.HypervisorType hypervisorType) {
|
||||||
|
|
||||||
if (details == null) {
|
if (details == null) {
|
||||||
return;
|
return;
|
||||||
@ -547,6 +552,15 @@ public class HostResponse extends BaseResponseWithAnnotations {
|
|||||||
this.setEncryptionSupported(new Boolean(false)); // default
|
this.setEncryptionSupported(new Boolean(false)); // default
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Hypervisor.HypervisorType.KVM.equals(hypervisorType)) {
|
||||||
|
if (detailsCopy.containsKey(Host.HOST_INSTANCE_CONVERSION)) {
|
||||||
|
this.setInstanceConversionSupported(Boolean.parseBoolean((String) detailsCopy.get(Host.HOST_INSTANCE_CONVERSION)));
|
||||||
|
detailsCopy.remove(Host.HOST_INSTANCE_CONVERSION);
|
||||||
|
} else {
|
||||||
|
this.setInstanceConversionSupported(new Boolean(false)); // default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.details = detailsCopy;
|
this.details = detailsCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -737,6 +751,10 @@ public class HostResponse extends BaseResponseWithAnnotations {
|
|||||||
this.encryptionSupported = encryptionSupported;
|
this.encryptionSupported = encryptionSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setInstanceConversionSupported(Boolean instanceConversionSupported) {
|
||||||
|
this.instanceConversionSupported = instanceConversionSupported;
|
||||||
|
}
|
||||||
|
|
||||||
public Boolean getIsTagARule() {
|
public Boolean getIsTagARule() {
|
||||||
return isTagARule;
|
return isTagARule;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
package org.apache.cloudstack.vm;
|
package org.apache.cloudstack.vm;
|
||||||
|
|
||||||
|
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class UnmanagedInstanceTO {
|
public class UnmanagedInstanceTO {
|
||||||
@ -317,6 +319,16 @@ public class UnmanagedInstanceTO {
|
|||||||
public int getDatastorePort() {
|
public int getDatastorePort() {
|
||||||
return datastorePort;
|
return datastorePort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Disk {" +
|
||||||
|
"diskId='" + diskId + '\'' +
|
||||||
|
", capacity=" + toHumanReadableSize(capacity) +
|
||||||
|
", controller='" + controller + '\'' +
|
||||||
|
", controllerUnit=" + controllerUnit +
|
||||||
|
"}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Nic {
|
public static class Nic {
|
||||||
@ -409,5 +421,14 @@ public class UnmanagedInstanceTO {
|
|||||||
public void setPciSlot(String pciSlot) {
|
public void setPciSlot(String pciSlot) {
|
||||||
this.pciSlot = pciSlot;
|
this.pciSlot = pciSlot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Nic{" +
|
||||||
|
"nicId='" + nicId + '\'' +
|
||||||
|
", adapterType='" + adapterType + '\'' +
|
||||||
|
", macAddress='" + macAddress + '\'' +
|
||||||
|
"}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,6 +39,37 @@ public interface UnmanagedVMsManager extends VmImportService, UnmanageVMService,
|
|||||||
ConfigKey.Scope.Global,
|
ConfigKey.Scope.Global,
|
||||||
null);
|
null);
|
||||||
|
|
||||||
|
ConfigKey<Integer> ConvertVmwareInstanceToKvmTimeout = new ConfigKey<>(Integer.class,
|
||||||
|
"convert.vmware.instance.to.kvm.timeout",
|
||||||
|
"Advanced",
|
||||||
|
"3",
|
||||||
|
"Timeout (in hours) for the instance conversion process from VMware through the virt-v2v binary on a KVM host",
|
||||||
|
true,
|
||||||
|
ConfigKey.Scope.Global,
|
||||||
|
null);
|
||||||
|
|
||||||
|
ConfigKey<Integer> ThreadsOnMSToImportVMwareVMFiles = new ConfigKey<>(Integer.class,
|
||||||
|
"threads.on.ms.to.import.vmware.vm.files",
|
||||||
|
"Advanced",
|
||||||
|
"0",
|
||||||
|
"Threads to use on the management server when importing VM files from VMWare." +
|
||||||
|
" -1 or 1 disables threads, 0 uses a thread per VM disk (disabled for single disk) and >1 for manual thread configuration." +
|
||||||
|
" Max number is 10, Default is 0.",
|
||||||
|
true,
|
||||||
|
ConfigKey.Scope.Global,
|
||||||
|
null);
|
||||||
|
|
||||||
|
ConfigKey<Integer> ThreadsOnKVMHostToImportVMwareVMFiles = new ConfigKey<>(Integer.class,
|
||||||
|
"threads.on.kvm.host.to.import.vmware.vm.files",
|
||||||
|
"Advanced",
|
||||||
|
"0",
|
||||||
|
"Threads to use on the KVM host (by the ovftool, if the version is 4.4.0+) when importing VM files from VMWare." +
|
||||||
|
" -1 or 1 disables threads, 0 uses a thread per VM disk (disabled for single disk) and >1 for manual thread configuration." +
|
||||||
|
" Max number is 10, Default is 0.",
|
||||||
|
true,
|
||||||
|
ConfigKey.Scope.Global,
|
||||||
|
null);
|
||||||
|
|
||||||
static boolean isSupported(Hypervisor.HypervisorType hypervisorType) {
|
static boolean isSupported(Hypervisor.HypervisorType hypervisorType) {
|
||||||
return hypervisorType == VMware || hypervisorType == KVM;
|
return hypervisorType == VMware || hypervisorType == KVM;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,8 @@ import org.junit.Test;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
|
|
||||||
public final class HostResponseTest extends TestCase {
|
public final class HostResponseTest extends TestCase {
|
||||||
|
|
||||||
private static final String VALID_KEY = "validkey";
|
private static final String VALID_KEY = "validkey";
|
||||||
@ -32,7 +34,7 @@ public final class HostResponseTest extends TestCase {
|
|||||||
public void testSetDetailsNull() {
|
public void testSetDetailsNull() {
|
||||||
|
|
||||||
final HostResponse hostResponse = new HostResponse();
|
final HostResponse hostResponse = new HostResponse();
|
||||||
hostResponse.setDetails(null);
|
hostResponse.setDetails(null, null);
|
||||||
|
|
||||||
assertEquals(null, hostResponse.getDetails());
|
assertEquals(null, hostResponse.getDetails());
|
||||||
|
|
||||||
@ -51,7 +53,7 @@ public final class HostResponseTest extends TestCase {
|
|||||||
final Map expectedDetails = new HashedMap();
|
final Map expectedDetails = new HashedMap();
|
||||||
expectedDetails.put(VALID_KEY, VALID_VALUE);
|
expectedDetails.put(VALID_KEY, VALID_VALUE);
|
||||||
|
|
||||||
hostResponse.setDetails(details);
|
hostResponse.setDetails(details, Hypervisor.HypervisorType.KVM);
|
||||||
final Map actualDetails = hostResponse.getDetails();
|
final Map actualDetails = hostResponse.getDetails();
|
||||||
|
|
||||||
assertTrue(details != actualDetails);
|
assertTrue(details != actualDetails);
|
||||||
@ -70,7 +72,7 @@ public final class HostResponseTest extends TestCase {
|
|||||||
final Map expectedDetails = new HashedMap();
|
final Map expectedDetails = new HashedMap();
|
||||||
expectedDetails.put(VALID_KEY, VALID_VALUE);
|
expectedDetails.put(VALID_KEY, VALID_VALUE);
|
||||||
|
|
||||||
hostResponse.setDetails(details);
|
hostResponse.setDetails(details, Hypervisor.HypervisorType.KVM);
|
||||||
final Map actualDetails = hostResponse.getDetails();
|
final Map actualDetails = hostResponse.getDetails();
|
||||||
|
|
||||||
assertTrue(details != actualDetails);
|
assertTrue(details != actualDetails);
|
||||||
|
|||||||
@ -0,0 +1,43 @@
|
|||||||
|
// 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;
|
||||||
|
|
||||||
|
public class CheckConvertInstanceAnswer extends Answer {
|
||||||
|
|
||||||
|
private boolean ovfExportSupported = false;
|
||||||
|
|
||||||
|
public CheckConvertInstanceAnswer() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckConvertInstanceAnswer(Command command, boolean success) {
|
||||||
|
super(command, success, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckConvertInstanceAnswer(Command command, boolean success, String details) {
|
||||||
|
super(command, success, details);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckConvertInstanceAnswer(Command command, boolean success, boolean ovfExportSupported, String details) {
|
||||||
|
super(command, success, details);
|
||||||
|
this.ovfExportSupported = ovfExportSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOvfExportSupported() {
|
||||||
|
return ovfExportSupported;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
// 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;
|
||||||
|
|
||||||
|
public class CheckConvertInstanceCommand extends Command {
|
||||||
|
boolean checkWindowsGuestConversionSupport = false;
|
||||||
|
|
||||||
|
public CheckConvertInstanceCommand() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckConvertInstanceCommand(boolean checkWindowsGuestConversionSupport) {
|
||||||
|
this.checkWindowsGuestConversionSupport = checkWindowsGuestConversionSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean executeInSequence() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getCheckWindowsGuestConversionSupport() {
|
||||||
|
return checkWindowsGuestConversionSupport;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -28,16 +28,24 @@ public class ConvertInstanceCommand extends Command {
|
|||||||
private Hypervisor.HypervisorType destinationHypervisorType;
|
private Hypervisor.HypervisorType destinationHypervisorType;
|
||||||
private List<String> destinationStoragePools;
|
private List<String> destinationStoragePools;
|
||||||
private DataStoreTO conversionTemporaryLocation;
|
private DataStoreTO conversionTemporaryLocation;
|
||||||
|
private String templateDirOnConversionLocation;
|
||||||
|
private boolean checkConversionSupport;
|
||||||
|
private boolean exportOvfToConversionLocation;
|
||||||
|
private int threadsCountToExportOvf = 0;
|
||||||
|
|
||||||
public ConvertInstanceCommand() {
|
public ConvertInstanceCommand() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConvertInstanceCommand(RemoteInstanceTO sourceInstance, Hypervisor.HypervisorType destinationHypervisorType,
|
public ConvertInstanceCommand(RemoteInstanceTO sourceInstance, Hypervisor.HypervisorType destinationHypervisorType,
|
||||||
List<String> destinationStoragePools, DataStoreTO conversionTemporaryLocation) {
|
List<String> destinationStoragePools, DataStoreTO conversionTemporaryLocation,
|
||||||
|
String templateDirOnConversionLocation, boolean checkConversionSupport, boolean exportOvfToConversionLocation) {
|
||||||
this.sourceInstance = sourceInstance;
|
this.sourceInstance = sourceInstance;
|
||||||
this.destinationHypervisorType = destinationHypervisorType;
|
this.destinationHypervisorType = destinationHypervisorType;
|
||||||
this.destinationStoragePools = destinationStoragePools;
|
this.destinationStoragePools = destinationStoragePools;
|
||||||
this.conversionTemporaryLocation = conversionTemporaryLocation;
|
this.conversionTemporaryLocation = conversionTemporaryLocation;
|
||||||
|
this.templateDirOnConversionLocation = templateDirOnConversionLocation;
|
||||||
|
this.checkConversionSupport = checkConversionSupport;
|
||||||
|
this.exportOvfToConversionLocation = exportOvfToConversionLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RemoteInstanceTO getSourceInstance() {
|
public RemoteInstanceTO getSourceInstance() {
|
||||||
@ -56,6 +64,26 @@ public class ConvertInstanceCommand extends Command {
|
|||||||
return conversionTemporaryLocation;
|
return conversionTemporaryLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTemplateDirOnConversionLocation() {
|
||||||
|
return templateDirOnConversionLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getCheckConversionSupport() {
|
||||||
|
return checkConversionSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getExportOvfToConversionLocation() {
|
||||||
|
return exportOvfToConversionLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getThreadsCountToExportOvf() {
|
||||||
|
return threadsCountToExportOvf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setThreadsCountToExportOvf(int threadsCountToExportOvf) {
|
||||||
|
this.threadsCountToExportOvf = threadsCountToExportOvf;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean executeInSequence() {
|
public boolean executeInSequence() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -97,14 +97,6 @@ public interface StorageManager extends StorageService {
|
|||||||
true,
|
true,
|
||||||
ConfigKey.Scope.Global,
|
ConfigKey.Scope.Global,
|
||||||
null);
|
null);
|
||||||
ConfigKey<Integer> ConvertVmwareInstanceToKvmTimeout = new ConfigKey<>(Integer.class,
|
|
||||||
"convert.vmware.instance.to.kvm.timeout",
|
|
||||||
"Storage",
|
|
||||||
"8",
|
|
||||||
"Timeout (in hours) for the instance conversion process from VMware through the virt-v2v binary on a KVM host",
|
|
||||||
true,
|
|
||||||
ConfigKey.Scope.Global,
|
|
||||||
null);
|
|
||||||
ConfigKey<Boolean> KvmAutoConvergence = new ConfigKey<>(Boolean.class,
|
ConfigKey<Boolean> KvmAutoConvergence = new ConfigKey<>(Boolean.class,
|
||||||
"kvm.auto.convergence",
|
"kvm.auto.convergence",
|
||||||
"Storage",
|
"Storage",
|
||||||
|
|||||||
@ -1972,20 +1972,24 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updatePersistenceMap(Map<String, Boolean> vlanToPersistenceMap, NetworkVO networkVO) {
|
private void updatePersistenceMap(Map<String, Boolean> vlanToPersistenceMap, NetworkVO networkVO) {
|
||||||
|
if (networkVO == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
NetworkOfferingVO offeringVO = networkOfferingDao.findById(networkVO.getNetworkOfferingId());
|
NetworkOfferingVO offeringVO = networkOfferingDao.findById(networkVO.getNetworkOfferingId());
|
||||||
if (offeringVO != null) {
|
if (offeringVO == null) {
|
||||||
Pair<String, Boolean> data = getVMNetworkDetails(networkVO, offeringVO.isPersistent());
|
return;
|
||||||
Boolean shouldDeleteNwResource = (MapUtils.isNotEmpty(vlanToPersistenceMap) && data != null) ? vlanToPersistenceMap.get(data.first()) : null;
|
}
|
||||||
if (data != null && (shouldDeleteNwResource == null || shouldDeleteNwResource)) {
|
Pair<String, Boolean> data = getVMNetworkDetails(networkVO, offeringVO.isPersistent());
|
||||||
vlanToPersistenceMap.put(data.first(), data.second());
|
Boolean shouldDeleteNwResource = (MapUtils.isNotEmpty(vlanToPersistenceMap) && data != null) ? vlanToPersistenceMap.get(data.first()) : null;
|
||||||
}
|
if (data != null && (shouldDeleteNwResource == null || shouldDeleteNwResource)) {
|
||||||
|
vlanToPersistenceMap.put(data.first(), data.second());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Boolean> getVlanToPersistenceMapForVM(long vmId) {
|
private Map<String, Boolean> getVlanToPersistenceMapForVM(long vmId) {
|
||||||
List<UserVmJoinVO> userVmJoinVOs = userVmJoinDao.searchByIds(vmId);
|
List<UserVmJoinVO> userVmJoinVOs = userVmJoinDao.searchByIds(vmId);
|
||||||
Map<String, Boolean> vlanToPersistenceMap = new HashMap<>();
|
Map<String, Boolean> vlanToPersistenceMap = new HashMap<>();
|
||||||
if (userVmJoinVOs != null && !userVmJoinVOs.isEmpty()) {
|
if (CollectionUtils.isNotEmpty(userVmJoinVOs)) {
|
||||||
for (UserVmJoinVO userVmJoinVO : userVmJoinVOs) {
|
for (UserVmJoinVO userVmJoinVO : userVmJoinVOs) {
|
||||||
NetworkVO networkVO = _networkDao.findById(userVmJoinVO.getNetworkId());
|
NetworkVO networkVO = _networkDao.findById(userVmJoinVO.getNetworkId());
|
||||||
updatePersistenceMap(vlanToPersistenceMap, networkVO);
|
updatePersistenceMap(vlanToPersistenceMap, networkVO);
|
||||||
|
|||||||
@ -4607,10 +4607,16 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
final NicVO vo = Transaction.execute(new TransactionCallback<NicVO>() {
|
final NicVO vo = Transaction.execute(new TransactionCallback<NicVO>() {
|
||||||
@Override
|
@Override
|
||||||
public NicVO doInTransaction(TransactionStatus status) {
|
public NicVO doInTransaction(TransactionStatus status) {
|
||||||
NicVO existingNic = _nicDao.findByNetworkIdAndMacAddress(network.getId(), macAddress);
|
if (StringUtils.isBlank(macAddress)) {
|
||||||
String macAddressToPersist = macAddress;
|
throw new CloudRuntimeException("Mac address not specified");
|
||||||
|
}
|
||||||
|
String macAddressToPersist = macAddress.trim();
|
||||||
|
if (!NetUtils.isValidMac(macAddressToPersist)) {
|
||||||
|
throw new CloudRuntimeException("Invalid mac address: " + macAddressToPersist);
|
||||||
|
}
|
||||||
|
NicVO existingNic = _nicDao.findByNetworkIdAndMacAddress(network.getId(), macAddressToPersist);
|
||||||
if (existingNic != null) {
|
if (existingNic != null) {
|
||||||
macAddressToPersist = generateNewMacAddressIfForced(network, macAddress, forced);
|
macAddressToPersist = generateNewMacAddressIfForced(network, macAddressToPersist, forced);
|
||||||
}
|
}
|
||||||
NicVO vo = new NicVO(network.getGuruName(), vm.getId(), network.getId(), vm.getType());
|
NicVO vo = new NicVO(network.getGuruName(), vm.getId(), network.getId(), vm.getType());
|
||||||
vo.setMacAddress(macAddressToPersist);
|
vo.setMacAddress(macAddressToPersist);
|
||||||
@ -4655,7 +4661,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
final NicProfile vmNic = new NicProfile(vo, network, vo.getBroadcastUri(), vo.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network),
|
final NicProfile vmNic = new NicProfile(vo, network, vo.getBroadcastUri(), vo.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network),
|
||||||
_networkModel.getNetworkTag(vm.getHypervisorType(), network));
|
_networkModel.getNetworkTag(vm.getHypervisorType(), network));
|
||||||
|
|
||||||
return new Pair<NicProfile, Integer>(vmNic, Integer.valueOf(deviceId));
|
return new Pair<>(vmNic, Integer.valueOf(deviceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getSelectedIpForNicImport(Network network, DataCenter dataCenter, Network.IpAddresses ipAddresses) {
|
protected String getSelectedIpForNicImport(Network network, DataCenter dataCenter, Network.IpAddresses ipAddresses) {
|
||||||
@ -4699,7 +4705,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
|
|
||||||
private String generateNewMacAddressIfForced(Network network, String macAddress, boolean forced) {
|
private String generateNewMacAddressIfForced(Network network, String macAddress, boolean forced) {
|
||||||
if (!forced) {
|
if (!forced) {
|
||||||
throw new CloudRuntimeException("NIC with MAC address = " + macAddress + " exists on network with ID = " + network.getId() +
|
throw new CloudRuntimeException("NIC with MAC address " + macAddress + " exists on network with ID " + network.getUuid() +
|
||||||
" and forced flag is disabled");
|
" and forced flag is disabled");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
package org.apache.cloudstack.engine.orchestration;
|
package org.apache.cloudstack.engine.orchestration;
|
||||||
|
|
||||||
import static org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService.NetworkLockTimeout;
|
import static org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService.NetworkLockTimeout;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
@ -31,8 +32,10 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.cloud.dc.DataCenter;
|
import com.cloud.dc.DataCenter;
|
||||||
|
import com.cloud.exception.InsufficientVirtualNetworkCapacityException;
|
||||||
import com.cloud.network.IpAddressManager;
|
import com.cloud.network.IpAddressManager;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@ -40,6 +43,7 @@ import org.junit.Test;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.JUnit4;
|
import org.junit.runners.JUnit4;
|
||||||
import org.mockito.Matchers;
|
import org.mockito.Matchers;
|
||||||
|
import org.mockito.MockedStatic;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
import com.cloud.api.query.dao.DomainRouterJoinDao;
|
import com.cloud.api.query.dao.DomainRouterJoinDao;
|
||||||
@ -72,6 +76,8 @@ import com.cloud.network.vpc.VpcManager;
|
|||||||
import com.cloud.network.vpc.VpcVO;
|
import com.cloud.network.vpc.VpcVO;
|
||||||
import com.cloud.offerings.NetworkOfferingVO;
|
import com.cloud.offerings.NetworkOfferingVO;
|
||||||
import com.cloud.utils.db.EntityManager;
|
import com.cloud.utils.db.EntityManager;
|
||||||
|
import com.cloud.utils.db.Transaction;
|
||||||
|
import com.cloud.utils.db.TransactionCallback;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.cloud.utils.net.Ip;
|
import com.cloud.utils.net.Ip;
|
||||||
import com.cloud.vm.DomainRouterVO;
|
import com.cloud.vm.DomainRouterVO;
|
||||||
@ -892,4 +898,118 @@ public class NetworkOrchestratorTest extends TestCase {
|
|||||||
verify(testOrchestrator._networksDao, times(1)).acquireInLockTable(networkId, NetworkLockTimeout.value());
|
verify(testOrchestrator._networksDao, times(1)).acquireInLockTable(networkId, NetworkLockTimeout.value());
|
||||||
verify(testOrchestrator._networksDao, times(1)).releaseFromLockTable(networkId);
|
verify(testOrchestrator._networksDao, times(1)).releaseFromLockTable(networkId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = InsufficientVirtualNetworkCapacityException.class)
|
||||||
|
public void testImportNicAcquireGuestIPFailed() throws Exception {
|
||||||
|
DataCenter dataCenter = Mockito.mock(DataCenter.class);
|
||||||
|
VirtualMachine vm = mock(VirtualMachine.class);
|
||||||
|
Network network = Mockito.mock(Network.class);
|
||||||
|
Mockito.when(network.getGuestType()).thenReturn(GuestType.Isolated);
|
||||||
|
Mockito.when(network.getNetworkOfferingId()).thenReturn(networkOfferingId);
|
||||||
|
long dataCenterId = 1L;
|
||||||
|
Mockito.when(network.getDataCenterId()).thenReturn(dataCenterId);
|
||||||
|
Network.IpAddresses ipAddresses = Mockito.mock(Network.IpAddresses.class);
|
||||||
|
String ipAddress = "10.1.10.10";
|
||||||
|
Mockito.when(ipAddresses.getIp4Address()).thenReturn(ipAddress);
|
||||||
|
Mockito.when(testOrchestrator.getSelectedIpForNicImport(network, dataCenter, ipAddresses)).thenReturn(null);
|
||||||
|
Mockito.when(testOrchestrator._networkModel.listNetworkOfferingServices(networkOfferingId)).thenReturn(Arrays.asList(Service.Dns, Service.Dhcp));
|
||||||
|
String macAddress = "02:01:01:82:00:01";
|
||||||
|
int deviceId = 0;
|
||||||
|
testOrchestrator.importNic(macAddress, deviceId, network, true, vm, ipAddresses, dataCenter, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InsufficientVirtualNetworkCapacityException.class)
|
||||||
|
public void testImportNicAutoAcquireGuestIPFailed() throws Exception {
|
||||||
|
DataCenter dataCenter = Mockito.mock(DataCenter.class);
|
||||||
|
VirtualMachine vm = mock(VirtualMachine.class);
|
||||||
|
Network network = Mockito.mock(Network.class);
|
||||||
|
Mockito.when(network.getGuestType()).thenReturn(GuestType.Isolated);
|
||||||
|
Mockito.when(network.getNetworkOfferingId()).thenReturn(networkOfferingId);
|
||||||
|
long dataCenterId = 1L;
|
||||||
|
Mockito.when(network.getDataCenterId()).thenReturn(dataCenterId);
|
||||||
|
Network.IpAddresses ipAddresses = Mockito.mock(Network.IpAddresses.class);
|
||||||
|
String ipAddress = "auto";
|
||||||
|
Mockito.when(ipAddresses.getIp4Address()).thenReturn(ipAddress);
|
||||||
|
Mockito.when(testOrchestrator.getSelectedIpForNicImport(network, dataCenter, ipAddresses)).thenReturn(null);
|
||||||
|
Mockito.when(testOrchestrator._networkModel.listNetworkOfferingServices(networkOfferingId)).thenReturn(Arrays.asList(Service.Dns, Service.Dhcp));
|
||||||
|
String macAddress = "02:01:01:82:00:01";
|
||||||
|
int deviceId = 0;
|
||||||
|
testOrchestrator.importNic(macAddress, deviceId, network, true, vm, ipAddresses, dataCenter, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testImportNicNoIP4Address() throws Exception {
|
||||||
|
DataCenter dataCenter = Mockito.mock(DataCenter.class);
|
||||||
|
Long vmId = 1L;
|
||||||
|
Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
|
||||||
|
VirtualMachine vm = mock(VirtualMachine.class);
|
||||||
|
Mockito.when(vm.getId()).thenReturn(vmId);
|
||||||
|
Mockito.when(vm.getHypervisorType()).thenReturn(hypervisorType);
|
||||||
|
Long networkId = 1L;
|
||||||
|
Network network = Mockito.mock(Network.class);
|
||||||
|
Mockito.when(network.getId()).thenReturn(networkId);
|
||||||
|
Network.IpAddresses ipAddresses = Mockito.mock(Network.IpAddresses.class);
|
||||||
|
Mockito.when(ipAddresses.getIp4Address()).thenReturn(null);
|
||||||
|
URI broadcastUri = URI.create("vlan://123");
|
||||||
|
NicVO nic = mock(NicVO.class);
|
||||||
|
Mockito.when(nic.getBroadcastUri()).thenReturn(broadcastUri);
|
||||||
|
String macAddress = "02:01:01:82:00:01";
|
||||||
|
int deviceId = 1;
|
||||||
|
Integer networkRate = 200;
|
||||||
|
Mockito.when(testOrchestrator._networkModel.getNetworkRate(networkId, vmId)).thenReturn(networkRate);
|
||||||
|
Mockito.when(testOrchestrator._networkModel.isSecurityGroupSupportedInNetwork(network)).thenReturn(false);
|
||||||
|
Mockito.when(testOrchestrator._networkModel.getNetworkTag(hypervisorType, network)).thenReturn("testtag");
|
||||||
|
try (MockedStatic<Transaction> transactionMocked = Mockito.mockStatic(Transaction.class)) {
|
||||||
|
transactionMocked.when(() -> Transaction.execute(any(TransactionCallback.class))).thenReturn(nic);
|
||||||
|
Pair<NicProfile, Integer> nicProfileIntegerPair = testOrchestrator.importNic(macAddress, deviceId, network, true, vm, ipAddresses, dataCenter, false);
|
||||||
|
verify(testOrchestrator._networkModel, times(1)).getNetworkRate(networkId, vmId);
|
||||||
|
verify(testOrchestrator._networkModel, times(1)).isSecurityGroupSupportedInNetwork(network);
|
||||||
|
verify(testOrchestrator._networkModel, times(1)).getNetworkTag(Hypervisor.HypervisorType.KVM, network);
|
||||||
|
assertEquals(deviceId, nicProfileIntegerPair.second().intValue());
|
||||||
|
NicProfile nicProfile = nicProfileIntegerPair.first();
|
||||||
|
assertEquals(broadcastUri, nicProfile.getBroadCastUri());
|
||||||
|
assertEquals(networkRate, nicProfile.getNetworkRate());
|
||||||
|
assertFalse(nicProfile.isSecurityGroupEnabled());
|
||||||
|
assertEquals("testtag", nicProfile.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testImportNicWithIP4Address() throws Exception {
|
||||||
|
DataCenter dataCenter = Mockito.mock(DataCenter.class);
|
||||||
|
Long vmId = 1L;
|
||||||
|
Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
|
||||||
|
VirtualMachine vm = mock(VirtualMachine.class);
|
||||||
|
Mockito.when(vm.getId()).thenReturn(vmId);
|
||||||
|
Mockito.when(vm.getHypervisorType()).thenReturn(hypervisorType);
|
||||||
|
Long networkId = 1L;
|
||||||
|
Network network = Mockito.mock(Network.class);
|
||||||
|
Mockito.when(network.getId()).thenReturn(networkId);
|
||||||
|
String ipAddress = "10.1.10.10";
|
||||||
|
Network.IpAddresses ipAddresses = Mockito.mock(Network.IpAddresses.class);
|
||||||
|
Mockito.when(ipAddresses.getIp4Address()).thenReturn(ipAddress);
|
||||||
|
URI broadcastUri = URI.create("vlan://123");
|
||||||
|
NicVO nic = mock(NicVO.class);
|
||||||
|
Mockito.when(nic.getBroadcastUri()).thenReturn(broadcastUri);
|
||||||
|
String macAddress = "02:01:01:82:00:01";
|
||||||
|
int deviceId = 1;
|
||||||
|
Integer networkRate = 200;
|
||||||
|
Mockito.when(testOrchestrator._networkModel.getNetworkRate(networkId, vmId)).thenReturn(networkRate);
|
||||||
|
Mockito.when(testOrchestrator._networkModel.isSecurityGroupSupportedInNetwork(network)).thenReturn(false);
|
||||||
|
Mockito.when(testOrchestrator._networkModel.getNetworkTag(hypervisorType, network)).thenReturn("testtag");
|
||||||
|
try (MockedStatic<Transaction> transactionMocked = Mockito.mockStatic(Transaction.class)) {
|
||||||
|
transactionMocked.when(() -> Transaction.execute(any(TransactionCallback.class))).thenReturn(nic);
|
||||||
|
Pair<NicProfile, Integer> nicProfileIntegerPair = testOrchestrator.importNic(macAddress, deviceId, network, true, vm, ipAddresses, dataCenter, false);
|
||||||
|
verify(testOrchestrator, times(1)).getSelectedIpForNicImport(network, dataCenter, ipAddresses);
|
||||||
|
verify(testOrchestrator._networkModel, times(1)).getNetworkRate(networkId, vmId);
|
||||||
|
verify(testOrchestrator._networkModel, times(1)).isSecurityGroupSupportedInNetwork(network);
|
||||||
|
verify(testOrchestrator._networkModel, times(1)).getNetworkTag(Hypervisor.HypervisorType.KVM, network);
|
||||||
|
assertEquals(deviceId, nicProfileIntegerPair.second().intValue());
|
||||||
|
NicProfile nicProfile = nicProfileIntegerPair.first();
|
||||||
|
assertEquals(broadcastUri, nicProfile.getBroadCastUri());
|
||||||
|
assertEquals(networkRate, nicProfile.getNetworkRate());
|
||||||
|
assertFalse(nicProfile.isSecurityGroupEnabled());
|
||||||
|
assertEquals("testtag", nicProfile.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -141,6 +141,8 @@ public interface HostDao extends GenericDao<HostVO, Long>, StateDao<Status, Stat
|
|||||||
|
|
||||||
List<HostVO> listByHostCapability(Host.Type type, Long clusterId, Long podId, long dcId, String hostCapabilty);
|
List<HostVO> listByHostCapability(Host.Type type, Long clusterId, Long podId, long dcId, String hostCapabilty);
|
||||||
|
|
||||||
|
List<HostVO> listByClusterHypervisorTypeAndHostCapability(Long clusterId, HypervisorType hypervisorType, String hostCapabilty);
|
||||||
|
|
||||||
List<HostVO> listByClusterAndHypervisorType(long clusterId, HypervisorType hypervisorType);
|
List<HostVO> listByClusterAndHypervisorType(long clusterId, HypervisorType hypervisorType);
|
||||||
|
|
||||||
HostVO findByName(String name);
|
HostVO findByName(String name);
|
||||||
|
|||||||
@ -344,6 +344,7 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
|
|||||||
ClusterHypervisorSearch.and("hypervisor", ClusterHypervisorSearch.entity().getHypervisorType(), SearchCriteria.Op.EQ);
|
ClusterHypervisorSearch.and("hypervisor", ClusterHypervisorSearch.entity().getHypervisorType(), SearchCriteria.Op.EQ);
|
||||||
ClusterHypervisorSearch.and("type", ClusterHypervisorSearch.entity().getType(), SearchCriteria.Op.EQ);
|
ClusterHypervisorSearch.and("type", ClusterHypervisorSearch.entity().getType(), SearchCriteria.Op.EQ);
|
||||||
ClusterHypervisorSearch.and("status", ClusterHypervisorSearch.entity().getStatus(), SearchCriteria.Op.EQ);
|
ClusterHypervisorSearch.and("status", ClusterHypervisorSearch.entity().getStatus(), SearchCriteria.Op.EQ);
|
||||||
|
ClusterHypervisorSearch.and("resourceState", ClusterHypervisorSearch.entity().getResourceState(), SearchCriteria.Op.EQ);
|
||||||
ClusterHypervisorSearch.done();
|
ClusterHypervisorSearch.done();
|
||||||
|
|
||||||
UnmanagedDirectConnectSearch = createSearchBuilder();
|
UnmanagedDirectConnectSearch = createSearchBuilder();
|
||||||
@ -1507,12 +1508,42 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
|
|||||||
return listBy(sc);
|
return listBy(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<HostVO> listByClusterHypervisorTypeAndHostCapability(Long clusterId, HypervisorType hypervisorType, String hostCapabilty) {
|
||||||
|
SearchBuilder<DetailVO> hostCapabilitySearch = _detailsDao.createSearchBuilder();
|
||||||
|
DetailVO tagEntity = hostCapabilitySearch.entity();
|
||||||
|
hostCapabilitySearch.and("capability", tagEntity.getName(), SearchCriteria.Op.EQ);
|
||||||
|
hostCapabilitySearch.and("value", tagEntity.getValue(), SearchCriteria.Op.EQ);
|
||||||
|
|
||||||
|
SearchBuilder<HostVO> hostSearch = createSearchBuilder();
|
||||||
|
HostVO entity = hostSearch.entity();
|
||||||
|
hostSearch.and("clusterId", entity.getClusterId(), SearchCriteria.Op.EQ);
|
||||||
|
hostSearch.and("hypervisor", entity.getHypervisorType(), SearchCriteria.Op.EQ);
|
||||||
|
hostSearch.and("type", entity.getType(), SearchCriteria.Op.EQ);
|
||||||
|
hostSearch.and("status", entity.getStatus(), SearchCriteria.Op.EQ);
|
||||||
|
hostSearch.and("resourceState", entity.getResourceState(), SearchCriteria.Op.EQ);
|
||||||
|
hostSearch.join("hostCapabilitySearch", hostCapabilitySearch, entity.getId(), tagEntity.getHostId(), JoinBuilder.JoinType.INNER);
|
||||||
|
|
||||||
|
SearchCriteria<HostVO> sc = hostSearch.create();
|
||||||
|
sc.setJoinParameters("hostCapabilitySearch", "value", Boolean.toString(true));
|
||||||
|
sc.setJoinParameters("hostCapabilitySearch", "capability", hostCapabilty);
|
||||||
|
|
||||||
|
sc.setParameters("clusterId", clusterId);
|
||||||
|
sc.setParameters("hypervisor", hypervisorType);
|
||||||
|
sc.setParameters("type", Type.Routing);
|
||||||
|
sc.setParameters("status", Status.Up);
|
||||||
|
sc.setParameters("resourceState", ResourceState.Enabled);
|
||||||
|
return listBy(sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public List<HostVO> listByClusterAndHypervisorType(long clusterId, HypervisorType hypervisorType) {
|
public List<HostVO> listByClusterAndHypervisorType(long clusterId, HypervisorType hypervisorType) {
|
||||||
SearchCriteria<HostVO> sc = ClusterHypervisorSearch.create();
|
SearchCriteria<HostVO> sc = ClusterHypervisorSearch.create();
|
||||||
sc.setParameters("clusterId", clusterId);
|
sc.setParameters("clusterId", clusterId);
|
||||||
sc.setParameters("hypervisor", hypervisorType);
|
sc.setParameters("hypervisor", hypervisorType);
|
||||||
sc.setParameters("type", Type.Routing);
|
sc.setParameters("type", Type.Routing);
|
||||||
sc.setParameters("status", Status.Up);
|
sc.setParameters("status", Status.Up);
|
||||||
|
sc.setParameters("resourceState", ResourceState.Enabled);
|
||||||
return listBy(sc);
|
return listBy(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
import com.cloud.storage.ScopeType;
|
import com.cloud.storage.ScopeType;
|
||||||
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.storage.StoragePoolStatus;
|
import com.cloud.storage.StoragePoolStatus;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.db.Filter;
|
import com.cloud.utils.db.Filter;
|
||||||
@ -126,6 +127,10 @@ public interface PrimaryDataStoreDao extends GenericDao<StoragePoolVO, Long> {
|
|||||||
|
|
||||||
List<StoragePoolVO> findZoneWideStoragePoolsByHypervisor(long dataCenterId, HypervisorType hypervisorType, String keyword);
|
List<StoragePoolVO> findZoneWideStoragePoolsByHypervisor(long dataCenterId, HypervisorType hypervisorType, String keyword);
|
||||||
|
|
||||||
|
List<StoragePoolVO> findZoneWideStoragePoolsByHypervisorAndPoolType(long dataCenterId, HypervisorType hypervisorType, Storage.StoragePoolType poolType);
|
||||||
|
|
||||||
|
List<StoragePoolVO> findClusterWideStoragePoolsByHypervisorAndPoolType(long clusterId, HypervisorType hypervisorType, Storage.StoragePoolType poolType);
|
||||||
|
|
||||||
List<StoragePoolVO> findLocalStoragePoolsByHostAndTags(long hostId, String[] tags);
|
List<StoragePoolVO> findLocalStoragePoolsByHostAndTags(long hostId, String[] tags);
|
||||||
|
|
||||||
List<StoragePoolVO> listLocalStoragePoolByPath(long datacenterId, String path);
|
List<StoragePoolVO> listLocalStoragePoolByPath(long datacenterId, String path);
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import java.util.stream.Collectors;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.db.Filter;
|
import com.cloud.utils.db.Filter;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
@ -621,6 +622,28 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
|||||||
return sc.list();
|
return sc.list();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StoragePoolVO> findZoneWideStoragePoolsByHypervisorAndPoolType(long dataCenterId, HypervisorType hypervisorType, Storage.StoragePoolType poolType) {
|
||||||
|
QueryBuilder<StoragePoolVO> sc = QueryBuilder.create(StoragePoolVO.class);
|
||||||
|
sc.and(sc.entity().getDataCenterId(), Op.EQ, dataCenterId);
|
||||||
|
sc.and(sc.entity().getStatus(), Op.EQ, StoragePoolStatus.Up);
|
||||||
|
sc.and(sc.entity().getScope(), Op.EQ, ScopeType.ZONE);
|
||||||
|
sc.and(sc.entity().getHypervisor(), Op.EQ, hypervisorType);
|
||||||
|
sc.and(sc.entity().getPoolType(), Op.EQ, poolType);
|
||||||
|
return sc.list();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StoragePoolVO> findClusterWideStoragePoolsByHypervisorAndPoolType(long clusterId, HypervisorType hypervisorType, Storage.StoragePoolType poolType) {
|
||||||
|
QueryBuilder<StoragePoolVO> sc = QueryBuilder.create(StoragePoolVO.class);
|
||||||
|
sc.and(sc.entity().getClusterId(), Op.EQ, clusterId);
|
||||||
|
sc.and(sc.entity().getStatus(), Op.EQ, StoragePoolStatus.Up);
|
||||||
|
sc.and(sc.entity().getScope(), Op.EQ, ScopeType.CLUSTER);
|
||||||
|
sc.and(sc.entity().getHypervisor(), Op.EQ, hypervisorType);
|
||||||
|
sc.and(sc.entity().getPoolType(), Op.EQ, poolType);
|
||||||
|
return sc.list();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deletePoolTags(long poolId) {
|
public void deletePoolTags(long poolId) {
|
||||||
_tagsDao.deleteTags(poolId);
|
_tagsDao.deleteTags(poolId);
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.hypervisor.kvm.resource;
|
package com.cloud.hypervisor.kvm.resource;
|
||||||
|
|
||||||
|
import static com.cloud.host.Host.HOST_INSTANCE_CONVERSION;
|
||||||
import static com.cloud.host.Host.HOST_VOLUME_ENCRYPTION;
|
import static com.cloud.host.Host.HOST_VOLUME_ENCRYPTION;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
@ -305,6 +306,16 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
|
|
||||||
public static final String TUNGSTEN_PATH = "scripts/vm/network/tungsten";
|
public static final String TUNGSTEN_PATH = "scripts/vm/network/tungsten";
|
||||||
|
|
||||||
|
public static final String INSTANCE_CONVERSION_SUPPORTED_CHECK_CMD = "virt-v2v --version";
|
||||||
|
// virt-v2v --version => sample output: virt-v2v 1.42.0rhel=8,release=22.module+el8.10.0+1590+a67ab969
|
||||||
|
public static final String OVF_EXPORT_SUPPORTED_CHECK_CMD = "ovftool --version";
|
||||||
|
// ovftool --version => sample output: VMware ovftool 4.6.0 (build-21452615)
|
||||||
|
public static final String OVF_EXPORT_TOOl_GET_VERSION_CMD = "ovftool --version | awk '{print $3}'";
|
||||||
|
|
||||||
|
public static final String WINDOWS_GUEST_CONVERSION_SUPPORTED_CHECK_CMD = "rpm -qa | grep -i virtio-win";
|
||||||
|
public static final String UBUNTU_WINDOWS_GUEST_CONVERSION_SUPPORTED_CHECK_CMD = "dpkg -l virtio-win";
|
||||||
|
public static final String UBUNTU_NBDKIT_PKG_CHECK_CMD = "dpkg -l nbdkit";
|
||||||
|
|
||||||
private String modifyVlanPath;
|
private String modifyVlanPath;
|
||||||
private String versionStringPath;
|
private String versionStringPath;
|
||||||
private String patchScriptPath;
|
private String patchScriptPath;
|
||||||
@ -3634,6 +3645,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
cmd.setGatewayIpAddress(localGateway);
|
cmd.setGatewayIpAddress(localGateway);
|
||||||
cmd.setIqn(getIqn());
|
cmd.setIqn(getIqn());
|
||||||
cmd.getHostDetails().put(HOST_VOLUME_ENCRYPTION, String.valueOf(hostSupportsVolumeEncryption()));
|
cmd.getHostDetails().put(HOST_VOLUME_ENCRYPTION, String.valueOf(hostSupportsVolumeEncryption()));
|
||||||
|
cmd.getHostDetails().put(HOST_INSTANCE_CONVERSION, String.valueOf(hostSupportsInstanceConversion()));
|
||||||
HealthCheckResult healthCheckResult = getHostHealthCheckResult();
|
HealthCheckResult healthCheckResult = getHostHealthCheckResult();
|
||||||
if (healthCheckResult != HealthCheckResult.IGNORE) {
|
if (healthCheckResult != HealthCheckResult.IGNORE) {
|
||||||
cmd.setHostHealthCheckResult(healthCheckResult == HealthCheckResult.SUCCESS);
|
cmd.setHostHealthCheckResult(healthCheckResult == HealthCheckResult.SUCCESS);
|
||||||
@ -5137,6 +5149,48 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hostSupportsInstanceConversion() {
|
||||||
|
int exitValue = Script.runSimpleBashScriptForExitValue(INSTANCE_CONVERSION_SUPPORTED_CHECK_CMD);
|
||||||
|
if (isUbuntuHost() && exitValue == 0) {
|
||||||
|
exitValue = Script.runSimpleBashScriptForExitValue(UBUNTU_NBDKIT_PKG_CHECK_CMD);
|
||||||
|
}
|
||||||
|
return exitValue == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hostSupportsWindowsGuestConversion() {
|
||||||
|
if (isUbuntuHost()) {
|
||||||
|
int exitValue = Script.runSimpleBashScriptForExitValue(UBUNTU_WINDOWS_GUEST_CONVERSION_SUPPORTED_CHECK_CMD);
|
||||||
|
return exitValue == 0;
|
||||||
|
}
|
||||||
|
int exitValue = Script.runSimpleBashScriptForExitValue(WINDOWS_GUEST_CONVERSION_SUPPORTED_CHECK_CMD);
|
||||||
|
return exitValue == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hostSupportsOvfExport() {
|
||||||
|
int exitValue = Script.runSimpleBashScriptForExitValue(OVF_EXPORT_SUPPORTED_CHECK_CMD);
|
||||||
|
return exitValue == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean ovfExportToolSupportsParallelThreads() {
|
||||||
|
String ovfExportToolVersion = Script.runSimpleBashScript(OVF_EXPORT_TOOl_GET_VERSION_CMD);
|
||||||
|
if (StringUtils.isBlank(ovfExportToolVersion)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String[] ovfExportToolVersions = ovfExportToolVersion.trim().split("\\.");
|
||||||
|
if (ovfExportToolVersions.length > 1) {
|
||||||
|
try {
|
||||||
|
int majorVersion = Integer.parseInt(ovfExportToolVersions[0]);
|
||||||
|
int minorVersion = Integer.parseInt(ovfExportToolVersions[1]);
|
||||||
|
//ovftool version >= 4.4 supports parallel threads
|
||||||
|
if (majorVersion > 4 || (majorVersion == 4 && minorVersion >= 4)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void setCpuTopology(CpuModeDef cmd, int vCpusInDef, Map<String, String> details) {
|
private void setCpuTopology(CpuModeDef cmd, int vCpusInDef, Map<String, String> details) {
|
||||||
if (!enableManuallySettingCpuTopologyOnKvmVm) {
|
if (!enableManuallySettingCpuTopologyOnKvmVm) {
|
||||||
s_logger.debug(String.format("Skipping manually setting CPU topology on VM's XML due to it is disabled in agent.properties {\"property\": \"%s\", \"value\": %s}.",
|
s_logger.debug(String.format("Skipping manually setting CPU topology on VM's XML due to it is disabled in agent.properties {\"property\": \"%s\", \"value\": %s}.",
|
||||||
|
|||||||
@ -0,0 +1,57 @@
|
|||||||
|
//
|
||||||
|
// 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.hypervisor.kvm.resource.wrapper;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.agent.api.CheckConvertInstanceAnswer;
|
||||||
|
import com.cloud.agent.api.CheckConvertInstanceCommand;
|
||||||
|
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
|
||||||
|
import com.cloud.resource.CommandWrapper;
|
||||||
|
import com.cloud.resource.ResourceWrapper;
|
||||||
|
|
||||||
|
@ResourceWrapper(handles = CheckConvertInstanceCommand.class)
|
||||||
|
public class LibvirtCheckConvertInstanceCommandWrapper extends CommandWrapper<CheckConvertInstanceCommand, Answer, LibvirtComputingResource> {
|
||||||
|
|
||||||
|
private static final Logger s_logger = Logger.getLogger(LibvirtCheckConvertInstanceCommandWrapper.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Answer execute(CheckConvertInstanceCommand cmd, LibvirtComputingResource serverResource) {
|
||||||
|
if (!serverResource.hostSupportsInstanceConversion()) {
|
||||||
|
String msg = String.format("Cannot convert the instance from VMware as the virt-v2v binary is not found on host %s. " +
|
||||||
|
"Please install virt-v2v%s on the host before attempting the instance conversion.", serverResource.getPrivateIp(), serverResource.isUbuntuHost()? ", nbdkit" : "");
|
||||||
|
s_logger.info(msg);
|
||||||
|
return new CheckConvertInstanceAnswer(cmd, false, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd.getCheckWindowsGuestConversionSupport() && !serverResource.hostSupportsWindowsGuestConversion()) {
|
||||||
|
String msg = String.format("Cannot convert the instance from VMware as the virtio-win package is not found on host %s. " +
|
||||||
|
"Please install virtio-win package on the host before attempting the windows guest instance conversion.", serverResource.getPrivateIp());
|
||||||
|
s_logger.info(msg);
|
||||||
|
return new CheckConvertInstanceAnswer(cmd, false, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverResource.hostSupportsOvfExport()) {
|
||||||
|
return new CheckConvertInstanceAnswer(cmd, true, true, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CheckConvertInstanceAnswer(cmd, true, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -65,8 +65,6 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
private static final List<Hypervisor.HypervisorType> supportedInstanceConvertSourceHypervisors =
|
private static final List<Hypervisor.HypervisorType> supportedInstanceConvertSourceHypervisors =
|
||||||
List.of(Hypervisor.HypervisorType.VMware);
|
List.of(Hypervisor.HypervisorType.VMware);
|
||||||
|
|
||||||
protected static final String checkIfConversionIsSupportedCommand = "which virt-v2v";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Answer execute(ConvertInstanceCommand cmd, LibvirtComputingResource serverResource) {
|
public Answer execute(ConvertInstanceCommand cmd, LibvirtComputingResource serverResource) {
|
||||||
RemoteInstanceTO sourceInstance = cmd.getSourceInstance();
|
RemoteInstanceTO sourceInstance = cmd.getSourceInstance();
|
||||||
@ -77,9 +75,9 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
DataStoreTO conversionTemporaryLocation = cmd.getConversionTemporaryLocation();
|
DataStoreTO conversionTemporaryLocation = cmd.getConversionTemporaryLocation();
|
||||||
long timeout = (long) cmd.getWait() * 1000;
|
long timeout = (long) cmd.getWait() * 1000;
|
||||||
|
|
||||||
if (!isInstanceConversionSupportedOnHost()) {
|
if (cmd.getCheckConversionSupport() && !serverResource.hostSupportsInstanceConversion()) {
|
||||||
String msg = String.format("Cannot convert the instance %s from VMware as the virt-v2v binary is not found. " +
|
String msg = String.format("Cannot convert the instance %s from VMware as the virt-v2v binary is not found. " +
|
||||||
"Please install virt-v2v on the host before attempting the instance conversion", sourceInstanceName);
|
"Please install virt-v2v%s on the host before attempting the instance conversion.", sourceInstanceName, serverResource.isUbuntuHost()? ", nbdkit" : "");
|
||||||
s_logger.info(msg);
|
s_logger.info(msg);
|
||||||
return new ConvertInstanceAnswer(cmd, false, msg);
|
return new ConvertInstanceAnswer(cmd, false, msg);
|
||||||
}
|
}
|
||||||
@ -94,21 +92,48 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
|
|
||||||
final KVMStoragePoolManager storagePoolMgr = serverResource.getStoragePoolMgr();
|
final KVMStoragePoolManager storagePoolMgr = serverResource.getStoragePoolMgr();
|
||||||
KVMStoragePool temporaryStoragePool = getTemporaryStoragePool(conversionTemporaryLocation, storagePoolMgr);
|
KVMStoragePool temporaryStoragePool = getTemporaryStoragePool(conversionTemporaryLocation, storagePoolMgr);
|
||||||
|
|
||||||
s_logger.info(String.format("Attempting to convert the instance %s from %s to KVM",
|
|
||||||
sourceInstanceName, sourceHypervisorType));
|
|
||||||
final String convertInstanceUrl = getConvertInstanceUrl(sourceInstance);
|
|
||||||
final String temporaryConvertUuid = UUID.randomUUID().toString();
|
|
||||||
final String temporaryPasswordFilePath = createTemporaryPasswordFileAndRetrievePath(sourceInstance);
|
|
||||||
final String temporaryConvertPath = temporaryStoragePool.getLocalPath();
|
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();
|
boolean verboseModeEnabled = serverResource.isConvertInstanceVerboseModeEnabled();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
boolean result = performInstanceConversion(convertInstanceUrl, sourceInstanceName, temporaryPasswordFilePath,
|
boolean result = performInstanceConversion(sourceOVFDirPath, temporaryConvertPath, temporaryConvertUuid,
|
||||||
temporaryConvertPath, temporaryConvertUuid, timeout, verboseModeEnabled);
|
timeout, verboseModeEnabled);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
String err = String.format("The virt-v2v conversion of the instance %s failed. " +
|
String err = String.format("The virt-v2v conversion for the OVF %s failed. " +
|
||||||
"Please check the agent logs for the virt-v2v output", sourceInstanceName);
|
"Please check the agent logs for the virt-v2v output", ovfTemplateDirOnConversionLocation);
|
||||||
s_logger.error(err);
|
s_logger.error(err);
|
||||||
return new ConvertInstanceAnswer(cmd, false, err);
|
return new ConvertInstanceAnswer(cmd, false, err);
|
||||||
}
|
}
|
||||||
@ -133,8 +158,11 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
s_logger.error(error, e);
|
s_logger.error(error, e);
|
||||||
return new ConvertInstanceAnswer(cmd, false, error);
|
return new ConvertInstanceAnswer(cmd, false, error);
|
||||||
} finally {
|
} finally {
|
||||||
s_logger.debug("Cleaning up instance conversion temporary password file");
|
if (ovfExported && StringUtils.isNotBlank(ovfTemplateDirOnConversionLocation)) {
|
||||||
Script.runSimpleBashScript(String.format("rm -rf %s", temporaryPasswordFilePath));
|
String sourceOVFDir = String.format("%s/%s", temporaryConvertPath, ovfTemplateDirOnConversionLocation);
|
||||||
|
s_logger.debug("Cleaning up exported OVA at dir " + sourceOVFDir);
|
||||||
|
Script.runSimpleBashScript("rm -rf " + sourceOVFDir);
|
||||||
|
}
|
||||||
if (conversionTemporaryLocation instanceof NfsTO) {
|
if (conversionTemporaryLocation instanceof NfsTO) {
|
||||||
s_logger.debug("Cleaning up secondary storage temporary location");
|
s_logger.debug("Cleaning up secondary storage temporary location");
|
||||||
storagePoolMgr.deleteStoragePool(temporaryStoragePool.getType(), temporaryStoragePool.getUuid());
|
storagePoolMgr.deleteStoragePool(temporaryStoragePool.getType(), temporaryStoragePool.getUuid());
|
||||||
@ -158,6 +186,27 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
supportedInstanceConvertSourceHypervisors.contains(sourceHypervisorType);
|
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) {
|
protected List<KVMPhysicalDisk> getTemporaryDisksFromParsedXml(KVMStoragePool pool, LibvirtDomainXMLParser xmlParser, String convertedBasePath) {
|
||||||
List<LibvirtVMDef.DiskDef> disksDefs = xmlParser.getDisks();
|
List<LibvirtVMDef.DiskDef> disksDefs = xmlParser.getDisks();
|
||||||
disksDefs = disksDefs.stream().filter(x -> x.getDiskType() == LibvirtVMDef.DiskDef.DiskType.FILE &&
|
disksDefs = disksDefs.stream().filter(x -> x.getDiskType() == LibvirtVMDef.DiskDef.DiskType.FILE &&
|
||||||
@ -207,11 +256,6 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
Script.runSimpleBashScript(String.format("rm -f %s/%s*.xml", temporaryStoragePool.getLocalPath(), temporaryConvertUuid));
|
Script.runSimpleBashScript(String.format("rm -f %s/%s*.xml", temporaryStoragePool.getLocalPath(), temporaryConvertUuid));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isInstanceConversionSupportedOnHost() {
|
|
||||||
int exitValue = Script.runSimpleBashScriptForExitValue(checkIfConversionIsSupportedCommand);
|
|
||||||
return exitValue == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void sanitizeDisksPath(List<LibvirtVMDef.DiskDef> disks) {
|
protected void sanitizeDisksPath(List<LibvirtVMDef.DiskDef> disks) {
|
||||||
for (LibvirtVMDef.DiskDef disk : disks) {
|
for (LibvirtVMDef.DiskDef disk : disks) {
|
||||||
String[] diskPathParts = disk.getDiskPath().split("/");
|
String[] diskPathParts = disk.getDiskPath().split("/");
|
||||||
@ -237,6 +281,11 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
s_logger.error(err);
|
s_logger.error(err);
|
||||||
continue;
|
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);
|
KVMPhysicalDisk sourceDisk = temporaryDisks.get(i);
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (s_logger.isDebugEnabled()) {
|
||||||
String msg = String.format("Trying to copy converted instance disk number %s from the temporary location %s" +
|
String msg = String.format("Trying to copy converted instance disk number %s from the temporary location %s" +
|
||||||
@ -308,25 +357,45 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
String sourceHostIp = null;
|
String sourceHostIp = null;
|
||||||
String sourcePath = null;
|
String sourcePath = null;
|
||||||
String storagePoolMountPoint = Script.runSimpleBashScript(String.format("mount | grep %s", storagePool.getLocalPath()));
|
String storagePoolMountPoint = Script.runSimpleBashScript(String.format("mount | grep %s", storagePool.getLocalPath()));
|
||||||
|
s_logger.debug(String.format("NFS Storage pool: %s - local path: %s, mount point: %s", storagePool.getUuid(), storagePool.getLocalPath(), storagePoolMountPoint));
|
||||||
if (StringUtils.isNotEmpty(storagePoolMountPoint)) {
|
if (StringUtils.isNotEmpty(storagePoolMountPoint)) {
|
||||||
String[] res = storagePoolMountPoint.strip().split(" ");
|
String[] res = storagePoolMountPoint.strip().split(" ");
|
||||||
res = res[0].split(":");
|
res = res[0].split(":");
|
||||||
sourceHostIp = res[0].strip();
|
if (res.length > 1) {
|
||||||
sourcePath = res[1].strip();
|
sourceHostIp = res[0].strip();
|
||||||
|
sourcePath = res[1].strip();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return new Pair<>(sourceHostIp, sourcePath);
|
return new Pair<>(sourceHostIp, sourcePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean performInstanceConversion(String convertInstanceUrl, String sourceInstanceName,
|
private boolean exportOVAFromVMOnVcenter(String vmExportUrl,
|
||||||
String temporaryPasswordFilePath,
|
String targetOvfDir,
|
||||||
String temporaryConvertFolder,
|
int noOfThreads,
|
||||||
String temporaryConvertUuid,
|
long timeout) {
|
||||||
long timeout, boolean verboseModeEnabled) {
|
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 script = new Script("virt-v2v", timeout, s_logger);
|
||||||
script.add("--root", "first");
|
script.add("--root", "first");
|
||||||
script.add("-ic", convertInstanceUrl);
|
script.add("-i", "ova");
|
||||||
script.add(sourceInstanceName);
|
script.add(sourceOVFDirPath);
|
||||||
script.add("--password-file", temporaryPasswordFilePath);
|
|
||||||
script.add("-o", "local");
|
script.add("-o", "local");
|
||||||
script.add("-os", temporaryConvertFolder);
|
script.add("-os", temporaryConvertFolder);
|
||||||
script.add("-of", "qcow2");
|
script.add("-of", "qcow2");
|
||||||
@ -335,44 +404,13 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
script.add("-v");
|
script.add("-v");
|
||||||
}
|
}
|
||||||
|
|
||||||
String logPrefix = String.format("virt-v2v source: %s %s progress", convertInstanceUrl, sourceInstanceName);
|
String logPrefix = String.format("virt-v2v ovf source: %s progress", sourceOVFDirPath);
|
||||||
OutputInterpreter.LineByLineOutputLogger outputLogger = new OutputInterpreter.LineByLineOutputLogger(s_logger, logPrefix);
|
OutputInterpreter.LineByLineOutputLogger outputLogger = new OutputInterpreter.LineByLineOutputLogger(s_logger, logPrefix);
|
||||||
script.execute(outputLogger);
|
script.execute(outputLogger);
|
||||||
int exitValue = script.getExitValue();
|
int exitValue = script.getExitValue();
|
||||||
return exitValue == 0;
|
return exitValue == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createTemporaryPasswordFileAndRetrievePath(RemoteInstanceTO sourceInstance) {
|
|
||||||
String password = null;
|
|
||||||
if (sourceInstance.getHypervisorType() == Hypervisor.HypervisorType.VMware) {
|
|
||||||
password = sourceInstance.getVcenterPassword();
|
|
||||||
}
|
|
||||||
String passwordFile = String.format("/tmp/vmw-%s", UUID.randomUUID());
|
|
||||||
String msg = String.format("Creating a temporary password file for VMware instance %s conversion on: %s", sourceInstance.getInstanceName(), passwordFile);
|
|
||||||
s_logger.debug(msg);
|
|
||||||
Script.runSimpleBashScriptForExitValueAvoidLogging(String.format("echo \"%s\" > %s", password, passwordFile));
|
|
||||||
return passwordFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getConvertInstanceUrl(RemoteInstanceTO sourceInstance) {
|
|
||||||
String url = null;
|
|
||||||
if (sourceInstance.getHypervisorType() == Hypervisor.HypervisorType.VMware) {
|
|
||||||
url = getConvertInstanceUrlFromVmware(sourceInstance);
|
|
||||||
}
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getConvertInstanceUrlFromVmware(RemoteInstanceTO vmwareInstance) {
|
|
||||||
String vcenter = vmwareInstance.getVcenterHost();
|
|
||||||
String datacenter = vmwareInstance.getDatacenterName();
|
|
||||||
String username = vmwareInstance.getVcenterUsername();
|
|
||||||
String host = vmwareInstance.getHostName();
|
|
||||||
String cluster = vmwareInstance.getClusterName();
|
|
||||||
|
|
||||||
String encodedUsername = encodeUsername(username);
|
|
||||||
return String.format("vpx://%s@%s/%s/%s/%s?no_verify=1",
|
|
||||||
encodedUsername, vcenter, datacenter, cluster, host);
|
|
||||||
}
|
|
||||||
protected LibvirtDomainXMLParser parseMigratedVMXmlDomain(String installPath) throws IOException {
|
protected LibvirtDomainXMLParser parseMigratedVMXmlDomain(String installPath) throws IOException {
|
||||||
String xmlPath = String.format("%s.xml", installPath);
|
String xmlPath = String.format("%s.xml", installPath);
|
||||||
if (!new File(xmlPath).exists()) {
|
if (!new File(xmlPath).exists()) {
|
||||||
|
|||||||
@ -0,0 +1,67 @@
|
|||||||
|
//
|
||||||
|
// 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.hypervisor.kvm.resource.wrapper;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.agent.api.CheckConvertInstanceCommand;
|
||||||
|
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class LibvirtCheckConvertInstanceCommandWrapperTest {
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
private LibvirtCheckConvertInstanceCommandWrapper checkConvertInstanceCommandWrapper = Mockito.spy(LibvirtCheckConvertInstanceCommandWrapper.class);
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private LibvirtComputingResource libvirtComputingResourceMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
CheckConvertInstanceCommand checkConvertInstanceCommandMock;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckInstanceCommand_success() {
|
||||||
|
Mockito.when(libvirtComputingResourceMock.hostSupportsInstanceConversion()).thenReturn(true);
|
||||||
|
Answer answer = checkConvertInstanceCommandWrapper.execute(checkConvertInstanceCommandMock, libvirtComputingResourceMock);
|
||||||
|
assertTrue(answer.getResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckInstanceCommand_failure() {
|
||||||
|
Mockito.when(libvirtComputingResourceMock.hostSupportsInstanceConversion()).thenReturn(false);
|
||||||
|
Answer answer = checkConvertInstanceCommandWrapper.execute(checkConvertInstanceCommandMock, libvirtComputingResourceMock);
|
||||||
|
assertFalse(answer.getResult());
|
||||||
|
assertTrue(StringUtils.isNotBlank(answer.getDetails()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -71,12 +71,6 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
|
|
||||||
private static final String secondaryPoolUrl = "nfs://192.168.1.1/secondary";
|
private static final String secondaryPoolUrl = "nfs://192.168.1.1/secondary";
|
||||||
private static final String vmName = "VmToImport";
|
private static final String vmName = "VmToImport";
|
||||||
private static final String hostName = "VmwareHost1";
|
|
||||||
private static final String vmwareVcenter = "192.168.1.2";
|
|
||||||
private static final String vmwareDatacenter = "Datacenter";
|
|
||||||
private static final String vmwareCluster = "Cluster";
|
|
||||||
private static final String vmwareUsername = "administrator@vsphere.local";
|
|
||||||
private static final String vmwarePassword = "password";
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@ -88,15 +82,6 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
Mockito.when(temporaryPool.listPhysicalDisks()).thenReturn(Arrays.asList(physicalDisk1, physicalDisk2));
|
Mockito.when(temporaryPool.listPhysicalDisks()).thenReturn(Arrays.asList(physicalDisk1, physicalDisk2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIsInstanceConversionSupportedOnHost() {
|
|
||||||
try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class)) {
|
|
||||||
Mockito.when(Script.runSimpleBashScriptForExitValue(LibvirtConvertInstanceCommandWrapper.checkIfConversionIsSupportedCommand)).thenReturn(0);
|
|
||||||
boolean supported = convertInstanceCommandWrapper.isInstanceConversionSupportedOnHost();
|
|
||||||
Assert.assertTrue(supported);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAreSourceAndDestinationHypervisorsSupported() {
|
public void testAreSourceAndDestinationHypervisorsSupported() {
|
||||||
boolean supported = convertInstanceCommandWrapper.areSourceAndDestinationHypervisorsSupported(Hypervisor.HypervisorType.VMware, Hypervisor.HypervisorType.KVM);
|
boolean supported = convertInstanceCommandWrapper.areSourceAndDestinationHypervisorsSupported(Hypervisor.HypervisorType.VMware, Hypervisor.HypervisorType.KVM);
|
||||||
@ -191,6 +176,7 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
Mockito.when(destDisk.getPath()).thenReturn("xyz");
|
Mockito.when(destDisk.getPath()).thenReturn("xyz");
|
||||||
Mockito.when(storagePoolManager.getStoragePool(Storage.StoragePoolType.NetworkFilesystem, destinationPoolUuid))
|
Mockito.when(storagePoolManager.getStoragePool(Storage.StoragePoolType.NetworkFilesystem, destinationPoolUuid))
|
||||||
.thenReturn(destinationPool);
|
.thenReturn(destinationPool);
|
||||||
|
Mockito.when(destinationPool.getType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem);
|
||||||
Mockito.when(storagePoolManager.copyPhysicalDisk(Mockito.eq(sourceDisk), Mockito.anyString(), Mockito.eq(destinationPool), Mockito.anyInt()))
|
Mockito.when(storagePoolManager.copyPhysicalDisk(Mockito.eq(sourceDisk), Mockito.anyString(), Mockito.eq(destinationPool), Mockito.anyInt()))
|
||||||
.thenReturn(destDisk);
|
.thenReturn(destDisk);
|
||||||
|
|
||||||
@ -244,21 +230,16 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
RemoteInstanceTO remoteInstanceTO = Mockito.mock(RemoteInstanceTO.class);
|
RemoteInstanceTO remoteInstanceTO = Mockito.mock(RemoteInstanceTO.class);
|
||||||
Mockito.when(remoteInstanceTO.getHypervisorType()).thenReturn(hypervisorType);
|
Mockito.when(remoteInstanceTO.getHypervisorType()).thenReturn(hypervisorType);
|
||||||
Mockito.when(remoteInstanceTO.getInstanceName()).thenReturn(vmName);
|
Mockito.when(remoteInstanceTO.getInstanceName()).thenReturn(vmName);
|
||||||
Mockito.when(remoteInstanceTO.getHostName()).thenReturn(hostName);
|
|
||||||
Mockito.when(remoteInstanceTO.getVcenterHost()).thenReturn(vmwareVcenter);
|
|
||||||
Mockito.when(remoteInstanceTO.getDatacenterName()).thenReturn(vmwareDatacenter);
|
|
||||||
Mockito.when(remoteInstanceTO.getClusterName()).thenReturn(vmwareCluster);
|
|
||||||
Mockito.when(remoteInstanceTO.getVcenterUsername()).thenReturn(vmwareUsername);
|
|
||||||
Mockito.when(remoteInstanceTO.getVcenterPassword()).thenReturn(vmwarePassword);
|
|
||||||
return remoteInstanceTO;
|
return remoteInstanceTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConvertInstanceCommand getConvertInstanceCommand(RemoteInstanceTO remoteInstanceTO, Hypervisor.HypervisorType hypervisorType) {
|
private ConvertInstanceCommand getConvertInstanceCommand(RemoteInstanceTO remoteInstanceTO, Hypervisor.HypervisorType hypervisorType, boolean checkConversionSupport) {
|
||||||
ConvertInstanceCommand cmd = Mockito.mock(ConvertInstanceCommand.class);
|
ConvertInstanceCommand cmd = Mockito.mock(ConvertInstanceCommand.class);
|
||||||
Mockito.when(cmd.getSourceInstance()).thenReturn(remoteInstanceTO);
|
Mockito.when(cmd.getSourceInstance()).thenReturn(remoteInstanceTO);
|
||||||
Mockito.when(cmd.getDestinationHypervisorType()).thenReturn(hypervisorType);
|
Mockito.when(cmd.getDestinationHypervisorType()).thenReturn(hypervisorType);
|
||||||
Mockito.when(cmd.getWait()).thenReturn(14400);
|
Mockito.when(cmd.getWait()).thenReturn(14400);
|
||||||
Mockito.when(cmd.getConversionTemporaryLocation()).thenReturn(secondaryDataStore);
|
Mockito.when(cmd.getConversionTemporaryLocation()).thenReturn(secondaryDataStore);
|
||||||
|
Mockito.when(cmd.getCheckConversionSupport()).thenReturn(checkConversionSupport);
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,8 +247,8 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
public void testExecuteConvertUnsupportedOnTheHost() {
|
public void testExecuteConvertUnsupportedOnTheHost() {
|
||||||
try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class)) {
|
try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class)) {
|
||||||
RemoteInstanceTO remoteInstanceTO = getRemoteInstanceTO(Hypervisor.HypervisorType.VMware);
|
RemoteInstanceTO remoteInstanceTO = getRemoteInstanceTO(Hypervisor.HypervisorType.VMware);
|
||||||
ConvertInstanceCommand cmd = getConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM);
|
ConvertInstanceCommand cmd = getConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM, true);
|
||||||
Mockito.when(Script.runSimpleBashScriptForExitValue(LibvirtConvertInstanceCommandWrapper.checkIfConversionIsSupportedCommand)).thenReturn(1);
|
Mockito.when(Script.runSimpleBashScriptForExitValue(LibvirtComputingResource.INSTANCE_CONVERSION_SUPPORTED_CHECK_CMD)).thenReturn(1);
|
||||||
Answer answer = convertInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
|
Answer answer = convertInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
|
||||||
Assert.assertFalse(answer.getResult());
|
Assert.assertFalse(answer.getResult());
|
||||||
}
|
}
|
||||||
@ -277,8 +258,8 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
public void testExecuteConvertUnsupportedHypervisors() {
|
public void testExecuteConvertUnsupportedHypervisors() {
|
||||||
try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class)) {
|
try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class)) {
|
||||||
RemoteInstanceTO remoteInstanceTO = getRemoteInstanceTO(Hypervisor.HypervisorType.XenServer);
|
RemoteInstanceTO remoteInstanceTO = getRemoteInstanceTO(Hypervisor.HypervisorType.XenServer);
|
||||||
ConvertInstanceCommand cmd = getConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM);
|
ConvertInstanceCommand cmd = getConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM, true);
|
||||||
Mockito.when(Script.runSimpleBashScriptForExitValue(LibvirtConvertInstanceCommandWrapper.checkIfConversionIsSupportedCommand)).thenReturn(0);
|
Mockito.when(Script.runSimpleBashScriptForExitValue(LibvirtComputingResource.INSTANCE_CONVERSION_SUPPORTED_CHECK_CMD)).thenReturn(0);
|
||||||
Answer answer = convertInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
|
Answer answer = convertInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
|
||||||
Assert.assertFalse(answer.getResult());
|
Assert.assertFalse(answer.getResult());
|
||||||
}
|
}
|
||||||
@ -287,7 +268,7 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testExecuteConvertFailure() {
|
public void testExecuteConvertFailure() {
|
||||||
RemoteInstanceTO remoteInstanceTO = getRemoteInstanceTO(Hypervisor.HypervisorType.VMware);
|
RemoteInstanceTO remoteInstanceTO = getRemoteInstanceTO(Hypervisor.HypervisorType.VMware);
|
||||||
ConvertInstanceCommand cmd = getConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM);
|
ConvertInstanceCommand cmd = getConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM, true);
|
||||||
String localMountPoint = "/mnt/xyz";
|
String localMountPoint = "/mnt/xyz";
|
||||||
Mockito.when(temporaryPool.getLocalPath()).thenReturn(localMountPoint);
|
Mockito.when(temporaryPool.getLocalPath()).thenReturn(localMountPoint);
|
||||||
|
|
||||||
@ -297,15 +278,15 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
Mockito.when(mock.getExitValue()).thenReturn(1);
|
Mockito.when(mock.getExitValue()).thenReturn(1);
|
||||||
})
|
})
|
||||||
) {
|
) {
|
||||||
Mockito.when(Script.runSimpleBashScriptForExitValue(LibvirtConvertInstanceCommandWrapper.checkIfConversionIsSupportedCommand)).thenReturn(0);
|
Mockito.when(libvirtComputingResourceMock.hostSupportsInstanceConversion()).thenReturn(true);
|
||||||
Mockito.when(Script.runSimpleBashScriptForExitValueAvoidLogging(Mockito.anyString())).thenReturn(0);
|
Mockito.when(Script.runSimpleBashScriptForExitValue(LibvirtComputingResource.INSTANCE_CONVERSION_SUPPORTED_CHECK_CMD)).thenReturn(0);
|
||||||
|
Mockito.when(Script.runSimpleBashScriptForExitValue(Mockito.anyString())).thenReturn(0);
|
||||||
Mockito.when(Script.runSimpleBashScript(Mockito.anyString())).thenReturn("");
|
Mockito.when(Script.runSimpleBashScript(Mockito.anyString())).thenReturn("");
|
||||||
|
|
||||||
Answer answer = convertInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
|
Answer answer = convertInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
|
||||||
Assert.assertFalse(answer.getResult());
|
Assert.assertFalse(answer.getResult());
|
||||||
Mockito.verify(convertInstanceCommandWrapper).performInstanceConversion(Mockito.anyString(),
|
Mockito.verify(convertInstanceCommandWrapper).performInstanceConversion(Mockito.anyString(),
|
||||||
Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyBoolean());
|
Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyBoolean());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,7 @@ package com.cloud.hypervisor.guru;
|
|||||||
|
|
||||||
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -28,10 +29,12 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.to.NfsTO;
|
||||||
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
|
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
|
||||||
import com.cloud.hypervisor.vmware.mo.HostMO;
|
import com.cloud.hypervisor.vmware.mo.HostMO;
|
||||||
import com.cloud.hypervisor.vmware.util.VmwareClient;
|
import com.cloud.hypervisor.vmware.util.VmwareClient;
|
||||||
import com.cloud.hypervisor.vmware.util.VmwareHelper;
|
import com.cloud.hypervisor.vmware.util.VmwareHelper;
|
||||||
|
import com.cloud.utils.script.Script;
|
||||||
import com.cloud.vm.VmDetailConstants;
|
import com.cloud.vm.VmDetailConstants;
|
||||||
import com.vmware.vim25.VirtualMachinePowerState;
|
import com.vmware.vim25.VirtualMachinePowerState;
|
||||||
import org.apache.cloudstack.acl.ControlledEntity;
|
import org.apache.cloudstack.acl.ControlledEntity;
|
||||||
@ -42,12 +45,14 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
|
|||||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
import org.apache.cloudstack.framework.config.Configurable;
|
import org.apache.cloudstack.framework.config.Configurable;
|
||||||
|
import org.apache.cloudstack.storage.NfsMountManager;
|
||||||
import org.apache.cloudstack.storage.command.CopyCommand;
|
import org.apache.cloudstack.storage.command.CopyCommand;
|
||||||
import org.apache.cloudstack.storage.command.DeleteCommand;
|
import org.apache.cloudstack.storage.command.DeleteCommand;
|
||||||
import org.apache.cloudstack.storage.command.DownloadCommand;
|
import org.apache.cloudstack.storage.command.DownloadCommand;
|
||||||
import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
|
import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
|
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
|
||||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||||
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
||||||
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
|
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
|
||||||
@ -195,6 +200,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
@Inject DiskOfferingDao diskOfferingDao;
|
@Inject DiskOfferingDao diskOfferingDao;
|
||||||
@Inject PhysicalNetworkDao physicalNetworkDao;
|
@Inject PhysicalNetworkDao physicalNetworkDao;
|
||||||
@Inject StoragePoolHostDao storagePoolHostDao;
|
@Inject StoragePoolHostDao storagePoolHostDao;
|
||||||
|
@Inject NfsMountManager mountManager;
|
||||||
|
|
||||||
protected VMwareGuru() {
|
protected VMwareGuru() {
|
||||||
super();
|
super();
|
||||||
@ -1342,7 +1348,13 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
DatacenterMO dataCenterMO) throws Exception {
|
DatacenterMO dataCenterMO) throws Exception {
|
||||||
HostMO sourceHost = vmMo.getRunningHost();
|
HostMO sourceHost = vmMo.getRunningHost();
|
||||||
String cloneName = UUID.randomUUID().toString();
|
String cloneName = UUID.randomUUID().toString();
|
||||||
DatastoreMO datastoreMO = vmMo.getAllDatastores().get(0); //pick the first datastore
|
List<DatastoreMO> vmDatastores = vmMo.getAllDatastores();
|
||||||
|
if (CollectionUtils.isEmpty(vmDatastores)) {
|
||||||
|
String err = String.format("Unable to fetch datastores, could not clone VM %s for migration from VMware", vmName);
|
||||||
|
s_logger.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
DatastoreMO datastoreMO = vmDatastores.get(0); //pick the first datastore
|
||||||
ManagedObjectReference morPool = vmMo.getRunningHost().getHyperHostOwnerResourcePool();
|
ManagedObjectReference morPool = vmMo.getRunningHost().getHyperHostOwnerResourcePool();
|
||||||
boolean result = vmMo.createFullClone(cloneName, dataCenterMO.getVmFolder(), morPool, datastoreMO.getMor(), Storage.ProvisioningType.THIN);
|
boolean result = vmMo.createFullClone(cloneName, dataCenterMO.getVmFolder(), morPool, datastoreMO.getMor(), Storage.ProvisioningType.THIN);
|
||||||
VirtualMachineMO clonedVM = dataCenterMO.findVm(cloneName);
|
VirtualMachineMO clonedVM = dataCenterMO.findVm(cloneName);
|
||||||
@ -1351,14 +1363,23 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
s_logger.error(err);
|
s_logger.error(err);
|
||||||
throw new CloudRuntimeException(err);
|
throw new CloudRuntimeException(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
relocateClonedVMToSourceHost(clonedVM, sourceHost);
|
relocateClonedVMToSourceHost(clonedVM, sourceHost);
|
||||||
return clonedVM;
|
return clonedVM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String createOVFTemplateOfVM(VirtualMachineMO vmMO, DataStoreTO convertLocation, int threadsCountToExportOvf) throws Exception {
|
||||||
|
String dataStoreUrl = getDataStoreUrlForTemplate(convertLocation);
|
||||||
|
String vmOvfName = UUID.randomUUID().toString();
|
||||||
|
String vmOvfCreationPath = createDirOnStorage(vmOvfName, dataStoreUrl, null);
|
||||||
|
s_logger.debug(String.format("Creating OVF %s for the VM %s at %s", vmOvfName, vmMO.getName(), vmOvfCreationPath));
|
||||||
|
vmMO.exportVm(vmOvfCreationPath, vmOvfName, false, false, threadsCountToExportOvf);
|
||||||
|
s_logger.debug(String.format("Created OVF %s for the VM %s at %s", vmOvfName, vmMO.getName(), vmOvfCreationPath));
|
||||||
|
return vmOvfName;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UnmanagedInstanceTO cloneHypervisorVMOutOfBand(String hostIp, String vmName,
|
public Pair<UnmanagedInstanceTO, Boolean> getHypervisorVMOutOfBandAndCloneIfRequired(String hostIp, String vmName, Map<String, String> params) {
|
||||||
Map<String, String> params) {
|
|
||||||
s_logger.debug(String.format("Cloning VM %s on external vCenter %s", vmName, hostIp));
|
|
||||||
String vcenter = params.get(VmDetailConstants.VMWARE_VCENTER_HOST);
|
String vcenter = params.get(VmDetailConstants.VMWARE_VCENTER_HOST);
|
||||||
String datacenter = params.get(VmDetailConstants.VMWARE_DATACENTER_NAME);
|
String datacenter = params.get(VmDetailConstants.VMWARE_DATACENTER_NAME);
|
||||||
String username = params.get(VmDetailConstants.VMWARE_VCENTER_USERNAME);
|
String username = params.get(VmDetailConstants.VMWARE_VCENTER_USERNAME);
|
||||||
@ -1369,25 +1390,45 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
DatacenterMO dataCenterMO = new DatacenterMO(context, datacenter);
|
DatacenterMO dataCenterMO = new DatacenterMO(context, datacenter);
|
||||||
VirtualMachineMO vmMo = dataCenterMO.findVm(vmName);
|
VirtualMachineMO vmMo = dataCenterMO.findVm(vmName);
|
||||||
if (vmMo == null) {
|
if (vmMo == null) {
|
||||||
String err = String.format("Cannot find VM with name %s on %s/%s", vmName, vcenter, datacenter);
|
String err = String.format("Cannot find VM with name %s on vCenter %s/%s", vmName, vcenter, datacenter);
|
||||||
s_logger.error(err);
|
s_logger.error(err);
|
||||||
throw new CloudRuntimeException(err);
|
throw new CloudRuntimeException(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualMachinePowerState sourceVmPowerState = vmMo.getPowerState();
|
VirtualMachinePowerState sourceVmPowerState = vmMo.getPowerState();
|
||||||
if (sourceVmPowerState == VirtualMachinePowerState.POWERED_ON && isWindowsVm(vmMo)) {
|
if (sourceVmPowerState == VirtualMachinePowerState.POWERED_OFF) {
|
||||||
s_logger.debug(String.format("VM %s is a Windows VM and its Running, cannot be imported." +
|
// Don't clone for powered off VMs, can export OVF from it
|
||||||
"Please gracefully shut it down before attempting the import",
|
UnmanagedInstanceTO instanceTO = VmwareHelper.getUnmanagedInstance(vmMo.getRunningHost(), vmMo);
|
||||||
vmName));
|
return new Pair<>(instanceTO, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sourceVmPowerState == VirtualMachinePowerState.POWERED_ON) {
|
||||||
|
if (isWindowsVm(vmMo)) {
|
||||||
|
String err = String.format("VM %s is a Windows VM and its Running, cannot be imported." +
|
||||||
|
" Please gracefully shut it down before attempting the import", vmName);
|
||||||
|
s_logger.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVMOnStandaloneHost(vmMo)) { // or datacenter.equalsIgnoreCase("ha-datacenter")? [Note: default datacenter name on standalone host: ha-datacenter]
|
||||||
|
String err = String.format("VM %s might be on standalone host and is Running, cannot be imported." +
|
||||||
|
" Please shut it down before attempting the import", vmName);
|
||||||
|
s_logger.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_logger.debug(String.format("Cloning VM %s at VMware host %s on vCenter %s", vmName, hostIp, vcenter));
|
||||||
VirtualMachineMO clonedVM = createCloneFromSourceVM(vmName, vmMo, dataCenterMO);
|
VirtualMachineMO clonedVM = createCloneFromSourceVM(vmName, vmMo, dataCenterMO);
|
||||||
s_logger.debug(String.format("VM %s cloned successfully", vmName));
|
s_logger.debug(String.format("VM %s cloned successfully, to VM %s", vmName, clonedVM.getName()));
|
||||||
UnmanagedInstanceTO clonedInstance = VmwareHelper.getUnmanagedInstance(vmMo.getRunningHost(), clonedVM);
|
UnmanagedInstanceTO clonedInstance = VmwareHelper.getUnmanagedInstance(vmMo.getRunningHost(), clonedVM);
|
||||||
setNicsFromSourceVM(clonedInstance, vmMo);
|
setDisksFromSourceVM(clonedInstance, vmMo);
|
||||||
clonedInstance.setCloneSourcePowerState(sourceVmPowerState == VirtualMachinePowerState.POWERED_ON ? UnmanagedInstanceTO.PowerState.PowerOn : UnmanagedInstanceTO.PowerState.PowerOff);
|
clonedInstance.setCloneSourcePowerState(sourceVmPowerState == VirtualMachinePowerState.POWERED_ON ? UnmanagedInstanceTO.PowerState.PowerOn : UnmanagedInstanceTO.PowerState.PowerOff);
|
||||||
return clonedInstance;
|
return new Pair<>(clonedInstance, true);
|
||||||
|
} catch (CloudRuntimeException cre) {
|
||||||
|
throw cre;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String err = String.format("Error cloning VM: %s from external vCenter %s: %s", vmName, vcenter, e.getMessage());
|
String err = String.format("Error while finding or cloning VM: %s from vCenter %s: %s", vmName, vcenter, e.getMessage());
|
||||||
s_logger.error(err, e);
|
s_logger.error(err, e);
|
||||||
throw new CloudRuntimeException(err, e);
|
throw new CloudRuntimeException(err, e);
|
||||||
}
|
}
|
||||||
@ -1398,7 +1439,12 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
return sourceInstance.getOperatingSystem().toLowerCase().contains("windows");
|
return sourceInstance.getOperatingSystem().toLowerCase().contains("windows");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setNicsFromSourceVM(UnmanagedInstanceTO clonedInstance, VirtualMachineMO vmMo) throws Exception {
|
private boolean isVMOnStandaloneHost(VirtualMachineMO vmMo) throws Exception {
|
||||||
|
UnmanagedInstanceTO sourceInstance = VmwareHelper.getUnmanagedInstance(vmMo.getRunningHost(), vmMo);
|
||||||
|
return StringUtils.isEmpty(sourceInstance.getClusterName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDisksFromSourceVM(UnmanagedInstanceTO clonedInstance, VirtualMachineMO vmMo) throws Exception {
|
||||||
UnmanagedInstanceTO sourceInstance = VmwareHelper.getUnmanagedInstance(vmMo.getRunningHost(), vmMo);
|
UnmanagedInstanceTO sourceInstance = VmwareHelper.getUnmanagedInstance(vmMo.getRunningHost(), vmMo);
|
||||||
List<UnmanagedInstanceTO.Disk> sourceDisks = sourceInstance.getDisks();
|
List<UnmanagedInstanceTO.Disk> sourceDisks = sourceInstance.getDisks();
|
||||||
List<UnmanagedInstanceTO.Disk> clonedDisks = clonedInstance.getDisks();
|
List<UnmanagedInstanceTO.Disk> clonedDisks = clonedInstance.getDisks();
|
||||||
@ -1410,12 +1456,40 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeClonedHypervisorVMOutOfBand(String hostIp, String vmName, Map<String, String> params) {
|
public String createVMTemplateOutOfBand(String hostIp, String vmName, Map<String, String> params, DataStoreTO templateLocation, int threadsCountToExportOvf) {
|
||||||
s_logger.debug(String.format("Removing VM %s on external vCenter %s", vmName, hostIp));
|
|
||||||
String vcenter = params.get(VmDetailConstants.VMWARE_VCENTER_HOST);
|
String vcenter = params.get(VmDetailConstants.VMWARE_VCENTER_HOST);
|
||||||
String datacenter = params.get(VmDetailConstants.VMWARE_DATACENTER_NAME);
|
String datacenter = params.get(VmDetailConstants.VMWARE_DATACENTER_NAME);
|
||||||
String username = params.get(VmDetailConstants.VMWARE_VCENTER_USERNAME);
|
String username = params.get(VmDetailConstants.VMWARE_VCENTER_USERNAME);
|
||||||
String password = params.get(VmDetailConstants.VMWARE_VCENTER_PASSWORD);
|
String password = params.get(VmDetailConstants.VMWARE_VCENTER_PASSWORD);
|
||||||
|
s_logger.debug(String.format("Creating template of the VM %s at VMware host %s on vCenter %s", vmName, hostIp, vcenter));
|
||||||
|
|
||||||
|
try {
|
||||||
|
VmwareContext context = connectToVcenter(vcenter, username, password);
|
||||||
|
DatacenterMO dataCenterMO = new DatacenterMO(context, datacenter);
|
||||||
|
VirtualMachineMO vmMo = dataCenterMO.findVm(vmName);
|
||||||
|
if (vmMo == null) {
|
||||||
|
String err = String.format("Cannot find VM with name %s on vCenter %s/%s, to create template file", vmName, vcenter, datacenter);
|
||||||
|
s_logger.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
String ovaTemplate = createOVFTemplateOfVM(vmMo, templateLocation, threadsCountToExportOvf);
|
||||||
|
s_logger.debug(String.format("OVF %s created successfully on the datastore", ovaTemplate));
|
||||||
|
return ovaTemplate;
|
||||||
|
} catch (Exception e) {
|
||||||
|
String err = String.format("Error create template file of the VM: %s from vCenter %s: %s", vmName, vcenter, e.getMessage());
|
||||||
|
s_logger.error(err, e);
|
||||||
|
throw new CloudRuntimeException(err, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeClonedHypervisorVMOutOfBand(String hostIp, String vmName, Map<String, String> params) {
|
||||||
|
String vcenter = params.get(VmDetailConstants.VMWARE_VCENTER_HOST);
|
||||||
|
String datacenter = params.get(VmDetailConstants.VMWARE_DATACENTER_NAME);
|
||||||
|
String username = params.get(VmDetailConstants.VMWARE_VCENTER_USERNAME);
|
||||||
|
String password = params.get(VmDetailConstants.VMWARE_VCENTER_PASSWORD);
|
||||||
|
s_logger.debug(String.format("Removing cloned VM %s at VMware host %s on vCenter %s", vmName, hostIp, vcenter));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
VmwareContext context = connectToVcenter(vcenter, username, password);
|
VmwareContext context = connectToVcenter(vcenter, username, password);
|
||||||
DatacenterMO dataCenterMO = new DatacenterMO(context, datacenter);
|
DatacenterMO dataCenterMO = new DatacenterMO(context, datacenter);
|
||||||
@ -1426,11 +1500,97 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
s_logger.error(err);
|
s_logger.error(err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return vmMo.destroy();
|
return vmMo.destroy();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String err = String.format("Error destroying external VM %s: %s", vmName, e.getMessage());
|
String err = String.format("Error destroying cloned VM %s: %s", vmName, e.getMessage());
|
||||||
s_logger.error(err, e);
|
s_logger.error(err, e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeVMTemplateOutOfBand(DataStoreTO templateLocation, String templateDir) {
|
||||||
|
s_logger.debug(String.format("Removing template %s", templateDir));
|
||||||
|
|
||||||
|
try {
|
||||||
|
String dataStoreUrl = getDataStoreUrlForTemplate(templateLocation);
|
||||||
|
return deleteDirOnStorage(templateDir, dataStoreUrl, null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
String err = String.format("Error removing template file %s: %s", templateDir, e.getMessage());
|
||||||
|
s_logger.error(err, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDataStoreUrlForTemplate(DataStoreTO templateLocation) {
|
||||||
|
String dataStoreUrl = null;
|
||||||
|
if (templateLocation instanceof NfsTO) {
|
||||||
|
NfsTO nfsStore = (NfsTO) templateLocation;
|
||||||
|
dataStoreUrl = nfsStore.getUrl();
|
||||||
|
} else if (templateLocation instanceof PrimaryDataStoreTO) {
|
||||||
|
PrimaryDataStoreTO primaryDataStoreTO = (PrimaryDataStoreTO) templateLocation;
|
||||||
|
if (primaryDataStoreTO.getPoolType().equals(Storage.StoragePoolType.NetworkFilesystem)) {
|
||||||
|
String psHost = primaryDataStoreTO.getHost();
|
||||||
|
String psPath = primaryDataStoreTO.getPath();
|
||||||
|
dataStoreUrl = "nfs://" + psHost + File.separator + psPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataStoreUrl == null) {
|
||||||
|
throw new CloudRuntimeException("Only NFS storage is supported for template creation");
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataStoreUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createDirOnStorage(String dirName, String nfsStorageUrl, String nfsVersion) throws Exception {
|
||||||
|
String mountPoint = mountManager.getMountPoint(nfsStorageUrl, nfsVersion);
|
||||||
|
s_logger.debug("Create dir storage location - url: " + nfsStorageUrl + ", mount point: " + mountPoint + ", dir: " + dirName);
|
||||||
|
String dirMountPath = mountPoint + File.separator + dirName;
|
||||||
|
createDir(dirMountPath);
|
||||||
|
return dirMountPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createDir(String dirName) throws Exception {
|
||||||
|
synchronized (dirName.intern()) {
|
||||||
|
Script command = new Script("mkdir", s_logger);
|
||||||
|
command.add("-p");
|
||||||
|
command.add(dirName);
|
||||||
|
String cmdResult = command.execute();
|
||||||
|
if (cmdResult != null) {
|
||||||
|
String msg = "Unable to create directory: " + dirName + ", error msg: " + cmdResult;
|
||||||
|
s_logger.error(msg);
|
||||||
|
throw new Exception(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean deleteDirOnStorage(String dirName, String nfsStorageUrl, String nfsVersion) throws Exception {
|
||||||
|
try {
|
||||||
|
String mountPoint = mountManager.getMountPoint(nfsStorageUrl, nfsVersion);
|
||||||
|
s_logger.debug("Delete dir storage location - url: " + nfsStorageUrl + ", mount point: " + mountPoint + ", dir: " + dirName);
|
||||||
|
String dirMountPath = mountPoint + File.separator + dirName;
|
||||||
|
deleteDir(dirMountPath);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
String err = String.format("Unable to delete dir %s: %s", dirName, e.getMessage());
|
||||||
|
s_logger.error(err, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteDir(String dirName) throws Exception {
|
||||||
|
synchronized (dirName.intern()) {
|
||||||
|
Script command = new Script("rm", s_logger);
|
||||||
|
command.add("-rf");
|
||||||
|
command.add(dirName);
|
||||||
|
String cmdResult = command.execute();
|
||||||
|
if (cmdResult != null) {
|
||||||
|
String msg = "Unable to delete directory: " + dirName + ", error msg: " + cmdResult;
|
||||||
|
s_logger.error(msg);
|
||||||
|
throw new Exception(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,21 +17,37 @@
|
|||||||
package com.cloud.hypervisor.guru;
|
package com.cloud.hypervisor.guru;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.mockito.Mockito.withSettings;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.storage.NfsMountManager;
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
|
import org.apache.cloudstack.vm.UnmanagedInstanceTO;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockedConstruction;
|
||||||
|
import org.mockito.MockedStatic;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
@ -41,9 +57,19 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
|||||||
|
|
||||||
import com.cloud.agent.api.Command;
|
import com.cloud.agent.api.Command;
|
||||||
import com.cloud.agent.api.MigrateVmToPoolCommand;
|
import com.cloud.agent.api.MigrateVmToPoolCommand;
|
||||||
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
|
import com.cloud.agent.api.to.NfsTO;
|
||||||
import com.cloud.dc.ClusterDetailsDao;
|
import com.cloud.dc.ClusterDetailsDao;
|
||||||
import com.cloud.host.HostVO;
|
import com.cloud.host.HostVO;
|
||||||
import com.cloud.host.dao.HostDao;
|
import com.cloud.host.dao.HostDao;
|
||||||
|
import com.cloud.hypervisor.vmware.mo.DatacenterMO;
|
||||||
|
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
|
||||||
|
import com.cloud.hypervisor.vmware.mo.HostMO;
|
||||||
|
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
|
||||||
|
import com.cloud.hypervisor.vmware.util.VmwareClient;
|
||||||
|
import com.cloud.hypervisor.vmware.util.VmwareContext;
|
||||||
|
import com.cloud.hypervisor.vmware.util.VmwareHelper;
|
||||||
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.storage.Storage.ProvisioningType;
|
import com.cloud.storage.Storage.ProvisioningType;
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
import com.cloud.storage.StoragePoolHostVO;
|
import com.cloud.storage.StoragePoolHostVO;
|
||||||
@ -51,8 +77,15 @@ import com.cloud.storage.Volume;
|
|||||||
import com.cloud.storage.VolumeVO;
|
import com.cloud.storage.VolumeVO;
|
||||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
|
import com.cloud.utils.UuidUtils;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.cloud.vm.VirtualMachine;
|
import com.cloud.vm.VirtualMachine;
|
||||||
import com.cloud.vm.VirtualMachineManager;
|
import com.cloud.vm.VirtualMachineManager;
|
||||||
|
import com.cloud.vm.VmDetailConstants;
|
||||||
|
import com.vmware.vim25.ManagedObjectReference;
|
||||||
|
import com.vmware.vim25.ServiceContent;
|
||||||
|
import com.vmware.vim25.VimPortType;
|
||||||
|
import com.vmware.vim25.VirtualMachinePowerState;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
|
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
|
||||||
@ -79,6 +112,21 @@ public class VMwareGuruTest {
|
|||||||
|
|
||||||
AutoCloseable closeable;
|
AutoCloseable closeable;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
NfsMountManager mountManager;
|
||||||
|
|
||||||
|
private static MockedStatic<VmwareHelper> mockedVmwareHelper;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void init() {
|
||||||
|
mockedVmwareHelper = Mockito.mockStatic(VmwareHelper.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void close() {
|
||||||
|
mockedVmwareHelper.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void testSetUp() throws Exception {
|
public void testSetUp() throws Exception {
|
||||||
closeable = MockitoAnnotations.openMocks(this);
|
closeable = MockitoAnnotations.openMocks(this);
|
||||||
@ -155,4 +203,415 @@ public class VMwareGuruTest {
|
|||||||
|
|
||||||
assertEquals(expected, result);
|
assertEquals(expected, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected=CloudRuntimeException.class)
|
||||||
|
public void testCloneHypervisorVM_NoExternalVM() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(null).when(mockDatacenterMO).findVm(vmName);
|
||||||
|
})) {
|
||||||
|
vMwareGuru.getHypervisorVMOutOfBandAndCloneIfRequired(hostIp, vmName, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=CloudRuntimeException.class)
|
||||||
|
public void testCloneHypervisorVM_WindowsVMRunning() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
VirtualMachineMO vmMo = Mockito.mock(VirtualMachineMO.class);
|
||||||
|
HostMO hostMo = Mockito.mock(HostMO.class);
|
||||||
|
Mockito.doReturn(VirtualMachinePowerState.POWERED_ON).when(vmMo).getPowerState();
|
||||||
|
Mockito.doReturn(hostMo).when(vmMo).getRunningHost();
|
||||||
|
UnmanagedInstanceTO instance = Mockito.mock(UnmanagedInstanceTO.class);
|
||||||
|
Mockito.doReturn("Windows 2019").when(instance).getOperatingSystem();
|
||||||
|
when(VmwareHelper.getUnmanagedInstance(hostMo, vmMo)).thenReturn(instance);
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(vmMo).when(mockDatacenterMO).findVm(vmName);
|
||||||
|
})) {
|
||||||
|
vMwareGuru.getHypervisorVMOutOfBandAndCloneIfRequired(hostIp, vmName, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=CloudRuntimeException.class)
|
||||||
|
public void testCloneHypervisorVM_GetDatastoresFailed() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
VirtualMachineMO vmMo = Mockito.mock(VirtualMachineMO.class);
|
||||||
|
HostMO hostMo = Mockito.mock(HostMO.class);
|
||||||
|
Mockito.doReturn(VirtualMachinePowerState.POWERED_ON).when(vmMo).getPowerState();
|
||||||
|
Mockito.doReturn(hostMo).when(vmMo).getRunningHost();
|
||||||
|
UnmanagedInstanceTO instance = Mockito.mock(UnmanagedInstanceTO.class);
|
||||||
|
Mockito.doReturn("CentOS").when(instance).getOperatingSystem();
|
||||||
|
Mockito.doReturn("test-cluster").when(instance).getClusterName();
|
||||||
|
when(VmwareHelper.getUnmanagedInstance(hostMo, vmMo)).thenReturn(instance);
|
||||||
|
List<DatastoreMO> datastores = new ArrayList<>();
|
||||||
|
Mockito.doReturn(datastores).when(vmMo).getAllDatastores();
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(vmMo).when(mockDatacenterMO).findVm(vmName);
|
||||||
|
})) {
|
||||||
|
vMwareGuru.getHypervisorVMOutOfBandAndCloneIfRequired(hostIp, vmName, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=CloudRuntimeException.class)
|
||||||
|
public void testCloneHypervisorVM_CloneVMFailed() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
VirtualMachineMO vmMo = Mockito.mock(VirtualMachineMO.class);
|
||||||
|
HostMO hostMo = Mockito.mock(HostMO.class);
|
||||||
|
Mockito.doReturn(VirtualMachinePowerState.POWERED_ON).when(vmMo).getPowerState();
|
||||||
|
Mockito.doReturn(hostMo).when(vmMo).getRunningHost();
|
||||||
|
Mockito.doReturn(mor).when(hostMo).getHyperHostOwnerResourcePool();
|
||||||
|
UnmanagedInstanceTO instance = Mockito.mock(UnmanagedInstanceTO.class);
|
||||||
|
Mockito.doReturn("CentOS").when(instance).getOperatingSystem();
|
||||||
|
Mockito.doReturn("test-cluster").when(instance).getClusterName();
|
||||||
|
when(VmwareHelper.getUnmanagedInstance(hostMo, vmMo)).thenReturn(instance);
|
||||||
|
DatastoreMO datastoreMO = Mockito.mock(DatastoreMO.class);
|
||||||
|
Mockito.doReturn(mor).when(datastoreMO).getMor();
|
||||||
|
List<DatastoreMO> datastores = new ArrayList<>();
|
||||||
|
datastores.add(datastoreMO);
|
||||||
|
Mockito.doReturn(datastores).when(vmMo).getAllDatastores();
|
||||||
|
Mockito.lenient().doReturn(false).when(vmMo).createFullClone(anyString(), any(ManagedObjectReference.class), any(ManagedObjectReference.class), any(ManagedObjectReference.class), any(Storage.ProvisioningType.class));
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(vmMo).when(mockDatacenterMO).findVm(anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockDatacenterMO).getVmFolder();
|
||||||
|
Mockito.doReturn(mor).when(mockDatacenterMO).getMor();
|
||||||
|
})) {
|
||||||
|
vMwareGuru.getHypervisorVMOutOfBandAndCloneIfRequired(hostIp, vmName, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCloneHypervisorVM() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
VirtualMachineMO vmMo = Mockito.mock(VirtualMachineMO.class);
|
||||||
|
HostMO hostMo = Mockito.mock(HostMO.class);
|
||||||
|
Mockito.doReturn(VirtualMachinePowerState.POWERED_ON).when(vmMo).getPowerState();
|
||||||
|
Mockito.doReturn(hostMo).when(vmMo).getRunningHost();
|
||||||
|
Mockito.doReturn(mor).when(hostMo).getHyperHostOwnerResourcePool();
|
||||||
|
Mockito.doReturn(mor).when(hostMo).getMor();
|
||||||
|
DatastoreMO datastoreMO = Mockito.mock(DatastoreMO.class);
|
||||||
|
Mockito.doReturn(mor).when(datastoreMO).getMor();
|
||||||
|
List<DatastoreMO> datastores = new ArrayList<>();
|
||||||
|
datastores.add(datastoreMO);
|
||||||
|
Mockito.doReturn(datastores).when(vmMo).getAllDatastores();
|
||||||
|
Mockito.lenient().doReturn(true).when(vmMo).createFullClone(anyString(), any(ManagedObjectReference.class), any(ManagedObjectReference.class), any(ManagedObjectReference.class), any(Storage.ProvisioningType.class));
|
||||||
|
UnmanagedInstanceTO instance = Mockito.mock(UnmanagedInstanceTO.class);
|
||||||
|
Mockito.doReturn("CentOS").when(instance).getOperatingSystem();
|
||||||
|
Mockito.doReturn("test-cluster").when(instance).getClusterName();
|
||||||
|
when(VmwareHelper.getUnmanagedInstance(hostMo, vmMo)).thenReturn(instance);
|
||||||
|
UnmanagedInstanceTO.Disk disk = Mockito.mock(UnmanagedInstanceTO.Disk.class);
|
||||||
|
Mockito.doReturn("1").when(disk).getDiskId();
|
||||||
|
List<UnmanagedInstanceTO.Disk> disks = new ArrayList<>();
|
||||||
|
disks.add(disk);
|
||||||
|
Mockito.doReturn(disks).when(instance).getDisks();
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(vmMo).when(mockDatacenterMO).findVm(anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockDatacenterMO).getVmFolder();
|
||||||
|
Mockito.doReturn(mor).when(mockDatacenterMO).getMor();
|
||||||
|
})) {
|
||||||
|
Pair<UnmanagedInstanceTO, Boolean> clonedVm = vMwareGuru.getHypervisorVMOutOfBandAndCloneIfRequired(hostIp, vmName, params);
|
||||||
|
assertNotNull(clonedVm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=CloudRuntimeException.class)
|
||||||
|
public void testCreateVMTemplateFileOutOfBand_NoClonedVM() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "cloned-test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
DataStoreTO dataStore = Mockito.mock(DataStoreTO.class);
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(null).when(mockDatacenterMO).findVm(vmName);
|
||||||
|
})) {
|
||||||
|
vMwareGuru.createVMTemplateOutOfBand(hostIp, vmName, params, dataStore, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateVMTemplateFileOutOfBand() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "cloned-test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
VirtualMachineMO vmMo = Mockito.mock(VirtualMachineMO.class);
|
||||||
|
Mockito.doNothing().when(vmMo).exportVm(anyString(), anyString(), anyBoolean(), anyBoolean(), anyInt());
|
||||||
|
NfsTO dataStore = Mockito.mock(NfsTO.class);
|
||||||
|
Mockito.doReturn("nfs://10.1.1.4/testdir").when(dataStore).getUrl();
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(vmMo).when(mockDatacenterMO).findVm(vmName);
|
||||||
|
})) {
|
||||||
|
String vmTemplate = vMwareGuru.createVMTemplateOutOfBand(hostIp, vmName, params, dataStore, -1);
|
||||||
|
assertNotNull(vmTemplate);
|
||||||
|
assertTrue(UuidUtils.isUuid(vmTemplate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveClonedHypervisorVM_NoClonedVM() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "cloned-test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(null).when(mockDatacenterMO).findVm(vmName);
|
||||||
|
})) {
|
||||||
|
boolean result = vMwareGuru.removeClonedHypervisorVMOutOfBand(hostIp, vmName, params);
|
||||||
|
assertFalse(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveClonedHypervisorVM() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "cloned-test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
VirtualMachineMO vmMo = Mockito.mock(VirtualMachineMO.class);
|
||||||
|
Mockito.doReturn(true).when(vmMo).destroy();
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(vmMo).when(mockDatacenterMO).findVm(vmName);
|
||||||
|
})) {
|
||||||
|
boolean result = vMwareGuru.removeClonedHypervisorVMOutOfBand(hostIp, vmName, params);
|
||||||
|
assertTrue(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveVMTemplateFileOutOfBand() throws Exception {
|
||||||
|
NfsTO dataStore = Mockito.mock(NfsTO.class);
|
||||||
|
Mockito.doReturn("nfs://10.1.1.4/testdir").when(dataStore).getUrl();
|
||||||
|
String templateDir = "f887b7b3-3d1f-4a7d-93e5-3147f58866c6";
|
||||||
|
boolean result = vMwareGuru.removeVMTemplateOutOfBand(dataStore, templateDir);
|
||||||
|
assertTrue(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5127,7 +5127,7 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||||||
} else if (instance.getHostName() != null) {
|
} else if (instance.getHostName() != null) {
|
||||||
response.setHostName(instance.getHostName());
|
response.setHostName(instance.getHostName());
|
||||||
}
|
}
|
||||||
response.setPowerState(instance.getPowerState().toString());
|
response.setPowerState((instance.getPowerState() != null)? instance.getPowerState().toString() : UnmanagedInstanceTO.PowerState.PowerUnknown.toString());
|
||||||
response.setCpuCores(instance.getCpuCores());
|
response.setCpuCores(instance.getCpuCores());
|
||||||
response.setCpuSpeed(instance.getCpuSpeed());
|
response.setCpuSpeed(instance.getCpuSpeed());
|
||||||
response.setCpuCoresPerSocket(instance.getCpuCoresPerSocket());
|
response.setCpuCoresPerSocket(instance.getCpuCoresPerSocket());
|
||||||
|
|||||||
@ -247,7 +247,7 @@ public class HostJoinDaoImpl extends GenericDaoBase<HostJoinVO, Long> implements
|
|||||||
host.getHypervisorType() == Hypervisor.HypervisorType.Custom)) {
|
host.getHypervisorType() == Hypervisor.HypervisorType.Custom)) {
|
||||||
//only kvm has the requirement to return host details
|
//only kvm has the requirement to return host details
|
||||||
try {
|
try {
|
||||||
hostResponse.setDetails(hostDetails);
|
hostResponse.setDetails(hostDetails, host.getHypervisorType());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
s_logger.debug("failed to get host details", e);
|
s_logger.debug("failed to get host details", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -467,9 +467,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
|
|
||||||
private long _defaultPageSize = Long.parseLong(Config.DefaultPageSize.getDefaultValue());
|
private long _defaultPageSize = Long.parseLong(Config.DefaultPageSize.getDefaultValue());
|
||||||
private static final String DOMAIN_NAME_PATTERN = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{1,63}$";
|
private static final String DOMAIN_NAME_PATTERN = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{1,63}$";
|
||||||
protected Set<String> configValuesForValidation;
|
private Set<String> configValuesForValidation = new HashSet<String>();
|
||||||
private Set<String> weightBasedParametersForValidation;
|
private Set<String> weightBasedParametersForValidation = new HashSet<String>();
|
||||||
private Set<String> overprovisioningFactorsForValidation;
|
private Set<String> overprovisioningFactorsForValidation = new HashSet<String>();
|
||||||
|
|
||||||
public static final ConfigKey<Boolean> SystemVMUseLocalStorage = new ConfigKey<Boolean>(Boolean.class, "system.vm.use.local.storage", "Advanced", "false",
|
public static final ConfigKey<Boolean> SystemVMUseLocalStorage = new ConfigKey<Boolean>(Boolean.class, "system.vm.use.local.storage", "Advanced", "false",
|
||||||
"Indicates whether to use local storage pools or shared storage pools for system VMs.", false, ConfigKey.Scope.Zone, null);
|
"Indicates whether to use local storage pools or shared storage pools for system VMs.", false, ConfigKey.Scope.Zone, null);
|
||||||
@ -530,8 +530,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populateConfigValuesForValidationSet() {
|
protected void populateConfigValuesForValidationSet() {
|
||||||
configValuesForValidation = new HashSet<String>();
|
|
||||||
configValuesForValidation.add("event.purge.interval");
|
configValuesForValidation.add("event.purge.interval");
|
||||||
configValuesForValidation.add("account.cleanup.interval");
|
configValuesForValidation.add("account.cleanup.interval");
|
||||||
configValuesForValidation.add("alert.wait");
|
configValuesForValidation.add("alert.wait");
|
||||||
@ -559,10 +558,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
configValuesForValidation.add(StorageManager.STORAGE_POOL_CLIENT_MAX_CONNECTIONS.key());
|
configValuesForValidation.add(StorageManager.STORAGE_POOL_CLIENT_MAX_CONNECTIONS.key());
|
||||||
configValuesForValidation.add(UserDataManager.VM_USERDATA_MAX_LENGTH_STRING);
|
configValuesForValidation.add(UserDataManager.VM_USERDATA_MAX_LENGTH_STRING);
|
||||||
configValuesForValidation.add(UnmanagedVMsManager.RemoteKvmInstanceDisksCopyTimeout.key());
|
configValuesForValidation.add(UnmanagedVMsManager.RemoteKvmInstanceDisksCopyTimeout.key());
|
||||||
|
configValuesForValidation.add(UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.key());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void weightBasedParametersForValidation() {
|
private void weightBasedParametersForValidation() {
|
||||||
weightBasedParametersForValidation = new HashSet<String>();
|
|
||||||
weightBasedParametersForValidation.add(AlertManager.CPUCapacityThreshold.key());
|
weightBasedParametersForValidation.add(AlertManager.CPUCapacityThreshold.key());
|
||||||
weightBasedParametersForValidation.add(AlertManager.StorageAllocatedCapacityThreshold.key());
|
weightBasedParametersForValidation.add(AlertManager.StorageAllocatedCapacityThreshold.key());
|
||||||
weightBasedParametersForValidation.add(AlertManager.StorageCapacityThreshold.key());
|
weightBasedParametersForValidation.add(AlertManager.StorageCapacityThreshold.key());
|
||||||
@ -582,11 +581,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
weightBasedParametersForValidation.add(CapacityManager.SecondaryStorageCapacityThreshold.key());
|
weightBasedParametersForValidation.add(CapacityManager.SecondaryStorageCapacityThreshold.key());
|
||||||
weightBasedParametersForValidation.add(ClusterDrsService.ClusterDrsImbalanceThreshold.key());
|
weightBasedParametersForValidation.add(ClusterDrsService.ClusterDrsImbalanceThreshold.key());
|
||||||
weightBasedParametersForValidation.add(ClusterDrsService.ClusterDrsImbalanceSkipThreshold.key());
|
weightBasedParametersForValidation.add(ClusterDrsService.ClusterDrsImbalanceSkipThreshold.key());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void overProvisioningFactorsForValidation() {
|
private void overProvisioningFactorsForValidation() {
|
||||||
overprovisioningFactorsForValidation = new HashSet<String>();
|
|
||||||
overprovisioningFactorsForValidation.add(CapacityManager.MemOverprovisioningFactor.key());
|
overprovisioningFactorsForValidation.add(CapacityManager.MemOverprovisioningFactor.key());
|
||||||
overprovisioningFactorsForValidation.add(CapacityManager.CpuOverprovisioningFactor.key());
|
overprovisioningFactorsForValidation.add(CapacityManager.CpuOverprovisioningFactor.key());
|
||||||
overprovisioningFactorsForValidation.add(CapacityManager.StorageOverprovisioningFactor.key());
|
overprovisioningFactorsForValidation.add(CapacityManager.StorageOverprovisioningFactor.key());
|
||||||
@ -1173,8 +1170,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
return new Pair<Configuration, String>(_configDao.findByName(name), newValue);
|
return new Pair<Configuration, String>(_configDao.findByName(name), newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String validateConfigurationValue(final String name, String value, final String scope) {
|
protected String validateConfigurationValue(final String name, String value, final String scope) {
|
||||||
|
|
||||||
final ConfigurationVO cfg = _configDao.findByName(name);
|
final ConfigurationVO cfg = _configDao.findByName(name);
|
||||||
if (cfg == null) {
|
if (cfg == null) {
|
||||||
s_logger.error("Missing configuration variable " + name + " in configuration table");
|
s_logger.error("Missing configuration variable " + name + " in configuration table");
|
||||||
@ -1256,45 +1252,48 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type.equals(Integer.class) && NetworkModel.MACIdentifier.key().equalsIgnoreCase(name)) {
|
if (type.equals(Integer.class)) {
|
||||||
try {
|
try {
|
||||||
final int val = Integer.parseInt(value);
|
final int val = Integer.parseInt(value);
|
||||||
//The value need to be between 0 to 255 because the mac generation needs a value of 8 bit
|
|
||||||
//0 value is considered as disable.
|
|
||||||
if(val < 0 || val > 255){
|
|
||||||
throw new InvalidParameterValueException(name+" value should be between 0 and 255. 0 value will disable this feature");
|
|
||||||
}
|
|
||||||
} catch (final NumberFormatException e) {
|
|
||||||
s_logger.error("There was an error trying to parse the integer value for:" + name);
|
|
||||||
throw new InvalidParameterValueException("There was an error trying to parse the integer value for:" + name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type.equals(Integer.class) && configValuesForValidation.contains(name)) {
|
if (NetworkModel.MACIdentifier.key().equalsIgnoreCase(name)) {
|
||||||
try {
|
//The value need to be between 0 to 255 because the mac generation needs a value of 8 bit
|
||||||
final int val = Integer.parseInt(value);
|
//0 value is considered as disable.
|
||||||
if (val <= 0) {
|
if(val < 0 || val > 255){
|
||||||
throw new InvalidParameterValueException("Please enter a positive value for the configuration parameter:" + name);
|
throw new InvalidParameterValueException(name + " value should be between 0 and 255. 0 value will disable this feature");
|
||||||
}
|
|
||||||
if ("vm.password.length".equalsIgnoreCase(name) && val < 6) {
|
|
||||||
throw new InvalidParameterValueException("Please enter a value greater than 5 for the configuration parameter:" + name);
|
|
||||||
}
|
|
||||||
if ("remote.access.vpn.psk.length".equalsIgnoreCase(name)) {
|
|
||||||
if (val < 8) {
|
|
||||||
throw new InvalidParameterValueException("Please enter a value greater than 7 for the configuration parameter:" + name);
|
|
||||||
}
|
|
||||||
if (val > 256) {
|
|
||||||
throw new InvalidParameterValueException("Please enter a value less than 257 for the configuration parameter:" + name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (UserDataManager.VM_USERDATA_MAX_LENGTH_STRING.equalsIgnoreCase(name)) {
|
|
||||||
if (val > 1048576) {
|
if (UnmanagedVMsManager.ThreadsOnMSToImportVMwareVMFiles.key().equalsIgnoreCase(name) || UnmanagedVMsManager.ThreadsOnKVMHostToImportVMwareVMFiles.key().equalsIgnoreCase(name)) {
|
||||||
throw new InvalidParameterValueException("Please enter a value less than 1048576 for the configuration parameter:" + name);
|
if (val > 10) {
|
||||||
|
throw new InvalidParameterValueException("Please enter a value between 0 and 10 for the configuration parameter: " + name + ", -1 will disable it");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configValuesForValidation.contains(name)) {
|
||||||
|
if (val <= 0) {
|
||||||
|
throw new InvalidParameterValueException("Please enter a positive value for the configuration parameter:" + name);
|
||||||
|
}
|
||||||
|
if ("vm.password.length".equalsIgnoreCase(name) && val < 6) {
|
||||||
|
throw new InvalidParameterValueException("Please enter a value greater than 5 for the configuration parameter:" + name);
|
||||||
|
}
|
||||||
|
if ("remote.access.vpn.psk.length".equalsIgnoreCase(name)) {
|
||||||
|
if (val < 8) {
|
||||||
|
throw new InvalidParameterValueException("Please enter a value greater than 7 for the configuration parameter:" + name);
|
||||||
|
}
|
||||||
|
if (val > 256) {
|
||||||
|
throw new InvalidParameterValueException("Please enter a value less than 257 for the configuration parameter:" + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (UserDataManager.VM_USERDATA_MAX_LENGTH_STRING.equalsIgnoreCase(name)) {
|
||||||
|
if (val > 1048576) {
|
||||||
|
throw new InvalidParameterValueException("Please enter a value less than 1048576 for the configuration parameter:" + name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (final NumberFormatException e) {
|
} catch (final NumberFormatException e) {
|
||||||
s_logger.error("There was an error trying to parse the integer value for:" + name);
|
s_logger.error("There was an error trying to parse the integer value for configuration parameter: " + name);
|
||||||
throw new InvalidParameterValueException("There was an error trying to parse the integer value for:" + name);
|
throw new InvalidParameterValueException("There was an error trying to parse the integer value for configuration parameter: " + name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1305,8 +1304,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
throw new InvalidParameterValueException("Please enter a value between 0 and 1 for the configuration parameter: " + name);
|
throw new InvalidParameterValueException("Please enter a value between 0 and 1 for the configuration parameter: " + name);
|
||||||
}
|
}
|
||||||
} catch (final NumberFormatException e) {
|
} catch (final NumberFormatException e) {
|
||||||
s_logger.error("There was an error trying to parse the float value for:" + name);
|
s_logger.error("There was an error trying to parse the float value for configuration parameter: " + name);
|
||||||
throw new InvalidParameterValueException("There was an error trying to parse the float value for:" + name);
|
throw new InvalidParameterValueException("There was an error trying to parse the float value for configuration parameter: " + name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -35,6 +35,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import com.cloud.agent.api.Command;
|
import com.cloud.agent.api.Command;
|
||||||
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
import com.cloud.agent.api.to.DiskTO;
|
import com.cloud.agent.api.to.DiskTO;
|
||||||
import com.cloud.agent.api.to.NicTO;
|
import com.cloud.agent.api.to.NicTO;
|
||||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||||
@ -377,7 +378,7 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UnmanagedInstanceTO cloneHypervisorVMOutOfBand(String hostIp, String vmName, Map<String, String> params) {
|
public Pair<UnmanagedInstanceTO, Boolean> getHypervisorVMOutOfBandAndCloneIfRequired(String hostIp, String vmName, Map<String, String> params) {
|
||||||
s_logger.error("Unsupported operation: cannot clone external VM");
|
s_logger.error("Unsupported operation: cannot clone external VM");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -387,4 +388,16 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
|
|||||||
s_logger.error("Unsupported operation: cannot remove external VM");
|
s_logger.error("Unsupported operation: cannot remove external VM");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createVMTemplateOutOfBand(String hostIp, String vmName, Map<String, String> params, DataStoreTO templateLocation, int threadsCountToExportOvf) {
|
||||||
|
s_logger.error("Unsupported operation: cannot create template file");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeVMTemplateOutOfBand(DataStoreTO templateLocation, String templateDir) {
|
||||||
|
s_logger.error("Unsupported operation: cannot remove template file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3834,7 +3834,6 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
MountDisabledStoragePool,
|
MountDisabledStoragePool,
|
||||||
VmwareCreateCloneFull,
|
VmwareCreateCloneFull,
|
||||||
VmwareAllowParallelExecution,
|
VmwareAllowParallelExecution,
|
||||||
ConvertVmwareInstanceToKvmTimeout,
|
|
||||||
DataStoreDownloadFollowRedirects
|
DataStoreDownloadFollowRedirects
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,8 @@ package org.apache.cloudstack.vm;
|
|||||||
|
|
||||||
import com.cloud.agent.AgentManager;
|
import com.cloud.agent.AgentManager;
|
||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.agent.api.CheckConvertInstanceAnswer;
|
||||||
|
import com.cloud.agent.api.CheckConvertInstanceCommand;
|
||||||
import com.cloud.agent.api.CheckVolumeAnswer;
|
import com.cloud.agent.api.CheckVolumeAnswer;
|
||||||
import com.cloud.agent.api.CheckVolumeCommand;
|
import com.cloud.agent.api.CheckVolumeCommand;
|
||||||
import com.cloud.agent.api.ConvertInstanceAnswer;
|
import com.cloud.agent.api.ConvertInstanceAnswer;
|
||||||
@ -95,7 +97,6 @@ import com.cloud.storage.ScopeType;
|
|||||||
import com.cloud.storage.Snapshot;
|
import com.cloud.storage.Snapshot;
|
||||||
import com.cloud.storage.SnapshotVO;
|
import com.cloud.storage.SnapshotVO;
|
||||||
import com.cloud.storage.Storage;
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.storage.StorageManager;
|
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
import com.cloud.storage.VMTemplateStoragePoolVO;
|
import com.cloud.storage.VMTemplateStoragePoolVO;
|
||||||
import com.cloud.storage.VMTemplateVO;
|
import com.cloud.storage.VMTemplateVO;
|
||||||
@ -687,7 +688,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
// Check for duplicate hostname in network, get all vms hostNames in the network
|
// Check for duplicate hostname in network, get all vms hostNames in the network
|
||||||
List<String> hostNames = vmDao.listDistinctHostNames(network.getId());
|
List<String> hostNames = vmDao.listDistinctHostNames(network.getId());
|
||||||
if (CollectionUtils.isNotEmpty(hostNames) && hostNames.contains(hostName)) {
|
if (CollectionUtils.isNotEmpty(hostNames) && hostNames.contains(hostName)) {
|
||||||
throw new InvalidParameterValueException(String.format("VM with Name [%s] already exists in the network [%s] domain [%s]. Cannot import another VM with the same name. Pleasy try again with a different name.", hostName, network, network.getNetworkDomain()));
|
throw new InvalidParameterValueException(String.format("VM with Name [%s] already exists in the network [%s] domain [%s]. Cannot import another VM with the same name. Please try again with a different name.", hostName, network, network.getNetworkDomain()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1531,17 +1532,30 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
return userVm;
|
return userVm;
|
||||||
}
|
}
|
||||||
|
|
||||||
private UnmanagedInstanceTO cloneSourceVmwareUnmanagedInstance(String vcenter, String datacenterName, String username, String password, String clusterName, String sourceHostName, String sourceVM) {
|
private Pair<UnmanagedInstanceTO, Boolean> getSourceVmwareUnmanagedInstance(String vcenter, String datacenterName, String username,
|
||||||
|
String password, String clusterName, String sourceHostName,
|
||||||
|
String sourceVM) {
|
||||||
HypervisorGuru vmwareGuru = hypervisorGuruManager.getGuru(Hypervisor.HypervisorType.VMware);
|
HypervisorGuru vmwareGuru = hypervisorGuruManager.getGuru(Hypervisor.HypervisorType.VMware);
|
||||||
|
|
||||||
Map<String, String> params = createParamsForTemplateFromVmwareVmMigration(vcenter, datacenterName,
|
Map<String, String> params = createParamsForTemplateFromVmwareVmMigration(vcenter, datacenterName,
|
||||||
username, password, clusterName, sourceHostName, sourceVM);
|
username, password, clusterName, sourceHostName, sourceVM);
|
||||||
|
|
||||||
return vmwareGuru.cloneHypervisorVMOutOfBand(sourceHostName, sourceVM, params);
|
return vmwareGuru.getHypervisorVMOutOfBandAndCloneIfRequired(sourceHostName, sourceVM, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createOvfTemplateOfSourceVmwareUnmanagedInstance(String vcenter, String datacenterName, String username,
|
||||||
|
String password, String clusterName, String sourceHostName,
|
||||||
|
String sourceVMwareInstanceName, DataStoreTO convertLocation, int threadsCountToExportOvf) {
|
||||||
|
HypervisorGuru vmwareGuru = hypervisorGuruManager.getGuru(Hypervisor.HypervisorType.VMware);
|
||||||
|
|
||||||
|
Map<String, String> params = createParamsForTemplateFromVmwareVmMigration(vcenter, datacenterName,
|
||||||
|
username, password, clusterName, sourceHostName, sourceVMwareInstanceName);
|
||||||
|
|
||||||
|
return vmwareGuru.createVMTemplateOutOfBand(sourceHostName, sourceVMwareInstanceName, params, convertLocation, threadsCountToExportOvf);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster destinationCluster, VMTemplateVO template,
|
protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster destinationCluster, VMTemplateVO template,
|
||||||
String sourceVM, String displayName, String hostName,
|
String sourceVMName, String displayName, String hostName,
|
||||||
Account caller, Account owner, long userId,
|
Account caller, Account owner, long userId,
|
||||||
ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap,
|
ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap,
|
||||||
Map<String, Long> nicNetworkMap, Map<String, Network.IpAddresses> nicIpAddressMap,
|
Map<String, Long> nicNetworkMap, Map<String, Network.IpAddresses> nicIpAddressMap,
|
||||||
@ -1568,7 +1582,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
if (existingVcenterId != null) {
|
if (existingVcenterId != null) {
|
||||||
VmwareDatacenterVO existingDC = vmwareDatacenterDao.findById(existingVcenterId);
|
VmwareDatacenterVO existingDC = vmwareDatacenterDao.findById(existingVcenterId);
|
||||||
if (existingDC == null) {
|
if (existingDC == null) {
|
||||||
String err = String.format("Cannot find any existing Vmware DC with ID %s", existingVcenterId);
|
String err = String.format("Cannot find any existing VMware DC with ID %s", existingVcenterId);
|
||||||
LOGGER.error(err);
|
LOGGER.error(err);
|
||||||
throw new CloudRuntimeException(err);
|
throw new CloudRuntimeException(err);
|
||||||
}
|
}
|
||||||
@ -1578,21 +1592,52 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
password = existingDC.getPassword();
|
password = existingDC.getPassword();
|
||||||
}
|
}
|
||||||
|
|
||||||
UnmanagedInstanceTO clonedInstance = null;
|
boolean isClonedInstance = false;
|
||||||
|
UnmanagedInstanceTO sourceVMwareInstance = null;
|
||||||
|
DataStoreTO temporaryConvertLocation = null;
|
||||||
|
String ovfTemplateOnConvertLocation = null;
|
||||||
try {
|
try {
|
||||||
|
HostVO convertHost = selectInstanceConversionKVMHostInCluster(destinationCluster, convertInstanceHostId);
|
||||||
|
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);
|
||||||
|
List<StoragePoolVO> convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster);
|
||||||
|
long importStartTime = System.currentTimeMillis();
|
||||||
|
Pair<UnmanagedInstanceTO, Boolean> sourceInstanceDetails = getSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password, clusterName, sourceHostName, sourceVMName);
|
||||||
|
sourceVMwareInstance = sourceInstanceDetails.first();
|
||||||
|
isClonedInstance = sourceInstanceDetails.second();
|
||||||
|
boolean isWindowsVm = sourceVMwareInstance.getOperatingSystem().toLowerCase().contains("windows");
|
||||||
|
if (isWindowsVm) {
|
||||||
|
checkConversionSupportOnHost(convertHost, sourceVMName, true);
|
||||||
|
}
|
||||||
|
|
||||||
String instanceName = getGeneratedInstanceName(owner);
|
String instanceName = getGeneratedInstanceName(owner);
|
||||||
clonedInstance = cloneSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password,
|
checkNetworkingBeforeConvertingVmwareInstance(zone, owner, instanceName, hostName, sourceVMwareInstance, nicNetworkMap, nicIpAddressMap, forced);
|
||||||
clusterName, sourceHostName, sourceVM);
|
UnmanagedInstanceTO convertedInstance;
|
||||||
checkNetworkingBeforeConvertingVmwareInstance(zone, owner, instanceName, hostName, clonedInstance, nicNetworkMap, nicIpAddressMap, forced);
|
if (cmd.getForceMsToImportVmFiles() || !conversionSupportAnswer.isOvfExportSupported()) {
|
||||||
UnmanagedInstanceTO convertedInstance = convertVmwareInstanceToKVM(vcenter, datacenterName, clusterName, username, password,
|
// Uses MS for OVF export to temporary conversion location
|
||||||
sourceHostName, clonedInstance, destinationCluster, convertInstanceHostId, convertStoragePoolId);
|
int noOfThreads = UnmanagedVMsManager.ThreadsOnMSToImportVMwareVMFiles.value();
|
||||||
sanitizeConvertedInstance(convertedInstance, clonedInstance);
|
ovfTemplateOnConvertLocation = createOvfTemplateOfSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password,
|
||||||
|
clusterName, sourceHostName, sourceVMwareInstance.getName(), temporaryConvertLocation, noOfThreads);
|
||||||
|
convertedInstance = convertVmwareInstanceToKVMWithOVFOnConvertLocation(sourceVMName, sourceVMwareInstance, convertHost, convertStoragePools,
|
||||||
|
temporaryConvertLocation, ovfTemplateOnConvertLocation);
|
||||||
|
} else {
|
||||||
|
// Uses KVM Host for OVF export to temporary conversion location, through ovftool
|
||||||
|
convertedInstance = convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(sourceVMName, sourceVMwareInstance, convertHost, convertStoragePools,
|
||||||
|
temporaryConvertLocation, vcenter, username, password, datacenterName);
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitizeConvertedInstance(convertedInstance, sourceVMwareInstance);
|
||||||
UserVm userVm = importVirtualMachineInternal(convertedInstance, instanceName, zone, destinationCluster, null,
|
UserVm userVm = importVirtualMachineInternal(convertedInstance, instanceName, zone, destinationCluster, null,
|
||||||
template, displayName, hostName, caller, owner, userId,
|
template, displayName, hostName, caller, owner, userId,
|
||||||
serviceOffering, dataDiskOfferingMap,
|
serviceOffering, dataDiskOfferingMap,
|
||||||
nicNetworkMap, nicIpAddressMap,
|
nicNetworkMap, nicIpAddressMap,
|
||||||
details, false, forced, false);
|
details, false, forced, false);
|
||||||
LOGGER.debug(String.format("VM %s imported successfully", sourceVM));
|
long timeElapsedInSecs = (System.currentTimeMillis() - importStartTime) / 1000;
|
||||||
|
LOGGER.debug(String.format("VMware VM %s imported successfully to CloudStack instance %s (%s), Time taken: %d secs, OVF files imported from %s, Source VMware VM details - OS: %s, PowerState: %s, Disks: %s, NICs: %s",
|
||||||
|
sourceVMName, instanceName, displayName, timeElapsedInSecs, (ovfTemplateOnConvertLocation != null)? "MS" : "KVM Host", sourceVMwareInstance.getOperatingSystem(), sourceVMwareInstance.getPowerState(), sourceVMwareInstance.getDisks(), sourceVMwareInstance.getNics()));
|
||||||
return userVm;
|
return userVm;
|
||||||
} catch (CloudRuntimeException e) {
|
} catch (CloudRuntimeException e) {
|
||||||
LOGGER.error(String.format("Error importing VM: %s", e.getMessage()), e);
|
LOGGER.error(String.format("Error importing VM: %s", e.getMessage()), e);
|
||||||
@ -1600,20 +1645,25 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
cmd.getEventDescription(), null, null, 0);
|
cmd.getEventDescription(), null, null, 0);
|
||||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
|
||||||
} finally {
|
} finally {
|
||||||
removeClonedInstance(vcenter, datacenterName, username, password, sourceHostName, clonedInstance.getName(), sourceVM);
|
if (isClonedInstance && sourceVMwareInstance != null) {
|
||||||
|
removeClonedInstance(vcenter, datacenterName, username, password, sourceHostName, sourceVMwareInstance.getName(), sourceVMName);
|
||||||
|
}
|
||||||
|
if (temporaryConvertLocation != null && StringUtils.isNotBlank(ovfTemplateOnConvertLocation)) {
|
||||||
|
removeTemplate(temporaryConvertLocation, ovfTemplateOnConvertLocation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkNetworkingBeforeConvertingVmwareInstance(DataCenter zone, Account owner, String instanceName,
|
private void checkNetworkingBeforeConvertingVmwareInstance(DataCenter zone, Account owner, String instanceName,
|
||||||
String hostName, UnmanagedInstanceTO clonedInstance,
|
String hostName, UnmanagedInstanceTO sourceVMwareInstance,
|
||||||
Map<String, Long> nicNetworkMap,
|
Map<String, Long> nicNetworkMap,
|
||||||
Map<String, Network.IpAddresses> nicIpAddressMap,
|
Map<String, Network.IpAddresses> nicIpAddressMap,
|
||||||
boolean forced) {
|
boolean forced) {
|
||||||
List<UnmanagedInstanceTO.Nic> nics = clonedInstance.getNics();
|
List<UnmanagedInstanceTO.Nic> nics = sourceVMwareInstance.getNics();
|
||||||
List<Long> networkIds = new ArrayList<>(nicNetworkMap.values());
|
List<Long> networkIds = new ArrayList<>(nicNetworkMap.values());
|
||||||
if (nics.size() != networkIds.size()) {
|
if (nics.size() != networkIds.size()) {
|
||||||
String msg = String.format("Different number of nics found on instance %s: %s vs %s nics provided",
|
String msg = String.format("Different number of nics found on instance %s: %s vs %s nics provided",
|
||||||
clonedInstance.getName(), nics.size(), networkIds.size());
|
sourceVMwareInstance.getName(), nics.size(), networkIds.size());
|
||||||
LOGGER.error(msg);
|
LOGGER.error(msg);
|
||||||
throw new CloudRuntimeException(msg);
|
throw new CloudRuntimeException(msg);
|
||||||
}
|
}
|
||||||
@ -1641,8 +1691,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
private void checkUnmanagedNicAndNetworkMacAddressForImport(NetworkVO network, UnmanagedInstanceTO.Nic nic, boolean forced) {
|
private void checkUnmanagedNicAndNetworkMacAddressForImport(NetworkVO network, UnmanagedInstanceTO.Nic nic, boolean forced) {
|
||||||
NicVO existingNic = nicDao.findByNetworkIdAndMacAddress(network.getId(), nic.getMacAddress());
|
NicVO existingNic = nicDao.findByNetworkIdAndMacAddress(network.getId(), nic.getMacAddress());
|
||||||
if (existingNic != null && !forced) {
|
if (existingNic != null && !forced) {
|
||||||
String err = String.format("NIC with MAC address = %s exists on network with ID = %s and forced flag is disabled",
|
String err = String.format("NIC with MAC address %s already exists on network with ID %s and forced flag is disabled. " +
|
||||||
nic.getMacAddress(), network.getId());
|
"Retry with forced flag enabled if a new MAC address to be generated.", nic.getMacAddress(), network.getUuid());
|
||||||
LOGGER.error(err);
|
LOGGER.error(err);
|
||||||
throw new CloudRuntimeException(err);
|
throw new CloudRuntimeException(err);
|
||||||
}
|
}
|
||||||
@ -1657,38 +1707,44 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
return VirtualMachineName.getVmName(id, owner.getId(), instanceSuffix);
|
return VirtualMachineName.getVmName(id, owner.getId(), instanceSuffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sanitizeConvertedInstance(UnmanagedInstanceTO convertedInstance, UnmanagedInstanceTO clonedInstance) {
|
private void sanitizeConvertedInstance(UnmanagedInstanceTO convertedInstance, UnmanagedInstanceTO sourceVMwareInstance) {
|
||||||
convertedInstance.setCpuCores(clonedInstance.getCpuCores());
|
convertedInstance.setCpuCores(sourceVMwareInstance.getCpuCores());
|
||||||
convertedInstance.setCpuSpeed(clonedInstance.getCpuSpeed());
|
convertedInstance.setCpuSpeed(sourceVMwareInstance.getCpuSpeed());
|
||||||
convertedInstance.setCpuCoresPerSocket(clonedInstance.getCpuCoresPerSocket());
|
convertedInstance.setCpuCoresPerSocket(sourceVMwareInstance.getCpuCoresPerSocket());
|
||||||
convertedInstance.setMemory(clonedInstance.getMemory());
|
convertedInstance.setMemory(sourceVMwareInstance.getMemory());
|
||||||
convertedInstance.setPowerState(UnmanagedInstanceTO.PowerState.PowerOff);
|
convertedInstance.setPowerState(UnmanagedInstanceTO.PowerState.PowerOff);
|
||||||
List<UnmanagedInstanceTO.Disk> convertedInstanceDisks = convertedInstance.getDisks();
|
List<UnmanagedInstanceTO.Disk> convertedInstanceDisks = convertedInstance.getDisks();
|
||||||
List<UnmanagedInstanceTO.Disk> clonedInstanceDisks = clonedInstance.getDisks();
|
List<UnmanagedInstanceTO.Disk> sourceVMwareInstanceDisks = sourceVMwareInstance.getDisks();
|
||||||
for (int i = 0; i < convertedInstanceDisks.size(); i++) {
|
for (int i = 0; i < convertedInstanceDisks.size(); i++) {
|
||||||
UnmanagedInstanceTO.Disk disk = convertedInstanceDisks.get(i);
|
UnmanagedInstanceTO.Disk disk = convertedInstanceDisks.get(i);
|
||||||
disk.setDiskId(clonedInstanceDisks.get(i).getDiskId());
|
disk.setDiskId(sourceVMwareInstanceDisks.get(i).getDiskId());
|
||||||
}
|
}
|
||||||
List<UnmanagedInstanceTO.Nic> convertedInstanceNics = convertedInstance.getNics();
|
List<UnmanagedInstanceTO.Nic> convertedInstanceNics = convertedInstance.getNics();
|
||||||
List<UnmanagedInstanceTO.Nic> clonedInstanceNics = clonedInstance.getNics();
|
List<UnmanagedInstanceTO.Nic> sourceVMwareInstanceNics = sourceVMwareInstance.getNics();
|
||||||
if (CollectionUtils.isEmpty(convertedInstanceNics) && CollectionUtils.isNotEmpty(clonedInstanceNics)) {
|
if (CollectionUtils.isEmpty(convertedInstanceNics) && CollectionUtils.isNotEmpty(sourceVMwareInstanceNics)) {
|
||||||
for (UnmanagedInstanceTO.Nic nic : clonedInstanceNics) {
|
for (UnmanagedInstanceTO.Nic nic : sourceVMwareInstanceNics) {
|
||||||
// In case the NICs information is not parsed from the converted XML domain, use the cloned instance NICs with virtio adapter
|
// In case the NICs information is not parsed from the converted XML domain, use the cloned instance NICs with virtio adapter
|
||||||
nic.setAdapterType("virtio");
|
nic.setAdapterType("virtio");
|
||||||
}
|
}
|
||||||
convertedInstance.setNics(clonedInstanceNics);
|
convertedInstance.setNics(sourceVMwareInstanceNics);
|
||||||
} else {
|
|
||||||
for (int i = 0; i < convertedInstanceNics.size(); i++) {
|
for (int i = 0; i < convertedInstanceNics.size(); i++) {
|
||||||
UnmanagedInstanceTO.Nic nic = convertedInstanceNics.get(i);
|
UnmanagedInstanceTO.Nic nic = convertedInstanceNics.get(i);
|
||||||
nic.setNicId(clonedInstanceNics.get(i).getNicId());
|
nic.setNicId(sourceVMwareInstanceNics.get(i).getNicId());
|
||||||
|
}
|
||||||
|
} else if (CollectionUtils.isNotEmpty(convertedInstanceNics) && CollectionUtils.isNotEmpty(sourceVMwareInstanceNics)
|
||||||
|
&& convertedInstanceNics.size() == sourceVMwareInstanceNics.size()) {
|
||||||
|
for (int i = 0; i < convertedInstanceNics.size(); i++) {
|
||||||
|
UnmanagedInstanceTO.Nic nic = convertedInstanceNics.get(i);
|
||||||
|
nic.setNicId(sourceVMwareInstanceNics.get(i).getNicId());
|
||||||
|
if (nic.getMacAddress() == null) {
|
||||||
|
nic.setMacAddress(sourceVMwareInstanceNics.get(i).getMacAddress());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeClonedInstance(String vcenter, String datacenterName,
|
private void removeClonedInstance(String vcenter, String datacenterName, String username, String password,
|
||||||
String username, String password,
|
String sourceHostName, String clonedInstanceName, String sourceVM) {
|
||||||
String sourceHostName, String clonedInstanceName,
|
|
||||||
String sourceVM) {
|
|
||||||
HypervisorGuru vmwareGuru = hypervisorGuruManager.getGuru(Hypervisor.HypervisorType.VMware);
|
HypervisorGuru vmwareGuru = hypervisorGuruManager.getGuru(Hypervisor.HypervisorType.VMware);
|
||||||
Map<String, String> params = createParamsForRemoveClonedInstance(vcenter, datacenterName, username, password, sourceVM);
|
Map<String, String> params = createParamsForRemoveClonedInstance(vcenter, datacenterName, username, password, sourceVM);
|
||||||
boolean result = vmwareGuru.removeClonedHypervisorVMOutOfBand(sourceHostName, clonedInstanceName, params);
|
boolean result = vmwareGuru.removeClonedHypervisorVMOutOfBand(sourceHostName, clonedInstanceName, params);
|
||||||
@ -1698,10 +1754,23 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
LOGGER.warn(msg);
|
LOGGER.warn(msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LOGGER.debug(String.format("Removed the cloned instance %s from VMWare datacenter %s:%s",
|
LOGGER.debug(String.format("Removed the cloned instance %s from VMWare datacenter %s/%s",
|
||||||
clonedInstanceName, vcenter, datacenterName));
|
clonedInstanceName, vcenter, datacenterName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void removeTemplate(DataStoreTO convertLocation, String ovfTemplateOnConvertLocation) {
|
||||||
|
HypervisorGuru vmwareGuru = hypervisorGuruManager.getGuru(Hypervisor.HypervisorType.VMware);
|
||||||
|
boolean result = vmwareGuru.removeVMTemplateOutOfBand(convertLocation, ovfTemplateOnConvertLocation);
|
||||||
|
if (!result) {
|
||||||
|
String msg = String.format("Could not remove the template file %s on datastore %s",
|
||||||
|
ovfTemplateOnConvertLocation, convertLocation.getUrl());
|
||||||
|
LOGGER.warn(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOGGER.debug(String.format("Removed the template file %s on datastore %s",
|
||||||
|
ovfTemplateOnConvertLocation, convertLocation.getUrl()));
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, String> createParamsForRemoveClonedInstance(String vcenter, String datacenterName, String username,
|
private Map<String, String> createParamsForRemoveClonedInstance(String vcenter, String datacenterName, String username,
|
||||||
String password, String sourceVM) {
|
String password, String sourceVM) {
|
||||||
Map<String, String> params = new HashMap<>();
|
Map<String, String> params = new HashMap<>();
|
||||||
@ -1712,7 +1781,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
private HostVO selectInstanceConvertionKVMHostInCluster(Cluster destinationCluster, Long convertInstanceHostId) {
|
private HostVO selectInstanceConversionKVMHostInCluster(Cluster destinationCluster, Long convertInstanceHostId) {
|
||||||
if (convertInstanceHostId != null) {
|
if (convertInstanceHostId != null) {
|
||||||
HostVO selectedHost = hostDao.findById(convertInstanceHostId);
|
HostVO selectedHost = hostDao.findById(convertInstanceHostId);
|
||||||
if (selectedHost == null) {
|
if (selectedHost == null) {
|
||||||
@ -1729,41 +1798,62 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
}
|
}
|
||||||
return selectedHost;
|
return selectedHost;
|
||||||
}
|
}
|
||||||
List<HostVO> hosts = hostDao.listByClusterAndHypervisorType(destinationCluster.getId(), destinationCluster.getHypervisorType());
|
|
||||||
if (CollectionUtils.isEmpty(hosts)) {
|
// Auto select host with conversion capability
|
||||||
String err = String.format("Could not find any running %s host in cluster %s",
|
List<HostVO> hosts = hostDao.listByClusterHypervisorTypeAndHostCapability(destinationCluster.getId(), destinationCluster.getHypervisorType(), Host.HOST_INSTANCE_CONVERSION);
|
||||||
destinationCluster.getHypervisorType(), destinationCluster.getName());
|
if (CollectionUtils.isNotEmpty(hosts)) {
|
||||||
LOGGER.error(err);
|
return hosts.get(new Random().nextInt(hosts.size()));
|
||||||
throw new CloudRuntimeException(err);
|
|
||||||
}
|
}
|
||||||
List<HostVO> filteredHosts = hosts.stream()
|
|
||||||
.filter(x -> x.getResourceState() == ResourceState.Enabled)
|
// Try without host capability check
|
||||||
.collect(Collectors.toList());
|
hosts = hostDao.listByClusterAndHypervisorType(destinationCluster.getId(), destinationCluster.getHypervisorType());
|
||||||
if (CollectionUtils.isEmpty(filteredHosts)) {
|
if (CollectionUtils.isNotEmpty(hosts)) {
|
||||||
String err = String.format("Could not find a %s host in cluster %s to perform the instance conversion",
|
return hosts.get(new Random().nextInt(hosts.size()));
|
||||||
destinationCluster.getHypervisorType(), destinationCluster.getName());
|
|
||||||
LOGGER.error(err);
|
|
||||||
throw new CloudRuntimeException(err);
|
|
||||||
}
|
}
|
||||||
return filteredHosts.get(new Random().nextInt(filteredHosts.size()));
|
|
||||||
|
String err = String.format("Could not find any suitable %s host in cluster %s to perform the instance conversion",
|
||||||
|
destinationCluster.getHypervisorType(), destinationCluster.getName());
|
||||||
|
LOGGER.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
private UnmanagedInstanceTO convertVmwareInstanceToKVM(String vcenter, String datacenterName, String clusterName,
|
private CheckConvertInstanceAnswer checkConversionSupportOnHost(HostVO convertHost, String sourceVM, boolean checkWindowsGuestConversionSupport) {
|
||||||
String username, String password, String hostName,
|
LOGGER.debug(String.format("Checking the %s conversion support on the host %s (%s)", checkWindowsGuestConversionSupport? "windows guest" : "", convertHost.getId(), convertHost.getName()));
|
||||||
UnmanagedInstanceTO clonedInstance, Cluster destinationCluster,
|
CheckConvertInstanceCommand cmd = new CheckConvertInstanceCommand(checkWindowsGuestConversionSupport);
|
||||||
Long convertInstanceHostId, Long convertStoragePoolId) {
|
int timeoutSeconds = 60;
|
||||||
HostVO convertHost = selectInstanceConvertionKVMHostInCluster(destinationCluster, convertInstanceHostId);
|
cmd.setWait(timeoutSeconds);
|
||||||
String vmName = clonedInstance.getName();
|
|
||||||
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(), vmName));
|
|
||||||
|
|
||||||
RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(hostName, vmName,
|
CheckConvertInstanceAnswer checkConvertInstanceAnswer;
|
||||||
vcenter, datacenterName, clusterName, username, password);
|
try {
|
||||||
DataStoreTO temporaryConvertLocation = selectInstanceConversionTemporaryLocation(destinationCluster, convertStoragePoolId, convertHost);
|
checkConvertInstanceAnswer = (CheckConvertInstanceAnswer) agentManager.send(convertHost.getId(), cmd);
|
||||||
List<String> destinationStoragePools = selectInstanceConvertionStoragePools(destinationCluster, clonedInstance.getDisks());
|
} catch (AgentUnavailableException | OperationTimedoutException e) {
|
||||||
|
String err = String.format("Failed to check %s conversion support on the host %s for converting instance %s from VMware to KVM due to: %s",
|
||||||
|
checkWindowsGuestConversionSupport? "windows guest" : "", convertHost.getName(), sourceVM, e.getMessage());
|
||||||
|
LOGGER.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!checkConvertInstanceAnswer.getResult()) {
|
||||||
|
String err = String.format("The host %s doesn't support conversion of instance %s from VMware to KVM due to: %s",
|
||||||
|
convertHost.getName(), sourceVM, checkConvertInstanceAnswer.getDetails());
|
||||||
|
LOGGER.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return checkConvertInstanceAnswer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UnmanagedInstanceTO convertVmwareInstanceToKVMWithOVFOnConvertLocation(String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost,
|
||||||
|
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,
|
ConvertInstanceCommand cmd = new ConvertInstanceCommand(remoteInstanceTO,
|
||||||
Hypervisor.HypervisorType.KVM, destinationStoragePools, temporaryConvertLocation);
|
Hypervisor.HypervisorType.KVM, destinationStoragePools, temporaryConvertLocation, ovfTemplateDirConvertLocation, false, false);
|
||||||
int timeoutSeconds = StorageManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60;
|
int timeoutSeconds = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60;
|
||||||
cmd.setWait(timeoutSeconds);
|
cmd.setWait(timeoutSeconds);
|
||||||
|
|
||||||
Answer convertAnswer;
|
Answer convertAnswer;
|
||||||
@ -1777,17 +1867,68 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!convertAnswer.getResult()) {
|
if (!convertAnswer.getResult()) {
|
||||||
String err = String.format("The convert process failed for instance %s from Vmware to KVM on host %s: %s",
|
String err = String.format("The convert process failed for instance %s from VMware to KVM on host %s: %s",
|
||||||
vmName, convertHost.getName(), convertAnswer.getDetails());
|
sourceVM, convertHost.getName(), convertAnswer.getDetails());
|
||||||
LOGGER.error(err);
|
LOGGER.error(err);
|
||||||
throw new CloudRuntimeException(err);
|
throw new CloudRuntimeException(err);
|
||||||
}
|
}
|
||||||
return ((ConvertInstanceAnswer) convertAnswer).getConvertedInstance();
|
return ((ConvertInstanceAnswer) convertAnswer).getConvertedInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> selectInstanceConvertionStoragePools(Cluster destinationCluster, List<UnmanagedInstanceTO.Disk> disks) {
|
private UnmanagedInstanceTO convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost,
|
||||||
|
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);
|
||||||
|
int timeoutSeconds = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60;
|
||||||
|
cmd.setWait(timeoutSeconds);
|
||||||
|
int noOfThreads = UnmanagedVMsManager.ThreadsOnKVMHostToImportVMwareVMFiles.value();
|
||||||
|
if (noOfThreads == 0) {
|
||||||
|
// Use no. of threads as the disks count
|
||||||
|
noOfThreads = sourceVMwareInstance.getDisks().size();
|
||||||
|
}
|
||||||
|
cmd.setThreadsCountToExportOvf(noOfThreads);
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<StoragePoolVO> findInstanceConversionStoragePoolsInCluster(Cluster destinationCluster) {
|
||||||
|
List<StoragePoolVO> pools = new ArrayList<>();
|
||||||
|
List<StoragePoolVO> clusterPools = primaryDataStoreDao.findClusterWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem);
|
||||||
|
pools.addAll(clusterPools);
|
||||||
|
List<StoragePoolVO> zonePools = primaryDataStoreDao.findZoneWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getDataCenterId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem);
|
||||||
|
pools.addAll(zonePools);
|
||||||
|
if (pools.isEmpty()) {
|
||||||
|
String msg = String.format("Cannot find suitable storage pools in cluster %s for the conversion", destinationCluster.getName());
|
||||||
|
LOGGER.error(msg);
|
||||||
|
throw new CloudRuntimeException(msg);
|
||||||
|
}
|
||||||
|
return pools;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> selectInstanceConversionStoragePools(List<StoragePoolVO> pools, List<UnmanagedInstanceTO.Disk> disks) {
|
||||||
List<String> storagePools = new ArrayList<>(disks.size());
|
List<String> storagePools = new ArrayList<>(disks.size());
|
||||||
List<StoragePoolVO> pools = primaryDataStoreDao.listPoolsByCluster(destinationCluster.getId());
|
|
||||||
//TODO: Choose pools by capacity
|
//TODO: Choose pools by capacity
|
||||||
for (UnmanagedInstanceTO.Disk disk : disks) {
|
for (UnmanagedInstanceTO.Disk disk : disks) {
|
||||||
Long capacity = disk.getCapacity();
|
Long capacity = disk.getCapacity();
|
||||||
@ -1801,7 +1942,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
throw new CloudRuntimeException(msg);
|
throw new CloudRuntimeException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DataStoreTO selectInstanceConversionTemporaryLocation(Cluster destinationCluster, Long convertStoragePoolId, HostVO convertHost) {
|
protected DataStoreTO selectInstanceConversionTemporaryLocation(Cluster destinationCluster, Long convertStoragePoolId) {
|
||||||
if (convertStoragePoolId != null) {
|
if (convertStoragePoolId != null) {
|
||||||
StoragePoolVO selectedStoragePool = primaryDataStoreDao.findById(convertStoragePoolId);
|
StoragePoolVO selectedStoragePool = primaryDataStoreDao.findById(convertStoragePoolId);
|
||||||
if (selectedStoragePool == null) {
|
if (selectedStoragePool == null) {
|
||||||
@ -1812,11 +1953,10 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
logFailureAndThrowException(String.format("Cannot use the storage pool %s for the instance conversion as " +
|
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()));
|
"it is not in the scope of the cluster %s", selectedStoragePool.getName(), destinationCluster.getName()));
|
||||||
}
|
}
|
||||||
if (selectedStoragePool.getScope() == ScopeType.HOST &&
|
if (selectedStoragePool.getScope() == ScopeType.HOST) {
|
||||||
storagePoolHostDao.findByPoolHost(selectedStoragePool.getId(), convertHost.getId()) == null) {
|
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()));
|
||||||
logFailureAndThrowException(String.format("The storage pool %s is not a local storage pool for the host %s", selectedStoragePool.getName(), convertHost.getName()));
|
|
||||||
} else if (selectedStoragePool.getPoolType() != Storage.StoragePoolType.NetworkFilesystem) {
|
} else if (selectedStoragePool.getPoolType() != Storage.StoragePoolType.NetworkFilesystem) {
|
||||||
logFailureAndThrowException(String.format("The storage pool %s is not supported for temporary conversion location, supported pools are NFS storage pools", selectedStoragePool.getName()));
|
logFailureAndThrowException(String.format("The storage pool %s is not supported for temporary conversion location, only NFS storage pools are supported", selectedStoragePool.getName()));
|
||||||
}
|
}
|
||||||
return dataStoreManager.getPrimaryDataStore(convertStoragePoolId).getTO();
|
return dataStoreManager.getPrimaryDataStore(convertStoragePoolId).getTO();
|
||||||
} else {
|
} else {
|
||||||
@ -2505,7 +2645,10 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
public ConfigKey<?>[] getConfigKeys() {
|
public ConfigKey<?>[] getConfigKeys() {
|
||||||
return new ConfigKey<?>[]{
|
return new ConfigKey<?>[]{
|
||||||
UnmanageVMPreserveNic,
|
UnmanageVMPreserveNic,
|
||||||
RemoteKvmInstanceDisksCopyTimeout
|
RemoteKvmInstanceDisksCopyTimeout,
|
||||||
|
ConvertVmwareInstanceToKvmTimeout,
|
||||||
|
ThreadsOnMSToImportVMwareVMFiles,
|
||||||
|
ThreadsOnKVMHostToImportVMwareVMFiles
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,9 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.configuration;
|
package com.cloud.configuration;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.cloud.exception.InvalidParameterValueException;
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
import com.cloud.storage.StorageManager;
|
import com.cloud.storage.StorageManager;
|
||||||
import com.cloud.utils.net.NetUtils;
|
import com.cloud.utils.net.NetUtils;
|
||||||
@ -31,8 +34,11 @@ import com.cloud.user.User;
|
|||||||
import com.cloud.utils.db.EntityManager;
|
import com.cloud.utils.db.EntityManager;
|
||||||
import com.cloud.utils.db.SearchCriteria;
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
import org.apache.cloudstack.api.command.admin.offering.UpdateDiskOfferingCmd;
|
import org.apache.cloudstack.api.command.admin.offering.UpdateDiskOfferingCmd;
|
||||||
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
|
import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
|
||||||
import org.apache.cloudstack.resourcedetail.DiskOfferingDetailVO;
|
import org.apache.cloudstack.resourcedetail.DiskOfferingDetailVO;
|
||||||
import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao;
|
import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao;
|
||||||
|
import org.apache.cloudstack.vm.UnmanagedVMsManager;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -47,7 +53,6 @@ import org.mockito.Spy;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class ConfigurationManagerImplTest {
|
public class ConfigurationManagerImplTest {
|
||||||
@Mock
|
@Mock
|
||||||
@ -65,6 +70,8 @@ public class ConfigurationManagerImplTest {
|
|||||||
@Mock
|
@Mock
|
||||||
Domain domainMock;
|
Domain domainMock;
|
||||||
@Mock
|
@Mock
|
||||||
|
ConfigurationDao configDaoMock;
|
||||||
|
@Mock
|
||||||
DataCenterDao zoneDaoMock;
|
DataCenterDao zoneDaoMock;
|
||||||
@Mock
|
@Mock
|
||||||
DomainDao domainDaoMock;
|
DomainDao domainDaoMock;
|
||||||
@ -300,6 +307,66 @@ public class ConfigurationManagerImplTest {
|
|||||||
configurationManagerImplSpy.validateIpAddressRelatedConfigValues("config.iprange", "192.168.1.1-192.168.1.100");
|
configurationManagerImplSpy.validateIpAddressRelatedConfigValues("config.iprange", "192.168.1.1-192.168.1.100");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateInvalidConfiguration() {
|
||||||
|
Mockito.doReturn(null).when(configDaoMock).findByName(Mockito.anyString());
|
||||||
|
String msg = configurationManagerImplSpy.validateConfigurationValue("test.config.name", "testvalue", ConfigKey.Scope.Global.toString());
|
||||||
|
Assert.assertEquals("Invalid configuration variable.", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateInvalidScopeForConfiguration() {
|
||||||
|
ConfigurationVO cfg = mock(ConfigurationVO.class);
|
||||||
|
when(cfg.getScope()).thenReturn(ConfigKey.Scope.Account.toString());
|
||||||
|
Mockito.doReturn(cfg).when(configDaoMock).findByName(Mockito.anyString());
|
||||||
|
String msg = configurationManagerImplSpy.validateConfigurationValue("test.config.name", "testvalue", ConfigKey.Scope.Domain.toString());
|
||||||
|
Assert.assertEquals("Invalid scope id provided for the parameter test.config.name", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateConfig_ThreadsOnKVMHostToTransferVMwareVMFiles_Failure() {
|
||||||
|
ConfigurationVO cfg = mock(ConfigurationVO.class);
|
||||||
|
when(cfg.getScope()).thenReturn(ConfigKey.Scope.Global.toString());
|
||||||
|
ConfigKey<Integer> configKey = UnmanagedVMsManager.ThreadsOnKVMHostToImportVMwareVMFiles;
|
||||||
|
Mockito.doReturn(cfg).when(configDaoMock).findByName(Mockito.anyString());
|
||||||
|
Mockito.doReturn(configKey).when(configurationManagerImplSpy._configDepot).get(configKey.key());
|
||||||
|
configurationManagerImplSpy.validateConfigurationValue(configKey.key(), "11", configKey.scope().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateConfig_ThreadsOnKVMHostToTransferVMwareVMFiles_Success() {
|
||||||
|
ConfigurationVO cfg = mock(ConfigurationVO.class);
|
||||||
|
when(cfg.getScope()).thenReturn(ConfigKey.Scope.Global.toString());
|
||||||
|
ConfigKey<Integer> configKey = UnmanagedVMsManager.ThreadsOnKVMHostToImportVMwareVMFiles;
|
||||||
|
Mockito.doReturn(cfg).when(configDaoMock).findByName(Mockito.anyString());
|
||||||
|
Mockito.doReturn(configKey).when(configurationManagerImplSpy._configDepot).get(configKey.key());
|
||||||
|
String msg = configurationManagerImplSpy.validateConfigurationValue(configKey.key(), "10", configKey.scope().toString());
|
||||||
|
Assert.assertNull(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateConfig_ConvertVmwareInstanceToKvmTimeout_Failure() {
|
||||||
|
ConfigurationVO cfg = mock(ConfigurationVO.class);
|
||||||
|
when(cfg.getScope()).thenReturn(ConfigKey.Scope.Global.toString());
|
||||||
|
ConfigKey<Integer> configKey = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout;
|
||||||
|
Mockito.doReturn(cfg).when(configDaoMock).findByName(Mockito.anyString());
|
||||||
|
Mockito.doReturn(configKey).when(configurationManagerImplSpy._configDepot).get(configKey.key());
|
||||||
|
configurationManagerImplSpy.populateConfigValuesForValidationSet();
|
||||||
|
configurationManagerImplSpy.validateConfigurationValue(configKey.key(), "0", configKey.scope().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateConfig_ConvertVmwareInstanceToKvmTimeout_Success() {
|
||||||
|
ConfigurationVO cfg = mock(ConfigurationVO.class);
|
||||||
|
when(cfg.getScope()).thenReturn(ConfigKey.Scope.Global.toString());
|
||||||
|
ConfigKey<Integer> configKey = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout;
|
||||||
|
Mockito.doReturn(cfg).when(configDaoMock).findByName(Mockito.anyString());
|
||||||
|
Mockito.doReturn(configKey).when(configurationManagerImplSpy._configDepot).get(configKey.key());
|
||||||
|
configurationManagerImplSpy.populateConfigValuesForValidationSet();
|
||||||
|
String msg = configurationManagerImplSpy.validateConfigurationValue(configKey.key(), "9", configKey.scope().toString());
|
||||||
|
Assert.assertNull(msg);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void validateDomainTestInvalidIdThrowException() {
|
public void validateDomainTestInvalidIdThrowException() {
|
||||||
Mockito.doReturn(null).when(domainDaoMock).findById(invalidId);
|
Mockito.doReturn(null).when(domainDaoMock).findById(invalidId);
|
||||||
|
|||||||
@ -19,6 +19,8 @@ package org.apache.cloudstack.vm;
|
|||||||
|
|
||||||
import com.cloud.agent.AgentManager;
|
import com.cloud.agent.AgentManager;
|
||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.agent.api.CheckConvertInstanceAnswer;
|
||||||
|
import com.cloud.agent.api.CheckConvertInstanceCommand;
|
||||||
import com.cloud.agent.api.CheckVolumeAnswer;
|
import com.cloud.agent.api.CheckVolumeAnswer;
|
||||||
import com.cloud.agent.api.CheckVolumeCommand;
|
import com.cloud.agent.api.CheckVolumeCommand;
|
||||||
import com.cloud.agent.api.ConvertInstanceAnswer;
|
import com.cloud.agent.api.ConvertInstanceAnswer;
|
||||||
@ -147,6 +149,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.ArgumentMatchers.anyMap;
|
import static org.mockito.ArgumentMatchers.anyMap;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
@ -586,6 +589,7 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
String host = "192.168.1.10";
|
String host = "192.168.1.10";
|
||||||
String vmName = "TestInstanceFromVmware";
|
String vmName = "TestInstanceFromVmware";
|
||||||
instance.setName(vmName);
|
instance.setName(vmName);
|
||||||
|
String tmplFileName = "5b8d689a-e61a-4ac3-9b76-e121ff90fbd3";
|
||||||
long newVmId = 2L;
|
long newVmId = 2L;
|
||||||
long networkId = 1L;
|
long networkId = 1L;
|
||||||
when(vmDao.getNextInSequence(Long.class, "id")).thenReturn(newVmId);
|
when(vmDao.getNextInSequence(Long.class, "id")).thenReturn(newVmId);
|
||||||
@ -614,8 +618,10 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
|
|
||||||
HypervisorGuru vmwareGuru = mock(HypervisorGuru.class);
|
HypervisorGuru vmwareGuru = mock(HypervisorGuru.class);
|
||||||
when(hypervisorGuruManager.getGuru(Hypervisor.HypervisorType.VMware)).thenReturn(vmwareGuru);
|
when(hypervisorGuruManager.getGuru(Hypervisor.HypervisorType.VMware)).thenReturn(vmwareGuru);
|
||||||
when(vmwareGuru.cloneHypervisorVMOutOfBand(anyString(), anyString(), anyMap())).thenReturn(instance);
|
when(vmwareGuru.getHypervisorVMOutOfBandAndCloneIfRequired(anyString(), anyString(), anyMap())).thenReturn(new Pair<>(instance, true));
|
||||||
when(vmwareGuru.removeClonedHypervisorVMOutOfBand(anyString(), anyString(), anyMap())).thenReturn(true);
|
when(vmwareGuru.removeClonedHypervisorVMOutOfBand(anyString(), anyString(), anyMap())).thenReturn(true);
|
||||||
|
when(vmwareGuru.createVMTemplateOutOfBand(anyString(), anyString(), anyMap(), any(DataStoreTO.class), anyInt())).thenReturn(tmplFileName);
|
||||||
|
when(vmwareGuru.removeVMTemplateOutOfBand(any(DataStoreTO.class), anyString())).thenReturn(true);
|
||||||
|
|
||||||
HostVO convertHost = mock(HostVO.class);
|
HostVO convertHost = mock(HostVO.class);
|
||||||
long convertHostId = 1L;
|
long convertHostId = 1L;
|
||||||
@ -639,6 +645,7 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
when(destPool.getDataCenterId()).thenReturn(zoneId);
|
when(destPool.getDataCenterId()).thenReturn(zoneId);
|
||||||
when(destPool.getClusterId()).thenReturn(null);
|
when(destPool.getClusterId()).thenReturn(null);
|
||||||
when(destPool.getPoolType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem);
|
when(destPool.getPoolType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem);
|
||||||
|
StoragePoolVO zoneDestPool = mock(StoragePoolVO.class);
|
||||||
if (selectTemporaryStorage) {
|
if (selectTemporaryStorage) {
|
||||||
long temporaryStoragePoolId = 1L;
|
long temporaryStoragePoolId = 1L;
|
||||||
when(importVmCmd.getConvertStoragePoolId()).thenReturn(temporaryStoragePoolId);
|
when(importVmCmd.getConvertStoragePoolId()).thenReturn(temporaryStoragePoolId);
|
||||||
@ -650,8 +657,9 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
when(imageStoreDao.findOneByZoneAndProtocol(zoneId, "nfs")).thenReturn(imageStoreVO);
|
when(imageStoreDao.findOneByZoneAndProtocol(zoneId, "nfs")).thenReturn(imageStoreVO);
|
||||||
when(dataStoreManager.getDataStore(1L, DataStoreRole.Image)).thenReturn(dataStore);
|
when(dataStoreManager.getDataStore(1L, DataStoreRole.Image)).thenReturn(dataStore);
|
||||||
}
|
}
|
||||||
when(primaryDataStoreDao.listPoolsByCluster(clusterId)).thenReturn(List.of(destPool));
|
|
||||||
when(primaryDataStoreDao.listPoolByHostPath(Mockito.anyString(), Mockito.anyString())).thenReturn(List.of(destPool));
|
when(primaryDataStoreDao.listPoolByHostPath(Mockito.anyString(), Mockito.anyString())).thenReturn(List.of(destPool));
|
||||||
|
when(primaryDataStoreDao.findClusterWideStoragePoolsByHypervisorAndPoolType(clusterId, Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem)).thenReturn(List.of(destPool));
|
||||||
|
when(primaryDataStoreDao.findZoneWideStoragePoolsByHypervisorAndPoolType(zoneId, Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem)).thenReturn(List.of(zoneDestPool));
|
||||||
|
|
||||||
if (VcenterParameter.EXISTING == vcenterParameter) {
|
if (VcenterParameter.EXISTING == vcenterParameter) {
|
||||||
VmwareDatacenterVO datacenterVO = mock(VmwareDatacenterVO.class);
|
VmwareDatacenterVO datacenterVO = mock(VmwareDatacenterVO.class);
|
||||||
@ -679,17 +687,25 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
when(vmwareDatacenterDao.findById(existingDatacenterId)).thenReturn(null);
|
when(vmwareDatacenterDao.findById(existingDatacenterId)).thenReturn(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConvertInstanceAnswer answer = mock(ConvertInstanceAnswer.class);
|
CheckConvertInstanceAnswer checkConvertInstanceAnswer = mock(CheckConvertInstanceAnswer.class);
|
||||||
when(answer.getResult()).thenReturn(vcenterParameter != VcenterParameter.CONVERT_FAILURE);
|
when(checkConvertInstanceAnswer.getResult()).thenReturn(vcenterParameter != VcenterParameter.CONVERT_FAILURE);
|
||||||
when(answer.getConvertedInstance()).thenReturn(instance);
|
|
||||||
if (VcenterParameter.AGENT_UNAVAILABLE != vcenterParameter) {
|
if (VcenterParameter.AGENT_UNAVAILABLE != vcenterParameter) {
|
||||||
when(agentManager.send(Mockito.eq(convertHostId), Mockito.any(ConvertInstanceCommand.class))).thenReturn(answer);
|
when(agentManager.send(Mockito.eq(convertHostId), Mockito.any(CheckConvertInstanceCommand.class))).thenReturn(checkConvertInstanceAnswer);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConvertInstanceAnswer convertInstanceAnswer = mock(ConvertInstanceAnswer.class);
|
||||||
|
when(convertInstanceAnswer.getResult()).thenReturn(vcenterParameter != VcenterParameter.CONVERT_FAILURE);
|
||||||
|
when(convertInstanceAnswer.getConvertedInstance()).thenReturn(instance);
|
||||||
|
if (VcenterParameter.AGENT_UNAVAILABLE != vcenterParameter) {
|
||||||
|
when(agentManager.send(Mockito.eq(convertHostId), Mockito.any(ConvertInstanceCommand.class))).thenReturn(convertInstanceAnswer);
|
||||||
}
|
}
|
||||||
|
|
||||||
try (MockedStatic<UsageEventUtils> ignored = Mockito.mockStatic(UsageEventUtils.class)) {
|
try (MockedStatic<UsageEventUtils> ignored = Mockito.mockStatic(UsageEventUtils.class)) {
|
||||||
unmanagedVMsManager.importVm(importVmCmd);
|
unmanagedVMsManager.importVm(importVmCmd);
|
||||||
verify(vmwareGuru).cloneHypervisorVMOutOfBand(Mockito.eq(host), Mockito.eq(vmName), anyMap());
|
verify(vmwareGuru).getHypervisorVMOutOfBandAndCloneIfRequired(Mockito.eq(host), Mockito.eq(vmName), anyMap());
|
||||||
|
verify(vmwareGuru).createVMTemplateOutOfBand(Mockito.eq(host), Mockito.eq(vmName), anyMap(), any(DataStoreTO.class), anyInt());
|
||||||
verify(vmwareGuru).removeClonedHypervisorVMOutOfBand(Mockito.eq(host), Mockito.eq(vmName), anyMap());
|
verify(vmwareGuru).removeClonedHypervisorVMOutOfBand(Mockito.eq(host), Mockito.eq(vmName), anyMap());
|
||||||
|
verify(vmwareGuru).removeVMTemplateOutOfBand(any(DataStoreTO.class), anyString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -797,7 +813,7 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
|
|
||||||
long poolId = 1L;
|
long poolId = 1L;
|
||||||
when(primaryDataStoreDao.findById(poolId)).thenReturn(null);
|
when(primaryDataStoreDao.findById(poolId)).thenReturn(null);
|
||||||
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, poolId, null);
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, poolId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = CloudRuntimeException.class)
|
@Test(expected = CloudRuntimeException.class)
|
||||||
@ -808,7 +824,7 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
Mockito.when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
|
Mockito.when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
|
||||||
Mockito.when(pool.getClusterId()).thenReturn(100L);
|
Mockito.when(pool.getClusterId()).thenReturn(100L);
|
||||||
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
||||||
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, poolId, null);
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, poolId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = CloudRuntimeException.class)
|
@Test(expected = CloudRuntimeException.class)
|
||||||
@ -818,9 +834,7 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
StoragePoolVO pool = mock(StoragePoolVO.class);
|
StoragePoolVO pool = mock(StoragePoolVO.class);
|
||||||
Mockito.when(pool.getScope()).thenReturn(ScopeType.HOST);
|
Mockito.when(pool.getScope()).thenReturn(ScopeType.HOST);
|
||||||
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
||||||
HostVO convertHost = Mockito.mock(HostVO.class);
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, poolId);
|
||||||
Mockito.when(convertHost.getId()).thenReturn(1L);
|
|
||||||
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, poolId, convertHost);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = CloudRuntimeException.class)
|
@Test(expected = CloudRuntimeException.class)
|
||||||
@ -831,15 +845,14 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
Mockito.when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
|
Mockito.when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
|
||||||
Mockito.when(pool.getClusterId()).thenReturn(1L);
|
Mockito.when(pool.getClusterId()).thenReturn(1L);
|
||||||
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
||||||
HostVO convertHost = Mockito.mock(HostVO.class);
|
|
||||||
Mockito.when(pool.getPoolType()).thenReturn(Storage.StoragePoolType.RBD);
|
Mockito.when(pool.getPoolType()).thenReturn(Storage.StoragePoolType.RBD);
|
||||||
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, poolId, convertHost);
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, poolId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = CloudRuntimeException.class)
|
@Test(expected = CloudRuntimeException.class)
|
||||||
public void testSelectInstanceConversionTemporaryLocationNoPoolAvailable() {
|
public void testSelectInstanceConversionTemporaryLocationNoPoolAvailable() {
|
||||||
ClusterVO cluster = getClusterForTests();
|
ClusterVO cluster = getClusterForTests();
|
||||||
Mockito.when(imageStoreDao.findOneByZoneAndProtocol(anyLong(), anyString())).thenReturn(null);
|
Mockito.when(imageStoreDao.findOneByZoneAndProtocol(anyLong(), anyString())).thenReturn(null);
|
||||||
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null, null);
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -918,6 +918,7 @@
|
|||||||
"label.for": "for",
|
"label.for": "for",
|
||||||
"label.forbidden": "Forbidden",
|
"label.forbidden": "Forbidden",
|
||||||
"label.forced": "Force",
|
"label.forced": "Force",
|
||||||
|
"label.force.ms.to.import.vm.files": "Force MS to import VM file(s) to temporary storage",
|
||||||
"label.force.stop": "Force stop",
|
"label.force.stop": "Force stop",
|
||||||
"label.force.reboot": "Force reboot",
|
"label.force.reboot": "Force reboot",
|
||||||
"label.forceencap": "Force UDP encapsulation of ESP packets",
|
"label.forceencap": "Force UDP encapsulation of ESP packets",
|
||||||
@ -1049,6 +1050,7 @@
|
|||||||
"label.installwizard.subtitle": "This guide will aid you in setting up your CloudStack™ installation",
|
"label.installwizard.subtitle": "This guide will aid you in setting up your CloudStack™ installation",
|
||||||
"label.installwizard.title": "Hello and welcome to CloudStack™",
|
"label.installwizard.title": "Hello and welcome to CloudStack™",
|
||||||
"label.instance": "Instance",
|
"label.instance": "Instance",
|
||||||
|
"label.instance.conversion.support": "Instance Conversion Supported",
|
||||||
"label.instance.groups": "Instance groups",
|
"label.instance.groups": "Instance groups",
|
||||||
"label.instance.name": "Instance name",
|
"label.instance.name": "Instance name",
|
||||||
"label.instancename": "Internal name",
|
"label.instancename": "Internal name",
|
||||||
@ -2039,6 +2041,7 @@
|
|||||||
"label.suitable": "Suitable",
|
"label.suitable": "Suitable",
|
||||||
"label.summary": "Summary",
|
"label.summary": "Summary",
|
||||||
"label.sunday": "Sunday",
|
"label.sunday": "Sunday",
|
||||||
|
"label.supported": "Supported",
|
||||||
"label.supportedservices": "Supported services",
|
"label.supportedservices": "Supported services",
|
||||||
"label.supportsautoscaling": "Supports auto scaling",
|
"label.supportsautoscaling": "Supports auto scaling",
|
||||||
"label.supportsha": "Supports HA",
|
"label.supportsha": "Supports HA",
|
||||||
@ -3116,11 +3119,13 @@
|
|||||||
"message.select.destination.image.stores": "Please select Image Store(s) to which data is to be migrated to",
|
"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.disk.offering": "Please select a disk offering for disk",
|
||||||
"message.select.end.date.and.time": "Select an end date & time.",
|
"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.load.balancer.rule": "Please select a load balancer rule for your AutoScale Instance group.",
|
"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.migration.policy": "Please select a migration policy.",
|
||||||
"message.select.nic.network": "Please select a Network for NIC",
|
"message.select.nic.network": "Please select a Network for NIC",
|
||||||
"message.select.security.groups": "Please select security group(s) for your new Instance.",
|
"message.select.security.groups": "Please select security group(s) for your new Instance.",
|
||||||
"message.select.start.date.and.time": "Select a start date & time.",
|
"message.select.start.date.and.time": "Select a start date & time.",
|
||||||
|
"message.select.temporary.storage.instance.conversion": "(Optional) Select a Storage temporary destination for the converted disks through virt-v2v",
|
||||||
"message.select.zone.description": "Select type of zone basic/advanced.",
|
"message.select.zone.description": "Select type of zone basic/advanced.",
|
||||||
"message.select.zone.hint": "This is the type of zone deployment that you want to use. Basic zone: provides a single Network where each Instance is assigned an IP directly from the Network. Guest isolation can be provided through layer-3 means such as security groups (IP address source filtering). Advanced zone: For more sophisticated Network topologies. This Network model provides the most flexibility in defining guest Networks and providing custom Network offerings such as firewall, VPN, or load balancer support.",
|
"message.select.zone.hint": "This is the type of zone deployment that you want to use. Basic zone: provides a single Network where each Instance is assigned an IP directly from the Network. Guest isolation can be provided through layer-3 means such as security groups (IP address source filtering). Advanced zone: For more sophisticated Network topologies. This Network model provides the most flexibility in defining guest Networks and providing custom Network offerings such as firewall, VPN, or load balancer support.",
|
||||||
"message.server.description": "NFS, iSCSI, or PreSetup: IP address or DNS name of the storage device. VMWare PreSetup: IP address or DNS name of the vCenter server. Linstor: http(s) url of the linstor-controller.",
|
"message.server.description": "NFS, iSCSI, or PreSetup: IP address or DNS name of the storage device. VMWare PreSetup: IP address or DNS name of the vCenter server. Linstor: http(s) url of the linstor-controller.",
|
||||||
|
|||||||
@ -48,6 +48,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-list-item>
|
</a-list-item>
|
||||||
|
<a-list-item v-if="host.instanceconversionsupported">
|
||||||
|
<div>
|
||||||
|
<strong>{{ $t('label.instance.conversion.support') }}</strong>
|
||||||
|
<div>
|
||||||
|
{{ host.instanceconversionsupported }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-list-item>
|
||||||
<a-list-item v-if="host.hosttags">
|
<a-list-item v-if="host.hosttags">
|
||||||
<div>
|
<div>
|
||||||
<strong>{{ $t('label.hosttags') }}</strong>
|
<strong>{{ $t('label.hosttags') }}</strong>
|
||||||
|
|||||||
@ -158,7 +158,7 @@
|
|||||||
v-if="cluster.hypervisortype === 'KVM' && selectedVmwareVcenter"
|
v-if="cluster.hypervisortype === 'KVM' && selectedVmwareVcenter"
|
||||||
:resourceKey="cluster.id"
|
:resourceKey="cluster.id"
|
||||||
:selectOptions="kvmHostsForConversion"
|
:selectOptions="kvmHostsForConversion"
|
||||||
:checkBoxLabel="'(Optional) Select a KVM host in the cluster to perform the instance conversion through virt-v2v'"
|
:checkBoxLabel="$t('message.select.kvm.host.instance.conversion')"
|
||||||
:defaultCheckBoxValue="false"
|
:defaultCheckBoxValue="false"
|
||||||
:reversed="false"
|
:reversed="false"
|
||||||
@handle-checkselectpair-change="updateSelectedKvmHostForConversion"
|
@handle-checkselectpair-change="updateSelectedKvmHostForConversion"
|
||||||
@ -167,11 +167,11 @@
|
|||||||
<a-form-item name="convertstorageoption" ref="convertstorageoption">
|
<a-form-item name="convertstorageoption" ref="convertstorageoption">
|
||||||
<check-box-select-pair
|
<check-box-select-pair
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
style="margin-bottom: 20px"
|
style="margin-bottom: 5px"
|
||||||
v-if="cluster.hypervisortype === 'KVM' && selectedVmwareVcenter"
|
v-if="cluster.hypervisortype === 'KVM' && selectedVmwareVcenter"
|
||||||
:resourceKey="cluster.id"
|
:resourceKey="cluster.id"
|
||||||
:selectOptions="storageOptionsForConversion"
|
:selectOptions="storageOptionsForConversion"
|
||||||
:checkBoxLabel="'(Optional) Select a Storage temporary destination for the converted disks through virt-v2v'"
|
:checkBoxLabel="$t('message.select.temporary.storage.instance.conversion')"
|
||||||
:defaultCheckBoxValue="false"
|
:defaultCheckBoxValue="false"
|
||||||
:reversed="false"
|
:reversed="false"
|
||||||
@handle-checkselectpair-change="updateSelectedStorageOptionForConversion"
|
@handle-checkselectpair-change="updateSelectedStorageOptionForConversion"
|
||||||
@ -192,6 +192,12 @@
|
|||||||
</a-select-option>
|
</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item name="forcemstoimportvmfiles" ref="forcemstoimportvmfiles" v-if="selectedVmwareVcenter">
|
||||||
|
<template #label>
|
||||||
|
<tooltip-label :title="$t('label.force.ms.to.import.vm.files')" :tooltip="apiParams.forcemstoimportvmfiles.description"/>
|
||||||
|
</template>
|
||||||
|
<a-switch v-model:checked="form.forcemstoimportvmfiles" @change="val => { switches.forceMsToImportVmFiles = val }" />
|
||||||
|
</a-form-item>
|
||||||
<a-form-item name="serviceofferingid" ref="serviceofferingid">
|
<a-form-item name="serviceofferingid" ref="serviceofferingid">
|
||||||
<template #label>
|
<template #label>
|
||||||
<tooltip-label :title="$t('label.serviceofferingid')" :tooltip="apiParams.serviceofferingid.description"/>
|
<tooltip-label :title="$t('label.serviceofferingid')" :tooltip="apiParams.serviceofferingid.description"/>
|
||||||
@ -518,6 +524,12 @@ export default {
|
|||||||
this.apiConfig.params.forEach(param => {
|
this.apiConfig.params.forEach(param => {
|
||||||
this.apiParams[param.name] = param
|
this.apiParams[param.name] = param
|
||||||
})
|
})
|
||||||
|
this.apiConfig = this.$store.getters.apis.importVm || {}
|
||||||
|
this.apiConfig.params.forEach(param => {
|
||||||
|
if (!(param.name in this.apiParams)) {
|
||||||
|
this.apiParams[param.name] = param
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
this.initForm()
|
this.initForm()
|
||||||
@ -696,6 +708,7 @@ export default {
|
|||||||
rootdiskid: 0,
|
rootdiskid: 0,
|
||||||
migrateallowed: this.switches.migrateAllowed,
|
migrateallowed: this.switches.migrateAllowed,
|
||||||
forced: this.switches.forced,
|
forced: this.switches.forced,
|
||||||
|
forcemstoimportvmfiles: this.switches.forceMsToImportVmFiles,
|
||||||
domainid: null,
|
domainid: null,
|
||||||
account: null
|
account: null
|
||||||
})
|
})
|
||||||
@ -909,13 +922,18 @@ export default {
|
|||||||
resourcestate: 'Enabled'
|
resourcestate: 'Enabled'
|
||||||
}).then(json => {
|
}).then(json => {
|
||||||
this.kvmHostsForConversion = json.listhostsresponse.host || []
|
this.kvmHostsForConversion = json.listhostsresponse.host || []
|
||||||
|
this.kvmHostsForConversion.map(host => {
|
||||||
|
if (host.instanceconversionsupported !== null && host.instanceconversionsupported !== undefined && host.instanceconversionsupported) {
|
||||||
|
host.name = host.name + ' (' + this.$t('label.supported') + ')'
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
fetchStoragePoolsForConversion () {
|
fetchStoragePoolsForConversion () {
|
||||||
if (this.selectedStorageOptionForConversion === 'primary') {
|
if (this.selectedStorageOptionForConversion === 'primary') {
|
||||||
api('listStoragePools', {
|
api('listStoragePools', {
|
||||||
zoneid: this.cluster.zoneid,
|
zoneid: this.cluster.zoneid,
|
||||||
state: 'Up'
|
status: 'Up'
|
||||||
}).then(json => {
|
}).then(json => {
|
||||||
this.storagePoolsForConversion = json.liststoragepoolsresponse.storagepool || []
|
this.storagePoolsForConversion = json.liststoragepoolsresponse.storagepool || []
|
||||||
})
|
})
|
||||||
@ -924,7 +942,7 @@ export default {
|
|||||||
api('listStoragePools', {
|
api('listStoragePools', {
|
||||||
scope: 'HOST',
|
scope: 'HOST',
|
||||||
ipaddress: kvmHost.ipaddress,
|
ipaddress: kvmHost.ipaddress,
|
||||||
state: 'Up'
|
status: 'Up'
|
||||||
}).then(json => {
|
}).then(json => {
|
||||||
this.storagePoolsForConversion = json.liststoragepoolsresponse.storagepool || []
|
this.storagePoolsForConversion = json.liststoragepoolsresponse.storagepool || []
|
||||||
})
|
})
|
||||||
@ -1084,8 +1102,9 @@ export default {
|
|||||||
if (this.selectedStoragePoolForConversion) {
|
if (this.selectedStoragePoolForConversion) {
|
||||||
params.convertinstancepoolid = this.selectedStoragePoolForConversion
|
params.convertinstancepoolid = this.selectedStoragePoolForConversion
|
||||||
}
|
}
|
||||||
|
params.forcemstoimportvmfiles = values.forcemstoimportvmfiles
|
||||||
}
|
}
|
||||||
var keys = ['hostname', 'domainid', 'projectid', 'account', 'migrateallowed', 'forced']
|
var keys = ['hostname', 'domainid', 'projectid', 'account', 'migrateallowed', 'forced', 'forcemstoimportvmfiles']
|
||||||
if (this.templateType !== 'auto') {
|
if (this.templateType !== 'auto') {
|
||||||
keys.push('templateid')
|
keys.push('templateid')
|
||||||
}
|
}
|
||||||
|
|||||||
@ -144,7 +144,12 @@ public class BaseMO {
|
|||||||
public int getCustomFieldKey(String morType, String fieldName) throws Exception {
|
public int getCustomFieldKey(String morType, String fieldName) throws Exception {
|
||||||
assert (morType != null);
|
assert (morType != null);
|
||||||
|
|
||||||
CustomFieldsManagerMO cfmMo = new CustomFieldsManagerMO(_context, _context.getServiceContent().getCustomFieldsManager());
|
ManagedObjectReference cfmMor = _context.getServiceContent().getCustomFieldsManager();
|
||||||
|
if (cfmMor == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomFieldsManagerMO cfmMo = new CustomFieldsManagerMO(_context, cfmMor);
|
||||||
|
|
||||||
return cfmMo.getCustomFieldKey(morType, fieldName);
|
return cfmMo.getCustomFieldKey(morType, fieldName);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,9 +32,12 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.cloud.storage.Storage;
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
@ -1798,6 +1801,10 @@ public class VirtualMachineMO extends BaseMO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void exportVm(String exportDir, String exportName, boolean packToOva, boolean leaveOvaFileOnly) throws Exception {
|
public void exportVm(String exportDir, String exportName, boolean packToOva, boolean leaveOvaFileOnly) throws Exception {
|
||||||
|
exportVm(exportDir, exportName, packToOva, leaveOvaFileOnly, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void exportVm(String exportDir, String exportName, boolean packToOva, boolean leaveOvaFileOnly, int threadsCountToExportOvf) throws Exception {
|
||||||
ManagedObjectReference morOvf = _context.getServiceContent().getOvfManager();
|
ManagedObjectReference morOvf = _context.getServiceContent().getOvfManager();
|
||||||
|
|
||||||
VirtualMachineRuntimeInfo runtimeInfo = getRuntimeInfo();
|
VirtualMachineRuntimeInfo runtimeInfo = getRuntimeInfo();
|
||||||
@ -1827,18 +1834,31 @@ public class VirtualMachineMO extends BaseMO {
|
|||||||
final HttpNfcLeaseMO.ProgressReporter progressReporter = leaseMo.createProgressReporter();
|
final HttpNfcLeaseMO.ProgressReporter progressReporter = leaseMo.createProgressReporter();
|
||||||
|
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
List<String> fileNames = new ArrayList<String>();
|
List<String> fileNames = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
HttpNfcLeaseInfo leaseInfo = leaseMo.getLeaseInfo();
|
HttpNfcLeaseInfo leaseInfo = leaseMo.getLeaseInfo();
|
||||||
final long totalBytes = leaseInfo.getTotalDiskCapacityInKB() * 1024;
|
final long totalBytes = leaseInfo.getTotalDiskCapacityInKB() * 1024;
|
||||||
long totalBytesDownloaded = 0;
|
AtomicLong totalBytesDownloaded = new AtomicLong(0L);
|
||||||
|
|
||||||
List<HttpNfcLeaseDeviceUrl> deviceUrls = leaseInfo.getDeviceUrl();
|
List<HttpNfcLeaseDeviceUrl> deviceUrls = leaseInfo.getDeviceUrl();
|
||||||
s_logger.info("volss: copy vmdk and ovf file starts " + System.currentTimeMillis());
|
s_logger.info("volss: copy vmdk and ovf file starts " + System.currentTimeMillis());
|
||||||
if (deviceUrls != null) {
|
if (deviceUrls != null) {
|
||||||
OvfFile[] ovfFiles = new OvfFile[deviceUrls.size()];
|
int deviceUrlsCount = deviceUrls.size();
|
||||||
for (int i = 0; i < deviceUrls.size(); i++) {
|
boolean parallelDownload = false;
|
||||||
|
if (threadsCountToExportOvf >= 0 && deviceUrlsCount > 1) {
|
||||||
|
if (threadsCountToExportOvf == 0) {
|
||||||
|
threadsCountToExportOvf = deviceUrlsCount;
|
||||||
|
parallelDownload = true;
|
||||||
|
} else if (threadsCountToExportOvf > 1) {
|
||||||
|
parallelDownload = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OvfFile[] ovfFiles = new OvfFile[deviceUrlsCount];
|
||||||
|
List<CompletableFuture<Long>> futures = new ArrayList<>();
|
||||||
|
ExecutorService executor = null;
|
||||||
|
for (int i = 0; i < deviceUrlsCount; i++) {
|
||||||
String deviceId = deviceUrls.get(i).getKey();
|
String deviceId = deviceUrls.get(i).getKey();
|
||||||
|
Long diskFileSize = deviceUrls.get(i).getFileSize();
|
||||||
String deviceUrlStr = deviceUrls.get(i).getUrl();
|
String deviceUrlStr = deviceUrls.get(i).getUrl();
|
||||||
String orgDiskFileName = deviceUrlStr.substring(deviceUrlStr.lastIndexOf("/") + 1);
|
String orgDiskFileName = deviceUrlStr.substring(deviceUrlStr.lastIndexOf("/") + 1);
|
||||||
String diskFileName = String.format("%s-disk%d%s", exportName, i, VmwareHelper.getFileExtension(orgDiskFileName, ".vmdk"));
|
String diskFileName = String.format("%s-disk%d%s", exportName, i, VmwareHelper.getFileExtension(orgDiskFileName, ".vmdk"));
|
||||||
@ -1847,25 +1867,77 @@ public class VirtualMachineMO extends BaseMO {
|
|||||||
String diskLocalPath = exportDir + File.separator + diskFileName;
|
String diskLocalPath = exportDir + File.separator + diskFileName;
|
||||||
fileNames.add(diskLocalPath);
|
fileNames.add(diskLocalPath);
|
||||||
|
|
||||||
if (s_logger.isInfoEnabled()) {
|
if (!parallelDownload) {
|
||||||
s_logger.info("Download VMDK file for export. url: " + deviceUrlStr);
|
if (s_logger.isInfoEnabled()) {
|
||||||
}
|
s_logger.info("Download VMDK file for export url: " + deviceUrlStr + ", size: " + diskFileSize);
|
||||||
long lengthOfDiskFile = _context.downloadVmdkFile(diskUrlStr, diskLocalPath, totalBytesDownloaded, new ActionDelegate<Long>() {
|
|
||||||
@Override
|
|
||||||
public void action(Long param) {
|
|
||||||
if (s_logger.isTraceEnabled()) {
|
|
||||||
s_logger.trace("Download progress " + param + "/" + toHumanReadableSize(totalBytes));
|
|
||||||
}
|
|
||||||
progressReporter.reportProgress((int)(param * 100 / totalBytes));
|
|
||||||
}
|
}
|
||||||
});
|
long lengthOfDiskFile = _context.downloadVmdkFile(diskUrlStr, diskLocalPath, totalBytesDownloaded, new ActionDelegate<Long>() {
|
||||||
totalBytesDownloaded += lengthOfDiskFile;
|
@Override
|
||||||
|
public void action(Long param) {
|
||||||
|
if (s_logger.isTraceEnabled()) {
|
||||||
|
s_logger.trace("Download progress " + param + "/" + toHumanReadableSize(totalBytes));
|
||||||
|
}
|
||||||
|
progressReporter.reportProgress((int)(param * 100 / totalBytes));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
totalBytesDownloaded.addAndGet(lengthOfDiskFile);
|
||||||
|
|
||||||
OvfFile ovfFile = new OvfFile();
|
OvfFile ovfFile = new OvfFile();
|
||||||
ovfFile.setPath(diskFileName);
|
ovfFile.setPath(diskFileName);
|
||||||
ovfFile.setDeviceId(deviceId);
|
ovfFile.setDeviceId(deviceId);
|
||||||
ovfFile.setSize(lengthOfDiskFile);
|
ovfFile.setSize(lengthOfDiskFile);
|
||||||
ovfFiles[i] = ovfFile;
|
ovfFiles[i] = ovfFile;
|
||||||
|
} else {
|
||||||
|
String diskUrl = diskUrlStr;
|
||||||
|
executor = Executors.newFixedThreadPool(Math.min(threadsCountToExportOvf, deviceUrlsCount));
|
||||||
|
if (s_logger.isInfoEnabled()) {
|
||||||
|
s_logger.info("Download VMDK file for export url: " + deviceUrlStr + ", size: " + diskFileSize);
|
||||||
|
}
|
||||||
|
CompletableFuture<Long> future = CompletableFuture.supplyAsync(() -> {
|
||||||
|
long lengthOfDiskFile = 0;
|
||||||
|
try {
|
||||||
|
lengthOfDiskFile = _context.downloadVmdkFile(diskUrl, diskLocalPath, totalBytesDownloaded, new ActionDelegate<Long>() {
|
||||||
|
@Override
|
||||||
|
public void action(Long param) {
|
||||||
|
if (s_logger.isTraceEnabled()) {
|
||||||
|
s_logger.trace("Download progress " + param + "/" + toHumanReadableSize(totalBytes));
|
||||||
|
}
|
||||||
|
progressReporter.reportProgress((int)(param * 100 / totalBytes));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
s_logger.error("Error on downloading VMDK file for export url: " + diskUrl, e);
|
||||||
|
}
|
||||||
|
return lengthOfDiskFile;
|
||||||
|
}, executor);
|
||||||
|
futures.add(future);
|
||||||
|
|
||||||
|
OvfFile ovfFile = new OvfFile();
|
||||||
|
ovfFile.setPath(diskFileName);
|
||||||
|
ovfFile.setDeviceId(deviceId);
|
||||||
|
ovfFile.setSize(0L);
|
||||||
|
ovfFiles[i] = ovfFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parallelDownload) {
|
||||||
|
CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
|
||||||
|
List<Long> diskFileLengths = allFutures.exceptionally(e -> {
|
||||||
|
s_logger.error("Error on downloading VMDK files: " + e.getMessage());
|
||||||
|
return null;
|
||||||
|
}).thenApply(v -> futures.stream().map(CompletableFuture::join).collect(Collectors.toList())).join();
|
||||||
|
executor.shutdown();
|
||||||
|
|
||||||
|
if (CollectionUtils.isNotEmpty(diskFileLengths)) {
|
||||||
|
int i = 0;
|
||||||
|
for (Long diskFileLength : diskFileLengths) {
|
||||||
|
if (diskFileLength != null) {
|
||||||
|
totalBytesDownloaded.addAndGet(diskFileLength);
|
||||||
|
ovfFiles[i].setSize(diskFileLength);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// write OVF descriptor file
|
// write OVF descriptor file
|
||||||
@ -1892,7 +1964,9 @@ public class VirtualMachineMO extends BaseMO {
|
|||||||
command.add("-cf", exportName + ".ova");
|
command.add("-cf", exportName + ".ova");
|
||||||
command.add(exportName + ".ovf"); // OVF file should be the first file in OVA archive
|
command.add(exportName + ".ovf"); // OVF file should be the first file in OVA archive
|
||||||
for (String name : fileNames) {
|
for (String name : fileNames) {
|
||||||
command.add((new File(name).getName()));
|
if (!name.endsWith(".ovf")) {
|
||||||
|
command.add((new File(name).getName()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s_logger.info("Package OVA with command: " + command.toString());
|
s_logger.info("Package OVA with command: " + command.toString());
|
||||||
|
|||||||
@ -35,6 +35,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
import javax.net.ssl.HostnameVerifier;
|
import javax.net.ssl.HostnameVerifier;
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
@ -469,7 +470,7 @@ public class VmwareContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long downloadVmdkFile(String urlString, String localFileName, long totalBytesDownloaded, ActionDelegate<Long> progressUpdater) throws Exception {
|
public long downloadVmdkFile(String urlString, String localFileName, AtomicLong totalBytesDownloaded, ActionDelegate<Long> progressUpdater) throws Exception {
|
||||||
HttpURLConnection conn = getRawHTTPConnection(urlString);
|
HttpURLConnection conn = getRawHTTPConnection(urlString);
|
||||||
|
|
||||||
String cookie = _vimClient.getServiceCookie();
|
String cookie = _vimClient.getServiceCookie();
|
||||||
@ -495,10 +496,10 @@ public class VmwareContext {
|
|||||||
while ((len = in.read(buf)) > 0) {
|
while ((len = in.read(buf)) > 0) {
|
||||||
out.write(buf, 0, len);
|
out.write(buf, 0, len);
|
||||||
bytesWritten += len;
|
bytesWritten += len;
|
||||||
totalBytesDownloaded += len;
|
totalBytesDownloaded.addAndGet(len);
|
||||||
|
|
||||||
if (progressUpdater != null)
|
if (progressUpdater != null)
|
||||||
progressUpdater.action(new Long(totalBytesDownloaded));
|
progressUpdater.action(new Long(totalBytesDownloaded.get()));
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (in != null)
|
if (in != null)
|
||||||
|
|||||||
@ -807,8 +807,13 @@ public class VmwareHelper {
|
|||||||
instance.setMemory(configSummary.getMemorySizeMB());
|
instance.setMemory(configSummary.getMemorySizeMB());
|
||||||
}
|
}
|
||||||
|
|
||||||
ClusterMO clusterMo = new ClusterMO(hyperHost.getContext(), hyperHost.getHyperHostCluster());
|
try {
|
||||||
instance.setClusterName(clusterMo.getName());
|
ClusterMO clusterMo = new ClusterMO(hyperHost.getContext(), hyperHost.getHyperHostCluster());
|
||||||
|
instance.setClusterName(clusterMo.getName());
|
||||||
|
} catch (Exception e) {
|
||||||
|
s_logger.warn("Unable to get unmanaged instance cluster info, due to: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
instance.setHostName(hyperHost.getHyperHostName());
|
instance.setHostName(hyperHost.getHyperHostName());
|
||||||
|
|
||||||
if (StringUtils.isEmpty(instance.getOperatingSystemId()) && configSummary != null) {
|
if (StringUtils.isEmpty(instance.getOperatingSystemId()) && configSummary != null) {
|
||||||
@ -838,7 +843,7 @@ public class VmwareHelper {
|
|||||||
instance.setDisks(getUnmanageInstanceDisks(vmMo));
|
instance.setDisks(getUnmanageInstanceDisks(vmMo));
|
||||||
instance.setNics(getUnmanageInstanceNics(hyperHost, vmMo));
|
instance.setNics(getUnmanageInstanceNics(hyperHost, vmMo));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
s_logger.info("Unable to retrieve unmanaged instance info. " + e.getMessage());
|
s_logger.error("Unable to retrieve unmanaged instance info, due to: " + e.getMessage());
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user