You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ah...@apache.org on 2013/05/14 02:43:08 UTC

[45/50] [abbrv] Merged master to vmsync

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d4039743/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
----------------------------------------------------------------------
diff --cc server/src/com/cloud/vm/VirtualMachineManagerImpl.java
index 5a4f179,521b5e0..752eb73
--- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@@ -32,29 -36,45 +32,46 @@@ import javax.ejb.Local
  import javax.inject.Inject;
  import javax.naming.ConfigurationException;
  
- import com.cloud.capacity.CapacityManager;
++import org.apache.log4j.Logger;
++
  import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
+ import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
+ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
 +import org.apache.cloudstack.framework.messagebus.MessageBus;
 +import org.apache.cloudstack.messagebus.TopicConstants;
  import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
- 
- import com.cloud.dc.*;
- import com.cloud.agent.api.*;
- import org.apache.log4j.Logger;
+ import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 -import org.apache.log4j.Logger;
  
  import com.cloud.agent.AgentManager;
  import com.cloud.agent.AgentManager.OnError;
  import com.cloud.agent.Listener;
+ import com.cloud.agent.api.AgentControlAnswer;
+ import com.cloud.agent.api.AgentControlCommand;
+ import com.cloud.agent.api.Answer;
+ import com.cloud.agent.api.CheckVirtualMachineAnswer;
+ import com.cloud.agent.api.CheckVirtualMachineCommand;
+ import com.cloud.agent.api.ClusterSyncAnswer;
 -import com.cloud.agent.api.ClusterSyncCommand;
+ import com.cloud.agent.api.Command;
 -import com.cloud.agent.api.MigrateAnswer;
 -import com.cloud.agent.api.MigrateCommand;
+ import com.cloud.agent.api.PingRoutingCommand;
 -import com.cloud.agent.api.PrepareForMigrationAnswer;
 -import com.cloud.agent.api.PrepareForMigrationCommand;
+ import com.cloud.agent.api.RebootAnswer;
+ import com.cloud.agent.api.RebootCommand;
 -import com.cloud.agent.api.ScaleVmCommand;
+ import com.cloud.agent.api.StartAnswer;
+ import com.cloud.agent.api.StartCommand;
+ import com.cloud.agent.api.StartupCommand;
+ import com.cloud.agent.api.StartupRoutingCommand;
 -import com.cloud.agent.api.StartupRoutingCommand.VmState;
+ import com.cloud.agent.api.StopAnswer;
+ import com.cloud.agent.api.StopCommand;
  import com.cloud.agent.api.to.NicTO;
  import com.cloud.agent.api.to.VirtualMachineTO;
  import com.cloud.agent.manager.Commands;
  import com.cloud.agent.manager.allocator.HostAllocator;
  import com.cloud.alert.AlertManager;
 +import com.cloud.api.ApiSerializerHelper;
 +import com.cloud.async.AsyncJob;
 +import com.cloud.async.AsyncJobConstants;
 +import com.cloud.async.AsyncJobExecutionContext;
 +import com.cloud.async.AsyncJobManager;
+ import com.cloud.capacity.CapacityManager;
  import com.cloud.cluster.ClusterManager;
  import com.cloud.configuration.Config;
  import com.cloud.configuration.ConfigurationManager;
@@@ -133,16 -165,17 +164,16 @@@ import com.cloud.utils.exception.CloudR
  import com.cloud.utils.exception.ExecutionException;
  import com.cloud.utils.fsm.NoTransitionException;
  import com.cloud.utils.fsm.StateMachine2;
--import com.cloud.vm.ItWorkVO.Step;
  import com.cloud.vm.VirtualMachine.Event;
 +import com.cloud.vm.VirtualMachine.PowerState;
  import com.cloud.vm.VirtualMachine.State;
++import com.cloud.vm.VmWorkJobVO.Step;
  import com.cloud.vm.dao.NicDao;
  import com.cloud.vm.dao.UserVmDao;
+ import com.cloud.vm.dao.UserVmDetailsDao;
  import com.cloud.vm.dao.VMInstanceDao;
 -import com.cloud.vm.snapshot.VMSnapshot;
  import com.cloud.vm.snapshot.VMSnapshotManager;
 -import com.cloud.vm.snapshot.VMSnapshotVO;
  import com.cloud.vm.snapshot.dao.VMSnapshotDao;
- import com.cloud.vm.dao.UserVmDetailsDao;
  
  @Local(value = VirtualMachineManager.class)
  public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, Listener {
@@@ -172,12 -207,8 +205,12 @@@
      protected DomainDao _domainDao;
      @Inject
      protected ClusterManager _clusterMgr;
 +   
- /*    
++/*
      @Inject
      protected ItWorkDao _workDao;
 +*/
 +    
      @Inject
      protected UserVmDao _userVmDao;
      @Inject
@@@ -229,10 -270,16 +272,16 @@@
  		this._hostAllocators = _hostAllocators;
  	}
  
 -    @Inject
 +	@Inject
+     protected List<StoragePoolAllocator> _storagePoolAllocators;
+ 
+     @Inject
      protected ResourceManager _resourceMgr;
 -
 +    
-     @Inject 
+     @Inject
+     protected SnapshotManager _snapshotMgr;
+ 
+     @Inject
      protected VMSnapshotManager _vmSnapshotMgr = null;
      @Inject
      protected ClusterDetailsDao  _clusterDetailsDao;
@@@ -243,11 -290,9 +292,13 @@@
      protected ConfigurationDao _configDao;
      @Inject
      VolumeManager volumeMgr;
 -
 +    
 +    @Inject protected MessageBus _messageBus;
 +    @Inject protected VirtualMachinePowerStateSync _syncMgr;
 +    @Inject protected VmWorkJobDao _workJobDao;
 +    @Inject protected AsyncJobManager _jobMgr;
+     @Inject
+     DeploymentPlanningManager _dpMgr;
  
      Map<VirtualMachine.Type, VirtualMachineGuru<? extends VMInstanceVO>> _vmGurus = new HashMap<VirtualMachine.Type, VirtualMachineGuru<? extends VMInstanceVO>>();
      protected StateMachine2<State, VirtualMachine.Event, VirtualMachine> _stateMachine;
@@@ -327,15 -359,15 +378,15 @@@
          }
  
          if (template.getFormat() == ImageFormat.ISO) {
--            this.volumeMgr.allocateRawVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), rootDiskOffering.second(), vm, owner);
++            volumeMgr.allocateRawVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), rootDiskOffering.second(), vm, owner);
          } else if (template.getFormat() == ImageFormat.BAREMETAL) {
              // Do nothing
          } else {
--            this.volumeMgr.allocateTemplatedVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), template, vm, owner);
++            volumeMgr.allocateTemplatedVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), template, vm, owner);
          }
  
          for (Pair<DiskOfferingVO, Long> offering : dataDiskOfferings) {
--            this.volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + vm.getId(), offering.first(), offering.second(), vm, owner);
++            volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + vm.getId(), offering.first(), offering.second(), vm, owner);
          }
  
          txn.commit();
@@@ -413,7 -450,8 +464,8 @@@
          s_logger.debug("Cleaning up NICS");
          _networkMgr.cleanupNics(profile);
          // Clean up volumes based on the vm's instance id
-         this.volumeMgr.cleanupVolumes(vm.getId());
+         List<VolumeVO> rootVol = _volsDao.findByInstanceAndType(vm.getId(), Volume.Type.ROOT);
 -        this.volumeMgr.cleanupVolumes(vm.getId());
++        volumeMgr.cleanupVolumes(vm.getId());
  
          VirtualMachineGuru<T> guru = getVmGuru(vm);
          guru.finalizeExpunge(vm);
@@@ -483,255 -550,143 +564,256 @@@
          }
      }
  
- /*    
--    protected boolean checkWorkItems(VMInstanceVO vm, State state) throws ConcurrentOperationException {
--        while (true) {
--            ItWorkVO vo = _workDao.findByOutstandingWork(vm.getId(), state);
--            if (vo == null) {
--                if (s_logger.isDebugEnabled()) {
--                    s_logger.debug("Unable to find work for VM: " + vm + " and state: " + state);
++    /*
++        protected boolean checkWorkItems(VMInstanceVO vm, State state) throws ConcurrentOperationException {
++            while (true) {
++                VmWorkJobVO vo = _workDao.findByOutstandingWork(vm.getId(), state);
++                if (vo == null) {
++                    if (s_logger.isDebugEnabled()) {
++                        s_logger.debug("Unable to find work for VM: " + vm + " and state: " + state);
++                    }
++                    return true;
                  }
--                return true;
--            }
  
--            if (vo.getStep() == Step.Done) {
--                if (s_logger.isDebugEnabled()) {
--                    s_logger.debug("Work for " + vm + " is " + vo.getStep());
++                if (vo.getStep() == Step.Done) {
++                    if (s_logger.isDebugEnabled()) {
++                        s_logger.debug("Work for " + vm + " is " + vo.getStep());
++                    }
++                    return true;
                  }
--                return true;
--            }
  
--            if (vo.getSecondsTaskIsInactive() > _cancelWait) {
--                s_logger.warn("The task item for vm " + vm + " has been inactive for " + vo.getSecondsTaskIsInactive());
--                return false;
--            }
++                if (vo.getSecondsTaskIsInactive() > _cancelWait) {
++                    s_logger.warn("The task item for vm " + vm + " has been inactive for " + vo.getSecondsTaskIsInactive());
++                    return false;
++                }
  
--            try {
--                Thread.sleep(_opWaitInterval);
--            } catch (InterruptedException e) {
--                s_logger.info("Waiting for " + vm + " but is interrupted");
--                throw new ConcurrentOperationException("Waiting for " + vm + " but is interrupted");
++                try {
++                    Thread.sleep(_opWaitInterval);
++                } catch (InterruptedException e) {
++                    s_logger.info("Waiting for " + vm + " but is interrupted");
++                    throw new ConcurrentOperationException("Waiting for " + vm + " but is interrupted");
++                }
++                s_logger.debug("Waiting some more to make sure there's no activity on " + vm);
              }
--            s_logger.debug("Waiting some more to make sure there's no activity on " + vm);
          }
-     }
- */
++    */
 +    
- /*    
-     @DB
-     protected <T extends VMInstanceVO> Ternary<T, ReservationContext, ItWorkVO> changeToStartState(VirtualMachineGuru<T> vmGuru, T vm, User caller, Account account)
-             throws ConcurrentOperationException {
-         long vmId = vm.getId();
++    /*
++        @DB
++        protected <T extends VMInstanceVO> Ternary<T, ReservationContext, VmWorkJobVO> changeToStartState(VirtualMachineGuru<T> vmGuru, T vm, User caller, Account account)
++                throws ConcurrentOperationException {
++            long vmId = vm.getId();
  
-         ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Starting, vm.getType(), vm.getId());
-         int retry = _lockStateRetry;
-         while (retry-- != 0) {
-             Transaction txn = Transaction.currentTxn();
-             Ternary<T, ReservationContext, ItWorkVO> result = null;
-             txn.start();
-             try {
-                 Journal journal = new Journal.LogJournal("Creating " + vm, s_logger);
-                 work = _workDao.persist(work);
-                 ReservationContextImpl context = new ReservationContextImpl(work.getId(), journal, caller, account);
 -    }
 -
 -    @DB
 -    protected <T extends VMInstanceVO> Ternary<T, ReservationContext, ItWorkVO> changeToStartState(VirtualMachineGuru<T> vmGuru, T vm, User caller, Account account)
 -            throws ConcurrentOperationException {
 -        long vmId = vm.getId();
 -
 -        ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Starting, vm.getType(), vm.getId());
 -        int retry = _lockStateRetry;
 -        while (retry-- != 0) {
 -            Transaction txn = Transaction.currentTxn();
 -            Ternary<T, ReservationContext, ItWorkVO> result = null;
 -            txn.start();
 -            try {
 -                Journal journal = new Journal.LogJournal("Creating " + vm, s_logger);
 -                work = _workDao.persist(work);
 -                ReservationContextImpl context = new ReservationContextImpl(work.getId(), journal, caller, account);
++            VmWorkJobVO work = new VmWorkJobVO(UUID.randomUUID().toString(), _nodeId, State.Starting, vm.getType(), vm.getId());
++            int retry = _lockStateRetry;
++            while (retry-- != 0) {
++                Transaction txn = Transaction.currentTxn();
++                Ternary<T, ReservationContext, VmWorkJobVO> result = null;
++                txn.start();
++                try {
++                    Journal journal = new Journal.LogJournal("Creating " + vm, s_logger);
++                    work = _workDao.persist(work);
++                    ReservationContextImpl context = new ReservationContextImpl(work.getId(), journal, caller, account);
  
--                if (stateTransitTo(vm, Event.StartRequested, null, work.getId())) {
++                    if (stateTransitTo(vm, Event.StartRequested, null, work.getId())) {
++                        if (s_logger.isDebugEnabled()) {
++                            s_logger.debug("Successfully transitioned to start state for " + vm + " reservation id = " + work.getId());
++                        }
++                        result = new Ternary<T, ReservationContext, VmWorkJobVO>(vmGuru.findById(vmId), context, work);
++                        txn.commit();
++                        return result;
++                    }
++                } catch (NoTransitionException e) {
                      if (s_logger.isDebugEnabled()) {
--                        s_logger.debug("Successfully transitioned to start state for " + vm + " reservation id = " + work.getId());
++                        s_logger.debug("Unable to transition into Starting state due to " + e.getMessage());
++                    }
++                } finally {
++                    if (result == null) {
++                        txn.rollback();
                      }
--                    result = new Ternary<T, ReservationContext, ItWorkVO>(vmGuru.findById(vmId), context, work);
--                    txn.commit();
--                    return result;
--                }
--            } catch (NoTransitionException e) {
--                if (s_logger.isDebugEnabled()) {
--                    s_logger.debug("Unable to transition into Starting state due to " + e.getMessage());
                  }
--            } finally {
--                if (result == null) {
--                    txn.rollback();
++
++                VMInstanceVO instance = _vmDao.findById(vmId);
++                if (instance == null) {
++                    throw new ConcurrentOperationException("Unable to acquire lock on " + vm);
                  }
--            }
  
--            VMInstanceVO instance = _vmDao.findById(vmId);
--            if (instance == null) {
--                throw new ConcurrentOperationException("Unable to acquire lock on " + vm);
--            }
++                if (s_logger.isDebugEnabled()) {
++                    s_logger.debug("Determining why we're unable to update the state to Starting for " + instance + ".  Retry=" + retry);
++                }
  
--            if (s_logger.isDebugEnabled()) {
--                s_logger.debug("Determining why we're unable to update the state to Starting for " + instance + ".  Retry=" + retry);
--            }
++                State state = instance.getState();
++                if (state == State.Running) {
++                    if (s_logger.isDebugEnabled()) {
++                        s_logger.debug("VM is already started: " + vm);
++                    }
++                    return null;
++                }
  
--            State state = instance.getState();
--            if (state == State.Running) {
--                if (s_logger.isDebugEnabled()) {
--                    s_logger.debug("VM is already started: " + vm);
++                if (state.isTransitional()) {
++                    if (!checkWorkItems(vm, state)) {
++                        throw new ConcurrentOperationException("There are concurrent operations on " + vm);
++                    } else {
++                        continue;
++                    }
                  }
--                return null;
--            }
  
--            if (state.isTransitional()) {
--                if (!checkWorkItems(vm, state)) {
--                    throw new ConcurrentOperationException("There are concurrent operations on " + vm);
--                } else {
--                    continue;
++                if (state != State.Stopped) {
++                    s_logger.debug("VM " + vm + " is not in a state to be started: " + state);
++                    return null;
                  }
              }
  
--            if (state != State.Stopped) {
--                s_logger.debug("VM " + vm + " is not in a state to be started: " + state);
--                return null;
--            }
++            throw new ConcurrentOperationException("Unable to change the state of " + vm);
          }
- 
-         throw new ConcurrentOperationException("Unable to change the state of " + vm);
-     }
- */
++    */
  
 +    @DB
 +    protected <T extends VMInstanceVO> Ternary<T, ReservationContext, VmWorkJobVO> changeToStartState(VirtualMachineGuru<T> vmGuru, T vm, User caller, Account account)
 +        throws ConcurrentOperationException {
 +    	
 +        long vmId = vm.getId();
 +        
 +        Ternary<T, ReservationContext, VmWorkJobVO> result = null;
 +        Transaction txn = Transaction.currentTxn();
 +        txn.start();
 +        try {
- 	        VmWorkJobVO work = this._workJobDao.findById(AsyncJobExecutionContext.getCurrentExecutionContext().getJob().getId());
++	        VmWorkJobVO work = _workJobDao.findById(AsyncJobExecutionContext.getCurrentExecutionContext().getJob().getId());
 +	        
 +	        Journal journal = new Journal.LogJournal("Creating " + vm, s_logger);
 +	        ReservationContextImpl context = new ReservationContextImpl(work.getUuid(), journal, caller, account);
 +	        if (stateTransitTo(vm, Event.StartRequested, null, work.getUuid())) {
 +	            if (s_logger.isDebugEnabled()) {
 +	                s_logger.debug("Successfully transitioned to start state for " + vm + " reservation id = " + work.getId());
 +	            }
 +	            result = new Ternary<T, ReservationContext, VmWorkJobVO>(vmGuru.findById(vmId), context, work);
 +	            txn.commit();
 +	            return result;
 +	        }
 +        } catch (NoTransitionException e) {
 +            s_logger.warn("Unable to transition into Starting state due to " + e.getMessage());
 +        } finally {
 +        	if(result == null)
 +        		txn.rollback();
 +        }
 +        
          throw new ConcurrentOperationException("Unable to change the state of " + vm);
      }
 -
 -    protected <T extends VMInstanceVO> boolean changeState(T vm, Event event, Long hostId, ItWorkVO work, Step step) throws NoTransitionException {
 +    
 +    protected <T extends VMInstanceVO> boolean changeState(T vm, Event event, Long hostId, VmWorkJobVO work, Step step) throws NoTransitionException {
          // FIXME: We should do this better.
 -        Step previousStep = work.getStep();
 -        _workDao.updateStep(work, step);
 +        VmWorkJobVO.Step previousStep = work.getStep();
 +        
          boolean result = false;
          try {
              result = stateTransitTo(vm, event, hostId);
              return result;
          } finally {
              if (!result) {
 -                _workDao.updateStep(work, previousStep);
 +            	work.setStep(previousStep);
-             	this._workJobDao.update(work.getId(), work);
++            	_workJobDao.update(work.getId(), work);
              }
          }
      }
 -
 +    
      @Override
      public <T extends VMInstanceVO> T advanceStart(T vm, Map<VirtualMachineProfile.Param, Object> params, User caller, Account account) throws InsufficientCapacityException,
 -    ConcurrentOperationException, ResourceUnavailableException {
 +    	ConcurrentOperationException, ResourceUnavailableException {
          return advanceStart(vm, params, caller, account, null);
      }
 +    
++    @Override
 +    @DB
 +    public <T extends VMInstanceVO> T advanceStart(final T vm, Map<VirtualMachineProfile.Param, Object> params, User caller, Account account, DeploymentPlan planToDeploy)
 +        throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
 +    	
 +    	VmWorkJobVO workJob = null;
 +    	Transaction txn = Transaction.currentTxn();
 +    	try {
 +        	txn.start();
 +        	
 +        	_vmDao.lockRow(vm.getId(), true);
 +        	
 +        	List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
 +        		VirtualMachine.Type.Instance, vm.getId(), VmWorkConstants.VM_WORK_START);
 +        	
 +        	if(pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
 +        		assert(pendingWorkJobs.size() == 1);
 +        		workJob = pendingWorkJobs.get(0);
 +        	} else {
 +        		workJob = new VmWorkJobVO();
 +        	
 +        		workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER);
 +        		workJob.setCmd(VmWorkConstants.VM_WORK_START);
 +        		
 +        		workJob.setAccountId(account.getId());
 +        		workJob.setUserId(caller.getId());
 +        		workJob.setStep(VmWorkJobVO.Step.Starting);
 +        		workJob.setVmType(vm.getType());
 +        		workJob.setVmInstanceId(vm.getId());
 +
 +        		// save work context info (there are some duplications)
 +        		VmWorkStart workInfo = new VmWorkStart();
 +        		workInfo.setAccountId(account.getId());
 +        		workInfo.setUserId(caller.getId());
 +        		workInfo.setVmId(vm.getId());
 +        		workInfo.setPlan(planToDeploy);
 +        		workInfo.setParams(params);
 +        		workJob.setCmdInfo(ApiSerializerHelper.toSerializedString(workInfo));
 +        		
 +        		_jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId());
 +        	}
 +    	
 +        	txn.commit();
 +    	} catch(Throwable e) {
 +    		s_logger.error("Unexpected exception", e);
 +    		txn.rollback();
 +    		throw new ConcurrentOperationException("Unhandled exception, converted to ConcurrentOperationException");
 +    	}
 +
 +    	final long jobId = workJob.getId();
 +    	
-     	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId); 
++    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
 +
 +    	//
 +    	// TODO : this will be replaced with fully-asynchronized way later so that we don't need
 +    	// to wait here. The reason we do it synchronized here is that callers of advanceStart is expecting
 +    	// synchronized semantics
-     	// 
++    	//
 +    	//
 +    	_jobMgr.waitAndCheck(
-     		new String[] { TopicConstants.VM_POWER_STATE, TopicConstants.JOB_STATE }, 
++    		new String[] { TopicConstants.VM_POWER_STATE, TopicConstants.JOB_STATE },
 +    		3000L, 600000L, new Predicate() {
 +
 +				@Override
 +				public boolean checkCondition() {
 +					VMInstanceVO instance = _vmDao.findById(vm.getId());
 +					if(instance.getPowerState() == VirtualMachine.PowerState.PowerOn)
 +						return true;
 +			
 +					VmWorkJobVO workJob = _workJobDao.findById(jobId);
 +					if(workJob.getStatus() != AsyncJobConstants.STATUS_IN_PROGRESS)
 +						return true;
 +					
 +					return false;
 +				}
 +    		});
 +    	AsyncJobExecutionContext.getCurrentExecutionContext().disjoinJob(jobId);
 +    	
 +    	return vm;
 +    }
  
      @Override
 -    public <T extends VMInstanceVO> T advanceStart(T vm, Map<VirtualMachineProfile.Param, Object> params, User caller, Account account, DeploymentPlan planToDeploy)
 +    public <T extends VMInstanceVO> T processVmStartWork(T vm, Map<VirtualMachineProfile.Param, Object> params, User caller, Account account, DeploymentPlan planToDeploy)
              throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
 -        long vmId = vm.getId();
          VirtualMachineGuru<T> vmGuru = getVmGuru(vm);
 -
          vm = vmGuru.findById(vm.getId());
 -        Ternary<T, ReservationContext, ItWorkVO> start = changeToStartState(vmGuru, vm, caller, account);
 -        if (start == null) {
 -            return vmGuru.findById(vmId);
 -        }
 +  
 +        Ternary<T, ReservationContext, VmWorkJobVO> start = changeToStartState(vmGuru, vm, caller, account);
 +        assert(start != null);
  
 -        vm = start.first();
          ReservationContext ctx = start.second();
 -        ItWorkVO work = start.third();
 +        VmWorkJobVO work = start.third();
  
          T startedVm = null;
          ServiceOfferingVO offering = _offeringDao.findById(vm.getServiceOfferingId());
@@@ -822,20 -780,15 +904,14 @@@
  
                  VirtualMachineProfileImpl<T> vmProfile = new VirtualMachineProfileImpl<T>(vm, template, offering, account, params);
                  DeployDestination dest = null;
-                 for (DeploymentPlanner planner : _planners) {
-                     if (planner.canHandle(vmProfile, plan, avoids)) {
-                         dest = planner.plan(vmProfile, plan, avoids);
-                     } else {
-                         continue;
-                     }
-                     if (dest != null) {
-                         avoids.addHost(dest.getHost().getId());
-                         AsyncJobExecutionContext.getCurrentExecutionContext().logJobJournal(
-                         	AsyncJob.JournalType.SUCCESS, "Deployment found, dest host: " + dest.getHost().getId(), null);
-                         break;
-                     }
-                 }
+                 try {
+                     dest = _dpMgr.planDeployment(vmProfile, plan, avoids);
+                 } catch (AffinityConflictException e2) {
+                     s_logger.warn("Unable to create deployment, affinity rules associted to the VM conflict", e2);
+                     throw new CloudRuntimeException(
+                             "Unable to create deployment, affinity rules associted to the VM conflict");
  
+                 }
 -
                  if (dest == null) {
                      if (planChangedByVolume) {
                          plan = originalPlan;
@@@ -847,6 -800,11 +923,13 @@@
                      throw new InsufficientServerCapacityException("Unable to create a deployment for " + vmProfile, DataCenter.class, plan.getDataCenterId());
                  }
  
+                 if (dest != null) {
+                     avoids.addHost(dest.getHost().getId());
 -                    journal.record("Deployment found ", vmProfile, dest);
++                    AsyncJobExecutionContext.getCurrentExecutionContext().logJobJournal(
++                            AsyncJob.JournalType.SUCCESS, "Deployment found, dest host: " + dest.getHost().getId(), null);
++                    break;
+                 }
+ 
                  long destHostId = dest.getHost().getId();
                  vm.setPodId(dest.getPod().getId());
                  Long cluster_id = dest.getCluster().getId();
@@@ -867,9 -825,9 +950,9 @@@
                      if (s_logger.isDebugEnabled()) {
                          s_logger.debug("VM is being created in podId: " + vm.getPodIdToDeployIn());
                      }
-                     _networkMgr.prepare(vmProfile, dest, ctx); 
+                     _networkMgr.prepare(vmProfile, dest, ctx);
                      if (vm.getHypervisorType() != HypervisorType.BareMetal) {
--                        this.volumeMgr.prepare(vmProfile, dest);
++                        volumeMgr.prepare(vmProfile, dest);
                      }
                      //since StorageMgr succeeded in volume creation, reuse Volume for further tries until current cluster has capacity
                      if(!reuseVolume){
@@@ -984,9 -946,14 +1067,14 @@@
              }
          }
  
+         if (startedVm == null) {
+             throw new CloudRuntimeException("Unable to start instance '" + vm.getHostName()
+                             + "' (" + vm.getUuid() + "), see management server log for details");
+         }
+ 
          return startedVm;
      }
 -
 +    
      @Override
      public <T extends VMInstanceVO> boolean stop(T vm, User user, Account account) throws ResourceUnavailableException {
          try {
@@@ -1080,96 -1047,34 +1168,96 @@@
              s_logger.warn("Unable to release some network resources.", e);
          }
  
--        this.volumeMgr.release(profile);
++        volumeMgr.release(profile);
          s_logger.debug("Successfully cleanued up resources for the vm " + vm + " in " + state + " state");
          return true;
      }
 +    
 +    @Override
 +    public <T extends VMInstanceVO> boolean advanceStop(final T vm, boolean forced, User user, Account account) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
 +    	VmWorkJobVO workJob = null;
 +    	Transaction txn = Transaction.currentTxn();
 +    	try {
 +        	txn.start();
 +        	
 +        	_vmDao.lockRow(vm.getId(), true);
 +        	
 +        	List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
 +        		VirtualMachine.Type.Instance, vm.getId(), VmWorkConstants.VM_WORK_STOP);
 +        	
 +        	if(pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
 +        		assert(pendingWorkJobs.size() == 1);
 +        		workJob = pendingWorkJobs.get(0);
 +        	} else {
 +        		workJob = new VmWorkJobVO();
 +        	
 +        		workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER);
 +        		workJob.setCmd(VmWorkConstants.VM_WORK_STOP);
 +        		
 +        		workJob.setAccountId(account.getId());
 +        		workJob.setUserId(user.getId());
 +        		workJob.setStep(VmWorkJobVO.Step.Prepare);
 +        		workJob.setVmType(vm.getType());
 +        		workJob.setVmInstanceId(vm.getId());
 +
 +        		// save work context info (there are some duplications)
 +        		VmWorkStop workInfo = new VmWorkStop();
 +        		workInfo.setAccountId(account.getId());
 +        		workInfo.setUserId(user.getId());
 +        		workInfo.setVmId(vm.getId());
 +        		workInfo.setForceStop(forced);
 +        		workJob.setCmdInfo(ApiSerializerHelper.toSerializedString(workInfo));
 +        		
 +        		_jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId());
 +        	}
 +    	
 +        	txn.commit();
 +    	} catch(Throwable e) {
 +    		s_logger.error("Unexpected exception", e);
 +    		txn.rollback();
 +    		throw new ConcurrentOperationException("Unhandled exception, converted to ConcurrentOperationException");
 +    	}
 +
 +    	final long jobId = workJob.getId();
 +    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
 +    	
 +    	//
 +    	// TODO : this will be replaced with fully-asynchronized way later so that we don't need
 +    	// to wait here. The reason we do it synchronized here is that callers of advanceStart is expecting
 +    	// synchronized semantics
-     	// 
++    	//
 +    	//
 +    	_jobMgr.waitAndCheck(
-     		new String[] { TopicConstants.VM_POWER_STATE, TopicConstants.JOB_STATE }, 
++    		new String[] { TopicConstants.VM_POWER_STATE, TopicConstants.JOB_STATE },
 +    		3000L, 600000L, new Predicate() {
 +
 +				@Override
 +				public boolean checkCondition() {
 +					VMInstanceVO instance = _vmDao.findById(vm.getId());
 +					if(instance.getPowerState() == VirtualMachine.PowerState.PowerOff)
 +						return true;
 +			
 +					VmWorkJobVO workJob = _workJobDao.findById(jobId);
 +					if(workJob.getStatus() != AsyncJobConstants.STATUS_IN_PROGRESS)
 +						return true;
 +					
 +					return false;
 +				}
 +    		});
 +    	
 +    	try {
 +    		AsyncJobExecutionContext.getCurrentExecutionContext().disjoinJob(jobId);
 +    	} catch(Exception e) {
 +    		s_logger.error("Unexpected exception", e);
 +    		return false;
 +    	}
 +    	return true;
 +    }
  
      @Override
 -    public <T extends VMInstanceVO> boolean advanceStop(T vm, boolean forced, User user, Account account) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
 -        State state = vm.getState();
 -        if (state == State.Stopped) {
 -            if (s_logger.isDebugEnabled()) {
 -                s_logger.debug("VM is already stopped: " + vm);
 -            }
 -            return true;
 -        }
 +    public <T extends VMInstanceVO> boolean processVmStopWork(T vm, boolean forced, User user, Account account) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
 +        VmWorkJobVO work = _workJobDao.findById(AsyncJobExecutionContext.getCurrentExecutionContext().getJob().getId());
  
 -        if (state == State.Destroyed || state == State.Expunging || state == State.Error) {
 -            if (s_logger.isDebugEnabled()) {
 -                s_logger.debug("Stopped called on " + vm + " but the state is " + state);
 -            }
 -            return true;
 -        }
 -        // grab outstanding work item if any
 -        ItWorkVO work = _workDao.findByOutstandingWork(vm.getId(), vm.getState());
 -        if (work != null) {
 -            if (s_logger.isDebugEnabled()) {
 -                s_logger.debug("Found an outstanding work item for this vm " + vm + " with state:" + vm.getState() + ", work id:" + work.getId());
 -            }
 -        }
          Long hostId = vm.getHostId();
          if (hostId == null) {
              if (!forced) {
@@@ -1277,7 -1198,7 +1365,7 @@@
  
          try {
              if (vm.getHypervisorType() != HypervisorType.BareMetal) {
--                this.volumeMgr.release(profile);
++                volumeMgr.release(profile);
                  s_logger.debug("Successfully released storage resources for the vm " + vm);
              }
          } catch (Exception e) {
@@@ -1299,174 -1221,6 +1387,176 @@@
          }
      }
  
- /*    
-     @Override
-     public <T extends VMInstanceVO> boolean advanceStop(T vm, boolean forced, User user, Account account) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
-         State state = vm.getState();
-         if (state == State.Stopped) {
-             if (s_logger.isDebugEnabled()) {
-                 s_logger.debug("VM is already stopped: " + vm);
++    /*
++        @Override
++        public <T extends VMInstanceVO> boolean advanceStop(T vm, boolean forced, User user, Account account) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
++            State state = vm.getState();
++            if (state == State.Stopped) {
++                if (s_logger.isDebugEnabled()) {
++                    s_logger.debug("VM is already stopped: " + vm);
++                }
++                return true;
 +            }
-             return true;
-         }
 +
-         if (state == State.Destroyed || state == State.Expunging || state == State.Error) {
-             if (s_logger.isDebugEnabled()) {
-                 s_logger.debug("Stopped called on " + vm + " but the state is " + state);
-             }
-             return true;
-         }
-         // grab outstanding work item if any
-         ItWorkVO work = _workDao.findByOutstandingWork(vm.getId(), vm.getState());
-         if (work != null) {
-             if (s_logger.isDebugEnabled()) {
-                 s_logger.debug("Found an outstanding work item for this vm " + vm + " with state:" + vm.getState() + ", work id:" + work.getId());
-             }
-         }
-         Long hostId = vm.getHostId();
-         if (hostId == null) {
-             if (!forced) {
++            if (state == State.Destroyed || state == State.Expunging || state == State.Error) {
 +                if (s_logger.isDebugEnabled()) {
-                     s_logger.debug("HostId is null but this is not a forced stop, cannot stop vm " + vm + " with state:" + vm.getState());
++                    s_logger.debug("Stopped called on " + vm + " but the state is " + state);
 +                }
-                 return false;
-             }
-             try {
-                 stateTransitTo(vm, Event.AgentReportStopped, null, null);
-             } catch (NoTransitionException e) {
-                 s_logger.warn(e.getMessage());
++                return true;
 +            }
-             // mark outstanding work item if any as done
++            // grab outstanding work item if any
++            VmWorkJobVO work = _workDao.findByOutstandingWork(vm.getId(), vm.getState());
 +            if (work != null) {
 +                if (s_logger.isDebugEnabled()) {
-                     s_logger.debug("Updating work item to Done, id:" + work.getId());
++                    s_logger.debug("Found an outstanding work item for this vm " + vm + " with state:" + vm.getState() + ", work id:" + work.getId());
 +                }
-                 work.setStep(Step.Done);
-                 _workDao.update(work.getId(), work);
-             }
-             return true;
-         }
- 
-         VirtualMachineGuru<T> vmGuru = getVmGuru(vm);
-         VirtualMachineProfile<T> profile = new VirtualMachineProfileImpl<T>(vm);
- 
-         try {
-             if (!stateTransitTo(vm, Event.StopRequested, vm.getHostId())) {
-                 throw new ConcurrentOperationException("VM is being operated on.");
-             }
-         } catch (NoTransitionException e1) {
-             if (!forced) {
-                 throw new CloudRuntimeException("We cannot stop " + vm + " when it is in state " + vm.getState());
-             }
-             boolean doCleanup = false;
-             if (s_logger.isDebugEnabled()) {
-                 s_logger.debug("Unable to transition the state but we're moving on because it's forced stop");
 +            }
-             if (state == State.Starting || state == State.Migrating) {
++            Long hostId = vm.getHostId();
++            if (hostId == null) {
++                if (!forced) {
++                    if (s_logger.isDebugEnabled()) {
++                        s_logger.debug("HostId is null but this is not a forced stop, cannot stop vm " + vm + " with state:" + vm.getState());
++                    }
++                    return false;
++                }
++                try {
++                    stateTransitTo(vm, Event.AgentReportStopped, null, null);
++                } catch (NoTransitionException e) {
++                    s_logger.warn(e.getMessage());
++                }
++                // mark outstanding work item if any as done
 +                if (work != null) {
-                     doCleanup = true;
-                 } else {
 +                    if (s_logger.isDebugEnabled()) {
-                         s_logger.debug("Unable to cleanup VM: " + vm + " ,since outstanding work item is not found");
++                        s_logger.debug("Updating work item to Done, id:" + work.getId());
 +                    }
-                     throw new CloudRuntimeException("Work item not found, We cannot stop " + vm + " when it is in state " + vm.getState());
++                    work.setStep(Step.Done);
++                    _workDao.update(work.getId(), work);
 +                }
-             } else if (state == State.Stopping) {
-                 doCleanup = true;
++                return true;
 +            }
 +
-             if (doCleanup) {
-                 if (cleanup(vmGuru, new VirtualMachineProfileImpl<T>(vm), work, Event.StopRequested, forced, user, account)) {
-                     try {
++            VirtualMachineGuru<T> vmGuru = getVmGuru(vm);
++            VirtualMachineProfile<T> profile = new VirtualMachineProfileImpl<T>(vm);
++
++            try {
++                if (!stateTransitTo(vm, Event.StopRequested, vm.getHostId())) {
++                    throw new ConcurrentOperationException("VM is being operated on.");
++                }
++            } catch (NoTransitionException e1) {
++                if (!forced) {
++                    throw new CloudRuntimeException("We cannot stop " + vm + " when it is in state " + vm.getState());
++                }
++                boolean doCleanup = false;
++                if (s_logger.isDebugEnabled()) {
++                    s_logger.debug("Unable to transition the state but we're moving on because it's forced stop");
++                }
++                if (state == State.Starting || state == State.Migrating) {
++                    if (work != null) {
++                        doCleanup = true;
++                    } else {
 +                        if (s_logger.isDebugEnabled()) {
-                             s_logger.debug("Updating work item to Done, id:" + work.getId());
++                            s_logger.debug("Unable to cleanup VM: " + vm + " ,since outstanding work item is not found");
 +                        }
-                         return changeState(vm, Event.AgentReportStopped, null, work, Step.Done);
-                     } catch (NoTransitionException e) {
-                         s_logger.warn("Unable to cleanup " + vm);
-                         return false;
++                        throw new CloudRuntimeException("Work item not found, We cannot stop " + vm + " when it is in state " + vm.getState());
 +                    }
-                 } else {
-                     if (s_logger.isDebugEnabled()) {
-                         s_logger.debug("Failed to cleanup VM: " + vm);
++                } else if (state == State.Stopping) {
++                    doCleanup = true;
++                }
++
++                if (doCleanup) {
++                    if (cleanup(vmGuru, new VirtualMachineProfileImpl<T>(vm), work, Event.StopRequested, forced, user, account)) {
++                        try {
++                            if (s_logger.isDebugEnabled()) {
++                                s_logger.debug("Updating work item to Done, id:" + work.getId());
++                            }
++                            return changeState(vm, Event.AgentReportStopped, null, work, Step.Done);
++                        } catch (NoTransitionException e) {
++                            s_logger.warn("Unable to cleanup " + vm);
++                            return false;
++                        }
++                    } else {
++                        if (s_logger.isDebugEnabled()) {
++                            s_logger.debug("Failed to cleanup VM: " + vm);
++                        }
++                        throw new CloudRuntimeException("Failed to cleanup " + vm + " , current state " + vm.getState());
 +                    }
-                     throw new CloudRuntimeException("Failed to cleanup " + vm + " , current state " + vm.getState());
 +                }
 +            }
-         }
- 
-         if (vm.getState() != State.Stopping) {
-             throw new CloudRuntimeException("We cannot proceed with stop VM " + vm + " since it is not in 'Stopping' state, current state: " + vm.getState());
-         }
 +
-         vmGuru.prepareStop(profile);
-         
-         StopCommand stop = new StopCommand(vm);
-         boolean stopped = false;
-         StopAnswer answer = null;
-         try {
-             answer = (StopAnswer) _agentMgr.send(vm.getHostId(), stop);
-             stopped = answer.getResult();
-             if (!stopped) {
-                 throw new CloudRuntimeException("Unable to stop the virtual machine due to " + answer.getDetails());
++            if (vm.getState() != State.Stopping) {
++                throw new CloudRuntimeException("We cannot proceed with stop VM " + vm + " since it is not in 'Stopping' state, current state: " + vm.getState());
 +            }
-             vmGuru.finalizeStop(profile, answer);
 +
-         } catch (AgentUnavailableException e) {
-         } catch (OperationTimedoutException e) {
-         } finally {
-             if (!stopped) {
-                 if (!forced) {
-                     s_logger.warn("Unable to stop vm " + vm);
-                     try {
-                         stateTransitTo(vm, Event.OperationFailed, vm.getHostId());
-                     } catch (NoTransitionException e) {
-                         s_logger.warn("Unable to transition the state " + vm);
++            vmGuru.prepareStop(profile);
++            
++            StopCommand stop = new StopCommand(vm);
++            boolean stopped = false;
++            StopAnswer answer = null;
++            try {
++                answer = (StopAnswer) _agentMgr.send(vm.getHostId(), stop);
++                stopped = answer.getResult();
++                if (!stopped) {
++                    throw new CloudRuntimeException("Unable to stop the virtual machine due to " + answer.getDetails());
++                }
++                vmGuru.finalizeStop(profile, answer);
++
++            } catch (AgentUnavailableException e) {
++                s_logger.warn("Unable to stop vm, agent unavailable: " + e.toString());
++            } catch (OperationTimedoutException e) {
++                s_logger.warn("Unable to stop vm, operation timed out: " + e.toString());
++            } finally {
++                if (!stopped) {
++                    if (!forced) {
++                        s_logger.warn("Unable to stop vm " + vm);
++                        try {
++                            stateTransitTo(vm, Event.OperationFailed, vm.getHostId());
++                        } catch (NoTransitionException e) {
++                            s_logger.warn("Unable to transition the state " + vm);
++                        }
++                        return false;
++                    } else {
++                        s_logger.warn("Unable to actually stop " + vm + " but continue with release because it's a force stop");
++                        vmGuru.finalizeStop(profile, answer);
 +                    }
-                     return false;
-                 } else {
-                     s_logger.warn("Unable to actually stop " + vm + " but continue with release because it's a force stop");
-                     vmGuru.finalizeStop(profile, answer);
 +                }
 +            }
-         }
 +
-         if (s_logger.isDebugEnabled()) {
-             s_logger.debug(vm + " is stopped on the host.  Proceeding to release resource held.");
-         }
++            if (s_logger.isDebugEnabled()) {
++                s_logger.debug(vm + " is stopped on the host.  Proceeding to release resource held.");
++            }
 +
-         try {
-             _networkMgr.release(profile, forced);
-             s_logger.debug("Successfully released network resources for the vm " + vm);
-         } catch (Exception e) {
-             s_logger.warn("Unable to release some network resources.", e);
-         }
- 
-         try {
-             if (vm.getHypervisorType() != HypervisorType.BareMetal) {
-                 this.volumeMgr.release(profile);
-                 s_logger.debug("Successfully released storage resources for the vm " + vm);
++            try {
++                _networkMgr.release(profile, forced);
++                s_logger.debug("Successfully released network resources for the vm " + vm);
++            } catch (Exception e) {
++                s_logger.warn("Unable to release some network resources.", e);
 +            }
-         } catch (Exception e) {
-             s_logger.warn("Unable to release storage resources.", e);
-         }
 +
-         try {
-             if (work != null) {
-                 if (s_logger.isDebugEnabled()) {
-                     s_logger.debug("Updating the outstanding work item to Done, id:" + work.getId());
++            try {
++                if (vm.getHypervisorType() != HypervisorType.BareMetal) {
++                    this.volumeMgr.release(profile);
++                    s_logger.debug("Successfully released storage resources for the vm " + vm);
 +                }
-                 work.setStep(Step.Done);
-                 _workDao.update(work.getId(), work);
++            } catch (Exception e) {
++                s_logger.warn("Unable to release storage resources.", e);
 +            }
 +
-             return stateTransitTo(vm, Event.OperationSucceeded, null, null);
-         } catch (NoTransitionException e) {
-             s_logger.warn(e.getMessage());
-             return false;
++            try {
++                if (work != null) {
++                    if (s_logger.isDebugEnabled()) {
++                        s_logger.debug("Updating the outstanding work item to Done, id:" + work.getId());
++                    }
++                    work.setStep(Step.Done);
++                    _workDao.update(work.getId(), work);
++                }
++
++                return stateTransitTo(vm, Event.OperationSucceeded, null);
++            } catch (NoTransitionException e) {
++                s_logger.warn(e.getMessage());
++                return false;
++            }
 +        }
-     }
- */
++    */
      private void setStateMachine() {
          _stateMachine = VirtualMachine.State.getStateMachine();
      }
@@@ -1478,16 -1232,12 +1568,16 @@@
  
      @Override
      public boolean stateTransitTo(VMInstanceVO vm, VirtualMachine.Event e, Long hostId) throws NoTransitionException {
 +
 +/*
 + *  TODO ???
-  *      	
++ * 
          // if there are active vm snapshots task, state change is not allowed
 -        if(_vmSnapshotMgr.hasActiveVMSnapshotTasks(vm.getId())){
 +        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;
          }
- */        
 -
++*/
          State oldState = vm.getState();
          if (oldState == State.Starting) {
              if (e == Event.OperationSucceeded) {
@@@ -1567,7 -1317,7 +1657,7 @@@
          VirtualMachineProfile<VMInstanceVO> profile = new VirtualMachineProfileImpl<VMInstanceVO>(vm);
          boolean migrationResult = false;
          try {
--            migrationResult = this.volumeMgr.storageMigration(profile, destPool);
++            migrationResult = volumeMgr.storageMigration(profile, destPool);
  
              if (migrationResult) {
                  //if the vm is migrated to different pod in basic mode, need to reallocate ip
@@@ -1610,40 -1360,267 +1700,271 @@@
  
      @Override
      public <T extends VMInstanceVO> T migrate(T vm, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException,
 -    VirtualMachineMigrationException {
 +    	VirtualMachineMigrationException {
          s_logger.info("Migrating " + vm + " to " + dest);
 +        
 +        return vm;
 +        
- /*
-         long dstHostId = dest.getHost().getId();
-         Host fromHost = _hostDao.findById(srcHostId);
-         if (fromHost == null) {
-             s_logger.info("Unable to find the host to migrate from: " + srcHostId);
-             throw new CloudRuntimeException("Unable to find the host to migrate from: " + srcHostId);
++        /*
++                long dstHostId = dest.getHost().getId();
++                Host fromHost = _hostDao.findById(srcHostId);
++                if (fromHost == null) {
++                    s_logger.info("Unable to find the host to migrate from: " + srcHostId);
++                    throw new CloudRuntimeException("Unable to find the host to migrate from: " + srcHostId);
++                }
+ 
 -        long dstHostId = dest.getHost().getId();
 -        Host fromHost = _hostDao.findById(srcHostId);
 -        if (fromHost == null) {
 -            s_logger.info("Unable to find the host to migrate from: " + srcHostId);
 -            throw new CloudRuntimeException("Unable to find the host to migrate from: " + srcHostId);
 -        }
++                if (fromHost.getClusterId().longValue() != dest.getCluster().getId()) {
++                    s_logger.info("Source and destination host are not in same cluster, unable to migrate to host: " + dest.getHost().getId());
++                    throw new CloudRuntimeException("Source and destination host are not in same cluster, unable to migrate to host: " + dest.getHost().getId());
++                }
+ 
 -        if (fromHost.getClusterId().longValue() != dest.getCluster().getId()) {
 -            s_logger.info("Source and destination host are not in same cluster, unable to migrate to host: " + dest.getHost().getId());
 -            throw new CloudRuntimeException("Source and destination host are not in same cluster, unable to migrate to host: " + dest.getHost().getId());
 -        }
++                VirtualMachineGuru<T> vmGuru = getVmGuru(vm);
+ 
 -        VirtualMachineGuru<T> vmGuru = getVmGuru(vm);
++                long vmId = vm.getId();
++                vm = vmGuru.findById(vmId);
++                if (vm == null) {
++                    if (s_logger.isDebugEnabled()) {
++                        s_logger.debug("Unable to find the vm " + vm);
++                    }
++                    throw new ManagementServerException("Unable to find a virtual machine with id " + vmId);
++                }
+ 
 -        long vmId = vm.getId();
 -        vm = vmGuru.findById(vmId);
 -        if (vm == null) {
 -            if (s_logger.isDebugEnabled()) {
 -                s_logger.debug("Unable to find the vm " + vm);
 -            }
 -            throw new ManagementServerException("Unable to find a virtual machine with id " + vmId);
 -        }
 -
 -        if (vm.getState() != State.Running) {
 -            if (s_logger.isDebugEnabled()) {
 -                s_logger.debug("VM is not Running, unable to migrate the vm " + vm);
 -            }
 -            throw new VirtualMachineMigrationException("VM is not Running, unable to migrate the vm currently " + vm + " , current state: " + vm.getState().toString());
 -        }
++                if (vm.getState() != State.Running) {
++                    if (s_logger.isDebugEnabled()) {
++                        s_logger.debug("VM is not Running, unable to migrate the vm " + vm);
++                    }
++                    throw new VirtualMachineMigrationException("VM is not Running, unable to migrate the vm currently " + vm + " , current state: " + vm.getState().toString());
++                }
+ 
 -        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;
 -        }
++                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;
++                }
+ 
 -        VirtualMachineProfile<VMInstanceVO> profile = new VirtualMachineProfileImpl<VMInstanceVO>(vm);
 -        _networkMgr.prepareNicForMigration(profile, dest);
 -        this.volumeMgr.prepareForMigration(profile, dest);
++                VirtualMachineProfile<VMInstanceVO> profile = new VirtualMachineProfileImpl<VMInstanceVO>(vm);
++                _networkMgr.prepareNicForMigration(profile, dest);
++                this.volumeMgr.prepareForMigration(profile, dest);
+ 
 -        VirtualMachineTO to = toVmTO(profile);
 -        PrepareForMigrationCommand pfmc = new PrepareForMigrationCommand(to);
++                VirtualMachineTO to = toVmTO(profile);
++                PrepareForMigrationCommand pfmc = new PrepareForMigrationCommand(to);
+ 
 -        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(dstHostId);
 -        work = _workDao.persist(work);
++                VmWorkJobVO work = new VmWorkJobVO(UUID.randomUUID().toString(), _nodeId, State.Migrating, vm.getType(), vm.getId());
++                work.setStep(Step.Prepare);
++                work.setResourceType(VmWorkJobVO.ResourceType.Host);
++                work.setResourceId(dstHostId);
++                work = _workDao.persist(work);
+ 
 -        PrepareForMigrationAnswer pfma = null;
 -        try {
 -            pfma = (PrepareForMigrationAnswer) _agentMgr.send(dstHostId, pfmc);
 -            if (!pfma.getResult()) {
 -                String msg = "Unable to prepare for migration due to " + pfma.getDetails();
 -                pfma = null;
 -                throw new AgentUnavailableException(msg, dstHostId);
 -            }
 -        } catch (OperationTimedoutException e1) {
 -            throw new AgentUnavailableException("Operation timed out", dstHostId);
 -        } finally {
 -            if (pfma == null) {
 -                work.setStep(Step.Done);
 -                _workDao.update(work.getId(), work);
 -            }
 -        }
++                PrepareForMigrationAnswer pfma = null;
++                try {
++                    pfma = (PrepareForMigrationAnswer) _agentMgr.send(dstHostId, pfmc);
++                    if (!pfma.getResult()) {
++                        String msg = "Unable to prepare for migration due to " + pfma.getDetails();
++                        pfma = null;
++                        throw new AgentUnavailableException(msg, dstHostId);
++                    }
++                } catch (OperationTimedoutException e1) {
++                    throw new AgentUnavailableException("Operation timed out", dstHostId);
++                } finally {
++                    if (pfma == null) {
++                        work.setStep(Step.Done);
++                        _workDao.update(work.getId(), work);
++                    }
++                }
+ 
 -        vm.setLastHostId(srcHostId);
 -        try {
 -            if (vm == null || vm.getHostId() == null || vm.getHostId() != srcHostId || !changeState(vm, Event.MigrationRequested, dstHostId, work, Step.Migrating)) {
 -                s_logger.info("Migration cancelled because state has changed: " + vm);
 -                throw new ConcurrentOperationException("Migration cancelled because state has changed: " + vm);
 -            }
 -        } catch (NoTransitionException e1) {
 -            s_logger.info("Migration cancelled because " + e1.getMessage());
 -            throw new ConcurrentOperationException("Migration cancelled because " + e1.getMessage());
 -        }
++                vm.setLastHostId(srcHostId);
++                try {
++                    if (vm == null || vm.getHostId() == null || vm.getHostId() != srcHostId || !changeState(vm, Event.MigrationRequested, dstHostId, work, Step.Migrating)) {
++                        s_logger.info("Migration cancelled because state has changed: " + vm);
++                        throw new ConcurrentOperationException("Migration cancelled because state has changed: " + vm);
++                    }
++                } catch (NoTransitionException e1) {
++                    s_logger.info("Migration cancelled because " + e1.getMessage());
++                    throw new ConcurrentOperationException("Migration cancelled because " + e1.getMessage());
++                }
+ 
 -        boolean migrated = false;
 -        try {
 -            boolean isWindows = _guestOsCategoryDao.findById(_guestOsDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
 -            MigrateCommand mc = new MigrateCommand(vm.getInstanceName(), dest.getHost().getPrivateIpAddress(), isWindows);
 -            mc.setHostGuid(dest.getHost().getGuid());
++                boolean migrated = false;
++                try {
++                    boolean isWindows = _guestOsCategoryDao.findById(_guestOsDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
++                    MigrateCommand mc = new MigrateCommand(vm.getInstanceName(), dest.getHost().getPrivateIpAddress(), isWindows);
++                    mc.setHostGuid(dest.getHost().getGuid());
+ 
 -            try {
 -                MigrateAnswer ma = (MigrateAnswer) _agentMgr.send(vm.getLastHostId(), mc);
 -                if (!ma.getResult()) {
 -                    s_logger.error("Unable to migrate due to " + ma.getDetails());
 -                    return null;
 -                }
 -            } catch (OperationTimedoutException e) {
 -                if (e.isActive()) {
 -                    s_logger.warn("Active migration command so scheduling a restart for " + vm);
 -                    _haMgr.scheduleRestart(vm, true);
 -                }
 -                throw new AgentUnavailableException("Operation timed out on migrating " + vm, dstHostId);
 -            }
++                    try {
++                        MigrateAnswer ma = (MigrateAnswer) _agentMgr.send(vm.getLastHostId(), mc);
++                        if (!ma.getResult()) {
++                            s_logger.error("Unable to migrate due to " + ma.getDetails());
++                            return null;
++                        }
++                    } catch (OperationTimedoutException e) {
++                        if (e.isActive()) {
++                            s_logger.warn("Active migration command so scheduling a restart for " + vm);
++                            _haMgr.scheduleRestart(vm, true);
++                        }
++                        throw new AgentUnavailableException("Operation timed out on migrating " + vm, dstHostId);
++                    }
+ 
 -            try {
 -                if (!changeState(vm, VirtualMachine.Event.OperationSucceeded, dstHostId, work, Step.Started)) {
 -                    throw new ConcurrentOperationException("Unable to change the state for " + vm);
 -                }
 -            } catch (NoTransitionException e1) {
 -                throw new ConcurrentOperationException("Unable to change state due to " + e1.getMessage());
 -            }
++                    try {
++                        if (!changeState(vm, VirtualMachine.Event.OperationSucceeded, dstHostId, work, Step.Started)) {
++                            throw new ConcurrentOperationException("Unable to change the state for " + vm);
++                        }
++                    } catch (NoTransitionException e1) {
++                        throw new ConcurrentOperationException("Unable to change state due to " + e1.getMessage());
++                    }
+ 
 -            try {
 -                if (!checkVmOnHost(vm, dstHostId)) {
 -                    s_logger.error("Unable to complete migration for " + vm);
+                     try {
 -                        _agentMgr.send(srcHostId, new Commands(cleanup(vm)), null);
 -                    } catch (AgentUnavailableException e) {
 -                        s_logger.error("AgentUnavailableException while cleanup on source host: " + srcHostId);
++                        if (!checkVmOnHost(vm, dstHostId)) {
++                            s_logger.error("Unable to complete migration for " + vm);
++                            try {
++                                _agentMgr.send(srcHostId, new Commands(cleanup(vm)), 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) {
+                     }
 -                    cleanup(vmGuru, new VirtualMachineProfileImpl<T>(vm), work, Event.AgentReportStopped, true, _accountMgr.getSystemUser(), _accountMgr.getSystemAccount());
 -                    return null;
 -                }
 -            } catch (OperationTimedoutException e) {
 -            }
+ 
 -            migrated = true;
 -            return vm;
 -        } finally {
 -            if (!migrated) {
 -                s_logger.info("Migration was unsuccessful.  Cleaning up: " + vm);
++                    migrated = true;
++                    return vm;
++                } finally {
++                    if (!migrated) {
++                        s_logger.info("Migration was unsuccessful.  Cleaning up: " + vm);
+ 
 -                _alertMgr.sendAlert(alertType, fromHost.getDataCenterId(), fromHost.getPodId(), "Unable to migrate vm " + vm.getInstanceName() + " from host " + fromHost.getName() + " in zone "
 -                        + dest.getDataCenter().getName() + " and pod " + dest.getPod().getName(), "Migrate Command failed.  Please check logs.");
 -                try {
 -                    _agentMgr.send(dstHostId, new Commands(cleanup(vm)), null);
 -                } catch (AgentUnavailableException ae) {
 -                    s_logger.info("Looks like the destination Host is unavailable for cleanup");
 -                }
++                        _alertMgr.sendAlert(alertType, fromHost.getDataCenterId(), fromHost.getPodId(), "Unable to migrate vm " + vm.getInstanceName() + " from host " + fromHost.getName() + " in zone "
++                                + dest.getDataCenter().getName() + " and pod " + dest.getPod().getName(), "Migrate Command failed.  Please check logs.");
++                        try {
++                            _agentMgr.send(dstHostId, new Commands(cleanup(vm)), null);
++                        } catch (AgentUnavailableException ae) {
++                            s_logger.info("Looks like the destination Host is unavailable for cleanup");
++                        }
+ 
 -                try {
 -                    stateTransitTo(vm, Event.OperationFailed, srcHostId);
 -                } catch (NoTransitionException e) {
 -                    s_logger.warn(e.getMessage());
 -                }
 -            }
++                        try {
++                            stateTransitTo(vm, Event.OperationFailed, srcHostId);
++                        } catch (NoTransitionException e) {
++                            s_logger.warn(e.getMessage());
++                        }
++                    }
+ 
 -            work.setStep(Step.Done);
 -            _workDao.update(work.getId(), work);
 -        }
++                    work.setStep(Step.Done);
++                    _workDao.update(work.getId(), work);
++                }
++        */
+     }
+ 
+     private Map<VolumeVO, StoragePoolVO> getPoolListForVolumesForMigration(VirtualMachineProfile<VMInstanceVO> profile,
+             Host host, Map<VolumeVO, StoragePoolVO> volumeToPool) {
+         List<VolumeVO> allVolumes = _volsDao.findUsableVolumesForInstance(profile.getId());
+         for (VolumeVO volume : allVolumes) {
+             StoragePoolVO pool = volumeToPool.get(volume);
+             DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
+             StoragePoolVO currentPool = _storagePoolDao.findById(volume.getPoolId());
+             if (pool != null) {
+                 // Check if pool is accessible from the destination host and disk offering with which the volume was
+                 // created is compliant with the pool type.
+                 if (_poolHostDao.findByPoolHost(pool.getId(), host.getId()) == null ||
+                         pool.isLocal() != diskOffering.getUseLocalStorage()) {
+                     // Cannot find a pool for the volume. Throw an exception.
+                     throw new CloudRuntimeException("Cannot migrate volume " + volume + " to storage pool " + pool +
+                             " while migrating vm to host " + host + ". Either the pool is not accessible from the " +
+                             "host or because of the offering with which the volume is created it cannot be placed on " +
+                             "the given pool.");
+                 } else if (pool.getId() == currentPool.getId()){
+                     // If the pool to migrate too is the same as current pool, remove the volume from the list of
+                     // volumes to be migrated.
+                     volumeToPool.remove(volume);
+                 }
+             } else {
+                 // Find a suitable pool for the volume. Call the storage pool allocator to find the list of pools.
+                 DiskProfile diskProfile = new DiskProfile(volume, diskOffering, profile.getHypervisorType());
+                 DataCenterDeployment plan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(),
+                         host.getClusterId(), host.getId(), null, null);
+                 ExcludeList avoid = new ExcludeList();
+                 boolean currentPoolAvailable = false;
+ 
+                 for (StoragePoolAllocator allocator : _storagePoolAllocators) {
+                     List<StoragePool> poolList = allocator.allocateToPool(diskProfile, profile, plan, avoid,
+                             StoragePoolAllocator.RETURN_UPTO_ALL);
+                     if (poolList != null && !poolList.isEmpty()) {
+                         // Volume needs to be migrated. Pick the first pool from the list. Add a mapping to migrate the
+                         // volume to a pool only if it is required; that is the current pool on which the volume resides
+                         // is not available on the destination host.
+                         if (poolList.contains(currentPool)) {
+                             currentPoolAvailable = true;
+                         } else {
+                             volumeToPool.put(volume, _storagePoolDao.findByUuid(poolList.get(0).getUuid()));
+                         }
+ 
+                         break;
+                     }
+                 }
+ 
+                 if (!currentPoolAvailable && !volumeToPool.containsKey(volume)) {
+                     // Cannot find a pool for the volume. Throw an exception.
+                     throw new CloudRuntimeException("Cannot find a storage pool which is available for volume " +
+                             volume + " while migrating virtual machine " + profile.getVirtualMachine() + " to host " +
+                             host);
+                 }
+             }
+         }
+ 
+         return volumeToPool;
+     }
+ 
 -    private <T extends VMInstanceVO> void moveVmToMigratingState(T vm, Long hostId, ItWorkVO work)
++    private <T extends VMInstanceVO> void moveVmToMigratingState(T vm, Long hostId, VmWorkJobVO work)
+             throws ConcurrentOperationException {
+         // Put the vm in migrating state.
+         try {
+             if (!changeState(vm, Event.MigrationRequested, hostId, work, Step.Migrating)) {
+                 s_logger.info("Migration cancelled because state has changed: " + vm);
+                 throw new ConcurrentOperationException("Migration cancelled because state has changed: " + vm);
+             }
+         } catch (NoTransitionException e) {
+             s_logger.info("Migration cancelled because " + e.getMessage());
+             throw new ConcurrentOperationException("Migration cancelled because " + e.getMessage());
          }
+     }
  
-         if (fromHost.getClusterId().longValue() != dest.getCluster().getId()) {
-             s_logger.info("Source and destination host are not in same cluster, unable to migrate to host: " + dest.getHost().getId());
-             throw new CloudRuntimeException("Source and destination host are not in same cluster, unable to migrate to host: " + dest.getHost().getId());
 -    private <T extends VMInstanceVO> void moveVmOutofMigratingStateOnSuccess(T vm, Long hostId, ItWorkVO work)
++    private <T extends VMInstanceVO> void moveVmOutofMigratingStateOnSuccess(T vm, Long hostId, VmWorkJobVO work)
+             throws ConcurrentOperationException {
+         // Put the vm in running state.
+         try {
+             if (!changeState(vm, Event.OperationSucceeded, hostId, work, Step.Started)) {
+                 s_logger.error("Unable to change the state for " + vm);
+                 throw new ConcurrentOperationException("Unable to change the state for " + vm);
+             }
+         } catch (NoTransitionException e) {
+             s_logger.error("Unable to change state due to " + e.getMessage());
+             throw new ConcurrentOperationException("Unable to change state due to " + e.getMessage());
          }
+     }
+ 
+     @Override
+     public <T extends VMInstanceVO> T migrateWithStorage(T vm, long srcHostId, long destHostId,
+             Map<VolumeVO, StoragePoolVO> volumeToPool) throws ResourceUnavailableException, ConcurrentOperationException,
+             ManagementServerException, VirtualMachineMigrationException {
  
+         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);
-         if (vm == null) {
-             if (s_logger.isDebugEnabled()) {
-                 s_logger.debug("Unable to find the vm " + vm);
-             }
-             throw new ManagementServerException("Unable to find a virtual machine with id " + vmId);
-         }
+         VirtualMachineProfile<VMInstanceVO> profile = new VirtualMachineProfileImpl<VMInstanceVO>(vm);
+         volumeToPool = getPoolListForVolumesForMigration(profile, destHost, volumeToPool);
  
-         if (vm.getState() != State.Running) {
-             if (s_logger.isDebugEnabled()) {
-                 s_logger.debug("VM is not Running, unable to migrate the vm " + vm);
-             }
-             throw new VirtualMachineMigrationException("VM is not Running, unable to migrate the vm currently " + vm + " , current state: " + vm.getState().toString());
+         // 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.");
          }
  
          short alertType = AlertManager.ALERT_TYPE_USERVM_MIGRATE;
@@@ -1653,80 -1630,34 +1974,35 @@@
              alertType = AlertManager.ALERT_TYPE_CONSOLE_PROXY_MIGRATE;
          }
  
-         VirtualMachineProfile<VMInstanceVO> profile = new VirtualMachineProfileImpl<VMInstanceVO>(vm);
-         _networkMgr.prepareNicForMigration(profile, dest);
-         this.volumeMgr.prepareForMigration(profile, dest);
- 
-         VirtualMachineTO to = toVmTO(profile);
-         PrepareForMigrationCommand pfmc = new PrepareForMigrationCommand(to);
+         _networkMgr.prepareNicForMigration(profile, destination);
 -        this.volumeMgr.prepareForMigration(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(dstHostId);
-         work = _workDao.persist(work);
- 
-         PrepareForMigrationAnswer pfma = null;
-         try {
-             pfma = (PrepareForMigrationAnswer) _agentMgr.send(dstHostId, pfmc);
-             if (!pfma.getResult()) {
-                 String msg = "Unable to prepare for migration due to " + pfma.getDetails();
-                 pfma = null;
-                 throw new AgentUnavailableException(msg, dstHostId);
-             }
-         } catch (OperationTimedoutException e1) {
-             throw new AgentUnavailableException("Operation timed out", dstHostId);
-         } finally {
-             if (pfma == null) {
-                 work.setStep(Step.Done);
-                 _workDao.update(work.getId(), work);
-             }
-         }
 -        work.setResourceId(destHostId);
 -        work = _workDao.persist(work);
++        VmWorkJobVO work = new VmWorkJobVO();
++//        VmWorkJobVO work = new VmWorkJobVO(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);
-         try {
-             if (vm == null || vm.getHostId() == null || vm.getHostId() != srcHostId || !changeState(vm, Event.MigrationRequested, dstHostId, work, Step.Migrating)) {
-                 s_logger.info("Migration cancelled because state has changed: " + vm);
-                 throw new ConcurrentOperationException("Migration cancelled because state has changed: " + vm);
-             }
-         } catch (NoTransitionException e1) {
-             s_logger.info("Migration cancelled because " + e1.getMessage());
-             throw new ConcurrentOperationException("Migration cancelled because " + e1.getMessage());
-         }
+         moveVmToMigratingState(vm, destHostId, work);
  
          boolean migrated = false;
          try {
-             boolean isWindows = _guestOsCategoryDao.findById(_guestOsDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
-             MigrateCommand mc = new MigrateCommand(vm.getInstanceName(), dest.getHost().getPrivateIpAddress(), isWindows);
-             mc.setHostGuid(dest.getHost().getGuid());
+             // Migrate the vm and its volume.
 -            this.volumeMgr.migrateVolumes(vm, to, srcHost, destHost, volumeToPool);
++            volumeMgr.migrateVolumes(vm, to, srcHost, destHost, volumeToPool);
  
-             try {
-                 MigrateAnswer ma = (MigrateAnswer) _agentMgr.send(vm.getLastHostId(), mc);
-                 if (!ma.getResult()) {
-                     s_logger.error("Unable to migrate due to " + ma.getDetails());
-                     return null;
-                 }
-             } catch (OperationTimedoutException e) {
-                 if (e.isActive()) {
-                     s_logger.warn("Active migration command so scheduling a restart for " + vm);
-                     _haMgr.scheduleRestart(vm, true);
-                 }
-                 throw new AgentUnavailableException("Operation timed out on migrating " + vm, dstHostId);
-             }
+             // Put the vm back to running state.
+             moveVmOutofMigratingStateOnSuccess(vm, destHost.getId(), work);
  
              try {
-                 if (!changeState(vm, VirtualMachine.Event.OperationSucceeded, dstHostId, work, Step.Started)) {
-                     throw new ConcurrentOperationException("Unable to change the state for " + vm);
-                 }
-             } catch (NoTransitionException e1) {
-                 throw new ConcurrentOperationException("Unable to change state due to " + e1.getMessage());
-             }
- 
-             try {
-                 if (!checkVmOnHost(vm, dstHostId)) {
-                     s_logger.error("Unable to complete migration for " + vm);
+                 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)), null);
+                         _agentMgr.send(srcHostId, new Commands(cleanup(vm.getInstanceName())), null);
                      } catch (AgentUnavailableException e) {
                          s_logger.error("AgentUnavailableException while cleanup on source host: " + srcHostId);
                      }
@@@ -1758,9 -1688,8 +2033,8 @@@
              }
  
              work.setStep(Step.Done);
--            _workDao.update(work.getId(), work);
++            // FIXME  _workDao.update(work.getId(), work);
          }
- */        
      }
  
      @Override
@@@ -1768,47 -1697,45 +2042,47 @@@
          HypervisorGuru hvGuru = _hvGuruMgr.getGuru(profile.getVirtualMachine().getHypervisorType());
          VirtualMachineTO to = hvGuru.implement(profile);
          return to;
 -    }
 +    	}
  
      protected void cancelWorkItems(long nodeId) {
- /*    	
--        GlobalLock scanLock = GlobalLock.getInternLock("vmmgr.cancel.workitem");
++        /*
++                GlobalLock scanLock = GlobalLock.getInternLock("vmmgr.cancel.workitem");
  
--        try {
--            if (scanLock.lock(3)) {
                  try {
--                    List<ItWorkVO> works = _workDao.listWorkInProgressFor(nodeId);
--                    for (ItWorkVO work : works) {
--                        s_logger.info("Handling unfinished work item: " + work);
++                    if (scanLock.lock(3)) {
                          try {
--                            VMInstanceVO vm = _vmDao.findById(work.getInstanceId());
--                            if (vm != null) {
--                                if (work.getType() == State.Starting) {
--                                    _haMgr.scheduleRestart(vm, true);
--                                    work.setManagementServerId(_nodeId);
--                                    _workDao.update(work.getId(), work);
--                                } else if (work.getType() == State.Stopping) {
--                                    _haMgr.scheduleStop(vm, vm.getHostId(), WorkType.CheckStop);
--                                    work.setManagementServerId(_nodeId);
--                                    _workDao.update(work.getId(), work);
--                                } else if (work.getType() == State.Migrating) {
--                                    _haMgr.scheduleMigration(vm);
--                                    work.setStep(Step.Done);
--                                    _workDao.update(work.getId(), work);
++                            List<VmWorkJobVO> works = _workDao.listWorkInProgressFor(nodeId);
++                            for (VmWorkJobVO work : works) {
++                                s_logger.info("Handling unfinished work item: " + work);
++                                try {
++                                    VMInstanceVO vm = _vmDao.findById(work.getInstanceId());
++                                    if (vm != null) {
++                                        if (work.getType() == State.Starting) {
++                                            _haMgr.scheduleRestart(vm, true);
++                                            work.setManagementServerId(_nodeId);
++                                            _workDao.update(work.getId(), work);
++                                        } else if (work.getType() == State.Stopping) {
++                                            _haMgr.scheduleStop(vm, vm.getHostId(), WorkType.CheckStop);
++                                            work.setManagementServerId(_nodeId);
++                                            _workDao.update(work.getId(), work);
++                                        } else if (work.getType() == State.Migrating) {
++                                            _haMgr.scheduleMigration(vm);
++                                            work.setStep(Step.Done);
++                                            _workDao.update(work.getId(), work);
++                                        }
++                                    }
++                                } catch (Exception e) {
++                                    s_logger.error("Error while handling " + work, e);
                                  }
                              }
--                        } catch (Exception e) {
--                            s_logger.error("Error while handling " + work, e);
++                        } finally {
++                            scanLock.unlock();
                          }
                      }
                  } finally {
--                    scanLock.unlock();
++                    scanLock.releaseRef();
                  }
--            }
--        } finally {
--            scanLock.releaseRef();
--        }
- */        
++        */
      }
  
      @Override
@@@ -1836,25 -1763,23 +2110,23 @@@
  
          DeployDestination dest = null;
          while (true) {
-             for (DeploymentPlanner planner : _planners) {
-                 if (planner.canHandle(profile, plan, excludes)) {
-                     dest = planner.plan(profile, plan, excludes);
-                 } else {
-                     continue;
+ 
+             try {
+                 dest = _dpMgr.planDeployment(profile, plan, excludes);
+             } catch (AffinityConflictException e2) {
+                 s_logger.warn("Unable to create deployment, affinity rules associted to the VM conflict", e2);
+                 throw new CloudRuntimeException(
+                         "Unable to create deployment, affinity rules associted to the VM conflict");
 -            }
 +                }
  
 -            if (dest != null) {
 -                if (s_logger.isDebugEnabled()) {
 +                if (dest != null) {
 +                    if (s_logger.isDebugEnabled()) {
-                         s_logger.debug("Planner " + planner + " found " + dest + " for migrating to.");
-                     }
-                     break;
+                     s_logger.debug("Found destination " + dest + " for migrating to.");
                  }
+             } else {
                  if (s_logger.isDebugEnabled()) {
-                     s_logger.debug("Planner " + planner + " was unable to find anything.");
+                     s_logger.debug("Unable to find destination for migrating the vm " + profile);
                  }
-             }
- 
-             if (dest == null) {
                  throw new InsufficientServerCapacityException("Unable to find a server to migrate to.", host.getClusterId());
              }
  
@@@ -1899,21 -1823,11 +2171,21 @@@
          @Override
          public void run() {
              s_logger.trace("VM Operation Thread Running");
 +            
 +            try {
 +	            Date cutDate = DateUtil.currentGMTTime();
 +	            cutDate = new Date(cutDate.getTime() - 60000);
 +	            _workJobDao.expungeCompletedWorkJobs(cutDate);
 +            } catch(Throwable e) {
 +            	s_logger.error("Unexpected exception", e);
 +            }
- /*            
++/*
              try {
                  _workDao.cleanup(_cleanupWait);
              } catch (Exception e) {
                  s_logger.error("VM Operations failed due to ", e);
              }
- */            
++*/
          }
      }
  
@@@ -1987,8 -1901,8 +2259,8 @@@
      public Command cleanup(String vmName) {
          return new StopCommand(vmName);
      }
 -
 +/*
-     public Commands fullHostSync(final long hostId, StartupRoutingCommand startup) {  
+     public Commands fullHostSync(final long hostId, StartupRoutingCommand startup) {
          Commands commands = new Commands(OnError.Continue);
  
          Map<Long, AgentVmInfo> infos = convertToInfos(startup);
@@@ -2112,132 -2029,138 +2384,132 @@@
              }
          }
      }
 -
 +*/
  
      public void fullSync(final long clusterId, Map<String, Pair<String, State>> newStates) {
- /*    	
--        if (newStates==null)return;
--        Map<Long, AgentVmInfo> infos = convertToInfos(newStates);
--        Set<VMInstanceVO> set_vms = Collections.synchronizedSet(new HashSet<VMInstanceVO>());
--        set_vms.addAll(_vmDao.listByClusterId(clusterId));
--        set_vms.addAll(_vmDao.listLHByClusterId(clusterId));
--
--        for (VMInstanceVO vm : set_vms) {
--            AgentVmInfo info =  infos.remove(vm.getId());
--            VMInstanceVO castedVm = null;
-             
-             // sync VM Snapshots related transient states
-             List<VMSnapshotVO> vmSnapshotsInExpungingStates = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging, VMSnapshot.State.Cre

<TRUNCATED>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d4039743/server/test/com/cloud/vm/MockUserVmManagerImpl.java
----------------------------------------------------------------------