Merge VirtualMachineManagerImpl for sync changes
diff --git a/engine/api/src/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/com/cloud/vm/VirtualMachineManager.java
index 9c76236..75198f9 100644
--- a/engine/api/src/com/cloud/vm/VirtualMachineManager.java
+++ b/engine/api/src/com/cloud/vm/VirtualMachineManager.java
@@ -85,9 +85,9 @@
         DeploymentPlan plan,
         HypervisorType hyperType) throws InsufficientCapacityException;
 
-    void start(String vmUuid, Map<VirtualMachineProfile.Param, Object> params);
+    void easyStart(String vmUuid, Map<VirtualMachineProfile.Param, Object> params);
 
-    void start(String vmUuid, Map<VirtualMachineProfile.Param, Object> params, DeploymentPlan planToDeploy);
+    void easyStart(String vmUuid, Map<VirtualMachineProfile.Param, Object> params, DeploymentPlan planToDeploy);
 
     void stop(String vmUuid) throws ResourceUnavailableException;
 
diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
index 591be6c..26d890c 100755
--- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -35,6 +35,7 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 import javax.ejb.Local;
 import javax.inject.Inject;
@@ -53,9 +54,11 @@
 import org.apache.cloudstack.framework.config.Configurable;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.framework.jobs.AsyncJobManager;
+import org.apache.cloudstack.framework.jobs.Outcome;
 import org.apache.cloudstack.framework.jobs.dao.VmWorkJobDao;
 import org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO;
 import org.apache.cloudstack.framework.messagebus.MessageBus;
+import org.apache.cloudstack.framework.messagebus.MessageDispatcher;
 import org.apache.cloudstack.framework.messagebus.MessageHandler;
 import org.apache.cloudstack.jobs.JobInfo;
 import org.apache.cloudstack.managed.context.ManagedContextRunnable;
@@ -291,10 +294,17 @@
     @Inject
     DeploymentPlanningManager _dpMgr;
 
-    @Inject protected MessageBus _messageBus;
-    @Inject protected VirtualMachinePowerStateSync _syncMgr;
-    @Inject protected VmWorkJobDao _workJobDao;
-    @Inject protected AsyncJobManager _jobMgr;
+    @Inject 
+    protected MessageBus _messageBus;
+    
+    @Inject 
+    protected VirtualMachinePowerStateSync _syncMgr;
+    
+    @Inject 
+    protected VmWorkJobDao _workJobDao;
+    
+    @Inject 
+    protected AsyncJobManager _jobMgr;
     
     Map<VirtualMachine.Type, VirtualMachineGuru> _vmGurus = new HashMap<VirtualMachine.Type, VirtualMachineGuru>();
     protected StateMachine2<State, VirtualMachine.Event, VirtualMachine> _stateMachine;
@@ -315,9 +325,13 @@
         "On destroy, force-stop takes this value ", true);
     static final ConfigKey<Integer> ClusterDeltaSyncInterval = new ConfigKey<Integer>("Advanced", Integer.class, "sync.interval", "60", "Cluster Delta sync interval in seconds",
         false);
-    
-    protected static final ConfigKey<Long> PingInterval = new ConfigKey<Long>("Advanced",
-            Long.class, "ping.interval", "60", "Ping interval in seconds", false);
+
+    static final ConfigKey<Long> VmJobCheckInterval = new ConfigKey<Long>("Advanced",
+            Long.class, "vm.job.check.interval", "3000", "Interval in milliseconds to check if the job is complete", true);
+    static final ConfigKey<Long> VmJobTimeout = new ConfigKey<Long>("Advanced",
+            Long.class, "vm.job.timeout", "600000", "Time in milliseconds to wait before attempting to cancel a job", true);
+    static final ConfigKey<Long> PingInterval = new ConfigKey<Long>("Advanced",
+            Long.class, "ping.interval", "60", "Ping interval in seconds", true);
 
     ScheduledExecutorService _executor = null;
 
@@ -493,6 +507,7 @@
 
     @Override
     public boolean start() {
+        _executor.scheduleAtFixedRate(new TransitionTask(), PingInterval.value(), PingInterval.value(), TimeUnit.SECONDS);
         _executor.scheduleAtFixedRate(new CleanupTask(), VmOpCleanupInterval.value(), VmOpCleanupInterval.value(), TimeUnit.SECONDS);
         cancelWorkItems(_nodeId);
         return true;
@@ -512,6 +527,7 @@
         _nodeId = ManagementServerNode.getManagementServerId();
 
         _agentMgr.registerForHostEvents(this, true, true, true);
+        _messageBus.subscribe(Topics.VM_POWER_STATE, MessageDispatcher.getDispatcher(this));
 
         return true;
     }
@@ -521,20 +537,21 @@
     }
 
     @Override
-    public void start(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) {
-        start(vmUuid, params, null);
+    public void easyStart(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) {
+        easyStart(vmUuid, params, null);
     }
 
     @Override
-    public void start(String vmUuid, Map<VirtualMachineProfile.Param, Object> params, DeploymentPlan planToDeploy) {
+    public void easyStart(String vmUuid, Map<VirtualMachineProfile.Param, Object> params, DeploymentPlan planToDeploy) {
+        Outcome<VirtualMachine> outcome = start(vmUuid, params, planToDeploy);
         try {
-            advanceStart(vmUuid, params, planToDeploy);
-        } catch (ConcurrentOperationException e) {
-            throw new CloudRuntimeException("Unable to start a VM due to concurrent operation", e).add(VirtualMachine.class, vmUuid);
-        } catch (InsufficientCapacityException e) {
-            throw new CloudRuntimeException("Unable to start a VM due to insufficient capacity", e).add(VirtualMachine.class, vmUuid);
-        } catch (ResourceUnavailableException e) {
-            throw new CloudRuntimeException("Unable to start a VM due to concurrent operation", e).add(VirtualMachine.class, vmUuid);
+            outcome.get(VmJobTimeout.value(), TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            // FIXME: What to do
+        } catch (java.util.concurrent.ExecutionException e) {
+            // FIXME: What to do
+        } catch (TimeoutException e) {
+            // FIXME: What to do
         }
     }
 
@@ -639,6 +656,7 @@
         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 {
         // FIXME: We should do this better.
         Step previousStep = work.getStep();
@@ -653,7 +671,24 @@
             }
         }
     }
+*/
+    
+    protected boolean changeState(VMInstanceVO vm, Event event, Long hostId, VmWorkJobVO work, Step step) throws NoTransitionException {
+        VmWorkJobVO.Step previousStep = work.getStep();
+        
+        Transaction txn = Transaction.currentTxn();
 
+        txn.start();
+        work.setStep(step);
+        boolean result = stateTransitTo(vm, event, hostId);
+        if (!result) {
+            work.setStep(previousStep);
+        }
+        _workJobDao.update(work.getId(), work);
+        txn.commit();
+        return result;
+    }
+    
     protected boolean areAffinityGroupsAssociated(VirtualMachineProfile vmProfile) {
         VirtualMachine vm = vmProfile.getVirtualMachine();
         long vmGroupCount = _affinityGroupVMMapDao.countAffinityGroupsForVm(vm.getId());
diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java b/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java
index e784295..5505637 100755
--- a/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java
+++ b/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java
@@ -224,7 +224,7 @@
             DataCenterDeployment reservedPlan = new DataCenterDeployment(vm.getDataCenterId(),
                     vmReservation.getPodId(), vmReservation.getClusterId(), vmReservation.getHostId(), null, null);
             try {
-                _itMgr.start(vm.getUuid(), params, reservedPlan);
+                _itMgr.easyStart(vm.getUuid(), params, reservedPlan);
             } catch (Exception ex) {
                 // Retry the deployment without using the reservation plan
                 DataCenterDeployment plan = new DataCenterDeployment(0, null, null, null, null, null);
@@ -233,11 +233,11 @@
                     plan.setAvoids(reservedPlan.getAvoids());
                 }
 
-                _itMgr.start(vm.getUuid(), params, plan);
+                _itMgr.easyStart(vm.getUuid(), params, plan);
             }
         } else {
             // no reservation found. Let VirtualMachineManager retry
-            _itMgr.start(vm.getUuid(), params, null);
+            _itMgr.easyStart(vm.getUuid(), params, null);
         }
 
     }
diff --git a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java
index 3f8fc5c..f6e7e15 100644
--- a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java
+++ b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java
@@ -536,7 +536,7 @@
     private DomainRouterVO start(DomainRouterVO elbVm, User user, Account caller, Map<Param, Object> params) throws StorageUnavailableException, InsufficientCapacityException,
     ConcurrentOperationException, ResourceUnavailableException {
         s_logger.debug("Starting ELB VM " + elbVm);
-        _itMgr.start(elbVm.getUuid(), params);
+        _itMgr.easyStart(elbVm.getUuid(), params);
         return _routerDao.findById(elbVm.getId());
     }
     
diff --git a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java
index 5da6e02..2d3b554 100644
--- a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java
+++ b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java
@@ -808,7 +808,7 @@
             throws StorageUnavailableException, InsufficientCapacityException,
             ConcurrentOperationException, ResourceUnavailableException {
         s_logger.debug("Starting Internal LB VM " + internalLbVm);
-        _itMgr.start(internalLbVm.getUuid(), params, null);
+        _itMgr.easyStart(internalLbVm.getUuid(), params, null);
         if (internalLbVm.isStopPending()) {
             s_logger.info("Clear the stop pending flag of Internal LB VM " + internalLbVm.getHostName() + " after start router successfully!");
             internalLbVm.setStopPending(false);
diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
index 5ea7560..25c7e73 100755
--- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
+++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
@@ -2737,7 +2737,7 @@
             throws StorageUnavailableException, InsufficientCapacityException,
     ConcurrentOperationException, ResourceUnavailableException {
         s_logger.debug("Starting router " + router);
-        _itMgr.start(router.getUuid(), params, planToDeploy);
+        _itMgr.easyStart(router.getUuid(), params, planToDeploy);
         if (router.isStopPending()) {
             s_logger.info("Clear the stop pending flag of router " + router.getHostName() + " after start router successfully!");
             router.setStopPending(false);
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java
index 6e87916..7ff1ccc 100755
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -4832,7 +4832,7 @@
 
         if (needRestart) {
             try {
-                _itMgr.start(vm.getUuid(), null);
+                _itMgr.easyStart(vm.getUuid(), null);
             } catch (Exception e) {
                 s_logger.debug("Unable to start VM " + vm.getUuid(), e);
                 CloudRuntimeException ex = new CloudRuntimeException(