Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,6 @@ public class ApiConstants {
public static final String SHOW_CAPACITIES = "showcapacities";
public static final String SHOW_REMOVED = "showremoved";
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_UNIQUE = "showunique";
public static final String SIGNATURE = "signature";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
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.ImportVmTask;
import org.apache.cloudstack.vm.ImportVmTasksManager;

import javax.inject.Inject;
Expand Down Expand Up @@ -75,11 +76,8 @@ public class ListImportVMTasksCmd extends BaseListCmd {
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;
@Parameter(name = ApiConstants.STATE, type = CommandType.STRING, description = "List tasks by status, valid options are: Running, Completed, Failed")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we add a since field?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Pearl1594, the since parameter is added on the API class entirely and it will use that one as all the parameters have been added on the same version (4.22)

private String state;

public Long getZoneId() {
return zoneId;
Expand All @@ -97,12 +95,8 @@ public Long getConvertHostId() {
return convertHostId;
}

public boolean isListAll() {
return listAll;
}

public boolean isShowCompleted() {
return showCompleted;
public String getState() {
return state == null ? ImportVmTask.TaskState.Running.name() : state;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ public class ImportVMTaskResponse extends BaseResponse {
@Param(description = "the display name of the importing VM")
private String displayName;

@SerializedName(ApiConstants.STATE)
@Param(description = "the state of the importing VM task")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since?

private String state;

@SerializedName(ApiConstants.VCENTER)
@Param(description = "the vcenter name of the importing VM task")
private String vcenter;
Expand Down Expand Up @@ -242,4 +246,12 @@ public Date getLastUpdated() {
public void setLastUpdated(Date lastUpdated) {
this.lastUpdated = lastUpdated;
}

public String getState() {
return state;
}

public void setState(String state) {
this.state = state;
}
}
15 changes: 14 additions & 1 deletion api/src/main/java/org/apache/cloudstack/vm/ImportVmTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,19 @@

public interface ImportVmTask extends Identity, InternalIdentity {
enum Step {
Prepare, CloningInstance, ConvertingInstance, Importing, Cleaning, Completed
Prepare, CloningInstance, ConvertingInstance, Importing, Completed
}

enum TaskState {
Running, Completed, Failed;

public static TaskState getValue(String state) {
for (TaskState s : TaskState.values()) {
if (s.name().equalsIgnoreCase(state)) {
return s;
}
}
throw new IllegalArgumentException("Invalid task state: " + state);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ ImportVmTask createImportVMTaskRecord(DataCenter zone, Account owner, long userI
void updateImportVMTaskStep(ImportVmTask importVMTaskVO, DataCenter zone, Account owner, Host convertHost,
Host importHost, Long vmId, ImportVmTask.Step step);

boolean removeImportVMTask(long taskId);
void updateImportVMTaskErrorState(ImportVmTask importVMTaskVO, ImportVmTask.TaskState state, String errorMsg);
}
11 changes: 11 additions & 0 deletions engine/schema/src/main/java/com/cloud/vm/ImportVMTaskVO.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ public ImportVMTaskVO() {
@Column(name = "step")
private Step step;

@Column(name = "state")
private TaskState state;

@Column(name = "description")
private String description;

Expand Down Expand Up @@ -217,6 +220,14 @@ public void setStep(Step step) {
this.step = step;
}

public TaskState getState() {
return state;
}

public void setState(TaskState state) {
this.state = state;
}

public String getDescription() {
return description;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@
//
package com.cloud.vm.dao;

import com.cloud.utils.Pair;
import com.cloud.utils.db.GenericDao;
import com.cloud.vm.ImportVMTaskVO;

import org.apache.cloudstack.vm.ImportVmTask;
import java.util.List;

public interface ImportVMTaskDao extends GenericDao<ImportVMTaskVO, Long> {

List<ImportVMTaskVO> listImportVMTasks(Long zoneId, Long accountId, String vcenter, Long convertHostId, boolean showCompleted);
Pair<List<ImportVMTaskVO>, Integer> listImportVMTasks(Long zoneId, Long accountId, String vcenter, Long convertHostId,
ImportVmTask.TaskState state, Long startIndex, Long pageSizeVal);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
// under the License.
package com.cloud.vm.dao;

import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
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.cloudstack.vm.ImportVmTask;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

Expand All @@ -41,12 +44,14 @@ void init() {
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.and("state", AllFieldsSearch.entity().getState(), SearchCriteria.Op.EQ);
AllFieldsSearch.done();
}


@Override
public List<ImportVMTaskVO> listImportVMTasks(Long zoneId, Long accountId, String vcenter, Long convertHostId, boolean showCompleted) {
public Pair<List<ImportVMTaskVO>, Integer> listImportVMTasks(Long zoneId, Long accountId, String vcenter, Long convertHostId,
ImportVmTask.TaskState state, Long startIndex, Long pageSizeVal) {
SearchCriteria<ImportVMTaskVO> sc = AllFieldsSearch.create();
if (zoneId != null) {
sc.setParameters("zoneId", zoneId);
Expand All @@ -60,6 +65,8 @@ public List<ImportVMTaskVO> listImportVMTasks(Long zoneId, Long accountId, Strin
if (convertHostId != null) {
sc.setParameters("convertHostId", convertHostId);
}
return showCompleted ? listIncludingRemovedBy(sc) : listBy(sc);
sc.setParameters("state", state);
Filter filter = new Filter(ImportVMTaskVO.class, "created", false, startIndex, pageSizeVal);
return searchAndCount(sc, filter);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ CREATE TABLE IF NOT EXISTS `cloud`.`import_vm_task`(
`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',
`step` varchar(20) COMMENT 'Importing VM Task Step',
`state` varchar(20) COMMENT 'Importing VM Task State',
`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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@
import com.cloud.user.Account;
import com.cloud.user.AccountService;
import com.cloud.utils.DateUtil;
import com.cloud.utils.Pair;
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.ApiErrorCode;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.admin.vm.ListImportVMTasksCmd;
import org.apache.cloudstack.api.response.ImportVMTaskResponse;
import org.apache.cloudstack.api.response.ListResponse;
Expand Down Expand Up @@ -72,22 +75,25 @@ public ListResponse<ImportVMTaskResponse> listImportVMTasks(ListImportVMTasksCmd
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);
Long startIndex = cmd.getStartIndex();
Long pageSizeVal = cmd.getPageSizeVal();

ImportVmTask.TaskState state;
try {
state = ImportVmTask.TaskState.getValue(cmd.getState());
} catch (IllegalArgumentException e) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid value for task state: " + cmd.getState());
}

Pair<List<ImportVMTaskVO>, Integer> result = importVMTaskDao.listImportVMTasks(zoneId, accountId, vcenter, convertHostId, state, startIndex, pageSizeVal);
List<ImportVMTaskVO> tasks = result.first();

List<ImportVMTaskResponse> responses = new ArrayList<>();
for (ImportVMTaskVO task : tasks) {
responses.add(createImportVMTaskResponse(task));
}
ListResponse<ImportVMTaskResponse> listResponses = new ListResponse<>();
listResponses.setResponses(responses, responses.size());
listResponses.setResponses(responses, result.second());
return listResponses;
}

Expand All @@ -98,6 +104,7 @@ public ImportVmTask createImportVMTaskRecord(DataCenter zone, Account owner, lon
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());
importVMTaskVO.setState(ImportVmTask.TaskState.Running);
return importVMTaskDao.persist(importVMTaskVO);
}

Expand All @@ -111,7 +118,6 @@ private String getStepDescription(ImportVMTaskVO importVMTaskVO, Host convertHos
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) {
Expand Down Expand Up @@ -142,13 +148,19 @@ public void updateImportVMTaskStep(ImportVmTask importVMTask, DataCenter zone, A
Duration duration = Duration.between(importVMTaskVO.getCreated().toInstant(), updatedDate.toInstant());
importVMTaskVO.setDuration(duration.toMillis());
importVMTaskVO.setVmId(vmId);
importVMTaskVO.setState(ImportVmTask.TaskState.Completed);
}
importVMTaskDao.update(importVMTaskVO.getId(), importVMTaskVO);
}

@Override
public boolean removeImportVMTask(long taskId) {
return importVMTaskDao.remove(taskId);
public void updateImportVMTaskErrorState(ImportVmTask importVMTask, ImportVmTask.TaskState state, String errorMsg) {
ImportVMTaskVO importVMTaskVO = (ImportVMTaskVO) importVMTask;
Date updatedDate = DateUtil.now();
importVMTaskVO.setUpdated(updatedDate);
importVMTaskVO.setState(state);
importVMTaskVO.setDescription(errorMsg);
importVMTaskDao.update(importVMTaskVO.getId(), importVMTaskVO);
}

private ImportVMTaskResponse createImportVMTaskResponse(ImportVMTaskVO task) {
Expand All @@ -169,19 +181,21 @@ private ImportVMTaskResponse createImportVMTaskResponse(ImportVMTaskVO task) {
response.setDisplayName(task.getDisplayName());
response.setStep(getStepDisplayField(task.getStep()));
response.setDescription(task.getDescription());
response.setState(task.getState().name());

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()));

if (updated != null) {
if (ImportVmTask.TaskState.Running == task.getState()) {
Duration stepDuration = Duration.between(updated.toInstant(), currentDate.toInstant());
response.setStepDuration(getDurationDisplay(stepDuration.toMillis()));
} else {
Duration totalDuration = Duration.between(task.getCreated().toInstant(), updated.toInstant());
response.setDuration(getDurationDisplay(totalDuration.toMillis()));
}
}

HostVO host = hostDao.findById(task.getConvertHostId());
if (host != null) {
response.setConvertInstanceHostId(host.getUuid());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1779,10 +1779,10 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster
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()));
importVmTasksManager.updateImportVMTaskStep(importVMTask, zone, owner, convertHost, importHost, userVm.getId(), Completed);
importVmTasksManager.removeImportVMTask(importVMTask.getId());
return userVm;
} catch (CloudRuntimeException e) {
logger.error(String.format("Error importing VM: %s", e.getMessage()), e);
importVmTasksManager.updateImportVMTaskErrorState(importVMTask, ImportVmTask.TaskState.Failed, e.getMessage());
ActionEventUtils.onCompletedActionEvent(userId, owner.getId(), EventVO.LEVEL_ERROR, EventTypes.EVENT_VM_IMPORT,
cmd.getEventDescription(), null, null, 0);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,6 @@ private void baseTestImportVmFromVmwareToKvm(VcenterParameter vcenterParameter,
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);
Expand Down
2 changes: 2 additions & 0 deletions ui/public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,7 @@
"label.import.instance": "Import Instance",
"label.import.offering": "Import Offering",
"label.import.role": "Import Role",
"label.import.vm.tasks": "Import VM Tasks",
"label.import.volume": "Import Volume",
"label.inactive": "Inactive",
"label.inbuilt": "Inbuilt",
Expand Down Expand Up @@ -3520,6 +3521,7 @@
"message.host.dedication.released": "Host dedication released.",
"message.host.external.datadisk": "Usage of data disks for the selected template is not applicable",
"message.import.running.instance.warning": "The selected VM is powered-on on the VMware Datacenter. The recommended state to convert a VMware VM into KVM is powered-off after a graceful shutdown of the guest OS.",
"message.import.vm.tasks": "Import from VMware to KVM tasks",
"message.import.volume": "Please specify the domain, account or project name. <br>If not set, the volume will be imported for the caller.",
"message.info.cloudian.console": "Cloudian Management Console should open in another window.",
"message.installwizard.cloudstack.helptext.website": " * Project website:\t ",
Expand Down
Loading
Loading