You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ke...@apache.org on 2013/11/21 03:33:47 UTC

[1/6] side-by-side VM sync management at manager level

Updated Branches:
  refs/heads/4.3 43c3b8dcb -> 5a44de282
  refs/heads/master 2d42b2d1a -> 278ef81a8


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java
index 9c47727..9aa9501 100644
--- a/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java
+++ b/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java
@@ -27,7 +27,6 @@ import org.apache.cloudstack.framework.messagebus.MessageBus;
 import org.apache.cloudstack.framework.messagebus.PublishScope;
 
 import com.cloud.agent.api.HostVmStateReportEntry;
-import com.cloud.vm.VirtualMachine.PowerState;
 import com.cloud.vm.dao.VMInstanceDao;
 
 public class VirtualMachinePowerStateSyncImpl implements VirtualMachinePowerStateSync {
@@ -56,11 +55,11 @@ public class VirtualMachinePowerStateSyncImpl implements VirtualMachinePowerStat
     }
 
     @Override
-	public void processHostVmStatePingReport(long hostId, Map<String, PowerState> report) {
+	public void processHostVmStatePingReport(long hostId, Map<String, HostVmStateReportEntry> report) {
     	if(s_logger.isDebugEnabled())
     		s_logger.debug("Process host VM state report from ping process. host: " + hostId);
     	
-    	Map<Long, VirtualMachine.PowerState> translatedInfo = convertHostPingInfos(report);
+    	Map<Long, VirtualMachine.PowerState> translatedInfo = convertToInfos(report);
     	processReport(hostId, translatedInfo);
     }
     
@@ -80,25 +79,6 @@ public class VirtualMachinePowerStateSyncImpl implements VirtualMachinePowerStat
     		}
     	}
     }
- 
-    private Map<Long, VirtualMachine.PowerState> convertHostPingInfos(Map<String, PowerState> states) {
-        final HashMap<Long, VirtualMachine.PowerState> map = new HashMap<Long, VirtualMachine.PowerState>();
-        if (states == null) {
-            return map;
-        }
-    	
-        for (Map.Entry<String, PowerState> entry : states.entrySet()) {
-        	VMInstanceVO vm = findVM(entry.getKey());
-        	if(vm != null) {
-        		map.put(vm.getId(), entry.getValue());
-        		break;
-        	} else {
-        		s_logger.info("Unable to find matched VM in CloudStack DB. name: " + entry.getKey());
-        	}
-        }
-
-        return map;
-    }
     	    
     private Map<Long, VirtualMachine.PowerState> convertToInfos(Map<String, HostVmStateReportEntry> states) {
         final HashMap<Long, VirtualMachine.PowerState> map = new HashMap<Long, VirtualMachine.PowerState>();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/src/com/cloud/vm/VmWorkAddVmToNetwork.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkAddVmToNetwork.java b/engine/orchestration/src/com/cloud/vm/VmWorkAddVmToNetwork.java
new file mode 100644
index 0000000..3590c0d
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkAddVmToNetwork.java
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import com.cloud.network.Network;
+
+public class VmWorkAddVmToNetwork extends VmWork {
+	private static final long serialVersionUID = 8861516006586736813L;
+
+	Network network;
+	NicProfile requstedNicProfile;
+	
+	public VmWorkAddVmToNetwork(long userId, long accountId, long vmId, 
+		Network network, NicProfile requested) {
+		super(userId, accountId, vmId);
+	
+		this.network = network;
+		this.requstedNicProfile = requested;
+	}
+	
+	public Network getNetwork() {
+		return this.network;
+	}
+	
+	public NicProfile getRequestedNicProfile() {
+		return this.requstedNicProfile;
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/src/com/cloud/vm/VmWorkJobDispatcher.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkJobDispatcher.java b/engine/orchestration/src/com/cloud/vm/VmWorkJobDispatcher.java
new file mode 100644
index 0000000..7c36d8c
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkJobDispatcher.java
@@ -0,0 +1,152 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.framework.jobs.AsyncJob;
+import org.apache.cloudstack.framework.jobs.AsyncJobDispatcher;
+import org.apache.cloudstack.framework.jobs.AsyncJobManager;
+import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper;
+import org.apache.cloudstack.jobs.JobInfo;
+
+import com.cloud.utils.component.AdapterBase;
+import com.cloud.vm.dao.VMInstanceDao;
+
+public class VmWorkJobDispatcher extends AdapterBase implements AsyncJobDispatcher {
+    private static final Logger s_logger = Logger.getLogger(VmWorkJobDispatcher.class);
+
+    public static final String VM_WORK_QUEUE = "VmWorkJobQueue";
+    public static final String VM_WORK_JOB_DISPATCHER = "VmWorkJobDispatcher";
+    public static final String VM_WORK_JOB_WAKEUP_DISPATCHER = "VmWorkJobWakeupDispatcher";
+    
+    @Inject private VirtualMachineManagerImpl _vmMgr;
+	@Inject private AsyncJobManager _asyncJobMgr;
+    @Inject private VMInstanceDao _instanceDao;
+    
+	@Override
+    public void runJob(AsyncJob job) {
+        VmWork work = null;
+        try {
+        	String cmd = job.getCmd();
+        	assert(cmd != null);
+        	
+        	if(s_logger.isDebugEnabled())
+        		s_logger.debug("Run VM work job: " + cmd);
+        	
+        	Class<?> workClz = null;
+        	try {
+        		workClz = Class.forName(job.getCmd());
+        	} catch(ClassNotFoundException e) {
+        		s_logger.error("VM work class " + cmd + " is not found", e);
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.FAILED, 0, e.getMessage());
+        		return;
+        	}
+        	
+        	work = VmWorkSerializer.deserialize(workClz, job.getCmdInfo());
+            assert(work != null);
+            if(work == null) {
+            	s_logger.error("Unable to deserialize VM work " + job.getCmd() + ", job info: " + job.getCmdInfo());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.FAILED, 0, "Unable to deserialize VM work");
+        		return;
+            }
+            
+            CallContext.register(work.getUserId(), work.getAccountId(), job.getRelated());
+
+            VMInstanceVO vm = _instanceDao.findById(work.getVmId());
+            if (vm == null) {
+                s_logger.info("Unable to find vm " + work.getVmId());
+            }
+            assert(vm != null);
+            if(work instanceof VmWorkStart) {
+            	VmWorkStart workStart = (VmWorkStart)work;
+            	_vmMgr.orchestrateStart(vm.getUuid(), workStart.getParams(), workStart.getPlan());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, null);
+            } else if(work instanceof VmWorkStop) {
+            	VmWorkStop workStop = (VmWorkStop)work;
+            	_vmMgr.orchestrateStop(vm.getUuid(), workStop.isCleanup());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, null);
+            } else if(work instanceof VmWorkMigrate) {
+            	VmWorkMigrate workMigrate = (VmWorkMigrate)work;
+            	_vmMgr.orchestrateMigrate(vm.getUuid(), workMigrate.getSrcHostId(), workMigrate.getDeployDestination());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, null);
+            } else if(work instanceof VmWorkMigrateWithStorage) {
+            	VmWorkMigrateWithStorage workMigrateWithStorage = (VmWorkMigrateWithStorage)work;
+            	_vmMgr.orchestrateMigrateWithStorage(vm.getUuid(), 
+            		workMigrateWithStorage.getSrcHostId(), 
+            		workMigrateWithStorage.getDestHostId(), 
+            		workMigrateWithStorage.getVolumeToPool());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, null);
+            } else if(work instanceof VmWorkMigrateForScale) { 
+            	VmWorkMigrateForScale workMigrateForScale = (VmWorkMigrateForScale)work;
+            	_vmMgr.orchestrateMigrateForScale(vm.getUuid(), 
+            		workMigrateForScale.getSrcHostId(), 
+            		workMigrateForScale.getDeployDestination(), 
+            		workMigrateForScale.getNewServiceOfferringId());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, null);
+            } else if(work instanceof VmWorkReboot) { 
+                VmWorkReboot workReboot = (VmWorkReboot)work;
+                _vmMgr.orchestrateReboot(vm.getUuid(), workReboot.getParams());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, null);
+            } else if(work instanceof VmWorkAddVmToNetwork) { 
+                VmWorkAddVmToNetwork workAddVmToNetwork = (VmWorkAddVmToNetwork)work;
+                NicProfile nic = _vmMgr.orchestrateAddVmToNetwork(vm, workAddVmToNetwork.getNetwork(), 
+                	workAddVmToNetwork.getRequestedNicProfile());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, 
+                    JobSerializerHelper.toObjectSerializedString(nic));
+            } else if(work instanceof VmWorkRemoveNicFromVm) { 
+                VmWorkRemoveNicFromVm workRemoveNicFromVm = (VmWorkRemoveNicFromVm)work;
+                boolean result = _vmMgr.orchestrateRemoveNicFromVm(vm, workRemoveNicFromVm.getNic());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, 
+                	JobSerializerHelper.toObjectSerializedString(new Boolean(result)));
+            } else if(work instanceof VmWorkRemoveVmFromNetwork) { 
+                VmWorkRemoveVmFromNetwork workRemoveVmFromNetwork = (VmWorkRemoveVmFromNetwork)work;
+                boolean result = _vmMgr.orchestrateRemoveVmFromNetwork(vm, 
+                	workRemoveVmFromNetwork.getNetwork(), workRemoveVmFromNetwork.getBroadcastUri());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, 
+                    	JobSerializerHelper.toObjectSerializedString(new Boolean(result)));
+            } else if(work instanceof VmWorkReconfigure) { 
+                VmWorkReconfigure workReconfigure = (VmWorkReconfigure)work;
+                _vmMgr.reConfigureVm(vm.getUuid(), workReconfigure.getNewServiceOffering(), 
+                	workReconfigure.isSameHost());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, null);
+            } else if(work instanceof VmWorkStorageMigration) { 
+                VmWorkStorageMigration workStorageMigration = (VmWorkStorageMigration)work;
+                _vmMgr.orchestrateStorageMigration(vm.getUuid(), workStorageMigration.getDestStoragePool());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, null);
+            } else {
+            	assert(false);
+                s_logger.error("Unhandled VM work command: " + job.getCmd());
+            	
+            	RuntimeException e = new RuntimeException("Unsupported VM work command: " + job.getCmd());
+                String exceptionJson = JobSerializerHelper.toSerializedString(e);
+                s_logger.error("Serialize exception object into json: " + exceptionJson);
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.FAILED, 0, exceptionJson);
+            }
+        } catch(Throwable e) {
+            s_logger.error("Unable to complete " + job, e);
+            
+            String exceptionJson = JobSerializerHelper.toSerializedString(e);
+            s_logger.info("Serialize exception object into json: " + exceptionJson);
+            _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.FAILED, 0, exceptionJson);
+        } finally {
+            CallContext.unregister();
+        }
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/src/com/cloud/vm/VmWorkMigrate.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkMigrate.java b/engine/orchestration/src/com/cloud/vm/VmWorkMigrate.java
new file mode 100644
index 0000000..c313876
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkMigrate.java
@@ -0,0 +1,86 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.Pod;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.host.Host;
+import com.cloud.org.Cluster;
+import com.cloud.storage.StoragePool;
+import com.cloud.storage.Volume;
+import com.cloud.utils.db.EntityManager;
+
+public class VmWorkMigrate extends VmWork {
+	private static final long serialVersionUID = 1689203333114836522L;
+
+	Long zoneId;
+    Long podId;
+    Long clusterId;
+    Long hostId;
+    private Map<String, String> storage;
+    long srcHostId;
+
+    public VmWorkMigrate(long userId, long accountId, long vmId, long srcHostId, DeployDestination dst) {
+        super(userId, accountId, vmId);
+        this.srcHostId = srcHostId;
+        zoneId = dst.getDataCenter() != null ? dst.getDataCenter().getId() : null;
+        podId = dst.getPod() != null ? dst.getPod().getId() : null;
+        clusterId = dst.getCluster() != null ? dst.getCluster().getId() : null;
+        hostId = dst.getHost() != null ? dst.getHost().getId() : null;
+        if (dst.getStorageForDisks() != null) {
+            storage = new HashMap<String, String>(dst.getStorageForDisks().size());
+            for (Map.Entry<Volume, StoragePool> entry : dst.getStorageForDisks().entrySet()) {
+                storage.put(entry.getKey().getUuid(), entry.getValue().getUuid());
+            }
+        } else {
+            storage = null;
+        }
+    }
+
+    public DeployDestination getDeployDestination() {
+        DataCenter zone = zoneId != null ? s_entityMgr.findById(DataCenter.class, zoneId) : null;
+        Pod pod = podId != null ? s_entityMgr.findById(Pod.class, podId) : null;
+        Cluster cluster = clusterId != null ? s_entityMgr.findById(Cluster.class, clusterId) : null;
+        Host host = hostId != null ? s_entityMgr.findById(Host.class, hostId) : null;
+        
+        Map<Volume, StoragePool> vols = null;
+
+        if (storage != null) {
+            vols = new HashMap<Volume, StoragePool>(storage.size());
+            for (Map.Entry<String, String> entry : storage.entrySet()) {
+                vols.put(s_entityMgr.findByUuid(Volume.class, entry.getKey()), s_entityMgr.findByUuid(StoragePool.class, entry.getValue()));
+            }
+        }
+
+        DeployDestination dest = new DeployDestination(zone, pod, cluster, host, vols);
+        return dest;
+    }
+
+    public long getSrcHostId() {
+        return srcHostId;
+    }
+
+    static private EntityManager s_entityMgr;
+
+    static public void init(EntityManager entityMgr) {
+        s_entityMgr = entityMgr;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/src/com/cloud/vm/VmWorkMigrateForScale.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkMigrateForScale.java b/engine/orchestration/src/com/cloud/vm/VmWorkMigrateForScale.java
new file mode 100644
index 0000000..8e71aa8
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkMigrateForScale.java
@@ -0,0 +1,48 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import com.cloud.deploy.DeployDestination;
+
+public class VmWorkMigrateForScale extends VmWork {
+	private static final long serialVersionUID = 6854870395568389613L;
+
+	long srcHostId;
+	DeployDestination deployDestination;
+	Long newSvcOfferingId;
+	
+    public VmWorkMigrateForScale(long userId, long accountId, long vmId, long srcHostId, 
+    	DeployDestination dest, Long newSvcOfferingId) {
+    	
+    	super(userId, accountId, vmId);
+    	this.srcHostId = srcHostId;
+    	this.deployDestination = dest;
+    	this.newSvcOfferingId = newSvcOfferingId;
+    }
+	
+    public long getSrcHostId() {
+    	return srcHostId;
+    }
+    
+    public DeployDestination getDeployDestination() {
+    	return this.deployDestination;
+    }
+    
+    public Long getNewServiceOfferringId() {
+    	return this.newSvcOfferingId;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/src/com/cloud/vm/VmWorkMigrateWithStorage.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkMigrateWithStorage.java b/engine/orchestration/src/com/cloud/vm/VmWorkMigrateWithStorage.java
new file mode 100644
index 0000000..ae91231
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkMigrateWithStorage.java
@@ -0,0 +1,52 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import java.util.Map;
+
+import com.cloud.storage.StoragePool;
+import com.cloud.storage.Volume;
+
+public class VmWorkMigrateWithStorage extends VmWork {
+	private static final long serialVersionUID = -5626053872453569165L;
+
+	long srcHostId;
+	long destHostId;
+	Map<Volume, StoragePool> volumeToPool;
+	
+    public VmWorkMigrateWithStorage(long userId, long accountId, long vmId, long srcHostId, 
+    	long destHostId, Map<Volume, StoragePool> volumeToPool) {
+    	
+    	super(userId, accountId, vmId);
+    
+    	this.srcHostId = srcHostId;
+    	this.destHostId = destHostId;
+    	this.volumeToPool = volumeToPool;
+    }
+    
+    public long getSrcHostId() {
+    	return this.srcHostId;
+    }
+    
+    public long getDestHostId() {
+    	return this.destHostId;
+    }
+    
+    public Map<Volume, StoragePool> getVolumeToPool() {
+    	return this.volumeToPool;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/src/com/cloud/vm/VmWorkReboot.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkReboot.java b/engine/orchestration/src/com/cloud/vm/VmWorkReboot.java
new file mode 100644
index 0000000..8f50702
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkReboot.java
@@ -0,0 +1,68 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper;
+
+public class VmWorkReboot extends VmWork {
+	private static final long serialVersionUID = 195907627459759933L;
+
+	// use serialization friendly map
+	private Map<String, String> rawParams;
+	
+    public VmWorkReboot(long userId, long accountId, long vmId, Map<VirtualMachineProfile.Param, Object> params) {
+    	super(userId, accountId, vmId);
+    	
+    	setParams(params);
+    }
+    
+	public Map<String, String> getRawParams() {
+		return rawParams;
+	}
+
+	public void setRawParams(Map<String, String> params) {
+		rawParams = params;
+	}
+	
+	public Map<VirtualMachineProfile.Param, Object> getParams() {
+		Map<VirtualMachineProfile.Param, Object> map = new HashMap<VirtualMachineProfile.Param, Object>();
+		
+		if(rawParams != null) {
+			for(Map.Entry<String, String> entry : rawParams.entrySet()) {
+				VirtualMachineProfile.Param key = new VirtualMachineProfile.Param(entry.getKey());
+				Object val = JobSerializerHelper.fromObjectSerializedString(entry.getValue());
+				map.put(key, val);
+			}
+		}
+		
+		return map;
+	}
+	
+	public void setParams(Map<VirtualMachineProfile.Param, Object> params) {
+		if(params != null) {
+			rawParams = new HashMap<String, String>();
+			for(Map.Entry<VirtualMachineProfile.Param, Object> entry : params.entrySet()) {
+				rawParams.put(entry.getKey().getName(), JobSerializerHelper.toObjectSerializedString(
+					entry.getValue() instanceof Serializable ? (Serializable)entry.getValue() : entry.getValue().toString()));
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/src/com/cloud/vm/VmWorkReconfigure.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkReconfigure.java b/engine/orchestration/src/com/cloud/vm/VmWorkReconfigure.java
new file mode 100644
index 0000000..48a9df3
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkReconfigure.java
@@ -0,0 +1,43 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import com.cloud.offering.ServiceOffering;
+
+public class VmWorkReconfigure extends VmWork {
+	private static final long serialVersionUID = -4517030323758086615L;
+	
+	ServiceOffering newServiceOffering;
+	boolean sameHost;
+	
+    public VmWorkReconfigure(long userId, long accountId, long vmId, 
+    	ServiceOffering newServiceOffering, boolean sameHost) {
+    	
+    	super(userId, accountId, vmId);
+    	
+    	this.newServiceOffering = newServiceOffering;
+    	this.sameHost = sameHost;
+    }
+    
+    public ServiceOffering getNewServiceOffering() {
+    	return this.newServiceOffering;
+    }
+    
+    public boolean isSameHost() {
+    	return this.sameHost;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/src/com/cloud/vm/VmWorkRemoveNicFromVm.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkRemoveNicFromVm.java b/engine/orchestration/src/com/cloud/vm/VmWorkRemoveNicFromVm.java
new file mode 100644
index 0000000..b756ac3
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkRemoveNicFromVm.java
@@ -0,0 +1,33 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+public class VmWorkRemoveNicFromVm extends VmWork {
+	private static final long serialVersionUID = -4265657031064437923L;
+
+	Nic nic;
+    
+	public VmWorkRemoveNicFromVm(long userId, long accountId, long vmId, Nic nic) {
+    	super(userId, accountId, vmId);
+    	
+    	this.nic = nic;
+    }
+    
+    public Nic getNic() {
+    	return this.nic;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/src/com/cloud/vm/VmWorkRemoveVmFromNetwork.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkRemoveVmFromNetwork.java b/engine/orchestration/src/com/cloud/vm/VmWorkRemoveVmFromNetwork.java
new file mode 100644
index 0000000..d4e0ae4
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkRemoveVmFromNetwork.java
@@ -0,0 +1,43 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import java.net.URI;
+
+import com.cloud.network.Network;
+
+public class VmWorkRemoveVmFromNetwork extends VmWork {
+	private static final long serialVersionUID = -5070392905642149925L;
+
+	Network network;
+	URI broadcastUri;
+	
+	public VmWorkRemoveVmFromNetwork(long userId, long accountId, long vmId, Network network, URI broadcastUri) {
+    	super(userId, accountId, vmId);
+    	
+    	this.network = network;
+    	this.broadcastUri = broadcastUri;
+	}
+	
+	public Network getNetwork() {
+		return this.network;
+	}
+	
+	public URI getBroadcastUri() {
+		return this.broadcastUri;
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/src/com/cloud/vm/VmWorkSerializer.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkSerializer.java b/engine/orchestration/src/com/cloud/vm/VmWorkSerializer.java
new file mode 100644
index 0000000..9a1aaac
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkSerializer.java
@@ -0,0 +1,75 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+
+public class VmWorkSerializer {
+    static class StringMapTypeAdapter implements JsonDeserializer<Map> {
+    	
+        @Override
+        public Map deserialize(JsonElement src, Type srcType, JsonDeserializationContext context) throws JsonParseException {
+
+            Map<String, String> obj = new HashMap<String, String>();
+            JsonObject json = src.getAsJsonObject();
+
+            for (Entry<String, JsonElement> entry : json.entrySet()) {
+                obj.put(entry.getKey(), entry.getValue().getAsString());
+            }
+
+            return obj;
+        }
+    }
+ 
+    protected static Gson s_gson;
+    static {
+        GsonBuilder gBuilder = new GsonBuilder();
+        gBuilder.setVersion(1.3);
+        gBuilder.registerTypeAdapter(Map.class, new StringMapTypeAdapter());
+        s_gson = gBuilder.create();
+    }
+   
+    public static String serialize(VmWork work) {
+    	// TODO: there are way many generics, too tedious to get serialization work under GSON
+    	// use java binary serialization instead
+    	// 
+    	return JobSerializerHelper.toObjectSerializedString(work);
+        // return s_gson.toJson(work);
+    }
+
+    public static <T extends VmWork> T deserialize(Class<?> clazz, String workInJsonText) {
+    	// TODO: there are way many generics, too tedious to get serialization work under GSON
+    	// use java binary serialization instead
+    	// 
+        return (T)JobSerializerHelper.fromObjectSerializedString(workInJsonText);
+    	// return (T)s_gson.fromJson(workInJsonText, clazz);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/src/com/cloud/vm/VmWorkStart.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkStart.java b/engine/orchestration/src/com/cloud/vm/VmWorkStart.java
new file mode 100644
index 0000000..7a7447f
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkStart.java
@@ -0,0 +1,125 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package com.cloud.vm;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper;
+
+import com.cloud.deploy.DataCenterDeployment;
+import com.cloud.deploy.DeploymentPlan;
+import com.cloud.deploy.DeploymentPlanner.ExcludeList;
+import com.cloud.utils.Journal;
+
+public class VmWorkStart extends VmWork {
+	private static final long serialVersionUID = 9038937399817468894L;
+
+	private static final Logger s_logger = Logger.getLogger(VmWorkStart.class);
+
+	long dcId;
+	Long podId;
+	Long clusterId;
+	Long hostId;
+	Long poolId;
+	ExcludeList avoids;
+	Long physicalNetworkId;
+	
+	String reservationId;
+	String journalName;
+	
+	// use serialization friendly map
+	private Map<String, String> rawParams;
+
+    public VmWorkStart(long userId, long accountId, long vmId) {
+        super(userId, accountId, vmId);
+	}
+
+	public DeploymentPlan getPlan() {
+		
+		if(podId != null || clusterId != null || hostId != null || poolId != null || physicalNetworkId != null) {
+			// this is ugly, to work with legacy code, we need to re-construct the DeploymentPlan hard-codely
+			// this has to be refactored together with migrating legacy code into the new way
+			ReservationContext context = null;
+			if(reservationId != null) {
+		        Journal journal = new Journal.LogJournal("VmWorkStart", s_logger);
+				context = new ReservationContextImpl(reservationId, journal, 
+						CallContext.current().getCallingUser(), 
+						CallContext.current().getCallingAccount());
+			}
+			
+			DeploymentPlan plan = new DataCenterDeployment(
+					dcId, podId, clusterId, hostId, poolId, physicalNetworkId,
+					context);
+			return plan;
+		}
+		
+		return null;
+	}
+
+	public void setPlan(DeploymentPlan plan) {
+		if(plan != null) {
+			dcId = plan.getDataCenterId();
+			podId = plan.getPodId();
+			clusterId = plan.getClusterId();
+			hostId = plan.getHostId();
+			poolId = plan.getPoolId();
+			physicalNetworkId = plan.getPhysicalNetworkId();
+			avoids = plan.getAvoids();
+			
+			if(plan.getReservationContext() != null)
+				reservationId = plan.getReservationContext().getReservationId();
+		}
+	}
+
+	public Map<String, String> getRawParams() {
+		return rawParams;
+	}
+
+	public void setRawParams(Map<String, String> params) {
+		rawParams = params;
+	}
+	
+	public Map<VirtualMachineProfile.Param, Object> getParams() {
+		Map<VirtualMachineProfile.Param, Object> map = new HashMap<VirtualMachineProfile.Param, Object>();
+		
+		if(rawParams != null) {
+			for(Map.Entry<String, String> entry : rawParams.entrySet()) {
+				VirtualMachineProfile.Param key = new VirtualMachineProfile.Param(entry.getKey());
+				Object val = JobSerializerHelper.fromObjectSerializedString(entry.getValue());
+				map.put(key, val);
+			}
+		}
+		
+		return map;
+	}
+	
+	public void setParams(Map<VirtualMachineProfile.Param, Object> params) {
+		if(params != null) {
+			rawParams = new HashMap<String, String>();
+			for(Map.Entry<VirtualMachineProfile.Param, Object> entry : params.entrySet()) {
+				rawParams.put(entry.getKey().getName(), JobSerializerHelper.toObjectSerializedString(
+					entry.getValue() instanceof Serializable ? (Serializable)entry.getValue() : entry.getValue().toString()));
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/src/com/cloud/vm/VmWorkStop.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkStop.java b/engine/orchestration/src/com/cloud/vm/VmWorkStop.java
new file mode 100644
index 0000000..0a27057
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkStop.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+public class VmWorkStop extends VmWork {
+	private static final long serialVersionUID = 202908740486785251L;
+	
+	private final boolean cleanup;
+	
+    public VmWorkStop(long userId, long accountId, long vmId, boolean cleanup) {
+        super(userId, accountId, vmId);
+        this.cleanup = cleanup;
+	}
+	
+	public boolean isCleanup() {
+		return cleanup;
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/src/com/cloud/vm/VmWorkStorageMigration.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkStorageMigration.java b/engine/orchestration/src/com/cloud/vm/VmWorkStorageMigration.java
new file mode 100644
index 0000000..ba8330c
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkStorageMigration.java
@@ -0,0 +1,35 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import com.cloud.storage.StoragePool;
+
+public class VmWorkStorageMigration extends VmWork {
+	private static final long serialVersionUID = -8677979691741157474L;
+
+	StoragePool destPool;
+	
+    public VmWorkStorageMigration(long userId, long accountId, long vmId, StoragePool destPool) {
+    	super(userId, accountId, vmId);
+    	
+    	this.destPool = destPool;
+    }
+    
+    public StoragePool getDestStoragePool() {
+    	return this.destPool;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/framework/cluster/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java
----------------------------------------------------------------------
diff --git a/framework/cluster/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java b/framework/cluster/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java
index 246bfe6..d187199 100644
--- a/framework/cluster/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java
+++ b/framework/cluster/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java
@@ -100,6 +100,7 @@ public class ManagementServerHostDaoImpl extends GenericDaoBase<ManagementServer
             txn.commit();
         } catch(Exception e) {
             s_logger.warn("Unexpected exception, ", e);
+            throw new RuntimeException(e.getMessage(), e);
         }
 	}
 	
@@ -119,9 +120,8 @@ public class ManagementServerHostDaoImpl extends GenericDaoBase<ManagementServer
         	return true;
         } catch(Exception e) {
             s_logger.warn("Unexpected exception, ", e);
+            throw new RuntimeException(e.getMessage(), e);
         }
-        
-        return false;
     }
 
 	@Override
@@ -145,6 +145,7 @@ public class ManagementServerHostDaoImpl extends GenericDaoBase<ManagementServer
             }
         } catch(Exception e) {
             s_logger.warn("Unexpected exception, ", e);
+            throw new RuntimeException(e.getMessage(), e);
         }
 	}
 	
@@ -180,7 +181,7 @@ public class ManagementServerHostDaoImpl extends GenericDaoBase<ManagementServer
             txn.commit();
         } catch(Exception e) {
             s_logger.warn("Unexpected exception, ", e);
-            txn.rollback();
+            throw new RuntimeException(e.getMessage(), e);
         }
         
         return changedRows;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/framework/jobs/resources/META-INF/cloudstack/core/spring-framework-jobs-core-context.xml
----------------------------------------------------------------------
diff --git a/framework/jobs/resources/META-INF/cloudstack/core/spring-framework-jobs-core-context.xml b/framework/jobs/resources/META-INF/cloudstack/core/spring-framework-jobs-core-context.xml
index 85cad02..2d1eba0 100644
--- a/framework/jobs/resources/META-INF/cloudstack/core/spring-framework-jobs-core-context.xml
+++ b/framework/jobs/resources/META-INF/cloudstack/core/spring-framework-jobs-core-context.xml
@@ -43,6 +43,6 @@
         class="org.apache.cloudstack.framework.jobs.dao.SyncQueueItemDaoImpl" />
     <bean id="syncQueueManagerImpl"
         class="org.apache.cloudstack.framework.jobs.impl.SyncQueueManagerImpl" />
-
-    
+    <bean id="vmWorkJobDaoImpl"
+        class="org.apache.cloudstack.framework.jobs.dao.VmWorkJobDaoImpl" />
 </beans>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java
----------------------------------------------------------------------
diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java
index 595800d..0263d3d 100644
--- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java
+++ b/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java
@@ -63,6 +63,14 @@ public class AsyncJobExecutionContext  {
     public void setJob(AsyncJob job) {
 		_job = job;
 	}
+    
+    public boolean isJobDispatchedBy(String jobDispatcherName) {
+    	assert(jobDispatcherName != null);
+    	if(_job != null && _job.getDispatcher() != null && _job.getDispatcher().equals(jobDispatcherName))
+    		return true;
+    	
+    	return false;
+    }
 	
     public void completeAsyncJob(JobInfo.Status jobStatus, int resultCode, String resultObject) {
     	assert(_job != null);
@@ -159,7 +167,7 @@ public class AsyncJobExecutionContext  {
         setCurrentExecutionContext(null);
         return context;
     }
-
+    
     // This is intended to be package level access for AsyncJobManagerImpl only.
     public static void setCurrentExecutionContext(AsyncJobExecutionContext currentContext) {
 		s_currentExectionContext.set(currentContext);


[6/6] git commit: updated refs/heads/4.3 to 5a44de2

Posted by ke...@apache.org.
CLOUDSTACK-669: side-by-side VM sync management at manager level


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/5a44de28
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/5a44de28
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/5a44de28

Branch: refs/heads/4.3
Commit: 5a44de282b30f6dc34b8a36d8f664bd3a3b9408b
Parents: 367db2e
Author: Kelven Yang <ke...@gmail.com>
Authored: Wed Nov 20 17:46:45 2013 -0800
Committer: Kelven Yang <ke...@gmail.com>
Committed: Wed Nov 20 18:22:38 2013 -0800

----------------------------------------------------------------------
 api/src/com/cloud/vm/VirtualMachine.java        |    7 +-
 .../apache/cloudstack/api/InternalIdentity.java |    4 +-
 .../apache/cloudstack/context/CallContext.java  |   12 +
 .../src/com/cloud/vm/VirtualMachineManager.java |   30 +-
 .../src/com/cloud/alert/AlertManager.java       |    2 +
 .../components-api/src/com/cloud/vm/VmWork.java |   45 +
 ...spring-engine-orchestration-core-context.xml |    1 +
 .../com/cloud/vm/VirtualMachineManagerImpl.java | 1348 +++++++++++++++++-
 .../cloud/vm/VirtualMachinePowerStateSync.java  |    3 +-
 .../vm/VirtualMachinePowerStateSyncImpl.java    |   24 +-
 .../src/com/cloud/vm/VmWorkAddVmToNetwork.java  |   42 +
 .../src/com/cloud/vm/VmWorkJobDispatcher.java   |  152 ++
 .../src/com/cloud/vm/VmWorkMigrate.java         |   86 ++
 .../src/com/cloud/vm/VmWorkMigrateForScale.java |   48 +
 .../com/cloud/vm/VmWorkMigrateWithStorage.java  |   52 +
 .../src/com/cloud/vm/VmWorkReboot.java          |   68 +
 .../src/com/cloud/vm/VmWorkReconfigure.java     |   43 +
 .../src/com/cloud/vm/VmWorkRemoveNicFromVm.java |   33 +
 .../com/cloud/vm/VmWorkRemoveVmFromNetwork.java |   43 +
 .../src/com/cloud/vm/VmWorkSerializer.java      |   75 +
 .../src/com/cloud/vm/VmWorkStart.java           |  125 ++
 .../src/com/cloud/vm/VmWorkStop.java            |   32 +
 .../com/cloud/vm/VmWorkStorageMigration.java    |   35 +
 .../dao/ManagementServerHostDaoImpl.java        |    7 +-
 .../core/spring-framework-jobs-core-context.xml |    4 +-
 .../jobs/AsyncJobExecutionContext.java          |   10 +-
 26 files changed, 2274 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/api/src/com/cloud/vm/VirtualMachine.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java
index 9a8d883..3400898 100755
--- a/api/src/com/cloud/vm/VirtualMachine.java
+++ b/api/src/com/cloud/vm/VirtualMachine.java
@@ -213,7 +213,12 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I
          * UserBareMetal is only used for selecting VirtualMachineGuru, there is no
          * VM with this type. UserBareMetal should treat exactly as User.
          */
-        UserBareMetal(false);
+        UserBareMetal(false),
+        
+        /*
+         * General VM type for queuing VM orchestration work
+         */
+        Instance(false);
 
         boolean _isUsedBySystem;
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/api/src/org/apache/cloudstack/api/InternalIdentity.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/InternalIdentity.java b/api/src/org/apache/cloudstack/api/InternalIdentity.java
index 1dfeb8c..4149dd1 100644
--- a/api/src/org/apache/cloudstack/api/InternalIdentity.java
+++ b/api/src/org/apache/cloudstack/api/InternalIdentity.java
@@ -16,11 +16,13 @@
 // under the License.
 package org.apache.cloudstack.api;
 
+import java.io.Serializable;
+
 // This interface is a contract that getId() will give the internal
 // ID of an entity which extends this interface
 // Any class having an internal ID in db table/schema should extend this
 // For example, all ControlledEntity, OwnedBy would have an internal ID
 
-public interface InternalIdentity {
+public interface InternalIdentity extends Serializable {
     long getId();
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/api/src/org/apache/cloudstack/context/CallContext.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/context/CallContext.java b/api/src/org/apache/cloudstack/context/CallContext.java
index 5439aee..3cdccc5 100644
--- a/api/src/org/apache/cloudstack/context/CallContext.java
+++ b/api/src/org/apache/cloudstack/context/CallContext.java
@@ -197,6 +197,18 @@ public class CallContext {
         }
         return register(user, account);
     }
+    
+    public static CallContext register(long callingUserId, long callingAccountId, String contextId) throws CloudAuthenticationException {
+        Account account = s_entityMgr.findById(Account.class, callingAccountId);
+        if (account == null) {
+            throw new CloudAuthenticationException("The account is no longer current.").add(Account.class, Long.toString(callingAccountId));
+        }
+        User user = s_entityMgr.findById(User.class, callingUserId);
+        if (user == null) {
+            throw new CloudAuthenticationException("The user is no longer current.").add(User.class, Long.toString(callingUserId));
+        }
+        return register(user, account, contextId);
+    }
 
     public static void unregisterAll() {
         while ( unregister() != null ) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/api/src/com/cloud/vm/VirtualMachineManager.java
----------------------------------------------------------------------
diff --git a/engine/api/src/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/com/cloud/vm/VirtualMachineManager.java
index cb6c62d..00393bf 100644
--- a/engine/api/src/com/cloud/vm/VirtualMachineManager.java
+++ b/engine/api/src/com/cloud/vm/VirtualMachineManager.java
@@ -103,8 +103,13 @@ public interface VirtualMachineManager extends Manager {
     void advanceStart(String vmUuid, Map<VirtualMachineProfile.Param, Object> params, DeploymentPlan planToDeploy) throws InsufficientCapacityException,
             ResourceUnavailableException, ConcurrentOperationException, OperationTimedoutException;
 
+    void orchestrateStart(String vmUuid, Map<VirtualMachineProfile.Param, Object> params, DeploymentPlan planToDeploy) throws InsufficientCapacityException,
+    	ResourceUnavailableException, ConcurrentOperationException, OperationTimedoutException;
+    
     void advanceStop(String vmUuid, boolean cleanupEvenIfUnableToStop) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException;
 
+    void orchestrateStop(String vmUuid, boolean cleanupEvenIfUnableToStop) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException;
+
     void advanceExpunge(String vmUuid) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException;
 
     void destroy(String vmUuid) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException;
@@ -112,11 +117,17 @@ public interface VirtualMachineManager extends Manager {
     void migrateAway(String vmUuid, long hostId) throws InsufficientServerCapacityException;
 
     void migrate(String vmUuid, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException;
+    
+    void orchestrateMigrate(String vmUuid, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException;
 
     void migrateWithStorage(String vmUuid, long srcId, long destId, Map<Volume, StoragePool> volumeToPool) throws ResourceUnavailableException, ConcurrentOperationException;
-
+    
+    void orchestrateMigrateWithStorage(String vmUuid, long srcId, long destId, Map<Volume, StoragePool> volumeToPool) throws ResourceUnavailableException, ConcurrentOperationException;
+    
     void reboot(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) throws InsufficientCapacityException, ResourceUnavailableException;
 
+    void orchestrateReboot(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) throws InsufficientCapacityException, ResourceUnavailableException;
+
     void advanceReboot(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) throws InsufficientCapacityException, ResourceUnavailableException,
             ConcurrentOperationException, OperationTimedoutException;
 
@@ -132,6 +143,8 @@ public interface VirtualMachineManager extends Manager {
     VirtualMachine findById(long vmId);
 
     void storageMigration(String vmUuid, StoragePool storagePoolId);
+    
+    void orchestrateStorageMigration(String vmUuid, StoragePool storagePoolId);
 
     /**
      * @param vmInstance
@@ -156,7 +169,11 @@ public interface VirtualMachineManager extends Manager {
      * @throws InsufficientCapacityException
      */
     NicProfile addVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) throws ConcurrentOperationException,
-                ResourceUnavailableException, InsufficientCapacityException;
+        ResourceUnavailableException, InsufficientCapacityException;
+    
+    NicProfile orchestrateAddVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) throws ConcurrentOperationException,
+    	ResourceUnavailableException, InsufficientCapacityException;
+    
 
     /**
      * @param vm
@@ -167,6 +184,8 @@ public interface VirtualMachineManager extends Manager {
      */
     boolean removeNicFromVm(VirtualMachine vm, Nic nic) throws ConcurrentOperationException, ResourceUnavailableException;
 
+    boolean orchestrateRemoveNicFromVm(VirtualMachine vm, Nic nic) throws ConcurrentOperationException, ResourceUnavailableException;
+
     /**
      * @param vm
      * @param network
@@ -176,6 +195,8 @@ public interface VirtualMachineManager extends Manager {
      * @throws ConcurrentOperationException
      */
     boolean removeVmFromNetwork(VirtualMachine vm, Network network, URI broadcastUri) throws ConcurrentOperationException, ResourceUnavailableException;
+    
+    boolean orchestrateRemoveVmFromNetwork(VirtualMachine vm, Network network, URI broadcastUri) throws ConcurrentOperationException, ResourceUnavailableException;
 
     /**
      * @param nic
@@ -191,12 +212,15 @@ public interface VirtualMachineManager extends Manager {
      */
     VirtualMachineTO toVmTO(VirtualMachineProfile profile);
 
-
     VirtualMachine reConfigureVm(String vmUuid, ServiceOffering newServiceOffering, boolean sameHost) throws ResourceUnavailableException, ConcurrentOperationException;
+    
+    VirtualMachine orchestrateReConfigureVm(String vmUuid, ServiceOffering newServiceOffering, boolean sameHost) throws ResourceUnavailableException, ConcurrentOperationException;
 
     void findHostAndMigrate(String vmUuid, Long newSvcOfferingId, DeploymentPlanner.ExcludeList excludeHostList) throws InsufficientCapacityException,
             ConcurrentOperationException, ResourceUnavailableException;
 
     void migrateForScale(String vmUuid, long srcHostId, DeployDestination dest, Long newSvcOfferingId) throws ResourceUnavailableException, ConcurrentOperationException;
+    
+    void orchestrateMigrateForScale(String vmUuid, long srcHostId, DeployDestination dest, Long newSvcOfferingId) throws ResourceUnavailableException, ConcurrentOperationException;
 
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/components-api/src/com/cloud/alert/AlertManager.java
----------------------------------------------------------------------
diff --git a/engine/components-api/src/com/cloud/alert/AlertManager.java b/engine/components-api/src/com/cloud/alert/AlertManager.java
index 1ae6b1b..eb5ac0c 100755
--- a/engine/components-api/src/com/cloud/alert/AlertManager.java
+++ b/engine/components-api/src/com/cloud/alert/AlertManager.java
@@ -50,6 +50,8 @@ public interface AlertManager extends Manager {
     public static final short ALERT_TYPE_DIRECT_ATTACHED_PUBLIC_IP = 24;
     public static final short ALERT_TYPE_LOCAL_STORAGE = 25;
     public static final short ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED = 26; // Generated when the resource limit exceeds the limit. Currently used for recurring snapshots only
+
+    public static final short ALERT_TYPE_SYNC = 27;
     
     static final ConfigKey<Double> StorageCapacityThreshold = new ConfigKey<Double>(Double.class, "cluster.storage.capacity.notificationthreshold", "Alert", "0.75",
         "Percentage (as a value between 0 and 1) of storage utilization above which alerts will be sent about low storage available.", true, ConfigKey.Scope.Cluster, null);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/components-api/src/com/cloud/vm/VmWork.java
----------------------------------------------------------------------
diff --git a/engine/components-api/src/com/cloud/vm/VmWork.java b/engine/components-api/src/com/cloud/vm/VmWork.java
new file mode 100644
index 0000000..3f9e71d
--- /dev/null
+++ b/engine/components-api/src/com/cloud/vm/VmWork.java
@@ -0,0 +1,45 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import java.io.Serializable;
+
+public class VmWork implements Serializable {
+	private static final long serialVersionUID = -6946320465729853589L;
+
+	long userId;
+	long accountId;
+	long vmId;
+
+    public VmWork(long userId, long accountId, long vmId) {
+        this.userId = userId;
+        this.accountId = accountId;
+        this.vmId = vmId;
+	}
+
+	public long getUserId() {
+		return userId;
+	}
+
+	public long getAccountId() {
+		return accountId;
+	}
+
+	public long getVmId() {
+		return vmId;
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml
----------------------------------------------------------------------
diff --git a/engine/orchestration/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml b/engine/orchestration/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml
index b5c4254..880002c 100644
--- a/engine/orchestration/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml
+++ b/engine/orchestration/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml
@@ -67,5 +67,6 @@
     
     <bean id="virtualMachineEntityImpl" class="org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntityImpl" />
     
+    <bean id="virtualMachinePowerStateSyncImpl" class="com.cloud.vm.VirtualMachinePowerStateSyncImpl" />
     
 </beans>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
index 555a58f..b92b41f 100755
--- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -18,6 +18,10 @@
 package com.cloud.vm;
 
 import java.net.URI;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
@@ -26,6 +30,7 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TimeZone;
 import java.util.UUID;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
@@ -45,6 +50,18 @@ import org.apache.cloudstack.framework.config.ConfigDepot;
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.Configurable;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.framework.jobs.AsyncJob;
+import org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext;
+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.AsyncJobVO;
+import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper;
+import org.apache.cloudstack.framework.jobs.impl.OutcomeImpl;
+import org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO;
+import org.apache.cloudstack.framework.messagebus.MessageBus;
+import org.apache.cloudstack.framework.messagebus.MessageHandler;
+import org.apache.cloudstack.jobs.JobInfo;
 import org.apache.cloudstack.managed.context.ManagedContextRunnable;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
@@ -152,8 +169,10 @@ import com.cloud.storage.dao.VolumeDao;
 import com.cloud.template.VirtualMachineTemplate;
 import com.cloud.user.Account;
 import com.cloud.user.User;
+import com.cloud.utils.DateUtil;
 import com.cloud.utils.Journal;
 import com.cloud.utils.Pair;
+import com.cloud.utils.Predicate;
 import com.cloud.utils.StringUtils;
 import com.cloud.utils.Ternary;
 import com.cloud.utils.component.ManagerBase;
@@ -162,8 +181,10 @@ import com.cloud.utils.db.DB;
 import com.cloud.utils.db.EntityManager;
 import com.cloud.utils.db.GlobalLock;
 import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallbackNoReturn;
 import com.cloud.utils.db.TransactionCallbackWithException;
 import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
+import com.cloud.utils.db.TransactionLegacy;
 import com.cloud.utils.db.TransactionStatus;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.exception.ExecutionException;
@@ -171,6 +192,7 @@ 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.dao.NicDao;
 import com.cloud.vm.dao.UserVmDao;
@@ -185,6 +207,8 @@ import com.cloud.vm.snapshot.dao.VMSnapshotDao;
 public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, Listener, Configurable {
     private static final Logger s_logger = Logger.getLogger(VirtualMachineManagerImpl.class);
 
+    private static final String VM_SYNC_ALERT_SUBJECT = "VM state sync alert";
+    
     @Inject
     DataStoreManager dataStoreMgr;
     @Inject
@@ -278,6 +302,11 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     @Inject
     DeploymentPlanningManager _dpMgr;
 
+    @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;
 
@@ -297,6 +326,19 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
             "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);
+    
+    static final ConfigKey<Boolean> VmJobEnabled = new ConfigKey<Boolean>("Advanced",
+            Boolean.class, "vm.job.enabled", "false", 
+            "True to enable new VM sync model. false to use the old way", 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", false);
+    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", false);
+    static final ConfigKey<Integer> VmJobStateReportInterval = new ConfigKey<Integer>("Advanced",
+    		Integer.class, "vm.job.report.interval", "60",
+            "Interval to send application level pings to make sure the connection is still working", false);
 
     ScheduledExecutorService _executor = null;
 
@@ -648,15 +690,46 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     }
 
     @Override
-    public void advanceStart(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) throws InsufficientCapacityException, ConcurrentOperationException,
-    ResourceUnavailableException {
+    public void advanceStart(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) 
+    	throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
+    	
         advanceStart(vmUuid, params, null);
     }
 
     @Override
     public void advanceStart(String vmUuid, Map<VirtualMachineProfile.Param, Object> params, DeploymentPlan planToDeploy) throws InsufficientCapacityException,
-    ConcurrentOperationException, ResourceUnavailableException {
-        CallContext cctxt = CallContext.current();
+		ConcurrentOperationException, ResourceUnavailableException {
+    	
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		orchestrateStart(vmUuid, params, planToDeploy);
+    	} else {
+    	    Outcome<VirtualMachine> outcome = startVmThroughJobQueue(vmUuid, params, planToDeploy);
+    	    
+	    	try {
+				VirtualMachine vm = outcome.get();
+			} catch (InterruptedException e) {
+				throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+				throw new RuntimeException("Execution excetion", e);
+			}
+	    	
+	    	Throwable jobException = retriveExecutionException(outcome.getJob());
+	    	if(jobException != null) {
+		    	if(jobException instanceof ConcurrentOperationException)
+		    		throw (ConcurrentOperationException)jobException;
+		    	else if(jobException instanceof ResourceUnavailableException)
+		    		throw (ResourceUnavailableException)jobException;
+	    	}
+    	}
+    }
+    
+    @Override
+    public void orchestrateStart(String vmUuid, Map<VirtualMachineProfile.Param, Object> params, DeploymentPlan planToDeploy) throws InsufficientCapacityException,
+    	ConcurrentOperationException, ResourceUnavailableException {
+        
+    	CallContext cctxt = CallContext.current();
         Account account = cctxt.getCallingAccount();
         User caller = cctxt.getCallingUser();
 
@@ -1146,7 +1219,38 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     }
 
     @Override
-    public void advanceStop(String vmUuid, boolean cleanUpEvenIfUnableToStop) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
+    public void advanceStop(String vmUuid, boolean cleanUpEvenIfUnableToStop) 
+    	throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
+    	
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		orchestrateStop(vmUuid, cleanUpEvenIfUnableToStop);
+    	} else {
+    	    Outcome<VirtualMachine> outcome = stopVmThroughJobQueue(vmUuid, cleanUpEvenIfUnableToStop);
+    	    
+	    	try {
+				VirtualMachine vm = outcome.get();
+			} catch (InterruptedException e) {
+				throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+				throw new RuntimeException("Execution excetion", e);
+			}
+	    	
+	    	Throwable jobException = retriveExecutionException(outcome.getJob());
+	    	if(jobException != null) {
+	    		if(jobException instanceof AgentUnavailableException)
+	    			throw (AgentUnavailableException)jobException;
+	    		else if(jobException instanceof ConcurrentOperationException)
+		    		throw (ConcurrentOperationException)jobException;
+		    	else if(jobException instanceof OperationTimedoutException)
+		    		throw (OperationTimedoutException)jobException;
+	    	}
+    	}
+    }
+
+    @Override
+    public void orchestrateStop(String vmUuid, boolean cleanUpEvenIfUnableToStop) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
         VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
 
         advanceStop(vm, cleanUpEvenIfUnableToStop);
@@ -1416,9 +1520,33 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
 
         return true;
     }
+    
+    public void storageMigration(String vmUuid, StoragePool destPool) {
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		orchestrateStorageMigration(vmUuid, destPool);
+    	} else {
+    	    Outcome<VirtualMachine> outcome = migrateVmStorageThroughJobQueue(vmUuid, destPool);
+    	    
+	    	try {
+				VirtualMachine vm = outcome.get();
+			} catch (InterruptedException e) {
+				throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+				throw new RuntimeException("Execution excetion", e);
+			}
+	    	
+	    	Throwable jobException = retriveExecutionException(outcome.getJob());
+	    	if(jobException != null) {
+		    	if(jobException instanceof RuntimeException)
+		    		throw (RuntimeException)jobException;
+	    	}
+    	}
+    }
 
     @Override
-    public void storageMigration(String vmUuid, StoragePool destPool) {
+    public void orchestrateStorageMigration(String vmUuid, StoragePool destPool) {
         VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
 
         try {
@@ -1474,7 +1602,38 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     }
 
     @Override
-    public void migrate(String vmUuid, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException {
+    public void migrate(String vmUuid, long srcHostId, DeployDestination dest) 
+    	throws ResourceUnavailableException, ConcurrentOperationException {
+    	
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		orchestrateMigrate(vmUuid, srcHostId, dest);
+    	} else {
+    	    Outcome<VirtualMachine> outcome = migrateVmThroughJobQueue(vmUuid, srcHostId, dest);
+    	    
+	    	try {
+				VirtualMachine vm = outcome.get();
+			} catch (InterruptedException e) {
+				throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+				throw new RuntimeException("Execution excetion", e);
+			}
+	    	
+	    	Throwable jobException = retriveExecutionException(outcome.getJob());
+	    	if(jobException != null) {
+		    	if(jobException instanceof ResourceUnavailableException)
+	    			throw (ResourceUnavailableException)jobException;
+	    		else if(jobException instanceof ConcurrentOperationException)
+		    		throw (ConcurrentOperationException)jobException;
+	    		else if(jobException instanceof RuntimeException)
+		    		throw (RuntimeException)jobException;
+	    	}
+    	}
+    }
+    
+    @Override
+    public void orchestrateMigrate(String vmUuid, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException {
         VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
         if (vm == null) {
             if (s_logger.isDebugEnabled()) {
@@ -1714,9 +1873,38 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         }
     }
 
+    public void migrateWithStorage(String vmUuid, long srcHostId, long destHostId, Map<Volume, StoragePool> volumeToPool) 
+    	throws ResourceUnavailableException, ConcurrentOperationException {
+    	
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		orchestrateMigrateWithStorage(vmUuid, srcHostId, destHostId, volumeToPool);
+    	} else {
+            Outcome<VirtualMachine> outcome = migrateVmWithStorageThroughJobQueue(vmUuid, srcHostId, destHostId, volumeToPool);
+    	    
+	    	try {
+                VirtualMachine vm = outcome.get();
+			} catch (InterruptedException e) {
+                throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+                throw new RuntimeException("Execution excetion", e);
+			}
+
+	    	Throwable jobException = retriveExecutionException(outcome.getJob());
+	    	if(jobException != null) {
+	    	    if(jobException instanceof ResourceUnavailableException)
+                    throw (ResourceUnavailableException)jobException;
+	    		else if(jobException instanceof ConcurrentOperationException)
+		    	    throw (ConcurrentOperationException)jobException;
+           }
+    	}
+    }
+    
     @Override
-    public void migrateWithStorage(String vmUuid, long srcHostId, long destHostId, Map<Volume, StoragePool> volumeToPool) throws ResourceUnavailableException,
-    ConcurrentOperationException {
+    public void orchestrateMigrateWithStorage(String vmUuid, long srcHostId, long destHostId, Map<Volume, StoragePool> volumeToPool) throws ResourceUnavailableException,
+    	ConcurrentOperationException {
+    	
         VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
 
         HostVO srcHost = _hostDao.findById(srcHostId);
@@ -1955,9 +2143,40 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
             throw new CloudRuntimeException("Unable to reboot a VM due to concurrent operation", e);
         }
     }
-
+    
     @Override
-    public void advanceReboot(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) throws InsufficientCapacityException, ConcurrentOperationException,
+    public void advanceReboot(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) 
+    	throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
+    	
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		orchestrateReboot(vmUuid, params);
+    	} else {
+    	    Outcome<VirtualMachine> outcome = rebootVmThroughJobQueue(vmUuid, params);
+    	    
+	    	try {
+				VirtualMachine vm = outcome.get();
+			} catch (InterruptedException e) {
+				throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+				throw new RuntimeException("Execution excetion", e);
+			}
+	    	
+	    	Throwable jobException = retriveExecutionException(outcome.getJob());
+	    	if(jobException != null) {
+	    		if(jobException instanceof ResourceUnavailableException)
+	    			throw (ResourceUnavailableException)jobException;
+	    		else if(jobException instanceof ConcurrentOperationException)
+		    		throw (ConcurrentOperationException)jobException;
+	    		else if(jobException instanceof InsufficientCapacityException)
+	    			throw (InsufficientCapacityException)jobException;
+	    	}
+    	}
+    }
+    
+    @Override
+    public void orchestrateReboot(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) throws InsufficientCapacityException, ConcurrentOperationException,
     ResourceUnavailableException {
         VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
 
@@ -2082,8 +2301,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         return commands;
     }
 
-
-
     public void deltaSync(Map<String, Ternary<String, State, String>> newStates) {
         Map<Long, AgentVmInfo> states = convertToInfos(newStates);
 
@@ -2616,6 +2833,16 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
                         }
                     }
                 }
+                
+                if(VmJobEnabled.value()) {
+	                if(ping.getHostVmStateReport() != null && ping.getHostVmStateReport().size() > 0) {                	
+	            		_syncMgr.processHostVmStatePingReport(agentId, ping.getHostVmStateReport());
+	                }
+                }
+                
+                // take the chance to scan VMs that are stuck in transitional states 
+                // and are missing from the report
+                scanStalledVMInTransitionStateOnUpHost(agentId);
                 processed = true;
             }
         }
@@ -2637,7 +2864,14 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         if (!(cmd instanceof StartupRoutingCommand)) {
             return;
         }
+        
+        if(s_logger.isDebugEnabled())
+        	s_logger.debug("Received startup command from hypervisor host. host id: " + agent.getId());
 
+        if(VmJobEnabled.value()) {
+        	_syncMgr.resetHostSyncState(agent.getId());
+        }
+        
         if (forRebalance) {
             s_logger.debug("Not processing listener " + this + " as connect happens on rebalance process");
             return;
@@ -2843,9 +3077,50 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         vmForUpdate.setServiceOfferingId(newSvcOff.getId());
         return _vmDao.update(vmId, vmForUpdate);
     }
-
+    
+    @Override
+    public NicProfile addVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) 
+    	throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
+    	
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		return orchestrateAddVmToNetwork(vm, network,requested);
+    	} else {
+            Outcome<VirtualMachine> outcome = addVmToNetworkThroughJobQueue(vm, network, requested);
+    	    
+	    	try {
+                outcome.get();
+			} catch (InterruptedException e) {
+                throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+                throw new RuntimeException("Execution excetion", e);
+			}
+	    	
+	    	AsyncJobVO jobVo = _entityMgr.findById(AsyncJobVO.class, outcome.getJob().getId());
+	    	if(jobVo.getResultCode() == JobInfo.Status.SUCCEEDED.ordinal()) {
+	    		
+	    		NicProfile nic = (NicProfile)JobSerializerHelper.fromObjectSerializedString(jobVo.getResult());
+	    		return nic;
+	    	} else {
+		    	Throwable jobException = retriveExecutionException(outcome.getJob());
+		    	if(jobException != null) {
+		    	    if(jobException instanceof ResourceUnavailableException)
+	                    throw (ResourceUnavailableException)jobException;
+		    		else if(jobException instanceof ConcurrentOperationException)
+			    	    throw (ConcurrentOperationException)jobException;
+		    		else if(jobException instanceof InsufficientCapacityException)
+			    	    throw (InsufficientCapacityException)jobException;
+		    		else if(jobException instanceof RuntimeException)
+			    	    throw (RuntimeException)jobException;
+	            }
+	    	    throw new RuntimeException("Job failed with unhandled exception");
+	    	}
+    	}
+    }
+    
     @Override
-    public NicProfile addVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) throws ConcurrentOperationException, ResourceUnavailableException,
+    public NicProfile orchestrateAddVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) throws ConcurrentOperationException, ResourceUnavailableException,
     InsufficientCapacityException {
         CallContext cctx = CallContext.current();
 
@@ -2910,9 +3185,48 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         NicTO nicTO = hvGuru.toNicTO(nic);
         return nicTO;
     }
+    
+    public boolean removeNicFromVm(VirtualMachine vm, Nic nic) 
+    	throws ConcurrentOperationException, ResourceUnavailableException {
+    	
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		return orchestrateRemoveNicFromVm(vm, nic);
+    	} else {
+            Outcome<VirtualMachine> outcome = removeNicFromVmThroughJobQueue(vm, nic);
+    	    
+	    	try {
+                outcome.get();
+			} catch (InterruptedException e) {
+                throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+                throw new RuntimeException("Execution excetion", e);
+			}
+
+	    	AsyncJobVO jobVo = _entityMgr.findById(AsyncJobVO.class, outcome.getJob().getId());
+	    	
+	    	if(jobVo.getResultCode() == JobInfo.Status.SUCCEEDED.ordinal()) {
+	    		Boolean result = (Boolean)JobSerializerHelper.fromObjectSerializedString(jobVo.getResult());
+	    		return result;
+	    	} else {
+		    	Throwable jobException = retriveExecutionException(outcome.getJob());
+		    	if(jobException != null) {
+		    	    if(jobException instanceof ResourceUnavailableException)
+	                    throw (ResourceUnavailableException)jobException;
+		    		else if(jobException instanceof ConcurrentOperationException)
+			    	    throw (ConcurrentOperationException)jobException;
+		    		else if(jobException instanceof RuntimeException)
+		    			throw (RuntimeException)jobException;
+	            }
+		    	
+		    	throw new RuntimeException("Job failed with un-handled exception");
+	    	}
+    	}
+    }
 
     @Override
-    public boolean removeNicFromVm(VirtualMachine vm, Nic nic) throws ConcurrentOperationException, ResourceUnavailableException {
+    public boolean orchestrateRemoveNicFromVm(VirtualMachine vm, Nic nic) throws ConcurrentOperationException, ResourceUnavailableException {
         CallContext cctx = CallContext.current();
         VMInstanceVO vmVO = _vmDao.findById(vm.getId());
         NetworkVO network = _networkDao.findById(nic.getNetworkId());
@@ -2972,6 +3286,13 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     @Override
     @DB
     public boolean removeVmFromNetwork(VirtualMachine vm, Network network, URI broadcastUri) throws ConcurrentOperationException, ResourceUnavailableException {
+    	// TODO will serialize on the VM object later to resolve operation conflicts
+    	return orchestrateRemoveVmFromNetwork(vm, network, broadcastUri);
+    }
+    
+    @Override
+    @DB
+    public boolean orchestrateRemoveVmFromNetwork(VirtualMachine vm, Network network, URI broadcastUri) throws ConcurrentOperationException, ResourceUnavailableException {
         CallContext cctx = CallContext.current();
         VMInstanceVO vmVO = _vmDao.findById(vm.getId());
         ReservationContext context = new ReservationContextImpl(null, null, cctx.getCallingUser(), cctx.getCallingAccount());
@@ -3107,10 +3428,40 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
             throw e;
         }
     }
+    
+    @Override
+    public void migrateForScale(String vmUuid, long srcHostId, DeployDestination dest, Long oldSvcOfferingId) 
+    	throws ResourceUnavailableException, ConcurrentOperationException {
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		orchestrateMigrateForScale(vmUuid, srcHostId, dest, oldSvcOfferingId);
+    	} else {
+    	    Outcome<VirtualMachine> outcome = migrateVmForScaleThroughJobQueue(vmUuid, srcHostId, dest, oldSvcOfferingId);
+    	    
+	    	try {
+				VirtualMachine vm = outcome.get();
+			} catch (InterruptedException e) {
+				throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+				throw new RuntimeException("Execution excetion", e);
+			}
+	    	
+	    	Throwable jobException = retriveExecutionException(outcome.getJob());
+	    	if(jobException != null) {
+	    		if(jobException instanceof ResourceUnavailableException)
+	    			throw (ResourceUnavailableException)jobException;
+	    		else if(jobException instanceof ConcurrentOperationException)
+		    		throw (ConcurrentOperationException)jobException;
+	    	}
+    	}
+    }
 
     @Override
-    public void migrateForScale(String vmUuid, long srcHostId, DeployDestination dest, Long oldSvcOfferingId) throws ResourceUnavailableException, ConcurrentOperationException {
-        VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+    public void orchestrateMigrateForScale(String vmUuid, long srcHostId, DeployDestination dest, Long oldSvcOfferingId) 
+    	throws ResourceUnavailableException, ConcurrentOperationException {
+        
+    	VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
         s_logger.info("Migrating " + vm + " to " + dest);
 
         vm.getServiceOfferingId();
@@ -3294,7 +3645,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     }
 
     public boolean unplugNic(Network network, NicTO nic, VirtualMachineTO vm, ReservationContext context, DeployDestination dest) throws ConcurrentOperationException,
-    ResourceUnavailableException {
+    	ResourceUnavailableException {
 
         boolean result = true;
         VMInstanceVO router = _vmDao.findById(vm.getId());
@@ -3325,9 +3676,46 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
 
         return result;
     }
-
+    
+    public VMInstanceVO reConfigureVm(String vmUuid, ServiceOffering oldServiceOffering, 
+    	boolean reconfiguringOnExistingHost) 
+    	throws ResourceUnavailableException, ConcurrentOperationException {
+
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		return orchestrateReConfigureVm(vmUuid, oldServiceOffering, reconfiguringOnExistingHost);
+    	} else {
+    	    Outcome<VirtualMachine> outcome = reconfigureVmThroughJobQueue(vmUuid, oldServiceOffering, reconfiguringOnExistingHost);
+    	    
+    	    VirtualMachine vm = null;
+	    	try {
+				vm = outcome.get();
+			} catch (InterruptedException e) {
+				throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+				throw new RuntimeException("Execution excetion", e);
+			}
+
+	    	AsyncJobVO jobVo = _entityMgr.findById(AsyncJobVO.class, outcome.getJob().getId());
+	    	if(jobVo.getResultCode() == JobInfo.Status.SUCCEEDED.ordinal()) {
+	    		return _entityMgr.findById(VMInstanceVO.class, vm.getId());
+	    	} else {
+		    	Throwable jobException = retriveExecutionException(outcome.getJob());
+		    	if(jobException != null) {
+		    		if(jobException instanceof ResourceUnavailableException)
+		    			throw (ResourceUnavailableException)jobException;
+		    		else if(jobException instanceof ConcurrentOperationException)
+			    		throw (ConcurrentOperationException)jobException;
+		    	}
+		    	
+		    	throw new RuntimeException("Failed with un-handled exception");
+	    	}
+    	}
+    }
+    
     @Override
-    public VMInstanceVO reConfigureVm(String vmUuid, ServiceOffering oldServiceOffering, boolean reconfiguringOnExistingHost) throws ResourceUnavailableException,
+    public VMInstanceVO orchestrateReConfigureVm(String vmUuid, ServiceOffering oldServiceOffering, boolean reconfiguringOnExistingHost) throws ResourceUnavailableException,
     ConcurrentOperationException {
         VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
 
@@ -3389,7 +3777,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     @Override
     public ConfigKey<?>[] getConfigKeys() {
         return new ConfigKey<?>[] {ClusterDeltaSyncInterval, StartRetry, VmDestroyForcestop, VmOpCancelInterval, VmOpCleanupInterval, VmOpCleanupWait, VmOpLockStateRetry,
-                VmOpWaitInterval};
+                VmOpWaitInterval, VmJobCheckInterval, VmJobTimeout, VmJobStateReportInterval};
     }
 
     public List<StoragePoolAllocator> getStoragePoolAllocators() {
@@ -3401,4 +3789,920 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         this._storagePoolAllocators = storagePoolAllocators;
     }
 
+    
+    //
+    // PowerState report handling for out-of-band changes and handling of left-over transitional VM states
+    //
+    
+    @MessageHandler(topic = Topics.VM_POWER_STATE)
+    private void HandlePownerStateReport(Object target, String subject, String senderAddress, Object args) {
+    	assert(args != null);
+    	Long vmId = (Long)args;
+    	
+    	List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+    		VirtualMachine.Type.Instance, vmId);
+    	if(pendingWorkJobs.size() == 0) {
+    		// there is no pending operation job
+            VMInstanceVO vm = _vmDao.findById(vmId);
+    		if(vm != null) {
+    			switch(vm.getPowerState()) {
+    			case PowerOn :
+    				handlePowerOnReportWithNoPendingJobsOnVM(vm);
+    				break;
+    				
+    			case PowerOff :
+    				handlePowerOffReportWithNoPendingJobsOnVM(vm);
+    				break;
+
+    			// PowerUnknown shouldn't be reported, it is a derived
+    			// VM power state from host state (host un-reachable
+    			case PowerUnknown :
+    			default :
+    				assert(false);
+    				break;
+    			}
+    		} else {
+    			s_logger.warn("VM " + vmId + " no longer exists when processing VM state report");
+    		}
+    	} else {
+    		// TODO, do job wake-up signalling, since currently async job wake-up is not in use
+    		// we will skip it for nows
+    	}
+    }
+    
+    private void handlePowerOnReportWithNoPendingJobsOnVM(VMInstanceVO vm) {
+    	//
+    	// 	1) handle left-over transitional VM states
+    	//	2) handle out of band VM live migration
+    	//	3) handle out of sync stationary states, marking VM from Stopped to Running with
+    	//	   alert messages
+    	//
+    	switch(vm.getState()) {
+    	case Starting :
+    		try {
+    			stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOnReport, vm.getPowerHostId());
+    		} catch(NoTransitionException e) {
+    			s_logger.warn("Unexpected VM state transition exception, race-condition?", e);
+    		}
+    		
+    		// we need to alert admin or user about this risky state transition
+    		_alertMgr.sendAlert(AlertManager.ALERT_TYPE_SYNC, vm.getDataCenterId(), vm.getPodIdToDeployIn(),
+    			VM_SYNC_ALERT_SUBJECT, "VM " + vm.getHostName() + "(" + vm.getInstanceName() + ") state is sync-ed (Starting -> Running) from out-of-context transition. VM network environment may need to be reset");
+    		break;
+    		
+    	case Running :
+    		try {
+    			if(vm.getHostId() != null && vm.getHostId().longValue() != vm.getPowerHostId().longValue())
+    				s_logger.info("Detected out of band VM migration from host " + vm.getHostId() + " to host " + vm.getPowerHostId());
+    			stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOnReport, vm.getPowerHostId());
+    		} catch(NoTransitionException e) {
+    			s_logger.warn("Unexpected VM state transition exception, race-condition?", e);
+    		}
+    		break;
+    		
+    	case Stopping :
+    	case Stopped :
+    		try {
+    			stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOnReport, vm.getPowerHostId());
+    		} catch(NoTransitionException e) {
+    			s_logger.warn("Unexpected VM state transition exception, race-condition?", e);
+    		}
+      		_alertMgr.sendAlert(AlertManager.ALERT_TYPE_SYNC, vm.getDataCenterId(), vm.getPodIdToDeployIn(),
+        			VM_SYNC_ALERT_SUBJECT, "VM " + vm.getHostName() + "(" + vm.getInstanceName() + ") state is sync-ed (" + vm.getState() + " -> Running) from out-of-context transition. VM network environment may need to be reset");
+          	break;
+    		
+    	case Destroyed :
+    	case Expunging :
+    		s_logger.info("Receive power on report when VM is in destroyed or expunging state. vm: "
+        		    + vm.getId() + ", state: " + vm.getState());
+    		break;
+    		
+    	case Migrating :
+    		try {
+    			stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOnReport, vm.getPowerHostId());
+    		} catch(NoTransitionException e) {
+    			s_logger.warn("Unexpected VM state transition exception, race-condition?", e);
+    		}
+    		break;
+    		
+    	case Error :
+    	default :
+    		s_logger.info("Receive power on report when VM is in error or unexpected state. vm: "
+    		    + vm.getId() + ", state: " + vm.getState());
+    		break;
+    	}
+    }
+    
+    private void handlePowerOffReportWithNoPendingJobsOnVM(VMInstanceVO vm) {
+
+    	// 	1) handle left-over transitional VM states
+    	//	2) handle out of sync stationary states, schedule force-stop to release resources
+    	//
+    	switch(vm.getState()) {
+    	case Starting :
+    	case Stopping :
+    	case Stopped :
+    	case Migrating :
+    		try {
+    			stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOffReport, vm.getPowerHostId());
+    		} catch(NoTransitionException e) {
+    			s_logger.warn("Unexpected VM state transition exception, race-condition?", e);
+    		}
+      		_alertMgr.sendAlert(AlertManager.ALERT_TYPE_SYNC, vm.getDataCenterId(), vm.getPodIdToDeployIn(),
+        			VM_SYNC_ALERT_SUBJECT, "VM " + vm.getHostName() + "(" + vm.getInstanceName() + ") state is sync-ed (" + vm.getState() + " -> Stopped) from out-of-context transition.");
+      		// TODO: we need to forcely release all resource allocation
+          	break;
+    		
+    	case Running :
+    	case Destroyed :
+    	case Expunging :
+    		break;
+    		
+    	case Error :
+    	default :
+    		break;
+    	}
+    }
+    
+    private void scanStalledVMInTransitionStateOnUpHost(long hostId) {
+    	//
+    	// Check VM that is stuck in Starting, Stopping, Migrating states, we won't check
+    	// VMs in expunging state (this need to be handled specially)
+    	//
+    	// checking condition
+    	//	1) no pending VmWork job
+    	//	2) on hostId host and host is UP
+    	//
+    	// When host is UP, soon or later we will get a report from the host about the VM,
+    	// however, if VM is missing from the host report (it may happen in out of band changes
+    	// or from designed behave of XS/KVM), the VM may not get a chance to run the state-sync logic
+    	//
+    	// Therefor, we will scan thoses VMs on UP host based on last update timestamp, if the host is UP
+    	// and a VM stalls for status update, we will consider them to be powered off
+    	// (which is relatively safe to do so)
+    	
+    	long stallThresholdInMs = VmJobStateReportInterval.value() + (VmJobStateReportInterval.value() >> 1);
+    	Date cutTime = new Date(DateUtil.currentGMTTime().getTime() - stallThresholdInMs);
+    	List<Long> mostlikelyStoppedVMs = listStalledVMInTransitionStateOnUpHost(hostId, cutTime);
+    	for(Long vmId : mostlikelyStoppedVMs) {
+    		VMInstanceVO vm = _vmDao.findById(vmId);
+    		assert(vm != null);
+    		handlePowerOffReportWithNoPendingJobsOnVM(vm);
+    	}
+    	
+    	List<Long> vmsWithRecentReport = listVMInTransitionStateWithRecentReportOnUpHost(hostId, cutTime);
+    	for(Long vmId : vmsWithRecentReport) {
+    		VMInstanceVO vm = _vmDao.findById(vmId);
+    		assert(vm != null);
+    		if(vm.getPowerState() == PowerState.PowerOn)
+    			handlePowerOnReportWithNoPendingJobsOnVM(vm);
+    		else
+    			handlePowerOffReportWithNoPendingJobsOnVM(vm);
+    	}
+    }
+    
+    private void scanStalledVMInTransitionStateOnDisconnectedHosts() {
+    	Date cutTime = new Date(DateUtil.currentGMTTime().getTime() - VmOpWaitInterval.value()*1000);
+    	List<Long> stuckAndUncontrollableVMs = listStalledVMInTransitionStateOnDisconnectedHosts(cutTime);
+    	for(Long vmId : stuckAndUncontrollableVMs) {
+    		VMInstanceVO vm = _vmDao.findById(vmId);
+    		
+    		// We now only alert administrator about this situation
+      		_alertMgr.sendAlert(AlertManager.ALERT_TYPE_SYNC, vm.getDataCenterId(), vm.getPodIdToDeployIn(),
+        		VM_SYNC_ALERT_SUBJECT, "VM " + vm.getHostName() + "(" + vm.getInstanceName() + ") is stuck in " + vm.getState() + " state and its host is unreachable for too long");
+    	}
+    }
+    
+    
+    // VMs that in transitional state without recent power state report
+    private List<Long> listStalledVMInTransitionStateOnUpHost(long hostId, Date cutTime) {
+    	String sql = "SELECT i.* FROM vm_instance as i, host as h WHERE h.status = 'UP' " +
+                     "AND h.id = ? AND i.power_state_update_time < ? AND i.host_id = h.id " +
+    			     "AND (i.state ='Starting' OR i.state='Stopping' OR i.state='Migrating') " +
+    			     "AND i.id NOT IN (SELECT w.vm_instance_id FROM vm_work_job AS w JOIN async_job AS j ON w.id = j.id WHERE j.job_status = ?)";
+    	
+    	List<Long> l = new ArrayList<Long>();
+    	TransactionLegacy txn = null;
+    	try {
+    		txn = TransactionLegacy.open(TransactionLegacy.CLOUD_DB);
+    	
+	        PreparedStatement pstmt = null;
+	        try {
+	            pstmt = txn.prepareAutoCloseStatement(sql);
+	            
+	            pstmt.setLong(1, hostId);
+	 	        pstmt.setString(2, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutTime));
+	 	        pstmt.setInt(3, JobInfo.Status.IN_PROGRESS.ordinal());
+	            ResultSet rs = pstmt.executeQuery();
+	            while(rs.next()) {
+	            	l.add(rs.getLong(1));
+	            }
+	        } catch (SQLException e) {
+	        } catch (Throwable e) {
+	        }
+        
+    	} finally {
+    		if(txn != null)
+    			txn.close();
+    	}
+        return l;
+    }
+    
+    // VMs that in transitional state and recently have power state update
+    private List<Long> listVMInTransitionStateWithRecentReportOnUpHost(long hostId, Date cutTime) {
+    	String sql = "SELECT i.* FROM vm_instance as i, host as h WHERE h.status = 'UP' " +
+                     "AND h.id = ? AND i.power_state_update_time > ? AND i.host_id = h.id " +
+    			     "AND (i.state ='Starting' OR i.state='Stopping' OR i.state='Migrating') " +
+    			     "AND i.id NOT IN (SELECT w.vm_instance_id FROM vm_work_job AS w JOIN async_job AS j ON w.id = j.id WHERE j.job_status = ?)";
+    	
+    	List<Long> l = new ArrayList<Long>();
+    	TransactionLegacy txn = null;
+    	try {
+    		txn = TransactionLegacy.open(TransactionLegacy.CLOUD_DB);
+	        PreparedStatement pstmt = null;
+	        try {
+	            pstmt = txn.prepareAutoCloseStatement(sql);
+	            
+	            pstmt.setLong(1, hostId);
+	 	        pstmt.setString(2, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutTime));
+	 	        pstmt.setInt(3, JobInfo.Status.IN_PROGRESS.ordinal());
+	            ResultSet rs = pstmt.executeQuery();
+	            while(rs.next()) {
+	            	l.add(rs.getLong(1));
+	            }
+	        } catch (SQLException e) {
+	        } catch (Throwable e) {
+	        }
+	        return l;
+    	} finally {
+    		if(txn != null)
+    			txn.close();
+    	}
+    }
+    
+    private List<Long> listStalledVMInTransitionStateOnDisconnectedHosts(Date cutTime) {
+    	String sql = "SELECT i.* FROM vm_instance as i, host as h WHERE h.status != 'UP' " +
+                 "AND i.power_state_update_time < ? AND i.host_id = h.id " +
+			     "AND (i.state ='Starting' OR i.state='Stopping' OR i.state='Migrating') " +
+			     "AND i.id NOT IN (SELECT w.vm_instance_id FROM vm_work_job AS w JOIN async_job AS j ON w.id = j.id WHERE j.job_status = ?)";
+	
+    	List<Long> l = new ArrayList<Long>();
+    	TransactionLegacy txn = null;
+    	try {
+    		txn = TransactionLegacy.open(TransactionLegacy.CLOUD_DB);
+	    	PreparedStatement pstmt = null;
+	    	try {
+		       pstmt = txn.prepareAutoCloseStatement(sql);
+		       
+		       pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutTime));
+		       pstmt.setInt(2, JobInfo.Status.IN_PROGRESS.ordinal());
+		       ResultSet rs = pstmt.executeQuery();
+		       while(rs.next()) {
+		       	l.add(rs.getLong(1));
+		       }
+	    	} catch (SQLException e) {
+	    	} catch (Throwable e) {
+	    	}
+	    	return l;
+    	} finally {
+    		if(txn != null)
+    			txn.close();
+    	}
+    }
+    
+    //
+    // VM operation based on new sync model
+    //
+    
+    public class VmStateSyncOutcome extends OutcomeImpl<VirtualMachine> {
+        private long _vmId;
+
+        public VmStateSyncOutcome(final AsyncJob job, final PowerState desiredPowerState, final long vmId, final Long srcHostIdForMigration) {
+            super(VirtualMachine.class, job, VmJobCheckInterval.value(), new Predicate() {
+                @Override
+                public boolean checkCondition() {
+                    VMInstanceVO instance = _vmDao.findById(vmId);
+                    if (instance.getPowerState() == desiredPowerState && (srcHostIdForMigration != null && instance.getPowerHostId() != srcHostIdForMigration))
+                        return true;
+                    return false;
+                }
+            }, Topics.VM_POWER_STATE, AsyncJob.Topics.JOB_STATE);
+            _vmId = vmId;
+        }
+
+        @Override
+        protected VirtualMachine retrieve() {
+            return _vmDao.findById(_vmId);
+        }
+    }
+
+    public class VmJobSyncOutcome extends OutcomeImpl<VirtualMachine> {
+        private long _vmId;
+
+        public VmJobSyncOutcome(final AsyncJob job, final long vmId) {
+            super(VirtualMachine.class, job, VmJobCheckInterval.value(), new Predicate() {
+                @Override
+                public boolean checkCondition() {
+                	AsyncJobVO jobVo = _entityMgr.findById(AsyncJobVO.class, job.getId());
+                	assert(jobVo != null);
+                	if(jobVo == null || jobVo.getStatus() != JobInfo.Status.IN_PROGRESS)
+                        return true;
+                	
+                    return false;
+                }
+            }, AsyncJob.Topics.JOB_STATE);
+            _vmId = vmId;
+        }
+
+        @Override
+        protected VirtualMachine retrieve() {
+            return _vmDao.findById(_vmId);
+        }
+    }
+    
+    public Throwable retriveExecutionException(AsyncJob job) {
+    	assert(job != null);
+    	assert(job.getDispatcher().equals(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER));
+    	
+    	AsyncJobVO jobVo = this._entityMgr.findById(AsyncJobVO.class, job.getId());
+    	if(jobVo != null && jobVo.getResult() != null) {
+    		Object obj = JobSerializerHelper.fromSerializedString(job.getResult());
+    		
+    		if(obj != null && obj instanceof Throwable)
+    			return (Throwable)obj;
+    	}
+    	return null;
+    }
+    
+    public Outcome<VirtualMachine> startVmThroughJobQueue(final String vmUuid, 
+    	final Map<VirtualMachineProfile.Param, Object> params, 
+    	final DeploymentPlan planToDeploy) {
+        
+    	final CallContext context = CallContext.current();
+        final User callingUser = context.getCallingUser();
+        final Account callingAccount = context.getCallingAccount();
+
+        final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+    	    	VmWorkJobVO workJob = null;
+    	    	
+    	        _vmDao.lockRow(vm.getId(), true);
+    	        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(VirtualMachine.Type.Instance, 
+    	        	vm.getId(), VmWorkStart.class.getName());
+    	        
+    	        if (pendingWorkJobs.size() > 0) {
+    	            assert (pendingWorkJobs.size() == 1);
+    	            workJob = pendingWorkJobs.get(0);
+    	        } else {
+    	            workJob = new VmWorkJobVO(context.getContextId());
+
+    	            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+    	            workJob.setCmd(VmWorkStart.class.getName());
+
+    	            workJob.setAccountId(callingAccount.getId());
+    	            workJob.setUserId(callingUser.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(callingUser.getId(), callingAccount.getId(), vm.getId());
+    	            workInfo.setPlan(planToDeploy);
+    	            workInfo.setParams(params);
+    	            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+
+    	            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+    	    	}
+    	        
+	            // Transaction syntax sugar has a cost here
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+    		}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmStateSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), 
+        	VirtualMachine.PowerState.PowerOn, vm.getId(), null);
+    }
+    
+    public Outcome<VirtualMachine> stopVmThroughJobQueue(final String vmUuid, final boolean cleanup) {
+        final CallContext context = CallContext.current();
+        final Account account = context.getCallingAccount();
+        final User user = context.getCallingUser();
+
+        final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+    	
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+	        		VirtualMachine.Type.Instance, vm.getId(), 
+	        		VmWorkStop.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkStop.class.getName());
+		
+		            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(user.getId(), account.getId(), vm.getId(), cleanup);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		    	}
+		        
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+    		}
+		});
+
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmStateSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), 
+        	VirtualMachine.PowerState.PowerOff, vm.getId(), null);
+    }
+    
+    public Outcome<VirtualMachine> rebootVmThroughJobQueue(final String vmUuid, 
+    	final Map<VirtualMachineProfile.Param, Object> params) {
+    	
+        final CallContext context = CallContext.current();
+        final Account account = context.getCallingAccount();
+        final User user = context.getCallingUser();
+
+        final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+    	
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+	        		VirtualMachine.Type.Instance, vm.getId(), 
+	        		VmWorkReboot.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkReboot.class.getName());
+		
+		            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)
+		            VmWorkReboot workInfo = new VmWorkReboot(user.getId(), account.getId(), vm.getId(), params);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		    	}
+		        
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+    		}
+		});
+
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmJobSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), 
+        	vm.getId());
+    }
+    
+    public Outcome<VirtualMachine> migrateVmThroughJobQueue(final String vmUuid, final long srcHostId, final DeployDestination dest) {
+        final CallContext context = CallContext.current();
+        final User user = context.getCallingUser();
+        final Account account = context.getCallingAccount();
+
+        final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+	
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+		        	VirtualMachine.Type.Instance, vm.getId(), 
+		        	VmWorkMigrate.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		                    
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkMigrate.class.getName());
+		
+		            workJob.setAccountId(account.getId());
+		            workJob.setUserId(user.getId());
+		            workJob.setVmType(vm.getType());
+		            workJob.setVmInstanceId(vm.getId());
+		
+		            // save work context info (there are some duplications)
+		            VmWorkMigrate workInfo = new VmWorkMigrate(user.getId(), account.getId(), vm.getId(), srcHostId, dest);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		        }
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+	    	}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmStateSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), 
+        	VirtualMachine.PowerState.PowerOn, vm.getId(), vm.getPowerHostId());
+    }
+    
+    public Outcome<VirtualMachine> migrateVmWithStorageThroughJobQueue(
+    	final String vmUuid, final long srcHostId, final long destHostId,
+    	final Map<Volume, StoragePool> volumeToPool) {
+    	
+        final CallContext context = CallContext.current();
+        final User user = context.getCallingUser();
+        final Account account = context.getCallingAccount();
+
+        final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+	
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+		        	VirtualMachine.Type.Instance, vm.getId(), 
+		        	VmWorkMigrateWithStorage.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		                    
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkMigrate.class.getName());
+		
+		            workJob.setAccountId(account.getId());
+		            workJob.setUserId(user.getId());
+		            workJob.setVmType(vm.getType());
+		            workJob.setVmInstanceId(vm.getId());
+		
+		            // save work context info (there are some duplications)
+		            VmWorkMigrateWithStorage workInfo = new VmWorkMigrateWithStorage(user.getId(), account.getId(), vm.getId(), 
+		            	srcHostId, destHostId, volumeToPool);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		        }
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+	    	}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmStateSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), 
+        	VirtualMachine.PowerState.PowerOn, vm.getId(), destHostId);
+    }
+    
+    //
+    // TODO build a common pattern to reduce code duplication in following methods
+    // no time for this at current iteration
+    //
+    public Outcome<VirtualMachine> migrateVmForScaleThroughJobQueue(
+    	final String vmUuid, final long srcHostId, final DeployDestination dest, final Long newSvcOfferingId) {
+    	
+        final CallContext context = CallContext.current();
+        final User user = context.getCallingUser();
+        final Account account = context.getCallingAccount();
+
+        final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+	
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+		        	VirtualMachine.Type.Instance, vm.getId(), 
+		        	VmWorkMigrateForScale.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		                    
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkMigrate.class.getName());
+		
+		            workJob.setAccountId(account.getId());
+		            workJob.setUserId(user.getId());
+		            workJob.setVmType(vm.getType());
+		            workJob.setVmInstanceId(vm.getId());
+		
+		            // save work context info (there are some duplications)
+		            VmWorkMigrateForScale workInfo = new VmWorkMigrateForScale(user.getId(), account.getId(), vm.getId(), 
+		            	srcHostId, dest, newSvcOfferingId);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		        }
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+	    	}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmJobSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), vm.getId());
+    }
+    
+    public Outcome<VirtualMachine> migrateVmStorageThroughJobQueue(
+    	final String vmUuid, final StoragePool destPool) {
+    	
+        final CallContext context = CallContext.current();
+        final User user = context.getCallingUser();
+        final Account account = context.getCallingAccount();
+
+        final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+	
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+		        	VirtualMachine.Type.Instance, vm.getId(), 
+		        	VmWorkStorageMigration.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		                    
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkStorageMigration.class.getName());
+		
+		            workJob.setAccountId(account.getId());
+		            workJob.setUserId(user.getId());
+		            workJob.setVmType(vm.getType());
+		            workJob.setVmInstanceId(vm.getId());
+		
+		            // save work context info (there are some duplications)
+		            VmWorkStorageMigration workInfo = new VmWorkStorageMigration(user.getId(), account.getId(), vm.getId(), 
+		            	destPool);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		        }
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+	    	}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmJobSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), vm.getId());
+    }
+    
+    public Outcome<VirtualMachine> addVmToNetworkThroughJobQueue(
+		final VirtualMachine vm, final Network network, final NicProfile requested) {
+    	
+        final CallContext context = CallContext.current();
+        final User user = context.getCallingUser();
+        final Account account = context.getCallingAccount();
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+	
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+		        	VirtualMachine.Type.Instance, vm.getId(), 
+		        	VmWorkAddVmToNetwork.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		                    
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkAddVmToNetwork.class.getName());
+		
+		            workJob.setAccountId(account.getId());
+		            workJob.setUserId(user.getId());
+		            workJob.setVmType(vm.getType());
+		            workJob.setVmInstanceId(vm.getId());
+		
+		            // save work context info (there are some duplications)
+		            VmWorkAddVmToNetwork workInfo = new VmWorkAddVmToNetwork(user.getId(), account.getId(), vm.getId(), 
+		            	network, requested);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		        }
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+	    	}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmJobSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), vm.getId());
+    }
+    
+    public Outcome<VirtualMachine> removeNicFromVmThroughJobQueue(
+    	final VirtualMachine vm, final Nic nic) {
+    	
+        final CallContext context = CallContext.current();
+        final User user = context.getCallingUser();
+        final Account account = context.getCallingAccount();
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+	
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+		        	VirtualMachine.Type.Instance, vm.getId(), 
+		        	VmWorkRemoveNicFromVm.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		                    
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkRemoveNicFromVm.class.getName());
+		
+		            workJob.setAccountId(account.getId());
+		            workJob.setUserId(user.getId());
+		            workJob.setVmType(vm.getType());
+		            workJob.setVmInstanceId(vm.getId());
+		
+		            // save work context info (there are some duplications)
+		            VmWorkRemoveNicFromVm workInfo = new VmWorkRemoveNicFromVm(user.getId(), account.getId(), vm.getId(), 
+		            	nic);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		        }
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+	    	}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmJobSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), vm.getId());
+    }
+
+    public Outcome<VirtualMachine> removeVmFromNetworkThroughJobQueue(
+    	final VirtualMachine vm, final Network network, final URI broadcastUri) {
+    	
+        final CallContext context = CallContext.current();
+        final User user = context.getCallingUser();
+        final Account account = context.getCallingAccount();
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+	
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+		        	VirtualMachine.Type.Instance, vm.getId(), 
+		        	VmWorkRemoveVmFromNetwork.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		                    
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkRemoveVmFromNetwork.class.getName());
+		
+		            workJob.setAccountId(account.getId());
+		            workJob.setUserId(user.getId());
+		            workJob.setVmType(vm.getType());
+		            workJob.setVmInstanceId(vm.getId());
+		
+		            // save work context info (there are some duplications)
+		            VmWorkRemoveVmFromNetwork workInfo = new VmWorkRemoveVmFromNetwork(user.getId(), account.getId(), vm.getId(), 
+		            	network, broadcastUri);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		        }
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+	    	}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmJobSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), vm.getId());
+    }
+    
+    public Outcome<VirtualMachine> reconfigureVmThroughJobQueue(
+    	final String vmUuid, final ServiceOffering oldServiceOffering, final boolean reconfiguringOnExistingHost) {
+    	
+        final CallContext context = CallContext.current();
+        final User user = context.getCallingUser();
+        final Account account = context.getCallingAccount();
+
+        final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+	
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+		        	VirtualMachine.Type.Instance, vm.getId(), 
+		        	VmWorkReconfigure.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		                    
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkReconfigure.class.getName());
+		
+		            workJob.setAccountId(account.getId());
+		            workJob.setUserId(user.getId());
+		            workJob.setVmType(vm.getType());
+		            workJob.setVmInstanceId(vm.getId());
+		
+		            // save work context info (there are some duplications)
+		            VmWorkReconfigure workInfo = new VmWorkReconfigure(user.getId(), account.getId(), vm.getId(), 
+		            		oldServiceOffering, reconfiguringOnExistingHost);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		        }
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+	    	}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmJobSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), vm.getId());
+    }
+   
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java b/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java
index 7a23ddd..dacc8d0 100644
--- a/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java
+++ b/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java
@@ -19,7 +19,6 @@ package com.cloud.vm;
 import java.util.Map;
 
 import com.cloud.agent.api.HostVmStateReportEntry;
-import com.cloud.vm.VirtualMachine.PowerState;
 
 public interface VirtualMachinePowerStateSync {
 	
@@ -28,5 +27,5 @@ public interface VirtualMachinePowerStateSync {
 	void processHostVmStateReport(long hostId, Map<String, HostVmStateReportEntry> report);
 	
 	// to adapt legacy ping report
-	void processHostVmStatePingReport(long hostId, Map<String, PowerState> report);
+	void processHostVmStatePingReport(long hostId, Map<String, HostVmStateReportEntry> report);
 }


[2/6] git commit: updated refs/heads/master to 278ef81

Posted by ke...@apache.org.
side-by-side VM sync management at manager level


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/278ef81a
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/278ef81a
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/278ef81a

Branch: refs/heads/master
Commit: 278ef81a8339e8dfc6ecd9dd04701d6713b9c062
Parents: 2d42b2d
Author: Kelven Yang <ke...@gmail.com>
Authored: Wed Nov 20 17:46:45 2013 -0800
Committer: Kelven Yang <ke...@gmail.com>
Committed: Wed Nov 20 17:59:38 2013 -0800

----------------------------------------------------------------------
 api/src/com/cloud/vm/VirtualMachine.java        |    7 +-
 .../apache/cloudstack/api/InternalIdentity.java |    4 +-
 .../apache/cloudstack/context/CallContext.java  |   12 +
 .../src/com/cloud/vm/VirtualMachineManager.java |   30 +-
 .../src/com/cloud/alert/AlertManager.java       |    2 +
 .../components-api/src/com/cloud/vm/VmWork.java |   45 +
 ...spring-engine-orchestration-core-context.xml |    1 +
 .../com/cloud/vm/VirtualMachineManagerImpl.java | 1348 +++++++++++++++++-
 .../cloud/vm/VirtualMachinePowerStateSync.java  |    3 +-
 .../vm/VirtualMachinePowerStateSyncImpl.java    |   24 +-
 .../src/com/cloud/vm/VmWorkAddVmToNetwork.java  |   42 +
 .../src/com/cloud/vm/VmWorkJobDispatcher.java   |  152 ++
 .../src/com/cloud/vm/VmWorkMigrate.java         |   86 ++
 .../src/com/cloud/vm/VmWorkMigrateForScale.java |   48 +
 .../com/cloud/vm/VmWorkMigrateWithStorage.java  |   52 +
 .../src/com/cloud/vm/VmWorkReboot.java          |   68 +
 .../src/com/cloud/vm/VmWorkReconfigure.java     |   43 +
 .../src/com/cloud/vm/VmWorkRemoveNicFromVm.java |   33 +
 .../com/cloud/vm/VmWorkRemoveVmFromNetwork.java |   43 +
 .../src/com/cloud/vm/VmWorkSerializer.java      |   75 +
 .../src/com/cloud/vm/VmWorkStart.java           |  125 ++
 .../src/com/cloud/vm/VmWorkStop.java            |   32 +
 .../com/cloud/vm/VmWorkStorageMigration.java    |   35 +
 .../dao/ManagementServerHostDaoImpl.java        |    7 +-
 .../core/spring-framework-jobs-core-context.xml |    4 +-
 .../jobs/AsyncJobExecutionContext.java          |   10 +-
 26 files changed, 2274 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/api/src/com/cloud/vm/VirtualMachine.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java
index 9a8d883..3400898 100755
--- a/api/src/com/cloud/vm/VirtualMachine.java
+++ b/api/src/com/cloud/vm/VirtualMachine.java
@@ -213,7 +213,12 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I
          * UserBareMetal is only used for selecting VirtualMachineGuru, there is no
          * VM with this type. UserBareMetal should treat exactly as User.
          */
-        UserBareMetal(false);
+        UserBareMetal(false),
+        
+        /*
+         * General VM type for queuing VM orchestration work
+         */
+        Instance(false);
 
         boolean _isUsedBySystem;
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/api/src/org/apache/cloudstack/api/InternalIdentity.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/InternalIdentity.java b/api/src/org/apache/cloudstack/api/InternalIdentity.java
index 1dfeb8c..4149dd1 100644
--- a/api/src/org/apache/cloudstack/api/InternalIdentity.java
+++ b/api/src/org/apache/cloudstack/api/InternalIdentity.java
@@ -16,11 +16,13 @@
 // under the License.
 package org.apache.cloudstack.api;
 
+import java.io.Serializable;
+
 // This interface is a contract that getId() will give the internal
 // ID of an entity which extends this interface
 // Any class having an internal ID in db table/schema should extend this
 // For example, all ControlledEntity, OwnedBy would have an internal ID
 
-public interface InternalIdentity {
+public interface InternalIdentity extends Serializable {
     long getId();
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/api/src/org/apache/cloudstack/context/CallContext.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/context/CallContext.java b/api/src/org/apache/cloudstack/context/CallContext.java
index 5439aee..3cdccc5 100644
--- a/api/src/org/apache/cloudstack/context/CallContext.java
+++ b/api/src/org/apache/cloudstack/context/CallContext.java
@@ -197,6 +197,18 @@ public class CallContext {
         }
         return register(user, account);
     }
+    
+    public static CallContext register(long callingUserId, long callingAccountId, String contextId) throws CloudAuthenticationException {
+        Account account = s_entityMgr.findById(Account.class, callingAccountId);
+        if (account == null) {
+            throw new CloudAuthenticationException("The account is no longer current.").add(Account.class, Long.toString(callingAccountId));
+        }
+        User user = s_entityMgr.findById(User.class, callingUserId);
+        if (user == null) {
+            throw new CloudAuthenticationException("The user is no longer current.").add(User.class, Long.toString(callingUserId));
+        }
+        return register(user, account, contextId);
+    }
 
     public static void unregisterAll() {
         while ( unregister() != null ) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/api/src/com/cloud/vm/VirtualMachineManager.java
----------------------------------------------------------------------
diff --git a/engine/api/src/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/com/cloud/vm/VirtualMachineManager.java
index 35804af..9d19cf5 100644
--- a/engine/api/src/com/cloud/vm/VirtualMachineManager.java
+++ b/engine/api/src/com/cloud/vm/VirtualMachineManager.java
@@ -108,8 +108,13 @@ public interface VirtualMachineManager extends Manager {
     void advanceStart(String vmUuid, Map<VirtualMachineProfile.Param, Object> params, DeploymentPlan planToDeploy) throws InsufficientCapacityException,
             ResourceUnavailableException, ConcurrentOperationException, OperationTimedoutException;
 
+    void orchestrateStart(String vmUuid, Map<VirtualMachineProfile.Param, Object> params, DeploymentPlan planToDeploy) throws InsufficientCapacityException,
+    	ResourceUnavailableException, ConcurrentOperationException, OperationTimedoutException;
+    
     void advanceStop(String vmUuid, boolean cleanupEvenIfUnableToStop) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException;
 
+    void orchestrateStop(String vmUuid, boolean cleanupEvenIfUnableToStop) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException;
+
     void advanceExpunge(String vmUuid) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException;
 
     void destroy(String vmUuid) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException;
@@ -117,11 +122,17 @@ public interface VirtualMachineManager extends Manager {
     void migrateAway(String vmUuid, long hostId) throws InsufficientServerCapacityException;
 
     void migrate(String vmUuid, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException;
+    
+    void orchestrateMigrate(String vmUuid, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException;
 
     void migrateWithStorage(String vmUuid, long srcId, long destId, Map<Volume, StoragePool> volumeToPool) throws ResourceUnavailableException, ConcurrentOperationException;
-
+    
+    void orchestrateMigrateWithStorage(String vmUuid, long srcId, long destId, Map<Volume, StoragePool> volumeToPool) throws ResourceUnavailableException, ConcurrentOperationException;
+    
     void reboot(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) throws InsufficientCapacityException, ResourceUnavailableException;
 
+    void orchestrateReboot(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) throws InsufficientCapacityException, ResourceUnavailableException;
+
     void advanceReboot(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) throws InsufficientCapacityException, ResourceUnavailableException,
             ConcurrentOperationException, OperationTimedoutException;
 
@@ -137,6 +148,8 @@ public interface VirtualMachineManager extends Manager {
     VirtualMachine findById(long vmId);
 
     void storageMigration(String vmUuid, StoragePool storagePoolId);
+    
+    void orchestrateStorageMigration(String vmUuid, StoragePool storagePoolId);
 
     /**
      * @param vmInstance
@@ -161,7 +174,11 @@ public interface VirtualMachineManager extends Manager {
      * @throws InsufficientCapacityException
      */
     NicProfile addVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) throws ConcurrentOperationException,
-                ResourceUnavailableException, InsufficientCapacityException;
+        ResourceUnavailableException, InsufficientCapacityException;
+    
+    NicProfile orchestrateAddVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) throws ConcurrentOperationException,
+    	ResourceUnavailableException, InsufficientCapacityException;
+    
 
     /**
      * @param vm
@@ -172,6 +189,8 @@ public interface VirtualMachineManager extends Manager {
      */
     boolean removeNicFromVm(VirtualMachine vm, Nic nic) throws ConcurrentOperationException, ResourceUnavailableException;
 
+    boolean orchestrateRemoveNicFromVm(VirtualMachine vm, Nic nic) throws ConcurrentOperationException, ResourceUnavailableException;
+
     /**
      * @param vm
      * @param network
@@ -181,6 +200,8 @@ public interface VirtualMachineManager extends Manager {
      * @throws ConcurrentOperationException
      */
     boolean removeVmFromNetwork(VirtualMachine vm, Network network, URI broadcastUri) throws ConcurrentOperationException, ResourceUnavailableException;
+    
+    boolean orchestrateRemoveVmFromNetwork(VirtualMachine vm, Network network, URI broadcastUri) throws ConcurrentOperationException, ResourceUnavailableException;
 
     /**
      * @param nic
@@ -196,12 +217,15 @@ public interface VirtualMachineManager extends Manager {
      */
     VirtualMachineTO toVmTO(VirtualMachineProfile profile);
 
-
     VirtualMachine reConfigureVm(String vmUuid, ServiceOffering newServiceOffering, boolean sameHost) throws ResourceUnavailableException, ConcurrentOperationException;
+    
+    VirtualMachine orchestrateReConfigureVm(String vmUuid, ServiceOffering newServiceOffering, boolean sameHost) throws ResourceUnavailableException, ConcurrentOperationException;
 
     void findHostAndMigrate(String vmUuid, Long newSvcOfferingId, DeploymentPlanner.ExcludeList excludeHostList) throws InsufficientCapacityException,
             ConcurrentOperationException, ResourceUnavailableException;
 
     void migrateForScale(String vmUuid, long srcHostId, DeployDestination dest, Long newSvcOfferingId) throws ResourceUnavailableException, ConcurrentOperationException;
+    
+    void orchestrateMigrateForScale(String vmUuid, long srcHostId, DeployDestination dest, Long newSvcOfferingId) throws ResourceUnavailableException, ConcurrentOperationException;
 
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/components-api/src/com/cloud/alert/AlertManager.java
----------------------------------------------------------------------
diff --git a/engine/components-api/src/com/cloud/alert/AlertManager.java b/engine/components-api/src/com/cloud/alert/AlertManager.java
index 1ae6b1b..eb5ac0c 100755
--- a/engine/components-api/src/com/cloud/alert/AlertManager.java
+++ b/engine/components-api/src/com/cloud/alert/AlertManager.java
@@ -50,6 +50,8 @@ public interface AlertManager extends Manager {
     public static final short ALERT_TYPE_DIRECT_ATTACHED_PUBLIC_IP = 24;
     public static final short ALERT_TYPE_LOCAL_STORAGE = 25;
     public static final short ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED = 26; // Generated when the resource limit exceeds the limit. Currently used for recurring snapshots only
+
+    public static final short ALERT_TYPE_SYNC = 27;
     
     static final ConfigKey<Double> StorageCapacityThreshold = new ConfigKey<Double>(Double.class, "cluster.storage.capacity.notificationthreshold", "Alert", "0.75",
         "Percentage (as a value between 0 and 1) of storage utilization above which alerts will be sent about low storage available.", true, ConfigKey.Scope.Cluster, null);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/components-api/src/com/cloud/vm/VmWork.java
----------------------------------------------------------------------
diff --git a/engine/components-api/src/com/cloud/vm/VmWork.java b/engine/components-api/src/com/cloud/vm/VmWork.java
new file mode 100644
index 0000000..3f9e71d
--- /dev/null
+++ b/engine/components-api/src/com/cloud/vm/VmWork.java
@@ -0,0 +1,45 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import java.io.Serializable;
+
+public class VmWork implements Serializable {
+	private static final long serialVersionUID = -6946320465729853589L;
+
+	long userId;
+	long accountId;
+	long vmId;
+
+    public VmWork(long userId, long accountId, long vmId) {
+        this.userId = userId;
+        this.accountId = accountId;
+        this.vmId = vmId;
+	}
+
+	public long getUserId() {
+		return userId;
+	}
+
+	public long getAccountId() {
+		return accountId;
+	}
+
+	public long getVmId() {
+		return vmId;
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml
----------------------------------------------------------------------
diff --git a/engine/orchestration/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml b/engine/orchestration/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml
index b5c4254..880002c 100644
--- a/engine/orchestration/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml
+++ b/engine/orchestration/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml
@@ -67,5 +67,6 @@
     
     <bean id="virtualMachineEntityImpl" class="org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntityImpl" />
     
+    <bean id="virtualMachinePowerStateSyncImpl" class="com.cloud.vm.VirtualMachinePowerStateSyncImpl" />
     
 </beans>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
index 75a95c5..189c2ba 100755
--- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -18,6 +18,10 @@
 package com.cloud.vm;
 
 import java.net.URI;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
@@ -26,6 +30,7 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TimeZone;
 import java.util.UUID;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
@@ -47,6 +52,18 @@ import org.apache.cloudstack.framework.config.ConfigDepot;
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.Configurable;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.framework.jobs.AsyncJob;
+import org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext;
+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.AsyncJobVO;
+import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper;
+import org.apache.cloudstack.framework.jobs.impl.OutcomeImpl;
+import org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO;
+import org.apache.cloudstack.framework.messagebus.MessageBus;
+import org.apache.cloudstack.framework.messagebus.MessageHandler;
+import org.apache.cloudstack.jobs.JobInfo;
 import org.apache.cloudstack.managed.context.ManagedContextRunnable;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
@@ -153,8 +170,10 @@ import com.cloud.storage.dao.VolumeDao;
 import com.cloud.template.VirtualMachineTemplate;
 import com.cloud.user.Account;
 import com.cloud.user.User;
+import com.cloud.utils.DateUtil;
 import com.cloud.utils.Journal;
 import com.cloud.utils.Pair;
+import com.cloud.utils.Predicate;
 import com.cloud.utils.StringUtils;
 import com.cloud.utils.Ternary;
 import com.cloud.utils.component.ManagerBase;
@@ -163,8 +182,10 @@ import com.cloud.utils.db.DB;
 import com.cloud.utils.db.EntityManager;
 import com.cloud.utils.db.GlobalLock;
 import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallbackNoReturn;
 import com.cloud.utils.db.TransactionCallbackWithException;
 import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
+import com.cloud.utils.db.TransactionLegacy;
 import com.cloud.utils.db.TransactionStatus;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.exception.ExecutionException;
@@ -172,6 +193,7 @@ 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.dao.NicDao;
 import com.cloud.vm.dao.UserVmDao;
@@ -186,6 +208,8 @@ import com.cloud.vm.snapshot.dao.VMSnapshotDao;
 public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, Listener, Configurable {
     private static final Logger s_logger = Logger.getLogger(VirtualMachineManagerImpl.class);
 
+    private static final String VM_SYNC_ALERT_SUBJECT = "VM state sync alert";
+    
     @Inject
     DataStoreManager dataStoreMgr;
     @Inject
@@ -279,6 +303,11 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     @Inject
     DeploymentPlanningManager _dpMgr;
 
+    @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;
 
@@ -298,6 +327,19 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
             "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);
+    
+    static final ConfigKey<Boolean> VmJobEnabled = new ConfigKey<Boolean>("Advanced",
+            Boolean.class, "vm.job.enabled", "false", 
+            "True to enable new VM sync model. false to use the old way", 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", false);
+    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", false);
+    static final ConfigKey<Integer> VmJobStateReportInterval = new ConfigKey<Integer>("Advanced",
+    		Integer.class, "vm.job.report.interval", "60",
+            "Interval to send application level pings to make sure the connection is still working", false);
 
 
 
@@ -651,15 +693,46 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     }
 
     @Override
-    public void advanceStart(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) throws InsufficientCapacityException, ConcurrentOperationException,
-    ResourceUnavailableException {
+    public void advanceStart(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) 
+    	throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
+    	
         advanceStart(vmUuid, params, null);
     }
 
     @Override
     public void advanceStart(String vmUuid, Map<VirtualMachineProfile.Param, Object> params, DeploymentPlan planToDeploy) throws InsufficientCapacityException,
-    ConcurrentOperationException, ResourceUnavailableException {
-        CallContext cctxt = CallContext.current();
+		ConcurrentOperationException, ResourceUnavailableException {
+    	
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		orchestrateStart(vmUuid, params, planToDeploy);
+    	} else {
+    	    Outcome<VirtualMachine> outcome = startVmThroughJobQueue(vmUuid, params, planToDeploy);
+    	    
+	    	try {
+				VirtualMachine vm = outcome.get();
+			} catch (InterruptedException e) {
+				throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+				throw new RuntimeException("Execution excetion", e);
+			}
+	    	
+	    	Throwable jobException = retriveExecutionException(outcome.getJob());
+	    	if(jobException != null) {
+		    	if(jobException instanceof ConcurrentOperationException)
+		    		throw (ConcurrentOperationException)jobException;
+		    	else if(jobException instanceof ResourceUnavailableException)
+		    		throw (ResourceUnavailableException)jobException;
+	    	}
+    	}
+    }
+    
+    @Override
+    public void orchestrateStart(String vmUuid, Map<VirtualMachineProfile.Param, Object> params, DeploymentPlan planToDeploy) throws InsufficientCapacityException,
+    	ConcurrentOperationException, ResourceUnavailableException {
+        
+    	CallContext cctxt = CallContext.current();
         Account account = cctxt.getCallingAccount();
         User caller = cctxt.getCallingUser();
 
@@ -1145,7 +1218,38 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     }
 
     @Override
-    public void advanceStop(String vmUuid, boolean cleanUpEvenIfUnableToStop) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
+    public void advanceStop(String vmUuid, boolean cleanUpEvenIfUnableToStop) 
+    	throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
+    	
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		orchestrateStop(vmUuid, cleanUpEvenIfUnableToStop);
+    	} else {
+    	    Outcome<VirtualMachine> outcome = stopVmThroughJobQueue(vmUuid, cleanUpEvenIfUnableToStop);
+    	    
+	    	try {
+				VirtualMachine vm = outcome.get();
+			} catch (InterruptedException e) {
+				throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+				throw new RuntimeException("Execution excetion", e);
+			}
+	    	
+	    	Throwable jobException = retriveExecutionException(outcome.getJob());
+	    	if(jobException != null) {
+	    		if(jobException instanceof AgentUnavailableException)
+	    			throw (AgentUnavailableException)jobException;
+	    		else if(jobException instanceof ConcurrentOperationException)
+		    		throw (ConcurrentOperationException)jobException;
+		    	else if(jobException instanceof OperationTimedoutException)
+		    		throw (OperationTimedoutException)jobException;
+	    	}
+    	}
+    }
+
+    @Override
+    public void orchestrateStop(String vmUuid, boolean cleanUpEvenIfUnableToStop) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException {
         VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
 
         advanceStop(vm, cleanUpEvenIfUnableToStop);
@@ -1415,9 +1519,33 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
 
         return true;
     }
+    
+    public void storageMigration(String vmUuid, StoragePool destPool) {
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		orchestrateStorageMigration(vmUuid, destPool);
+    	} else {
+    	    Outcome<VirtualMachine> outcome = migrateVmStorageThroughJobQueue(vmUuid, destPool);
+    	    
+	    	try {
+				VirtualMachine vm = outcome.get();
+			} catch (InterruptedException e) {
+				throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+				throw new RuntimeException("Execution excetion", e);
+			}
+	    	
+	    	Throwable jobException = retriveExecutionException(outcome.getJob());
+	    	if(jobException != null) {
+		    	if(jobException instanceof RuntimeException)
+		    		throw (RuntimeException)jobException;
+	    	}
+    	}
+    }
 
     @Override
-    public void storageMigration(String vmUuid, StoragePool destPool) {
+    public void orchestrateStorageMigration(String vmUuid, StoragePool destPool) {
         VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
 
         try {
@@ -1473,7 +1601,38 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     }
 
     @Override
-    public void migrate(String vmUuid, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException {
+    public void migrate(String vmUuid, long srcHostId, DeployDestination dest) 
+    	throws ResourceUnavailableException, ConcurrentOperationException {
+    	
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		orchestrateMigrate(vmUuid, srcHostId, dest);
+    	} else {
+    	    Outcome<VirtualMachine> outcome = migrateVmThroughJobQueue(vmUuid, srcHostId, dest);
+    	    
+	    	try {
+				VirtualMachine vm = outcome.get();
+			} catch (InterruptedException e) {
+				throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+				throw new RuntimeException("Execution excetion", e);
+			}
+	    	
+	    	Throwable jobException = retriveExecutionException(outcome.getJob());
+	    	if(jobException != null) {
+		    	if(jobException instanceof ResourceUnavailableException)
+	    			throw (ResourceUnavailableException)jobException;
+	    		else if(jobException instanceof ConcurrentOperationException)
+		    		throw (ConcurrentOperationException)jobException;
+	    		else if(jobException instanceof RuntimeException)
+		    		throw (RuntimeException)jobException;
+	    	}
+    	}
+    }
+    
+    @Override
+    public void orchestrateMigrate(String vmUuid, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException {
         VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
         if (vm == null) {
             if (s_logger.isDebugEnabled()) {
@@ -1713,9 +1872,38 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         }
     }
 
+    public void migrateWithStorage(String vmUuid, long srcHostId, long destHostId, Map<Volume, StoragePool> volumeToPool) 
+    	throws ResourceUnavailableException, ConcurrentOperationException {
+    	
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		orchestrateMigrateWithStorage(vmUuid, srcHostId, destHostId, volumeToPool);
+    	} else {
+            Outcome<VirtualMachine> outcome = migrateVmWithStorageThroughJobQueue(vmUuid, srcHostId, destHostId, volumeToPool);
+    	    
+	    	try {
+                VirtualMachine vm = outcome.get();
+			} catch (InterruptedException e) {
+                throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+                throw new RuntimeException("Execution excetion", e);
+			}
+
+	    	Throwable jobException = retriveExecutionException(outcome.getJob());
+	    	if(jobException != null) {
+	    	    if(jobException instanceof ResourceUnavailableException)
+                    throw (ResourceUnavailableException)jobException;
+	    		else if(jobException instanceof ConcurrentOperationException)
+		    	    throw (ConcurrentOperationException)jobException;
+           }
+    	}
+    }
+    
     @Override
-    public void migrateWithStorage(String vmUuid, long srcHostId, long destHostId, Map<Volume, StoragePool> volumeToPool) throws ResourceUnavailableException,
-    ConcurrentOperationException {
+    public void orchestrateMigrateWithStorage(String vmUuid, long srcHostId, long destHostId, Map<Volume, StoragePool> volumeToPool) throws ResourceUnavailableException,
+    	ConcurrentOperationException {
+    	
         VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
 
         HostVO srcHost = _hostDao.findById(srcHostId);
@@ -1954,9 +2142,40 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
             throw new CloudRuntimeException("Unable to reboot a VM due to concurrent operation", e);
         }
     }
-
+    
     @Override
-    public void advanceReboot(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) throws InsufficientCapacityException, ConcurrentOperationException,
+    public void advanceReboot(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) 
+    	throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
+    	
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		orchestrateReboot(vmUuid, params);
+    	} else {
+    	    Outcome<VirtualMachine> outcome = rebootVmThroughJobQueue(vmUuid, params);
+    	    
+	    	try {
+				VirtualMachine vm = outcome.get();
+			} catch (InterruptedException e) {
+				throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+				throw new RuntimeException("Execution excetion", e);
+			}
+	    	
+	    	Throwable jobException = retriveExecutionException(outcome.getJob());
+	    	if(jobException != null) {
+	    		if(jobException instanceof ResourceUnavailableException)
+	    			throw (ResourceUnavailableException)jobException;
+	    		else if(jobException instanceof ConcurrentOperationException)
+		    		throw (ConcurrentOperationException)jobException;
+	    		else if(jobException instanceof InsufficientCapacityException)
+	    			throw (InsufficientCapacityException)jobException;
+	    	}
+    	}
+    }
+    
+    @Override
+    public void orchestrateReboot(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) throws InsufficientCapacityException, ConcurrentOperationException,
     ResourceUnavailableException {
         VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
 
@@ -2081,8 +2300,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         return commands;
     }
 
-
-
     public void deltaSync(Map<String, Ternary<String, State, String>> newStates) {
         Map<Long, AgentVmInfo> states = convertToInfos(newStates);
 
@@ -2615,6 +2832,16 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
                         }
                     }
                 }
+                
+                if(VmJobEnabled.value()) {
+	                if(ping.getHostVmStateReport() != null && ping.getHostVmStateReport().size() > 0) {                	
+	            		_syncMgr.processHostVmStatePingReport(agentId, ping.getHostVmStateReport());
+	                }
+                }
+                
+                // take the chance to scan VMs that are stuck in transitional states 
+                // and are missing from the report
+                scanStalledVMInTransitionStateOnUpHost(agentId);
                 processed = true;
             }
         }
@@ -2636,7 +2863,14 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         if (!(cmd instanceof StartupRoutingCommand)) {
             return;
         }
+        
+        if(s_logger.isDebugEnabled())
+        	s_logger.debug("Received startup command from hypervisor host. host id: " + agent.getId());
 
+        if(VmJobEnabled.value()) {
+        	_syncMgr.resetHostSyncState(agent.getId());
+        }
+        
         if (forRebalance) {
             s_logger.debug("Not processing listener " + this + " as connect happens on rebalance process");
             return;
@@ -2842,9 +3076,50 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         vmForUpdate.setServiceOfferingId(newSvcOff.getId());
         return _vmDao.update(vmId, vmForUpdate);
     }
-
+    
+    @Override
+    public NicProfile addVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) 
+    	throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
+    	
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		return orchestrateAddVmToNetwork(vm, network,requested);
+    	} else {
+            Outcome<VirtualMachine> outcome = addVmToNetworkThroughJobQueue(vm, network, requested);
+    	    
+	    	try {
+                outcome.get();
+			} catch (InterruptedException e) {
+                throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+                throw new RuntimeException("Execution excetion", e);
+			}
+	    	
+	    	AsyncJobVO jobVo = _entityMgr.findById(AsyncJobVO.class, outcome.getJob().getId());
+	    	if(jobVo.getResultCode() == JobInfo.Status.SUCCEEDED.ordinal()) {
+	    		
+	    		NicProfile nic = (NicProfile)JobSerializerHelper.fromObjectSerializedString(jobVo.getResult());
+	    		return nic;
+	    	} else {
+		    	Throwable jobException = retriveExecutionException(outcome.getJob());
+		    	if(jobException != null) {
+		    	    if(jobException instanceof ResourceUnavailableException)
+	                    throw (ResourceUnavailableException)jobException;
+		    		else if(jobException instanceof ConcurrentOperationException)
+			    	    throw (ConcurrentOperationException)jobException;
+		    		else if(jobException instanceof InsufficientCapacityException)
+			    	    throw (InsufficientCapacityException)jobException;
+		    		else if(jobException instanceof RuntimeException)
+			    	    throw (RuntimeException)jobException;
+	            }
+	    	    throw new RuntimeException("Job failed with unhandled exception");
+	    	}
+    	}
+    }
+    
     @Override
-    public NicProfile addVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) throws ConcurrentOperationException, ResourceUnavailableException,
+    public NicProfile orchestrateAddVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) throws ConcurrentOperationException, ResourceUnavailableException,
     InsufficientCapacityException {
         CallContext cctx = CallContext.current();
 
@@ -2909,9 +3184,48 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         NicTO nicTO = hvGuru.toNicTO(nic);
         return nicTO;
     }
+    
+    public boolean removeNicFromVm(VirtualMachine vm, Nic nic) 
+    	throws ConcurrentOperationException, ResourceUnavailableException {
+    	
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		return orchestrateRemoveNicFromVm(vm, nic);
+    	} else {
+            Outcome<VirtualMachine> outcome = removeNicFromVmThroughJobQueue(vm, nic);
+    	    
+	    	try {
+                outcome.get();
+			} catch (InterruptedException e) {
+                throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+                throw new RuntimeException("Execution excetion", e);
+			}
+
+	    	AsyncJobVO jobVo = _entityMgr.findById(AsyncJobVO.class, outcome.getJob().getId());
+	    	
+	    	if(jobVo.getResultCode() == JobInfo.Status.SUCCEEDED.ordinal()) {
+	    		Boolean result = (Boolean)JobSerializerHelper.fromObjectSerializedString(jobVo.getResult());
+	    		return result;
+	    	} else {
+		    	Throwable jobException = retriveExecutionException(outcome.getJob());
+		    	if(jobException != null) {
+		    	    if(jobException instanceof ResourceUnavailableException)
+	                    throw (ResourceUnavailableException)jobException;
+		    		else if(jobException instanceof ConcurrentOperationException)
+			    	    throw (ConcurrentOperationException)jobException;
+		    		else if(jobException instanceof RuntimeException)
+		    			throw (RuntimeException)jobException;
+	            }
+		    	
+		    	throw new RuntimeException("Job failed with un-handled exception");
+	    	}
+    	}
+    }
 
     @Override
-    public boolean removeNicFromVm(VirtualMachine vm, Nic nic) throws ConcurrentOperationException, ResourceUnavailableException {
+    public boolean orchestrateRemoveNicFromVm(VirtualMachine vm, Nic nic) throws ConcurrentOperationException, ResourceUnavailableException {
         CallContext cctx = CallContext.current();
         VMInstanceVO vmVO = _vmDao.findById(vm.getId());
         NetworkVO network = _networkDao.findById(nic.getNetworkId());
@@ -2971,6 +3285,13 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     @Override
     @DB
     public boolean removeVmFromNetwork(VirtualMachine vm, Network network, URI broadcastUri) throws ConcurrentOperationException, ResourceUnavailableException {
+    	// TODO will serialize on the VM object later to resolve operation conflicts
+    	return orchestrateRemoveVmFromNetwork(vm, network, broadcastUri);
+    }
+    
+    @Override
+    @DB
+    public boolean orchestrateRemoveVmFromNetwork(VirtualMachine vm, Network network, URI broadcastUri) throws ConcurrentOperationException, ResourceUnavailableException {
         CallContext cctx = CallContext.current();
         VMInstanceVO vmVO = _vmDao.findById(vm.getId());
         ReservationContext context = new ReservationContextImpl(null, null, cctx.getCallingUser(), cctx.getCallingAccount());
@@ -3106,10 +3427,40 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
             throw e;
         }
     }
+    
+    @Override
+    public void migrateForScale(String vmUuid, long srcHostId, DeployDestination dest, Long oldSvcOfferingId) 
+    	throws ResourceUnavailableException, ConcurrentOperationException {
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		orchestrateMigrateForScale(vmUuid, srcHostId, dest, oldSvcOfferingId);
+    	} else {
+    	    Outcome<VirtualMachine> outcome = migrateVmForScaleThroughJobQueue(vmUuid, srcHostId, dest, oldSvcOfferingId);
+    	    
+	    	try {
+				VirtualMachine vm = outcome.get();
+			} catch (InterruptedException e) {
+				throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+				throw new RuntimeException("Execution excetion", e);
+			}
+	    	
+	    	Throwable jobException = retriveExecutionException(outcome.getJob());
+	    	if(jobException != null) {
+	    		if(jobException instanceof ResourceUnavailableException)
+	    			throw (ResourceUnavailableException)jobException;
+	    		else if(jobException instanceof ConcurrentOperationException)
+		    		throw (ConcurrentOperationException)jobException;
+	    	}
+    	}
+    }
 
     @Override
-    public void migrateForScale(String vmUuid, long srcHostId, DeployDestination dest, Long oldSvcOfferingId) throws ResourceUnavailableException, ConcurrentOperationException {
-        VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+    public void orchestrateMigrateForScale(String vmUuid, long srcHostId, DeployDestination dest, Long oldSvcOfferingId) 
+    	throws ResourceUnavailableException, ConcurrentOperationException {
+        
+    	VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
         s_logger.info("Migrating " + vm + " to " + dest);
 
         vm.getServiceOfferingId();
@@ -3293,7 +3644,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     }
 
     public boolean unplugNic(Network network, NicTO nic, VirtualMachineTO vm, ReservationContext context, DeployDestination dest) throws ConcurrentOperationException,
-    ResourceUnavailableException {
+    	ResourceUnavailableException {
 
         boolean result = true;
         VMInstanceVO router = _vmDao.findById(vm.getId());
@@ -3324,9 +3675,46 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
 
         return result;
     }
-
+    
+    public VMInstanceVO reConfigureVm(String vmUuid, ServiceOffering oldServiceOffering, 
+    	boolean reconfiguringOnExistingHost) 
+    	throws ResourceUnavailableException, ConcurrentOperationException {
+
+    	AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
+    	if(!VmJobEnabled.value() || jobContext.isJobDispatchedBy(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER)) {
+    		// avoid re-entrance
+    		return orchestrateReConfigureVm(vmUuid, oldServiceOffering, reconfiguringOnExistingHost);
+    	} else {
+    	    Outcome<VirtualMachine> outcome = reconfigureVmThroughJobQueue(vmUuid, oldServiceOffering, reconfiguringOnExistingHost);
+    	    
+    	    VirtualMachine vm = null;
+	    	try {
+				vm = outcome.get();
+			} catch (InterruptedException e) {
+				throw new RuntimeException("Operation is interrupted", e);
+			} catch (java.util.concurrent.ExecutionException e) {
+				throw new RuntimeException("Execution excetion", e);
+			}
+
+	    	AsyncJobVO jobVo = _entityMgr.findById(AsyncJobVO.class, outcome.getJob().getId());
+	    	if(jobVo.getResultCode() == JobInfo.Status.SUCCEEDED.ordinal()) {
+	    		return _entityMgr.findById(VMInstanceVO.class, vm.getId());
+	    	} else {
+		    	Throwable jobException = retriveExecutionException(outcome.getJob());
+		    	if(jobException != null) {
+		    		if(jobException instanceof ResourceUnavailableException)
+		    			throw (ResourceUnavailableException)jobException;
+		    		else if(jobException instanceof ConcurrentOperationException)
+			    		throw (ConcurrentOperationException)jobException;
+		    	}
+		    	
+		    	throw new RuntimeException("Failed with un-handled exception");
+	    	}
+    	}
+    }
+    
     @Override
-    public VMInstanceVO reConfigureVm(String vmUuid, ServiceOffering oldServiceOffering, boolean reconfiguringOnExistingHost) throws ResourceUnavailableException,
+    public VMInstanceVO orchestrateReConfigureVm(String vmUuid, ServiceOffering oldServiceOffering, boolean reconfiguringOnExistingHost) throws ResourceUnavailableException,
     ConcurrentOperationException {
         VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
 
@@ -3388,7 +3776,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     @Override
     public ConfigKey<?>[] getConfigKeys() {
         return new ConfigKey<?>[] {ClusterDeltaSyncInterval, StartRetry, VmDestroyForcestop, VmOpCancelInterval, VmOpCleanupInterval, VmOpCleanupWait, VmOpLockStateRetry,
-                VmOpWaitInterval, ExecuteInSequence};
+                VmOpWaitInterval, ExecuteInSequence, VmJobCheckInterval, VmJobTimeout, VmJobStateReportInterval};
     }
 
     public List<StoragePoolAllocator> getStoragePoolAllocators() {
@@ -3400,4 +3788,920 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         _storagePoolAllocators = storagePoolAllocators;
     }
 
+    
+    //
+    // PowerState report handling for out-of-band changes and handling of left-over transitional VM states
+    //
+    
+    @MessageHandler(topic = Topics.VM_POWER_STATE)
+    private void HandlePownerStateReport(Object target, String subject, String senderAddress, Object args) {
+    	assert(args != null);
+    	Long vmId = (Long)args;
+    	
+    	List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+    		VirtualMachine.Type.Instance, vmId);
+    	if(pendingWorkJobs.size() == 0) {
+    		// there is no pending operation job
+            VMInstanceVO vm = _vmDao.findById(vmId);
+    		if(vm != null) {
+    			switch(vm.getPowerState()) {
+    			case PowerOn :
+    				handlePowerOnReportWithNoPendingJobsOnVM(vm);
+    				break;
+    				
+    			case PowerOff :
+    				handlePowerOffReportWithNoPendingJobsOnVM(vm);
+    				break;
+
+    			// PowerUnknown shouldn't be reported, it is a derived
+    			// VM power state from host state (host un-reachable
+    			case PowerUnknown :
+    			default :
+    				assert(false);
+    				break;
+    			}
+    		} else {
+    			s_logger.warn("VM " + vmId + " no longer exists when processing VM state report");
+    		}
+    	} else {
+    		// TODO, do job wake-up signalling, since currently async job wake-up is not in use
+    		// we will skip it for nows
+    	}
+    }
+    
+    private void handlePowerOnReportWithNoPendingJobsOnVM(VMInstanceVO vm) {
+    	//
+    	// 	1) handle left-over transitional VM states
+    	//	2) handle out of band VM live migration
+    	//	3) handle out of sync stationary states, marking VM from Stopped to Running with
+    	//	   alert messages
+    	//
+    	switch(vm.getState()) {
+    	case Starting :
+    		try {
+    			stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOnReport, vm.getPowerHostId());
+    		} catch(NoTransitionException e) {
+    			s_logger.warn("Unexpected VM state transition exception, race-condition?", e);
+    		}
+    		
+    		// we need to alert admin or user about this risky state transition
+    		_alertMgr.sendAlert(AlertManager.ALERT_TYPE_SYNC, vm.getDataCenterId(), vm.getPodIdToDeployIn(),
+    			VM_SYNC_ALERT_SUBJECT, "VM " + vm.getHostName() + "(" + vm.getInstanceName() + ") state is sync-ed (Starting -> Running) from out-of-context transition. VM network environment may need to be reset");
+    		break;
+    		
+    	case Running :
+    		try {
+    			if(vm.getHostId() != null && vm.getHostId().longValue() != vm.getPowerHostId().longValue())
+    				s_logger.info("Detected out of band VM migration from host " + vm.getHostId() + " to host " + vm.getPowerHostId());
+    			stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOnReport, vm.getPowerHostId());
+    		} catch(NoTransitionException e) {
+    			s_logger.warn("Unexpected VM state transition exception, race-condition?", e);
+    		}
+    		break;
+    		
+    	case Stopping :
+    	case Stopped :
+    		try {
+    			stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOnReport, vm.getPowerHostId());
+    		} catch(NoTransitionException e) {
+    			s_logger.warn("Unexpected VM state transition exception, race-condition?", e);
+    		}
+      		_alertMgr.sendAlert(AlertManager.ALERT_TYPE_SYNC, vm.getDataCenterId(), vm.getPodIdToDeployIn(),
+        			VM_SYNC_ALERT_SUBJECT, "VM " + vm.getHostName() + "(" + vm.getInstanceName() + ") state is sync-ed (" + vm.getState() + " -> Running) from out-of-context transition. VM network environment may need to be reset");
+          	break;
+    		
+    	case Destroyed :
+    	case Expunging :
+    		s_logger.info("Receive power on report when VM is in destroyed or expunging state. vm: "
+        		    + vm.getId() + ", state: " + vm.getState());
+    		break;
+    		
+    	case Migrating :
+    		try {
+    			stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOnReport, vm.getPowerHostId());
+    		} catch(NoTransitionException e) {
+    			s_logger.warn("Unexpected VM state transition exception, race-condition?", e);
+    		}
+    		break;
+    		
+    	case Error :
+    	default :
+    		s_logger.info("Receive power on report when VM is in error or unexpected state. vm: "
+    		    + vm.getId() + ", state: " + vm.getState());
+    		break;
+    	}
+    }
+    
+    private void handlePowerOffReportWithNoPendingJobsOnVM(VMInstanceVO vm) {
+
+    	// 	1) handle left-over transitional VM states
+    	//	2) handle out of sync stationary states, schedule force-stop to release resources
+    	//
+    	switch(vm.getState()) {
+    	case Starting :
+    	case Stopping :
+    	case Stopped :
+    	case Migrating :
+    		try {
+    			stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOffReport, vm.getPowerHostId());
+    		} catch(NoTransitionException e) {
+    			s_logger.warn("Unexpected VM state transition exception, race-condition?", e);
+    		}
+      		_alertMgr.sendAlert(AlertManager.ALERT_TYPE_SYNC, vm.getDataCenterId(), vm.getPodIdToDeployIn(),
+        			VM_SYNC_ALERT_SUBJECT, "VM " + vm.getHostName() + "(" + vm.getInstanceName() + ") state is sync-ed (" + vm.getState() + " -> Stopped) from out-of-context transition.");
+      		// TODO: we need to forcely release all resource allocation
+          	break;
+    		
+    	case Running :
+    	case Destroyed :
+    	case Expunging :
+    		break;
+    		
+    	case Error :
+    	default :
+    		break;
+    	}
+    }
+    
+    private void scanStalledVMInTransitionStateOnUpHost(long hostId) {
+    	//
+    	// Check VM that is stuck in Starting, Stopping, Migrating states, we won't check
+    	// VMs in expunging state (this need to be handled specially)
+    	//
+    	// checking condition
+    	//	1) no pending VmWork job
+    	//	2) on hostId host and host is UP
+    	//
+    	// When host is UP, soon or later we will get a report from the host about the VM,
+    	// however, if VM is missing from the host report (it may happen in out of band changes
+    	// or from designed behave of XS/KVM), the VM may not get a chance to run the state-sync logic
+    	//
+    	// Therefor, we will scan thoses VMs on UP host based on last update timestamp, if the host is UP
+    	// and a VM stalls for status update, we will consider them to be powered off
+    	// (which is relatively safe to do so)
+    	
+    	long stallThresholdInMs = VmJobStateReportInterval.value() + (VmJobStateReportInterval.value() >> 1);
+    	Date cutTime = new Date(DateUtil.currentGMTTime().getTime() - stallThresholdInMs);
+    	List<Long> mostlikelyStoppedVMs = listStalledVMInTransitionStateOnUpHost(hostId, cutTime);
+    	for(Long vmId : mostlikelyStoppedVMs) {
+    		VMInstanceVO vm = _vmDao.findById(vmId);
+    		assert(vm != null);
+    		handlePowerOffReportWithNoPendingJobsOnVM(vm);
+    	}
+    	
+    	List<Long> vmsWithRecentReport = listVMInTransitionStateWithRecentReportOnUpHost(hostId, cutTime);
+    	for(Long vmId : vmsWithRecentReport) {
+    		VMInstanceVO vm = _vmDao.findById(vmId);
+    		assert(vm != null);
+    		if(vm.getPowerState() == PowerState.PowerOn)
+    			handlePowerOnReportWithNoPendingJobsOnVM(vm);
+    		else
+    			handlePowerOffReportWithNoPendingJobsOnVM(vm);
+    	}
+    }
+    
+    private void scanStalledVMInTransitionStateOnDisconnectedHosts() {
+    	Date cutTime = new Date(DateUtil.currentGMTTime().getTime() - VmOpWaitInterval.value()*1000);
+    	List<Long> stuckAndUncontrollableVMs = listStalledVMInTransitionStateOnDisconnectedHosts(cutTime);
+    	for(Long vmId : stuckAndUncontrollableVMs) {
+    		VMInstanceVO vm = _vmDao.findById(vmId);
+    		
+    		// We now only alert administrator about this situation
+      		_alertMgr.sendAlert(AlertManager.ALERT_TYPE_SYNC, vm.getDataCenterId(), vm.getPodIdToDeployIn(),
+        		VM_SYNC_ALERT_SUBJECT, "VM " + vm.getHostName() + "(" + vm.getInstanceName() + ") is stuck in " + vm.getState() + " state and its host is unreachable for too long");
+    	}
+    }
+    
+    
+    // VMs that in transitional state without recent power state report
+    private List<Long> listStalledVMInTransitionStateOnUpHost(long hostId, Date cutTime) {
+    	String sql = "SELECT i.* FROM vm_instance as i, host as h WHERE h.status = 'UP' " +
+                     "AND h.id = ? AND i.power_state_update_time < ? AND i.host_id = h.id " +
+    			     "AND (i.state ='Starting' OR i.state='Stopping' OR i.state='Migrating') " +
+    			     "AND i.id NOT IN (SELECT w.vm_instance_id FROM vm_work_job AS w JOIN async_job AS j ON w.id = j.id WHERE j.job_status = ?)";
+    	
+    	List<Long> l = new ArrayList<Long>();
+    	TransactionLegacy txn = null;
+    	try {
+    		txn = TransactionLegacy.open(TransactionLegacy.CLOUD_DB);
+    	
+	        PreparedStatement pstmt = null;
+	        try {
+	            pstmt = txn.prepareAutoCloseStatement(sql);
+	            
+	            pstmt.setLong(1, hostId);
+	 	        pstmt.setString(2, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutTime));
+	 	        pstmt.setInt(3, JobInfo.Status.IN_PROGRESS.ordinal());
+	            ResultSet rs = pstmt.executeQuery();
+	            while(rs.next()) {
+	            	l.add(rs.getLong(1));
+	            }
+	        } catch (SQLException e) {
+	        } catch (Throwable e) {
+	        }
+        
+    	} finally {
+    		if(txn != null)
+    			txn.close();
+    	}
+        return l;
+    }
+    
+    // VMs that in transitional state and recently have power state update
+    private List<Long> listVMInTransitionStateWithRecentReportOnUpHost(long hostId, Date cutTime) {
+    	String sql = "SELECT i.* FROM vm_instance as i, host as h WHERE h.status = 'UP' " +
+                     "AND h.id = ? AND i.power_state_update_time > ? AND i.host_id = h.id " +
+    			     "AND (i.state ='Starting' OR i.state='Stopping' OR i.state='Migrating') " +
+    			     "AND i.id NOT IN (SELECT w.vm_instance_id FROM vm_work_job AS w JOIN async_job AS j ON w.id = j.id WHERE j.job_status = ?)";
+    	
+    	List<Long> l = new ArrayList<Long>();
+    	TransactionLegacy txn = null;
+    	try {
+    		txn = TransactionLegacy.open(TransactionLegacy.CLOUD_DB);
+	        PreparedStatement pstmt = null;
+	        try {
+	            pstmt = txn.prepareAutoCloseStatement(sql);
+	            
+	            pstmt.setLong(1, hostId);
+	 	        pstmt.setString(2, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutTime));
+	 	        pstmt.setInt(3, JobInfo.Status.IN_PROGRESS.ordinal());
+	            ResultSet rs = pstmt.executeQuery();
+	            while(rs.next()) {
+	            	l.add(rs.getLong(1));
+	            }
+	        } catch (SQLException e) {
+	        } catch (Throwable e) {
+	        }
+	        return l;
+    	} finally {
+    		if(txn != null)
+    			txn.close();
+    	}
+    }
+    
+    private List<Long> listStalledVMInTransitionStateOnDisconnectedHosts(Date cutTime) {
+    	String sql = "SELECT i.* FROM vm_instance as i, host as h WHERE h.status != 'UP' " +
+                 "AND i.power_state_update_time < ? AND i.host_id = h.id " +
+			     "AND (i.state ='Starting' OR i.state='Stopping' OR i.state='Migrating') " +
+			     "AND i.id NOT IN (SELECT w.vm_instance_id FROM vm_work_job AS w JOIN async_job AS j ON w.id = j.id WHERE j.job_status = ?)";
+	
+    	List<Long> l = new ArrayList<Long>();
+    	TransactionLegacy txn = null;
+    	try {
+    		txn = TransactionLegacy.open(TransactionLegacy.CLOUD_DB);
+	    	PreparedStatement pstmt = null;
+	    	try {
+		       pstmt = txn.prepareAutoCloseStatement(sql);
+		       
+		       pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutTime));
+		       pstmt.setInt(2, JobInfo.Status.IN_PROGRESS.ordinal());
+		       ResultSet rs = pstmt.executeQuery();
+		       while(rs.next()) {
+		       	l.add(rs.getLong(1));
+		       }
+	    	} catch (SQLException e) {
+	    	} catch (Throwable e) {
+	    	}
+	    	return l;
+    	} finally {
+    		if(txn != null)
+    			txn.close();
+    	}
+    }
+    
+    //
+    // VM operation based on new sync model
+    //
+    
+    public class VmStateSyncOutcome extends OutcomeImpl<VirtualMachine> {
+        private long _vmId;
+
+        public VmStateSyncOutcome(final AsyncJob job, final PowerState desiredPowerState, final long vmId, final Long srcHostIdForMigration) {
+            super(VirtualMachine.class, job, VmJobCheckInterval.value(), new Predicate() {
+                @Override
+                public boolean checkCondition() {
+                    VMInstanceVO instance = _vmDao.findById(vmId);
+                    if (instance.getPowerState() == desiredPowerState && (srcHostIdForMigration != null && instance.getPowerHostId() != srcHostIdForMigration))
+                        return true;
+                    return false;
+                }
+            }, Topics.VM_POWER_STATE, AsyncJob.Topics.JOB_STATE);
+            _vmId = vmId;
+        }
+
+        @Override
+        protected VirtualMachine retrieve() {
+            return _vmDao.findById(_vmId);
+        }
+    }
+
+    public class VmJobSyncOutcome extends OutcomeImpl<VirtualMachine> {
+        private long _vmId;
+
+        public VmJobSyncOutcome(final AsyncJob job, final long vmId) {
+            super(VirtualMachine.class, job, VmJobCheckInterval.value(), new Predicate() {
+                @Override
+                public boolean checkCondition() {
+                	AsyncJobVO jobVo = _entityMgr.findById(AsyncJobVO.class, job.getId());
+                	assert(jobVo != null);
+                	if(jobVo == null || jobVo.getStatus() != JobInfo.Status.IN_PROGRESS)
+                        return true;
+                	
+                    return false;
+                }
+            }, AsyncJob.Topics.JOB_STATE);
+            _vmId = vmId;
+        }
+
+        @Override
+        protected VirtualMachine retrieve() {
+            return _vmDao.findById(_vmId);
+        }
+    }
+    
+    public Throwable retriveExecutionException(AsyncJob job) {
+    	assert(job != null);
+    	assert(job.getDispatcher().equals(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER));
+    	
+    	AsyncJobVO jobVo = this._entityMgr.findById(AsyncJobVO.class, job.getId());
+    	if(jobVo != null && jobVo.getResult() != null) {
+    		Object obj = JobSerializerHelper.fromSerializedString(job.getResult());
+    		
+    		if(obj != null && obj instanceof Throwable)
+    			return (Throwable)obj;
+    	}
+    	return null;
+    }
+    
+    public Outcome<VirtualMachine> startVmThroughJobQueue(final String vmUuid, 
+    	final Map<VirtualMachineProfile.Param, Object> params, 
+    	final DeploymentPlan planToDeploy) {
+        
+    	final CallContext context = CallContext.current();
+        final User callingUser = context.getCallingUser();
+        final Account callingAccount = context.getCallingAccount();
+
+        final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+    	    	VmWorkJobVO workJob = null;
+    	    	
+    	        _vmDao.lockRow(vm.getId(), true);
+    	        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(VirtualMachine.Type.Instance, 
+    	        	vm.getId(), VmWorkStart.class.getName());
+    	        
+    	        if (pendingWorkJobs.size() > 0) {
+    	            assert (pendingWorkJobs.size() == 1);
+    	            workJob = pendingWorkJobs.get(0);
+    	        } else {
+    	            workJob = new VmWorkJobVO(context.getContextId());
+
+    	            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+    	            workJob.setCmd(VmWorkStart.class.getName());
+
+    	            workJob.setAccountId(callingAccount.getId());
+    	            workJob.setUserId(callingUser.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(callingUser.getId(), callingAccount.getId(), vm.getId());
+    	            workInfo.setPlan(planToDeploy);
+    	            workInfo.setParams(params);
+    	            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+
+    	            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+    	    	}
+    	        
+	            // Transaction syntax sugar has a cost here
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+    		}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmStateSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), 
+        	VirtualMachine.PowerState.PowerOn, vm.getId(), null);
+    }
+    
+    public Outcome<VirtualMachine> stopVmThroughJobQueue(final String vmUuid, final boolean cleanup) {
+        final CallContext context = CallContext.current();
+        final Account account = context.getCallingAccount();
+        final User user = context.getCallingUser();
+
+        final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+    	
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+	        		VirtualMachine.Type.Instance, vm.getId(), 
+	        		VmWorkStop.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkStop.class.getName());
+		
+		            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(user.getId(), account.getId(), vm.getId(), cleanup);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		    	}
+		        
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+    		}
+		});
+
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmStateSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), 
+        	VirtualMachine.PowerState.PowerOff, vm.getId(), null);
+    }
+    
+    public Outcome<VirtualMachine> rebootVmThroughJobQueue(final String vmUuid, 
+    	final Map<VirtualMachineProfile.Param, Object> params) {
+    	
+        final CallContext context = CallContext.current();
+        final Account account = context.getCallingAccount();
+        final User user = context.getCallingUser();
+
+        final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+    	
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+	        		VirtualMachine.Type.Instance, vm.getId(), 
+	        		VmWorkReboot.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkReboot.class.getName());
+		
+		            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)
+		            VmWorkReboot workInfo = new VmWorkReboot(user.getId(), account.getId(), vm.getId(), params);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		    	}
+		        
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+    		}
+		});
+
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmJobSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), 
+        	vm.getId());
+    }
+    
+    public Outcome<VirtualMachine> migrateVmThroughJobQueue(final String vmUuid, final long srcHostId, final DeployDestination dest) {
+        final CallContext context = CallContext.current();
+        final User user = context.getCallingUser();
+        final Account account = context.getCallingAccount();
+
+        final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+	
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+		        	VirtualMachine.Type.Instance, vm.getId(), 
+		        	VmWorkMigrate.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		                    
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkMigrate.class.getName());
+		
+		            workJob.setAccountId(account.getId());
+		            workJob.setUserId(user.getId());
+		            workJob.setVmType(vm.getType());
+		            workJob.setVmInstanceId(vm.getId());
+		
+		            // save work context info (there are some duplications)
+		            VmWorkMigrate workInfo = new VmWorkMigrate(user.getId(), account.getId(), vm.getId(), srcHostId, dest);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		        }
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+	    	}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmStateSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), 
+        	VirtualMachine.PowerState.PowerOn, vm.getId(), vm.getPowerHostId());
+    }
+    
+    public Outcome<VirtualMachine> migrateVmWithStorageThroughJobQueue(
+    	final String vmUuid, final long srcHostId, final long destHostId,
+    	final Map<Volume, StoragePool> volumeToPool) {
+    	
+        final CallContext context = CallContext.current();
+        final User user = context.getCallingUser();
+        final Account account = context.getCallingAccount();
+
+        final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+	
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+		        	VirtualMachine.Type.Instance, vm.getId(), 
+		        	VmWorkMigrateWithStorage.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		                    
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkMigrate.class.getName());
+		
+		            workJob.setAccountId(account.getId());
+		            workJob.setUserId(user.getId());
+		            workJob.setVmType(vm.getType());
+		            workJob.setVmInstanceId(vm.getId());
+		
+		            // save work context info (there are some duplications)
+		            VmWorkMigrateWithStorage workInfo = new VmWorkMigrateWithStorage(user.getId(), account.getId(), vm.getId(), 
+		            	srcHostId, destHostId, volumeToPool);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		        }
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+	    	}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmStateSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), 
+        	VirtualMachine.PowerState.PowerOn, vm.getId(), destHostId);
+    }
+    
+    //
+    // TODO build a common pattern to reduce code duplication in following methods
+    // no time for this at current iteration
+    //
+    public Outcome<VirtualMachine> migrateVmForScaleThroughJobQueue(
+    	final String vmUuid, final long srcHostId, final DeployDestination dest, final Long newSvcOfferingId) {
+    	
+        final CallContext context = CallContext.current();
+        final User user = context.getCallingUser();
+        final Account account = context.getCallingAccount();
+
+        final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+	
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+		        	VirtualMachine.Type.Instance, vm.getId(), 
+		        	VmWorkMigrateForScale.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		                    
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkMigrate.class.getName());
+		
+		            workJob.setAccountId(account.getId());
+		            workJob.setUserId(user.getId());
+		            workJob.setVmType(vm.getType());
+		            workJob.setVmInstanceId(vm.getId());
+		
+		            // save work context info (there are some duplications)
+		            VmWorkMigrateForScale workInfo = new VmWorkMigrateForScale(user.getId(), account.getId(), vm.getId(), 
+		            	srcHostId, dest, newSvcOfferingId);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		        }
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+	    	}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmJobSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), vm.getId());
+    }
+    
+    public Outcome<VirtualMachine> migrateVmStorageThroughJobQueue(
+    	final String vmUuid, final StoragePool destPool) {
+    	
+        final CallContext context = CallContext.current();
+        final User user = context.getCallingUser();
+        final Account account = context.getCallingAccount();
+
+        final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+	
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+		        	VirtualMachine.Type.Instance, vm.getId(), 
+		        	VmWorkStorageMigration.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		                    
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkStorageMigration.class.getName());
+		
+		            workJob.setAccountId(account.getId());
+		            workJob.setUserId(user.getId());
+		            workJob.setVmType(vm.getType());
+		            workJob.setVmInstanceId(vm.getId());
+		
+		            // save work context info (there are some duplications)
+		            VmWorkStorageMigration workInfo = new VmWorkStorageMigration(user.getId(), account.getId(), vm.getId(), 
+		            	destPool);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		        }
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+	    	}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmJobSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), vm.getId());
+    }
+    
+    public Outcome<VirtualMachine> addVmToNetworkThroughJobQueue(
+		final VirtualMachine vm, final Network network, final NicProfile requested) {
+    	
+        final CallContext context = CallContext.current();
+        final User user = context.getCallingUser();
+        final Account account = context.getCallingAccount();
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+	
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+		        	VirtualMachine.Type.Instance, vm.getId(), 
+		        	VmWorkAddVmToNetwork.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		                    
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkAddVmToNetwork.class.getName());
+		
+		            workJob.setAccountId(account.getId());
+		            workJob.setUserId(user.getId());
+		            workJob.setVmType(vm.getType());
+		            workJob.setVmInstanceId(vm.getId());
+		
+		            // save work context info (there are some duplications)
+		            VmWorkAddVmToNetwork workInfo = new VmWorkAddVmToNetwork(user.getId(), account.getId(), vm.getId(), 
+		            	network, requested);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		        }
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+	    	}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmJobSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), vm.getId());
+    }
+    
+    public Outcome<VirtualMachine> removeNicFromVmThroughJobQueue(
+    	final VirtualMachine vm, final Nic nic) {
+    	
+        final CallContext context = CallContext.current();
+        final User user = context.getCallingUser();
+        final Account account = context.getCallingAccount();
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+	
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+		        	VirtualMachine.Type.Instance, vm.getId(), 
+		        	VmWorkRemoveNicFromVm.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		                    
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkRemoveNicFromVm.class.getName());
+		
+		            workJob.setAccountId(account.getId());
+		            workJob.setUserId(user.getId());
+		            workJob.setVmType(vm.getType());
+		            workJob.setVmInstanceId(vm.getId());
+		
+		            // save work context info (there are some duplications)
+		            VmWorkRemoveNicFromVm workInfo = new VmWorkRemoveNicFromVm(user.getId(), account.getId(), vm.getId(), 
+		            	nic);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		        }
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+	    	}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmJobSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), vm.getId());
+    }
+
+    public Outcome<VirtualMachine> removeVmFromNetworkThroughJobQueue(
+    	final VirtualMachine vm, final Network network, final URI broadcastUri) {
+    	
+        final CallContext context = CallContext.current();
+        final User user = context.getCallingUser();
+        final Account account = context.getCallingAccount();
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+	
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+		        	VirtualMachine.Type.Instance, vm.getId(), 
+		        	VmWorkRemoveVmFromNetwork.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		                    
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkRemoveVmFromNetwork.class.getName());
+		
+		            workJob.setAccountId(account.getId());
+		            workJob.setUserId(user.getId());
+		            workJob.setVmType(vm.getType());
+		            workJob.setVmInstanceId(vm.getId());
+		
+		            // save work context info (there are some duplications)
+		            VmWorkRemoveVmFromNetwork workInfo = new VmWorkRemoveVmFromNetwork(user.getId(), account.getId(), vm.getId(), 
+		            	network, broadcastUri);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		        }
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+	    	}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmJobSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), vm.getId());
+    }
+    
+    public Outcome<VirtualMachine> reconfigureVmThroughJobQueue(
+    	final String vmUuid, final ServiceOffering oldServiceOffering, final boolean reconfiguringOnExistingHost) {
+    	
+        final CallContext context = CallContext.current();
+        final User user = context.getCallingUser();
+        final Account account = context.getCallingAccount();
+
+        final VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
+
+    	Transaction.execute(new TransactionCallbackNoReturn () {
+    		public void doInTransactionWithoutResult(TransactionStatus status) {
+	
+		        _vmDao.lockRow(vm.getId(), true);
+		
+		        List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
+		        	VirtualMachine.Type.Instance, vm.getId(), 
+		        	VmWorkReconfigure.class.getName());
+		
+		        VmWorkJobVO workJob = null;
+		        if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
+		            assert (pendingWorkJobs.size() == 1);
+		            workJob = pendingWorkJobs.get(0);
+		        } else {
+		                    
+		            workJob = new VmWorkJobVO(context.getContextId());
+		
+		            workJob.setDispatcher(VmWorkJobDispatcher.VM_WORK_JOB_DISPATCHER);
+		            workJob.setCmd(VmWorkReconfigure.class.getName());
+		
+		            workJob.setAccountId(account.getId());
+		            workJob.setUserId(user.getId());
+		            workJob.setVmType(vm.getType());
+		            workJob.setVmInstanceId(vm.getId());
+		
+		            // save work context info (there are some duplications)
+		            VmWorkReconfigure workInfo = new VmWorkReconfigure(user.getId(), account.getId(), vm.getId(), 
+		            		oldServiceOffering, reconfiguringOnExistingHost);
+		            workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
+		
+		            _jobMgr.submitAsyncJob(workJob, VmWorkJobDispatcher.VM_WORK_QUEUE, vm.getId());
+		        }
+	            context.putContextParameter("workJob", workJob);
+	            context.putContextParameter("jobId", new Long(vm.getId()));
+	    	}
+    	});
+    	
+    	final long jobId = (Long)context.getContextParameter("jobId");
+    	AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(jobId);
+    	
+        return new VmJobSyncOutcome((VmWorkJobVO)context.getContextParameter("workJob"), vm.getId());
+    }
+   
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/278ef81a/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java b/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java
index 7a23ddd..dacc8d0 100644
--- a/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java
+++ b/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java
@@ -19,7 +19,6 @@ package com.cloud.vm;
 import java.util.Map;
 
 import com.cloud.agent.api.HostVmStateReportEntry;
-import com.cloud.vm.VirtualMachine.PowerState;
 
 public interface VirtualMachinePowerStateSync {
 	
@@ -28,5 +27,5 @@ public interface VirtualMachinePowerStateSync {
 	void processHostVmStateReport(long hostId, Map<String, HostVmStateReportEntry> report);
 	
 	// to adapt legacy ping report
-	void processHostVmStatePingReport(long hostId, Map<String, PowerState> report);
+	void processHostVmStatePingReport(long hostId, Map<String, HostVmStateReportEntry> report);
 }


[3/6] git commit: updated refs/heads/4.3 to 5a44de2

Posted by ke...@apache.org.
CLOUDSTACK-669: Add host level side-by-side VM state report for graceful sync model migration


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/7be9b121
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/7be9b121
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/7be9b121

Branch: refs/heads/4.3
Commit: 7be9b121cfde399fdfb1b0fc4ea52f3d6cfc5efd
Parents: 43c3b8d
Author: Kelven Yang <ke...@gmail.com>
Authored: Mon Nov 11 22:42:36 2013 -0800
Committer: Kelven Yang <ke...@gmail.com>
Committed: Wed Nov 20 18:17:29 2013 -0800

----------------------------------------------------------------------
 .../com/cloud/agent/resource/DummyResource.java |   2 +-
 .../cloud/agent/api/HostVmStateReportEntry.java |  19 +-
 .../com/cloud/agent/api/PingRoutingCommand.java |  16 +-
 .../api/PingRoutingWithNwGroupsCommand.java     |   6 +-
 .../agent/api/PingRoutingWithOvsCommand.java    |   6 +-
 .../cloud/agent/api/StartupRoutingCommand.java  |  46 +++-
 .../networkservice/BareMetalResourceBase.java   |  33 ++-
 .../BaremetalDhcpResourceBase.java              |   4 +-
 .../networkservice/BaremetalDhcpdResource.java  |   4 +-
 .../BaremetalDnsmasqResource.java               |   4 +-
 .../BaremetalKickStartPxeResource.java          |   4 +-
 .../BaremetalPingPxeResource.java               |   4 +-
 .../resource/HypervDirectConnectResource.java   |   8 +-
 .../test/HypervDirectConnectResourceTest.java   |   4 +-
 .../kvm/resource/LibvirtComputingResource.java  | 133 +++++++++-
 .../cloud/ovm/hypervisor/OvmResourceBase.java   |  42 ++-
 .../cloud/resource/AgentRoutingResource.java    |  16 +-
 .../vmware/resource/VmwareResource.java         | 257 +++++++++++++------
 .../xen/resource/CitrixResourceBase.java        |  78 +++++-
 .../kvm/discoverer/KvmDummyResourceBase.java    |   5 +-
 .../cloud/resource/DummyHostServerResource.java |   4 +-
 .../hypervisor/vmware/mo/VirtualMachineMO.java  |  20 +-
 22 files changed, 584 insertions(+), 131 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/agent/src/com/cloud/agent/resource/DummyResource.java
----------------------------------------------------------------------
diff --git a/agent/src/com/cloud/agent/resource/DummyResource.java b/agent/src/com/cloud/agent/resource/DummyResource.java
index 37a8b3d..4918207 100755
--- a/agent/src/com/cloud/agent/resource/DummyResource.java
+++ b/agent/src/com/cloud/agent/resource/DummyResource.java
@@ -169,7 +169,7 @@ public class DummyResource implements ServerResource {
         final StartupRoutingCommand cmd = new StartupRoutingCommand(
                 (Integer) info.get(0), (Long) info.get(1), (Long) info.get(2),
                 (Long) info.get(4), (String) info.get(3), HypervisorType.KVM,
-                RouterPrivateIpStrategy.HostLocal, changes);
+                RouterPrivateIpStrategy.HostLocal, changes, null);
         fillNetworkInformation(cmd);
         cmd.getHostDetails().putAll(getVersionStrings());
         cmd.setCluster(getConfiguredProperty("cluster", "1"));

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/api/src/com/cloud/agent/api/HostVmStateReportEntry.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/HostVmStateReportEntry.java b/api/src/com/cloud/agent/api/HostVmStateReportEntry.java
index 7bcb50f..0b1a01e 100644
--- a/api/src/com/cloud/agent/api/HostVmStateReportEntry.java
+++ b/api/src/com/cloud/agent/api/HostVmStateReportEntry.java
@@ -19,16 +19,29 @@ package com.cloud.agent.api;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachine.PowerState;
 
+//
+// TODO vmsync
+// We should also have a HostVmStateReport class instead of using raw Map<> data structure,
+// for now, we store host-specific info at each VM entry and host fields are fixed
+// 
+// This needs to be refactor-ed afterwards
+//
 public class HostVmStateReportEntry {
     VirtualMachine.PowerState state;
+    
+    // host name or host uuid
     String host;
+
+    // XS needs Xen Tools version info
+    String hostToolsVersion;
     
     public HostVmStateReportEntry() {
     }
     
-    public HostVmStateReportEntry(PowerState state, String host) {
+    public HostVmStateReportEntry(PowerState state, String host, String hostToolsVersion) {
         this.state = state;
         this.host = host;
+        this.hostToolsVersion = hostToolsVersion;
     }
     
     public PowerState getState() {
@@ -38,4 +51,8 @@ public class HostVmStateReportEntry {
     public String getHost() {
         return host;
     }
+    
+    public String getHostToolsVersion() {
+    	return hostToolsVersion;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/core/src/com/cloud/agent/api/PingRoutingCommand.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/PingRoutingCommand.java b/core/src/com/cloud/agent/api/PingRoutingCommand.java
index e25ac62..cffa7ec 100755
--- a/core/src/com/cloud/agent/api/PingRoutingCommand.java
+++ b/core/src/com/cloud/agent/api/PingRoutingCommand.java
@@ -22,21 +22,33 @@ import com.cloud.host.Host;
 import com.cloud.vm.VirtualMachine.State;
 
 public class PingRoutingCommand extends PingCommand {
-    Map<String, State> newStates;
+    
+	// TODO vmsync {
+	Map<String, State> newStates;
+    // TODO vmsync }
+	
+	Map<String, HostVmStateReportEntry> _hostVmStateReport;
+    
     boolean _gatewayAccessible = true;
     boolean _vnetAccessible = true;
 
     protected PingRoutingCommand() {
     }
 
-    public PingRoutingCommand(Host.Type type, long id, Map<String, State> states) {
+    public PingRoutingCommand(Host.Type type, long id, Map<String, State> states,
+    	Map<String, HostVmStateReportEntry> hostVmStateReport) {
         super(type, id);
         this.newStates = states;
+        this._hostVmStateReport = hostVmStateReport;
     }
 
     public Map<String, State> getNewStates() {
         return newStates;
     }
+    
+    public Map<String, HostVmStateReportEntry> getHostVmStateReport() {
+    	return this._hostVmStateReport;
+    }
 
     public boolean isGatewayAccessible() {
         return _gatewayAccessible;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/core/src/com/cloud/agent/api/PingRoutingWithNwGroupsCommand.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/PingRoutingWithNwGroupsCommand.java b/core/src/com/cloud/agent/api/PingRoutingWithNwGroupsCommand.java
index 51226bc..5a25a75 100644
--- a/core/src/com/cloud/agent/api/PingRoutingWithNwGroupsCommand.java
+++ b/core/src/com/cloud/agent/api/PingRoutingWithNwGroupsCommand.java
@@ -31,8 +31,10 @@ public class PingRoutingWithNwGroupsCommand extends PingRoutingCommand {
 		super();
 	}
 
-	public PingRoutingWithNwGroupsCommand(Host.Type type, long id, Map<String, State> states, HashMap<String, Pair<Long, Long>> nwGrpStates) {
-		super(type, id, states);
+	public PingRoutingWithNwGroupsCommand(Host.Type type, long id, 
+		Map<String, State> states, Map<String, HostVmStateReportEntry> hostVmStateReport, 
+		HashMap<String, Pair<Long, Long>> nwGrpStates) {
+		super(type, id, states, hostVmStateReport);
 		newGroupStates = nwGrpStates;
 	}
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/core/src/com/cloud/agent/api/PingRoutingWithOvsCommand.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/PingRoutingWithOvsCommand.java b/core/src/com/cloud/agent/api/PingRoutingWithOvsCommand.java
index d44987b..b87dd0a 100644
--- a/core/src/com/cloud/agent/api/PingRoutingWithOvsCommand.java
+++ b/core/src/com/cloud/agent/api/PingRoutingWithOvsCommand.java
@@ -31,8 +31,10 @@ public class PingRoutingWithOvsCommand extends PingRoutingCommand {
 	}
 
 	public PingRoutingWithOvsCommand(Host.Type type, long id,
-			Map<String, State> states, List<Pair<String, Long>> ovsStates) {
-		super(type, id, states);
+			Map<String, State> states, Map<String, HostVmStateReportEntry> hostVmStateReport, 
+			List<Pair<String, Long>> ovsStates) {
+		super(type, id, states, hostVmStateReport);
+		
 		this.states = ovsStates;
 	}
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/core/src/com/cloud/agent/api/StartupRoutingCommand.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/StartupRoutingCommand.java b/core/src/com/cloud/agent/api/StartupRoutingCommand.java
index f312e0f..c75b6d1 100755
--- a/core/src/com/cloud/agent/api/StartupRoutingCommand.java
+++ b/core/src/com/cloud/agent/api/StartupRoutingCommand.java
@@ -48,8 +48,18 @@ public class StartupRoutingCommand extends StartupCommand {
     long memory;
     long dom0MinMemory;
     boolean poolSync;
+    
+    // VM power state report is added in a side-by-side way as old VM state report
+    // this is to allow a graceful migration from the old VM state sync model to the new model
+    //
+    // side-by-side addition of power state sync
+    Map<String, HostVmStateReportEntry> _hostVmStateReport;
+    
+    // TODO vmsync
+    // deprecated, will delete after full replacement
     Map<String, VmState> vms;
     HashMap<String, Ternary<String, State, String>> _clusterVMStates;
+    
     String caps;
     String pool;
     HypervisorType hypervisorType;
@@ -70,8 +80,10 @@ public class StartupRoutingCommand extends StartupCommand {
                                    String caps,
                                    HypervisorType hypervisorType,
                                    RouterPrivateIpStrategy privIpStrategy,
-                                   Map<String, VmState> vms) {
-        this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, vms);
+                                   Map<String, VmState> vms,
+                                   Map<String, HostVmStateReportEntry> hostVmStateReport
+    							) {
+        this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, vms, hostVmStateReport);
         getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStrategy.toString());
     }
 
@@ -82,9 +94,11 @@ public class StartupRoutingCommand extends StartupCommand {
             String caps,
             HypervisorType hypervisorType,
             RouterPrivateIpStrategy privIpStrategy) {
-this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, new HashMap<String,String>(), new HashMap<String, VmState>());
-getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStrategy.toString());
-}
+    	this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, new HashMap<String,String>(), 
+    		new HashMap<String, VmState>(), new HashMap<String, HostVmStateReportEntry>());
+    	
+    	getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStrategy.toString());
+    }
 
     public StartupRoutingCommand(int cpus,
             long speed,
@@ -93,13 +107,15 @@ getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStr
             final String caps,
             final HypervisorType hypervisorType,
             final Map<String, String> hostDetails,
-            Map<String, VmState> vms) {
+            Map<String, VmState> vms,
+            Map<String, HostVmStateReportEntry> hostVmStateReport) {
         super(Host.Type.Routing);
         this.cpus = cpus;
         this.speed = speed;
         this.memory = memory;
         this.dom0MinMemory = dom0MinMemory;
         this.vms = vms;
+        this._hostVmStateReport = hostVmStateReport;
         this.hypervisorType = hypervisorType;
         this.hostDetails = hostDetails;
         this.caps = caps;
@@ -108,12 +124,14 @@ getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStr
 
     public StartupRoutingCommand(int cpus2, long speed2, long memory2,
             long dom0MinMemory2, String caps2, HypervisorType hypervisorType2,
-            Map<String, VmState> vms2) {
-        this(cpus2, speed2, memory2, dom0MinMemory2, caps2, hypervisorType2, new HashMap<String,String>(), vms2);
+            Map<String, VmState> vms2, Map<String, HostVmStateReportEntry> hostVmStateReport
+            ) {
+        this(cpus2, speed2, memory2, dom0MinMemory2, caps2, hypervisorType2, new HashMap<String,String>(), vms2, hostVmStateReport);
     }
 
-    public StartupRoutingCommand(int cpus, long speed, long memory, long dom0MinMemory, final String caps, final HypervisorType hypervisorType, final Map<String, String> hostDetails, Map<String, VmState> vms, String hypervisorVersion) {
-        this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, hostDetails, vms);
+    public StartupRoutingCommand(int cpus, long speed, long memory, long dom0MinMemory, final String caps, final HypervisorType hypervisorType, final Map<String, String> hostDetails, 
+    		Map<String, VmState> vms, Map<String, HostVmStateReportEntry> vmPowerStates, String hypervisorVersion) {
+        this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, hostDetails, vms, vmPowerStates);
         this.hypervisorVersion = hypervisorVersion;
     }
 
@@ -229,5 +247,13 @@ getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStr
     public void setHypervisorVersion(String hypervisorVersion) {
         this.hypervisorVersion = hypervisorVersion;
     }
+    
+    public Map<String, HostVmStateReportEntry> getHostVmStateReport() {
+    	return this._hostVmStateReport;
+    }
+    
+    public void setHostVmStateReport(Map<String, HostVmStateReportEntry> hostVmStateReport) {
+    	this._hostVmStateReport = hostVmStateReport;
+    }
 }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java
index fa7abd5..2418a19 100755
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java
@@ -31,7 +31,6 @@ import javax.ejb.Local;
 import javax.naming.ConfigurationException;
 
 import org.apache.log4j.Logger;
-
 import org.apache.cloudstack.api.ApiConstants;
 
 import com.cloud.agent.IAgentControl;
@@ -41,6 +40,7 @@ import com.cloud.agent.api.CheckNetworkCommand;
 import com.cloud.agent.api.CheckVirtualMachineAnswer;
 import com.cloud.agent.api.CheckVirtualMachineCommand;
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.HostVmStateReportEntry;
 import com.cloud.agent.api.MaintainAnswer;
 import com.cloud.agent.api.MaintainCommand;
 import com.cloud.agent.api.MigrateAnswer;
@@ -77,6 +77,7 @@ import com.cloud.utils.script.Script2;
 import com.cloud.utils.script.Script2.ParamType;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachine.PowerState;
 import com.cloud.vm.VirtualMachine.State;
 import com.cloud.vm.dao.VMInstanceDao;
 
@@ -332,10 +333,36 @@ public class BareMetalResourceBase extends ManagerBase implements ServerResource
 
         return states;
     }
+    
+    protected Map<String, HostVmStateReportEntry> getHostVmStateReport() {
+        Map<String, HostVmStateReportEntry> states = new HashMap<String, HostVmStateReportEntry>();
+        if (hostId != null) {
+            vmDao = ComponentContext.getComponent(VMInstanceDao.class);
+            final List<? extends VMInstanceVO> vms = vmDao.listByHostId(hostId);
+            for (VMInstanceVO vm : vms) {
+                states.put(
+                	vm.getInstanceName(), 
+                	new HostVmStateReportEntry(
+                	    vm.getState() == State.Running ? PowerState.PowerOn : PowerState.PowerOff, "host-" + hostId, null
+                	)
+                );
+            }
+        }
+        /*
+         * Map<String, State> changes = new HashMap<String, State>();
+         * 
+         * if (_vmName != null) { State state = getVmState(); if (state != null)
+         * { changes.put(_vmName, state); } }
+         */
+
+        return states;
+    }
 
 	@Override
 	public StartupCommand[] initialize() {
-		StartupRoutingCommand cmd = new StartupRoutingCommand(0, 0, 0, 0, null, Hypervisor.HypervisorType.BareMetal, new HashMap<String, String>(), null);
+		StartupRoutingCommand cmd = new StartupRoutingCommand(0, 0, 0, 0, null, Hypervisor.HypervisorType.BareMetal, 
+			new HashMap<String, String>(), null, null);
+		
 		cmd.setDataCenter(_zone);
 		cmd.setPod(_pod);
 		cmd.setCluster(_cluster);
@@ -372,7 +399,7 @@ public class BareMetalResourceBase extends ManagerBase implements ServerResource
 			return null;
 		}
 
-		return new PingRoutingCommand(getType(), id, deltaSync());
+		return new PingRoutingCommand(getType(), id, deltaSync(), getHostVmStateReport());
 	}
 
 	protected Answer execute(IpmISetBootDevCommand cmd) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResourceBase.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResourceBase.java
index 2a17a43..f992fe9 100755
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResourceBase.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResourceBase.java
@@ -32,6 +32,7 @@ import org.apache.log4j.Logger;
 import com.cloud.agent.IAgentControl;
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.HostVmStateReportEntry;
 import com.cloud.agent.api.PingCommand;
 import com.cloud.agent.api.PingRoutingCommand;
 import com.cloud.agent.api.ReadyAnswer;
@@ -129,7 +130,8 @@ public class BaremetalDhcpResourceBase extends ManagerBase implements ServerReso
 	@Override
 	public PingCommand getCurrentStatus(long id) {
 		//TODO: check server
-		return new PingRoutingCommand(getType(), id, new HashMap<String, State>());
+		return new PingRoutingCommand(getType(), id, new HashMap<String, State>(),
+			new HashMap<String, HostVmStateReportEntry>());
 	}
 
 	protected ReadyAnswer execute(ReadyCommand cmd) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpdResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpdResource.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpdResource.java
index a27a6f2..dc77812 100755
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpdResource.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpdResource.java
@@ -31,6 +31,7 @@ import org.apache.log4j.Logger;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.HostVmStateReportEntry;
 import com.cloud.agent.api.PingCommand;
 import com.cloud.agent.api.PingRoutingCommand;
 import com.cloud.agent.api.routing.DhcpEntryCommand;
@@ -105,7 +106,8 @@ public class BaremetalDhcpdResource extends BaremetalDhcpResourceBase {
 			return null;
 		} else {
 			SSHCmdHelper.releaseSshConnection(sshConnection);
-			return new PingRoutingCommand(getType(), id, new HashMap<String, State>());
+			return new PingRoutingCommand(getType(), id, new HashMap<String, State>(), 
+				new HashMap<String, HostVmStateReportEntry>());
 		}
 	}
 	

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java
index d0fb2b4..19a4d90 100755
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java
@@ -32,6 +32,7 @@ import org.apache.log4j.Logger;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.HostVmStateReportEntry;
 import com.cloud.agent.api.PingCommand;
 import com.cloud.agent.api.PingRoutingCommand;
 import com.cloud.agent.api.routing.DhcpEntryCommand;
@@ -98,7 +99,8 @@ public class BaremetalDnsmasqResource extends BaremetalDhcpResourceBase {
 			return null;
 		} else {
 			SSHCmdHelper.releaseSshConnection(sshConnection);
-			return new PingRoutingCommand(getType(), id, new HashMap<String, State>());
+			return new PingRoutingCommand(getType(), id, new HashMap<String, State>(),
+				new HashMap<String, HostVmStateReportEntry>());
 		}
 	}
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java
index 7a7a515..e4f0cee 100755
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java
@@ -29,6 +29,7 @@ import org.apache.log4j.Logger;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.HostVmStateReportEntry;
 import com.cloud.agent.api.PingCommand;
 import com.cloud.agent.api.PingRoutingCommand;
 import com.cloud.agent.api.routing.VmDataCommand;
@@ -106,7 +107,8 @@ public class BaremetalKickStartPxeResource extends BaremetalPxeResourceBase {
             return null;
         } else {
             SSHCmdHelper.releaseSshConnection(sshConnection);
-            return new PingRoutingCommand(getType(), id, new HashMap<String, State>());
+            return new PingRoutingCommand(getType(), id, new HashMap<String, State>(),
+            	new HashMap<String, HostVmStateReportEntry>());
         }
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java
index 2fb5415..59efe24 100755
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java
@@ -32,6 +32,7 @@ import org.apache.log4j.Logger;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.HostVmStateReportEntry;
 import com.cloud.agent.api.PingCommand;
 import com.cloud.agent.api.PingRoutingCommand;
 import com.cloud.agent.api.baremetal.PreparePxeServerAnswer;
@@ -142,7 +143,8 @@ public class BaremetalPingPxeResource extends BaremetalPxeResourceBase {
 			return null;
 		} else {
 			SSHCmdHelper.releaseSshConnection(sshConnection);
-			return new PingRoutingCommand(getType(), id, new HashMap<String, State>());
+			return new PingRoutingCommand(getType(), id, new HashMap<String, State>(),
+				new HashMap<String, HostVmStateReportEntry>());
 		}
 	}
 	

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
index 194ad77..165d706 100644
--- a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
+++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
@@ -42,7 +42,6 @@ import org.apache.http.util.EntityUtils;
 import org.apache.log4j.Logger;
 
 import com.google.gson.Gson;
-
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.CheckRouterAnswer;
 import com.cloud.agent.api.CheckRouterCommand;
@@ -51,6 +50,7 @@ import com.cloud.agent.api.CheckS2SVpnConnectionsCommand;
 import com.cloud.agent.api.Command;
 import com.cloud.agent.api.GetDomRVersionAnswer;
 import com.cloud.agent.api.GetDomRVersionCmd;
+import com.cloud.agent.api.HostVmStateReportEntry;
 import com.cloud.agent.api.NetworkUsageAnswer;
 import com.cloud.agent.api.NetworkUsageCommand;
 import com.cloud.agent.api.PingCommand;
@@ -158,7 +158,8 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
                 new StartupRoutingCommand(0, 0, 0, 0, null,
                         Hypervisor.HypervisorType.Hyperv,
                         RouterPrivateIpStrategy.HostLocal,
-                        new HashMap<String, VmState>());
+                        new HashMap<String, VmState>(),
+                        new HashMap<String, HostVmStateReportEntry>());
 
         // Identity within the data centre is decided by CloudStack kernel,
         // and passed via ServerResource.configure()
@@ -293,7 +294,8 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
 
     @Override
     public final PingCommand getCurrentStatus(final long id) {
-        PingCommand pingCmd = new PingRoutingCommand(getType(), id, null);
+    	// TODO, need to report VM states on host
+        PingCommand pingCmd = new PingRoutingCommand(getType(), id, null, null);
 
         if (s_logger.isDebugEnabled()) {
             s_logger.debug("Ping host " + _name + " (IP " + _agentIp + ")");

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/plugins/hypervisors/hyperv/test/com/cloud/hypervisor/hyperv/test/HypervDirectConnectResourceTest.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/test/com/cloud/hypervisor/hyperv/test/HypervDirectConnectResourceTest.java b/plugins/hypervisors/hyperv/test/com/cloud/hypervisor/hyperv/test/HypervDirectConnectResourceTest.java
index 1f90da9..3369460 100644
--- a/plugins/hypervisors/hyperv/test/com/cloud/hypervisor/hyperv/test/HypervDirectConnectResourceTest.java
+++ b/plugins/hypervisors/hyperv/test/com/cloud/hypervisor/hyperv/test/HypervDirectConnectResourceTest.java
@@ -57,6 +57,7 @@ import com.cloud.agent.api.GetStorageStatsAnswer;
 import com.cloud.agent.api.GetStorageStatsCommand;
 import com.cloud.agent.api.GetVmStatsAnswer;
 import com.cloud.agent.api.GetVmStatsCommand;
+import com.cloud.agent.api.HostVmStateReportEntry;
 import com.cloud.agent.api.ModifyStoragePoolCommand;
 import com.cloud.agent.api.StartAnswer;
 import com.cloud.agent.api.StartCommand;
@@ -298,7 +299,8 @@ public class HypervDirectConnectResourceTest {
         StartupRoutingCommand defaultStartRoutCmd = new StartupRoutingCommand(
                 0, 0, 0, 0, null, Hypervisor.HypervisorType.Hyperv,
                 RouterPrivateIpStrategy.HostLocal,
-                new HashMap<String, VmState>());
+                new HashMap<String, VmState>(),
+                new HashMap<String, HostVmStateReportEntry>());
 
         // Identity within the data centre is decided by CloudStack kernel,
         // and passed via ServerResource.configure()

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index 775b2b8..50f43c0 100755
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@ -59,6 +59,7 @@ import javax.naming.ConfigurationException;
 
 import com.cloud.agent.api.CheckOnHostCommand;
 import com.cloud.agent.api.routing.*;
+
 import org.apache.commons.io.FileUtils;
 import org.apache.log4j.Logger;
 import org.libvirt.Connect;
@@ -69,7 +70,6 @@ import org.libvirt.DomainInterfaceStats;
 import org.libvirt.DomainSnapshot;
 import org.libvirt.LibvirtException;
 import org.libvirt.NodeInfo;
-
 import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
 import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
 import org.apache.cloudstack.storage.to.VolumeObjectTO;
@@ -112,6 +112,7 @@ import com.cloud.agent.api.GetVmStatsCommand;
 import com.cloud.agent.api.GetVncPortAnswer;
 import com.cloud.agent.api.GetVncPortCommand;
 import com.cloud.agent.api.HostStatsEntry;
+import com.cloud.agent.api.HostVmStateReportEntry;
 import com.cloud.agent.api.MaintainAnswer;
 import com.cloud.agent.api.MaintainCommand;
 import com.cloud.agent.api.ManageSnapshotAnswer;
@@ -236,8 +237,8 @@ import com.cloud.utils.script.OutputInterpreter;
 import com.cloud.utils.script.Script;
 import com.cloud.vm.DiskProfile;
 import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachine.PowerState;
 import com.cloud.vm.VirtualMachine.State;
-
 import com.ceph.rados.Rados;
 import com.ceph.rados.RadosException;
 import com.ceph.rados.IoCTX;
@@ -373,6 +374,8 @@ ServerResource {
     protected int _timeout;
     protected int _cmdsTimeout;
     protected int _stopTimeout;
+    
+    // TODO vmsync {
     protected static HashMap<DomainInfo.DomainState, State> s_statesTable;
     static {
         s_statesTable = new HashMap<DomainInfo.DomainState, State>();
@@ -389,6 +392,24 @@ ServerResource {
         s_statesTable.put(DomainInfo.DomainState.VIR_DOMAIN_SHUTDOWN,
                 State.Stopping);
     }
+    // TODO vmsync }
+
+    protected static HashMap<DomainInfo.DomainState, PowerState> s_powerStatesTable;
+    static {
+    	s_powerStatesTable = new HashMap<DomainInfo.DomainState, PowerState>();
+    	s_powerStatesTable.put(DomainInfo.DomainState.VIR_DOMAIN_SHUTOFF,
+                PowerState.PowerOff);
+    	s_powerStatesTable.put(DomainInfo.DomainState.VIR_DOMAIN_PAUSED,
+                PowerState.PowerOn);
+    	s_powerStatesTable.put(DomainInfo.DomainState.VIR_DOMAIN_RUNNING,
+                PowerState.PowerOn);
+    	s_powerStatesTable.put(DomainInfo.DomainState.VIR_DOMAIN_BLOCKED,
+                PowerState.PowerOn);
+    	s_powerStatesTable.put(DomainInfo.DomainState.VIR_DOMAIN_NOSTATE,
+                PowerState.PowerUnknown);
+    	s_powerStatesTable.put(DomainInfo.DomainState.VIR_DOMAIN_SHUTDOWN,
+                PowerState.PowerOff);
+    }
 
     protected HashMap<String, State> _vms = new HashMap<String, State>(20);
     protected List<String> _vmsKilled = new ArrayList<String>();
@@ -2814,6 +2835,11 @@ ServerResource {
         final State state = s_statesTable.get(ps);
         return state == null ? State.Unknown : state;
     }
+    
+    protected PowerState convertToPowerState(DomainInfo.DomainState ps) {
+        final PowerState state = s_powerStatesTable.get(ps);
+        return state == null ? PowerState.PowerUnknown : state;
+    }
 
     protected State getVmState(Connect conn, final String vmName) {
         int retry = 3;
@@ -3962,10 +3988,10 @@ ServerResource {
 
         if (!_can_bridge_firewall) {
             return new PingRoutingCommand(com.cloud.host.Host.Type.Routing, id,
-                    newStates);
+                    newStates, this.getHostVmStateReport());
         } else {
             HashMap<String, Pair<Long, Long>> nwGrpStates = syncNetworkGroups(id);
-            return new PingRoutingWithNwGroupsCommand(getType(), id, newStates,
+            return new PingRoutingWithNwGroupsCommand(getType(), id, newStates, this.getHostVmStateReport(),
                     nwGrpStates);
         }
     }
@@ -4010,6 +4036,7 @@ ServerResource {
         cmd.setPool(_pool);
         cmd.setCluster(_clusterId);
         cmd.setGatewayIpAddress(_localGateway);
+        cmd.setHostVmStateReport(getHostVmStateReport());
 
         StartupStorageCommand sscmd = null;
         try {
@@ -4323,6 +4350,104 @@ ServerResource {
 
         return vmStates;
     }
+    
+    private HashMap<String, HostVmStateReportEntry> getHostVmStateReport() {
+        final HashMap<String, HostVmStateReportEntry> vmStates = new HashMap<String, HostVmStateReportEntry>();
+        Connect conn = null;
+
+        if (_hypervisorType == HypervisorType.LXC) {
+        try {
+            conn = LibvirtConnection.getConnectionByType(HypervisorType.LXC.toString());
+            vmStates.putAll(getHostVmStateReport(conn));
+        } catch (LibvirtException e) {
+            s_logger.debug("Failed to get connection: " + e.getMessage());
+        }
+        }
+
+        if (_hypervisorType == HypervisorType.KVM) {
+        try {
+            conn = LibvirtConnection.getConnectionByType(HypervisorType.KVM.toString());
+            vmStates.putAll(getHostVmStateReport(conn));
+        } catch (LibvirtException e) {
+            s_logger.debug("Failed to get connection: " + e.getMessage());
+        }
+        }
+
+        return vmStates;
+    }
+    
+    private HashMap<String, HostVmStateReportEntry> getHostVmStateReport(Connect conn) {
+        final HashMap<String, HostVmStateReportEntry> vmStates = new HashMap<String, HostVmStateReportEntry>();
+
+        String[] vms = null;
+        int[] ids = null;
+
+        try {
+            ids = conn.listDomains();
+        } catch (final LibvirtException e) {
+            s_logger.warn("Unable to listDomains", e);
+            return null;
+        }
+        try {
+            vms = conn.listDefinedDomains();
+        } catch (final LibvirtException e) {
+            s_logger.warn("Unable to listDomains", e);
+            return null;
+        }
+
+        Domain dm = null;
+        for (int i = 0; i < ids.length; i++) {
+            try {
+                dm = conn.domainLookupByID(ids[i]);
+
+                DomainInfo.DomainState ps = dm.getInfo().state;
+
+                final PowerState state = convertToPowerState(ps);
+
+                s_logger.trace("VM " + dm.getName() + ": powerstate = " + ps
+                        + "; vm state=" + state.toString());
+                String vmName = dm.getName();
+                vmStates.put(vmName, new HostVmStateReportEntry(state, conn.getHostName(), null));
+            } catch (final LibvirtException e) {
+                s_logger.warn("Unable to get vms", e);
+            } finally {
+                try {
+                    if (dm != null) {
+                        dm.free();
+                    }
+                } catch (LibvirtException e) {
+                    s_logger.trace("Ignoring libvirt error.", e);
+                }
+            }
+        }
+
+        for (int i = 0; i < vms.length; i++) {
+            try {
+
+                dm = conn.domainLookupByName(vms[i]);
+
+                DomainInfo.DomainState ps = dm.getInfo().state;
+                final PowerState state = convertToPowerState(ps);
+                String vmName = dm.getName();
+                s_logger.trace("VM " + vmName + ": powerstate = " + ps
+                        + "; vm state=" + state.toString());
+
+                vmStates.put(vmName, new HostVmStateReportEntry(state, conn.getHostName(), null));
+            } catch (final LibvirtException e) {
+                s_logger.warn("Unable to get vms", e);
+            } finally {
+                try {
+                    if (dm != null) {
+                        dm.free();
+                    }
+                } catch (LibvirtException e) {
+                    s_logger.trace("Ignoring libvirt error.", e);
+                }
+            }
+        }
+
+        return vmStates;
+    }
 
     protected List<Object> getHostInfo() {
         final ArrayList<Object> info = new ArrayList<Object>();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java b/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java
index 2d0d67b..32679c8 100755
--- a/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java
+++ b/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java
@@ -35,7 +35,6 @@ import org.apache.log4j.Logger;
 import org.apache.xmlrpc.XmlRpcException;
 
 import com.trilead.ssh2.SCPClient;
-
 import com.cloud.agent.IAgentControl;
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.AttachIsoCommand;
@@ -61,6 +60,7 @@ import com.cloud.agent.api.GetVmStatsCommand;
 import com.cloud.agent.api.GetVncPortAnswer;
 import com.cloud.agent.api.GetVncPortCommand;
 import com.cloud.agent.api.HostStatsEntry;
+import com.cloud.agent.api.HostVmStateReportEntry;
 import com.cloud.agent.api.MaintainAnswer;
 import com.cloud.agent.api.MaintainCommand;
 import com.cloud.agent.api.MigrateAnswer;
@@ -131,6 +131,7 @@ import com.cloud.utils.script.Script;
 import com.cloud.utils.ssh.SSHCmdHelper;
 import com.cloud.vm.DiskProfile;
 import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachine.PowerState;
 import com.cloud.vm.VirtualMachine.State;
 import com.trilead.ssh2.SCPClient;
 
@@ -153,11 +154,12 @@ public class OvmResourceBase implements ServerResource, HypervisorResource {
     boolean _canBridgeFirewall;
     static boolean _isHeartBeat = false;
     List<String> _bridges = null;
-	protected HashMap<String, State> _vms = new HashMap<String, State>(50);
-	static HashMap<String, State> _stateMaps;
 	private final Map<String, Pair<Long, Long>> _vmNetworkStats= new ConcurrentHashMap<String, Pair<Long, Long>>();
 	private static String _ovsAgentPath = "/opt/ovs-agent-latest";
-	
+
+	// TODO vmsync {
+	static HashMap<String, State> _stateMaps;
+	protected HashMap<String, State> _vms = new HashMap<String, State>(50);
 	static {
 		_stateMaps = new HashMap<String, State>();
 		_stateMaps.put("RUNNING", State.Running);
@@ -165,6 +167,16 @@ public class OvmResourceBase implements ServerResource, HypervisorResource {
 		_stateMaps.put("ERROR", State.Error);
 		_stateMaps.put("SUSPEND", State.Stopped);
 	}
+	// TODO vmsync }
+	
+	static HashMap<String, PowerState> _powerStateMaps;
+	static {
+		_powerStateMaps = new HashMap<String, PowerState>();
+		_powerStateMaps.put("RUNNING", PowerState.PowerOn);
+		_powerStateMaps.put("DOWN", PowerState.PowerOff);
+		_powerStateMaps.put("ERROR", PowerState.PowerUnknown);
+		_powerStateMaps.put("SUSPEND", PowerState.PowerOff);
+	}
 	
 	@Override
 	public boolean configure(String name, Map<String, Object> params)
@@ -303,6 +315,7 @@ public class OvmResourceBase implements ServerResource, HypervisorResource {
 			//TODO: introudce PIF
 			cmd.setPrivateIpAddress(_ip);
 			cmd.setStorageIpAddress(_ip);
+			cmd.setHostVmStateReport(getHostVmStateReport());
 			
 			String defaultBridge = OvmBridge.getBridgeByIp(_conn, _ip);
 			if (_publicNetworkName == null) {
@@ -397,7 +410,7 @@ public class OvmResourceBase implements ServerResource, HypervisorResource {
 		try {
 			OvmHost.ping(_conn);
 			HashMap<String, State> newStates = sync();
-			return new PingRoutingCommand(getType(), id, newStates);
+			return new PingRoutingCommand(getType(), id, newStates, this.getHostVmStateReport());
 		} catch (XmlRpcException e) {
 			s_logger.debug("Check agent status failed", e);
 			return null;
@@ -785,6 +798,25 @@ public class OvmResourceBase implements ServerResource, HypervisorResource {
         return state;
     }
 
+    private PowerState toPowerState(String vmName, String s) {
+        PowerState state = _powerStateMaps.get(s);
+        if (state == null) {
+            s_logger.debug("Unkown state " + s + " for " + vmName);
+            state = PowerState.PowerUnknown;
+        }
+        return state;
+    }
+           
+    protected HashMap<String, HostVmStateReportEntry> getHostVmStateReport() throws XmlRpcException {
+        final HashMap<String, HostVmStateReportEntry> vmStates = new HashMap<String, HostVmStateReportEntry>();
+        Map<String, String> vms = OvmHost.getAllVms(_conn);
+        for (final Map.Entry<String, String> entry : vms.entrySet()) {
+            PowerState state = toPowerState(entry.getKey(), entry.getValue());
+            vmStates.put(entry.getKey(), new HostVmStateReportEntry(state, _conn.getIp(), null));
+        }
+        return vmStates;
+    }
+    
     protected HashMap<String, State> getAllVms() throws XmlRpcException {
         final HashMap<String, State> vmStates = new HashMap<String, State>();
         Map<String, String> vms = OvmHost.getAllVms(_conn);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java b/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java
index 9a27d74..727e067 100644
--- a/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java
+++ b/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java
@@ -29,6 +29,7 @@ import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.CheckVirtualMachineAnswer;
 import com.cloud.agent.api.CheckVirtualMachineCommand;
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.HostVmStateReportEntry;
 import com.cloud.agent.api.PingCommand;
 import com.cloud.agent.api.PingRoutingWithNwGroupsCommand;
 import com.cloud.agent.api.ReadyAnswer;
@@ -53,6 +54,7 @@ import com.cloud.simulator.MockVMVO;
 import com.cloud.storage.Storage.StorageResourceType;
 import com.cloud.storage.template.TemplateProp;
 import com.cloud.utils.Pair;
+import com.cloud.vm.VirtualMachine.PowerState;
 import com.cloud.vm.VirtualMachine.State;
 
 public class AgentRoutingResource extends AgentStorageResource {
@@ -114,7 +116,7 @@ public class AgentRoutingResource extends AgentStorageResource {
         }
         final HashMap<String, State> newStates = sync();
         HashMap<String, Pair<Long, Long>> nwGrpStates = _simMgr.syncNetworkGroups(hostGuid);
-        return new PingRoutingWithNwGroupsCommand(getType(), id, newStates, nwGrpStates);
+        return new PingRoutingWithNwGroupsCommand(getType(), id, newStates, getHostVmStateReport(), nwGrpStates);
     }
 
     @Override
@@ -275,6 +277,18 @@ public class AgentRoutingResource extends AgentStorageResource {
 
         return info;
     }
+    
+    protected HashMap<String, HostVmStateReportEntry> getHostVmStateReport() {
+    	HashMap<String, HostVmStateReportEntry> report = new HashMap<String, HostVmStateReportEntry>();
+    	
+    	for(String vmName : _runningVms.keySet()) {
+    		report.put(vmName, new HostVmStateReportEntry(PowerState.PowerOn, agentHost.getName(), null));
+    	}
+    	
+    	
+    	
+    	return report;
+    }
 
     protected HashMap<String, State> sync() {
         Map<String, State> newStates;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index 03af0da..26ef047 100755
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -46,6 +46,7 @@ import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
 import com.cloud.agent.api.routing.*;
+
 import org.apache.log4j.Logger;
 import org.apache.log4j.NDC;
 
@@ -161,6 +162,7 @@ import com.cloud.agent.api.GetVmStatsCommand;
 import com.cloud.agent.api.GetVncPortAnswer;
 import com.cloud.agent.api.GetVncPortCommand;
 import com.cloud.agent.api.HostStatsEntry;
+import com.cloud.agent.api.HostVmStateReportEntry;
 import com.cloud.agent.api.MaintainAnswer;
 import com.cloud.agent.api.MaintainCommand;
 import com.cloud.agent.api.ManageSnapshotAnswer;
@@ -301,6 +303,7 @@ import com.cloud.utils.net.NetUtils;
 import com.cloud.utils.ssh.SshHelper;
 import com.cloud.vm.DiskProfile;
 import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachine.PowerState;
 import com.cloud.vm.VirtualMachine.State;
 import com.cloud.vm.VirtualMachineName;
 import com.cloud.vm.VmDetailConstants;
@@ -358,6 +361,17 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
 
     protected StorageSubsystemCommandHandler storageHandler;
 
+    protected static HashMap<VirtualMachinePowerState, PowerState> s_powerStatesTable;
+    static {
+    	s_powerStatesTable = new HashMap<VirtualMachinePowerState, PowerState>();
+    	s_powerStatesTable.put(VirtualMachinePowerState.POWERED_ON, PowerState.PowerOn);
+    	s_powerStatesTable.put(VirtualMachinePowerState.POWERED_OFF, PowerState.PowerOff);
+    	s_powerStatesTable.put(VirtualMachinePowerState.SUSPENDED, PowerState.PowerOn);
+    }
+    
+    // TODO vmsync {
+    // deprecated, will delete after full replacement
+    //
     protected static HashMap<VirtualMachinePowerState, State> s_statesTable;
     static {
         s_statesTable = new HashMap<VirtualMachinePowerState, State>();
@@ -365,6 +379,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         s_statesTable.put(VirtualMachinePowerState.POWERED_OFF, State.Stopped);
         s_statesTable.put(VirtualMachinePowerState.SUSPENDED, State.Stopped);
     }
+    // TODO vmsync }
 
     public Gson getGson() {
         return _gson;
@@ -2559,7 +2574,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
             long requestedMaxMemoryInMb = vmSpec.getMaxRam() / (1024 * 1024);
 
             // Check if VM is really running on hypervisor host
-            if (getVmState(vmMo) != State.Running) {
+            if (getVmPowerState(vmMo) != PowerState.PowerOn) {
                 throw new CloudRuntimeException("Found that the VM " + vmMo.getVmName() + " is not running. Unable to scale-up this VM");
             }
 
@@ -2609,7 +2624,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         try {
             VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
 
-            // mark VM as starting state so that sync() can know not to report stopped too early
+            // mark VM as starting state so that sync can know not to report stopped too early
             synchronized (_vms) {
                 _vms.put(vmInternalCSName, State.Starting);
             }
@@ -2639,7 +2654,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
             boolean hasSnapshot = false;
             if (vmMo != null) {
                 s_logger.info("VM " + vmInternalCSName + " already exists, tear down devices for reconfiguration");
-                if (getVmState(vmMo) != State.Stopped)
+                if (getVmPowerState(vmMo) != PowerState.PowerOff)
                     vmMo.safePowerOff(_shutdown_waitMs);
              
                 // retrieve disk information before we tear down
@@ -2662,7 +2677,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
 
                     takeVmFromOtherHyperHost(hyperHost, vmInternalCSName);
 
-                    if (getVmState(vmMo) != State.Stopped)
+                    if (getVmPowerState(vmMo) != PowerState.PowerOff)
                         vmMo.safePowerOff(_shutdown_waitMs);
                     
                     diskInfoBuilder = vmMo.getDiskInfoBuilder();
@@ -3885,7 +3900,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                 try {
                     vmMo.setCustomFieldValue(CustomFieldConstants.CLOUD_NIC_MASK, "0");
 
-                    if (getVmState(vmMo) != State.Stopped) {
+                    if (getVmPowerState(vmMo) != PowerState.PowerOff) {
                         if (vmMo.safePowerOff(_shutdown_waitMs)) {
                             state = State.Stopped;
                             return new StopAnswer(cmd, "Stop VM " + cmd.getVmName() + " Succeed", true);
@@ -5488,7 +5503,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                         List<NetworkDetails> networks = vmMo.getNetworksWithDetails();
 
                         // tear down all devices first before we destroy the VM to avoid accidently delete disk backing files
-                        if (getVmState(vmMo) != State.Stopped)
+                        if (getVmPowerState(vmMo) != PowerState.PowerOff)
                             vmMo.safePowerOff(_shutdown_waitMs);
                         vmMo.tearDownDevices(new Class<?>[] { /* VirtualDisk.class, */ VirtualEthernetCard.class });
                         vmMo.destroy();
@@ -5813,86 +5828,85 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
 
     @Override
     public PingCommand getCurrentStatus(long id) {
-    	try {
-	        HashMap<String, State> newStates = sync();
-	        if (newStates == null) {
-	            return null;
-	        }
-	
-	        try {
-	            // take the chance to do left-over dummy VM cleanup from previous run
-	            VmwareContext context = getServiceContext();
-	            VmwareHypervisorHost hyperHost = getHyperHost(context);
-	            VmwareManager mgr = hyperHost.getContext().getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
-	
-	            if(hyperHost.isHyperHostConnected()) {
-	                mgr.gcLeftOverVMs(context);
-	
-                    s_logger.info("Scan hung worker VM to recycle");
-                    
-            		int workerKey = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_WORKER);
-            		int workerTagKey = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_WORKER_TAG);
-            		String workerPropName = String.format("value[%d]", workerKey);
-            		String workerTagPropName = String.format("value[%d]", workerTagKey);
-
-                    // GC worker that has been running for too long
-                    ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost(
-                            new String[] {"name", "config.template", workerPropName, workerTagPropName, 
-                            		 });
-                    if(ocs != null) {
-                        for(ObjectContent oc : ocs) {
-                            List<DynamicProperty> props = oc.getPropSet();
-                            if(props != null) {
-                                boolean template = false;
-                                boolean isWorker = false;
-                                String workerTag = null;
-
-                                for(DynamicProperty prop : props) {
-                                    if(prop.getName().equals("config.template")) {
-                                        template = (Boolean)prop.getVal();
-                                    } else if(prop.getName().equals(workerPropName)) {
-                                    	CustomFieldStringValue val = (CustomFieldStringValue)prop.getVal();
-                                    	if(val != null && val.getValue() != null && val.getValue().equalsIgnoreCase("true"))
-                                    		isWorker = true;
-                                    }
-                                    else if(prop.getName().equals(workerTagPropName)) {
-                                    	CustomFieldStringValue val = (CustomFieldStringValue)prop.getVal();
-                                    	workerTag = val.getValue();
-                                    }
+		gcAndKillHungWorkerVMs();
+        
+		HashMap<String, State> newStates = sync();
+        if (newStates == null) {
+            return null;
+        }
+        return new PingRoutingCommand(getType(), id, newStates, syncHostVmStates());
+    }
+    
+    private void gcAndKillHungWorkerVMs() {
+        try {
+            // take the chance to do left-over dummy VM cleanup from previous run
+            VmwareContext context = getServiceContext();
+            VmwareHypervisorHost hyperHost = getHyperHost(context);
+            VmwareManager mgr = hyperHost.getContext().getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
+
+            if(hyperHost.isHyperHostConnected()) {
+                mgr.gcLeftOverVMs(context);
+
+                s_logger.info("Scan hung worker VM to recycle");
+                
+        		int workerKey = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_WORKER);
+        		int workerTagKey = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_WORKER_TAG);
+        		String workerPropName = String.format("value[%d]", workerKey);
+        		String workerTagPropName = String.format("value[%d]", workerTagKey);
+
+                // GC worker that has been running for too long
+                ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost(
+                        new String[] {"name", "config.template", workerPropName, workerTagPropName, 
+                        		 });
+                if(ocs != null) {
+                    for(ObjectContent oc : ocs) {
+                        List<DynamicProperty> props = oc.getPropSet();
+                        if(props != null) {
+                            boolean template = false;
+                            boolean isWorker = false;
+                            String workerTag = null;
+
+                            for(DynamicProperty prop : props) {
+                                if(prop.getName().equals("config.template")) {
+                                    template = (Boolean)prop.getVal();
+                                } else if(prop.getName().equals(workerPropName)) {
+                                	CustomFieldStringValue val = (CustomFieldStringValue)prop.getVal();
+                                	if(val != null && val.getValue() != null && val.getValue().equalsIgnoreCase("true"))
+                                		isWorker = true;
+                                }
+                                else if(prop.getName().equals(workerTagPropName)) {
+                                	CustomFieldStringValue val = (CustomFieldStringValue)prop.getVal();
+                                	workerTag = val.getValue();
                                 }
+                            }
 
-                                VirtualMachineMO vmMo = new VirtualMachineMO(hyperHost.getContext(), oc.getObj());
-                                if(!template && isWorker) {
-                                    boolean recycle = false;
-                                    recycle = mgr.needRecycle(workerTag);
+                            VirtualMachineMO vmMo = new VirtualMachineMO(hyperHost.getContext(), oc.getObj());
+                            if(!template && isWorker) {
+                                boolean recycle = false;
+                                recycle = mgr.needRecycle(workerTag);
 
-                                    if(recycle) {
-                                        s_logger.info("Recycle pending worker VM: " + vmMo.getName());
+                                if(recycle) {
+                                    s_logger.info("Recycle pending worker VM: " + vmMo.getName());
 
-                                        vmMo.powerOff();
-                                        vmMo.destroy();
-                                    }
+                                    vmMo.powerOff();
+                                    vmMo.destroy();
                                 }
                             }
                         }
-	                }
-	            } else {
-	                s_logger.error("Host is no longer connected.");
-	                return null;
-	            }
-	        } catch (Throwable e) {
-	            if (e instanceof RemoteException) {
-	                s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context");
-	                invalidateServiceContext();
-	                return null;
-	            }
-	        }
-	
-	        return new PingRoutingCommand(getType(), id, newStates);
+                    }
+                }
+            } else {
+                s_logger.error("Host is no longer connected.");
+            }
         
-    	} finally {
-    		recycleServiceContext();
-    	}
+        } catch (Throwable e) {
+            if (e instanceof RemoteException) {
+                s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context");
+                invalidateServiceContext();
+            }
+        } finally {
+        	recycleServiceContext();
+        }
     }
 
     @Override
@@ -5935,7 +5949,14 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
 	        }
 	
 	        cmd.setHypervisorType(HypervisorType.VMware);
+	        
+	        // TODO vmsync {
+	        // deprecated after full replacement
 	        cmd.setStateChanges(changes);
+	        // TODO vmsync}
+	        
+	        cmd.setHostVmStateReport(syncHostVmStates());
+	        
 	        cmd.setCluster(_cluster);
 	        cmd.setHypervisorVersion(hostApiVersion);
 	
@@ -6091,6 +6112,14 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         }
     }
 
+    protected HashMap<String, HostVmStateReportEntry> syncHostVmStates() {
+       try {
+           return getHostVmStateReport();
+       } catch(Exception e) {
+            return new HashMap<String, HostVmStateReportEntry>();
+       }
+    }
+    
     protected HashMap<String, State> sync() {
         HashMap<String, State> changes = new HashMap<String, State>();
         HashMap<String, State> oldStates = null;
@@ -6295,6 +6324,65 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         return VirtualMachineGuestOsIdentifier.OTHER_GUEST;
     }
 
+    private HashMap<String, HostVmStateReportEntry> getHostVmStateReport() throws Exception {
+        VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext());
+        
+		int key = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_VM_INTERNAL_NAME);
+		if(key == 0) {
+			s_logger.warn("Custom field " + CustomFieldConstants.CLOUD_VM_INTERNAL_NAME + " is not registered ?!");
+		}
+		String instanceNameCustomField = "value[" + key + "]";
+        
+        // CLOUD_VM_INTERNAL_NAME stores the internal CS generated vm name. This was earlier stored in name. Now, name can be either the hostname or
+        // the internal CS name, but the custom field CLOUD_VM_INTERNAL_NAME always stores the internal CS name.
+        ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost(
+        	new String[] { "name", "runtime.powerState", "config.template", instanceNameCustomField }
+        );
+
+        HashMap<String, HostVmStateReportEntry> newStates = new HashMap<String, HostVmStateReportEntry>();
+        if (ocs != null && ocs.length > 0) {
+            for (ObjectContent oc : ocs) {
+                List<DynamicProperty> objProps = oc.getPropSet();
+                if (objProps != null) {
+
+                    boolean isTemplate = false;
+                    String name = null;
+                    String VMInternalCSName = null;
+                    VirtualMachinePowerState powerState = VirtualMachinePowerState.POWERED_OFF;
+                    for (DynamicProperty objProp : objProps) {
+                        if (objProp.getName().equals("config.template")) {
+                            if (objProp.getVal().toString().equalsIgnoreCase("true")) {
+                                isTemplate = true;
+                            }
+                        } else if (objProp.getName().equals("runtime.powerState")) {
+                            powerState = (VirtualMachinePowerState) objProp.getVal();
+                        } else if (objProp.getName().equals("name")) {
+                            name = (String) objProp.getVal();
+                        } else if(objProp.getName().contains(instanceNameCustomField)) {
+		                	if(objProp.getVal() != null)
+		                		VMInternalCSName = ((CustomFieldStringValue)objProp.getVal()).getValue();
+		                }
+                        else {
+                            assert (false);
+                        }
+                    }
+                    
+                    if (VMInternalCSName != null)
+                        name = VMInternalCSName;
+
+                    if (!isTemplate) {
+                        newStates.put(
+                        	name, 
+                        	new HostVmStateReportEntry(convertPowerState(powerState), hyperHost.getHyperHostName(), null)
+                        );
+                    }
+                }
+            }
+        }
+        return newStates;
+    }
+    
+    // TODO vmsync {
     private HashMap<String, State> getVmStates() throws Exception {
         VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext());
         
@@ -6462,6 +6550,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         }
         return vmResponseMap;
     }
+    // TODO vmsync }
 
     protected String networkUsage(final String privateIpAddress, final String option, final String ethName) {
         String args = null;
@@ -6572,6 +6661,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         return connect(vmname, ipAddress, 3922);
     }
 
+    // TODO vmsync {
+    // deprecated after full replacement
     private static State convertState(VirtualMachinePowerState powerState) {
         return s_statesTable.get(powerState);
     }
@@ -6580,7 +6671,17 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         VirtualMachineRuntimeInfo runtimeInfo = vmMo.getRuntimeInfo();
         return convertState(runtimeInfo.getPowerState());
     }
+    // TODO vmsync }
+    
+    private static PowerState convertPowerState(VirtualMachinePowerState powerState) {
+        return s_powerStatesTable.get(powerState);
+    }
 
+    public static PowerState getVmPowerState(VirtualMachineMO vmMo) throws Exception {
+        VirtualMachineRuntimeInfo runtimeInfo = vmMo.getRuntimeInfo();
+        return convertPowerState(runtimeInfo.getPowerState());
+    }
+ 
     private static HostStatsEntry getHyperHostStats(VmwareHypervisorHost hyperHost) throws Exception {
         ComputeResourceSummary hardwareSummary = hyperHost.getHyperHostHardwareSummary();
         if(hardwareSummary == null)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
index 69b7c9e..aadfc17 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
@@ -63,6 +63,7 @@ import com.cloud.agent.api.GetVmStatsCommand;
 import com.cloud.agent.api.GetVncPortAnswer;
 import com.cloud.agent.api.GetVncPortCommand;
 import com.cloud.agent.api.HostStatsEntry;
+import com.cloud.agent.api.HostVmStateReportEntry;
 import com.cloud.agent.api.MaintainAnswer;
 import com.cloud.agent.api.MaintainCommand;
 import com.cloud.agent.api.ManageSnapshotAnswer;
@@ -188,6 +189,7 @@ import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.net.NetUtils;
 import com.cloud.vm.DiskProfile;
 import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachine.PowerState;
 import com.cloud.vm.VirtualMachine.State;
 import com.cloud.vm.snapshot.VMSnapshot;
 import com.google.gson.Gson;
@@ -225,6 +227,7 @@ import com.xensource.xenapi.VLAN;
 import com.xensource.xenapi.VM;
 import com.xensource.xenapi.VMGuestMetrics;
 import com.xensource.xenapi.XenAPIObject;
+
 import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
 import org.apache.cloudstack.storage.to.TemplateObjectTO;
 import org.apache.cloudstack.storage.to.VolumeObjectTO;
@@ -239,6 +242,7 @@ import org.xml.sax.InputSource;
 import javax.ejb.Local;
 import javax.naming.ConfigurationException;
 import javax.xml.parsers.DocumentBuilderFactory;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
@@ -347,6 +351,17 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         }
     }
 
+    protected static HashMap<Types.VmPowerState, PowerState> s_powerStatesTable;
+    static {
+    	s_powerStatesTable = new HashMap<Types.VmPowerState, PowerState>();
+        s_powerStatesTable.put(Types.VmPowerState.HALTED, PowerState.PowerOff);
+        s_powerStatesTable.put(Types.VmPowerState.PAUSED, PowerState.PowerOn);
+        s_powerStatesTable.put(Types.VmPowerState.RUNNING, PowerState.PowerOn);
+        s_powerStatesTable.put(Types.VmPowerState.SUSPENDED, PowerState.PowerOn);
+        s_powerStatesTable.put(Types.VmPowerState.UNRECOGNIZED, PowerState.PowerUnknown);
+    }
+
+    // TODO vmsync {
     protected static HashMap<Types.VmPowerState, State> s_statesTable;
     static {
         s_statesTable = new HashMap<Types.VmPowerState, State>();
@@ -356,6 +371,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         s_statesTable.put(Types.VmPowerState.SUSPENDED, State.Running);
         s_statesTable.put(Types.VmPowerState.UNRECOGNIZED, State.Unknown);
     }
+    // TODO vmsync }
 
     public XsHost getHost() {
         return _host;
@@ -2975,7 +2991,61 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         final State state = s_statesTable.get(ps);
         return state == null ? State.Unknown : state;
     }
+    
+    private static PowerState convertPowerState(Types.VmPowerState powerState) {
+        return s_powerStatesTable.get(powerState);
+    }
+
+    protected HashMap<String, HostVmStateReportEntry> getHostVmStateReport(Connection conn) {
+        final HashMap<String, HostVmStateReportEntry> vmStates = new HashMap<String, HostVmStateReportEntry>();
+        Map<VM, VM.Record>  vm_map = null;
+        for (int i = 0; i < 2; i++) {
+            try {
+                vm_map = VM.getAllRecords(conn);  //USE THIS TO GET ALL VMS FROM  A CLUSTER
+                break;
+            } catch (final Throwable e) {
+                s_logger.warn("Unable to get vms", e);
+            }
+            try {
+                Thread.sleep(1000);
+            } catch (final InterruptedException ex) {
+
+            }
+        }
+
+        if (vm_map == null) {
+            return null;
+        }
+        for (VM.Record record: vm_map.values()) {
+            if (record.isControlDomain || record.isASnapshot || record.isATemplate) {
+                continue; // Skip DOM0
+            }
 
+            VmPowerState ps = record.powerState;
+            Host host = record.residentOn;
+            String xstoolsversion = getVMXenToolsVersion(record.platform);
+            String host_uuid = null;
+            if( ! isRefNull(host) ) {
+                try {
+                    host_uuid = host.getUuid(conn);
+                } catch (BadServerResponse e) {
+                    s_logger.error("Failed to get host uuid for host " + host.toWireString(), e);
+                } catch (XenAPIException e) {
+                    s_logger.error("Failed to get host uuid for host " + host.toWireString(), e);
+                } catch (XmlRpcException e) {
+                    s_logger.error("Failed to get host uuid for host " + host.toWireString(), e);
+                }
+                vmStates.put(
+                	record.nameLabel, 
+                	new HostVmStateReportEntry(convertPowerState(ps), host_uuid, xstoolsversion)
+                );
+            }
+        }
+
+        return vmStates;
+    }
+    
+    // TODO vmsync {
     protected HashMap<String, Ternary<String, State, String>> getAllVms(Connection conn) {
         final HashMap<String, Ternary<String, State, String>> vmStates = new HashMap<String, Ternary<String, State, String>>();
         Map<VM, VM.Record>  vm_map = null;
@@ -3025,6 +3095,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
 
         return vmStates;
     }
+    // TODO vmsync }
 
     protected State getVmState(Connection conn, final String vmName) {
         int retry = 3;
@@ -4749,13 +4820,13 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
             }
             Connection conn = getConnection();
             if (!_canBridgeFirewall && !_isOvs) {
-                return new PingRoutingCommand(getType(), id, null);
+                return new PingRoutingCommand(getType(), id, null, getHostVmStateReport(conn));
             } else if (_isOvs) {
                 List<Pair<String, Long>>ovsStates = ovsFullSyncStates();
-                return new PingRoutingWithOvsCommand(getType(), id, null, ovsStates);
+                return new PingRoutingWithOvsCommand(getType(), id, null, getHostVmStateReport(conn), ovsStates);
             }else {
                 HashMap<String, Pair<Long, Long>> nwGrpStates = syncNetworkGroups(conn, id);
-                return new PingRoutingWithNwGroupsCommand(getType(), id, null, nwGrpStates);
+                return new PingRoutingWithNwGroupsCommand(getType(), id, null, getHostVmStateReport(conn), nwGrpStates);
             }
         } catch (Exception e) {
             s_logger.warn("Unable to get current status", e);
@@ -5010,6 +5081,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         cmd.setHypervisorType(HypervisorType.XenServer);
         cmd.setCluster(_cluster);
         cmd.setPoolSync(false);
+        cmd.setHostVmStateReport(this.getHostVmStateReport(conn));
 
         Pool pool;
         try {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/server/src/com/cloud/hypervisor/kvm/discoverer/KvmDummyResourceBase.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/hypervisor/kvm/discoverer/KvmDummyResourceBase.java b/server/src/com/cloud/hypervisor/kvm/discoverer/KvmDummyResourceBase.java
index 240ea6c..d6fde31 100644
--- a/server/src/com/cloud/hypervisor/kvm/discoverer/KvmDummyResourceBase.java
+++ b/server/src/com/cloud/hypervisor/kvm/discoverer/KvmDummyResourceBase.java
@@ -23,6 +23,7 @@ import javax.naming.ConfigurationException;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.HostVmStateReportEntry;
 import com.cloud.agent.api.PingCommand;
 import com.cloud.agent.api.StartupCommand;
 import com.cloud.agent.api.StartupRoutingCommand;
@@ -46,7 +47,9 @@ public class KvmDummyResourceBase extends ServerResourceBase implements ServerRe
 
 	@Override
 	public StartupCommand[] initialize() {
-		StartupRoutingCommand cmd = new StartupRoutingCommand(0, 0, 0, 0, null, Hypervisor.HypervisorType.KVM, new HashMap<String, String>(), new HashMap<String, VmState>());
+		StartupRoutingCommand cmd = new StartupRoutingCommand(0, 0, 0, 0, null, Hypervisor.HypervisorType.KVM, 
+			new HashMap<String, String>(), new HashMap<String, VmState>(),
+			new HashMap<String, HostVmStateReportEntry>());
 		cmd.setDataCenter(_zoneId);
 		cmd.setPod(_podId);
 		cmd.setCluster(_clusterId);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/server/src/com/cloud/resource/DummyHostServerResource.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/resource/DummyHostServerResource.java b/server/src/com/cloud/resource/DummyHostServerResource.java
index 977dbbf..1d58c80 100644
--- a/server/src/com/cloud/resource/DummyHostServerResource.java
+++ b/server/src/com/cloud/resource/DummyHostServerResource.java
@@ -23,6 +23,7 @@ import javax.naming.ConfigurationException;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.HostVmStateReportEntry;
 import com.cloud.agent.api.PingCommand;
 import com.cloud.agent.api.PingRoutingCommand;
 import com.cloud.agent.api.StartupCommand;
@@ -57,7 +58,8 @@ public class DummyHostServerResource extends ServerResourceBase {
 	@Override
 	public PingCommand getCurrentStatus(long id) {
         HashMap<String, VirtualMachine.State> newStates = new HashMap<String, VirtualMachine.State>();
-        return new PingRoutingCommand(com.cloud.host.Host.Type.Routing, id, newStates);
+        return new PingRoutingCommand(com.cloud.host.Host.Type.Routing, id, newStates,
+        	new HashMap<String, HostVmStateReportEntry>());
 	}
 
 	@Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7be9b121/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
----------------------------------------------------------------------
diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
index 784c031..108e35a 100644
--- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
+++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
@@ -180,7 +180,7 @@ public class VirtualMachineMO extends BaseMO {
 	}
 
 	public boolean powerOn() throws Exception {
-		if(getPowerState() == VirtualMachinePowerState.POWERED_ON)
+		if(getResetSafePowerState() == VirtualMachinePowerState.POWERED_ON)
 			return true;
 
 		ManagedObjectReference morTask = _context.getService().powerOnVMTask(_mor, null);
@@ -197,7 +197,7 @@ public class VirtualMachineMO extends BaseMO {
 	}
 
 	public boolean powerOff() throws Exception {
-		if(getPowerState() == VirtualMachinePowerState.POWERED_OFF)
+		if(getResetSafePowerState() == VirtualMachinePowerState.POWERED_OFF)
 			return true;
 
 		return powerOffNoCheck();
@@ -205,7 +205,7 @@ public class VirtualMachineMO extends BaseMO {
 
 	public boolean safePowerOff(int shutdownWaitMs) throws Exception {
 
-		if(getPowerState() == VirtualMachinePowerState.POWERED_OFF)
+		if(getResetSafePowerState() == VirtualMachinePowerState.POWERED_OFF)
 			return true;
 
 		if(isVMwareToolsRunning()) {
@@ -216,14 +216,14 @@ public class VirtualMachineMO extends BaseMO {
 				shutdown();
 
 				long startTick = System.currentTimeMillis();
-				while(getPowerState() != VirtualMachinePowerState.POWERED_OFF && System.currentTimeMillis() - startTick < shutdownWaitMs) {
+				while(getResetSafePowerState() != VirtualMachinePowerState.POWERED_OFF && System.currentTimeMillis() - startTick < shutdownWaitMs) {
 					try {
 						Thread.sleep(1000);
 					} catch(InterruptedException e) {
 					}
 				}
 
-				if(getPowerState() != VirtualMachinePowerState.POWERED_OFF) {
+				if(getResetSafePowerState() != VirtualMachinePowerState.POWERED_OFF) {
 					s_logger.info("can not gracefully shutdown VM within " + (shutdownWaitMs/1000) + " seconds, we will perform force power off on VM " + vmName);
 					return powerOffNoCheck();
 				}
@@ -248,7 +248,7 @@ public class VirtualMachineMO extends BaseMO {
 			// wait up to 5 seconds to make sure to avoid race conditioning for immediate following on operations
 			// that relies on a powered-off VM
 			long startTick = System.currentTimeMillis();
-			while(getPowerState() != VirtualMachinePowerState.POWERED_OFF && System.currentTimeMillis() - startTick < 5000) {
+			while(getResetSafePowerState() != VirtualMachinePowerState.POWERED_OFF && System.currentTimeMillis() - startTick < 5000) {
 				try {
 					Thread.sleep(1000);
 				} catch(InterruptedException e) {
@@ -256,7 +256,7 @@ public class VirtualMachineMO extends BaseMO {
 			}
 			return true;
 		} else {
-			 if(getPowerState() == VirtualMachinePowerState.POWERED_OFF) {
+			 if(getResetSafePowerState() == VirtualMachinePowerState.POWERED_OFF) {
 				 // to help deal with possible race-condition
 				 s_logger.info("Current power-off task failed. However, VM has been switched to the state we are expecting for");
 				 return true;
@@ -268,7 +268,7 @@ public class VirtualMachineMO extends BaseMO {
 		return false;
 	}
 
-	public VirtualMachinePowerState getPowerState() throws Exception {
+	public VirtualMachinePowerState getResetSafePowerState() throws Exception {
 
 	    VirtualMachinePowerState powerState = VirtualMachinePowerState.POWERED_OFF;
 
@@ -293,6 +293,10 @@ public class VirtualMachineMO extends BaseMO {
 
 	    return powerState;
 	}
+	
+	public VirtualMachinePowerState getPowerState() throws Exception {
+        return (VirtualMachinePowerState)getContext().getVimClient().getDynamicProperty(_mor, "runtime.powerState");
+	}
 
 	public boolean reset() throws Exception {
 		ManagedObjectReference morTask = _context.getService().resetVMTask(_mor);


[4/6] git commit: updated refs/heads/4.3 to 5a44de2

Posted by ke...@apache.org.
Newly added VR monitoring service has broken VMware basic network mode.


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/367db2e4
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/367db2e4
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/367db2e4

Branch: refs/heads/4.3
Commit: 367db2e45fcd6fd172cc3c060f621d81c2a6087a
Parents: 7be9b12
Author: Kelven Yang <ke...@citrix.com>
Authored: Tue Nov 12 23:48:56 2013 -0800
Committer: Kelven Yang <ke...@gmail.com>
Committed: Wed Nov 20 18:18:48 2013 -0800

----------------------------------------------------------------------
 .../router/VirtualNetworkApplianceManagerImpl.java    | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/367db2e4/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
index 3ba6cec..806e3af 100755
--- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
+++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
@@ -2211,12 +2211,12 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V
 
             finalizeUserDataAndDhcpOnStart(cmds, router, provider, guestNetworkId);
         }
-        finalizeMonitorServiceOnStrat(cmds, router, provider, routerGuestNtwkIds.get(0));
+        finalizeMonitorServiceOnStrat(cmds, profile, router, provider, routerGuestNtwkIds.get(0));
 
         return true;
     }
 
-    private void finalizeMonitorServiceOnStrat(Commands cmds, DomainRouterVO router, Provider provider, long networkId) {
+    private void finalizeMonitorServiceOnStrat(Commands cmds, VirtualMachineProfile profile, DomainRouterVO router, Provider provider, long networkId) {
 
         NetworkVO network = _networkDao.findById(networkId);
 
@@ -2249,18 +2249,18 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V
             servicesTO.add(serviceTO);
         }
 
+        // TODO : This is a hacking fix
+        // at VR startup time, information in VirtualMachineProfile may not updated to DB yet, 
+        // getRouterControlIp() may give wrong IP under basic network mode in VMware environment
+        NicProfile controlNic = getControlNic(profile);
         SetMonitorServiceCommand command = new SetMonitorServiceCommand(servicesTO);
-        command.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId()));
+        command.setAccessDetail(NetworkElementCommand.ROUTER_IP, controlNic.getIp4Address());
         command.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, getRouterIpInNetwork(networkId, router.getId()));
         command.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName());
 
         cmds.addCommand("monitor", command);
     }
 
-
-
-
-
     protected NicProfile getControlNic(VirtualMachineProfile profile) {
         DomainRouterVO router = _routerDao.findById(profile.getId());
         DataCenterVO dcVo = _dcDao.findById(router.getDataCenterId());


[5/6] CLOUDSTACK-669: side-by-side VM sync management at manager level

Posted by ke...@apache.org.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java
index 9c47727..9aa9501 100644
--- a/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java
+++ b/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java
@@ -27,7 +27,6 @@ import org.apache.cloudstack.framework.messagebus.MessageBus;
 import org.apache.cloudstack.framework.messagebus.PublishScope;
 
 import com.cloud.agent.api.HostVmStateReportEntry;
-import com.cloud.vm.VirtualMachine.PowerState;
 import com.cloud.vm.dao.VMInstanceDao;
 
 public class VirtualMachinePowerStateSyncImpl implements VirtualMachinePowerStateSync {
@@ -56,11 +55,11 @@ public class VirtualMachinePowerStateSyncImpl implements VirtualMachinePowerStat
     }
 
     @Override
-	public void processHostVmStatePingReport(long hostId, Map<String, PowerState> report) {
+	public void processHostVmStatePingReport(long hostId, Map<String, HostVmStateReportEntry> report) {
     	if(s_logger.isDebugEnabled())
     		s_logger.debug("Process host VM state report from ping process. host: " + hostId);
     	
-    	Map<Long, VirtualMachine.PowerState> translatedInfo = convertHostPingInfos(report);
+    	Map<Long, VirtualMachine.PowerState> translatedInfo = convertToInfos(report);
     	processReport(hostId, translatedInfo);
     }
     
@@ -80,25 +79,6 @@ public class VirtualMachinePowerStateSyncImpl implements VirtualMachinePowerStat
     		}
     	}
     }
- 
-    private Map<Long, VirtualMachine.PowerState> convertHostPingInfos(Map<String, PowerState> states) {
-        final HashMap<Long, VirtualMachine.PowerState> map = new HashMap<Long, VirtualMachine.PowerState>();
-        if (states == null) {
-            return map;
-        }
-    	
-        for (Map.Entry<String, PowerState> entry : states.entrySet()) {
-        	VMInstanceVO vm = findVM(entry.getKey());
-        	if(vm != null) {
-        		map.put(vm.getId(), entry.getValue());
-        		break;
-        	} else {
-        		s_logger.info("Unable to find matched VM in CloudStack DB. name: " + entry.getKey());
-        	}
-        }
-
-        return map;
-    }
     	    
     private Map<Long, VirtualMachine.PowerState> convertToInfos(Map<String, HostVmStateReportEntry> states) {
         final HashMap<Long, VirtualMachine.PowerState> map = new HashMap<Long, VirtualMachine.PowerState>();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/src/com/cloud/vm/VmWorkAddVmToNetwork.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkAddVmToNetwork.java b/engine/orchestration/src/com/cloud/vm/VmWorkAddVmToNetwork.java
new file mode 100644
index 0000000..3590c0d
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkAddVmToNetwork.java
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import com.cloud.network.Network;
+
+public class VmWorkAddVmToNetwork extends VmWork {
+	private static final long serialVersionUID = 8861516006586736813L;
+
+	Network network;
+	NicProfile requstedNicProfile;
+	
+	public VmWorkAddVmToNetwork(long userId, long accountId, long vmId, 
+		Network network, NicProfile requested) {
+		super(userId, accountId, vmId);
+	
+		this.network = network;
+		this.requstedNicProfile = requested;
+	}
+	
+	public Network getNetwork() {
+		return this.network;
+	}
+	
+	public NicProfile getRequestedNicProfile() {
+		return this.requstedNicProfile;
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/src/com/cloud/vm/VmWorkJobDispatcher.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkJobDispatcher.java b/engine/orchestration/src/com/cloud/vm/VmWorkJobDispatcher.java
new file mode 100644
index 0000000..7c36d8c
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkJobDispatcher.java
@@ -0,0 +1,152 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.framework.jobs.AsyncJob;
+import org.apache.cloudstack.framework.jobs.AsyncJobDispatcher;
+import org.apache.cloudstack.framework.jobs.AsyncJobManager;
+import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper;
+import org.apache.cloudstack.jobs.JobInfo;
+
+import com.cloud.utils.component.AdapterBase;
+import com.cloud.vm.dao.VMInstanceDao;
+
+public class VmWorkJobDispatcher extends AdapterBase implements AsyncJobDispatcher {
+    private static final Logger s_logger = Logger.getLogger(VmWorkJobDispatcher.class);
+
+    public static final String VM_WORK_QUEUE = "VmWorkJobQueue";
+    public static final String VM_WORK_JOB_DISPATCHER = "VmWorkJobDispatcher";
+    public static final String VM_WORK_JOB_WAKEUP_DISPATCHER = "VmWorkJobWakeupDispatcher";
+    
+    @Inject private VirtualMachineManagerImpl _vmMgr;
+	@Inject private AsyncJobManager _asyncJobMgr;
+    @Inject private VMInstanceDao _instanceDao;
+    
+	@Override
+    public void runJob(AsyncJob job) {
+        VmWork work = null;
+        try {
+        	String cmd = job.getCmd();
+        	assert(cmd != null);
+        	
+        	if(s_logger.isDebugEnabled())
+        		s_logger.debug("Run VM work job: " + cmd);
+        	
+        	Class<?> workClz = null;
+        	try {
+        		workClz = Class.forName(job.getCmd());
+        	} catch(ClassNotFoundException e) {
+        		s_logger.error("VM work class " + cmd + " is not found", e);
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.FAILED, 0, e.getMessage());
+        		return;
+        	}
+        	
+        	work = VmWorkSerializer.deserialize(workClz, job.getCmdInfo());
+            assert(work != null);
+            if(work == null) {
+            	s_logger.error("Unable to deserialize VM work " + job.getCmd() + ", job info: " + job.getCmdInfo());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.FAILED, 0, "Unable to deserialize VM work");
+        		return;
+            }
+            
+            CallContext.register(work.getUserId(), work.getAccountId(), job.getRelated());
+
+            VMInstanceVO vm = _instanceDao.findById(work.getVmId());
+            if (vm == null) {
+                s_logger.info("Unable to find vm " + work.getVmId());
+            }
+            assert(vm != null);
+            if(work instanceof VmWorkStart) {
+            	VmWorkStart workStart = (VmWorkStart)work;
+            	_vmMgr.orchestrateStart(vm.getUuid(), workStart.getParams(), workStart.getPlan());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, null);
+            } else if(work instanceof VmWorkStop) {
+            	VmWorkStop workStop = (VmWorkStop)work;
+            	_vmMgr.orchestrateStop(vm.getUuid(), workStop.isCleanup());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, null);
+            } else if(work instanceof VmWorkMigrate) {
+            	VmWorkMigrate workMigrate = (VmWorkMigrate)work;
+            	_vmMgr.orchestrateMigrate(vm.getUuid(), workMigrate.getSrcHostId(), workMigrate.getDeployDestination());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, null);
+            } else if(work instanceof VmWorkMigrateWithStorage) {
+            	VmWorkMigrateWithStorage workMigrateWithStorage = (VmWorkMigrateWithStorage)work;
+            	_vmMgr.orchestrateMigrateWithStorage(vm.getUuid(), 
+            		workMigrateWithStorage.getSrcHostId(), 
+            		workMigrateWithStorage.getDestHostId(), 
+            		workMigrateWithStorage.getVolumeToPool());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, null);
+            } else if(work instanceof VmWorkMigrateForScale) { 
+            	VmWorkMigrateForScale workMigrateForScale = (VmWorkMigrateForScale)work;
+            	_vmMgr.orchestrateMigrateForScale(vm.getUuid(), 
+            		workMigrateForScale.getSrcHostId(), 
+            		workMigrateForScale.getDeployDestination(), 
+            		workMigrateForScale.getNewServiceOfferringId());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, null);
+            } else if(work instanceof VmWorkReboot) { 
+                VmWorkReboot workReboot = (VmWorkReboot)work;
+                _vmMgr.orchestrateReboot(vm.getUuid(), workReboot.getParams());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, null);
+            } else if(work instanceof VmWorkAddVmToNetwork) { 
+                VmWorkAddVmToNetwork workAddVmToNetwork = (VmWorkAddVmToNetwork)work;
+                NicProfile nic = _vmMgr.orchestrateAddVmToNetwork(vm, workAddVmToNetwork.getNetwork(), 
+                	workAddVmToNetwork.getRequestedNicProfile());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, 
+                    JobSerializerHelper.toObjectSerializedString(nic));
+            } else if(work instanceof VmWorkRemoveNicFromVm) { 
+                VmWorkRemoveNicFromVm workRemoveNicFromVm = (VmWorkRemoveNicFromVm)work;
+                boolean result = _vmMgr.orchestrateRemoveNicFromVm(vm, workRemoveNicFromVm.getNic());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, 
+                	JobSerializerHelper.toObjectSerializedString(new Boolean(result)));
+            } else if(work instanceof VmWorkRemoveVmFromNetwork) { 
+                VmWorkRemoveVmFromNetwork workRemoveVmFromNetwork = (VmWorkRemoveVmFromNetwork)work;
+                boolean result = _vmMgr.orchestrateRemoveVmFromNetwork(vm, 
+                	workRemoveVmFromNetwork.getNetwork(), workRemoveVmFromNetwork.getBroadcastUri());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, 
+                    	JobSerializerHelper.toObjectSerializedString(new Boolean(result)));
+            } else if(work instanceof VmWorkReconfigure) { 
+                VmWorkReconfigure workReconfigure = (VmWorkReconfigure)work;
+                _vmMgr.reConfigureVm(vm.getUuid(), workReconfigure.getNewServiceOffering(), 
+                	workReconfigure.isSameHost());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, null);
+            } else if(work instanceof VmWorkStorageMigration) { 
+                VmWorkStorageMigration workStorageMigration = (VmWorkStorageMigration)work;
+                _vmMgr.orchestrateStorageMigration(vm.getUuid(), workStorageMigration.getDestStoragePool());
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.SUCCEEDED, 0, null);
+            } else {
+            	assert(false);
+                s_logger.error("Unhandled VM work command: " + job.getCmd());
+            	
+            	RuntimeException e = new RuntimeException("Unsupported VM work command: " + job.getCmd());
+                String exceptionJson = JobSerializerHelper.toSerializedString(e);
+                s_logger.error("Serialize exception object into json: " + exceptionJson);
+                _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.FAILED, 0, exceptionJson);
+            }
+        } catch(Throwable e) {
+            s_logger.error("Unable to complete " + job, e);
+            
+            String exceptionJson = JobSerializerHelper.toSerializedString(e);
+            s_logger.info("Serialize exception object into json: " + exceptionJson);
+            _asyncJobMgr.completeAsyncJob(job.getId(), JobInfo.Status.FAILED, 0, exceptionJson);
+        } finally {
+            CallContext.unregister();
+        }
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/src/com/cloud/vm/VmWorkMigrate.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkMigrate.java b/engine/orchestration/src/com/cloud/vm/VmWorkMigrate.java
new file mode 100644
index 0000000..c313876
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkMigrate.java
@@ -0,0 +1,86 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.Pod;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.host.Host;
+import com.cloud.org.Cluster;
+import com.cloud.storage.StoragePool;
+import com.cloud.storage.Volume;
+import com.cloud.utils.db.EntityManager;
+
+public class VmWorkMigrate extends VmWork {
+	private static final long serialVersionUID = 1689203333114836522L;
+
+	Long zoneId;
+    Long podId;
+    Long clusterId;
+    Long hostId;
+    private Map<String, String> storage;
+    long srcHostId;
+
+    public VmWorkMigrate(long userId, long accountId, long vmId, long srcHostId, DeployDestination dst) {
+        super(userId, accountId, vmId);
+        this.srcHostId = srcHostId;
+        zoneId = dst.getDataCenter() != null ? dst.getDataCenter().getId() : null;
+        podId = dst.getPod() != null ? dst.getPod().getId() : null;
+        clusterId = dst.getCluster() != null ? dst.getCluster().getId() : null;
+        hostId = dst.getHost() != null ? dst.getHost().getId() : null;
+        if (dst.getStorageForDisks() != null) {
+            storage = new HashMap<String, String>(dst.getStorageForDisks().size());
+            for (Map.Entry<Volume, StoragePool> entry : dst.getStorageForDisks().entrySet()) {
+                storage.put(entry.getKey().getUuid(), entry.getValue().getUuid());
+            }
+        } else {
+            storage = null;
+        }
+    }
+
+    public DeployDestination getDeployDestination() {
+        DataCenter zone = zoneId != null ? s_entityMgr.findById(DataCenter.class, zoneId) : null;
+        Pod pod = podId != null ? s_entityMgr.findById(Pod.class, podId) : null;
+        Cluster cluster = clusterId != null ? s_entityMgr.findById(Cluster.class, clusterId) : null;
+        Host host = hostId != null ? s_entityMgr.findById(Host.class, hostId) : null;
+        
+        Map<Volume, StoragePool> vols = null;
+
+        if (storage != null) {
+            vols = new HashMap<Volume, StoragePool>(storage.size());
+            for (Map.Entry<String, String> entry : storage.entrySet()) {
+                vols.put(s_entityMgr.findByUuid(Volume.class, entry.getKey()), s_entityMgr.findByUuid(StoragePool.class, entry.getValue()));
+            }
+        }
+
+        DeployDestination dest = new DeployDestination(zone, pod, cluster, host, vols);
+        return dest;
+    }
+
+    public long getSrcHostId() {
+        return srcHostId;
+    }
+
+    static private EntityManager s_entityMgr;
+
+    static public void init(EntityManager entityMgr) {
+        s_entityMgr = entityMgr;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/src/com/cloud/vm/VmWorkMigrateForScale.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkMigrateForScale.java b/engine/orchestration/src/com/cloud/vm/VmWorkMigrateForScale.java
new file mode 100644
index 0000000..8e71aa8
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkMigrateForScale.java
@@ -0,0 +1,48 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import com.cloud.deploy.DeployDestination;
+
+public class VmWorkMigrateForScale extends VmWork {
+	private static final long serialVersionUID = 6854870395568389613L;
+
+	long srcHostId;
+	DeployDestination deployDestination;
+	Long newSvcOfferingId;
+	
+    public VmWorkMigrateForScale(long userId, long accountId, long vmId, long srcHostId, 
+    	DeployDestination dest, Long newSvcOfferingId) {
+    	
+    	super(userId, accountId, vmId);
+    	this.srcHostId = srcHostId;
+    	this.deployDestination = dest;
+    	this.newSvcOfferingId = newSvcOfferingId;
+    }
+	
+    public long getSrcHostId() {
+    	return srcHostId;
+    }
+    
+    public DeployDestination getDeployDestination() {
+    	return this.deployDestination;
+    }
+    
+    public Long getNewServiceOfferringId() {
+    	return this.newSvcOfferingId;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/src/com/cloud/vm/VmWorkMigrateWithStorage.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkMigrateWithStorage.java b/engine/orchestration/src/com/cloud/vm/VmWorkMigrateWithStorage.java
new file mode 100644
index 0000000..ae91231
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkMigrateWithStorage.java
@@ -0,0 +1,52 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import java.util.Map;
+
+import com.cloud.storage.StoragePool;
+import com.cloud.storage.Volume;
+
+public class VmWorkMigrateWithStorage extends VmWork {
+	private static final long serialVersionUID = -5626053872453569165L;
+
+	long srcHostId;
+	long destHostId;
+	Map<Volume, StoragePool> volumeToPool;
+	
+    public VmWorkMigrateWithStorage(long userId, long accountId, long vmId, long srcHostId, 
+    	long destHostId, Map<Volume, StoragePool> volumeToPool) {
+    	
+    	super(userId, accountId, vmId);
+    
+    	this.srcHostId = srcHostId;
+    	this.destHostId = destHostId;
+    	this.volumeToPool = volumeToPool;
+    }
+    
+    public long getSrcHostId() {
+    	return this.srcHostId;
+    }
+    
+    public long getDestHostId() {
+    	return this.destHostId;
+    }
+    
+    public Map<Volume, StoragePool> getVolumeToPool() {
+    	return this.volumeToPool;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/src/com/cloud/vm/VmWorkReboot.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkReboot.java b/engine/orchestration/src/com/cloud/vm/VmWorkReboot.java
new file mode 100644
index 0000000..8f50702
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkReboot.java
@@ -0,0 +1,68 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper;
+
+public class VmWorkReboot extends VmWork {
+	private static final long serialVersionUID = 195907627459759933L;
+
+	// use serialization friendly map
+	private Map<String, String> rawParams;
+	
+    public VmWorkReboot(long userId, long accountId, long vmId, Map<VirtualMachineProfile.Param, Object> params) {
+    	super(userId, accountId, vmId);
+    	
+    	setParams(params);
+    }
+    
+	public Map<String, String> getRawParams() {
+		return rawParams;
+	}
+
+	public void setRawParams(Map<String, String> params) {
+		rawParams = params;
+	}
+	
+	public Map<VirtualMachineProfile.Param, Object> getParams() {
+		Map<VirtualMachineProfile.Param, Object> map = new HashMap<VirtualMachineProfile.Param, Object>();
+		
+		if(rawParams != null) {
+			for(Map.Entry<String, String> entry : rawParams.entrySet()) {
+				VirtualMachineProfile.Param key = new VirtualMachineProfile.Param(entry.getKey());
+				Object val = JobSerializerHelper.fromObjectSerializedString(entry.getValue());
+				map.put(key, val);
+			}
+		}
+		
+		return map;
+	}
+	
+	public void setParams(Map<VirtualMachineProfile.Param, Object> params) {
+		if(params != null) {
+			rawParams = new HashMap<String, String>();
+			for(Map.Entry<VirtualMachineProfile.Param, Object> entry : params.entrySet()) {
+				rawParams.put(entry.getKey().getName(), JobSerializerHelper.toObjectSerializedString(
+					entry.getValue() instanceof Serializable ? (Serializable)entry.getValue() : entry.getValue().toString()));
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/src/com/cloud/vm/VmWorkReconfigure.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkReconfigure.java b/engine/orchestration/src/com/cloud/vm/VmWorkReconfigure.java
new file mode 100644
index 0000000..48a9df3
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkReconfigure.java
@@ -0,0 +1,43 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import com.cloud.offering.ServiceOffering;
+
+public class VmWorkReconfigure extends VmWork {
+	private static final long serialVersionUID = -4517030323758086615L;
+	
+	ServiceOffering newServiceOffering;
+	boolean sameHost;
+	
+    public VmWorkReconfigure(long userId, long accountId, long vmId, 
+    	ServiceOffering newServiceOffering, boolean sameHost) {
+    	
+    	super(userId, accountId, vmId);
+    	
+    	this.newServiceOffering = newServiceOffering;
+    	this.sameHost = sameHost;
+    }
+    
+    public ServiceOffering getNewServiceOffering() {
+    	return this.newServiceOffering;
+    }
+    
+    public boolean isSameHost() {
+    	return this.sameHost;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/src/com/cloud/vm/VmWorkRemoveNicFromVm.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkRemoveNicFromVm.java b/engine/orchestration/src/com/cloud/vm/VmWorkRemoveNicFromVm.java
new file mode 100644
index 0000000..b756ac3
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkRemoveNicFromVm.java
@@ -0,0 +1,33 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+public class VmWorkRemoveNicFromVm extends VmWork {
+	private static final long serialVersionUID = -4265657031064437923L;
+
+	Nic nic;
+    
+	public VmWorkRemoveNicFromVm(long userId, long accountId, long vmId, Nic nic) {
+    	super(userId, accountId, vmId);
+    	
+    	this.nic = nic;
+    }
+    
+    public Nic getNic() {
+    	return this.nic;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/src/com/cloud/vm/VmWorkRemoveVmFromNetwork.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkRemoveVmFromNetwork.java b/engine/orchestration/src/com/cloud/vm/VmWorkRemoveVmFromNetwork.java
new file mode 100644
index 0000000..d4e0ae4
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkRemoveVmFromNetwork.java
@@ -0,0 +1,43 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import java.net.URI;
+
+import com.cloud.network.Network;
+
+public class VmWorkRemoveVmFromNetwork extends VmWork {
+	private static final long serialVersionUID = -5070392905642149925L;
+
+	Network network;
+	URI broadcastUri;
+	
+	public VmWorkRemoveVmFromNetwork(long userId, long accountId, long vmId, Network network, URI broadcastUri) {
+    	super(userId, accountId, vmId);
+    	
+    	this.network = network;
+    	this.broadcastUri = broadcastUri;
+	}
+	
+	public Network getNetwork() {
+		return this.network;
+	}
+	
+	public URI getBroadcastUri() {
+		return this.broadcastUri;
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/src/com/cloud/vm/VmWorkSerializer.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkSerializer.java b/engine/orchestration/src/com/cloud/vm/VmWorkSerializer.java
new file mode 100644
index 0000000..9a1aaac
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkSerializer.java
@@ -0,0 +1,75 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+
+public class VmWorkSerializer {
+    static class StringMapTypeAdapter implements JsonDeserializer<Map> {
+    	
+        @Override
+        public Map deserialize(JsonElement src, Type srcType, JsonDeserializationContext context) throws JsonParseException {
+
+            Map<String, String> obj = new HashMap<String, String>();
+            JsonObject json = src.getAsJsonObject();
+
+            for (Entry<String, JsonElement> entry : json.entrySet()) {
+                obj.put(entry.getKey(), entry.getValue().getAsString());
+            }
+
+            return obj;
+        }
+    }
+ 
+    protected static Gson s_gson;
+    static {
+        GsonBuilder gBuilder = new GsonBuilder();
+        gBuilder.setVersion(1.3);
+        gBuilder.registerTypeAdapter(Map.class, new StringMapTypeAdapter());
+        s_gson = gBuilder.create();
+    }
+   
+    public static String serialize(VmWork work) {
+    	// TODO: there are way many generics, too tedious to get serialization work under GSON
+    	// use java binary serialization instead
+    	// 
+    	return JobSerializerHelper.toObjectSerializedString(work);
+        // return s_gson.toJson(work);
+    }
+
+    public static <T extends VmWork> T deserialize(Class<?> clazz, String workInJsonText) {
+    	// TODO: there are way many generics, too tedious to get serialization work under GSON
+    	// use java binary serialization instead
+    	// 
+        return (T)JobSerializerHelper.fromObjectSerializedString(workInJsonText);
+    	// return (T)s_gson.fromJson(workInJsonText, clazz);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/src/com/cloud/vm/VmWorkStart.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkStart.java b/engine/orchestration/src/com/cloud/vm/VmWorkStart.java
new file mode 100644
index 0000000..7a7447f
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkStart.java
@@ -0,0 +1,125 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package com.cloud.vm;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper;
+
+import com.cloud.deploy.DataCenterDeployment;
+import com.cloud.deploy.DeploymentPlan;
+import com.cloud.deploy.DeploymentPlanner.ExcludeList;
+import com.cloud.utils.Journal;
+
+public class VmWorkStart extends VmWork {
+	private static final long serialVersionUID = 9038937399817468894L;
+
+	private static final Logger s_logger = Logger.getLogger(VmWorkStart.class);
+
+	long dcId;
+	Long podId;
+	Long clusterId;
+	Long hostId;
+	Long poolId;
+	ExcludeList avoids;
+	Long physicalNetworkId;
+	
+	String reservationId;
+	String journalName;
+	
+	// use serialization friendly map
+	private Map<String, String> rawParams;
+
+    public VmWorkStart(long userId, long accountId, long vmId) {
+        super(userId, accountId, vmId);
+	}
+
+	public DeploymentPlan getPlan() {
+		
+		if(podId != null || clusterId != null || hostId != null || poolId != null || physicalNetworkId != null) {
+			// this is ugly, to work with legacy code, we need to re-construct the DeploymentPlan hard-codely
+			// this has to be refactored together with migrating legacy code into the new way
+			ReservationContext context = null;
+			if(reservationId != null) {
+		        Journal journal = new Journal.LogJournal("VmWorkStart", s_logger);
+				context = new ReservationContextImpl(reservationId, journal, 
+						CallContext.current().getCallingUser(), 
+						CallContext.current().getCallingAccount());
+			}
+			
+			DeploymentPlan plan = new DataCenterDeployment(
+					dcId, podId, clusterId, hostId, poolId, physicalNetworkId,
+					context);
+			return plan;
+		}
+		
+		return null;
+	}
+
+	public void setPlan(DeploymentPlan plan) {
+		if(plan != null) {
+			dcId = plan.getDataCenterId();
+			podId = plan.getPodId();
+			clusterId = plan.getClusterId();
+			hostId = plan.getHostId();
+			poolId = plan.getPoolId();
+			physicalNetworkId = plan.getPhysicalNetworkId();
+			avoids = plan.getAvoids();
+			
+			if(plan.getReservationContext() != null)
+				reservationId = plan.getReservationContext().getReservationId();
+		}
+	}
+
+	public Map<String, String> getRawParams() {
+		return rawParams;
+	}
+
+	public void setRawParams(Map<String, String> params) {
+		rawParams = params;
+	}
+	
+	public Map<VirtualMachineProfile.Param, Object> getParams() {
+		Map<VirtualMachineProfile.Param, Object> map = new HashMap<VirtualMachineProfile.Param, Object>();
+		
+		if(rawParams != null) {
+			for(Map.Entry<String, String> entry : rawParams.entrySet()) {
+				VirtualMachineProfile.Param key = new VirtualMachineProfile.Param(entry.getKey());
+				Object val = JobSerializerHelper.fromObjectSerializedString(entry.getValue());
+				map.put(key, val);
+			}
+		}
+		
+		return map;
+	}
+	
+	public void setParams(Map<VirtualMachineProfile.Param, Object> params) {
+		if(params != null) {
+			rawParams = new HashMap<String, String>();
+			for(Map.Entry<VirtualMachineProfile.Param, Object> entry : params.entrySet()) {
+				rawParams.put(entry.getKey().getName(), JobSerializerHelper.toObjectSerializedString(
+					entry.getValue() instanceof Serializable ? (Serializable)entry.getValue() : entry.getValue().toString()));
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/src/com/cloud/vm/VmWorkStop.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkStop.java b/engine/orchestration/src/com/cloud/vm/VmWorkStop.java
new file mode 100644
index 0000000..0a27057
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkStop.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+public class VmWorkStop extends VmWork {
+	private static final long serialVersionUID = 202908740486785251L;
+	
+	private final boolean cleanup;
+	
+    public VmWorkStop(long userId, long accountId, long vmId, boolean cleanup) {
+        super(userId, accountId, vmId);
+        this.cleanup = cleanup;
+	}
+	
+	public boolean isCleanup() {
+		return cleanup;
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/engine/orchestration/src/com/cloud/vm/VmWorkStorageMigration.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VmWorkStorageMigration.java b/engine/orchestration/src/com/cloud/vm/VmWorkStorageMigration.java
new file mode 100644
index 0000000..ba8330c
--- /dev/null
+++ b/engine/orchestration/src/com/cloud/vm/VmWorkStorageMigration.java
@@ -0,0 +1,35 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.vm;
+
+import com.cloud.storage.StoragePool;
+
+public class VmWorkStorageMigration extends VmWork {
+	private static final long serialVersionUID = -8677979691741157474L;
+
+	StoragePool destPool;
+	
+    public VmWorkStorageMigration(long userId, long accountId, long vmId, StoragePool destPool) {
+    	super(userId, accountId, vmId);
+    	
+    	this.destPool = destPool;
+    }
+    
+    public StoragePool getDestStoragePool() {
+    	return this.destPool;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/framework/cluster/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java
----------------------------------------------------------------------
diff --git a/framework/cluster/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java b/framework/cluster/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java
index 246bfe6..d187199 100644
--- a/framework/cluster/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java
+++ b/framework/cluster/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java
@@ -100,6 +100,7 @@ public class ManagementServerHostDaoImpl extends GenericDaoBase<ManagementServer
             txn.commit();
         } catch(Exception e) {
             s_logger.warn("Unexpected exception, ", e);
+            throw new RuntimeException(e.getMessage(), e);
         }
 	}
 	
@@ -119,9 +120,8 @@ public class ManagementServerHostDaoImpl extends GenericDaoBase<ManagementServer
         	return true;
         } catch(Exception e) {
             s_logger.warn("Unexpected exception, ", e);
+            throw new RuntimeException(e.getMessage(), e);
         }
-        
-        return false;
     }
 
 	@Override
@@ -145,6 +145,7 @@ public class ManagementServerHostDaoImpl extends GenericDaoBase<ManagementServer
             }
         } catch(Exception e) {
             s_logger.warn("Unexpected exception, ", e);
+            throw new RuntimeException(e.getMessage(), e);
         }
 	}
 	
@@ -180,7 +181,7 @@ public class ManagementServerHostDaoImpl extends GenericDaoBase<ManagementServer
             txn.commit();
         } catch(Exception e) {
             s_logger.warn("Unexpected exception, ", e);
-            txn.rollback();
+            throw new RuntimeException(e.getMessage(), e);
         }
         
         return changedRows;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/framework/jobs/resources/META-INF/cloudstack/core/spring-framework-jobs-core-context.xml
----------------------------------------------------------------------
diff --git a/framework/jobs/resources/META-INF/cloudstack/core/spring-framework-jobs-core-context.xml b/framework/jobs/resources/META-INF/cloudstack/core/spring-framework-jobs-core-context.xml
index 85cad02..2d1eba0 100644
--- a/framework/jobs/resources/META-INF/cloudstack/core/spring-framework-jobs-core-context.xml
+++ b/framework/jobs/resources/META-INF/cloudstack/core/spring-framework-jobs-core-context.xml
@@ -43,6 +43,6 @@
         class="org.apache.cloudstack.framework.jobs.dao.SyncQueueItemDaoImpl" />
     <bean id="syncQueueManagerImpl"
         class="org.apache.cloudstack.framework.jobs.impl.SyncQueueManagerImpl" />
-
-    
+    <bean id="vmWorkJobDaoImpl"
+        class="org.apache.cloudstack.framework.jobs.dao.VmWorkJobDaoImpl" />
 </beans>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5a44de28/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java
----------------------------------------------------------------------
diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java
index 595800d..0263d3d 100644
--- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java
+++ b/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java
@@ -63,6 +63,14 @@ public class AsyncJobExecutionContext  {
     public void setJob(AsyncJob job) {
 		_job = job;
 	}
+    
+    public boolean isJobDispatchedBy(String jobDispatcherName) {
+    	assert(jobDispatcherName != null);
+    	if(_job != null && _job.getDispatcher() != null && _job.getDispatcher().equals(jobDispatcherName))
+    		return true;
+    	
+    	return false;
+    }
 	
     public void completeAsyncJob(JobInfo.Status jobStatus, int resultCode, String resultObject) {
     	assert(_job != null);
@@ -159,7 +167,7 @@ public class AsyncJobExecutionContext  {
         setCurrentExecutionContext(null);
         return context;
     }
-
+    
     // This is intended to be package level access for AsyncJobManagerImpl only.
     public static void setCurrentExecutionContext(AsyncJobExecutionContext currentContext) {
 		s_currentExectionContext.set(currentContext);