VirtualMachineManager.migrateAway() need to put under management of new sync model

This commit is contained in:
Kelven Yang 2014-02-06 16:44:34 -08:00
parent 434f8dab72
commit fa7d9ad1a8
5 changed files with 164 additions and 12 deletions

View File

@ -109,7 +109,7 @@ public interface VirtualMachineManager extends Manager {
void destroy(String vmUuid) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException;
void migrateAway(String vmUuid, long hostId, DeploymentPlanner planner) throws InsufficientServerCapacityException;
void migrateAway(String vmUuid, long hostId) throws InsufficientServerCapacityException;
void migrate(String vmUuid, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException;

View File

@ -18,6 +18,7 @@ package com.cloud.ha;
import java.util.List;
import com.cloud.deploy.DeploymentPlanner;
import com.cloud.host.HostVO;
import com.cloud.host.Status;
import com.cloud.utils.component.Manager;
@ -103,4 +104,6 @@ public interface HighAvailabilityManager extends Manager {
* @return
*/
String getHaTag();
DeploymentPlanner getHAPlanner();
}

View File

@ -1546,7 +1546,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
// Disable this hacking thing, VM snapshot task need to be managed by its orchestartion flow istelf instead of
// hacking it here at general VM manager
/*
/*
if (_vmSnapshotMgr.hasActiveVMSnapshotTasks(vm.getId())) {
s_logger.error("State transit with event: " + e + " failed due to: " + vm.getInstanceName() + " has active VM snapshots tasks");
return false;
@ -2183,7 +2183,53 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
}
@Override
public void migrateAway(String vmUuid, long srcHostId, DeploymentPlanner planner) throws InsufficientServerCapacityException {
public void migrateAway(String vmUuid, long srcHostId) throws InsufficientServerCapacityException {
AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
if (!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) {
// avoid re-entrance
VmWorkJobVO placeHolder = null;
if (VmJobEnabled.value()) {
VirtualMachine vm = _vmDao.findByUuid(vmUuid);
placeHolder = createPlaceHolderWork(vm.getId());
}
try {
try {
orchestrateMigrateAway(vmUuid, srcHostId, null);
} catch (InsufficientServerCapacityException e) {
s_logger.warn("Failed to deploy vm " + vmUuid + " with original planner, sending HAPlanner");
orchestrateMigrateAway(vmUuid, srcHostId, _haMgr.getHAPlanner());
}
} finally {
if (VmJobEnabled.value())
_workJobDao.expunge(placeHolder.getId());
}
} else {
Outcome<VirtualMachine> outcome = migrateVmAwayThroughJobQueue(vmUuid, srcHostId);
try {
VirtualMachine vm = outcome.get();
} catch (InterruptedException e) {
throw new RuntimeException("Operation is interrupted", e);
} catch (java.util.concurrent.ExecutionException e) {
throw new RuntimeException("Execution excetion", e);
}
Object jobException = _jobMgr.unmarshallResultObject(outcome.getJob());
if (jobException != null) {
if (jobException instanceof InsufficientServerCapacityException)
throw (InsufficientServerCapacityException)jobException;
else if (jobException instanceof ConcurrentOperationException)
throw (ConcurrentOperationException)jobException;
else if (jobException instanceof RuntimeException)
throw (RuntimeException)jobException;
else if (jobException instanceof Throwable)
throw new RuntimeException("Unexpected exception", (Throwable)jobException);
}
}
}
private void orchestrateMigrateAway(String vmUuid, long srcHostId, DeploymentPlanner planner) throws InsufficientServerCapacityException {
VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
if (vm == null) {
s_logger.debug("Unable to find a VM for " + vmUuid);
@ -4562,6 +4608,57 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
VirtualMachine.PowerState.PowerOn, vm.getId(), vm.getPowerHostId());
}
public Outcome<VirtualMachine> migrateVmAwayThroughJobQueue(final String vmUuid, final long srcHostId) {
final CallContext context = CallContext.current();
final User user = context.getCallingUser();
final Account account = context.getCallingAccount();
final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
Object[] result = Transaction.execute(new TransactionCallback<Object[]>() {
@Override
public Object[] doInTransaction(TransactionStatus status) {
_vmDao.lockRow(vm.getId(), true);
List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
VirtualMachine.Type.Instance, vm.getId(),
VmWorkMigrateAway.class.getName());
VmWorkJobVO workJob = null;
if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
assert (pendingWorkJobs.size() == 1);
workJob = pendingWorkJobs.get(0);
} else {
workJob = new VmWorkJobVO(context.getContextId());
workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER);
workJob.setCmd(VmWorkMigrateAway.class.getName());
workJob.setAccountId(account.getId());
workJob.setUserId(user.getId());
workJob.setVmType(VirtualMachine.Type.Instance);
workJob.setVmInstanceId(vm.getId());
workJob.setRelated(AsyncJobExecutionContext.getOriginJobContextId());
// save work context info (there are some duplications)
VmWorkMigrateAway workInfo = new VmWorkMigrateAway(user.getId(), account.getId(), vm.getId(), VirtualMachineManagerImpl.VM_WORK_JOB_HANDLER, srcHostId);
workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
_jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId());
}
return new Object[] {workJob, new Long(workJob.getId())};
}
});
final long jobId = (Long)result[1];
AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
return new VmStateSyncOutcome((VmWorkJobVO)result[0],
VirtualMachine.PowerState.PowerOn, vm.getId(), vm.getPowerHostId());
}
public Outcome<VirtualMachine> migrateVmWithStorageThroughJobQueue(
final String vmUuid, final long srcHostId, final long destHostId,
final Map<Volume, StoragePool> volumeToPool) {
@ -4964,6 +5061,23 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
return new Pair<JobInfo.Status, String>(JobInfo.Status.SUCCEEDED, null);
}
private Pair<JobInfo.Status, String> orchestrateMigrateAway(VmWorkMigrateAway work) throws Exception {
VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, work.getVmId());
if (vm == null) {
s_logger.info("Unable to find vm " + work.getVmId());
}
assert (vm != null);
try {
orchestrateMigrateAway(vm.getUuid(), work.getSrcHostId(), null);
} catch (InsufficientServerCapacityException e) {
s_logger.warn("Failed to deploy vm " + vm.getId() + " with original planner, sending HAPlanner");
orchestrateMigrateAway(vm.getUuid(), work.getSrcHostId(), _haMgr.getHAPlanner());
}
return new Pair<JobInfo.Status, String>(JobInfo.Status.SUCCEEDED, null);
}
private Pair<JobInfo.Status, String> orchestrateMigrateWithStorage(VmWorkMigrateWithStorage work) throws Exception {
VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, work.getVmId());
if (vm == null) {

View File

@ -0,0 +1,36 @@
// 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;
public class VmWorkMigrateAway extends VmWork {
private static final long serialVersionUID = -5917512239025814373L;
private long srcHostId;
public VmWorkMigrateAway(long userId, long accountId, long vmId, String handlerName,
long srcHostId) {
super(userId, accountId, vmId, handlerName);
this.srcHostId = srcHostId;
}
public long getSrcHostId() {
return srcHostId;
}
}

View File

@ -32,7 +32,6 @@ import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
import org.apache.log4j.NDC;
import com.cloud.deploy.HAPlanner;
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.managed.context.ManagedContext;
@ -48,6 +47,8 @@ import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.HostPodDao;
import com.cloud.deploy.DeploymentPlanner;
import com.cloud.deploy.HAPlanner;
import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
@ -148,7 +149,7 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements HighAvai
}
public void setHaPlanners(List<HAPlanner> haPlanners) {
this._haPlanners = haPlanners;
_haPlanners = haPlanners;
}
@ -611,13 +612,7 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements HighAvai
VMInstanceVO vm = _instanceDao.findById(vmId);
// First try starting the vm with its original planner, if it doesn't succeed send HAPlanner as its an emergency.
boolean result = false;
try {
_itMgr.migrateAway(vm.getUuid(), srcHostId, null);
}catch (InsufficientServerCapacityException e) {
s_logger.warn("Failed to deploy vm " + vmId + " with original planner, sending HAPlanner");
_itMgr.migrateAway(vm.getUuid(), srcHostId, _haPlanners.get(0));
}
_itMgr.migrateAway(vm.getUuid(), srcHostId);
return null;
} catch (InsufficientServerCapacityException e) {
s_logger.warn("Insufficient capacity for migrating a VM.");
@ -935,4 +930,8 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements HighAvai
return _haTag;
}
@Override
public DeploymentPlanner getHAPlanner() {
return _haPlanners.get(0);
}
}