mirror of
https://github.com/apache/cloudstack.git
synced 2025-12-16 10:32:34 +01:00
VMware to KVM Migrations improvements (#11594)
* Add source VM name on virt-v2v migration log entries * Improve the feedback by displaying the running importing tasks * Add source VM name prefix on more conversion logs * Improve listing and also list completed tasks * Pass extra parameters to virt-v2v if administrator allows via global setting * Add Force converting directly to storage pool option * Refactor based on review comments * Add properties for env vars for the instance conversion * Add separate component for Import VM Tasks * applying copilot suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix importing unmanaged instances due to incorrect internal name * Add VM prefix on each log operation for conversion * Log the original VM name instead of the cloned VM in case of cloning * Allow searching storage pool by UUID after conversion to support SharedMountPoint * Fix search pools logic * Improve UI and add checks for force convert to pool parameter * Support Local storage when forceconverttopool is set to true * Add config key to for allowed extra params and add validation * Fix params lists * Fix compile error * Remove extra stubbings * Fix extra params execution --------- Co-authored-by: Abhishek Kumar <abhishek.mrt22@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Suresh Kumar Anaparti <sureshkumar.anaparti@gmail.com>
This commit is contained in:
parent
b99a03092f
commit
b106d6e190
@ -451,3 +451,9 @@ iscsi.session.cleanup.enabled=false
|
|||||||
|
|
||||||
# If set to true, creates VMs as full clones of their templates on KVM hypervisor. Creates as linked clones otherwise.
|
# If set to true, creates VMs as full clones of their templates on KVM hypervisor. Creates as linked clones otherwise.
|
||||||
# create.full.clone=false
|
# create.full.clone=false
|
||||||
|
|
||||||
|
# Instance conversion TMPDIR env var
|
||||||
|
#convert.instance.env.tmpdir=
|
||||||
|
|
||||||
|
# Instance conversion VIRT_V2V_TMPDIR env var
|
||||||
|
#convert.instance.env.virtv2v.tmpdir=
|
||||||
|
|||||||
@ -794,6 +794,20 @@ public class AgentProperties{
|
|||||||
*/
|
*/
|
||||||
public static final Property<Boolean> VIRTV2V_VERBOSE_ENABLED = new Property<>("virtv2v.verbose.enabled", false);
|
public static final Property<Boolean> VIRTV2V_VERBOSE_ENABLED = new Property<>("virtv2v.verbose.enabled", false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set env TMPDIR var for virt-v2v Instance Conversion from VMware to KVM
|
||||||
|
* Data type: String.<br>
|
||||||
|
* Default value: <code>null</code>
|
||||||
|
*/
|
||||||
|
public static final Property<String> CONVERT_ENV_TMPDIR = new Property<>("convert.instance.env.tmpdir", null, String.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set env VIRT_V2V_TMPDIR var for virt-v2v Instance Conversion from VMware to KVM
|
||||||
|
* Data type: String.<br>
|
||||||
|
* Default value: <code>null</code>
|
||||||
|
*/
|
||||||
|
public static final Property<String> CONVERT_ENV_VIRTV2V_TMPDIR = new Property<>("convert.instance.env.virtv2v.tmpdir", null, String.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BGP controll CIDR
|
* BGP controll CIDR
|
||||||
* Data type: String.<br>
|
* Data type: String.<br>
|
||||||
|
|||||||
@ -225,6 +225,7 @@ public class ApiConstants {
|
|||||||
public static final String EVENT_TYPE = "eventtype";
|
public static final String EVENT_TYPE = "eventtype";
|
||||||
public static final String EXPIRES = "expires";
|
public static final String EXPIRES = "expires";
|
||||||
public static final String EXTRA_CONFIG = "extraconfig";
|
public static final String EXTRA_CONFIG = "extraconfig";
|
||||||
|
public static final String EXTRA_PARAMS = "extraparams";
|
||||||
public static final String EXTRA_DHCP_OPTION = "extradhcpoption";
|
public static final String EXTRA_DHCP_OPTION = "extradhcpoption";
|
||||||
public static final String EXTRA_DHCP_OPTION_NAME = "extradhcpoptionname";
|
public static final String EXTRA_DHCP_OPTION_NAME = "extradhcpoptionname";
|
||||||
public static final String EXTRA_DHCP_OPTION_CODE = "extradhcpoptioncode";
|
public static final String EXTRA_DHCP_OPTION_CODE = "extradhcpoptioncode";
|
||||||
@ -243,6 +244,8 @@ public class ApiConstants {
|
|||||||
public static final String FIRSTNAME = "firstname";
|
public static final String FIRSTNAME = "firstname";
|
||||||
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_CONVERT_TO_POOL = "forceconverttopool";
|
||||||
|
|
||||||
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 FORCE_MS_TO_IMPORT_VM_FILES = "forcemstoimportvmfiles";
|
||||||
public static final String FORCE_UPDATE_OS_TYPE = "forceupdateostype";
|
public static final String FORCE_UPDATE_OS_TYPE = "forceupdateostype";
|
||||||
@ -529,6 +532,7 @@ public class ApiConstants {
|
|||||||
public static final String SHOW_CAPACITIES = "showcapacities";
|
public static final String SHOW_CAPACITIES = "showcapacities";
|
||||||
public static final String SHOW_REMOVED = "showremoved";
|
public static final String SHOW_REMOVED = "showremoved";
|
||||||
public static final String SHOW_RESOURCE_ICON = "showicon";
|
public static final String SHOW_RESOURCE_ICON = "showicon";
|
||||||
|
public static final String SHOW_COMPLETED = "showcompleted";
|
||||||
public static final String SHOW_INACTIVE = "showinactive";
|
public static final String SHOW_INACTIVE = "showinactive";
|
||||||
public static final String SHOW_UNIQUE = "showunique";
|
public static final String SHOW_UNIQUE = "showunique";
|
||||||
public static final String SIGNATURE = "signature";
|
public static final String SIGNATURE = "signature";
|
||||||
|
|||||||
@ -159,6 +159,18 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
|
|||||||
description = "(only for importing VMs from VMware to KVM) optional - if true, forces MS to export OVF from VMware to temporary storage, else uses KVM Host if ovftool is available, falls back to MS if not.")
|
description = "(only for importing VMs from VMware to KVM) optional - if true, forces MS to export OVF from VMware to temporary storage, else uses KVM Host if ovftool is available, falls back to MS if not.")
|
||||||
private Boolean forceMsToImportVmFiles;
|
private Boolean forceMsToImportVmFiles;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.EXTRA_PARAMS,
|
||||||
|
type = CommandType.STRING,
|
||||||
|
since = "4.22",
|
||||||
|
description = "(only for importing VMs from VMware to KVM) optional - extra parameters to be passed on the virt-v2v command, if allowed by the administrator")
|
||||||
|
private String extraParams;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.FORCE_CONVERT_TO_POOL,
|
||||||
|
type = CommandType.BOOLEAN,
|
||||||
|
since = "4.22",
|
||||||
|
description = "(only for importing VMs from VMware to KVM) optional - if true, forces virt-v2v conversions to write directly on the provided storage pool (avoid using temporary conversion pool).")
|
||||||
|
private Boolean forceConvertToPool;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -248,6 +260,14 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
|
|||||||
return EventTypes.EVENT_VM_IMPORT;
|
return EventTypes.EVENT_VM_IMPORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getExtraParams() {
|
||||||
|
return extraParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getForceConvertToPool() {
|
||||||
|
return BooleanUtils.toBooleanDefaultIfNull(forceConvertToPool, false);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getEventDescription() {
|
public String getEventDescription() {
|
||||||
String vmName = getName();
|
String vmName = getName();
|
||||||
|
|||||||
@ -0,0 +1,123 @@
|
|||||||
|
// 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 org.apache.cloudstack.api.command.admin.vm;
|
||||||
|
|
||||||
|
import com.cloud.exception.ConcurrentOperationException;
|
||||||
|
import com.cloud.exception.InsufficientCapacityException;
|
||||||
|
import com.cloud.exception.NetworkRuleConflictException;
|
||||||
|
import com.cloud.exception.ResourceAllocationException;
|
||||||
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.BaseListCmd;
|
||||||
|
import org.apache.cloudstack.api.Parameter;
|
||||||
|
import org.apache.cloudstack.api.ResponseObject;
|
||||||
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
|
import org.apache.cloudstack.api.response.AccountResponse;
|
||||||
|
import org.apache.cloudstack.api.response.HostResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ImportVMTaskResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||||
|
import org.apache.cloudstack.context.CallContext;
|
||||||
|
import org.apache.cloudstack.vm.ImportVmTasksManager;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
@APICommand(name = "listImportVmTasks",
|
||||||
|
description = "List running import virtual machine tasks from a unmanaged hosts into CloudStack",
|
||||||
|
responseObject = ImportVMTaskResponse.class,
|
||||||
|
responseView = ResponseObject.ResponseView.Full,
|
||||||
|
requestHasSensitiveInfo = false,
|
||||||
|
authorized = {RoleType.Admin},
|
||||||
|
since = "4.22")
|
||||||
|
public class ListImportVMTasksCmd extends BaseListCmd {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public ImportVmTasksManager importVmTasksManager;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.ZONE_ID,
|
||||||
|
type = CommandType.UUID,
|
||||||
|
entityType = ZoneResponse.class,
|
||||||
|
required = true,
|
||||||
|
description = "the zone ID")
|
||||||
|
private Long zoneId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.ACCOUNT_ID,
|
||||||
|
type = CommandType.UUID,
|
||||||
|
entityType = AccountResponse.class,
|
||||||
|
description = "the ID of the Account")
|
||||||
|
private Long accountId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.VCENTER,
|
||||||
|
type = CommandType.STRING,
|
||||||
|
description = "The name/ip of vCenter. Make sure it is IP address or full qualified domain name for host running vCenter server.")
|
||||||
|
private String vcenter;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.CONVERT_INSTANCE_HOST_ID,
|
||||||
|
type = CommandType.UUID,
|
||||||
|
entityType = HostResponse.class,
|
||||||
|
description = "Conversion host of the importing task")
|
||||||
|
private Long convertHostId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.LIST_ALL, type = CommandType.BOOLEAN, description = "Whether to list all import tasks.")
|
||||||
|
private boolean listAll = false;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.SHOW_COMPLETED, type = CommandType.BOOLEAN, description = "Whether to list completed tasks.")
|
||||||
|
private boolean showCompleted = false;
|
||||||
|
|
||||||
|
public Long getZoneId() {
|
||||||
|
return zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAccountId() {
|
||||||
|
return accountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVcenter() {
|
||||||
|
return vcenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getConvertHostId() {
|
||||||
|
return convertHostId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isListAll() {
|
||||||
|
return listAll;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isShowCompleted() {
|
||||||
|
return showCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
|
||||||
|
ListResponse<ImportVMTaskResponse> response = importVmTasksManager.listImportVMTasks(this);
|
||||||
|
response.setResponseName(getCommandName());
|
||||||
|
setResponseObject(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getEntityOwnerId() {
|
||||||
|
Account account = CallContext.current().getCallingAccount();
|
||||||
|
if (account != null) {
|
||||||
|
return account.getId();
|
||||||
|
}
|
||||||
|
return Account.ACCOUNT_ID_SYSTEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,245 @@
|
|||||||
|
//
|
||||||
|
// 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 org.apache.cloudstack.api.response;
|
||||||
|
|
||||||
|
import com.cloud.serializer.Param;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.BaseResponse;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class ImportVMTaskResponse extends BaseResponse {
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.ID)
|
||||||
|
@Param(description = "the ID of importing task")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.ZONE_ID)
|
||||||
|
@Param(description = "the Zone ID")
|
||||||
|
private String zoneId;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.ZONE_NAME)
|
||||||
|
@Param(description = "the Zone name")
|
||||||
|
private String zoneName;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.ACCOUNT)
|
||||||
|
@Param(description = "the account name")
|
||||||
|
private String accountName;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.ACCOUNT_ID)
|
||||||
|
@Param(description = "the ID of account")
|
||||||
|
private String accountId;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.VIRTUAL_MACHINE_ID)
|
||||||
|
@Param(description = "the ID of the imported VM (after task is completed)")
|
||||||
|
private String virtualMachineId;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.DISPLAY_NAME)
|
||||||
|
@Param(description = "the display name of the importing VM")
|
||||||
|
private String displayName;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.VCENTER)
|
||||||
|
@Param(description = "the vcenter name of the importing VM task")
|
||||||
|
private String vcenter;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.DATACENTER_NAME)
|
||||||
|
@Param(description = "the datacenter name of the importing VM task")
|
||||||
|
private String datacenterName;
|
||||||
|
|
||||||
|
@SerializedName("sourcevmname")
|
||||||
|
@Param(description = "the source VM name")
|
||||||
|
private String sourceVMName;
|
||||||
|
|
||||||
|
@SerializedName("step")
|
||||||
|
@Param(description = "the current step on the importing VM task")
|
||||||
|
private String step;
|
||||||
|
|
||||||
|
@SerializedName("stepduration")
|
||||||
|
@Param(description = "the duration of the current step")
|
||||||
|
private String stepDuration;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.DURATION)
|
||||||
|
@Param(description = "the total task duration")
|
||||||
|
private String duration;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.DESCRIPTION)
|
||||||
|
@Param(description = "the current step description on the importing VM task")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.CONVERT_INSTANCE_HOST_ID)
|
||||||
|
@Param(description = "the ID of the host on which the instance is being converted")
|
||||||
|
private String convertInstanceHostId;
|
||||||
|
|
||||||
|
@SerializedName("convertinstancehostname")
|
||||||
|
@Param(description = "the name of the host on which the instance is being converted")
|
||||||
|
private String convertInstanceHostName;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.CREATED)
|
||||||
|
@Param(description = "the create date of the importing task")
|
||||||
|
private Date created;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.LAST_UPDATED)
|
||||||
|
@Param(description = "the last updated date of the importing task")
|
||||||
|
private Date lastUpdated;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getZoneId() {
|
||||||
|
return zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZoneId(String zoneId) {
|
||||||
|
this.zoneId = zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getZoneName() {
|
||||||
|
return zoneName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZoneName(String zoneName) {
|
||||||
|
this.zoneName = zoneName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAccountName() {
|
||||||
|
return accountName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccountName(String accountName) {
|
||||||
|
this.accountName = accountName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAccountId() {
|
||||||
|
return accountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccountId(String accountId) {
|
||||||
|
this.accountId = accountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVirtualMachineId() {
|
||||||
|
return virtualMachineId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVirtualMachineId(String virtualMachineId) {
|
||||||
|
this.virtualMachineId = virtualMachineId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisplayName(String displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVcenter() {
|
||||||
|
return vcenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVcenter(String vcenter) {
|
||||||
|
this.vcenter = vcenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDatacenterName() {
|
||||||
|
return datacenterName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDatacenterName(String datacenterName) {
|
||||||
|
this.datacenterName = datacenterName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceVMName() {
|
||||||
|
return sourceVMName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSourceVMName(String sourceVMName) {
|
||||||
|
this.sourceVMName = sourceVMName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStep() {
|
||||||
|
return step;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStep(String step) {
|
||||||
|
this.step = step;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStepDuration() {
|
||||||
|
return stepDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStepDuration(String stepDuration) {
|
||||||
|
this.stepDuration = stepDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDuration() {
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDuration(String duration) {
|
||||||
|
this.duration = duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConvertInstanceHostId() {
|
||||||
|
return convertInstanceHostId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConvertInstanceHostId(String convertInstanceHostId) {
|
||||||
|
this.convertInstanceHostId = convertInstanceHostId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConvertInstanceHostName() {
|
||||||
|
return convertInstanceHostName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConvertInstanceHostName(String convertInstanceHostName) {
|
||||||
|
this.convertInstanceHostName = convertInstanceHostName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreated() {
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreated(Date created) {
|
||||||
|
this.created = created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getLastUpdated() {
|
||||||
|
return lastUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastUpdated(Date lastUpdated) {
|
||||||
|
this.lastUpdated = lastUpdated;
|
||||||
|
}
|
||||||
|
}
|
||||||
28
api/src/main/java/org/apache/cloudstack/vm/ImportVmTask.java
Normal file
28
api/src/main/java/org/apache/cloudstack/vm/ImportVmTask.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.apache.cloudstack.vm;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.Identity;
|
||||||
|
import org.apache.cloudstack.api.InternalIdentity;
|
||||||
|
|
||||||
|
public interface ImportVmTask extends Identity, InternalIdentity {
|
||||||
|
enum Step {
|
||||||
|
Prepare, CloningInstance, ConvertingInstance, Importing, Cleaning, Completed
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
// 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 org.apache.cloudstack.vm;
|
||||||
|
|
||||||
|
import com.cloud.dc.DataCenter;
|
||||||
|
import com.cloud.host.Host;
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
import org.apache.cloudstack.api.command.admin.vm.ListImportVMTasksCmd;
|
||||||
|
import org.apache.cloudstack.api.response.ImportVMTaskResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
|
|
||||||
|
public interface ImportVmTasksManager {
|
||||||
|
|
||||||
|
ListResponse<ImportVMTaskResponse> listImportVMTasks(ListImportVMTasksCmd cmd);
|
||||||
|
|
||||||
|
ImportVmTask createImportVMTaskRecord(DataCenter zone, Account owner, long userId, String displayName,
|
||||||
|
String vcenter, String datacenterName, String sourceVMName,
|
||||||
|
Host convertHost, Host importHost);
|
||||||
|
|
||||||
|
void updateImportVMTaskStep(ImportVmTask importVMTaskVO, DataCenter zone, Account owner, Host convertHost,
|
||||||
|
Host importHost, Long vmId, ImportVmTask.Step step);
|
||||||
|
|
||||||
|
boolean removeImportVMTask(long taskId);
|
||||||
|
}
|
||||||
@ -23,30 +23,37 @@ import com.cloud.hypervisor.Hypervisor;
|
|||||||
public class ConvertInstanceCommand extends Command {
|
public class ConvertInstanceCommand extends Command {
|
||||||
|
|
||||||
private RemoteInstanceTO sourceInstance;
|
private RemoteInstanceTO sourceInstance;
|
||||||
|
private String originalVMName;
|
||||||
private Hypervisor.HypervisorType destinationHypervisorType;
|
private Hypervisor.HypervisorType destinationHypervisorType;
|
||||||
private DataStoreTO conversionTemporaryLocation;
|
private DataStoreTO conversionTemporaryLocation;
|
||||||
private String templateDirOnConversionLocation;
|
private String templateDirOnConversionLocation;
|
||||||
private boolean checkConversionSupport;
|
private boolean checkConversionSupport;
|
||||||
private boolean exportOvfToConversionLocation;
|
private boolean exportOvfToConversionLocation;
|
||||||
private int threadsCountToExportOvf = 0;
|
private int threadsCountToExportOvf = 0;
|
||||||
|
private String extraParams;
|
||||||
|
|
||||||
public ConvertInstanceCommand() {
|
public ConvertInstanceCommand() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConvertInstanceCommand(RemoteInstanceTO sourceInstance, Hypervisor.HypervisorType destinationHypervisorType, DataStoreTO conversionTemporaryLocation,
|
public ConvertInstanceCommand(RemoteInstanceTO sourceInstance, Hypervisor.HypervisorType destinationHypervisorType, DataStoreTO conversionTemporaryLocation,
|
||||||
String templateDirOnConversionLocation, boolean checkConversionSupport, boolean exportOvfToConversionLocation) {
|
String templateDirOnConversionLocation, boolean checkConversionSupport, boolean exportOvfToConversionLocation, String sourceVMName) {
|
||||||
this.sourceInstance = sourceInstance;
|
this.sourceInstance = sourceInstance;
|
||||||
this.destinationHypervisorType = destinationHypervisorType;
|
this.destinationHypervisorType = destinationHypervisorType;
|
||||||
this.conversionTemporaryLocation = conversionTemporaryLocation;
|
this.conversionTemporaryLocation = conversionTemporaryLocation;
|
||||||
this.templateDirOnConversionLocation = templateDirOnConversionLocation;
|
this.templateDirOnConversionLocation = templateDirOnConversionLocation;
|
||||||
this.checkConversionSupport = checkConversionSupport;
|
this.checkConversionSupport = checkConversionSupport;
|
||||||
this.exportOvfToConversionLocation = exportOvfToConversionLocation;
|
this.exportOvfToConversionLocation = exportOvfToConversionLocation;
|
||||||
|
this.originalVMName = sourceVMName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RemoteInstanceTO getSourceInstance() {
|
public RemoteInstanceTO getSourceInstance() {
|
||||||
return sourceInstance;
|
return sourceInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getOriginalVMName() {
|
||||||
|
return originalVMName;
|
||||||
|
}
|
||||||
|
|
||||||
public Hypervisor.HypervisorType getDestinationHypervisorType() {
|
public Hypervisor.HypervisorType getDestinationHypervisorType() {
|
||||||
return destinationHypervisorType;
|
return destinationHypervisorType;
|
||||||
}
|
}
|
||||||
@ -75,6 +82,14 @@ public class ConvertInstanceCommand extends Command {
|
|||||||
this.threadsCountToExportOvf = threadsCountToExportOvf;
|
this.threadsCountToExportOvf = threadsCountToExportOvf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getExtraParams() {
|
||||||
|
return extraParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExtraParams(String extraParams) {
|
||||||
|
this.extraParams = extraParams;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean executeInSequence() {
|
public boolean executeInSequence() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -27,17 +27,20 @@ public class ImportConvertedInstanceCommand extends Command {
|
|||||||
private List<String> destinationStoragePools;
|
private List<String> destinationStoragePools;
|
||||||
private DataStoreTO conversionTemporaryLocation;
|
private DataStoreTO conversionTemporaryLocation;
|
||||||
private String temporaryConvertUuid;
|
private String temporaryConvertUuid;
|
||||||
|
private boolean forceConvertToPool;
|
||||||
|
|
||||||
public ImportConvertedInstanceCommand() {
|
public ImportConvertedInstanceCommand() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImportConvertedInstanceCommand(RemoteInstanceTO sourceInstance,
|
public ImportConvertedInstanceCommand(RemoteInstanceTO sourceInstance,
|
||||||
List<String> destinationStoragePools,
|
List<String> destinationStoragePools,
|
||||||
DataStoreTO conversionTemporaryLocation, String temporaryConvertUuid) {
|
DataStoreTO conversionTemporaryLocation, String temporaryConvertUuid,
|
||||||
|
boolean forceConvertToPool) {
|
||||||
this.sourceInstance = sourceInstance;
|
this.sourceInstance = sourceInstance;
|
||||||
this.destinationStoragePools = destinationStoragePools;
|
this.destinationStoragePools = destinationStoragePools;
|
||||||
this.conversionTemporaryLocation = conversionTemporaryLocation;
|
this.conversionTemporaryLocation = conversionTemporaryLocation;
|
||||||
this.temporaryConvertUuid = temporaryConvertUuid;
|
this.temporaryConvertUuid = temporaryConvertUuid;
|
||||||
|
this.forceConvertToPool = forceConvertToPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RemoteInstanceTO getSourceInstance() {
|
public RemoteInstanceTO getSourceInstance() {
|
||||||
@ -56,6 +59,10 @@ public class ImportConvertedInstanceCommand extends Command {
|
|||||||
return temporaryConvertUuid;
|
return temporaryConvertUuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isForceConvertToPool() {
|
||||||
|
return forceConvertToPool;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean executeInSequence() {
|
public boolean executeInSequence() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
259
engine/schema/src/main/java/com/cloud/vm/ImportVMTaskVO.java
Normal file
259
engine/schema/src/main/java/com/cloud/vm/ImportVMTaskVO.java
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
//
|
||||||
|
// 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.vm;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.vm.ImportVmTask;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.Temporal;
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "import_vm_task")
|
||||||
|
public class ImportVMTaskVO implements ImportVmTask {
|
||||||
|
|
||||||
|
public ImportVMTaskVO(long zoneId, long accountId, long userId, String displayName,
|
||||||
|
String vcenter, String datacenter, String sourceVMName, long convertHostId, long importHostId) {
|
||||||
|
this.zoneId = zoneId;
|
||||||
|
this.accountId = accountId;
|
||||||
|
this.userId = userId;
|
||||||
|
this.displayName = displayName;
|
||||||
|
this.vcenter = vcenter;
|
||||||
|
this.datacenter = datacenter;
|
||||||
|
this.sourceVMName = sourceVMName;
|
||||||
|
this.step = Step.Prepare;
|
||||||
|
this.uuid = UUID.randomUUID().toString();
|
||||||
|
this.convertHostId = convertHostId;
|
||||||
|
this.importHostId = importHostId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImportVMTaskVO() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "id")
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@Column(name = "uuid")
|
||||||
|
private String uuid;
|
||||||
|
|
||||||
|
@Column(name = "zone_id")
|
||||||
|
private long zoneId;
|
||||||
|
|
||||||
|
@Column(name = "account_id")
|
||||||
|
private long accountId;
|
||||||
|
|
||||||
|
@Column(name = "user_id")
|
||||||
|
private long userId;
|
||||||
|
|
||||||
|
@Column(name = "vm_id")
|
||||||
|
private Long vmId;
|
||||||
|
@Column(name = "display_name")
|
||||||
|
private String displayName;
|
||||||
|
|
||||||
|
@Column(name = "vcenter")
|
||||||
|
private String vcenter;
|
||||||
|
|
||||||
|
@Column(name = "datacenter")
|
||||||
|
private String datacenter;
|
||||||
|
|
||||||
|
@Column(name = "source_vm_name")
|
||||||
|
private String sourceVMName;
|
||||||
|
|
||||||
|
@Column(name = "convert_host_id")
|
||||||
|
private long convertHostId;
|
||||||
|
|
||||||
|
@Column(name = "import_host_id")
|
||||||
|
private long importHostId;
|
||||||
|
|
||||||
|
@Column(name = "step")
|
||||||
|
private Step step;
|
||||||
|
|
||||||
|
@Column(name = "description")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@Column(name = "duration")
|
||||||
|
private Long duration;
|
||||||
|
|
||||||
|
@Column(name = "created")
|
||||||
|
@Temporal(value = TemporalType.TIMESTAMP)
|
||||||
|
private Date created;
|
||||||
|
|
||||||
|
@Column(name = "updated")
|
||||||
|
@Temporal(value = TemporalType.TIMESTAMP)
|
||||||
|
private Date updated;
|
||||||
|
|
||||||
|
@Column(name = "removed")
|
||||||
|
@Temporal(value = TemporalType.TIMESTAMP)
|
||||||
|
private Date removed;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuid(String uuid) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getZoneId() {
|
||||||
|
return zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZoneId(long zoneId) {
|
||||||
|
this.zoneId = zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getAccountId() {
|
||||||
|
return accountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccountId(long accountId) {
|
||||||
|
this.accountId = accountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(long userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getVmId() {
|
||||||
|
return vmId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVmId(Long vmId) {
|
||||||
|
this.vmId = vmId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisplayName(String displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVcenter() {
|
||||||
|
return vcenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVcenter(String vcenter) {
|
||||||
|
this.vcenter = vcenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDatacenter() {
|
||||||
|
return datacenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDatacenter(String datacenter) {
|
||||||
|
this.datacenter = datacenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceVMName() {
|
||||||
|
return sourceVMName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSourceVMName(String sourceVMName) {
|
||||||
|
this.sourceVMName = sourceVMName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getConvertHostId() {
|
||||||
|
return convertHostId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConvertHostId(long convertHostId) {
|
||||||
|
this.convertHostId = convertHostId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getImportHostId() {
|
||||||
|
return importHostId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImportHostId(long importHostId) {
|
||||||
|
this.importHostId = importHostId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Step getStep() {
|
||||||
|
return step;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStep(Step step) {
|
||||||
|
this.step = step;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDuration() {
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDuration(Long duration) {
|
||||||
|
this.duration = duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreated() {
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreated(Date created) {
|
||||||
|
this.created = created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getUpdated() {
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdated(Date updated) {
|
||||||
|
this.updated = updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getRemoved() {
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemoved(Date removed) {
|
||||||
|
this.removed = removed;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
//
|
||||||
|
// 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.vm.dao;
|
||||||
|
|
||||||
|
import com.cloud.utils.db.GenericDao;
|
||||||
|
import com.cloud.vm.ImportVMTaskVO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface ImportVMTaskDao extends GenericDao<ImportVMTaskVO, Long> {
|
||||||
|
|
||||||
|
List<ImportVMTaskVO> listImportVMTasks(Long zoneId, Long accountId, String vcenter, Long convertHostId, boolean showCompleted);
|
||||||
|
}
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
// 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.vm.dao;
|
||||||
|
|
||||||
|
import com.cloud.utils.db.GenericDaoBase;
|
||||||
|
import com.cloud.utils.db.SearchBuilder;
|
||||||
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
|
import com.cloud.vm.ImportVMTaskVO;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ImportVMTaskDaoImpl extends GenericDaoBase<ImportVMTaskVO, Long> implements ImportVMTaskDao {
|
||||||
|
|
||||||
|
private SearchBuilder<ImportVMTaskVO> AllFieldsSearch;
|
||||||
|
|
||||||
|
public ImportVMTaskDaoImpl() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
void init() {
|
||||||
|
AllFieldsSearch = createSearchBuilder();
|
||||||
|
AllFieldsSearch.and("zoneId", AllFieldsSearch.entity().getZoneId(), SearchCriteria.Op.EQ);
|
||||||
|
AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
|
||||||
|
AllFieldsSearch.and("vcenter", AllFieldsSearch.entity().getVcenter(), SearchCriteria.Op.EQ);
|
||||||
|
AllFieldsSearch.and("convertHostId", AllFieldsSearch.entity().getConvertHostId(), SearchCriteria.Op.EQ);
|
||||||
|
AllFieldsSearch.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ImportVMTaskVO> listImportVMTasks(Long zoneId, Long accountId, String vcenter, Long convertHostId, boolean showCompleted) {
|
||||||
|
SearchCriteria<ImportVMTaskVO> sc = AllFieldsSearch.create();
|
||||||
|
if (zoneId != null) {
|
||||||
|
sc.setParameters("zoneId", zoneId);
|
||||||
|
}
|
||||||
|
if (accountId != null) {
|
||||||
|
sc.setParameters("accountId", accountId);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(vcenter)) {
|
||||||
|
sc.setParameters("vcenter", vcenter);
|
||||||
|
}
|
||||||
|
if (convertHostId != null) {
|
||||||
|
sc.setParameters("convertHostId", convertHostId);
|
||||||
|
}
|
||||||
|
return showCompleted ? listIncludingRemovedBy(sc) : listBy(sc);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -309,4 +309,5 @@
|
|||||||
<bean id="gpuCardDaoImpl" class="com.cloud.gpu.dao.GpuCardDaoImpl" />
|
<bean id="gpuCardDaoImpl" class="com.cloud.gpu.dao.GpuCardDaoImpl" />
|
||||||
<bean id="gpuDeviceDaoImpl" class="com.cloud.gpu.dao.GpuDeviceDaoImpl" />
|
<bean id="gpuDeviceDaoImpl" class="com.cloud.gpu.dao.GpuDeviceDaoImpl" />
|
||||||
<bean id="vgpuProfileDaoImpl" class="com.cloud.gpu.dao.VgpuProfileDaoImpl" />
|
<bean id="vgpuProfileDaoImpl" class="com.cloud.gpu.dao.VgpuProfileDaoImpl" />
|
||||||
|
<bean id="importVMTaskDaoImpl" class="com.cloud.vm.dao.ImportVMTaskDaoImpl" />
|
||||||
</beans>
|
</beans>
|
||||||
|
|||||||
@ -48,5 +48,35 @@ CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backup_repository', 'cross_zone_inst
|
|||||||
UPDATE `cloud`.`storage_pool_details` SET display = 0 WHERE name LIKE '%password%';
|
UPDATE `cloud`.`storage_pool_details` SET display = 0 WHERE name LIKE '%password%';
|
||||||
UPDATE `cloud`.`storage_pool_details` SET display = 0 WHERE name LIKE '%token%';
|
UPDATE `cloud`.`storage_pool_details` SET display = 0 WHERE name LIKE '%token%';
|
||||||
|
|
||||||
|
-- VMware to KVM migration improvements
|
||||||
|
CREATE TABLE IF NOT EXISTS `cloud`.`import_vm_task`(
|
||||||
|
`id` bigint unsigned NOT NULL auto_increment COMMENT 'id',
|
||||||
|
`uuid` varchar(40),
|
||||||
|
`zone_id` bigint unsigned NOT NULL COMMENT 'Zone ID',
|
||||||
|
`account_id` bigint unsigned NOT NULL COMMENT 'Account ID',
|
||||||
|
`user_id` bigint unsigned NOT NULL COMMENT 'User ID',
|
||||||
|
`vm_id` bigint unsigned COMMENT 'VM ID',
|
||||||
|
`display_name` varchar(255) COMMENT 'Display VM Name',
|
||||||
|
`vcenter` varchar(255) COMMENT 'VCenter',
|
||||||
|
`datacenter` varchar(255) COMMENT 'VCenter Datacenter name',
|
||||||
|
`source_vm_name` varchar(255) COMMENT 'Source VM name on vCenter',
|
||||||
|
`convert_host_id` bigint unsigned COMMENT 'Convert Host ID',
|
||||||
|
`import_host_id` bigint unsigned COMMENT 'Import Host ID',
|
||||||
|
`step` varchar(20) NOT NULL COMMENT 'Importing VM Task Step',
|
||||||
|
`description` varchar(255) COMMENT 'Importing VM Task Description',
|
||||||
|
`duration` bigint unsigned COMMENT 'Duration in milliseconds for the completed tasks',
|
||||||
|
`created` datetime NOT NULL COMMENT 'date created',
|
||||||
|
`updated` datetime COMMENT 'date updated if not null',
|
||||||
|
`removed` datetime COMMENT 'date removed if not null',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
CONSTRAINT `fk_import_vm_task__zone_id` FOREIGN KEY `fk_import_vm_task__zone_id` (`zone_id`) REFERENCES `data_center`(`id`) ON DELETE CASCADE,
|
||||||
|
CONSTRAINT `fk_import_vm_task__account_id` FOREIGN KEY `fk_import_vm_task__account_id` (`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE,
|
||||||
|
CONSTRAINT `fk_import_vm_task__user_id` FOREIGN KEY `fk_import_vm_task__user_id` (`user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE,
|
||||||
|
CONSTRAINT `fk_import_vm_task__vm_id` FOREIGN KEY `fk_import_vm_task__vm_id` (`vm_id`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE,
|
||||||
|
CONSTRAINT `fk_import_vm_task__convert_host_id` FOREIGN KEY `fk_import_vm_task__convert_host_id` (`convert_host_id`) REFERENCES `host`(`id`) ON DELETE CASCADE,
|
||||||
|
CONSTRAINT `fk_import_vm_task__import_host_id` FOREIGN KEY `fk_import_vm_task__import_host_id` (`import_host_id`) REFERENCES `host`(`id`) ON DELETE CASCADE,
|
||||||
|
INDEX `i_import_vm_task__zone_id`(`zone_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
CALL `cloud`.`INSERT_EXTENSION_IF_NOT_EXISTS`('MaaS', 'Baremetal Extension for Canonical MaaS written in Python', 'MaaS/maas.py');
|
CALL `cloud`.`INSERT_EXTENSION_IF_NOT_EXISTS`('MaaS', 'Baremetal Extension for Canonical MaaS written in Python', 'MaaS/maas.py');
|
||||||
CALL `cloud`.`INSERT_EXTENSION_DETAIL_IF_NOT_EXISTS`('MaaS', 'orchestratorrequirespreparevm', 'true', 0);
|
CALL `cloud`.`INSERT_EXTENSION_DETAIL_IF_NOT_EXISTS`('MaaS', 'orchestratorrequirespreparevm', 'true', 0);
|
||||||
|
|||||||
@ -882,6 +882,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
protected StorageSubsystemCommandHandler storageHandler;
|
protected StorageSubsystemCommandHandler storageHandler;
|
||||||
|
|
||||||
private boolean convertInstanceVerboseMode = false;
|
private boolean convertInstanceVerboseMode = false;
|
||||||
|
private String[] convertInstanceEnv = null;
|
||||||
protected boolean dpdkSupport = false;
|
protected boolean dpdkSupport = false;
|
||||||
protected String dpdkOvsPath;
|
protected String dpdkOvsPath;
|
||||||
protected String directDownloadTemporaryDownloadPath;
|
protected String directDownloadTemporaryDownloadPath;
|
||||||
@ -946,6 +947,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
return convertInstanceVerboseMode;
|
return convertInstanceVerboseMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String[] getConvertInstanceEnv() {
|
||||||
|
return convertInstanceEnv;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines resource's public and private network interface according to what is configured in agent.properties.
|
* Defines resource's public and private network interface according to what is configured in agent.properties.
|
||||||
*/
|
*/
|
||||||
@ -1146,6 +1151,11 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
|
|
||||||
convertInstanceVerboseMode = BooleanUtils.isTrue(AgentPropertiesFileHandler.getPropertyValue(AgentProperties.VIRTV2V_VERBOSE_ENABLED));
|
convertInstanceVerboseMode = BooleanUtils.isTrue(AgentPropertiesFileHandler.getPropertyValue(AgentProperties.VIRTV2V_VERBOSE_ENABLED));
|
||||||
|
|
||||||
|
String convertEnvTmpDir = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.CONVERT_ENV_TMPDIR);
|
||||||
|
String convertEnvVirtv2vTmpDir = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.CONVERT_ENV_VIRTV2V_TMPDIR);
|
||||||
|
|
||||||
|
setConvertInstanceEnv(convertEnvTmpDir, convertEnvVirtv2vTmpDir);
|
||||||
|
|
||||||
pool = (String)params.get("pool");
|
pool = (String)params.get("pool");
|
||||||
if (pool == null) {
|
if (pool == null) {
|
||||||
pool = "/root";
|
pool = "/root";
|
||||||
@ -1422,6 +1432,22 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setConvertInstanceEnv(String convertEnvTmpDir, String convertEnvVirtv2vTmpDir) {
|
||||||
|
if (StringUtils.isAllBlank(convertEnvTmpDir, convertEnvVirtv2vTmpDir)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(convertEnvTmpDir) && StringUtils.isNotBlank(convertEnvVirtv2vTmpDir)) {
|
||||||
|
convertInstanceEnv = new String[2];
|
||||||
|
convertInstanceEnv[0] = String.format("%s=%s", "TMPDIR", convertEnvTmpDir);
|
||||||
|
convertInstanceEnv[1] = String.format("%s=%s", "VIRT_V2V_TMPDIR", convertEnvVirtv2vTmpDir);
|
||||||
|
} else {
|
||||||
|
convertInstanceEnv = new String[1];
|
||||||
|
String key = StringUtils.isNotBlank(convertEnvTmpDir) ? "TMPDIR" : "VIRT_V2V_TMPDIR";
|
||||||
|
String value = StringUtils.isNotBlank(convertEnvTmpDir) ? convertEnvTmpDir : convertEnvVirtv2vTmpDir;
|
||||||
|
convertInstanceEnv[0] = String.format("%s=%s", key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a string containing whitespace-separated CPU feature names and converts it into a list.
|
* Parses a string containing whitespace-separated CPU feature names and converts it into a list.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -20,6 +20,7 @@ package com.cloud.hypervisor.kvm.resource.wrapper;
|
|||||||
|
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@ -57,11 +58,13 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
Hypervisor.HypervisorType destinationHypervisorType = cmd.getDestinationHypervisorType();
|
Hypervisor.HypervisorType destinationHypervisorType = cmd.getDestinationHypervisorType();
|
||||||
DataStoreTO conversionTemporaryLocation = cmd.getConversionTemporaryLocation();
|
DataStoreTO conversionTemporaryLocation = cmd.getConversionTemporaryLocation();
|
||||||
long timeout = (long) cmd.getWait() * 1000;
|
long timeout = (long) cmd.getWait() * 1000;
|
||||||
|
String extraParams = cmd.getExtraParams();
|
||||||
|
String originalVMName = cmd.getOriginalVMName(); // For logging purposes, as the sourceInstance may have been cloned
|
||||||
|
|
||||||
if (cmd.getCheckConversionSupport() && !serverResource.hostSupportsInstanceConversion()) {
|
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%s on the host before attempting the instance conversion.", sourceInstanceName, serverResource.isUbuntuOrDebianHost()? ", nbdkit" : "");
|
"Please install virt-v2v%s on the host before attempting the instance conversion.", sourceInstanceName, serverResource.isUbuntuOrDebianHost()? ", nbdkit" : "");
|
||||||
logger.info(msg);
|
logger.info(String.format("(%s) %s", originalVMName, msg));
|
||||||
return new Answer(cmd, false, msg);
|
return new Answer(cmd, false, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,25 +72,25 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
String err = destinationHypervisorType != Hypervisor.HypervisorType.KVM ?
|
String err = destinationHypervisorType != Hypervisor.HypervisorType.KVM ?
|
||||||
String.format("The destination hypervisor type is %s, KVM was expected, cannot handle it", destinationHypervisorType) :
|
String.format("The destination hypervisor type is %s, KVM was expected, cannot handle it", destinationHypervisorType) :
|
||||||
String.format("The source hypervisor type %s is not supported for KVM conversion", sourceHypervisorType);
|
String.format("The source hypervisor type %s is not supported for KVM conversion", sourceHypervisorType);
|
||||||
logger.error(err);
|
logger.error(String.format("(%s) %s", originalVMName, err));
|
||||||
return new Answer(cmd, false, err);
|
return new Answer(cmd, false, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
final KVMStoragePoolManager storagePoolMgr = serverResource.getStoragePoolMgr();
|
final KVMStoragePoolManager storagePoolMgr = serverResource.getStoragePoolMgr();
|
||||||
KVMStoragePool temporaryStoragePool = getTemporaryStoragePool(conversionTemporaryLocation, storagePoolMgr);
|
KVMStoragePool temporaryStoragePool = getTemporaryStoragePool(conversionTemporaryLocation, storagePoolMgr);
|
||||||
|
|
||||||
logger.info(String.format("Attempting to convert the instance %s from %s to KVM",
|
logger.info(String.format("(%s) Attempting to convert the instance %s from %s to KVM",
|
||||||
sourceInstanceName, sourceHypervisorType));
|
originalVMName, sourceInstanceName, sourceHypervisorType));
|
||||||
final String temporaryConvertPath = temporaryStoragePool.getLocalPath();
|
final String temporaryConvertPath = temporaryStoragePool.getLocalPath();
|
||||||
|
|
||||||
String ovfTemplateDirOnConversionLocation;
|
String ovfTemplateDirOnConversionLocation;
|
||||||
String sourceOVFDirPath;
|
String sourceOVFDirPath;
|
||||||
boolean ovfExported = false;
|
boolean ovfExported = false;
|
||||||
if (cmd.getExportOvfToConversionLocation()) {
|
if (cmd.getExportOvfToConversionLocation()) {
|
||||||
String exportInstanceOVAUrl = getExportInstanceOVAUrl(sourceInstance);
|
String exportInstanceOVAUrl = getExportInstanceOVAUrl(sourceInstance, originalVMName);
|
||||||
if (StringUtils.isBlank(exportInstanceOVAUrl)) {
|
if (StringUtils.isBlank(exportInstanceOVAUrl)) {
|
||||||
String err = String.format("Couldn't export OVA for the VM %s, due to empty url", sourceInstanceName);
|
String err = String.format("Couldn't export OVA for the VM %s, due to empty url", sourceInstanceName);
|
||||||
logger.error(err);
|
logger.error(String.format("(%s) %s", originalVMName, err));
|
||||||
return new Answer(cmd, false, err);
|
return new Answer(cmd, false, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,10 +101,10 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
ovfTemplateDirOnConversionLocation = UUID.randomUUID().toString();
|
ovfTemplateDirOnConversionLocation = UUID.randomUUID().toString();
|
||||||
temporaryStoragePool.createFolder(ovfTemplateDirOnConversionLocation);
|
temporaryStoragePool.createFolder(ovfTemplateDirOnConversionLocation);
|
||||||
sourceOVFDirPath = String.format("%s/%s/", temporaryConvertPath, ovfTemplateDirOnConversionLocation);
|
sourceOVFDirPath = String.format("%s/%s/", temporaryConvertPath, ovfTemplateDirOnConversionLocation);
|
||||||
ovfExported = exportOVAFromVMOnVcenter(exportInstanceOVAUrl, sourceOVFDirPath, noOfThreads, timeout);
|
ovfExported = exportOVAFromVMOnVcenter(exportInstanceOVAUrl, sourceOVFDirPath, noOfThreads, originalVMName, timeout);
|
||||||
if (!ovfExported) {
|
if (!ovfExported) {
|
||||||
String err = String.format("Export OVA for the VM %s failed", sourceInstanceName);
|
String err = String.format("Export OVA for the VM %s failed", sourceInstanceName);
|
||||||
logger.error(err);
|
logger.error(String.format("(%s) %s", originalVMName, err));
|
||||||
return new Answer(cmd, false, err);
|
return new Answer(cmd, false, err);
|
||||||
}
|
}
|
||||||
sourceOVFDirPath = String.format("%s%s/", sourceOVFDirPath, sourceInstanceName);
|
sourceOVFDirPath = String.format("%s%s/", sourceOVFDirPath, sourceInstanceName);
|
||||||
@ -110,38 +113,40 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
sourceOVFDirPath = String.format("%s/%s/", temporaryConvertPath, ovfTemplateDirOnConversionLocation);
|
sourceOVFDirPath = String.format("%s/%s/", temporaryConvertPath, ovfTemplateDirOnConversionLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(String.format("Attempting to convert the OVF %s of the instance %s from %s to KVM", ovfTemplateDirOnConversionLocation, sourceInstanceName, sourceHypervisorType));
|
logger.info(String.format("(%s) Attempting to convert the OVF %s of the instance %s from %s to KVM",
|
||||||
|
originalVMName, ovfTemplateDirOnConversionLocation, sourceInstanceName, sourceHypervisorType));
|
||||||
|
|
||||||
final String temporaryConvertUuid = UUID.randomUUID().toString();
|
final String temporaryConvertUuid = UUID.randomUUID().toString();
|
||||||
boolean verboseModeEnabled = serverResource.isConvertInstanceVerboseModeEnabled();
|
boolean verboseModeEnabled = serverResource.isConvertInstanceVerboseModeEnabled();
|
||||||
|
|
||||||
boolean cleanupSecondaryStorage = false;
|
boolean cleanupSecondaryStorage = false;
|
||||||
try {
|
try {
|
||||||
boolean result = performInstanceConversion(sourceOVFDirPath, temporaryConvertPath, temporaryConvertUuid,
|
boolean result = performInstanceConversion(originalVMName, sourceOVFDirPath, temporaryConvertPath, temporaryConvertUuid,
|
||||||
timeout, verboseModeEnabled);
|
timeout, verboseModeEnabled, extraParams, serverResource);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
String err = String.format(
|
String err = String.format(
|
||||||
"The virt-v2v conversion for the OVF %s failed. Please check the agent logs " +
|
"The virt-v2v conversion for the OVF %s failed. Please check the agent logs " +
|
||||||
"for the virt-v2v output. Please try on a different kvm host which " +
|
"for the virt-v2v output. Please try on a different kvm host which " +
|
||||||
"has a different virt-v2v version.",
|
"has a different virt-v2v version.",
|
||||||
ovfTemplateDirOnConversionLocation);
|
ovfTemplateDirOnConversionLocation);
|
||||||
logger.error(err);
|
logger.error(String.format("(%s) %s", originalVMName, err));
|
||||||
return new Answer(cmd, false, err);
|
return new Answer(cmd, false, err);
|
||||||
}
|
}
|
||||||
return new ConvertInstanceAnswer(cmd, temporaryConvertUuid);
|
return new ConvertInstanceAnswer(cmd, temporaryConvertUuid);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String error = String.format("Error converting instance %s from %s, due to: %s",
|
String error = String.format("Error converting instance %s from %s, due to: %s",
|
||||||
sourceInstanceName, sourceHypervisorType, e.getMessage());
|
sourceInstanceName, sourceHypervisorType, e.getMessage());
|
||||||
logger.error(error, e);
|
logger.error(String.format("(%s) %s", originalVMName, error), e);
|
||||||
cleanupSecondaryStorage = true;
|
cleanupSecondaryStorage = true;
|
||||||
return new Answer(cmd, false, error);
|
return new Answer(cmd, false, error);
|
||||||
} finally {
|
} finally {
|
||||||
if (ovfExported && StringUtils.isNotBlank(ovfTemplateDirOnConversionLocation)) {
|
if (ovfExported && StringUtils.isNotBlank(ovfTemplateDirOnConversionLocation)) {
|
||||||
String sourceOVFDir = String.format("%s/%s", temporaryConvertPath, ovfTemplateDirOnConversionLocation);
|
String sourceOVFDir = String.format("%s/%s", temporaryConvertPath, ovfTemplateDirOnConversionLocation);
|
||||||
logger.debug("Cleaning up exported OVA at dir " + sourceOVFDir);
|
logger.debug("({}) Cleaning up exported OVA at dir: {}", originalVMName, sourceOVFDir);
|
||||||
FileUtil.deletePath(sourceOVFDir);
|
FileUtil.deletePath(sourceOVFDir);
|
||||||
}
|
}
|
||||||
if (cleanupSecondaryStorage && conversionTemporaryLocation instanceof NfsTO) {
|
if (cleanupSecondaryStorage && conversionTemporaryLocation instanceof NfsTO) {
|
||||||
logger.debug("Cleaning up secondary storage temporary location");
|
logger.debug("({}) Cleaning up secondary storage temporary location", originalVMName);
|
||||||
storagePoolMgr.deleteStoragePool(temporaryStoragePool.getType(), temporaryStoragePool.getUuid());
|
storagePoolMgr.deleteStoragePool(temporaryStoragePool.getType(), temporaryStoragePool.getUuid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,15 +168,15 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
supportedInstanceConvertSourceHypervisors.contains(sourceHypervisorType);
|
supportedInstanceConvertSourceHypervisors.contains(sourceHypervisorType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getExportInstanceOVAUrl(RemoteInstanceTO sourceInstance) {
|
private String getExportInstanceOVAUrl(RemoteInstanceTO sourceInstance, String originalVMName) {
|
||||||
String url = null;
|
String url = null;
|
||||||
if (sourceInstance.getHypervisorType() == Hypervisor.HypervisorType.VMware) {
|
if (sourceInstance.getHypervisorType() == Hypervisor.HypervisorType.VMware) {
|
||||||
url = getExportOVAUrlFromRemoteInstance(sourceInstance);
|
url = getExportOVAUrlFromRemoteInstance(sourceInstance, originalVMName);
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getExportOVAUrlFromRemoteInstance(RemoteInstanceTO vmwareInstance) {
|
private String getExportOVAUrlFromRemoteInstance(RemoteInstanceTO vmwareInstance, String originalVMName) {
|
||||||
String vcenter = vmwareInstance.getVcenterHost();
|
String vcenter = vmwareInstance.getVcenterHost();
|
||||||
String username = vmwareInstance.getVcenterUsername();
|
String username = vmwareInstance.getVcenterUsername();
|
||||||
String password = vmwareInstance.getVcenterPassword();
|
String password = vmwareInstance.getVcenterPassword();
|
||||||
@ -182,7 +187,7 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
String encodedUsername = encodeUsername(username);
|
String encodedUsername = encodeUsername(username);
|
||||||
String encodedPassword = encodeUsername(password);
|
String encodedPassword = encodeUsername(password);
|
||||||
if (StringUtils.isNotBlank(path)) {
|
if (StringUtils.isNotBlank(path)) {
|
||||||
logger.info("VM path: {}", path);
|
logger.info("({}) VM path: {}", originalVMName, path);
|
||||||
return String.format("vi://%s:%s@%s/%s/%s/%s",
|
return String.format("vi://%s:%s@%s/%s/%s/%s",
|
||||||
encodedUsername, encodedPassword, vcenter, datacenter, path, vm);
|
encodedUsername, encodedPassword, vcenter, datacenter, path, vm);
|
||||||
}
|
}
|
||||||
@ -201,7 +206,7 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
private boolean exportOVAFromVMOnVcenter(String vmExportUrl,
|
private boolean exportOVAFromVMOnVcenter(String vmExportUrl,
|
||||||
String targetOvfDir,
|
String targetOvfDir,
|
||||||
int noOfThreads,
|
int noOfThreads,
|
||||||
long timeout) {
|
String originalVMName, long timeout) {
|
||||||
Script script = new Script("ovftool", timeout, logger);
|
Script script = new Script("ovftool", timeout, logger);
|
||||||
script.add("--noSSLVerify");
|
script.add("--noSSLVerify");
|
||||||
if (noOfThreads > 1) {
|
if (noOfThreads > 1) {
|
||||||
@ -210,17 +215,18 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
script.add(vmExportUrl);
|
script.add(vmExportUrl);
|
||||||
script.add(targetOvfDir);
|
script.add(targetOvfDir);
|
||||||
|
|
||||||
String logPrefix = "export ovf";
|
String logPrefix = String.format("(%s) export ovf", originalVMName);
|
||||||
OutputInterpreter.LineByLineOutputLogger outputLogger = new OutputInterpreter.LineByLineOutputLogger(logger, logPrefix);
|
OutputInterpreter.LineByLineOutputLogger outputLogger = new OutputInterpreter.LineByLineOutputLogger(logger, logPrefix);
|
||||||
script.execute(outputLogger);
|
script.execute(outputLogger);
|
||||||
int exitValue = script.getExitValue();
|
int exitValue = script.getExitValue();
|
||||||
return exitValue == 0;
|
return exitValue == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean performInstanceConversion(String sourceOVFDirPath,
|
protected boolean performInstanceConversion(String originalVMName, String sourceOVFDirPath,
|
||||||
String temporaryConvertFolder,
|
String temporaryConvertFolder,
|
||||||
String temporaryConvertUuid,
|
String temporaryConvertUuid,
|
||||||
long timeout, boolean verboseModeEnabled) {
|
long timeout, boolean verboseModeEnabled, String extraParams,
|
||||||
|
LibvirtComputingResource serverResource) {
|
||||||
Script script = new Script("virt-v2v", timeout, logger);
|
Script script = new Script("virt-v2v", timeout, logger);
|
||||||
script.add("--root", "first");
|
script.add("--root", "first");
|
||||||
script.add("-i", "ova");
|
script.add("-i", "ova");
|
||||||
@ -232,14 +238,33 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
if (verboseModeEnabled) {
|
if (verboseModeEnabled) {
|
||||||
script.add("-v");
|
script.add("-v");
|
||||||
}
|
}
|
||||||
|
if (StringUtils.isNotBlank(extraParams)) {
|
||||||
|
addExtraParamsToScript(extraParams, script);
|
||||||
|
}
|
||||||
|
|
||||||
String logPrefix = String.format("virt-v2v ovf source: %s progress", sourceOVFDirPath);
|
String logPrefix = String.format("(%s) virt-v2v ovf source: %s progress", originalVMName, sourceOVFDirPath);
|
||||||
OutputInterpreter.LineByLineOutputLogger outputLogger = new OutputInterpreter.LineByLineOutputLogger(logger, logPrefix);
|
OutputInterpreter.LineByLineOutputLogger outputLogger = new OutputInterpreter.LineByLineOutputLogger(logger, logPrefix);
|
||||||
script.execute(outputLogger);
|
script.execute(outputLogger);
|
||||||
int exitValue = script.getExitValue();
|
int exitValue = script.getExitValue();
|
||||||
return exitValue == 0;
|
return exitValue == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void addExtraParamsToScript(String extraParams, Script script) {
|
||||||
|
List<String> separatedArgs = Arrays.asList(extraParams.split(" "));
|
||||||
|
int i = 0;
|
||||||
|
while (i < separatedArgs.size()) {
|
||||||
|
String current = separatedArgs.get(i);
|
||||||
|
String next = (i + 1) < separatedArgs.size() ? separatedArgs.get(i + 1) : null;
|
||||||
|
if (next == null || next.startsWith("-")) {
|
||||||
|
script.add(current);
|
||||||
|
i = i + 1;
|
||||||
|
} else {
|
||||||
|
script.add(current, next);
|
||||||
|
i = i + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected String encodeUsername(String username) {
|
protected String encodeUsername(String username) {
|
||||||
return URLEncoder.encode(username, Charset.defaultCharset());
|
return URLEncoder.encode(username, Charset.defaultCharset());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -67,6 +67,7 @@ public class LibvirtImportConvertedInstanceCommandWrapper extends CommandWrapper
|
|||||||
List<String> destinationStoragePools = cmd.getDestinationStoragePools();
|
List<String> destinationStoragePools = cmd.getDestinationStoragePools();
|
||||||
DataStoreTO conversionTemporaryLocation = cmd.getConversionTemporaryLocation();
|
DataStoreTO conversionTemporaryLocation = cmd.getConversionTemporaryLocation();
|
||||||
final String temporaryConvertUuid = cmd.getTemporaryConvertUuid();
|
final String temporaryConvertUuid = cmd.getTemporaryConvertUuid();
|
||||||
|
final boolean forceConvertToPool = cmd.isForceConvertToPool();
|
||||||
|
|
||||||
final KVMStoragePoolManager storagePoolMgr = serverResource.getStoragePoolMgr();
|
final KVMStoragePoolManager storagePoolMgr = serverResource.getStoragePoolMgr();
|
||||||
KVMStoragePool temporaryStoragePool = getTemporaryStoragePool(conversionTemporaryLocation, storagePoolMgr);
|
KVMStoragePool temporaryStoragePool = getTemporaryStoragePool(conversionTemporaryLocation, storagePoolMgr);
|
||||||
@ -80,13 +81,18 @@ public class LibvirtImportConvertedInstanceCommandWrapper extends CommandWrapper
|
|||||||
getTemporaryDisksWithPrefixFromTemporaryPool(temporaryStoragePool, temporaryConvertPath, temporaryConvertUuid) :
|
getTemporaryDisksWithPrefixFromTemporaryPool(temporaryStoragePool, temporaryConvertPath, temporaryConvertUuid) :
|
||||||
getTemporaryDisksFromParsedXml(temporaryStoragePool, xmlParser, convertedBasePath);
|
getTemporaryDisksFromParsedXml(temporaryStoragePool, xmlParser, convertedBasePath);
|
||||||
|
|
||||||
List<KVMPhysicalDisk> destinationDisks = moveTemporaryDisksToDestination(temporaryDisks,
|
List<KVMPhysicalDisk> disks = null;
|
||||||
|
if (forceConvertToPool) {
|
||||||
|
// Force flag to use the conversion path, no need to move disks
|
||||||
|
disks = temporaryDisks;
|
||||||
|
} else {
|
||||||
|
disks = moveTemporaryDisksToDestination(temporaryDisks,
|
||||||
destinationStoragePools, storagePoolMgr);
|
destinationStoragePools, storagePoolMgr);
|
||||||
|
|
||||||
cleanupDisksAndDomainFromTemporaryLocation(temporaryDisks, temporaryStoragePool, temporaryConvertUuid);
|
cleanupDisksAndDomainFromTemporaryLocation(temporaryDisks, temporaryStoragePool, temporaryConvertUuid);
|
||||||
|
}
|
||||||
|
|
||||||
UnmanagedInstanceTO convertedInstanceTO = getConvertedUnmanagedInstance(temporaryConvertUuid,
|
UnmanagedInstanceTO convertedInstanceTO = getConvertedUnmanagedInstance(temporaryConvertUuid,
|
||||||
destinationDisks, xmlParser);
|
disks, xmlParser);
|
||||||
return new ImportConvertedInstanceAnswer(cmd, convertedInstanceTO);
|
return new ImportConvertedInstanceAnswer(cmd, convertedInstanceTO);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String error = String.format("Error converting instance %s from %s, due to: %s",
|
String error = String.format("Error converting instance %s from %s, due to: %s",
|
||||||
|
|||||||
@ -128,6 +128,7 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
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);
|
Mockito.when(cmd.getCheckConversionSupport()).thenReturn(checkConversionSupport);
|
||||||
|
Mockito.when(cmd.getOriginalVMName()).thenReturn(vmName);
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,8 +167,26 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
|
|
||||||
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.anyLong(), Mockito.anyBoolean());
|
Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyBoolean(), Mockito.nullable(String.class), Mockito.any(LibvirtComputingResource.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddExtraParamsToScriptSameKeysAndValues() {
|
||||||
|
Script script = Mockito.mock(Script.class);
|
||||||
|
String extraParams = "--mac 00:0c:29:e6:3d:9d:ip:192.168.0.89,192.168.0.1,24,192.168.0.254";
|
||||||
|
convertInstanceCommandWrapper.addExtraParamsToScript(extraParams, script);
|
||||||
|
Mockito.verify(script).add("--mac", "00:0c:29:e6:3d:9d:ip:192.168.0.89,192.168.0.1,24,192.168.0.254");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddExtraParamsToScriptDifferentArgs() {
|
||||||
|
Script script = Mockito.mock(Script.class);
|
||||||
|
String extraParams = "--mac 00:0c:29:e6:3d:9d:ip:192.168.0.89,192.168.0.1,24,192.168.0.254 -x -v";
|
||||||
|
convertInstanceCommandWrapper.addExtraParamsToScript(extraParams, script);
|
||||||
|
Mockito.verify(script).add("--mac", "00:0c:29:e6:3d:9d:ip:192.168.0.89,192.168.0.1,24,192.168.0.254");
|
||||||
|
Mockito.verify(script).add("-x");
|
||||||
|
Mockito.verify(script).add("-v");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,225 @@
|
|||||||
|
// 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 org.apache.cloudstack.vm;
|
||||||
|
|
||||||
|
import com.cloud.dc.DataCenter;
|
||||||
|
import com.cloud.dc.DataCenterVO;
|
||||||
|
import com.cloud.dc.dao.DataCenterDao;
|
||||||
|
import com.cloud.host.Host;
|
||||||
|
import com.cloud.host.HostVO;
|
||||||
|
import com.cloud.host.dao.HostDao;
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
import com.cloud.user.AccountService;
|
||||||
|
import com.cloud.utils.DateUtil;
|
||||||
|
import com.cloud.vm.ImportVMTaskVO;
|
||||||
|
import com.cloud.vm.UserVmVO;
|
||||||
|
import com.cloud.vm.dao.ImportVMTaskDao;
|
||||||
|
import com.cloud.vm.dao.UserVmDao;
|
||||||
|
import org.apache.cloudstack.api.command.admin.vm.ListImportVMTasksCmd;
|
||||||
|
import org.apache.cloudstack.api.response.ImportVMTaskResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
import static org.apache.cloudstack.vm.ImportVmTask.Step.CloningInstance;
|
||||||
|
import static org.apache.cloudstack.vm.ImportVmTask.Step.Completed;
|
||||||
|
import static org.apache.cloudstack.vm.ImportVmTask.Step.ConvertingInstance;
|
||||||
|
import static org.apache.cloudstack.vm.ImportVmTask.Step.Importing;
|
||||||
|
import static org.apache.cloudstack.vm.ImportVmTask.Step.Prepare;
|
||||||
|
|
||||||
|
public class ImportVmTasksManagerImpl implements ImportVmTasksManager {
|
||||||
|
|
||||||
|
protected Logger logger = LogManager.getLogger(ImportVmTasksManagerImpl.class);
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ImportVMTaskDao importVMTaskDao;
|
||||||
|
@Inject
|
||||||
|
private DataCenterDao dataCenterDao;
|
||||||
|
@Inject
|
||||||
|
private AccountService accountService;
|
||||||
|
@Inject
|
||||||
|
private HostDao hostDao;
|
||||||
|
@Inject
|
||||||
|
private UserVmDao userVmDao;
|
||||||
|
|
||||||
|
public ImportVmTasksManagerImpl() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListResponse<ImportVMTaskResponse> listImportVMTasks(ListImportVMTasksCmd cmd) {
|
||||||
|
Long zoneId = cmd.getZoneId();
|
||||||
|
Long accountId = cmd.getAccountId();
|
||||||
|
String vcenter = cmd.getVcenter();
|
||||||
|
Long convertHostId = cmd.getConvertHostId();
|
||||||
|
boolean listAll = cmd.isListAll();
|
||||||
|
boolean showCompleted = cmd.isShowCompleted();
|
||||||
|
|
||||||
|
List<ImportVMTaskVO> tasks;
|
||||||
|
if (listAll) {
|
||||||
|
tasks = importVMTaskDao.listAll();
|
||||||
|
} else {
|
||||||
|
tasks = importVMTaskDao.listImportVMTasks(zoneId, accountId, vcenter, convertHostId, showCompleted);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ImportVMTaskResponse> responses = new ArrayList<>();
|
||||||
|
for (ImportVMTaskVO task : tasks) {
|
||||||
|
responses.add(createImportVMTaskResponse(task));
|
||||||
|
}
|
||||||
|
ListResponse<ImportVMTaskResponse> listResponses = new ListResponse<>();
|
||||||
|
listResponses.setResponses(responses, responses.size());
|
||||||
|
return listResponses;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImportVmTask createImportVMTaskRecord(DataCenter zone, Account owner, long userId, String displayName, String vcenter, String datacenterName, String sourceVMName, Host convertHost, Host importHost) {
|
||||||
|
logger.debug("Creating import VM task entry for VM: {} for account {} on zone {} " +
|
||||||
|
"from the vCenter: {} / datacenter: {} / source VM: {}",
|
||||||
|
sourceVMName, owner.getAccountName(), zone.getName(), displayName, vcenter, datacenterName);
|
||||||
|
ImportVMTaskVO importVMTaskVO = new ImportVMTaskVO(zone.getId(), owner.getAccountId(), userId, displayName,
|
||||||
|
vcenter, datacenterName, sourceVMName, convertHost.getId(), importHost.getId());
|
||||||
|
return importVMTaskDao.persist(importVMTaskVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getStepDescription(ImportVMTaskVO importVMTaskVO, Host convertHost, Host importHost,
|
||||||
|
ImportVMTaskVO.Step step, Date updatedDate) {
|
||||||
|
String sourceVMName = importVMTaskVO.getSourceVMName();
|
||||||
|
String vcenter = importVMTaskVO.getVcenter();
|
||||||
|
String datacenter = importVMTaskVO.getDatacenter();
|
||||||
|
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
if (Completed == step) {
|
||||||
|
stringBuilder.append("Completed at ").append(DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), updatedDate));
|
||||||
|
} else {
|
||||||
|
stringBuilder.append(String.format("[%s] ", DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), updatedDate)));
|
||||||
|
if (CloningInstance == step) {
|
||||||
|
stringBuilder.append(String.format("Cloning source instance: %s on vCenter: %s / datacenter: %s", sourceVMName, vcenter, datacenter));
|
||||||
|
} else if (ConvertingInstance == step) {
|
||||||
|
stringBuilder.append(String.format("Converting the cloned VMware instance to a KVM instance on the host: %s", convertHost.getName()));
|
||||||
|
} else if (Importing == step) {
|
||||||
|
stringBuilder.append(String.format("Importing the converted KVM instance on the host: %s", importHost.getName()));
|
||||||
|
} else if (Prepare == step) {
|
||||||
|
stringBuilder.append("Preparing to convert Vmware instance");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateImportVMTaskStep(ImportVmTask importVMTask, DataCenter zone, Account owner, Host convertHost,
|
||||||
|
Host importHost, Long vmId, ImportVmTask.Step step) {
|
||||||
|
ImportVMTaskVO importVMTaskVO = (ImportVMTaskVO) importVMTask;
|
||||||
|
logger.debug("Updating import VM task entry for VM: {} for account {} on zone {} " +
|
||||||
|
"from the vCenter: {} / datacenter: {} / source VM: {} to step: {}",
|
||||||
|
importVMTaskVO.getSourceVMName(), owner.getAccountName(), zone.getName(), importVMTaskVO.getDisplayName(),
|
||||||
|
importVMTaskVO.getVcenter(), importVMTaskVO.getDatacenter(), step);
|
||||||
|
Date updatedDate = DateUtil.now();
|
||||||
|
String description = getStepDescription(importVMTaskVO, convertHost, importHost, step, updatedDate);
|
||||||
|
importVMTaskVO.setStep(step);
|
||||||
|
importVMTaskVO.setDescription(description);
|
||||||
|
importVMTaskVO.setUpdated(updatedDate);
|
||||||
|
if (Completed == step) {
|
||||||
|
Duration duration = Duration.between(importVMTaskVO.getCreated().toInstant(), updatedDate.toInstant());
|
||||||
|
importVMTaskVO.setDuration(duration.toMillis());
|
||||||
|
importVMTaskVO.setVmId(vmId);
|
||||||
|
}
|
||||||
|
importVMTaskDao.update(importVMTaskVO.getId(), importVMTaskVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeImportVMTask(long taskId) {
|
||||||
|
return importVMTaskDao.remove(taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImportVMTaskResponse createImportVMTaskResponse(ImportVMTaskVO task) {
|
||||||
|
ImportVMTaskResponse response = new ImportVMTaskResponse();
|
||||||
|
DataCenterVO zone = dataCenterDao.findById(task.getZoneId());
|
||||||
|
if (zone != null) {
|
||||||
|
response.setZoneId(zone.getUuid());
|
||||||
|
response.setZoneName(zone.getName());
|
||||||
|
}
|
||||||
|
Account account = accountService.getAccount(task.getAccountId());
|
||||||
|
if (account != null) {
|
||||||
|
response.setAccountId(account.getUuid());
|
||||||
|
response.setAccountName(account.getAccountName());
|
||||||
|
}
|
||||||
|
response.setVcenter(task.getVcenter());
|
||||||
|
response.setDatacenterName(task.getDatacenter());
|
||||||
|
response.setSourceVMName(task.getSourceVMName());
|
||||||
|
response.setDisplayName(task.getDisplayName());
|
||||||
|
response.setStep(getStepDisplayField(task.getStep()));
|
||||||
|
response.setDescription(task.getDescription());
|
||||||
|
|
||||||
|
Date updated = task.getUpdated();
|
||||||
|
Date currentDate = new Date();
|
||||||
|
if (updated != null && Completed != task.getStep()) {
|
||||||
|
Duration stepDuration = Duration.between(updated.toInstant(), currentDate.toInstant());
|
||||||
|
response.setStepDuration(getDurationDisplay(stepDuration.toMillis()));
|
||||||
|
}
|
||||||
|
if (Completed == task.getStep()) {
|
||||||
|
response.setStepDuration(getDurationDisplay(task.getDuration()));
|
||||||
|
} else {
|
||||||
|
Duration totalDuration = Duration.between(task.getCreated().toInstant(), currentDate.toInstant());
|
||||||
|
response.setDuration(getDurationDisplay(totalDuration.toMillis()));
|
||||||
|
}
|
||||||
|
HostVO host = hostDao.findById(task.getConvertHostId());
|
||||||
|
if (host != null) {
|
||||||
|
response.setConvertInstanceHostId(host.getUuid());
|
||||||
|
response.setConvertInstanceHostName(host.getName());
|
||||||
|
}
|
||||||
|
if (task.getVmId() != null) {
|
||||||
|
UserVmVO userVm = userVmDao.findById(task.getVmId());
|
||||||
|
response.setVirtualMachineId(userVm.getUuid());
|
||||||
|
}
|
||||||
|
response.setCreated(task.getCreated());
|
||||||
|
response.setLastUpdated(task.getUpdated());
|
||||||
|
response.setObjectName("importvmtask");
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getStepDisplayField(ImportVMTaskVO.Step step) {
|
||||||
|
int totalSteps = ImportVMTaskVO.Step.values().length;
|
||||||
|
return String.format("[%s/%s] %s", step.ordinal() + 1, totalSteps, step.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String getDurationDisplay(Long durationMs) {
|
||||||
|
if (durationMs == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
long hours = durationMs / (1000 * 60 * 60);
|
||||||
|
long minutes = (durationMs / (1000 * 60)) % 60;
|
||||||
|
long seconds = (durationMs / 1000) % 60;
|
||||||
|
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
if (hours > 0) {
|
||||||
|
result.append(String.format("%s hs ", hours));
|
||||||
|
}
|
||||||
|
if (minutes > 0) {
|
||||||
|
result.append(String.format("%s min ", minutes));
|
||||||
|
}
|
||||||
|
if (seconds > 0) {
|
||||||
|
result.append(String.format("%s secs", seconds));
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -122,6 +122,7 @@ import com.cloud.user.dao.UserDao;
|
|||||||
import com.cloud.uservm.UserVm;
|
import com.cloud.uservm.UserVm;
|
||||||
import com.cloud.utils.LogUtils;
|
import com.cloud.utils.LogUtils;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
|
import com.cloud.utils.UuidUtils;
|
||||||
import com.cloud.utils.db.EntityManager;
|
import com.cloud.utils.db.EntityManager;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.cloud.utils.net.NetUtils;
|
import com.cloud.utils.net.NetUtils;
|
||||||
@ -150,6 +151,7 @@ import org.apache.cloudstack.api.ResponseObject;
|
|||||||
import org.apache.cloudstack.api.ServerApiException;
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
import org.apache.cloudstack.api.command.admin.vm.ImportUnmanagedInstanceCmd;
|
import org.apache.cloudstack.api.command.admin.vm.ImportUnmanagedInstanceCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.vm.ImportVmCmd;
|
import org.apache.cloudstack.api.command.admin.vm.ImportVmCmd;
|
||||||
|
import org.apache.cloudstack.api.command.admin.vm.ListImportVMTasksCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.vm.ListUnmanagedInstancesCmd;
|
import org.apache.cloudstack.api.command.admin.vm.ListUnmanagedInstancesCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.vm.ListVmsForImportCmd;
|
import org.apache.cloudstack.api.command.admin.vm.ListVmsForImportCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.vm.UnmanageVMInstanceCmd;
|
import org.apache.cloudstack.api.command.admin.vm.UnmanageVMInstanceCmd;
|
||||||
@ -173,6 +175,8 @@ import org.apache.cloudstack.storage.volume.VolumeOnStorageTO;
|
|||||||
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
|
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.collections.MapUtils;
|
import org.apache.commons.collections.MapUtils;
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
@ -180,7 +184,9 @@ import org.apache.logging.log4j.Logger;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -190,6 +196,10 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import static org.apache.cloudstack.api.ApiConstants.MAX_IOPS;
|
import static org.apache.cloudstack.api.ApiConstants.MAX_IOPS;
|
||||||
import static org.apache.cloudstack.api.ApiConstants.MIN_IOPS;
|
import static org.apache.cloudstack.api.ApiConstants.MIN_IOPS;
|
||||||
|
import static org.apache.cloudstack.vm.ImportVmTask.Step.CloningInstance;
|
||||||
|
import static org.apache.cloudstack.vm.ImportVmTask.Step.Completed;
|
||||||
|
import static org.apache.cloudstack.vm.ImportVmTask.Step.ConvertingInstance;
|
||||||
|
import static org.apache.cloudstack.vm.ImportVmTask.Step.Importing;
|
||||||
|
|
||||||
public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
||||||
public static final String VM_IMPORT_DEFAULT_TEMPLATE_NAME = "system-default-vm-import-dummy-template.iso";
|
public static final String VM_IMPORT_DEFAULT_TEMPLATE_NAME = "system-default-vm-import-dummy-template.iso";
|
||||||
@ -198,6 +208,28 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
private static final List<Hypervisor.HypervisorType> importUnmanagedInstancesSupportedHypervisors =
|
private static final List<Hypervisor.HypervisorType> importUnmanagedInstancesSupportedHypervisors =
|
||||||
Arrays.asList(Hypervisor.HypervisorType.VMware, Hypervisor.HypervisorType.KVM);
|
Arrays.asList(Hypervisor.HypervisorType.VMware, Hypervisor.HypervisorType.KVM);
|
||||||
|
|
||||||
|
private static final List<Storage.StoragePoolType> forceConvertToPoolAllowedTypes =
|
||||||
|
Arrays.asList(Storage.StoragePoolType.NetworkFilesystem, Storage.StoragePoolType.Filesystem,
|
||||||
|
Storage.StoragePoolType.SharedMountPoint);
|
||||||
|
|
||||||
|
ConfigKey<Boolean> ConvertVmwareInstanceToKvmExtraParamsAllowed = new ConfigKey<>(Boolean.class,
|
||||||
|
"convert.vmware.instance.to.kvm.extra.params.allowed",
|
||||||
|
"Advanced",
|
||||||
|
"false",
|
||||||
|
"Disabled by default. If enabled, allows extra parameters to be passed to the virt-v2v binary on KVM conversion hosts",
|
||||||
|
true,
|
||||||
|
ConfigKey.Scope.Global,
|
||||||
|
null);
|
||||||
|
|
||||||
|
ConfigKey<String> ConvertVmwareInstanceToKvmExtraParamsAllowedList = new ConfigKey<>(ConfigKey.CATEGORY_ADVANCED,
|
||||||
|
String.class,
|
||||||
|
"convert.vmware.instance.to.kvm.extra.params.allowed.list",
|
||||||
|
"",
|
||||||
|
"Comma separated list of allowed extra parameters to be passed to the virt-v2v binary on KVM conversion hosts",
|
||||||
|
true,
|
||||||
|
ConfigKey.Kind.CSV,
|
||||||
|
null);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private AgentManager agentManager;
|
private AgentManager agentManager;
|
||||||
@Inject
|
@Inject
|
||||||
@ -282,6 +314,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
private ImageStoreDao imageStoreDao;
|
private ImageStoreDao imageStoreDao;
|
||||||
@Inject
|
@Inject
|
||||||
private DataStoreManager dataStoreManager;
|
private DataStoreManager dataStoreManager;
|
||||||
|
@Inject
|
||||||
|
private ImportVmTasksManager importVmTasksManager;
|
||||||
|
|
||||||
protected Gson gson;
|
protected Gson gson;
|
||||||
|
|
||||||
@ -557,11 +591,12 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (storagePool == null) {
|
if (storagePool == null) {
|
||||||
List<StoragePoolVO> pools = primaryDataStoreDao.listPoolsByCluster(cluster.getId());
|
Set<StoragePoolVO> pools = new HashSet<>(primaryDataStoreDao.listPoolsByCluster(cluster.getId()));
|
||||||
pools.addAll(primaryDataStoreDao.listByDataCenterId(zone.getId()));
|
pools.addAll(primaryDataStoreDao.listByDataCenterId(zone.getId()));
|
||||||
|
boolean isNameUuid = StringUtils.isNotBlank(dsName) && UuidUtils.isUuid(dsName);
|
||||||
for (StoragePool pool : pools) {
|
for (StoragePool pool : pools) {
|
||||||
String searchPoolParam = StringUtils.isNotBlank(dsPath) ? dsPath : dsName;
|
String searchPoolParam = StringUtils.isNotBlank(dsPath) ? dsPath : dsName;
|
||||||
if (StringUtils.contains(pool.getPath(), searchPoolParam) &&
|
if ((StringUtils.contains(pool.getPath(), searchPoolParam) || isNameUuid && pool.getUuid().equals(dsName)) &&
|
||||||
volumeApiService.doesStoragePoolSupportDiskOffering(pool, diskOffering)) {
|
volumeApiService.doesStoragePoolSupportDiskOffering(pool, diskOffering)) {
|
||||||
storagePool = pool;
|
storagePool = pool;
|
||||||
break;
|
break;
|
||||||
@ -1418,6 +1453,33 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
return responseGenerator.createUserVmResponse(ResponseObject.ResponseView.Full, "virtualmachine", userVm).get(0);
|
return responseGenerator.createUserVmResponse(ResponseObject.ResponseView.Full, "virtualmachine", userVm).get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void checkExtraParamsAllowed(String extraParams) {
|
||||||
|
if (StringUtils.isBlank(extraParams)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (BooleanUtils.isFalse(ConvertVmwareInstanceToKvmExtraParamsAllowed.value())) {
|
||||||
|
throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
|
||||||
|
"Extra parameters for Vmware to KVM conversion are disabled by the administrator");
|
||||||
|
}
|
||||||
|
String allowedParamsStr = ConvertVmwareInstanceToKvmExtraParamsAllowedList.value();
|
||||||
|
if (StringUtils.isBlank(allowedParamsStr)) {
|
||||||
|
throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
|
||||||
|
"Extra parameters for Vmware to KVM conversion are enabled but the allowed list of parameters is empty");
|
||||||
|
}
|
||||||
|
List<String> allowedParams = Arrays.asList(allowedParamsStr.split(","));
|
||||||
|
List<String> sanitizedParams = Arrays.asList(extraParams.split(" "))
|
||||||
|
.stream()
|
||||||
|
.filter(x -> x.startsWith("-"))
|
||||||
|
.map(s -> s.replaceFirst("^-+", "").trim()) //Remove the starting hyphens as in --X or -x
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
for (String param : sanitizedParams) {
|
||||||
|
if (!allowedParams.contains(param)) {
|
||||||
|
throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
|
||||||
|
String.format("The parameter %s is not allowed by the administrator", param));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private long getUserIdForImportInstance(Account owner) {
|
private long getUserIdForImportInstance(Account owner) {
|
||||||
long userId = CallContext.current().getCallingUserId();
|
long userId = CallContext.current().getCallingUserId();
|
||||||
List<UserVO> userVOs = userDao.listByAccount(owner.getAccountId());
|
List<UserVO> userVOs = userDao.listByAccount(owner.getAccountId());
|
||||||
@ -1513,6 +1575,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
String source = cmd.getImportSource().toUpperCase();
|
String source = cmd.getImportSource().toUpperCase();
|
||||||
ImportSource importSource = Enum.valueOf(ImportSource.class, source);
|
ImportSource importSource = Enum.valueOf(ImportSource.class, source);
|
||||||
if (ImportSource.VMWARE == importSource || ImportSource.UNMANAGED == importSource) {
|
if (ImportSource.VMWARE == importSource || ImportSource.UNMANAGED == importSource) {
|
||||||
|
checkExtraParamsAllowed(cmd.getExtraParams());
|
||||||
return baseImportInstance(cmd);
|
return baseImportInstance(cmd);
|
||||||
} else {
|
} else {
|
||||||
return importKvmInstance(cmd);
|
return importKvmInstance(cmd);
|
||||||
@ -1621,6 +1684,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
Long convertInstanceHostId = cmd.getConvertInstanceHostId();
|
Long convertInstanceHostId = cmd.getConvertInstanceHostId();
|
||||||
Long importInstanceHostId = cmd.getImportInstanceHostId();
|
Long importInstanceHostId = cmd.getImportInstanceHostId();
|
||||||
Long convertStoragePoolId = cmd.getConvertStoragePoolId();
|
Long convertStoragePoolId = cmd.getConvertStoragePoolId();
|
||||||
|
String extraParams = cmd.getExtraParams();
|
||||||
|
boolean forceConvertToPool = cmd.getForceConvertToPool();
|
||||||
|
|
||||||
if ((existingVcenterId == null && vcenter == null) || (existingVcenterId != null && vcenter != null)) {
|
if ((existingVcenterId == null && vcenter == null) || (existingVcenterId != null && vcenter != null)) {
|
||||||
throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
|
throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
|
||||||
@ -1631,6 +1696,10 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
"Please set all the information for a vCenter IP/Name, datacenter, username and password");
|
"Please set all the information for a vCenter IP/Name, datacenter, username and password");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkConversionStoragePool(convertStoragePoolId, forceConvertToPool);
|
||||||
|
|
||||||
|
checkExtraParamsAllowed(extraParams);
|
||||||
|
|
||||||
if (existingVcenterId != null) {
|
if (existingVcenterId != null) {
|
||||||
VmwareDatacenterVO existingDC = vmwareDatacenterDao.findById(existingVcenterId);
|
VmwareDatacenterVO existingDC = vmwareDatacenterDao.findById(existingVcenterId);
|
||||||
if (existingDC == null) {
|
if (existingDC == null) {
|
||||||
@ -1648,6 +1717,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
UnmanagedInstanceTO sourceVMwareInstance = null;
|
UnmanagedInstanceTO sourceVMwareInstance = null;
|
||||||
DataStoreTO temporaryConvertLocation = null;
|
DataStoreTO temporaryConvertLocation = null;
|
||||||
String ovfTemplateOnConvertLocation = null;
|
String ovfTemplateOnConvertLocation = null;
|
||||||
|
ImportVmTask importVMTask = null;
|
||||||
try {
|
try {
|
||||||
HostVO convertHost = selectKVMHostForConversionInCluster(destinationCluster, convertInstanceHostId);
|
HostVO convertHost = selectKVMHostForConversionInCluster(destinationCluster, convertInstanceHostId);
|
||||||
HostVO importHost = selectKVMHostForImportingInCluster(destinationCluster, importInstanceHostId);
|
HostVO importHost = selectKVMHostForImportingInCluster(destinationCluster, importInstanceHostId);
|
||||||
@ -1656,12 +1726,21 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
"instance {} from VMware to KVM ", convertHost, sourceVMName);
|
"instance {} from VMware to KVM ", convertHost, sourceVMName);
|
||||||
|
|
||||||
temporaryConvertLocation = selectInstanceConversionTemporaryLocation(
|
temporaryConvertLocation = selectInstanceConversionTemporaryLocation(
|
||||||
destinationCluster, convertHost, convertStoragePoolId);
|
destinationCluster, convertHost, importHost, convertStoragePoolId, forceConvertToPool);
|
||||||
List<StoragePoolVO> convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster, serviceOffering, dataDiskOfferingMap);
|
List<StoragePoolVO> convertStoragePools = findInstanceConversionDestinationStoragePoolsInCluster(destinationCluster, serviceOffering, dataDiskOfferingMap, temporaryConvertLocation, forceConvertToPool);
|
||||||
|
|
||||||
long importStartTime = System.currentTimeMillis();
|
long importStartTime = System.currentTimeMillis();
|
||||||
|
importVMTask = importVmTasksManager.createImportVMTaskRecord(zone, owner, userId, displayName, vcenter, datacenterName, sourceVMName,
|
||||||
|
convertHost, importHost);
|
||||||
|
importVmTasksManager.updateImportVMTaskStep(importVMTask, zone, owner, convertHost, importHost, null, CloningInstance);
|
||||||
|
|
||||||
|
// sourceVMwareInstance could be a cloned instance from sourceVMName, of the sourceVMName itself if its powered off.
|
||||||
|
// isClonedInstance indicates if the VM is a clone of sourceVMName
|
||||||
|
|
||||||
Pair<UnmanagedInstanceTO, Boolean> sourceInstanceDetails = getSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password, clusterName, sourceHostName, sourceVMName);
|
Pair<UnmanagedInstanceTO, Boolean> sourceInstanceDetails = getSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password, clusterName, sourceHostName, sourceVMName);
|
||||||
sourceVMwareInstance = sourceInstanceDetails.first();
|
sourceVMwareInstance = sourceInstanceDetails.first();
|
||||||
isClonedInstance = sourceInstanceDetails.second();
|
isClonedInstance = sourceInstanceDetails.second();
|
||||||
|
|
||||||
boolean isWindowsVm = sourceVMwareInstance.getOperatingSystem().toLowerCase().contains("windows");
|
boolean isWindowsVm = sourceVMwareInstance.getOperatingSystem().toLowerCase().contains("windows");
|
||||||
if (isWindowsVm) {
|
if (isWindowsVm) {
|
||||||
checkConversionSupportOnHost(convertHost, sourceVMName, true);
|
checkConversionSupportOnHost(convertHost, sourceVMName, true);
|
||||||
@ -1672,22 +1751,25 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
if (cmd.getForceMsToImportVmFiles() || !conversionSupportAnswer.isOvfExportSupported()) {
|
if (cmd.getForceMsToImportVmFiles() || !conversionSupportAnswer.isOvfExportSupported()) {
|
||||||
// Uses MS for OVF export to temporary conversion location
|
// Uses MS for OVF export to temporary conversion location
|
||||||
int noOfThreads = UnmanagedVMsManager.ThreadsOnMSToImportVMwareVMFiles.value();
|
int noOfThreads = UnmanagedVMsManager.ThreadsOnMSToImportVMwareVMFiles.value();
|
||||||
|
importVmTasksManager.updateImportVMTaskStep(importVMTask, zone, owner, convertHost, importHost, null, ConvertingInstance);
|
||||||
ovfTemplateOnConvertLocation = createOvfTemplateOfSourceVmwareUnmanagedInstance(
|
ovfTemplateOnConvertLocation = createOvfTemplateOfSourceVmwareUnmanagedInstance(
|
||||||
vcenter, datacenterName, username, password, clusterName, sourceHostName,
|
vcenter, datacenterName, username, password, clusterName, sourceHostName,
|
||||||
sourceVMwareInstance.getName(), temporaryConvertLocation, noOfThreads);
|
sourceVMwareInstance.getName(), temporaryConvertLocation, noOfThreads);
|
||||||
convertedInstance = convertVmwareInstanceToKVMWithOVFOnConvertLocation(sourceVMName,
|
convertedInstance = convertVmwareInstanceToKVMWithOVFOnConvertLocation(sourceVMName,
|
||||||
sourceVMwareInstance, convertHost, importHost, convertStoragePools,
|
sourceVMwareInstance, convertHost, importHost, convertStoragePools,
|
||||||
serviceOffering, dataDiskOfferingMap, temporaryConvertLocation,
|
serviceOffering, dataDiskOfferingMap, temporaryConvertLocation,
|
||||||
ovfTemplateOnConvertLocation);
|
ovfTemplateOnConvertLocation, forceConvertToPool, extraParams);
|
||||||
} else {
|
} else {
|
||||||
// Uses KVM Host for OVF export to temporary conversion location, through ovftool
|
// Uses KVM Host for OVF export to temporary conversion location, through ovftool
|
||||||
|
importVmTasksManager.updateImportVMTaskStep(importVMTask, zone, owner, convertHost, importHost, null, ConvertingInstance);
|
||||||
convertedInstance = convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(
|
convertedInstance = convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(
|
||||||
sourceVMName, sourceVMwareInstance, convertHost, importHost,
|
sourceVMName, sourceVMwareInstance, convertHost, importHost,
|
||||||
convertStoragePools, serviceOffering, dataDiskOfferingMap,
|
convertStoragePools, serviceOffering, dataDiskOfferingMap,
|
||||||
temporaryConvertLocation, vcenter, username, password, datacenterName);
|
temporaryConvertLocation, vcenter, username, password, datacenterName, forceConvertToPool, extraParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
sanitizeConvertedInstance(convertedInstance, sourceVMwareInstance);
|
sanitizeConvertedInstance(convertedInstance, sourceVMwareInstance);
|
||||||
|
importVmTasksManager.updateImportVMTaskStep(importVMTask, zone, owner, convertHost, importHost, null, Importing);
|
||||||
UserVm userVm = importVirtualMachineInternal(convertedInstance, null, zone, destinationCluster, null,
|
UserVm userVm = importVirtualMachineInternal(convertedInstance, null, zone, destinationCluster, null,
|
||||||
template, displayName, hostName, caller, owner, userId,
|
template, displayName, hostName, caller, owner, userId,
|
||||||
serviceOffering, dataDiskOfferingMap,
|
serviceOffering, dataDiskOfferingMap,
|
||||||
@ -1696,6 +1778,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
long timeElapsedInSecs = (System.currentTimeMillis() - importStartTime) / 1000;
|
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",
|
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, displayName, displayName, timeElapsedInSecs, (ovfTemplateOnConvertLocation != null)? "MS" : "KVM Host", sourceVMwareInstance.getOperatingSystem(), sourceVMwareInstance.getPowerState(), sourceVMwareInstance.getDisks(), sourceVMwareInstance.getNics()));
|
sourceVMName, displayName, displayName, timeElapsedInSecs, (ovfTemplateOnConvertLocation != null)? "MS" : "KVM Host", sourceVMwareInstance.getOperatingSystem(), sourceVMwareInstance.getPowerState(), sourceVMwareInstance.getDisks(), sourceVMwareInstance.getNics()));
|
||||||
|
importVmTasksManager.updateImportVMTaskStep(importVMTask, zone, owner, convertHost, importHost, userVm.getId(), Completed);
|
||||||
|
importVmTasksManager.removeImportVMTask(importVMTask.getId());
|
||||||
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);
|
||||||
@ -1712,6 +1796,30 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the conversion storage pool exists and is suitable for the conversion or not.
|
||||||
|
* Secondary storage is only allowed when forceConvertToPool is false.
|
||||||
|
* @param convertStoragePoolId the ID of the storage pool (primary or secondary)
|
||||||
|
* @param forceConvertToPool when true, only primary storage pool must be allowed
|
||||||
|
* @throws CloudRuntimeException in case these requirements are not met
|
||||||
|
*/
|
||||||
|
protected void checkConversionStoragePool(Long convertStoragePoolId, boolean forceConvertToPool) {
|
||||||
|
if (forceConvertToPool && convertStoragePoolId == null) {
|
||||||
|
String msg = "The parameter forceconverttopool is set to true, but a primary storage pool has not been provided for conversion";
|
||||||
|
logFailureAndThrowException(msg);
|
||||||
|
}
|
||||||
|
if (convertStoragePoolId != null) {
|
||||||
|
StoragePoolVO selectedStoragePool = primaryDataStoreDao.findById(convertStoragePoolId);
|
||||||
|
if (selectedStoragePool == null) {
|
||||||
|
logFailureAndThrowException(String.format("Cannot find a storage pool with ID %s", convertStoragePoolId));
|
||||||
|
}
|
||||||
|
if (forceConvertToPool && !forceConvertToPoolAllowedTypes.contains(selectedStoragePool.getPoolType())) {
|
||||||
|
logFailureAndThrowException(String.format("The selected storage pool %s does not support direct conversion " +
|
||||||
|
"as its type %s", selectedStoragePool.getName(), selectedStoragePool.getPoolType().name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void checkNetworkingBeforeConvertingVmwareInstance(DataCenter zone, Account owner, String displayName,
|
private void checkNetworkingBeforeConvertingVmwareInstance(DataCenter zone, Account owner, String displayName,
|
||||||
String hostName, UnmanagedInstanceTO sourceVMwareInstance,
|
String hostName, UnmanagedInstanceTO sourceVMwareInstance,
|
||||||
Map<String, Long> nicNetworkMap,
|
Map<String, Long> nicNetworkMap,
|
||||||
@ -1953,20 +2061,25 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost,
|
String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost,
|
||||||
HostVO importHost, List<StoragePoolVO> convertStoragePools,
|
HostVO importHost, List<StoragePoolVO> convertStoragePools,
|
||||||
ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap,
|
ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap,
|
||||||
DataStoreTO temporaryConvertLocation, String ovfTemplateDirConvertLocation
|
DataStoreTO temporaryConvertLocation, String ovfTemplateDirConvertLocation,
|
||||||
) {
|
boolean forceConvertToPool, String extraParams) {
|
||||||
|
|
||||||
logger.debug("Delegating the conversion of instance {} from VMware to KVM to the host {} using OVF {} on conversion datastore",
|
logger.debug("Delegating the conversion of instance {} from VMware to KVM to the host {} using OVF {} on conversion datastore",
|
||||||
sourceVM, convertHost, ovfTemplateDirConvertLocation);
|
sourceVM, convertHost, ovfTemplateDirConvertLocation);
|
||||||
|
|
||||||
RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(sourceVM);
|
RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(sourceVM);
|
||||||
List<String> destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks(), serviceOffering, dataDiskOfferingMap);
|
List<String> destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks(), serviceOffering, dataDiskOfferingMap);
|
||||||
ConvertInstanceCommand cmd = new ConvertInstanceCommand(remoteInstanceTO,
|
ConvertInstanceCommand cmd = new ConvertInstanceCommand(remoteInstanceTO,
|
||||||
Hypervisor.HypervisorType.KVM, temporaryConvertLocation, ovfTemplateDirConvertLocation, false, false);
|
Hypervisor.HypervisorType.KVM, temporaryConvertLocation,
|
||||||
|
ovfTemplateDirConvertLocation, false, false, sourceVM);
|
||||||
|
if (StringUtils.isNotBlank(extraParams)) {
|
||||||
|
cmd.setExtraParams(extraParams);
|
||||||
|
}
|
||||||
int timeoutSeconds = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60;
|
int timeoutSeconds = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60;
|
||||||
cmd.setWait(timeoutSeconds);
|
cmd.setWait(timeoutSeconds);
|
||||||
|
|
||||||
return convertAndImportToKVM(cmd, convertHost, importHost, sourceVM,
|
return convertAndImportToKVM(cmd, convertHost, importHost, sourceVM,
|
||||||
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation);
|
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation, forceConvertToPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
private UnmanagedInstanceTO convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(
|
private UnmanagedInstanceTO convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(
|
||||||
@ -1974,14 +2087,13 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
HostVO importHost, List<StoragePoolVO> convertStoragePools,
|
HostVO importHost, List<StoragePoolVO> convertStoragePools,
|
||||||
ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap,
|
ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap,
|
||||||
DataStoreTO temporaryConvertLocation, String vcenterHost, String vcenterUsername,
|
DataStoreTO temporaryConvertLocation, String vcenterHost, String vcenterUsername,
|
||||||
String vcenterPassword, String datacenterName
|
String vcenterPassword, String datacenterName, boolean forceConvertToPool, String extraParams) {
|
||||||
) {
|
|
||||||
logger.debug("Delegating the conversion of instance {} from VMware to KVM to the host {} after OVF export through ovftool", sourceVM, convertHost);
|
logger.debug("Delegating the conversion of instance {} from VMware to KVM to the host {} after OVF export through ovftool", sourceVM, convertHost);
|
||||||
|
|
||||||
RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(sourceVMwareInstance.getName(), sourceVMwareInstance.getPath(), vcenterHost, vcenterUsername, vcenterPassword, datacenterName);
|
RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(sourceVMwareInstance.getName(), sourceVMwareInstance.getPath(), vcenterHost, vcenterUsername, vcenterPassword, datacenterName);
|
||||||
List<String> destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks(), serviceOffering, dataDiskOfferingMap);
|
List<String> destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks(), serviceOffering, dataDiskOfferingMap);
|
||||||
ConvertInstanceCommand cmd = new ConvertInstanceCommand(remoteInstanceTO,
|
ConvertInstanceCommand cmd = new ConvertInstanceCommand(remoteInstanceTO,
|
||||||
Hypervisor.HypervisorType.KVM, temporaryConvertLocation, null, false, true);
|
Hypervisor.HypervisorType.KVM, temporaryConvertLocation, null, false, true, sourceVM);
|
||||||
int timeoutSeconds = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60;
|
int timeoutSeconds = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60;
|
||||||
cmd.setWait(timeoutSeconds);
|
cmd.setWait(timeoutSeconds);
|
||||||
int noOfThreads = UnmanagedVMsManager.ThreadsOnKVMHostToImportVMwareVMFiles.value();
|
int noOfThreads = UnmanagedVMsManager.ThreadsOnKVMHostToImportVMwareVMFiles.value();
|
||||||
@ -1990,16 +2102,19 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
noOfThreads = sourceVMwareInstance.getDisks().size();
|
noOfThreads = sourceVMwareInstance.getDisks().size();
|
||||||
}
|
}
|
||||||
cmd.setThreadsCountToExportOvf(noOfThreads);
|
cmd.setThreadsCountToExportOvf(noOfThreads);
|
||||||
|
if (StringUtils.isNotBlank(extraParams)) {
|
||||||
|
cmd.setExtraParams(extraParams);
|
||||||
|
}
|
||||||
return convertAndImportToKVM(cmd, convertHost, importHost, sourceVM,
|
return convertAndImportToKVM(cmd, convertHost, importHost, sourceVM,
|
||||||
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation);
|
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation, forceConvertToPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
private UnmanagedInstanceTO convertAndImportToKVM(ConvertInstanceCommand convertInstanceCommand, HostVO convertHost, HostVO importHost,
|
private UnmanagedInstanceTO convertAndImportToKVM(ConvertInstanceCommand convertInstanceCommand, HostVO convertHost, HostVO importHost,
|
||||||
String sourceVM,
|
String sourceVM,
|
||||||
RemoteInstanceTO remoteInstanceTO,
|
RemoteInstanceTO remoteInstanceTO,
|
||||||
List<String> destinationStoragePools,
|
List<String> destinationStoragePools,
|
||||||
DataStoreTO temporaryConvertLocation) {
|
DataStoreTO temporaryConvertLocation,
|
||||||
|
boolean forceConvertToPool) {
|
||||||
Answer convertAnswer;
|
Answer convertAnswer;
|
||||||
try {
|
try {
|
||||||
convertAnswer = agentManager.send(convertHost.getId(), convertInstanceCommand);
|
convertAnswer = agentManager.send(convertHost.getId(), convertInstanceCommand);
|
||||||
@ -2021,7 +2136,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
try {
|
try {
|
||||||
ImportConvertedInstanceCommand importCmd = new ImportConvertedInstanceCommand(
|
ImportConvertedInstanceCommand importCmd = new ImportConvertedInstanceCommand(
|
||||||
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation,
|
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation,
|
||||||
((ConvertInstanceAnswer)convertAnswer).getTemporaryConvertUuid());
|
((ConvertInstanceAnswer)convertAnswer).getTemporaryConvertUuid(), forceConvertToPool);
|
||||||
importAnswer = agentManager.send(importHost.getId(), importCmd);
|
importAnswer = agentManager.send(importHost.getId(), importCmd);
|
||||||
} catch (AgentUnavailableException | OperationTimedoutException e) {
|
} catch (AgentUnavailableException | OperationTimedoutException e) {
|
||||||
String err = String.format(
|
String err = String.format(
|
||||||
@ -2042,18 +2157,24 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
return ((ImportConvertedInstanceAnswer) importAnswer).getConvertedInstance();
|
return ((ImportConvertedInstanceAnswer) importAnswer).getConvertedInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<StoragePoolVO> findInstanceConversionStoragePoolsInCluster(
|
private List<StoragePoolVO> findInstanceConversionDestinationStoragePoolsInCluster(
|
||||||
Cluster destinationCluster, ServiceOfferingVO serviceOffering,
|
Cluster destinationCluster, ServiceOfferingVO serviceOffering,
|
||||||
Map<String, Long> dataDiskOfferingMap
|
Map<String, Long> dataDiskOfferingMap,
|
||||||
) {
|
DataStoreTO temporaryConvertLocation, boolean forceConvertToPool) {
|
||||||
List<StoragePoolVO> pools = new ArrayList<>();
|
List<StoragePoolVO> poolsList;
|
||||||
pools.addAll(primaryDataStoreDao.findClusterWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem));
|
if (!forceConvertToPool) {
|
||||||
|
Set<StoragePoolVO> pools = new HashSet<>(primaryDataStoreDao.findClusterWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem));
|
||||||
pools.addAll(primaryDataStoreDao.findZoneWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getDataCenterId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem));
|
pools.addAll(primaryDataStoreDao.findZoneWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getDataCenterId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem));
|
||||||
if (pools.isEmpty()) {
|
if (pools.isEmpty()) {
|
||||||
String msg = String.format("Cannot find suitable storage pools in the cluster %s for the conversion", destinationCluster.getName());
|
String msg = String.format("Cannot find suitable storage pools in the cluster %s for the conversion", destinationCluster.getName());
|
||||||
logger.error(msg);
|
logger.error(msg);
|
||||||
throw new CloudRuntimeException(msg);
|
throw new CloudRuntimeException(msg);
|
||||||
}
|
}
|
||||||
|
poolsList = new ArrayList<>(pools);
|
||||||
|
} else {
|
||||||
|
DataStore dataStore = dataStoreManager.getDataStore(temporaryConvertLocation.getUuid(), temporaryConvertLocation.getRole());
|
||||||
|
poolsList = Collections.singletonList(primaryDataStoreDao.findById(dataStore.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
if (serviceOffering.getDiskOfferingId() != null) {
|
if (serviceOffering.getDiskOfferingId() != null) {
|
||||||
DiskOfferingVO diskOffering = diskOfferingDao.findById(serviceOffering.getDiskOfferingId());
|
DiskOfferingVO diskOffering = diskOfferingDao.findById(serviceOffering.getDiskOfferingId());
|
||||||
@ -2062,7 +2183,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
logger.error(msg);
|
logger.error(msg);
|
||||||
throw new CloudRuntimeException(msg);
|
throw new CloudRuntimeException(msg);
|
||||||
}
|
}
|
||||||
if (getStoragePoolWithTags(pools, diskOffering.getTags()) == null) {
|
if (getStoragePoolWithTags(poolsList, diskOffering.getTags()) == null) {
|
||||||
String msg = String.format("Cannot find suitable storage pool for disk offering %s that belongs to the service offering %s", diskOffering.getName(), serviceOffering.getName());
|
String msg = String.format("Cannot find suitable storage pool for disk offering %s that belongs to the service offering %s", diskOffering.getName(), serviceOffering.getName());
|
||||||
logger.error(msg);
|
logger.error(msg);
|
||||||
throw new CloudRuntimeException(msg);
|
throw new CloudRuntimeException(msg);
|
||||||
@ -2075,14 +2196,14 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
logger.error(msg);
|
logger.error(msg);
|
||||||
throw new CloudRuntimeException(msg);
|
throw new CloudRuntimeException(msg);
|
||||||
}
|
}
|
||||||
if (getStoragePoolWithTags(pools, diskOffering.getTags()) == null) {
|
if (getStoragePoolWithTags(poolsList, diskOffering.getTags()) == null) {
|
||||||
String msg = String.format("Cannot find suitable storage pool for disk offering %s", diskOffering.getName());
|
String msg = String.format("Cannot find suitable storage pool for disk offering %s", diskOffering.getName());
|
||||||
logger.error(msg);
|
logger.error(msg);
|
||||||
throw new CloudRuntimeException(msg);
|
throw new CloudRuntimeException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pools;
|
return poolsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
private StoragePoolVO getStoragePoolWithTags(List<StoragePoolVO> pools, String tags) {
|
private StoragePoolVO getStoragePoolWithTags(List<StoragePoolVO> pools, String tags) {
|
||||||
@ -2128,11 +2249,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
throw new CloudRuntimeException(msg);
|
throw new CloudRuntimeException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DataStoreTO selectInstanceConversionTemporaryLocation(Cluster destinationCluster,
|
private void checkBeforeSelectingTemporaryConversionStoragePool(StoragePoolVO selectedStoragePool, Long convertStoragePoolId, Cluster destinationCluster, HostVO convertHost) {
|
||||||
HostVO convertHost,
|
|
||||||
Long convertStoragePoolId) {
|
|
||||||
if (convertStoragePoolId != null) {
|
|
||||||
StoragePoolVO selectedStoragePool = primaryDataStoreDao.findById(convertStoragePoolId);
|
|
||||||
if (selectedStoragePool == null) {
|
if (selectedStoragePool == null) {
|
||||||
logFailureAndThrowException(String.format("Cannot find a storage pool with ID %s", convertStoragePoolId));
|
logFailureAndThrowException(String.format("Cannot find a storage pool with ID %s", convertStoragePoolId));
|
||||||
}
|
}
|
||||||
@ -2145,13 +2262,12 @@ 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 " +
|
||||||
"the host %s for conversion is in a different cluster", selectedStoragePool.getName(), convertHost.getName()));
|
"the host %s for conversion is in a different cluster", selectedStoragePool.getName(), convertHost.getName()));
|
||||||
}
|
}
|
||||||
if (selectedStoragePool.getScope() == ScopeType.HOST) {
|
|
||||||
logFailureAndThrowException(String.format("The storage pool %s is a local storage pool and not supported for temporary conversion location, cluster and zone wide NFS storage pools are supported", selectedStoragePool.getName()));
|
|
||||||
} else if (selectedStoragePool.getPoolType() != Storage.StoragePoolType.NetworkFilesystem) {
|
|
||||||
logFailureAndThrowException(String.format("The storage pool %s is not supported for temporary conversion location, only NFS storage pools are supported", selectedStoragePool.getName()));
|
|
||||||
}
|
}
|
||||||
return dataStoreManager.getPrimaryDataStore(convertStoragePoolId).getTO();
|
|
||||||
} else {
|
private DataStoreTO getImageStoreOnDestinationZoneForTemporaryConversion(Cluster destinationCluster, boolean forceConvertToPool) {
|
||||||
|
if (forceConvertToPool) {
|
||||||
|
logFailureAndThrowException("Please select a primary storage pool when the parameter forceconverttopool is set to true");
|
||||||
|
}
|
||||||
long zoneId = destinationCluster.getDataCenterId();
|
long zoneId = destinationCluster.getDataCenterId();
|
||||||
ImageStoreVO imageStore = imageStoreDao.findOneByZoneAndProtocol(zoneId, "nfs");
|
ImageStoreVO imageStore = imageStoreDao.findOneByZoneAndProtocol(zoneId, "nfs");
|
||||||
if (imageStore == null) {
|
if (imageStore == null) {
|
||||||
@ -2161,6 +2277,35 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
DataStore dataStore = dataStoreManager.getDataStore(imageStore.getId(), DataStoreRole.Image);
|
DataStore dataStore = dataStoreManager.getDataStore(imageStore.getId(), DataStoreRole.Image);
|
||||||
return dataStore.getTO();
|
return dataStore.getTO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkDestinationOrTemporaryStoragePoolForConversion(StoragePoolVO selectedStoragePool, boolean forceConvertToPool, HostVO convertHost, HostVO importHost) {
|
||||||
|
if (selectedStoragePool.getScope() == ScopeType.HOST && (ObjectUtils.anyNull(convertHost, importHost) ||
|
||||||
|
ObjectUtils.allNotNull(convertHost, importHost) && convertHost.getId() != importHost.getId() ||
|
||||||
|
!forceConvertToPool) ) {
|
||||||
|
logFailureAndThrowException("Please select the same host as convert and importing host and " +
|
||||||
|
"set forceconvertopool to true to use a local storage pool for conversion");
|
||||||
|
}
|
||||||
|
if (!forceConvertToPool && selectedStoragePool.getPoolType() != Storage.StoragePoolType.NetworkFilesystem) {
|
||||||
|
logFailureAndThrowException(String.format("The storage pool %s is not supported for temporary conversion location," +
|
||||||
|
"only NFS storage pools are supported when forceconverttopool is set to false", selectedStoragePool.getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DataStoreTO selectInstanceConversionTemporaryLocation(Cluster destinationCluster,
|
||||||
|
HostVO convertHost, HostVO importHost,
|
||||||
|
Long convertStoragePoolId, boolean forceConvertToPool) {
|
||||||
|
if (convertStoragePoolId == null) {
|
||||||
|
String msg = String.format("No convert storage pool has been provided, " +
|
||||||
|
"selecting an NFS secondary storage pool from the destination cluster (%s) zone", destinationCluster.getName());
|
||||||
|
logger.debug(msg);
|
||||||
|
return getImageStoreOnDestinationZoneForTemporaryConversion(destinationCluster, forceConvertToPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
StoragePoolVO selectedStoragePool = primaryDataStoreDao.findById(convertStoragePoolId);
|
||||||
|
checkBeforeSelectingTemporaryConversionStoragePool(selectedStoragePool, convertStoragePoolId, destinationCluster, convertHost);
|
||||||
|
checkDestinationOrTemporaryStoragePoolForConversion(selectedStoragePool, forceConvertToPool, convertHost, importHost);
|
||||||
|
|
||||||
|
return dataStoreManager.getPrimaryDataStore(convertStoragePoolId).getTO();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Map<String, String> createParamsForTemplateFromVmwareVmMigration(String vcenterHost, String datacenterName,
|
protected Map<String, String> createParamsForTemplateFromVmwareVmMigration(String vcenterHost, String datacenterName,
|
||||||
@ -2186,6 +2331,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
cmdList.add(UnmanageVMInstanceCmd.class);
|
cmdList.add(UnmanageVMInstanceCmd.class);
|
||||||
cmdList.add(ListVmsForImportCmd.class);
|
cmdList.add(ListVmsForImportCmd.class);
|
||||||
cmdList.add(ImportVmCmd.class);
|
cmdList.add(ImportVmCmd.class);
|
||||||
|
cmdList.add(ListImportVMTasksCmd.class);
|
||||||
return cmdList;
|
return cmdList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2865,7 +3011,9 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
RemoteKvmInstanceDisksCopyTimeout,
|
RemoteKvmInstanceDisksCopyTimeout,
|
||||||
ConvertVmwareInstanceToKvmTimeout,
|
ConvertVmwareInstanceToKvmTimeout,
|
||||||
ThreadsOnMSToImportVMwareVMFiles,
|
ThreadsOnMSToImportVMwareVMFiles,
|
||||||
ThreadsOnKVMHostToImportVMwareVMFiles
|
ThreadsOnKVMHostToImportVMwareVMFiles,
|
||||||
|
ConvertVmwareInstanceToKvmExtraParamsAllowed,
|
||||||
|
ConvertVmwareInstanceToKvmExtraParamsAllowedList
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,4 +37,6 @@
|
|||||||
|
|
||||||
<bean id="vmImportService" class="org.apache.cloudstack.vm.UnmanagedVMsManagerImpl" />
|
<bean id="vmImportService" class="org.apache.cloudstack.vm.UnmanagedVMsManagerImpl" />
|
||||||
|
|
||||||
|
<bean id="importVmTasksManager" class="org.apache.cloudstack.vm.ImportVmTasksManagerImpl" />
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
|||||||
@ -39,6 +39,7 @@ import java.util.Map;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import com.cloud.offering.DiskOffering;
|
import com.cloud.offering.DiskOffering;
|
||||||
|
import com.cloud.vm.ImportVMTaskVO;
|
||||||
import org.apache.cloudstack.api.ResponseGenerator;
|
import org.apache.cloudstack.api.ResponseGenerator;
|
||||||
import org.apache.cloudstack.api.ResponseObject;
|
import org.apache.cloudstack.api.ResponseObject;
|
||||||
import org.apache.cloudstack.api.ServerApiException;
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
@ -54,6 +55,7 @@ import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationSe
|
|||||||
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
|
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
||||||
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
|
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
|
||||||
@ -236,6 +238,8 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
private DataStoreManager dataStoreManager;
|
private DataStoreManager dataStoreManager;
|
||||||
@Mock
|
@Mock
|
||||||
private StoragePoolHostDao storagePoolHostDao;
|
private StoragePoolHostDao storagePoolHostDao;
|
||||||
|
@Mock
|
||||||
|
private ImportVmTasksManager importVmTasksManager;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private VMInstanceVO virtualMachine;
|
private VMInstanceVO virtualMachine;
|
||||||
@ -244,8 +248,15 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
@Mock
|
@Mock
|
||||||
DeploymentPlanningManager deploymentPlanningManager;
|
DeploymentPlanningManager deploymentPlanningManager;
|
||||||
@Mock
|
@Mock
|
||||||
|
ImportVMTaskVO importVMTaskVO;
|
||||||
|
@Mock
|
||||||
private VMInstanceDetailsDao vmInstanceDetailsDao;
|
private VMInstanceDetailsDao vmInstanceDetailsDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ConfigKey<Boolean> configKeyMockParamsAllowed;
|
||||||
|
@Mock
|
||||||
|
private ConfigKey<String> configKeyMockParamsAllowedList;
|
||||||
|
|
||||||
private static final long virtualMachineId = 1L;
|
private static final long virtualMachineId = 1L;
|
||||||
|
|
||||||
private AutoCloseable closeable;
|
private AutoCloseable closeable;
|
||||||
@ -720,7 +731,6 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
when(dataStore.getTO()).thenReturn(dataStoreTO);
|
when(dataStore.getTO()).thenReturn(dataStoreTO);
|
||||||
|
|
||||||
StoragePoolVO destPool = mock(StoragePoolVO.class);
|
StoragePoolVO destPool = mock(StoragePoolVO.class);
|
||||||
when(destPool.getUuid()).thenReturn(UUID.randomUUID().toString());
|
|
||||||
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);
|
||||||
@ -772,6 +782,9 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
when(agentManager.send(Mockito.eq(convertHostId), Mockito.any(CheckConvertInstanceCommand.class))).thenReturn(checkConvertInstanceAnswer);
|
when(agentManager.send(Mockito.eq(convertHostId), Mockito.any(CheckConvertInstanceCommand.class))).thenReturn(checkConvertInstanceAnswer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
when(importVMTaskVO.getId()).thenReturn(1L);
|
||||||
|
when(importVmTasksManager.createImportVMTaskRecord(any(DataCenter.class), any(Account.class), anyLong(), anyString(),
|
||||||
|
anyString(), anyString(), anyString(), any(Host.class), any(Host.class))).thenReturn(importVMTaskVO);
|
||||||
when(volumeApiService.doesStoragePoolSupportDiskOffering(any(StoragePool.class), any(DiskOffering.class))).thenReturn(true);
|
when(volumeApiService.doesStoragePoolSupportDiskOffering(any(StoragePool.class), any(DiskOffering.class))).thenReturn(true);
|
||||||
|
|
||||||
ConvertInstanceAnswer convertInstanceAnswer = mock(ConvertInstanceAnswer.class);
|
ConvertInstanceAnswer convertInstanceAnswer = mock(ConvertInstanceAnswer.class);
|
||||||
@ -895,7 +908,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, null, poolId);
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null, null, poolId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = CloudRuntimeException.class)
|
@Test(expected = CloudRuntimeException.class)
|
||||||
@ -906,7 +919,7 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
|
when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
|
||||||
when(pool.getClusterId()).thenReturn(100L);
|
when(pool.getClusterId()).thenReturn(100L);
|
||||||
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
||||||
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null, poolId);
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null, null, poolId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -920,7 +933,7 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
HostVO host = mock(HostVO.class);
|
HostVO host = mock(HostVO.class);
|
||||||
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
||||||
when(host.getClusterId()).thenReturn(2L);
|
when(host.getClusterId()).thenReturn(2L);
|
||||||
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, host, poolId);
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, host, null, poolId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -931,7 +944,7 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
StoragePoolVO pool = mock(StoragePoolVO.class);
|
StoragePoolVO pool = mock(StoragePoolVO.class);
|
||||||
when(pool.getScope()).thenReturn(ScopeType.HOST);
|
when(pool.getScope()).thenReturn(ScopeType.HOST);
|
||||||
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
||||||
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null, poolId);
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null, null, poolId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = CloudRuntimeException.class)
|
@Test(expected = CloudRuntimeException.class)
|
||||||
@ -943,14 +956,14 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
when(pool.getClusterId()).thenReturn(1L);
|
when(pool.getClusterId()).thenReturn(1L);
|
||||||
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
||||||
when(pool.getPoolType()).thenReturn(Storage.StoragePoolType.RBD);
|
when(pool.getPoolType()).thenReturn(Storage.StoragePoolType.RBD);
|
||||||
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null, poolId);
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null, null, poolId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = CloudRuntimeException.class)
|
@Test(expected = CloudRuntimeException.class)
|
||||||
public void testSelectInstanceConversionTemporaryLocationNoPoolAvailable() {
|
public void testSelectInstanceConversionTemporaryLocationNoPoolAvailable() {
|
||||||
ClusterVO cluster = getClusterForTests();
|
ClusterVO cluster = getClusterForTests();
|
||||||
when(imageStoreDao.findOneByZoneAndProtocol(anyLong(), anyString())).thenReturn(null);
|
when(imageStoreDao.findOneByZoneAndProtocol(anyLong(), anyString())).thenReturn(null);
|
||||||
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null, null);
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null, null, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -1220,4 +1233,81 @@ public class UnmanagedVMsManagerImplTest {
|
|||||||
Assert.fail("Exception encountered: " + e.getMessage());
|
Assert.fail("Exception encountered: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckConversionStoragePoolSecondaryStorageStaging() {
|
||||||
|
unmanagedVMsManager.checkConversionStoragePool(null, false);
|
||||||
|
Mockito.verifyNoInteractions(primaryDataStoreDao);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testCheckConversionStoragePoolTemporarySecondaryStorageForceConvertToPool() {
|
||||||
|
unmanagedVMsManager.checkConversionStoragePool(null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckConversionStoragePoolPrimaryStagingPool() {
|
||||||
|
StoragePoolVO destPool = mock(StoragePoolVO.class);
|
||||||
|
long destPoolId = 1L;
|
||||||
|
Mockito.when(primaryDataStoreDao.findById(destPoolId)).thenReturn(destPool);
|
||||||
|
unmanagedVMsManager.checkConversionStoragePool(destPoolId, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckConversionStoragePoolPrimaryStagingPoolTypeAllowedForce() {
|
||||||
|
StoragePoolVO destPool = mock(StoragePoolVO.class);
|
||||||
|
Mockito.when(destPool.getPoolType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem);
|
||||||
|
long destPoolId = 1L;
|
||||||
|
Mockito.when(primaryDataStoreDao.findById(destPoolId)).thenReturn(destPool);
|
||||||
|
unmanagedVMsManager.checkConversionStoragePool(destPoolId, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testCheckConversionStoragePoolPrimaryStagingPoolTypeNotAllowedForce() {
|
||||||
|
StoragePoolVO destPool = mock(StoragePoolVO.class);
|
||||||
|
Mockito.when(destPool.getPoolType()).thenReturn(Storage.StoragePoolType.RBD);
|
||||||
|
long destPoolId = 1L;
|
||||||
|
Mockito.when(primaryDataStoreDao.findById(destPoolId)).thenReturn(destPool);
|
||||||
|
unmanagedVMsManager.checkConversionStoragePool(destPoolId, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckExtraParamsAllowedEmptyParams() {
|
||||||
|
unmanagedVMsManager.checkExtraParamsAllowed(null);
|
||||||
|
Mockito.verifyNoInteractions(configKeyMockParamsAllowed);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ServerApiException.class)
|
||||||
|
public void testCheckExtraParamsAllowedDisabledByAdministrator() {
|
||||||
|
unmanagedVMsManager.ConvertVmwareInstanceToKvmExtraParamsAllowed = configKeyMockParamsAllowed;
|
||||||
|
Mockito.when(configKeyMockParamsAllowed.value()).thenReturn(false);
|
||||||
|
unmanagedVMsManager.checkExtraParamsAllowed("--mac 00:0c:29:e6:3d:9d:ip:192.168.0.89,192.168.0.1,24,192.168.0.254 -x");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ServerApiException.class)
|
||||||
|
public void testCheckExtraParamsAllowedEnabledButEmptyAllowedList() {
|
||||||
|
unmanagedVMsManager.ConvertVmwareInstanceToKvmExtraParamsAllowed = configKeyMockParamsAllowed;
|
||||||
|
unmanagedVMsManager.ConvertVmwareInstanceToKvmExtraParamsAllowedList = configKeyMockParamsAllowedList;
|
||||||
|
Mockito.when(configKeyMockParamsAllowed.value()).thenReturn(true);
|
||||||
|
Mockito.when(configKeyMockParamsAllowedList.value()).thenReturn(null);
|
||||||
|
unmanagedVMsManager.checkExtraParamsAllowed("--mac 00:0c:29:e6:3d:9d:ip:192.168.0.89,192.168.0.1,24,192.168.0.254 -x");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckExtraParamsAllowedEnabledAndAllowedList() {
|
||||||
|
unmanagedVMsManager.ConvertVmwareInstanceToKvmExtraParamsAllowed = configKeyMockParamsAllowed;
|
||||||
|
unmanagedVMsManager.ConvertVmwareInstanceToKvmExtraParamsAllowedList = configKeyMockParamsAllowedList;
|
||||||
|
Mockito.when(configKeyMockParamsAllowed.value()).thenReturn(true);
|
||||||
|
Mockito.when(configKeyMockParamsAllowedList.value()).thenReturn("mac,network,x");
|
||||||
|
unmanagedVMsManager.checkExtraParamsAllowed("--mac 00:0c:29:e6:3d:9d:ip:192.168.0.89,192.168.0.1,24,192.168.0.254 -x");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ServerApiException.class)
|
||||||
|
public void testCheckExtraParamsAllowedEnabledParamNotInTheAllowedList() {
|
||||||
|
unmanagedVMsManager.ConvertVmwareInstanceToKvmExtraParamsAllowed = configKeyMockParamsAllowed;
|
||||||
|
unmanagedVMsManager.ConvertVmwareInstanceToKvmExtraParamsAllowedList = configKeyMockParamsAllowedList;
|
||||||
|
Mockito.when(configKeyMockParamsAllowed.value()).thenReturn(true);
|
||||||
|
Mockito.when(configKeyMockParamsAllowedList.value()).thenReturn("network,x");
|
||||||
|
unmanagedVMsManager.checkExtraParamsAllowed("--mac 00:0c:29:e6:3d:9d:ip:192.168.0.89,192.168.0.1,24,192.168.0.254 -x");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -272,7 +272,8 @@ known_categories = {
|
|||||||
'Extension' : 'Extension',
|
'Extension' : 'Extension',
|
||||||
'Extensions' : 'Extension',
|
'Extensions' : 'Extension',
|
||||||
'CustomAction' : 'Extension',
|
'CustomAction' : 'Extension',
|
||||||
'CustomActions' : 'Extension'
|
'CustomActions' : 'Extension',
|
||||||
|
'ImportVmTask': 'Import VM Task'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1089,6 +1089,7 @@
|
|||||||
"label.forcks": "For CKS",
|
"label.forcks": "For CKS",
|
||||||
"label.forbidden": "Forbidden",
|
"label.forbidden": "Forbidden",
|
||||||
"label.forced": "Force",
|
"label.forced": "Force",
|
||||||
|
"label.force.convert.to.pool": "Force converting to storage pool directly (not using temporary storage for conversion)",
|
||||||
"label.force.ms.to.import.vm.files": "Enable to force OVF Download via Management Server. Disable to use KVM Host ovftool (if installed)",
|
"label.force.ms.to.import.vm.files": "Enable to force OVF Download via Management Server. Disable to use KVM Host ovftool (if installed)",
|
||||||
"label.force.update.os.type": "Force update OS type",
|
"label.force.update.os.type": "Force update OS type",
|
||||||
"label.force.stop": "Force stop",
|
"label.force.stop": "Force stop",
|
||||||
@ -3732,8 +3733,10 @@
|
|||||||
"message.select.deselect.desired.options": "Please select / deselect the desired options",
|
"message.select.deselect.desired.options": "Please select / deselect the desired options",
|
||||||
"message.select.deselect.to.sort": "Please select / deselect to sort the values",
|
"message.select.deselect.to.sort": "Please select / deselect to sort the values",
|
||||||
"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.destination.storage.instance.conversion": "(Optional) Select a Primary Storage destination for the converted disks",
|
||||||
"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.extra.parameters.for.instance.conversion": "(Optional) Pass extra parameters to the virt-v2v command on the conversion host",
|
||||||
"message.select.kvm.host.instance.conversion": "(Optional) Select a KVM host in the Zone to perform the instance conversion through virt-v2v",
|
"message.select.kvm.host.instance.conversion": "(Optional) Select a KVM host in the Zone to perform the instance conversion through virt-v2v",
|
||||||
"message.select.kvm.host.instance.import": "(Optional) Select a KVM host in the Cluster to perform the importing of the converted instance",
|
"message.select.kvm.host.instance.import": "(Optional) Select a KVM host in the Cluster to perform the importing of the converted instance",
|
||||||
"message.select.load.balancer.rule": "Please select a load balancer rule for your AutoScale Instance group.",
|
"message.select.load.balancer.rule": "Please select a load balancer rule for your AutoScale Instance group.",
|
||||||
@ -3741,7 +3744,7 @@
|
|||||||
"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.temporary.storage.instance.conversion": "(Optional) Select a staging storage for the converted disks",
|
||||||
"message.select.volume.to.continue": "Please select a volume to continue.",
|
"message.select.volume.to.continue": "Please select a volume to continue.",
|
||||||
"message.select.vm.to.continue": "Please select an Instance to continue.",
|
"message.select.vm.to.continue": "Please select an Instance to continue.",
|
||||||
"message.select.zone.description": "Select type of Zone basic/advanced.",
|
"message.select.zone.description": "Select type of Zone basic/advanced.",
|
||||||
|
|||||||
@ -152,6 +152,12 @@
|
|||||||
</a-row>
|
</a-row>
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item name="forceconverttopool" ref="forceconverttopool" v-if="selectedVmwareVcenter">
|
||||||
|
<template #label>
|
||||||
|
<tooltip-label :title="$t('label.force.convert.to.pool')" :tooltip="apiParams.forceconverttopool.description"/>
|
||||||
|
</template>
|
||||||
|
<a-switch v-model:checked="form.forceconverttopool" @change="onForceConvertToPoolChange" />
|
||||||
|
</a-form-item>
|
||||||
<a-form-item name="converthostid" ref="converthostid">
|
<a-form-item name="converthostid" ref="converthostid">
|
||||||
<check-box-select-pair
|
<check-box-select-pair
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
@ -179,17 +185,21 @@
|
|||||||
<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: 5px"
|
|
||||||
v-if="cluster.hypervisortype === 'KVM' && selectedVmwareVcenter"
|
v-if="cluster.hypervisortype === 'KVM' && selectedVmwareVcenter"
|
||||||
:resourceKey="cluster.id"
|
:resourceKey="cluster.id"
|
||||||
:selectOptions="storageOptionsForConversion"
|
:selectOptions="storageOptionsForConversion"
|
||||||
:checkBoxLabel="$t('message.select.temporary.storage.instance.conversion')"
|
:checkBoxLabel="switches.forceConvertToPool ? $t('message.select.destination.storage.instance.conversion') : $t('message.select.temporary.storage.instance.conversion')"
|
||||||
:defaultCheckBoxValue="false"
|
:defaultCheckBoxValue="false"
|
||||||
:reversed="false"
|
:reversed="false"
|
||||||
@handle-checkselectpair-change="updateSelectedStorageOptionForConversion"
|
@handle-checkselectpair-change="updateSelectedStorageOptionForConversion"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item v-if="showStoragePoolsForConversion" name="convertstoragepool" ref="convertstoragepool" :label="$t('label.storagepool')">
|
<a-form-item
|
||||||
|
v-if="showStoragePoolsForConversion"
|
||||||
|
name="convertstoragepool"
|
||||||
|
ref="convertstoragepool"
|
||||||
|
:label="$t('label.storagepool')"
|
||||||
|
>
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="form.convertstoragepoolid"
|
v-model:value="form.convertstoragepoolid"
|
||||||
defaultActiveFirstOption
|
defaultActiveFirstOption
|
||||||
@ -204,6 +214,18 @@
|
|||||||
</a-select-option>
|
</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item name="extraparams" ref="extraparams">
|
||||||
|
<a-checkbox
|
||||||
|
v-if="cluster.hypervisortype === 'KVM' && selectedVmwareVcenter && vmwareToKvmExtraParamsAllowed"
|
||||||
|
v-model:checked="vmwareToKvmExtraParamsSelected">
|
||||||
|
{{ $t('message.select.extra.parameters.for.instance.conversion') }}
|
||||||
|
</a-checkbox>
|
||||||
|
<a-input
|
||||||
|
v-if="vmwareToKvmExtraParamsSelected"
|
||||||
|
v-model:value="vmwareToKvmExtraParams"
|
||||||
|
:placeholder="$t('label.extra')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
<a-form-item name="forcemstoimportvmfiles" ref="forcemstoimportvmfiles" v-if="selectedVmwareVcenter">
|
<a-form-item name="forcemstoimportvmfiles" ref="forcemstoimportvmfiles" v-if="selectedVmwareVcenter">
|
||||||
<template #label>
|
<template #label>
|
||||||
<tooltip-label :title="$t('label.force.ms.to.import.vm.files')" :tooltip="apiParams.forcemstoimportvmfiles.description"/>
|
<tooltip-label :title="$t('label.force.ms.to.import.vm.files')" :tooltip="apiParams.forcemstoimportvmfiles.description"/>
|
||||||
@ -529,7 +551,10 @@ export default {
|
|||||||
title: this.$t('label.rootdisk')
|
title: this.$t('label.rootdisk')
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
selectedRootDiskSources: []
|
selectedRootDiskSources: [],
|
||||||
|
vmwareToKvmExtraParamsAllowed: false,
|
||||||
|
vmwareToKvmExtraParamsSelected: false,
|
||||||
|
vmwareToKvmExtraParams: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeCreate () {
|
beforeCreate () {
|
||||||
@ -724,6 +749,7 @@ export default {
|
|||||||
migrateallowed: this.switches.migrateAllowed,
|
migrateallowed: this.switches.migrateAllowed,
|
||||||
forced: this.switches.forced,
|
forced: this.switches.forced,
|
||||||
forcemstoimportvmfiles: this.switches.forceMsToImportVmFiles,
|
forcemstoimportvmfiles: this.switches.forceMsToImportVmFiles,
|
||||||
|
forceconverttopool: this.switches.forceConvertToPool,
|
||||||
domainid: null,
|
domainid: null,
|
||||||
account: null
|
account: null
|
||||||
})
|
})
|
||||||
@ -749,6 +775,20 @@ export default {
|
|||||||
if (this.resource?.disk?.length > 1) {
|
if (this.resource?.disk?.length > 1) {
|
||||||
this.updateSelectedRootDisk()
|
this.updateSelectedRootDisk()
|
||||||
}
|
}
|
||||||
|
this.fetchVmwareToKVMExtraConfigsSetting()
|
||||||
|
},
|
||||||
|
fetchVmwareToKVMExtraConfigsSetting () {
|
||||||
|
const params = {
|
||||||
|
name: 'convert.vmware.instance.to.kvm.extra.params.allowed'
|
||||||
|
}
|
||||||
|
getAPI('listConfigurations', params).then(json => {
|
||||||
|
if (json.listconfigurationsresponse.configuration !== null) {
|
||||||
|
const config = json.listconfigurationsresponse.configuration[0]
|
||||||
|
if (config && config.name === params.name) {
|
||||||
|
this.vmwareToKvmExtraParamsAllowed = config.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
getMeta (obj, metaKeys) {
|
getMeta (obj, metaKeys) {
|
||||||
var meta = []
|
var meta = []
|
||||||
@ -1027,20 +1067,23 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
resetStorageOptionsForConversion () {
|
resetStorageOptionsForConversion () {
|
||||||
this.storageOptionsForConversion = [
|
this.storageOptionsForConversion = this.switches.forceConvertToPool ? [] : [{
|
||||||
{
|
|
||||||
id: 'secondary',
|
id: 'secondary',
|
||||||
name: 'Secondary Storage'
|
name: 'Secondary Storage'
|
||||||
}, {
|
}]
|
||||||
|
this.storageOptionsForConversion.push({
|
||||||
id: 'primary',
|
id: 'primary',
|
||||||
name: 'Primary Storage'
|
name: 'Primary Storage'
|
||||||
}
|
})
|
||||||
]
|
|
||||||
},
|
},
|
||||||
onSelectRootDisk (val) {
|
onSelectRootDisk (val) {
|
||||||
this.selectedRootDiskIndex = val
|
this.selectedRootDiskIndex = val
|
||||||
this.updateSelectedRootDisk()
|
this.updateSelectedRootDisk()
|
||||||
},
|
},
|
||||||
|
onForceConvertToPoolChange (val) {
|
||||||
|
this.switches.forceConvertToPool = val
|
||||||
|
this.resetStorageOptionsForConversion()
|
||||||
|
},
|
||||||
updateSelectedRootDisk () {
|
updateSelectedRootDisk () {
|
||||||
var rootDisk = this.resource.disk[this.selectedRootDiskIndex]
|
var rootDisk = this.resource.disk[this.selectedRootDiskIndex]
|
||||||
rootDisk.size = rootDisk.capacity / (1024 * 1024 * 1024)
|
rootDisk.size = rootDisk.capacity / (1024 * 1024 * 1024)
|
||||||
@ -1156,7 +1199,13 @@ export default {
|
|||||||
if (this.selectedStoragePoolForConversion) {
|
if (this.selectedStoragePoolForConversion) {
|
||||||
params.convertinstancepoolid = this.selectedStoragePoolForConversion
|
params.convertinstancepoolid = this.selectedStoragePoolForConversion
|
||||||
}
|
}
|
||||||
|
if (this.vmwareToKvmExtraParams) {
|
||||||
|
params.extraparams = this.vmwareToKvmExtraParams
|
||||||
|
}
|
||||||
params.forcemstoimportvmfiles = values.forcemstoimportvmfiles
|
params.forcemstoimportvmfiles = values.forcemstoimportvmfiles
|
||||||
|
if (values.forceconverttopool) {
|
||||||
|
params.forceconverttopool = values.forceconverttopool
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var keys = ['hostname', 'domainid', 'projectid', 'account', 'migrateallowed', 'forced', 'forcemstoimportvmfiles']
|
var keys = ['hostname', 'domainid', 'projectid', 'account', 'migrateallowed', 'forced', 'forcemstoimportvmfiles']
|
||||||
if (this.templateType !== 'auto') {
|
if (this.templateType !== 'auto') {
|
||||||
|
|||||||
150
ui/src/views/tools/ImportVmTasks.vue
Normal file
150
ui/src/views/tools/ImportVmTasks.vue
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-card class="instances-card">
|
||||||
|
<template #title>
|
||||||
|
Import VM Tasks
|
||||||
|
<a-tooltip :title="'Running Import VM Tasks'">
|
||||||
|
<info-circle-outlined />
|
||||||
|
</a-tooltip>
|
||||||
|
<a-button
|
||||||
|
style="margin-left: 12px; margin-top: 4px"
|
||||||
|
:loading="loading"
|
||||||
|
size="small"
|
||||||
|
shape="round"
|
||||||
|
@click="fetchData()">
|
||||||
|
<template #icon><reload-outlined /></template>
|
||||||
|
</a-button>
|
||||||
|
<a-select
|
||||||
|
:placeholder="$t('label.filterby')"
|
||||||
|
:value="importVmTasksFilterValue"
|
||||||
|
style="min-width: 100px; margin-left: 10px; margin-bottom: 5px"
|
||||||
|
size=small
|
||||||
|
@change="onFilterChange"
|
||||||
|
showSearch
|
||||||
|
optionFilterProp="label"
|
||||||
|
:filterOption="(input, option) => {
|
||||||
|
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #suffixIcon><filter-outlined class="ant-select-suffix" /></template>
|
||||||
|
<a-select-option
|
||||||
|
v-for="filter in filters"
|
||||||
|
:key="filter"
|
||||||
|
:label="$t('label.' + filter)"
|
||||||
|
>
|
||||||
|
{{ $t('label.' + filter) }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</template>
|
||||||
|
<a-table
|
||||||
|
:data-source="tasks"
|
||||||
|
:columns="columns">
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'convertinstancehostid'">
|
||||||
|
<router-link :to="{ path: '/host/' + record.convertinstancehostid }">{{ record.convertinstancehostname }}</router-link>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'displayname'">
|
||||||
|
<router-link v-if="record.virtualmachineid" :to="{ path: '/vm/' + record.virtualmachineid }">{{ record.displayname }}</router-link>
|
||||||
|
<span v-else>{{ record.displayname }}</span>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ImportVmTasks',
|
||||||
|
components: {
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
tasks: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
key: 'displayname',
|
||||||
|
title: 'VM Display Name',
|
||||||
|
dataIndex: 'displayname'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'convertinstancehostid',
|
||||||
|
title: 'Conversion Host',
|
||||||
|
dataIndex: 'convertinstancehostid'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'step',
|
||||||
|
title: 'Current Step',
|
||||||
|
dataIndex: 'step'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'stepduration',
|
||||||
|
title: 'Current Step Duration',
|
||||||
|
dataIndex: 'stepduration'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'description',
|
||||||
|
title: 'Description',
|
||||||
|
dataIndex: 'description'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'duration',
|
||||||
|
title: 'Total Duration',
|
||||||
|
dataIndex: 'duration'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'sourcevmname',
|
||||||
|
title: 'Source VM Name',
|
||||||
|
dataIndex: 'sourcevmname'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'vcenter',
|
||||||
|
title: 'vCenter',
|
||||||
|
dataIndex: 'vcenter'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'datacentername',
|
||||||
|
title: 'Datacenter Name',
|
||||||
|
dataIndex: 'datacentername'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
return {
|
||||||
|
columns,
|
||||||
|
filters: ['running', 'completed'],
|
||||||
|
filterValue: 'running'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetchData () {
|
||||||
|
this.$emit('fetch-import-vm-tasks', this.filterValue)
|
||||||
|
},
|
||||||
|
onFilterChange (e) {
|
||||||
|
this.filterValue = e
|
||||||
|
this.fetchData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -333,6 +333,9 @@
|
|||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
<a-divider />
|
<a-divider />
|
||||||
|
|
||||||
|
<a-tabs v-model:activeKey="activeTabKey" @change="onTabChange">
|
||||||
|
<a-tab-pane :key=1 tab="Instances Listing">
|
||||||
<a-row :gutter="12">
|
<a-row :gutter="12">
|
||||||
<a-col v-if="!isDiskImport" :md="24" :lg="(!isMigrateFromVmware && showManagedInstances) ? 12 : 24">
|
<a-col v-if="!isDiskImport" :md="24" :lg="(!isMigrateFromVmware && showManagedInstances) ? 12 : 24">
|
||||||
<a-card class="instances-card">
|
<a-card class="instances-card">
|
||||||
@ -493,6 +496,16 @@
|
|||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane :key=2 tab="Import VM Tasks" v-if="isMigrateFromVmware">
|
||||||
|
<ImportVmTasks
|
||||||
|
:tasks="importVmTasks"
|
||||||
|
:loading="loadingImportVmTasks"
|
||||||
|
@fetch-import-vm-tasks="fetchImportVmTasks"
|
||||||
|
/>
|
||||||
|
</a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|
||||||
<a-modal
|
<a-modal
|
||||||
@ -546,6 +559,7 @@ import ImportUnmanagedInstances from '@/views/tools/ImportUnmanagedInstance'
|
|||||||
import ResourceIcon from '@/components/view/ResourceIcon'
|
import ResourceIcon from '@/components/view/ResourceIcon'
|
||||||
import SelectVmwareVcenter from '@/views/tools/SelectVmwareVcenter'
|
import SelectVmwareVcenter from '@/views/tools/SelectVmwareVcenter'
|
||||||
import TooltipLabel from '@/components/widgets/TooltipLabel.vue'
|
import TooltipLabel from '@/components/widgets/TooltipLabel.vue'
|
||||||
|
import ImportVmTasks from '@/views/tools/ImportVmTasks.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -555,7 +569,8 @@ export default {
|
|||||||
SearchView,
|
SearchView,
|
||||||
ImportUnmanagedInstances,
|
ImportUnmanagedInstances,
|
||||||
ResourceIcon,
|
ResourceIcon,
|
||||||
SelectVmwareVcenter
|
SelectVmwareVcenter,
|
||||||
|
ImportVmTasks
|
||||||
},
|
},
|
||||||
name: 'ManageVms',
|
name: 'ManageVms',
|
||||||
data () {
|
data () {
|
||||||
@ -747,7 +762,10 @@ export default {
|
|||||||
selectedUnmanagedInstance: {},
|
selectedUnmanagedInstance: {},
|
||||||
query: {},
|
query: {},
|
||||||
vmwareVcenterType: undefined,
|
vmwareVcenterType: undefined,
|
||||||
selectedVmwareVcenter: undefined
|
selectedVmwareVcenter: undefined,
|
||||||
|
activeTabKey: 1,
|
||||||
|
loadingImportVmTasks: false,
|
||||||
|
importVmTasks: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
@ -1084,6 +1102,7 @@ export default {
|
|||||||
this.page.managed = 1
|
this.page.managed = 1
|
||||||
this.managedInstances = []
|
this.managedInstances = []
|
||||||
this.managedInstancesSelectedRowKeys = []
|
this.managedInstancesSelectedRowKeys = []
|
||||||
|
this.activeTabKey = 1
|
||||||
},
|
},
|
||||||
onSelectHypervisor (value) {
|
onSelectHypervisor (value) {
|
||||||
this.sourceHypervisor = value
|
this.sourceHypervisor = value
|
||||||
@ -1154,6 +1173,27 @@ export default {
|
|||||||
this.updateQuery('scope', value)
|
this.updateQuery('scope', value)
|
||||||
this.fetchOptions(this.params.pools, 'pools', value)
|
this.fetchOptions(this.params.pools, 'pools', value)
|
||||||
},
|
},
|
||||||
|
onTabChange (e) {
|
||||||
|
if (e === 2) {
|
||||||
|
this.fetchImportVmTasks()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fetchImportVmTasks (filter) {
|
||||||
|
this.loadingImportVmTasks = true
|
||||||
|
const params = {
|
||||||
|
zoneid: this.zoneId
|
||||||
|
}
|
||||||
|
if (filter && filter === 'completed') {
|
||||||
|
params.showcompleted = true
|
||||||
|
}
|
||||||
|
getAPI('listImportVmTasks', params).then(response => {
|
||||||
|
this.importVmTasks = response.listimportvmtasksresponse.importvmtask || []
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notifyError(error)
|
||||||
|
}).finally(() => {
|
||||||
|
this.loadingImportVmTasks = false
|
||||||
|
})
|
||||||
|
},
|
||||||
fetchInstances () {
|
fetchInstances () {
|
||||||
this.fetchUnmanagedInstances()
|
this.fetchUnmanagedInstances()
|
||||||
if (this.isUnmanaged) {
|
if (this.isUnmanaged) {
|
||||||
|
|||||||
@ -244,6 +244,7 @@ public class Script implements Callable<String> {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
_logger.trace(String.format("Creating process for command [%s].", commandLine));
|
_logger.trace(String.format("Creating process for command [%s].", commandLine));
|
||||||
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(command);
|
ProcessBuilder pb = new ProcessBuilder(command);
|
||||||
pb.redirectErrorStream(true);
|
pb.redirectErrorStream(true);
|
||||||
if (_workDir != null)
|
if (_workDir != null)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user