HostVO srcHost = _hostDao.findById(srcHostId);
HostVO destHost = _hostDao.findById(destHostId);
VirtualMachineGuru<T> vmGuru = getVmGuru(vm);
DataCenterVO dc = _dcDao.findById(destHost.getDataCenterId());
HostPodVO pod = _podDao.findById(destHost.getPodId());
Cluster cluster = _clusterDao.findById(destHost.getClusterId());
DeployDestination destination = new DeployDestination(dc, pod, cluster, destHost);
// Create a map of which volume should go in which storage pool.
long vmId = vm.getId();
vm = vmGuru.findById(vmId);
VirtualMachineProfile<VMInstanceVO> profile = new VirtualMachineProfileImpl<VMInstanceVO>(vm);
volumeToPool = getPoolListForVolumesForMigration(profile, destHost, volumeToPool);
// If none of the volumes have to be migrated, fail the call. Administrator needs to make a call for migrating
// a vm and not migrating a vm with storage.
if (volumeToPool.isEmpty()) {
throw new InvalidParameterValueException("Migration of the vm " + vm + "from host " + srcHost +
" to destination host " + destHost + " doesn't involve migrating the volumes. Please use migrateVirtualMachine API.");
}
short alertType = AlertManager.ALERT_TYPE_USERVM_MIGRATE;
if (VirtualMachine.Type.DomainRouter.equals(vm.getType())) {
alertType = AlertManager.ALERT_TYPE_DOMAIN_ROUTER_MIGRATE;
} else if (VirtualMachine.Type.ConsoleProxy.equals(vm.getType())) {
alertType = AlertManager.ALERT_TYPE_CONSOLE_PROXY_MIGRATE;
}
_networkMgr.prepareNicForMigration(profile, destination);
volumeMgr.prepareForMigration(profile, destination);
HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vm.getHypervisorType());
VirtualMachineTO to = hvGuru.implement(profile);
ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Migrating, vm.getType(), vm.getId());
work.setStep(Step.Prepare);
work.setResourceType(ItWorkVO.ResourceType.Host);
work.setResourceId(destHostId);
work = _workDao.persist(work);
// Put the vm in migrating state.
vm.setLastHostId(srcHostId);
moveVmToMigratingState(vm, destHostId, work);
boolean migrated = false;
try {
// Migrate the vm and its volume.
volumeMgr.migrateVolumes(vm, to, srcHost, destHost, volumeToPool);
// Put the vm back to running state.
moveVmOutofMigratingStateOnSuccess(vm, destHost.getId(), work);
try {
if (!checkVmOnHost(vm, destHostId)) {
s_logger.error("Vm not found on destination host. Unable to complete migration for " + vm);
try {
_agentMgr.send(srcHostId, new Commands(cleanup(vm.getInstanceName())), null);
} catch (AgentUnavailableException e) {
s_logger.error("AgentUnavailableException while cleanup on source host: " + srcHostId);
}
cleanup(vmGuru, new VirtualMachineProfileImpl<T>(vm), work, Event.AgentReportStopped, true,
_accountMgr.getSystemUser(), _accountMgr.getSystemAccount());
return null;
}
} catch (OperationTimedoutException e) {
s_logger.warn("Error while checking the vm " + vm + " is on host " + destHost, e);
}
migrated = true;
return vm;
} finally {
if (!migrated) {
s_logger.info("Migration was unsuccessful. Cleaning up: " + vm);
_alertMgr.sendAlert(alertType, srcHost.getDataCenterId(), srcHost.getPodId(), "Unable to migrate vm " +
vm.getInstanceName() + " from host " + srcHost.getName() + " in zone " + dc.getName() +
" and pod " + dc.getName(), "Migrate Command failed. Please check logs.");
try {
_agentMgr.send(destHostId, new Commands(cleanup(vm.getInstanceName())), null);
stateTransitTo(vm, Event.OperationFailed, srcHostId);
} catch (AgentUnavailableException e) {
s_logger.warn("Looks like the destination Host is unavailable for cleanup.", e);