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

[67/67] [abbrv] git commit: updated refs/heads/pluggable_vm_snapshot to d73f75a

move a lot of code into vmsnapshot strategy


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

Branch: refs/heads/pluggable_vm_snapshot
Commit: d73f75a2d5e9baf8b83fd2462439578066f3c179
Parents: 746c8c5
Author: Edison Su <su...@gmail.com>
Authored: Thu Oct 10 18:00:21 2013 -0700
Committer: Edison Su <su...@gmail.com>
Committed: Thu Oct 10 18:00:21 2013 -0700

----------------------------------------------------------------------
 .../api/storage/VMSnapshotStrategy.java         |  28 ++
 .../cloud/vm/snapshot/VMSnapshotDetailsVO.java  |  81 ++++
 .../vm/snapshot/dao/VMSnapshotDetailsDao.java   |  28 ++
 .../snapshot/dao/VMSnapshotDetailsDaoImpl.java  |  52 +++
 .../vmsnapshot/DefaultVMSnapshotStrategy.java   | 371 ++++++++++++++++++
 .../storage/vmsnapshot/VMSnapshotHelper.java    |  27 ++
 .../vmsnapshot/VMSnapshotHelperImpl.java        |  40 ++
 .../vm/snapshot/VMSnapshotManagerImpl.java      | 374 +++----------------
 8 files changed, 672 insertions(+), 329 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d73f75a2/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VMSnapshotStrategy.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VMSnapshotStrategy.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VMSnapshotStrategy.java
new file mode 100644
index 0000000..8dd6eca
--- /dev/null
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VMSnapshotStrategy.java
@@ -0,0 +1,28 @@
+/*
+ * 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 org.apache.cloudstack.engine.subsystem.api.storage;
+
+import com.cloud.vm.snapshot.VMSnapshot;
+
+public interface VMSnapshotStrategy {
+    VMSnapshot takeVMSnapshot(VMSnapshot vmSnapshot);
+    boolean deleteVMSnapshot(VMSnapshot vmSnapshot);
+    boolean revertVMSnapshot(VMSnapshot vmSnapshot);
+    boolean canHandle(VMSnapshot vmSnapshot);
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d73f75a2/engine/schema/src/com/cloud/vm/snapshot/VMSnapshotDetailsVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/vm/snapshot/VMSnapshotDetailsVO.java b/engine/schema/src/com/cloud/vm/snapshot/VMSnapshotDetailsVO.java
new file mode 100644
index 0000000..7ab7c72
--- /dev/null
+++ b/engine/schema/src/com/cloud/vm/snapshot/VMSnapshotDetailsVO.java
@@ -0,0 +1,81 @@
+/*
+ * 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.snapshot;
+
+import org.apache.cloudstack.api.InternalIdentity;
+
+import javax.persistence.Column;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+public class VMSnapshotDetailsVO implements InternalIdentity {
+    @Id
+    @GeneratedValue(strategy= GenerationType.IDENTITY)
+    @Column(name="id")
+    private long id;
+
+    @Column(name = "vm_snapshot_id")
+    Long vmSnapshotId;
+
+    @Column(name = "name")
+    String name;
+
+    @Column(name = "value")
+    String value;
+
+    public VMSnapshotDetailsVO() {
+
+    }
+
+    public VMSnapshotDetailsVO(Long vmSnapshotId, String name, String value) {
+        this.vmSnapshotId = vmSnapshotId;
+        this.name = name;
+        this.value = value;
+    }
+
+    public Long getVmSnapshotId() {
+        return this.vmSnapshotId;
+    }
+
+    public void setVmSnapshotId(Long vmSnapshotId) {
+        this.vmSnapshotId = vmSnapshotId;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getValue() {
+        return this.value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    @Override
+    public long getId() {
+       return id;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d73f75a2/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDetailsDao.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDetailsDao.java b/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDetailsDao.java
new file mode 100644
index 0000000..e84178c
--- /dev/null
+++ b/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDetailsDao.java
@@ -0,0 +1,28 @@
+/*
+ * 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.snapshot.dao;
+
+import com.cloud.utils.db.GenericDao;
+import com.cloud.vm.snapshot.VMSnapshotDetailsVO;
+
+import java.util.Map;
+
+public interface VMSnapshotDetailsDao extends GenericDao<VMSnapshotDetailsVO, Long> {
+    Map<String, String> getDetails(Long vmSnapshotId);
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d73f75a2/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDetailsDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDetailsDaoImpl.java b/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDetailsDaoImpl.java
new file mode 100644
index 0000000..b528b39
--- /dev/null
+++ b/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDetailsDaoImpl.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.snapshot.dao;
+
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.vm.snapshot.VMSnapshotDetailsVO;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class VMSnapshotDetailsDaoImpl extends GenericDaoBase<VMSnapshotDetailsVO, Long> implements VMSnapshotDetailsDao {
+    protected final SearchBuilder<VMSnapshotDetailsVO> searchDetails;
+
+    protected VMSnapshotDetailsDaoImpl() {
+        super();
+        searchDetails = createSearchBuilder();
+        searchDetails.and("vmsnapshotId", searchDetails.entity().getVmSnapshotId(), SearchCriteria.Op.EQ);
+        searchDetails.done();
+    }
+    @Override
+    public Map<String, String> getDetails(Long vmSnapshotId) {
+        SearchCriteria<VMSnapshotDetailsVO> sc = searchDetails.create();
+        sc.setParameters("vmsnapshotId", vmSnapshotId);
+
+        List<VMSnapshotDetailsVO> details = listBy(sc);
+        Map<String, String> detailsMap = new HashMap<String, String>();
+        for (VMSnapshotDetailsVO detail : details) {
+            detailsMap.put(detail.getName(), detail.getValue());
+        }
+
+        return detailsMap;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d73f75a2/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java
new file mode 100644
index 0000000..054f28c
--- /dev/null
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java
@@ -0,0 +1,371 @@
+/*
+ * 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 org.apache.cloudstack.storage.vmsnapshot;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.CreateVMSnapshotAnswer;
+import com.cloud.agent.api.CreateVMSnapshotCommand;
+import com.cloud.agent.api.DeleteVMSnapshotAnswer;
+import com.cloud.agent.api.DeleteVMSnapshotCommand;
+import com.cloud.agent.api.RevertToVMSnapshotAnswer;
+import com.cloud.agent.api.RevertToVMSnapshotCommand;
+import com.cloud.agent.api.VMSnapshotTO;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.event.EventTypes;
+import com.cloud.event.UsageEventUtils;
+import com.cloud.exception.AgentUnavailableException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.storage.DiskOfferingVO;
+import com.cloud.storage.GuestOSVO;
+import com.cloud.storage.VolumeVO;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.fsm.NoTransitionException;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+import org.apache.cloudstack.engine.subsystem.api.storage.VMSnapshotStrategy;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
+
+import javax.inject.Inject;
+import java.util.List;
+
+public class DefaultVMSnapshotStrategy implements VMSnapshotStrategy {
+    @Inject
+    VMSnapshotHelper vmSnapshotHelper;
+    @Override
+    public VMSnapshot takeVMSnapshot(VMSnapshot vmSnapshot) {
+        Long hostId = pickRunningHost(vmId);
+        try {
+            vmSnapshotHelper.vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.CreateRequested);
+        } catch (NoTransitionException e) {
+            throw new CloudRuntimeException(e.getMessage());
+        }
+
+        CreateVMSnapshotAnswer answer = null;
+        try {
+            GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId());
+
+            // prepare snapshotVolumeTos
+            List<VolumeTO> volumeTOs = getVolumeTOList(userVm.getId());
+
+            // prepare target snapshotTO and its parent snapshot (current snapshot)
+            VMSnapshotTO current = null;
+            VMSnapshotVO currentSnapshot = _vmSnapshotDao.findCurrentSnapshotByVmId(userVm.getId());
+            if (currentSnapshot != null)
+                current = getSnapshotWithParents(currentSnapshot);
+            VMSnapshotTO target = new VMSnapshotTO(vmSnapshot.getId(),  vmSnapshot.getName(), vmSnapshot.getType(), null, vmSnapshot.getDescription(), false,
+                    current);
+            if (current == null)
+                vmSnapshot.setParent(null);
+            else
+                vmSnapshot.setParent(current.getId());
+
+            CreateVMSnapshotCommand ccmd = new CreateVMSnapshotCommand(userVm.getInstanceName(),target ,volumeTOs, guestOS.getDisplayName(),userVm.getState());
+            ccmd.setWait(_wait);
+
+            answer = (CreateVMSnapshotAnswer) sendToPool(hostId, ccmd);
+            if (answer != null && answer.getResult()) {
+                processAnswer(vmSnapshot, userVm, answer, hostId);
+                s_logger.debug("Create vm snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName());
+            }else{
+
+                String errMsg = "Creating VM snapshot: " + vmSnapshot.getName() + " failed";
+                if(answer != null && answer.getDetails() != null)
+                    errMsg = errMsg + " due to " + answer.getDetails();
+                s_logger.error(errMsg);
+                vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed);
+                throw new CloudRuntimeException(errMsg);
+            }
+            return vmSnapshot;
+        } catch (Exception e) {
+            if(e instanceof AgentUnavailableException){
+                try {
+                    vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed);
+                } catch (NoTransitionException e1) {
+                    s_logger.error("Cannot set vm snapshot state due to: " + e1.getMessage());
+                }
+            }
+            String msg = e.getMessage();
+            s_logger.error("Create vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName() + " due to " + msg);
+            throw new CloudRuntimeException(msg);
+        } finally{
+            if(vmSnapshot.getState() == VMSnapshot.State.Allocated){
+                s_logger.warn("Create vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName());
+                _vmSnapshotDao.remove(vmSnapshot.getId());
+            }
+            if(vmSnapshot.getState() == VMSnapshot.State.Ready && answer != null){
+                for (VolumeTO volumeTo : answer.getVolumeTOs()){
+                    publishUsageEvent(EventTypes.EVENT_VM_SNAPSHOT_CREATE,vmSnapshot,userVm,volumeTo);
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean deleteVMSnapshot(VMSnapshot vmSnapshot) {
+        UserVmVO userVm = _userVMDao.findById(vmSnapshot.getVmId());
+        DeleteVMSnapshotAnswer answer = null;
+        try {
+            vmSnapshotStateTransitTo(vmSnapshot,VMSnapshot.Event.ExpungeRequested);
+            Long hostId = pickRunningHost(vmSnapshot.getVmId());
+
+            // prepare snapshotVolumeTos
+            List<VolumeTO> volumeTOs = getVolumeTOList(vmSnapshot.getVmId());
+
+            // prepare DeleteVMSnapshotCommand
+            String vmInstanceName = userVm.getInstanceName();
+            VMSnapshotTO parent = getSnapshotWithParents(vmSnapshot).getParent();
+            VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(vmSnapshot.getId(), vmSnapshot.getName(), vmSnapshot.getType(),
+                    vmSnapshot.getCreated().getTime(), vmSnapshot.getDescription(), vmSnapshot.getCurrent(), parent);
+            GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId());
+            DeleteVMSnapshotCommand deleteSnapshotCommand = new DeleteVMSnapshotCommand(vmInstanceName, vmSnapshotTO, volumeTOs,guestOS.getDisplayName());
+
+            answer = (DeleteVMSnapshotAnswer) sendToPool(hostId, deleteSnapshotCommand);
+
+            if (answer != null && answer.getResult()) {
+                processAnswer(vmSnapshot, userVm, answer, hostId);
+                s_logger.debug("Delete VM snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName());
+                return true;
+            } else {
+                s_logger.error("Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + answer.getDetails());
+                return false;
+            }
+        } catch (Exception e) {
+            String msg = "Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + e.getMessage();
+            s_logger.error(msg , e);
+            throw new CloudRuntimeException(e.getMessage());
+        } finally{
+            if(answer != null && answer.getResult()){
+                for (VolumeTO volumeTo : answer.getVolumeTOs()){
+                    publishUsageEvent(EventTypes.EVENT_VM_SNAPSHOT_DELETE,vmSnapshot,userVm,volumeTo);
+                }
+            }
+        }
+    }
+
+    @DB
+    protected void processAnswer(VMSnapshotVO vmSnapshot, UserVmVO userVm, Answer as, Long hostId) {
+        final Transaction txn = Transaction.currentTxn();
+        try {
+            txn.start();
+            if (as instanceof CreateVMSnapshotAnswer) {
+                CreateVMSnapshotAnswer answer = (CreateVMSnapshotAnswer) as;
+                finalizeCreate(vmSnapshot, answer.getVolumeTOs());
+                vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded);
+            } else if (as instanceof RevertToVMSnapshotAnswer) {
+                RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) as;
+                finalizeRevert(vmSnapshot, answer.getVolumeTOs());
+                vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded);
+            } else if (as instanceof DeleteVMSnapshotAnswer) {
+                DeleteVMSnapshotAnswer answer = (DeleteVMSnapshotAnswer) as;
+                finalizeDelete(vmSnapshot, answer.getVolumeTOs());
+                _vmSnapshotDao.remove(vmSnapshot.getId());
+            }
+            txn.commit();
+        } catch (Exception e) {
+            String errMsg = "Error while process answer: " + as.getClass() + " due to " + e.getMessage();
+            s_logger.error(errMsg, e);
+            txn.rollback();
+            throw new CloudRuntimeException(errMsg);
+        } finally {
+            txn.close();
+        }
+    }
+
+    protected void finalizeDelete(VMSnapshotVO vmSnapshot, List<VolumeTO> VolumeTOs) {
+        // update volumes path
+        updateVolumePath(VolumeTOs);
+
+        // update children's parent snapshots
+        List<VMSnapshotVO> children= _vmSnapshotDao.listByParent(vmSnapshot.getId());
+        for (VMSnapshotVO child : children) {
+            child.setParent(vmSnapshot.getParent());
+            _vmSnapshotDao.persist(child);
+        }
+
+        // update current snapshot
+        VMSnapshotVO current = _vmSnapshotDao.findCurrentSnapshotByVmId(vmSnapshot.getVmId());
+        if(current != null && current.getId() == vmSnapshot.getId() && vmSnapshot.getParent() != null){
+            VMSnapshotVO parent = _vmSnapshotDao.findById(vmSnapshot.getParent());
+            parent.setCurrent(true);
+            _vmSnapshotDao.persist(parent);
+        }
+        vmSnapshot.setCurrent(false);
+        _vmSnapshotDao.persist(vmSnapshot);
+    }
+
+    protected void finalizeCreate(VMSnapshotVO vmSnapshot, List<VolumeTO> VolumeTOs) {
+        // update volumes path
+        updateVolumePath(VolumeTOs);
+
+        vmSnapshot.setCurrent(true);
+
+        // change current snapshot
+        if (vmSnapshot.getParent() != null) {
+            VMSnapshotVO previousCurrent = _vmSnapshotDao.findById(vmSnapshot.getParent());
+            previousCurrent.setCurrent(false);
+            _vmSnapshotDao.persist(previousCurrent);
+        }
+        _vmSnapshotDao.persist(vmSnapshot);
+    }
+
+    protected void finalizeRevert(VMSnapshotVO vmSnapshot, List<VolumeTO> volumeToList) {
+        // update volumes path
+        updateVolumePath(volumeToList);
+
+        // update current snapshot, current snapshot is the one reverted to
+        VMSnapshotVO previousCurrent = _vmSnapshotDao.findCurrentSnapshotByVmId(vmSnapshot.getVmId());
+        if(previousCurrent != null){
+            previousCurrent.setCurrent(false);
+            _vmSnapshotDao.persist(previousCurrent);
+        }
+        vmSnapshot.setCurrent(true);
+        _vmSnapshotDao.persist(vmSnapshot);
+    }
+
+    private void updateVolumePath(List<VolumeTO> volumeTOs) {
+        for (VolumeTO volume : volumeTOs) {
+            if (volume.getPath() != null) {
+                VolumeVO volumeVO = _volumeDao.findById(volume.getId());
+                volumeVO.setPath(volume.getPath());
+                volumeVO.setVmSnapshotChainSize(volume.getChainSize());
+                _volumeDao.persist(volumeVO);
+            }
+        }
+    }
+
+    protected Long pickRunningHost(Long vmId) {
+        UserVmVO vm = _userVMDao.findById(vmId);
+        // use VM's host if VM is running
+        if(vm.getState() == VirtualMachine.State.Running)
+            return vm.getHostId();
+
+        // check if lastHostId is available
+        if(vm.getLastHostId() != null){
+            HostVO lastHost =  _hostDao.findById(vm.getLastHostId());
+            if(lastHost.getStatus() == com.cloud.host.Status.Up && !lastHost.isInMaintenanceStates())
+                return lastHost.getId();
+        }
+
+        List<VolumeVO> listVolumes = _volumeDao.findByInstance(vmId);
+        if (listVolumes == null || listVolumes.size() == 0) {
+            throw new InvalidParameterValueException("vmInstance has no volumes");
+        }
+        VolumeVO volume = listVolumes.get(0);
+        Long poolId = volume.getPoolId();
+        if (poolId == null) {
+            throw new InvalidParameterValueException("pool id is not found");
+        }
+        StoragePoolVO storagePool = _storagePoolDao.findById(poolId);
+        if (storagePool == null) {
+            throw new InvalidParameterValueException("storage pool is not found");
+        }
+        List<HostVO> listHost = _hostDao.listAllUpAndEnabledNonHAHosts(Host.Type.Routing, storagePool.getClusterId(), storagePool.getPodId(),
+                storagePool.getDataCenterId(), null);
+        if (listHost == null || listHost.size() == 0) {
+            throw new InvalidParameterValueException("no host in up state is found");
+        }
+        return listHost.get(0).getId();
+    }
+
+
+    private void publishUsageEvent(String type, VMSnapshot vmSnapshot, UserVm userVm, VolumeTO volumeTo){
+        VolumeVO volume = _volumeDao.findById(volumeTo.getId());
+        Long diskOfferingId = volume.getDiskOfferingId();
+        Long offeringId = null;
+        if (diskOfferingId != null) {
+            DiskOfferingVO offering = _diskOfferingDao.findById(diskOfferingId);
+            if (offering != null
+                    && (offering.getType() == DiskOfferingVO.Type.Disk)) {
+                offeringId = offering.getId();
+            }
+        }
+        UsageEventUtils.publishUsageEvent(
+                type,
+                vmSnapshot.getAccountId(),
+                userVm.getDataCenterId(),
+                userVm.getId(),
+                vmSnapshot.getName(),
+                offeringId,
+                volume.getId(), // save volume's id into templateId field
+                volumeTo.getChainSize(),
+                VMSnapshot.class.getName(), vmSnapshot.getUuid());
+    }
+
+    @Override
+    public boolean revertVMSnapshot(VMSnapshot vmSnapshot) {
+        userVm = _userVMDao.findById(userVm.getId());
+        try {
+            vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.RevertRequested);
+        } catch (NoTransitionException e) {
+            throw new CloudRuntimeException(e.getMessage());
+        }
+
+        try {
+            VMSnapshotVO snapshot = _vmSnapshotDao.findById(vmSnapshotVo.getId());
+            // prepare RevertToSnapshotCommand
+            List<VolumeTO> volumeTOs = getVolumeTOList(userVm.getId());
+            String vmInstanceName = userVm.getInstanceName();
+            VMSnapshotTO parent = getSnapshotWithParents(snapshot).getParent();
+            VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(snapshot.getId(), snapshot.getName(), snapshot.getType(),
+                    snapshot.getCreated().getTime(), snapshot.getDescription(), snapshot.getCurrent(), parent);
+
+            GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId());
+            RevertToVMSnapshotCommand revertToSnapshotCommand = new RevertToVMSnapshotCommand(vmInstanceName, vmSnapshotTO, volumeTOs, guestOS.getDisplayName());
+
+            RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) sendToPool(hostId, revertToSnapshotCommand);
+            if (answer != null && answer.getResult()) {
+                processAnswer(vmSnapshotVo, userVm, answer, hostId);
+                s_logger.debug("RevertTo " + vmSnapshotVo.getName() + " succeeded for vm: " + userVm.getInstanceName());
+            } else {
+                String errMsg = "Revert VM: " + userVm.getInstanceName() + " to snapshot: "+ vmSnapshotVo.getName() + " failed";
+                if(answer != null && answer.getDetails() != null)
+                    errMsg = errMsg + " due to " + answer.getDetails();
+                s_logger.error(errMsg);
+                // agent report revert operation fails
+                vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.OperationFailed);
+                throw new CloudRuntimeException(errMsg);
+            }
+        } catch (Exception e) {
+            if(e instanceof AgentUnavailableException){
+                try {
+                    vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.OperationFailed);
+                } catch (NoTransitionException e1) {
+                    s_logger.error("Cannot set vm snapshot state due to: " + e1.getMessage());
+                }
+            }
+            // for other exceptions, do not change VM snapshot state, leave it for snapshotSync
+            String errMsg = "revert vm: " + userVm.getInstanceName() + " to snapshot " + vmSnapshotVo.getName() + " failed due to " + e.getMessage();
+            s_logger.error(errMsg);
+            throw new CloudRuntimeException(e.getMessage());
+        }
+        return userVm;
+    }
+
+    @Override
+    public boolean canHandle(VMSnapshot vmSnapshot) {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d73f75a2/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotHelper.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotHelper.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotHelper.java
new file mode 100644
index 0000000..4330498
--- /dev/null
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotHelper.java
@@ -0,0 +1,27 @@
+/*
+ * 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 org.apache.cloudstack.storage.vmsnapshot;
+
+import com.cloud.utils.fsm.NoTransitionException;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+
+public interface VMSnapshotHelper {
+  boolean vmSnapshotStateTransitTo(VMSnapshot vsnp, VMSnapshot.Event event) throws NoTransitionException;
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d73f75a2/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotHelperImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotHelperImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotHelperImpl.java
new file mode 100644
index 0000000..c96b8ef
--- /dev/null
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotHelperImpl.java
@@ -0,0 +1,40 @@
+/*
+ * 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 org.apache.cloudstack.storage.vmsnapshot;
+
+import com.cloud.utils.fsm.NoTransitionException;
+import com.cloud.utils.fsm.StateMachine2;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
+
+import javax.inject.Inject;
+
+public class VMSnapshotHelperImpl implements VMSnapshotHelper {
+    @Inject
+    VMSnapshotDao _vmSnapshotDao;
+    StateMachine2<VMSnapshot.State, VMSnapshot.Event, VMSnapshot> _vmSnapshottateMachine ;
+    public VMSnapshotHelperImpl() {
+        _vmSnapshottateMachine   = VMSnapshot.State.getStateMachine();
+    }
+    @Override
+    public boolean vmSnapshotStateTransitTo(VMSnapshot vsnp, VMSnapshot.Event event) throws NoTransitionException {
+        return _vmSnapshottateMachine.transitTo(vsnp, event, null, _vmSnapshotDao);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d73f75a2/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
index aa772fe..dc5d9ed 100644
--- a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
+++ b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
@@ -27,6 +27,7 @@ import javax.ejb.Local;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import org.apache.cloudstack.engine.subsystem.api.storage.VMSnapshotStrategy;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
@@ -127,9 +128,20 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
     @Inject HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
     @Inject DiskOfferingDao _diskOfferingDao;
     @Inject ServiceOfferingDao _serviceOfferingDao;
+    @Inject List<VMSnapshotStrategy> vmSnapshotStrategies;
+
+    public List<VMSnapshotStrategy> getVmSnapshotStrategies() {
+        return vmSnapshotStrategies;
+    }
+
+    @Inject
+    public void setVmSnapshotStrategies(List<VMSnapshotStrategy> vmSnapshotStrategies) {
+        this.vmSnapshotStrategies = vmSnapshotStrategies;
+    }
+
     int _vmSnapshotMax;
     int _wait;
-    StateMachine2<VMSnapshot.State, VMSnapshot.Event, VMSnapshot> _vmSnapshottateMachine ;
+
 
     @Override
     public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
@@ -144,7 +156,6 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
         String value = _configDao.getValue("vmsnapshot.create.wait");
         _wait = NumbersUtil.parseInt(value, 1800);
 
-        _vmSnapshottateMachine   = VMSnapshot.State.getStateMachine();
         return true;
     }
 
@@ -336,6 +347,22 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
         return _name;
     }
 
+    private VMSnapshotStrategy findVMSnapshotStrategy(VMSnapshot vmSnapshot) {
+        VMSnapshotStrategy snapshotStrategy = null;
+        for(VMSnapshotStrategy strategy : vmSnapshotStrategies) {
+            if (strategy.canHandle(vmSnapshot)) {
+                snapshotStrategy = strategy;
+                break;
+            }
+        }
+
+        if (snapshotStrategy == null) {
+            throw new CloudRuntimeException("can't find vm snapshot strategy for vmsnapshot: " + vmSnapshot.getId());
+        }
+
+        return snapshotStrategy;
+    }
+
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_CREATE, eventDescription = "creating VM snapshot", async = true)
     public VMSnapshot creatVMSnapshot(Long vmId, Long vmSnapshotId) {
@@ -347,99 +374,12 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
         if(vmSnapshot == null){
             throw new CloudRuntimeException("VM snapshot id: " + vmSnapshotId + " can not be found");
         }
-        Long hostId = pickRunningHost(vmId);
-        try {
-            vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.CreateRequested);
-        } catch (NoTransitionException e) {
-            throw new CloudRuntimeException(e.getMessage());
-        }
-        return createVmSnapshotInternal(userVm, vmSnapshot, hostId);
-    }
 
-    protected VMSnapshot createVmSnapshotInternal(UserVmVO userVm, VMSnapshotVO vmSnapshot, Long hostId) {
-        CreateVMSnapshotAnswer answer = null;
-        try {
-            GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId());
-            
-            // prepare snapshotVolumeTos
-            List<VolumeTO> volumeTOs = getVolumeTOList(userVm.getId());
-            
-            // prepare target snapshotTO and its parent snapshot (current snapshot)
-            VMSnapshotTO current = null;
-            VMSnapshotVO currentSnapshot = _vmSnapshotDao.findCurrentSnapshotByVmId(userVm.getId());
-            if (currentSnapshot != null)
-                current = getSnapshotWithParents(currentSnapshot);
-            VMSnapshotTO target = new VMSnapshotTO(vmSnapshot.getId(),  vmSnapshot.getName(), vmSnapshot.getType(), null, vmSnapshot.getDescription(), false,
-                    current);
-            if (current == null)
-                vmSnapshot.setParent(null);
-            else
-                vmSnapshot.setParent(current.getId());
-
-            CreateVMSnapshotCommand ccmd = new CreateVMSnapshotCommand(userVm.getInstanceName(),target ,volumeTOs, guestOS.getDisplayName(),userVm.getState());
-            ccmd.setWait(_wait);
-            
-            answer = (CreateVMSnapshotAnswer) sendToPool(hostId, ccmd);
-            if (answer != null && answer.getResult()) {
-                processAnswer(vmSnapshot, userVm, answer, hostId);
-                s_logger.debug("Create vm snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName());
-            }else{
-                
-                String errMsg = "Creating VM snapshot: " + vmSnapshot.getName() + " failed";
-                if(answer != null && answer.getDetails() != null)
-                    errMsg = errMsg + " due to " + answer.getDetails();
-                s_logger.error(errMsg);
-                vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed);
-                throw new CloudRuntimeException(errMsg);
-            }
-            return vmSnapshot;
-        } catch (Exception e) {
-            if(e instanceof AgentUnavailableException){
-                try {
-                    vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed);
-                } catch (NoTransitionException e1) {
-                    s_logger.error("Cannot set vm snapshot state due to: " + e1.getMessage());
-                }
-            }
-            String msg = e.getMessage();
-            s_logger.error("Create vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName() + " due to " + msg);
-            throw new CloudRuntimeException(msg);
-        } finally{
-            if(vmSnapshot.getState() == VMSnapshot.State.Allocated){
-                s_logger.warn("Create vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName());
-                _vmSnapshotDao.remove(vmSnapshot.getId());
-            }
-            if(vmSnapshot.getState() == VMSnapshot.State.Ready && answer != null){
-                for (VolumeTO volumeTo : answer.getVolumeTOs()){
-                    publishUsageEvent(EventTypes.EVENT_VM_SNAPSHOT_CREATE,vmSnapshot,userVm,volumeTo);
-                }
-            }
-        }
+        VMSnapshotStrategy strategy = findVMSnapshotStrategy(vmSnapshot);
+        VMSnapshot snapshot = strategy.takeVMSnapshot(vmSnapshot);
+        return snapshot;
     }
 
-    private void publishUsageEvent(String type, VMSnapshot vmSnapshot, UserVm userVm, VolumeTO volumeTo){
-        VolumeVO volume = _volumeDao.findById(volumeTo.getId());
-        Long diskOfferingId = volume.getDiskOfferingId();
-        Long offeringId = null;
-        if (diskOfferingId != null) {
-            DiskOfferingVO offering = _diskOfferingDao.findById(diskOfferingId);
-            if (offering != null
-                    && (offering.getType() == DiskOfferingVO.Type.Disk)) {
-                offeringId = offering.getId();
-            }
-        }
-        UsageEventUtils.publishUsageEvent(
-                type,
-                vmSnapshot.getAccountId(),
-                userVm.getDataCenterId(),
-                userVm.getId(),
-                vmSnapshot.getName(),
-                offeringId,     
-                volume.getId(), // save volume's id into templateId field
-                volumeTo.getChainSize(),
-                VMSnapshot.class.getName(), vmSnapshot.getUuid());       
-    }
-    
     protected List<VolumeTO> getVolumeTOList(Long vmId) {
         List<VolumeTO> volumeTOs = new ArrayList<VolumeTO>();
         List<VolumeVO> volumeVos = _volumeDao.findByInstance(vmId);
@@ -477,111 +417,10 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
                 vo.getCurrent(), null);
     }
 
-    protected boolean vmSnapshotStateTransitTo(VMSnapshotVO vsnp, VMSnapshot.Event event) throws NoTransitionException {
-        return _vmSnapshottateMachine.transitTo(vsnp, event, null, _vmSnapshotDao);
-    }
-    
-    @DB
-    protected void processAnswer(VMSnapshotVO vmSnapshot, UserVmVO  userVm, Answer as, Long hostId) {
-        final Transaction txn = Transaction.currentTxn();
-        try {
-            txn.start();
-            if (as instanceof CreateVMSnapshotAnswer) {
-                CreateVMSnapshotAnswer answer = (CreateVMSnapshotAnswer) as;
-                finalizeCreate(vmSnapshot, answer.getVolumeTOs());
-                vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded);
-            } else if (as instanceof RevertToVMSnapshotAnswer) {
-                RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) as;
-                finalizeRevert(vmSnapshot, answer.getVolumeTOs());
-                vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded);
-            } else if (as instanceof DeleteVMSnapshotAnswer) {
-                DeleteVMSnapshotAnswer answer = (DeleteVMSnapshotAnswer) as;
-                finalizeDelete(vmSnapshot, answer.getVolumeTOs());
-                _vmSnapshotDao.remove(vmSnapshot.getId());
-            }
-            txn.commit();
-        } catch (Exception e) {
-            String errMsg = "Error while process answer: " + as.getClass() + " due to " + e.getMessage();
-            s_logger.error(errMsg, e);
-            txn.rollback();
-            throw new CloudRuntimeException(errMsg);
-        } finally {
-            txn.close();
-        }
-    }
-
-    protected void finalizeDelete(VMSnapshotVO vmSnapshot, List<VolumeTO> VolumeTOs) {
-        // update volumes path
-        updateVolumePath(VolumeTOs);
-        
-        // update children's parent snapshots
-        List<VMSnapshotVO> children= _vmSnapshotDao.listByParent(vmSnapshot.getId());
-        for (VMSnapshotVO child : children) {
-            child.setParent(vmSnapshot.getParent());
-            _vmSnapshotDao.persist(child);
-        }
-        
-        // update current snapshot
-        VMSnapshotVO current = _vmSnapshotDao.findCurrentSnapshotByVmId(vmSnapshot.getVmId());
-        if(current != null && current.getId() == vmSnapshot.getId() && vmSnapshot.getParent() != null){
-            VMSnapshotVO parent = _vmSnapshotDao.findById(vmSnapshot.getParent());
-            parent.setCurrent(true);
-            _vmSnapshotDao.persist(parent);
-        }
-        vmSnapshot.setCurrent(false);
-        _vmSnapshotDao.persist(vmSnapshot);
-    }
-
-    protected void finalizeCreate(VMSnapshotVO vmSnapshot, List<VolumeTO> VolumeTOs) {
-        // update volumes path
-        updateVolumePath(VolumeTOs);
-        
-        vmSnapshot.setCurrent(true);
-        
-        // change current snapshot
-        if (vmSnapshot.getParent() != null) {
-            VMSnapshotVO previousCurrent = _vmSnapshotDao.findById(vmSnapshot.getParent());
-            previousCurrent.setCurrent(false);
-            _vmSnapshotDao.persist(previousCurrent);
-        }
-        _vmSnapshotDao.persist(vmSnapshot);
-    }
-
-    protected void finalizeRevert(VMSnapshotVO vmSnapshot, List<VolumeTO> volumeToList) {
-        // update volumes path
-        updateVolumePath(volumeToList);
-
-        // update current snapshot, current snapshot is the one reverted to
-        VMSnapshotVO previousCurrent = _vmSnapshotDao.findCurrentSnapshotByVmId(vmSnapshot.getVmId());
-        if(previousCurrent != null){
-            previousCurrent.setCurrent(false);
-            _vmSnapshotDao.persist(previousCurrent);
-        }
-        vmSnapshot.setCurrent(true);
-        _vmSnapshotDao.persist(vmSnapshot);
-    }
-
-    private void updateVolumePath(List<VolumeTO> volumeTOs) {
-        for (VolumeTO volume : volumeTOs) {
-            if (volume.getPath() != null) {
-                VolumeVO volumeVO = _volumeDao.findById(volume.getId());
-                volumeVO.setPath(volume.getPath());
-                volumeVO.setVmSnapshotChainSize(volume.getChainSize());
-                _volumeDao.persist(volumeVO);
-            }
-        }
-    }
-    
     public VMSnapshotManagerImpl() {
         
     }
-    
-    protected Answer sendToPool(Long hostId, Command cmd) throws AgentUnavailableException, OperationTimedoutException {
-        long targetHostId = _hvGuruMgr.getGuruProcessedCommandTargetHost(hostId, cmd);
-        Answer answer = _agentMgr.send(targetHostId, cmd);
-        return answer;
-    }
-    
+
     @Override
     public boolean hasActiveVMSnapshotTasks(Long vmId){
         List<VMSnapshotVO> activeVMSnapshots = _vmSnapshotDao.listByInstanceId(vmId,
@@ -617,50 +456,9 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
 
         if(vmSnapshot.getState() == VMSnapshot.State.Allocated){
             return _vmSnapshotDao.remove(vmSnapshot.getId());
-        }else{
-            return deleteSnapshotInternal(vmSnapshot);
-        }
-    }
-
-    @DB
-    protected boolean deleteSnapshotInternal(VMSnapshotVO vmSnapshot) {
-        UserVmVO userVm = _userVMDao.findById(vmSnapshot.getVmId());
-        DeleteVMSnapshotAnswer answer = null;
-        try {
-            vmSnapshotStateTransitTo(vmSnapshot,VMSnapshot.Event.ExpungeRequested);
-            Long hostId = pickRunningHost(vmSnapshot.getVmId());
-
-            // prepare snapshotVolumeTos
-            List<VolumeTO> volumeTOs = getVolumeTOList(vmSnapshot.getVmId());
-            
-            // prepare DeleteVMSnapshotCommand
-            String vmInstanceName = userVm.getInstanceName();
-            VMSnapshotTO parent = getSnapshotWithParents(vmSnapshot).getParent();
-            VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(vmSnapshot.getId(), vmSnapshot.getName(), vmSnapshot.getType(),
-                    vmSnapshot.getCreated().getTime(), vmSnapshot.getDescription(), vmSnapshot.getCurrent(), parent);
-            GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId());
-            DeleteVMSnapshotCommand deleteSnapshotCommand = new DeleteVMSnapshotCommand(vmInstanceName, vmSnapshotTO, volumeTOs,guestOS.getDisplayName());
-            
-            answer = (DeleteVMSnapshotAnswer) sendToPool(hostId, deleteSnapshotCommand);
-           
-            if (answer != null && answer.getResult()) {
-                processAnswer(vmSnapshot, userVm, answer, hostId);
-                s_logger.debug("Delete VM snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName());
-                return true;
-            } else {
-                s_logger.error("Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + answer.getDetails());
-                return false;
-            }
-        } catch (Exception e) {
-            String msg = "Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + e.getMessage();
-            s_logger.error(msg , e);
-            throw new CloudRuntimeException(e.getMessage());
-        } finally{
-            if(answer != null && answer.getResult()){
-                for (VolumeTO volumeTo : answer.getVolumeTOs()){
-                    publishUsageEvent(EventTypes.EVENT_VM_SNAPSHOT_DELETE,vmSnapshot,userVm,volumeTo);
-                }
-            }
+        } else{
+            VMSnapshotStrategy strategy = findVMSnapshotStrategy(vmSnapshot);
+            return strategy.deleteVMSnapshot(vmSnapshot);
         }
     }
 
@@ -726,108 +524,24 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
                     throw new CloudRuntimeException(e.getMessage());
                 }
             }
-            hostId = pickRunningHost(userVm.getId());
         }
-        
-        if(hostId == null)
-            throw new CloudRuntimeException("Can not find any host to revert snapshot " + vmSnapshotVo.getName());
-        
+
         // check if there are other active VM snapshot tasks
         if (hasActiveVMSnapshotTasks(userVm.getId())) {
             throw new InvalidParameterValueException("There is other active vm snapshot tasks on the instance, please try again later");
         }
         
-        userVm = _userVMDao.findById(userVm.getId());
-        try {
-            vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.RevertRequested);
-        } catch (NoTransitionException e) {
-            throw new CloudRuntimeException(e.getMessage());
-        }
-        return revertInternal(userVm, vmSnapshotVo, hostId);
-    }
-
-    private UserVm revertInternal(UserVmVO userVm, VMSnapshotVO vmSnapshotVo, Long hostId) {
-        try {
-            VMSnapshotVO snapshot = _vmSnapshotDao.findById(vmSnapshotVo.getId());
-            // prepare RevertToSnapshotCommand
-            List<VolumeTO> volumeTOs = getVolumeTOList(userVm.getId());
-            String vmInstanceName = userVm.getInstanceName();
-            VMSnapshotTO parent = getSnapshotWithParents(snapshot).getParent();
-            VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(snapshot.getId(), snapshot.getName(), snapshot.getType(), 
-                    snapshot.getCreated().getTime(), snapshot.getDescription(), snapshot.getCurrent(), parent);
-            
-            GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId());
-            RevertToVMSnapshotCommand revertToSnapshotCommand = new RevertToVMSnapshotCommand(vmInstanceName, vmSnapshotTO, volumeTOs, guestOS.getDisplayName());
-           
-            RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) sendToPool(hostId, revertToSnapshotCommand);
-            if (answer != null && answer.getResult()) {
-                processAnswer(vmSnapshotVo, userVm, answer, hostId);
-                s_logger.debug("RevertTo " + vmSnapshotVo.getName() + " succeeded for vm: " + userVm.getInstanceName());
-            } else {
-                String errMsg = "Revert VM: " + userVm.getInstanceName() + " to snapshot: "+ vmSnapshotVo.getName() + " failed";
-                if(answer != null && answer.getDetails() != null)
-                    errMsg = errMsg + " due to " + answer.getDetails();
-                s_logger.error(errMsg);
-                // agent report revert operation fails
-                vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.OperationFailed);
-                throw new CloudRuntimeException(errMsg);
-            }
-        } catch (Exception e) {
-            if(e instanceof AgentUnavailableException){
-                try {
-                    vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.OperationFailed);
-                } catch (NoTransitionException e1) {
-                    s_logger.error("Cannot set vm snapshot state due to: " + e1.getMessage());
-                }
-            }
-            // for other exceptions, do not change VM snapshot state, leave it for snapshotSync
-            String errMsg = "revert vm: " + userVm.getInstanceName() + " to snapshot " + vmSnapshotVo.getName() + " failed due to " + e.getMessage();
-            s_logger.error(errMsg);
-            throw new CloudRuntimeException(e.getMessage());
-        }
+        VMSnapshotStrategy strategy = findVMSnapshotStrategy(vmSnapshotVo);
+        strategy.revertVMSnapshot(vmSnapshotVo);
         return userVm;
     }
 
-
     @Override
     public VMSnapshot getVMSnapshotById(Long id) {
         VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(id);
         return vmSnapshot;
     }
 
-    protected Long pickRunningHost(Long vmId) {
-        UserVmVO vm = _userVMDao.findById(vmId);
-        // use VM's host if VM is running
-        if(vm.getState() == State.Running)
-            return vm.getHostId();
-        
-        // check if lastHostId is available
-        if(vm.getLastHostId() != null){
-           HostVO lastHost =  _hostDao.findById(vm.getLastHostId());
-           if(lastHost.getStatus() == com.cloud.host.Status.Up && !lastHost.isInMaintenanceStates())
-               return lastHost.getId();
-        }
-        
-        List<VolumeVO> listVolumes = _volumeDao.findByInstance(vmId);
-        if (listVolumes == null || listVolumes.size() == 0) {
-            throw new InvalidParameterValueException("vmInstance has no volumes");
-        }
-        VolumeVO volume = listVolumes.get(0);
-        Long poolId = volume.getPoolId();
-        if (poolId == null) {
-            throw new InvalidParameterValueException("pool id is not found");
-        }
-        StoragePoolVO storagePool = _storagePoolDao.findById(poolId);
-        if (storagePool == null) {
-            throw new InvalidParameterValueException("storage pool is not found");
-        }
-        List<HostVO> listHost = _hostDao.listAllUpAndEnabledNonHAHosts(Host.Type.Routing, storagePool.getClusterId(), storagePool.getPodId(),
-                storagePool.getDataCenterId(), null);
-        if (listHost == null || listHost.size() == 0) {
-            throw new InvalidParameterValueException("no host in up state is found");
-        }
-        return listHost.get(0).getId();
-    }
 
     @Override
     public VirtualMachine getVMBySnapshotId(Long id) {
@@ -851,7 +565,8 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
             VMSnapshotVO target = _vmSnapshotDao.findById(snapshot.getId());
             if(type != null && target.getType() != type)
                 continue;
-            if (!deleteSnapshotInternal(target)) {
+            VMSnapshotStrategy strategy = findVMSnapshotStrategy(target);
+            if (!strategy.deleteVMSnapshot(target)) {
                 result = false;
                 break;
             }
@@ -869,12 +584,13 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
             
             List<VMSnapshotVO> vmSnapshotsInExpungingStates = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging, VMSnapshot.State.Reverting, VMSnapshot.State.Creating);
             for (VMSnapshotVO vmSnapshotVO : vmSnapshotsInExpungingStates) {
+                VMSnapshotStrategy strategy = findVMSnapshotStrategy(vmSnapshotVO);
                 if(vmSnapshotVO.getState() == VMSnapshot.State.Expunging){
-                    return deleteSnapshotInternal(vmSnapshotVO);
+                    return strategy.deleteVMSnapshot(vmSnapshotVO);
                 }else if(vmSnapshotVO.getState() == VMSnapshot.State.Creating){
-                    return createVmSnapshotInternal(userVm, vmSnapshotVO, hostId) != null;
+                    return strategy.takeVMSnapshot(vmSnapshotVO) != null;
                 }else if(vmSnapshotVO.getState() == VMSnapshot.State.Reverting){
-                    return revertInternal(userVm, vmSnapshotVO, hostId) != null;
+                    return strategy.revertVMSnapshot(vmSnapshotVO);
                 }
             }
         }catch (Exception e) {