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:51 UTC

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

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);