Skip to content

Commit

Permalink
KVM Ingestion - Import Instance (apache#7976)
Browse files Browse the repository at this point in the history
This PR adds new functionality to import KVM instances from an external host or from disk images in local or shared storage.
Doc PR: apache/cloudstack-documentation#356
  • Loading branch information
kishankavala authored and dhslove committed Dec 15, 2023
1 parent 821be6d commit d7c7101
Show file tree
Hide file tree
Showing 40 changed files with 3,467 additions and 356 deletions.
4 changes: 3 additions & 1 deletion api/src/main/java/com/cloud/vm/UserVmService.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// under the License.
package com.cloud.vm;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -538,7 +539,8 @@ UserVm upgradeVirtualMachine(ScaleVMCmd cmd) throws ResourceUnavailableException

UserVm importVM(final DataCenter zone, final Host host, final VirtualMachineTemplate template, final String instanceName, final String displayName, final Account owner, final String userData, final Account caller, final Boolean isDisplayVm, final String keyboard,
final long accountId, final long userId, final ServiceOffering serviceOffering, final String sshPublicKey,
final String hostName, final HypervisorType hypervisorType, final Map<String, String> customParameters, final VirtualMachine.PowerState powerState) throws InsufficientCapacityException;
final String hostName, final HypervisorType hypervisorType, final Map<String, String> customParameters,
final VirtualMachine.PowerState powerState, final LinkedHashMap<String, List<NicProfile>> networkNicMap) throws InsufficientCapacityException;

/**
* Unmanage a guest VM from CloudStack
Expand Down
2 changes: 2 additions & 0 deletions api/src/main/java/com/cloud/vm/VmDetailConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public interface VmDetailConstants {
String KVM_VNC_PORT = "kvm.vnc.port";
String KVM_VNC_ADDRESS = "kvm.vnc.address";
String TPM_VERSION = "tpmversion";
String KVM_VNC_PASSWORD = "kvm.vnc.password";

// KVM specific, custom virtual GPU hardware
String VIDEO_HARDWARE = "video.hardware";
String VIDEO_RAM = "video.ram";
Expand Down
3 changes: 3 additions & 0 deletions api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ public class ApiConstants {
public static final String HOST_IDS = "hostids";
public static final String HOST_IP = "hostip";
public static final String HOST_NAME = "hostname";
public static final String HOST = "host";
public static final String HOST_CONTROL_STATE = "hostcontrolstate";
public static final String HOSTS_MAP = "hostsmap";
public static final String HYPERVISOR = "hypervisor";
Expand Down Expand Up @@ -1124,7 +1125,9 @@ public class ApiConstants {
public static final String SOURCE_NAT_IP = "sourcenatipaddress";
public static final String SOURCE_NAT_IP_ID = "sourcenatipaddressid";
public static final String HAS_RULES = "hasrules";
public static final String DISK_PATH = "diskpath";
public static final String IMPORT_SOURCE = "importsource";
public static final String TEMP_PATH = "temppath";
public static final String OBJECT_STORAGE = "objectstore";

public static final String FIRST_LOGIN = "firstlogin";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public class ImportUnmanagedInstanceCmd extends BaseAsyncCmd {
@Parameter(name = ApiConstants.NAME,
type = CommandType.STRING,
required = true,
description = "the hypervisor name of the instance")
description = "the name of the instance as it is known to the hypervisor")
private String name;

@Parameter(name = ApiConstants.DISPLAY_NAME,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,18 @@
import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.NetworkResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VmwareDatacenterResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.vm.VmImportService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import javax.inject.Inject;

@APICommand(name = "importVm",
description = "Import virtual machine from a unmanaged host into CloudStack",
responseObject = UserVmResponse.class,
Expand All @@ -47,21 +52,72 @@
authorized = {RoleType.Admin},
since = "4.19.0")
public class ImportVmCmd extends ImportUnmanagedInstanceCmd {

public static final Logger LOGGER = Logger.getLogger(ImportVmCmd.class);

@Inject
public VmImportService vmImportService;

/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////


@Parameter(name = ApiConstants.ZONE_ID,
type = CommandType.UUID,
entityType = ZoneResponse.class,
required = true,
description = "the zone ID")
private Long zoneId;

@Parameter(name = ApiConstants.USERNAME,
type = CommandType.STRING,
description = "the username for the host")
private String username;

@Parameter(name = ApiConstants.PASSWORD,
type = CommandType.STRING,
description = "the password for the host")
private String password;

@Parameter(name = ApiConstants.HOST,
type = CommandType.STRING,
description = "the host name or IP address")
private String host;

@Parameter(name = ApiConstants.HYPERVISOR,
type = CommandType.STRING,
required = true,
description = "hypervisor type of the host")
private String hypervisor;

@Parameter(name = ApiConstants.DISK_PATH,
type = CommandType.STRING,
description = "path of the disk image")
private String diskPath;

@Parameter(name = ApiConstants.IMPORT_SOURCE,
type = CommandType.STRING,
required = true,
description = "Source location for Import" )
private String importSource;

@Parameter(name = ApiConstants.NETWORK_ID,
type = CommandType.UUID,
entityType = NetworkResponse.class,
description = "the network ID")
private Long networkId;

@Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, description = "Host where local disk is located")
private Long hostId;

@Parameter(name = ApiConstants.STORAGE_ID, type = CommandType.UUID, entityType = StoragePoolResponse.class, description = "Shared storage pool where disk is located")
private Long storagePoolId;

@Parameter(name = ApiConstants.TEMP_PATH,
type = CommandType.STRING,
description = "Temp Path on external host for disk image copy" )
private String tmpPath;

// Import from Vmware to KVM migration parameters

@Parameter(name = ApiConstants.EXISTING_VCENTER_ID,
Expand All @@ -73,7 +129,7 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
@Parameter(name = ApiConstants.HOST_IP,
type = BaseCmd.CommandType.STRING,
description = "(only for importing migrated VMs from Vmware to KVM) VMware ESXi host IP/Name.")
private String host;
private String hostip;

@Parameter(name = ApiConstants.VCENTER,
type = CommandType.STRING,
Expand All @@ -88,14 +144,6 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
description = "(only for importing migrated VMs from Vmware to KVM) Name of VMware cluster.")
private String clusterName;

@Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING,
description = "(only for importing migrated VMs from Vmware to KVM) The Username required to connect to resource.")
private String username;

@Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING,
description = "(only for importing migrated VMs from Vmware to KVM) The password for the specified username.")
private String password;

@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.")
private Long convertInstanceHostId;
Expand All @@ -104,30 +152,20 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
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.")
private Long convertStoragePoolId;

@Override
public String getEventType() {
return EventTypes.EVENT_VM_IMPORT;
}
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////

@Override
public String getEventDescription() {
String vmName = getName();
if (ObjectUtils.anyNotNull(vcenter, existingVcenterId)) {
String msg = StringUtils.isNotBlank(vcenter) ?
String.format("external vCenter: %s - datacenter: %s", vcenter, datacenterName) :
String.format("existing vCenter Datacenter with ID: %s", existingVcenterId);
return String.format("Importing unmanaged VM: %s from %s - VM: %s", getDisplayName(), msg, vmName);
}
return String.format("Importing unmanaged VM: %s", vmName);
public Long getZoneId() {
return zoneId;
}


public Long getExistingVcenterId() {
return existingVcenterId;
}

public String getHost() {
return host;
public String getHostIp() {
return hostip;
}

public String getVcenter() {
Expand All @@ -150,6 +188,10 @@ public String getPassword() {
return password;
}

public String getHost() {
return host;
}

public Long getConvertInstanceHostId() {
return convertInstanceHostId;
}
Expand All @@ -162,10 +204,47 @@ public String getHypervisor() {
return hypervisor;
}

public String getDiskPath() {
return diskPath;
}

public String getImportSource() {
return importSource;
}

public Long getHostId() {
return hostId;
}

public Long getStoragePoolId() {
return storagePoolId;
}

public String getTmpPath() {
return tmpPath;
}

public Long getNetworkId() {
return networkId;
}

@Override
public String getEventType() {
return EventTypes.EVENT_VM_IMPORT;
}

@Override
public String getEventDescription() {
String vmName = getName();
if (ObjectUtils.anyNotNull(vcenter, existingVcenterId)) {
String msg = StringUtils.isNotBlank(vcenter) ?
String.format("external vCenter: %s - datacenter: %s", vcenter, datacenterName) :
String.format("existing vCenter Datacenter with ID: %s", existingVcenterId);
return String.format("Importing unmanaged VM: %s from %s - VM: %s", getDisplayName(), msg, vmName);
}
return String.format("Importing unmanaged VM: %s", vmName);
}

/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
Expand All @@ -176,5 +255,4 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE
response.setResponseName(getCommandName());
setResponseObject(response);
}

}
Loading

0 comments on commit d7c7101

Please sign in to comment.