From 3b466f8e788f39a41d80a09b0478292320c50cfa Mon Sep 17 00:00:00 2001 From: Alexander Verhaar Date: Wed, 23 Jun 2021 22:03:22 +0200 Subject: [PATCH 01/14] First try --- .../wrapper/LibvirtGetDomJobInfoWrapper.java | 46 ++++++ .../api/command/user/vm/GetVMProgressCmd.java | 60 ++++++++ .../api/response/VmProgressResponse.java | 142 ++++++++++++++++++ .../main/java/com/cloud/vm/UserVmService.java | 6 + .../com/cloud/vm/VirtualMachineManager.java | 4 + .../cloud/vm/VirtualMachineManagerImpl.java | 45 ++++++ .../java/com/cloud/vm/UserVmManagerImpl.java | 31 ++++ .../answer/MigrationProgressAnswer.java | 101 +++++++++++++ .../command/MigrationProgressCommand.java | 22 +++ 9 files changed, 457 insertions(+) create mode 100644 cosmic-agent/src/main/java/com/cloud/agent/resource/kvm/wrapper/LibvirtGetDomJobInfoWrapper.java create mode 100644 cosmic-core/api/src/main/java/com/cloud/api/command/user/vm/GetVMProgressCmd.java create mode 100644 cosmic-core/api/src/main/java/com/cloud/api/response/VmProgressResponse.java create mode 100644 cosmic-model/src/main/java/com/cloud/legacymodel/communication/answer/MigrationProgressAnswer.java create mode 100644 cosmic-model/src/main/java/com/cloud/legacymodel/communication/command/MigrationProgressCommand.java diff --git a/cosmic-agent/src/main/java/com/cloud/agent/resource/kvm/wrapper/LibvirtGetDomJobInfoWrapper.java b/cosmic-agent/src/main/java/com/cloud/agent/resource/kvm/wrapper/LibvirtGetDomJobInfoWrapper.java new file mode 100644 index 0000000000..87f3394194 --- /dev/null +++ b/cosmic-agent/src/main/java/com/cloud/agent/resource/kvm/wrapper/LibvirtGetDomJobInfoWrapper.java @@ -0,0 +1,46 @@ +package com.cloud.agent.resource.kvm.wrapper; + +import com.cloud.agent.resource.kvm.LibvirtComputingResource; +import com.cloud.common.request.ResourceWrapper; +import com.cloud.legacymodel.communication.answer.Answer; +import com.cloud.legacymodel.communication.answer.MigrationProgressAnswer; +import com.cloud.legacymodel.communication.command.MigrationProgressCommand; + +import org.libvirt.Connect; +import org.libvirt.Domain; +import org.libvirt.DomainJobInfo; +import org.libvirt.LibvirtException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@ResourceWrapper(handles = MigrationProgressCommand.class) +public final class LibvirtGetDomJobInfoWrapper extends LibvirtCommandWrapper { + + private static final Logger s_logger = LoggerFactory.getLogger(LibvirtGetDomJobInfoWrapper.class); + + @Override + public Answer execute(final MigrationProgressCommand command, final LibvirtComputingResource libvirtComputingResource) { + final String vmName = command.getVmName(); + final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper(); + final Connect conn; + DomainJobInfo domainJobInfo; + Domain vm; + + try { + conn = libvirtUtilitiesHelper.getConnectionByVmName(vmName); + vm = libvirtComputingResource.getDomain(conn, vmName); + domainJobInfo = vm.getJobInfo(); + } catch (LibvirtException e) { + final String msg = " Getting domain job info failed due to " + e.toString(); + s_logger.warn(msg, e); + return new MigrationProgressAnswer(command, false, msg); + } + + return new MigrationProgressAnswer(command, true, null, + domainJobInfo.getTimeElapsed(), domainJobInfo.getTimeRemaining(), + domainJobInfo.getDataTotal(), domainJobInfo.getDataProcessed(), domainJobInfo.getDataRemaining(), + domainJobInfo.getMemTotal(), domainJobInfo.getMemProcessed(), domainJobInfo.getMemRemaining(), + domainJobInfo.getFileTotal(), domainJobInfo.getFileProcessed(), domainJobInfo.getFileRemaining() + ); + } +} diff --git a/cosmic-core/api/src/main/java/com/cloud/api/command/user/vm/GetVMProgressCmd.java b/cosmic-core/api/src/main/java/com/cloud/api/command/user/vm/GetVMProgressCmd.java new file mode 100644 index 0000000000..61d9918326 --- /dev/null +++ b/cosmic-core/api/src/main/java/com/cloud/api/command/user/vm/GetVMProgressCmd.java @@ -0,0 +1,60 @@ +package com.cloud.api.command.user.vm; + +import com.cloud.api.APICommand; +import com.cloud.api.APICommandGroup; +import com.cloud.api.ApiConstants; +import com.cloud.api.BaseCmd; +import com.cloud.api.Parameter; +import com.cloud.api.response.VmProgressResponse; +import com.cloud.legacymodel.exceptions.CloudRuntimeException; +import com.cloud.legacymodel.exceptions.InvalidParameterValueException; +import com.cloud.legacymodel.exceptions.ResourceUnavailableException; +import com.cloud.legacymodel.user.Account; +import com.cloud.uservm.UserVm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@APICommand(name = "getvmprogress", group = APICommandGroup.VirtualMachineService, description = "Get migration progress of VM", responseObject = VmProgressResponse.class) +public class GetVMProgressCmd extends BaseCmd { + public static final Logger s_logger = LoggerFactory.getLogger(GetVMProgressCmd.class.getName()); + + private static final String COMMAND_NAME = "getvmprogressresponse"; + @Parameter(name = ApiConstants.UUID, type = BaseCmd.CommandType.STRING, required = true, description = "The UUID of the VM.") + private String uuid; + + @Override + public void execute() { + + try { + final VmProgressResponse response = _userVmService.getVmProgress(this); + response.setResponseName(getCommandName()); + setResponseObject(response); + } catch (InvalidParameterValueException e) { + s_logger.error("Invalid parameter: " + e.getMessage()); + } catch (CloudRuntimeException e) { + s_logger.error("CloudRuntimeException: " + e.getMessage()); + } catch (Exception e) { + s_logger.error("Unexpected exception: " + e.getMessage()); + } + } + + @Override + public String getCommandName() { + return COMMAND_NAME; + } + + @Override + public long getEntityOwnerId() { + final UserVm userVm = _entityMgr.findByUuid(UserVm.class, getUuid()); + if (userVm != null) { + return userVm.getAccountId(); + } + + return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked + } + + public String getUuid() { + return uuid; + } +} diff --git a/cosmic-core/api/src/main/java/com/cloud/api/response/VmProgressResponse.java b/cosmic-core/api/src/main/java/com/cloud/api/response/VmProgressResponse.java new file mode 100644 index 0000000000..994af9f390 --- /dev/null +++ b/cosmic-core/api/src/main/java/com/cloud/api/response/VmProgressResponse.java @@ -0,0 +1,142 @@ +package com.cloud.api.response; + +import com.cloud.api.ApiConstants; +import com.cloud.api.BaseResponse; +import com.cloud.serializer.Param; + +import com.google.gson.annotations.SerializedName; + +public class VmProgressResponse extends BaseResponse { + + @SerializedName("timeelapsed") + @Param(description = "Time elapsed") + long timeElapsed; + + @SerializedName("timeremaining") + @Param(description = "Time remaining") + long timeRemaining; + + @SerializedName("datatotal") + @Param(description = "Data total") + long dataTotal; + + @SerializedName("dataprocessed") + @Param(description = "Data processed") + long dataProcessed; + + @SerializedName("dataremaining") + @Param(description = "Data remaining") + long dataRemaining; + + @SerializedName("memorytotal") + @Param(description = "Memory total") + long memTotal; + + @SerializedName("memoryprocessed") + @Param(description = "Memory processed") + long memProcessed; + + @SerializedName("memoryremaining") + @Param(description = "Memory remaining") + long memRemaining; + + @SerializedName("filetotal") + @Param(description = "File total") + long fileTotal; + + @SerializedName("fileprocessed") + @Param(description = "File processed") + long fileProcessed; + + @SerializedName("fileremaining") + @Param(description = "File remaining") + long fileRemaining; + + public long getTimeElapsed() { + return timeElapsed; + } + + public void setTimeElapsed(final long timeElapsed) { + this.timeElapsed = timeElapsed; + } + + public long getTimeRemaining() { + return timeRemaining; + } + + public void setTimeRemaining(final long timeRemaining) { + this.timeRemaining = timeRemaining; + } + + public long getDataTotal() { + return dataTotal; + } + + public void setDataTotal(final long dataTotal) { + this.dataTotal = dataTotal; + } + + public long getDataProcessed() { + return dataProcessed; + } + + public void setDataProcessed(final long dataProcessed) { + this.dataProcessed = dataProcessed; + } + + public long getDataRemaining() { + return dataRemaining; + } + + public void setDataRemaining(final long dataRemaining) { + this.dataRemaining = dataRemaining; + } + + public long getMemTotal() { + return memTotal; + } + + public void setMemTotal(final long memTotal) { + this.memTotal = memTotal; + } + + public long getMemProcessed() { + return memProcessed; + } + + public void setMemProcessed(final long memProcessed) { + this.memProcessed = memProcessed; + } + + public long getMemRemaining() { + return memRemaining; + } + + public void setMemRemaining(final long memRemaining) { + this.memRemaining = memRemaining; + } + + public long getFileTotal() { + return fileTotal; + } + + public void setFileTotal(final long fileTotal) { + this.fileTotal = fileTotal; + } + + public long getFileProcessed() { + return fileProcessed; + } + + public void setFileProcessed(final long fileProcessed) { + this.fileProcessed = fileProcessed; + } + + public long getFileRemaining() { + return fileRemaining; + } + + public void setFileRemaining(final long fileRemaining) { + this.fileRemaining = fileRemaining; + } +} diff --git a/cosmic-core/api/src/main/java/com/cloud/vm/UserVmService.java b/cosmic-core/api/src/main/java/com/cloud/vm/UserVmService.java index d9c1595b18..a6b72fa5dd 100644 --- a/cosmic-core/api/src/main/java/com/cloud/vm/UserVmService.java +++ b/cosmic-core/api/src/main/java/com/cloud/vm/UserVmService.java @@ -6,6 +6,7 @@ import com.cloud.api.command.user.vm.AddNicToVMCmd; import com.cloud.api.command.user.vm.DeployVMCmd; import com.cloud.api.command.user.vm.DestroyVMCmd; +import com.cloud.api.command.user.vm.GetVMProgressCmd; import com.cloud.api.command.user.vm.RebootVMCmd; import com.cloud.api.command.user.vm.RemoveNicFromVMCmd; import com.cloud.api.command.user.vm.ResetVMPasswordCmd; @@ -19,11 +20,15 @@ import com.cloud.api.command.user.vm.UpgradeVMCmd; import com.cloud.api.command.user.vmgroup.CreateVMGroupCmd; import com.cloud.api.command.user.vmgroup.DeleteVMGroupCmd; +import com.cloud.api.response.VmProgressResponse; import com.cloud.db.model.Zone; +import com.cloud.legacymodel.communication.command.MigrationProgressCommand; import com.cloud.legacymodel.dc.Host; +import com.cloud.legacymodel.exceptions.CloudRuntimeException; import com.cloud.legacymodel.exceptions.ConcurrentOperationException; import com.cloud.legacymodel.exceptions.ExecutionException; import com.cloud.legacymodel.exceptions.InsufficientCapacityException; +import com.cloud.legacymodel.exceptions.InvalidParameterValueException; import com.cloud.legacymodel.exceptions.ManagementServerException; import com.cloud.legacymodel.exceptions.ResourceAllocationException; import com.cloud.legacymodel.exceptions.ResourceUnavailableException; @@ -235,6 +240,7 @@ VirtualMachine migrateVirtualMachineWithVolume(Long vmId, Host destinationHost, UserVm expungeVm(long vmId) throws ResourceUnavailableException, ConcurrentOperationException; + VmProgressResponse getVmProgress(GetVMProgressCmd cmd) throws CloudRuntimeException, InvalidParameterValueException; /** * Finds and returns an encrypted password for a VM. * diff --git a/cosmic-core/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java b/cosmic-core/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java index 9885904760..9c85083d76 100644 --- a/cosmic-core/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java +++ b/cosmic-core/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java @@ -4,7 +4,9 @@ import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner; import com.cloud.framework.config.ConfigKey; +import com.cloud.legacymodel.communication.answer.MigrationProgressAnswer; import com.cloud.legacymodel.exceptions.AgentUnavailableException; +import com.cloud.legacymodel.exceptions.CloudRuntimeException; import com.cloud.legacymodel.exceptions.ConcurrentOperationException; import com.cloud.legacymodel.exceptions.InsufficientCapacityException; import com.cloud.legacymodel.exceptions.InsufficientServerCapacityException; @@ -190,6 +192,8 @@ void findHostAndMigrate(String vmUuid, Long newSvcOfferingId, DeploymentPlanner. boolean getExecuteInSequence(HypervisorType hypervisorType); + MigrationProgressAnswer getMigrationProgress(String vmUuid) throws CloudRuntimeException; + public interface Topics { public static final String VM_POWER_STATE = "vm.powerstate"; } diff --git a/cosmic-core/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/cosmic-core/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 0e1a53505c..32ec2d9d8d 100644 --- a/cosmic-core/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/cosmic-core/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -58,6 +58,7 @@ import com.cloud.legacymodel.communication.answer.Answer; import com.cloud.legacymodel.communication.answer.CheckVirtualMachineAnswer; import com.cloud.legacymodel.communication.answer.ClusterVMMetaDataSyncAnswer; +import com.cloud.legacymodel.communication.answer.MigrationProgressAnswer; import com.cloud.legacymodel.communication.answer.PlugNicAnswer; import com.cloud.legacymodel.communication.answer.RebootAnswer; import com.cloud.legacymodel.communication.answer.RestoreVMSnapshotAnswer; @@ -69,6 +70,7 @@ import com.cloud.legacymodel.communication.command.ClusterVMMetaDataSyncCommand; import com.cloud.legacymodel.communication.command.Command; import com.cloud.legacymodel.communication.command.MigrateCommand; +import com.cloud.legacymodel.communication.command.MigrationProgressCommand; import com.cloud.legacymodel.communication.command.PingRoutingCommand; import com.cloud.legacymodel.communication.command.PlugNicCommand; import com.cloud.legacymodel.communication.command.PrepareForMigrationCommand; @@ -195,6 +197,7 @@ import java.util.Map; import java.util.TimeZone; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -235,6 +238,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac "Interval to send application level pings to make sure the connection is still working", false); static final ConfigKey DefaultDiskControllerName = new ConfigKey<>("Advanced", String.class, "vm.default.disk.controller", "SCSI", "Default disk controller type for routers, systemVMs and ", false); + static final ConfigKey VmOpProgressInterval = new ConfigKey<>("Advanced", Long.class, "vm.op.progress.interval", "1000", + "Time (in milliseconds) to wait before checking migration progress", false); private static final Logger s_logger = LoggerFactory.getLogger(VirtualMachineManagerImpl.class); private static final String VM_SYNC_ALERT_SUBJECT = "VM state sync alert"; @Inject @@ -344,6 +349,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac VmWorkJobHandlerProxy _jobHandlerProxy = new VmWorkJobHandlerProxy(this); Map _vmGurus = new HashMap<>(); + ConcurrentHashMap migrationProgressQueue = new ConcurrentHashMap<>(); + ConcurrentHashMap migrationProgressAnswerMap = new ConcurrentHashMap<>(); ScheduledExecutorService _executor = null; protected VirtualMachineManagerImpl() { @@ -390,6 +397,7 @@ public boolean start() { // TODO, initial delay is hardcoded _executor.scheduleAtFixedRate(new CleanupTask(), 5, VmJobStateReportInterval.value(), TimeUnit.SECONDS); _executor.scheduleAtFixedRate(new TransitionTask(), VmOpCleanupInterval.value(), VmOpCleanupInterval.value(), TimeUnit.SECONDS); + _executor.scheduleAtFixedRate(new MonitorMigrationTask(), VmOpProgressInterval.value(), VmOpProgressInterval.value(), TimeUnit.MILLISECONDS); cancelWorkItems(_nodeId); volumeMgr.cleanupStorageJobs(); @@ -724,9 +732,13 @@ private void orchestrateMigrateWithStorage(final String vmUuid, final long srcHo } } + migrationProgressQueue.put(vm.getInstanceName(), srcHost.getId()); + // Migrate the vm and its volume. volumeMgr.migrateVolumes(vm, to, srcHost, destHost, volumeToPoolMap); + migrationProgressQueue.remove(vm.getInstanceName()); + // Put the vm back to running state. moveVmOutofMigratingStateOnSuccess(vm, destHost.getId(), work); @@ -2667,6 +2679,13 @@ public boolean getExecuteInSequence(final HypervisorType hypervisorType) { } } + public MigrationProgressAnswer getMigrationProgress(String vmUuid) throws CloudRuntimeException { + if (migrationProgressAnswerMap.containsKey(vmUuid)) { + return migrationProgressAnswerMap.get(vmUuid); + } + throw new CloudRuntimeException("Unable get job for vm " + vmUuid); + } + private void orchestrateReboot(final String vmUuid, final Map params) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { final VMInstanceVO vm = _vmDao.findByUuid(vmUuid); @@ -4672,4 +4691,30 @@ public boolean jobIsForSameNetwork(final VmWorkJobVO workJob, final Network netw } } } + + protected class MonitorMigrationTask extends ManagedContextRunnable { + public MonitorMigrationTask() { + s_logger.info("Starting Monitor Migration task"); + } + + @Override + protected void runInContext() { + try { + if (!migrationProgressQueue.isEmpty()) { + for (Map.Entry entry: migrationProgressQueue.entrySet()) { + final MigrationProgressCommand migrationProgressCommand = new MigrationProgressCommand(entry.getKey()); + Answer answer = _agentMgr.send(entry.getValue(), migrationProgressCommand); + migrationProgressAnswerMap.put(entry.getKey(), (MigrationProgressAnswer) answer); + } + } + TimeUnit.MILLISECONDS.sleep(VmOpProgressInterval.value()); + } catch (AgentUnavailableException e) { + s_logger.error("Agent unavailable: " + e.getMessage()); + } catch (OperationTimedoutException e) { + s_logger.error("Operation timeout: " + e.getMessage()); + } catch (Exception e) { + s_logger.error("Unexpected exception: " + e.getMessage()); + } + } + } } diff --git a/cosmic-core/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/cosmic-core/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 1acab8f8ed..01b500c963 100644 --- a/cosmic-core/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/cosmic-core/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -16,6 +16,7 @@ import com.cloud.api.command.user.vm.AddNicToVMCmd; import com.cloud.api.command.user.vm.DeployVMCmd; import com.cloud.api.command.user.vm.DestroyVMCmd; +import com.cloud.api.command.user.vm.GetVMProgressCmd; import com.cloud.api.command.user.vm.RebootVMCmd; import com.cloud.api.command.user.vm.RemoveNicFromVMCmd; import com.cloud.api.command.user.vm.ResetVMPasswordCmd; @@ -29,6 +30,7 @@ import com.cloud.api.command.user.vm.UpgradeVMCmd; import com.cloud.api.command.user.vmgroup.CreateVMGroupCmd; import com.cloud.api.command.user.vmgroup.DeleteVMGroupCmd; +import com.cloud.api.response.VmProgressResponse; import com.cloud.capacity.Capacity; import com.cloud.capacity.CapacityManager; import com.cloud.common.managed.context.ManagedContextRunnable; @@ -79,6 +81,7 @@ import com.cloud.legacymodel.communication.answer.Answer; import com.cloud.legacymodel.communication.answer.GetVmDiskStatsAnswer; import com.cloud.legacymodel.communication.answer.GetVmStatsAnswer; +import com.cloud.legacymodel.communication.answer.MigrationProgressAnswer; import com.cloud.legacymodel.communication.answer.RestoreVMSnapshotAnswer; import com.cloud.legacymodel.communication.answer.StartAnswer; import com.cloud.legacymodel.communication.command.Command; @@ -86,6 +89,7 @@ import com.cloud.legacymodel.communication.command.GetVmDiskStatsCommand; import com.cloud.legacymodel.communication.command.GetVmIpAddressCommand; import com.cloud.legacymodel.communication.command.GetVmStatsCommand; +import com.cloud.legacymodel.communication.command.MigrationProgressCommand; import com.cloud.legacymodel.communication.command.PvlanSetupCommand; import com.cloud.legacymodel.communication.command.RestoreVMSnapshotCommand; import com.cloud.legacymodel.configuration.Resource.ResourceType; @@ -3559,6 +3563,33 @@ public UserVm expungeVm(final long vmId) throws ResourceUnavailableException, Co } } + @Override + public VmProgressResponse getVmProgress(final GetVMProgressCmd cmd) throws CloudRuntimeException, InvalidParameterValueException { + String uuid = cmd.getUuid(); + final UserVmVO vm = _vmDao.findByUuid(uuid); + if (vm == null) { + throw new InvalidParameterValueException("Unable to find virtual machine with uuid: " + uuid); + } + //check permissions + _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, vm); + + MigrationProgressAnswer migrationProgressAnswer = _itMgr.getMigrationProgress(uuid); + + VmProgressResponse vmProgressResponse = new VmProgressResponse(); + vmProgressResponse.setTimeElapsed(migrationProgressAnswer.getTimeElapsed()); + vmProgressResponse.setTimeRemaining(migrationProgressAnswer.getTimeRemaining()); + vmProgressResponse.setDataTotal(migrationProgressAnswer.getDataTotal()); + vmProgressResponse.setDataProcessed(migrationProgressAnswer.getDataProcessed()); + vmProgressResponse.setDataRemaining(migrationProgressAnswer.getDataRemaining()); + vmProgressResponse.setMemTotal(migrationProgressAnswer.getMemTotal()); + vmProgressResponse.setMemProcessed(migrationProgressAnswer.getMemProcessed()); + vmProgressResponse.setMemRemaining(migrationProgressAnswer.getMemRemaining()); + vmProgressResponse.setFileTotal(migrationProgressAnswer.getFileTotal()); + vmProgressResponse.setFileProcessed(migrationProgressAnswer.getFileProcessed()); + vmProgressResponse.setFileRemaining(migrationProgressAnswer.getFileRemaining()); + return vmProgressResponse; + } + @Override public String getVmUserData(final long vmId) { final UserVmVO vm = _vmDao.findById(vmId); diff --git a/cosmic-model/src/main/java/com/cloud/legacymodel/communication/answer/MigrationProgressAnswer.java b/cosmic-model/src/main/java/com/cloud/legacymodel/communication/answer/MigrationProgressAnswer.java new file mode 100644 index 0000000000..01039960a3 --- /dev/null +++ b/cosmic-model/src/main/java/com/cloud/legacymodel/communication/answer/MigrationProgressAnswer.java @@ -0,0 +1,101 @@ +package com.cloud.legacymodel.communication.answer; + +import com.cloud.legacymodel.communication.command.MigrationProgressCommand; + +public class MigrationProgressAnswer extends Answer { + long timeElapsed; + long timeRemaining; + long dataTotal; + long dataProcessed; + long dataRemaining; + long memTotal; + long memProcessed; + long memRemaining; + long fileTotal; + long fileProcessed; + long fileRemaining; + + public MigrationProgressAnswer(final MigrationProgressCommand cmd, final boolean success, final String details) { + super(cmd, success, details); + } + + public MigrationProgressAnswer(final MigrationProgressCommand cmd, final boolean success, final String details, + final long timeElapsed, final long timeRemaining, + final long dataTotal, final long dataProcessed, final long dataRemaining, + final long memTotal, final long memProcessed, final long memRemaining, + final long fileTotal, final long fileProcessed, final long fileRemaining) { + super(cmd, success, details); + + this.timeElapsed = timeElapsed; + this.timeRemaining = timeRemaining; + this.dataTotal = dataTotal; + this.dataProcessed = dataProcessed; + this.dataRemaining = dataRemaining; + this.memTotal = memTotal; + this.memProcessed = memProcessed; + this.memRemaining = memRemaining; + this.fileTotal = fileTotal; + this.fileProcessed = fileProcessed; + this.fileRemaining = fileRemaining; + } + + public long getTimeElapsed() { + return timeElapsed; + } + + public long getTimeRemaining() { + return timeRemaining; + } + + public long getDataTotal() { + return dataTotal; + } + + public long getDataProcessed() { + return dataProcessed; + } + + public long getDataRemaining() { + return dataRemaining; + } + + public long getMemTotal() { + return memTotal; + } + + public long getMemProcessed() { + return memProcessed; + } + + public long getMemRemaining() { + return memRemaining; + } + + public long getFileTotal() { + return fileTotal; + } + + public long getFileProcessed() { + return fileProcessed; + } + + public long getFileRemaining() { + return fileRemaining; + } + + public String String() { + return "MigrationProgressAnswer{" + + "timeElapsed=" + timeElapsed + + ", timeRemaining=" + timeRemaining + + ", dataTotal=" + dataTotal + + ", dataProcessed=" + dataProcessed + + ", dataRemaining=" + dataRemaining + + ", memTotal=" + memTotal + + ", memProcessed=" + memProcessed + + ", memRemaining=" + memRemaining + + ", fileTotal=" + fileTotal + + ", fileProcessed=" + fileProcessed + + ", fileRemaining=" + fileRemaining + + '}'; + } +} diff --git a/cosmic-model/src/main/java/com/cloud/legacymodel/communication/command/MigrationProgressCommand.java b/cosmic-model/src/main/java/com/cloud/legacymodel/communication/command/MigrationProgressCommand.java new file mode 100644 index 0000000000..45068c6543 --- /dev/null +++ b/cosmic-model/src/main/java/com/cloud/legacymodel/communication/command/MigrationProgressCommand.java @@ -0,0 +1,22 @@ +package com.cloud.legacymodel.communication.command; + +public class MigrationProgressCommand extends Command { + String vmName; + + protected MigrationProgressCommand() { + super(); + } + + public MigrationProgressCommand(final String vmName) { + this.vmName = vmName; + } + + public String getVmName() { + return vmName; + } + + @Override + public boolean executeInSequence() { + return false; + } +} From 7a82aba4c8bc18f045e83aa1c3d635183be9d2bf Mon Sep 17 00:00:00 2001 From: Alexander Verhaar Date: Wed, 23 Jun 2021 22:18:22 +0200 Subject: [PATCH 02/14] Fix api name --- .../java/com/cloud/api/command/user/vm/GetVMProgressCmd.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cosmic-core/api/src/main/java/com/cloud/api/command/user/vm/GetVMProgressCmd.java b/cosmic-core/api/src/main/java/com/cloud/api/command/user/vm/GetVMProgressCmd.java index 61d9918326..e3d81a46a5 100644 --- a/cosmic-core/api/src/main/java/com/cloud/api/command/user/vm/GetVMProgressCmd.java +++ b/cosmic-core/api/src/main/java/com/cloud/api/command/user/vm/GetVMProgressCmd.java @@ -15,7 +15,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@APICommand(name = "getvmprogress", group = APICommandGroup.VirtualMachineService, description = "Get migration progress of VM", responseObject = VmProgressResponse.class) +@APICommand(name = "getVmProgress", group = APICommandGroup.VirtualMachineService, description = "Get migration progress of VM", responseObject = VmProgressResponse.class) public class GetVMProgressCmd extends BaseCmd { public static final Logger s_logger = LoggerFactory.getLogger(GetVMProgressCmd.class.getName()); From 0975626b11c815e275b599dd1c9e61680f837388 Mon Sep 17 00:00:00 2001 From: Alexander Verhaar Date: Wed, 23 Jun 2021 22:24:13 +0200 Subject: [PATCH 03/14] Add class to api cmdList --- .../src/main/java/com/cloud/server/ManagementServerImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cosmic-core/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/cosmic-core/server/src/main/java/com/cloud/server/ManagementServerImpl.java index 1242d44b61..1ef3cf3c9f 100644 --- a/cosmic-core/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/cosmic-core/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -337,6 +337,7 @@ import com.cloud.api.command.user.vm.DeployVMCmd; import com.cloud.api.command.user.vm.DestroyVMCmd; import com.cloud.api.command.user.vm.GetVMPasswordCmd; +import com.cloud.api.command.user.vm.GetVMProgressCmd; import com.cloud.api.command.user.vm.ListNicsCmd; import com.cloud.api.command.user.vm.ListVMsCmd; import com.cloud.api.command.user.vm.RebootVMCmd; @@ -3699,6 +3700,7 @@ public List> getCommands() { cmdList.add(ListHAWorkersCmd.class); cmdList.add(ListWhoHasThisIpCmd.class); cmdList.add(ListWhoHasThisMacCmd.class); + cmdList.add(GetVMProgressCmd.class); // separated admin commands cmdList.add(ListAccountsCmdByAdmin.class); cmdList.add(ListZonesCmdByAdmin.class); From ca903fc0db947d92f8a1895e19009a39ce2b1402 Mon Sep 17 00:00:00 2001 From: Alexander Verhaar Date: Thu, 24 Jun 2021 10:53:32 +0200 Subject: [PATCH 04/14] Return empty response if no job is running --- .../java/com/cloud/vm/UserVmManagerImpl.java | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/cosmic-core/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/cosmic-core/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 01b500c963..6cfe52e03e 100644 --- a/cosmic-core/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/cosmic-core/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -3573,21 +3573,26 @@ public VmProgressResponse getVmProgress(final GetVMProgressCmd cmd) throws Cloud //check permissions _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, vm); - MigrationProgressAnswer migrationProgressAnswer = _itMgr.getMigrationProgress(uuid); - - VmProgressResponse vmProgressResponse = new VmProgressResponse(); - vmProgressResponse.setTimeElapsed(migrationProgressAnswer.getTimeElapsed()); - vmProgressResponse.setTimeRemaining(migrationProgressAnswer.getTimeRemaining()); - vmProgressResponse.setDataTotal(migrationProgressAnswer.getDataTotal()); - vmProgressResponse.setDataProcessed(migrationProgressAnswer.getDataProcessed()); - vmProgressResponse.setDataRemaining(migrationProgressAnswer.getDataRemaining()); - vmProgressResponse.setMemTotal(migrationProgressAnswer.getMemTotal()); - vmProgressResponse.setMemProcessed(migrationProgressAnswer.getMemProcessed()); - vmProgressResponse.setMemRemaining(migrationProgressAnswer.getMemRemaining()); - vmProgressResponse.setFileTotal(migrationProgressAnswer.getFileTotal()); - vmProgressResponse.setFileProcessed(migrationProgressAnswer.getFileProcessed()); - vmProgressResponse.setFileRemaining(migrationProgressAnswer.getFileRemaining()); - return vmProgressResponse; + try { + MigrationProgressAnswer migrationProgressAnswer = _itMgr.getMigrationProgress(uuid); + + VmProgressResponse vmProgressResponse = new VmProgressResponse(); + vmProgressResponse.setTimeElapsed(migrationProgressAnswer.getTimeElapsed()); + vmProgressResponse.setTimeRemaining(migrationProgressAnswer.getTimeRemaining()); + vmProgressResponse.setDataTotal(migrationProgressAnswer.getDataTotal()); + vmProgressResponse.setDataProcessed(migrationProgressAnswer.getDataProcessed()); + vmProgressResponse.setDataRemaining(migrationProgressAnswer.getDataRemaining()); + vmProgressResponse.setMemTotal(migrationProgressAnswer.getMemTotal()); + vmProgressResponse.setMemProcessed(migrationProgressAnswer.getMemProcessed()); + vmProgressResponse.setMemRemaining(migrationProgressAnswer.getMemRemaining()); + vmProgressResponse.setFileTotal(migrationProgressAnswer.getFileTotal()); + vmProgressResponse.setFileProcessed(migrationProgressAnswer.getFileProcessed()); + vmProgressResponse.setFileRemaining(migrationProgressAnswer.getFileRemaining()); + return vmProgressResponse; + } catch (CloudRuntimeException e) { + // Virtual Machine exists but no job is running, return empty response + return new VmProgressResponse(); + } } @Override From 00f753f27f55027f16c82fe2bd1a35cacee7f8fd Mon Sep 17 00:00:00 2001 From: Alexander Verhaar Date: Thu, 24 Jun 2021 11:02:09 +0200 Subject: [PATCH 05/14] Add API call to commands.properties --- cosmic-client/src/main/resources/commands.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/cosmic-client/src/main/resources/commands.properties b/cosmic-client/src/main/resources/commands.properties index 2777f89f16..a3050042b5 100644 --- a/cosmic-client/src/main/resources/commands.properties +++ b/cosmic-client/src/main/resources/commands.properties @@ -54,6 +54,7 @@ migrateVirtualMachineWithVolume=1 recoverVirtualMachine=15 expungeVirtualMachine=15 getVirtualMachineUserData=15 +getVmProgress=15 #### snapshot commands createSnapshot=15 listSnapshots=31 From 8015e8bd5b5dac86914b7d4333e2ae9f59e3bfed Mon Sep 17 00:00:00 2001 From: Alexander Verhaar Date: Thu, 24 Jun 2021 11:06:16 +0200 Subject: [PATCH 06/14] Update apidoc --- .../apidoc/XmlToHtmlConverterData.java | 29 +++++++++++++++++++ .../apidoc/generatetocforadmin_include.xsl | 0 .../generatetocfordomainadmin_include.xsl | 0 .../apidoc/generatetocforuser_include.xsl | 0 4 files changed, 29 insertions(+) create mode 100644 cosmic-core/apidoc/XmlToHtmlConverterData.java create mode 100644 cosmic-core/apidoc/generatetocforadmin_include.xsl create mode 100644 cosmic-core/apidoc/generatetocfordomainadmin_include.xsl create mode 100644 cosmic-core/apidoc/generatetocforuser_include.xsl diff --git a/cosmic-core/apidoc/XmlToHtmlConverterData.java b/cosmic-core/apidoc/XmlToHtmlConverterData.java new file mode 100644 index 0000000000..63225c7182 --- /dev/null +++ b/cosmic-core/apidoc/XmlToHtmlConverterData.java @@ -0,0 +1,29 @@ +/* Generated using gen_toc.py. Do not edit. */ + +import java.util.HashSet; +import java.util.Set; + +public class XmlToHtmlConverterData { + + Set rootAdminCommandNames = new HashSet(); + Set domainAdminCommandNames = new HashSet(); + Set userCommandNames = new HashSet(); + + + public void populateForUser() { + + } + + + public void populateForRootAdmin() { + + } + + + public void populateForDomainAdmin() { + + } + + +} + diff --git a/cosmic-core/apidoc/generatetocforadmin_include.xsl b/cosmic-core/apidoc/generatetocforadmin_include.xsl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cosmic-core/apidoc/generatetocfordomainadmin_include.xsl b/cosmic-core/apidoc/generatetocfordomainadmin_include.xsl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cosmic-core/apidoc/generatetocforuser_include.xsl b/cosmic-core/apidoc/generatetocforuser_include.xsl new file mode 100644 index 0000000000..e69de29bb2 From a279fdb2a38fdf602a329738a8a1aedf6352af13 Mon Sep 17 00:00:00 2001 From: Alexander Verhaar Date: Thu, 24 Jun 2021 11:09:32 +0200 Subject: [PATCH 07/14] Add API call to gen_toc.py --- cosmic-core/apidoc/gen_toc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cosmic-core/apidoc/gen_toc.py b/cosmic-core/apidoc/gen_toc.py index adf2ebebe8..7322579434 100755 --- a/cosmic-core/apidoc/gen_toc.py +++ b/cosmic-core/apidoc/gen_toc.py @@ -136,7 +136,8 @@ 'CacheStore': 'Cache Store', 'listHAWorkers': 'CloudOps', 'listWhoHasThisIp': 'CloudOps', - 'listWhoHasThisMac': 'CloudOps' + 'listWhoHasThisMac': 'CloudOps', + 'getVmProgress': 'Virtual Machine' } categories = { } From d009905646bfa73704d8af107615984957c10d45 Mon Sep 17 00:00:00 2001 From: Alexander Verhaar Date: Thu, 24 Jun 2021 11:20:37 +0200 Subject: [PATCH 08/14] Set response name --- .../java/com/cloud/api/command/user/vm/GetVMProgressCmd.java | 1 + 1 file changed, 1 insertion(+) diff --git a/cosmic-core/api/src/main/java/com/cloud/api/command/user/vm/GetVMProgressCmd.java b/cosmic-core/api/src/main/java/com/cloud/api/command/user/vm/GetVMProgressCmd.java index e3d81a46a5..75c98bae07 100644 --- a/cosmic-core/api/src/main/java/com/cloud/api/command/user/vm/GetVMProgressCmd.java +++ b/cosmic-core/api/src/main/java/com/cloud/api/command/user/vm/GetVMProgressCmd.java @@ -29,6 +29,7 @@ public void execute() { try { final VmProgressResponse response = _userVmService.getVmProgress(this); response.setResponseName(getCommandName()); + response.setObjectName(getCommandName()); setResponseObject(response); } catch (InvalidParameterValueException e) { s_logger.error("Invalid parameter: " + e.getMessage()); From 07cf5ceadec2d9ac20e9880df17ec2befb2405b4 Mon Sep 17 00:00:00 2001 From: Alexander Verhaar Date: Thu, 24 Jun 2021 11:35:15 +0200 Subject: [PATCH 09/14] Throw exceptions in API --- .../java/com/cloud/api/command/user/vm/GetVMProgressCmd.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cosmic-core/api/src/main/java/com/cloud/api/command/user/vm/GetVMProgressCmd.java b/cosmic-core/api/src/main/java/com/cloud/api/command/user/vm/GetVMProgressCmd.java index 75c98bae07..f911bf2338 100644 --- a/cosmic-core/api/src/main/java/com/cloud/api/command/user/vm/GetVMProgressCmd.java +++ b/cosmic-core/api/src/main/java/com/cloud/api/command/user/vm/GetVMProgressCmd.java @@ -3,8 +3,10 @@ import com.cloud.api.APICommand; import com.cloud.api.APICommandGroup; import com.cloud.api.ApiConstants; +import com.cloud.api.ApiErrorCode; import com.cloud.api.BaseCmd; import com.cloud.api.Parameter; +import com.cloud.api.ServerApiException; import com.cloud.api.response.VmProgressResponse; import com.cloud.legacymodel.exceptions.CloudRuntimeException; import com.cloud.legacymodel.exceptions.InvalidParameterValueException; @@ -33,10 +35,13 @@ public void execute() { setResponseObject(response); } catch (InvalidParameterValueException e) { s_logger.error("Invalid parameter: " + e.getMessage()); + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid parameter"); } catch (CloudRuntimeException e) { s_logger.error("CloudRuntimeException: " + e.getMessage()); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to get progress"); } catch (Exception e) { s_logger.error("Unexpected exception: " + e.getMessage()); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Unexpected exception"); } } From bb761f24d439ed22743613c5c17be9dd4f63e866 Mon Sep 17 00:00:00 2001 From: Alexander Verhaar Date: Thu, 29 Jul 2021 13:10:52 +0200 Subject: [PATCH 10/14] Added progressbar in UI --- .../src/main/webapp/css/cloudstack3.css | 50 +++++++++++++++++++ .../src/main/webapp/scripts/instances.js | 8 +-- .../webapp/scripts/ui/widgets/detailView.js | 34 +++++++++++++ cosmic-core/apidoc/gen_toc.py | 2 +- 4 files changed, 90 insertions(+), 4 deletions(-) diff --git a/cosmic-client/src/main/webapp/css/cloudstack3.css b/cosmic-client/src/main/webapp/css/cloudstack3.css index cd1c6420e7..e7edaedc97 100644 --- a/cosmic-client/src/main/webapp/css/cloudstack3.css +++ b/cosmic-client/src/main/webapp/css/cloudstack3.css @@ -12429,3 +12429,53 @@ div.gpugroups div.list-view { background: transparent url("../images/icons.png") no-repeat -626px -209px; padding: 0 0 3px 18px; } + +.ui-progressbar { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + border: none; + border-radius: 5px; + width: 25%; + height: 15px; + z-index: 0; + position: relative; + background-color: #eee; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25) inset; + display: inline-table; +} + +.ui-progressbar-value { + position: absolute; + width: 0; + height: inherit; + background-image: -webkit-linear-gradient(-45deg, transparent 33%, rgba(0, 0, 0, .1) 33%, rgba(0, 0, 0, .1) 66%, transparent 66%), -webkit-linear-gradient(top, rgba(255, 255, 255, .66), rgba(37, 79, 163, .66)); + border-radius: inherit; + background-size: 35px 20px, 100% 100%, 100% 100%; + text-align: center; + -webkit-animation: animate-stripes 5s linear infinite; + animation: animate-stripes 5s linear infinite; + line-height: 15px; +} + +.ui-progressbar-value span { + font-size: larger; +} + +.progress-grid { + display: flex !important; + align-content: center; + grid-gap: 10px; +} + +@-webkit-keyframes animate-stripes { + 100% { + background-position: 100px 0px; + } +} + +@keyframes animate-stripes { + 100% { + background-position: 100px 0px; + } +}⏎ diff --git a/cosmic-client/src/main/webapp/scripts/instances.js b/cosmic-client/src/main/webapp/scripts/instances.js index f3b88dfa4f..44e5b906f0 100644 --- a/cosmic-client/src/main/webapp/scripts/instances.js +++ b/cosmic-client/src/main/webapp/scripts/instances.js @@ -2098,19 +2098,21 @@ }, state: { label: 'label.state', + pollMigrationProgress: true, pollAgainIfValueIsIn: { 'Starting': 1, - 'Stopping': 1 + 'Stopping': 1, + 'Migrating': 1 }, pollAgainFn: function (context) { var toClearInterval = false; $.ajax({ - url: createURL("listVirtualMachines&id=" + context.instances[0].id), + url: createURL("listVirtualMachines&id=" + context.id), dataType: "json", async: false, success: function (json) { var jsonObj = json.listvirtualmachinesresponse.virtualmachine[0]; - if (jsonObj.state != context.instances[0].state) { + if (jsonObj.state !== context.state) { toClearInterval = true; //to clear interval } } diff --git a/cosmic-client/src/main/webapp/scripts/ui/widgets/detailView.js b/cosmic-client/src/main/webapp/scripts/ui/widgets/detailView.js index ffe75eb688..2749dd8ba0 100644 --- a/cosmic-client/src/main/webapp/scripts/ui/widgets/detailView.js +++ b/cosmic-client/src/main/webapp/scripts/ui/widgets/detailView.js @@ -1132,6 +1132,40 @@ $value.data('detail-view-is-password', value.isPassword); } + if (typeof(value.pollAgainFn) === "function") { + for(let state in value.pollAgainIfValueIsIn) { + let interval_id = 0; + if (content === state) { + if (!value.pollAgainFn(data)) { + if (value.pollMigrationProgress) { + interval_id = setInterval(function () { + $.ajax({ + url: createURL("getVmProgress&uuid=" + context.instances[0].id), + dataType: "json", + async: false + }).done(function (jsonObj) { + let json = jsonObj.getvmprogressresponse.getvmprogressresponse; + if (json.timeremaining === 0) { + clearInterval(interval_id); + } else { + let percentage = (json.dataprocessed / (json.datatotal & 1) * 100); + if (percentage >= 100) { + percentage = 100; + } + $("#migration-progress").progressbar({value: percentage}) + .children('.ui-progressbar-value') + .html('' + percentage + '%'); + } + }).fail(function (json) { + clearInterval(interval_id); + }); + }, 1000); + } + } + } + } + } + return true; }); }); diff --git a/cosmic-core/apidoc/gen_toc.py b/cosmic-core/apidoc/gen_toc.py index 7322579434..ac9e84adeb 100755 --- a/cosmic-core/apidoc/gen_toc.py +++ b/cosmic-core/apidoc/gen_toc.py @@ -1,4 +1,4 @@ -#!/cygdrive/c/Python27 +#!/usr/bin/env python2.7 import os.path From 578fa003811163e58021a2d0739c02fd560e6ddc Mon Sep 17 00:00:00 2001 From: Alexander Verhaar Date: Wed, 23 Jun 2021 22:03:22 +0200 Subject: [PATCH 11/14] First try --- .../server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/cosmic-core/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/cosmic-core/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 6cfe52e03e..12e8905519 100644 --- a/cosmic-core/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/cosmic-core/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -3572,7 +3572,6 @@ public VmProgressResponse getVmProgress(final GetVMProgressCmd cmd) throws Cloud } //check permissions _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, vm); - try { MigrationProgressAnswer migrationProgressAnswer = _itMgr.getMigrationProgress(uuid); From 33fd36e35ec40a958b05674786d9e834740c8967 Mon Sep 17 00:00:00 2001 From: Alexander Verhaar Date: Thu, 24 Jun 2021 10:53:32 +0200 Subject: [PATCH 12/14] Return empty response if no job is running --- .../server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/cosmic-core/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/cosmic-core/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 12e8905519..6cfe52e03e 100644 --- a/cosmic-core/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/cosmic-core/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -3572,6 +3572,7 @@ public VmProgressResponse getVmProgress(final GetVMProgressCmd cmd) throws Cloud } //check permissions _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, vm); + try { MigrationProgressAnswer migrationProgressAnswer = _itMgr.getMigrationProgress(uuid); From 89dc1143e437ba2196cde35c0aa3b4f30df1d92f Mon Sep 17 00:00:00 2001 From: Alexander Verhaar Date: Wed, 21 Dec 2022 08:49:23 +0100 Subject: [PATCH 13/14] Use uuid instead of instanceName --- .../src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cosmic-core/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/cosmic-core/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 32ec2d9d8d..7be6eed654 100644 --- a/cosmic-core/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/cosmic-core/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -732,12 +732,12 @@ private void orchestrateMigrateWithStorage(final String vmUuid, final long srcHo } } - migrationProgressQueue.put(vm.getInstanceName(), srcHost.getId()); + migrationProgressQueue.put(vm.getUuid(), srcHost.getId()); // Migrate the vm and its volume. volumeMgr.migrateVolumes(vm, to, srcHost, destHost, volumeToPoolMap); - migrationProgressQueue.remove(vm.getInstanceName()); + migrationProgressQueue.remove(vm.getUuid()); // Put the vm back to running state. moveVmOutofMigratingStateOnSuccess(vm, destHost.getId(), work); From 549b6c88afb5b195272e74131c7dc6f3dc1ce560 Mon Sep 17 00:00:00 2001 From: Alexander Verhaar Date: Wed, 21 Dec 2022 21:53:09 +0100 Subject: [PATCH 14/14] Fix to get vm domjobinfo from agent --- .../cloud/vm/VirtualMachineManagerImpl.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/cosmic-core/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/cosmic-core/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 7be6eed654..da676506e5 100644 --- a/cosmic-core/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/cosmic-core/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -349,7 +349,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac VmWorkJobHandlerProxy _jobHandlerProxy = new VmWorkJobHandlerProxy(this); Map _vmGurus = new HashMap<>(); - ConcurrentHashMap migrationProgressQueue = new ConcurrentHashMap<>(); + ConcurrentHashMap> migrationProgressQueue = new ConcurrentHashMap<>(); ConcurrentHashMap migrationProgressAnswerMap = new ConcurrentHashMap<>(); ScheduledExecutorService _executor = null; @@ -727,18 +727,16 @@ private void orchestrateMigrateWithStorage(final String vmUuid, final long srcHo _agentMgr.send(srcHost.getId(), dettachCommand); s_logger.debug("Deleted config drive ISO for vm " + vm.getInstanceName() + " In host " + srcHost); } catch (final OperationTimedoutException e) { - s_logger.debug("TIme out occured while exeuting command AttachOrDettachConfigDrive " + e.getMessage()); + s_logger.debug("Time out occurred while executing command AttachOrDettachConfigDrive " + e.getMessage()); } } } - migrationProgressQueue.put(vm.getUuid(), srcHost.getId()); + migrationProgressQueue.put(vm.getUuid(), new Pair<>(srcHost.getId(), vm)); // Migrate the vm and its volume. volumeMgr.migrateVolumes(vm, to, srcHost, destHost, volumeToPoolMap); - migrationProgressQueue.remove(vm.getUuid()); - // Put the vm back to running state. moveVmOutofMigratingStateOnSuccess(vm, destHost.getId(), work); @@ -759,6 +757,8 @@ private void orchestrateMigrateWithStorage(final String vmUuid, final long srcHo migrated = true; } finally { + migrationProgressQueue.remove(vm.getUuid()); + if (!migrated) { s_logger.info("Migration was unsuccessful. Cleaning up: " + vm); _alertMgr.sendAlert(alertType, srcHost.getDataCenterId(), srcHost.getPodId(), @@ -4701,10 +4701,13 @@ public MonitorMigrationTask() { protected void runInContext() { try { if (!migrationProgressQueue.isEmpty()) { - for (Map.Entry entry: migrationProgressQueue.entrySet()) { - final MigrationProgressCommand migrationProgressCommand = new MigrationProgressCommand(entry.getKey()); - Answer answer = _agentMgr.send(entry.getValue(), migrationProgressCommand); - migrationProgressAnswerMap.put(entry.getKey(), (MigrationProgressAnswer) answer); + for (Map.Entry> entry: migrationProgressQueue.entrySet()) { + VMInstanceVO vmInstanceVO = entry.getValue().second(); + final MigrationProgressCommand migrationProgressCommand = new MigrationProgressCommand(vmInstanceVO.getInstanceName()); + if (vmInstanceVO.getState() == State.Migrating) { + Answer answer = _agentMgr.send(entry.getValue().first(), migrationProgressCommand); + migrationProgressAnswerMap.put(entry.getKey(), (MigrationProgressAnswer) answer); + } } } TimeUnit.MILLISECONDS.sleep(VmOpProgressInterval.value());