http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/3a60d5e1/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
new file mode 100644
index 0000000..54f92ae
--- /dev/null
+++ b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
@@ -0,0 +1,948 @@
+// 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 java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.AgentManager;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.ComputeChecksumCommand;
+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.GetVolumesChangedAnswer;
+import com.cloud.agent.api.GetVolumesChangedCommand;
+import com.cloud.agent.api.RevertToSnapshotAnswer;
+import com.cloud.agent.api.RevertToSnapshotCommand;
+import com.cloud.agent.api.StopAnswer;
+import com.cloud.agent.api.StopCommand;
+import com.cloud.agent.api.to.VMSnapshotVolumeTO;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.api.commands.CreateVMSnapshotCmd;
+import com.cloud.api.commands.DeleteVMSnapshotCmd;
+import com.cloud.api.commands.ListVmSnapshotCmd;
+import com.cloud.api.commands.RevertToSnapshotCmd;
+import com.cloud.configuration.ConfigurationManager;
+import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.dc.ClusterVO;
+import com.cloud.dc.dao.ClusterDao;
+import com.cloud.domain.dao.DomainDao;
+import com.cloud.event.ActionEvent;
+import com.cloud.event.EventTypes;
+import com.cloud.event.dao.UsageEventDao;
+import com.cloud.exception.AgentUnavailableException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.OperationTimedoutException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.ha.HighAvailabilityManager;
+import com.cloud.ha.HighAvailabilityManager.WorkType;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.hypervisor.HypervisorGuruManager;
+import com.cloud.network.NetworkManager;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.security.SecurityGroupManager;
+import com.cloud.network.security.dao.SecurityGroupDao;
+import com.cloud.offerings.dao.NetworkOfferingDao;
+import com.cloud.projects.Project.ListProjectResourcesCriteria;
+import com.cloud.service.dao.ServiceOfferingDao;
+import com.cloud.storage.GuestOSVO;
+import com.cloud.storage.Snapshot;
+import com.cloud.storage.SnapshotVO;
+import com.cloud.storage.StoragePoolVO;
+import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.GuestOSDao;
+import com.cloud.storage.dao.SnapshotDao;
+import com.cloud.storage.dao.StoragePoolDao;
+import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.storage.dao.VMTemplateDetailsDao;
+import com.cloud.storage.dao.VolumeDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.UserContext;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.user.dao.SSHKeyPairDao;
+import com.cloud.user.dao.UserDao;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.DateUtil;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.Pair;
+import com.cloud.utils.Ternary;
+import com.cloud.utils.component.ComponentLocator;
+import com.cloud.utils.component.Inject;
+import com.cloud.utils.component.Manager;
+import com.cloud.utils.concurrency.NamedThreadFactory;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GlobalLock;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.exception.ExecutionException;
+import com.cloud.utils.fsm.NoTransitionException;
+import com.cloud.utils.fsm.StateMachine2;
+import com.cloud.vm.UserVmManager;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachine.Event;
+import com.cloud.vm.VirtualMachine.State;
+import com.cloud.vm.VirtualMachineGuru;
+import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.dao.VMInstanceDao;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
+import com.cloud.vm.snapshot.dao.VMSnapshotVolumeDao;
+
+@Local(value = { VMSnapshotManager.class, VMSnapshotService.class })
+public class VMSnapshotManagerImpl implements VMSnapshotManager,
+        VMSnapshotService, Manager {
+    private static final Logger s_logger = Logger
+            .getLogger(VMSnapshotManagerImpl.class);
+    String _name;
+    @Inject
+    protected VMSnapshotDao _vmSnapshotDao;
+    @Inject
+    protected VolumeDao _volumeDao;
+    @Inject
+    protected AccountDao _accountDao;
+    @Inject
+    protected VMInstanceDao _vmInstanceDao;
+    @Inject
+    protected UserVmDao _userVMDao;
+    @Inject
+    protected HostDao _hostDao;
+    @Inject
+    protected ClusterDao _clusterDao;
+    @Inject
+    protected UserDao _userDao;
+    @Inject
+    protected VMSnapshotVolumeDao _vmSnapshotVolumeDao;
+    @Inject
+    protected AgentManager _agentMgr;
+    @Inject
+    protected HypervisorGuruManager _hvGuruMgr;
+    @Inject
+    protected AccountManager _accountMgr;
+    @Inject
+    protected VolumeDao _volsDao = null;
+    @Inject
+    protected GuestOSDao _guestOSDao = null;
+    @Inject
+    protected VMTemplateDao _templateDao = null;
+    @Inject
+    protected VMTemplateDetailsDao _templateDetailsDao = null;
+    @Inject
+    private StoragePoolDao _storagePoolDao;
+    @Inject
+    protected NetworkManager _networkMgr = null;
+    @Inject
+    protected NetworkDao _networkDao = null;
+    @Inject
+    protected SecurityGroupManager _securityGroupMgr;
+    @Inject
+    protected SecurityGroupDao _securityGroupDao;
+    @Inject
+    protected ConfigurationManager _configMgr = null;
+    @Inject
+    protected NetworkOfferingDao _networkOfferingDao;
+    @Inject
+    protected DomainDao _domainDao;
+    @Inject
+    protected ServiceOfferingDao _serviceOfferingDao;
+    @Inject
+    protected SSHKeyPairDao _sshKeyPairDao;
+    @Inject
+    protected UserVmDao _vmDao = null;
+    @Inject
+    protected UsageEventDao _usageEventDao;
+    @Inject
+    protected VMTemplateDao _vmTemplateDao;
+    @Inject
+    UserVmManager _userVmMgr;
+    @Inject
+    protected SnapshotDao _snapshotDao = null;
+    @Inject
+    protected HighAvailabilityManager _haMgr;
+    @Inject
+    GuestOSDao _guestOsDao;
+
+    private ConfigurationDao _configDao;
+    protected String _instance;
+    protected int _vmSnapshotMax;
+    protected StateMachine2<State, VirtualMachine.Event, VirtualMachine> 
_stateMachine;
+    ScheduledExecutorService _executor = null;
+    int _snapshotCleanupInterval;
+
+    Map<VirtualMachine.Type, VirtualMachineGuru<? extends VMInstanceVO>> 
_vmGurus = new HashMap<VirtualMachine.Type, VirtualMachineGuru<? extends 
VMInstanceVO>>();
+
+    @Override
+    public boolean configure(String name, Map<String, Object> params)
+            throws ConfigurationException {
+        _name = name;
+
+        ComponentLocator locator = ComponentLocator.getCurrentLocator();
+        _configDao = locator.getDao(ConfigurationDao.class);
+        if (_configDao == null) {
+            throw new ConfigurationException(
+                    "Unable to get the configuration dao.");
+        }
+        s_logger.info("Snapshot Manager is configured.");
+
+        Map<String, String> configs = _configDao.getConfiguration(
+                "AgentManager", params);
+        _instance = configs.get("instance.name");
+
+        _vmSnapshotMax = NumbersUtil.parseInt(
+                _configDao.getValue("vmsnapshot.max"), VMSNAPSHOTMAX);
+
+        _stateMachine = VirtualMachine.State.getStateMachine();
+
+        String workers = configs.get("vmsnapshot.expunge.workers");
+        int wrks = NumbersUtil.parseInt(workers, 10);
+        _executor = Executors.newScheduledThreadPool(wrks,
+                new NamedThreadFactory("VMSnapshotManager-Scavenger"));
+
+        String time = configs.get("vmsnapshot.expunge.interval");
+        _snapshotCleanupInterval = NumbersUtil.parseInt(time, 86400);
+
+        return true;
+    }
+
+    @Override
+    public boolean start() {
+        Random generator = new Random();
+        int initialDelay = generator.nextInt(_snapshotCleanupInterval);
+        _executor.scheduleWithFixedDelay(new VMSnapshotGarbageCollector(),
+                initialDelay, _snapshotCleanupInterval, TimeUnit.SECONDS);
+        return true;
+    }
+
+    @Override
+    public boolean stop() {
+        return true;
+    }
+
+    @Override
+    public List<VMSnapshotVO> listVMSnapshots(ListVmSnapshotCmd cmd) {
+        Account caller = UserContext.current().getCaller();
+        List<Long> permittedAccounts = new ArrayList<Long>();
+
+        boolean listAll = cmd.listAll();
+        Long id = cmd.getId();
+        Long vmId = cmd.getVmId();
+        String state = cmd.getState();
+        String keyword = cmd.getKeyword();
+        String name = cmd.getVmSnapshotName();
+        String accountName = cmd.getAccountName();
+
+        Ternary<Long, Boolean, ListProjectResourcesCriteria> 
domainIdRecursiveListProject = new Ternary<Long, Boolean, 
ListProjectResourcesCriteria>(
+                cmd.getDomainId(), cmd.isRecursive(), null);
+        _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(),
+                cmd.getProjectId(), permittedAccounts,
+                domainIdRecursiveListProject, listAll, false);
+        Long domainId = domainIdRecursiveListProject.first();
+        Boolean isRecursive = domainIdRecursiveListProject.second();
+        ListProjectResourcesCriteria listProjectResourcesCriteria = 
domainIdRecursiveListProject
+                .third();
+
+        Filter searchFilter = new Filter(VMSnapshotVO.class, "created", false,
+                cmd.getStartIndex(), cmd.getPageSizeVal());
+        SearchBuilder<VMSnapshotVO> sb = _vmSnapshotDao.createSearchBuilder();
+        _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive,
+                permittedAccounts, listProjectResourcesCriteria);
+
+        sb.and("vm_id", sb.entity().getvmId(), SearchCriteria.Op.EQ);
+        sb.and("domain_id", sb.entity().getDomainId(), SearchCriteria.Op.EQ);
+        sb.and("status", sb.entity().getState(), SearchCriteria.Op.IN);
+        sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ);
+        sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
+        sb.and("display_name", sb.entity().getDisplayName(),
+                SearchCriteria.Op.EQ);
+        sb.and("account_id", sb.entity().getAccountId(), SearchCriteria.Op.EQ);
+        sb.done();
+
+        SearchCriteria<VMSnapshotVO> sc = sb.create();
+        _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive,
+                permittedAccounts, listProjectResourcesCriteria);
+
+        if (accountName != null && cmd.getDomainId() != null) {
+            Account account = _accountMgr.getActiveAccountByName(accountName,
+                    cmd.getDomainId());
+            sc.setParameters("account_id", account.getId());
+        }
+
+        if (vmId != null) {
+            sc.setParameters("vm_id", vmId);
+        }
+
+        if (domainId != null) {
+            sc.setParameters("domain_id", domainId);
+        }
+
+        if (state == null) {
+            VMSnapshot.Status[] status = { VMSnapshot.Status.Created,
+                    VMSnapshot.Status.Creating, VMSnapshot.Status.Error,
+                    VMSnapshot.Status.Expunging };
+            sc.setParameters("status", (Object[]) status);
+        } else {
+            sc.setParameters("state", state);
+        }
+
+        if (name != null) {
+            sc.setParameters("display_name", name);
+        }
+
+        if (keyword != null) {
+            SearchCriteria<VMSnapshotVO> ssc = _vmSnapshotDao
+                    .createSearchCriteria();
+            ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
+            ssc.addOr("display_name", SearchCriteria.Op.LIKE, "%" + keyword
+                    + "%");
+            ssc.addOr("description", SearchCriteria.Op.LIKE, "%" + keyword
+                    + "%");
+            sc.addAnd("name", SearchCriteria.Op.SC, ssc);
+        }
+
+        if (id != null) {
+            sc.setParameters("id", id);
+        }
+
+        return _vmSnapshotDao.search(sc, searchFilter);
+    }
+
+    @Override
+    @DB
+    public VMSnapshot allocVMSnapshot(CreateVMSnapshotCmd cmd)
+            throws ResourceAllocationException {
+        Long vmId = cmd.getVmId();
+        String vsDisplayName = cmd.getDisplayName();
+        String vsDescription = cmd.getDescription();
+        Boolean snapshotMemory = cmd.snapshotMemory();
+
+        Account caller = UserContext.current().getCaller();
+        final Transaction txn = Transaction.currentTxn();
+
+        VMInstanceVO vmInstanceVo = _vmInstanceDao.findById(vmId);
+        if (vmInstanceVo == null) {
+            throw new InvalidParameterValueException(
+                    "Creating vm snapshot failed due to vm:" + vmId
+                            + " doesn't exist");
+        }
+
+        UserVmVO userVmVo = _userVMDao.findById(vmId);
+        if (userVmVo == null) {
+            throw new InvalidParameterValueException(
+                    "Creating vm snapshot failed due to vm:" + vmId
+                            + " is system vm");
+        }
+
+        if (vmInstanceVo.getState() != VirtualMachine.State.Running
+                && vmInstanceVo.getState() != VirtualMachine.State.Stopped) {
+            throw new InvalidParameterValueException(
+                    "Creating vm snapshot failed due to vm:" + vmId
+                            + " is not in the running or Stopped state");
+        }
+
+        _accountMgr.checkAccess(caller, null, true, vmInstanceVo);
+
+        if (_vmSnapshotDao.findByVm(vmId).size() >= _vmSnapshotMax) {
+            throw new InvalidParameterValueException(
+                    "Creating vm snapshot failed due to a vm can just have : "
+                            + _vmSnapshotMax
+                            + " snapshots. Please delete old ones");
+        }
+
+        List<VolumeVO> listVolumes = _volumeDao.findByInstance(vmId);
+        for (VolumeVO volume : listVolumes) {
+            List<SnapshotVO> activeSnapshots = _snapshotDao
+                    .listByInstanceId(volume.getInstanceId(),
+                            Snapshot.Status.Creating,
+                            Snapshot.Status.CreatedOnPrimary,
+                            Snapshot.Status.BackingUp);
+            if (activeSnapshots.size() > 0) {
+                throw new CloudRuntimeException(
+                        "There is other active volume snapshot tasks on the 
instance to which the volume is attached, please try again later.");
+            }
+        }
+
+        List<VMSnapshotVO> activeVMSnapshots = _vmSnapshotDao.listByInstanceId(
+                vmId, VMSnapshot.Status.Creating);
+        if (activeVMSnapshots.size() > 1) {
+            throw new CloudRuntimeException(
+                    "There is other active vm snapshot tasks on the instance 
to which the volume is attached, please try again later");
+        }
+        try {
+            if (vmInstanceVo.getState() == VirtualMachine.State.Stopped) {
+                snapshotMemory = false;
+            }
+            String timeString = DateUtil
+                    .getDateDisplayString(DateUtil.GMT_TIMEZONE, new Date(),
+                            DateUtil.YYYYMMDD_FORMAT);
+            String vmSnapshotName = vmInstanceVo.getInstanceName()
+                    + "_Snapshot_" + timeString;
+            if (vsDisplayName == null) {
+                vsDisplayName = vmSnapshotName;
+            }
+
+            txn.start();
+
+            VMSnapshotVO vmSnapshotVo = new VMSnapshotVO(
+                    vmInstanceVo.getAccountId(), vmInstanceVo.getDomainId(),
+                    vmId, vsDescription, vmSnapshotName, vsDisplayName,
+                    vmInstanceVo.getServiceOfferingId(), snapshotMemory);
+            VMSnapshot vmSnapshot = _vmSnapshotDao.persist(vmSnapshotVo);
+            if (vmSnapshot == null) {
+                throw new CloudRuntimeException(
+                        "Failed to create snapshot for vm: " + vmId);
+            }
+            List<VolumeVO> volumes = _volumeDao.findByInstance(vmId);
+            for (VolumeVO volume : volumes) {
+                VMSnapshotVolumeVO vmSnapshotVolumeVo = new VMSnapshotVolumeVO(
+                        vmSnapshot.getId(), volume.getVolumeType(),
+                        volume.getId());
+                _vmSnapshotVolumeDao.persist(vmSnapshotVolumeVo);
+            }
+            txn.commit();
+            return vmSnapshot;
+        } catch (Exception e) {
+            String msg = e.getMessage();
+            s_logger.error("create vm snapshot record failed for vm: " + vmId
+                    + " due to " + msg);
+            txn.rollback();
+        } finally {
+            txn.close();
+        }
+
+        return null;
+    }
+
+    @Override
+    public String getName() {
+        return _name;
+    }
+
+    @Override
+    @DB
+    @ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_CREATE, 
eventDescription = "creating_vm_snapshot", async = true)
+    public VMSnapshot creatVMSnapshot(CreateVMSnapshotCmd cmd) {
+        Long vmId = cmd.getVmId();
+        VMInstanceVO vmInstanceVo = _vmInstanceDao.findById(vmId);
+        VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(cmd.getEntityId());
+        CreateVMSnapshotAnswer answer = null;
+        Boolean snapshotMemory = cmd.snapshotMemory();
+
+        try {
+            Long hostId = pickRunningHost(vmId);
+            List<VMSnapshotVolumeVO> snapshotVolumeList = _vmSnapshotVolumeDao
+                    .findByVMSnapshot(vmSnapshot.getId());
+            List<VMSnapshotVolumeTO> snapshotVolumeTos = new 
ArrayList<VMSnapshotVolumeTO>();
+            GuestOSVO guestOS = _guestOsDao.findById(vmInstanceVo
+                    .getGuestOSId());
+            for (VMSnapshotVolumeVO snapshotVolume : snapshotVolumeList) {
+                VolumeVO volume = _volumeDao.findById(snapshotVolume
+                        .getSnapshotOf());
+                VMSnapshotVolumeTO snapshotVolumeTo = new VMSnapshotVolumeTO(
+                        snapshotVolume.getId(), volume.getPath(),
+                        volume.getDeviceId());
+                snapshotVolumeTos.add(snapshotVolumeTo);
+            }
+            CreateVMSnapshotCommand ccmd = new CreateVMSnapshotCommand(
+                    vmInstanceVo.getInstanceName(), vmSnapshot.getName(),
+                    vmSnapshot.getDescription(), snapshotVolumeTos,
+                    snapshotMemory, vmInstanceVo.getState(),
+                    guestOS.getDisplayName());
+            answer = (CreateVMSnapshotAnswer) sendToPool(hostId, ccmd);
+            if (answer != null && answer.getResult()) {
+                processAnswer(vmSnapshot, answer);
+            }
+        } catch (Exception e) {
+            String msg = e.getMessage();
+            s_logger.error("create vm snapshot failed for vm: " + vmId
+                    + " due to " + msg);
+            throw new CloudRuntimeException(msg);
+        } finally {
+            if (answer == null || answer.getResult() == false
+                    || vmSnapshot.getState() != VMSnapshot.Status.Created) {
+                vmSnapshot.setState(VMSnapshot.Status.Error);
+                _vmSnapshotDao.persist(vmSnapshot);
+                List<VMSnapshotVolumeVO> listVolumes = _vmSnapshotVolumeDao
+                        .findByVMSnapshot(vmSnapshot.getId());
+                for (VMSnapshotVolumeVO volume : listVolumes) {
+                    _vmSnapshotVolumeDao.remove(volume.getId());
+                }
+            }
+        }
+        return vmSnapshot;
+    }
+
+    @DB
+    private void processAnswer(VMSnapshotVO vmSnapshot, Answer as) {
+        final Transaction txn = Transaction.currentTxn();
+        try {
+            txn.start();
+            if (as instanceof CreateVMSnapshotAnswer) {
+                CreateVMSnapshotAnswer answer = (CreateVMSnapshotAnswer) as;
+                List<VMSnapshotVolumeTO> snapshotVolumeToList = answer
+                        .getSnapshotVolumeTos();
+                String snapshotUUID = answer.getSnapshotUUID();
+                for (VMSnapshotVolumeTO snapshotVolumeTo : 
snapshotVolumeToList) {
+                    VMSnapshotVolumeVO vsvolume = _vmSnapshotVolumeDao
+                            .findById(snapshotVolumeTo.getSnapshotVolumeId());
+                    vsvolume.setVolumePath(snapshotVolumeTo
+                            .getSnapshotVolumePath());
+                    _vmSnapshotVolumeDao.persist(vsvolume);
+                }
+                updateVolumePath(snapshotVolumeToList);
+                vmSnapshot.setSnapshotUUID(snapshotUUID);
+                vmSnapshot.setState(VMSnapshot.Status.Created);
+                _vmSnapshotDao.persist(vmSnapshot);
+            } else if (as instanceof RevertToSnapshotAnswer) {
+                RevertToSnapshotAnswer answer = (RevertToSnapshotAnswer) as;
+                List<VMSnapshotVolumeTO> snapshotVolumeToList = answer
+                        .getSnapshotVolumeTos();
+                updateVolumePath(snapshotVolumeToList);
+                VMSnapshotVolumeTO snapshotVolumeTo = snapshotVolumeToList
+                        .iterator().next();
+                Long snapshotVolumeId = snapshotVolumeTo.getSnapshotVolumeId();
+                VMSnapshotVolumeVO snapshotVolume = _vmSnapshotVolumeDao
+                        .findById(snapshotVolumeId);
+                VolumeVO volume = _volumeDao.findById(snapshotVolume
+                        .getSnapshotOf());
+                VMInstanceVO vm = _vmInstanceDao.findById(volume
+                        .getInstanceId());
+                vm.setState(answer.getVmState());
+                _vmInstanceDao.persist(vm);
+            } else if (as instanceof DeleteVMSnapshotAnswer) {
+                DeleteVMSnapshotAnswer answer = (DeleteVMSnapshotAnswer) as;
+                List<VMSnapshotVolumeVO> snapshotVolumeVoList = 
_vmSnapshotVolumeDao
+                        .findByVMSnapshot(vmSnapshot.getId());
+                List<VMSnapshotVolumeTO> snapshotVolumeToList = answer
+                        .getSnapshotVolumeTos();
+                if (snapshotVolumeToList != null
+                        && snapshotVolumeToList.size() > 0) {
+                    updateVolumePath(snapshotVolumeToList);
+                    for (VMSnapshotVolumeVO snapshotVolumeVo : 
snapshotVolumeVoList) {
+                        _vmSnapshotVolumeDao.remove(snapshotVolumeVo.getId());
+                    }
+                }
+                _vmSnapshotDao.remove(vmSnapshot.getId());
+            }
+            txn.commit();
+        } catch (Exception e) {
+            s_logger.error("error while process answer: " + as.getClass()
+                    + " due to " + e.getMessage(), e);
+            txn.rollback();
+        } finally {
+            txn.close();
+        }
+    }
+
+    private void updateVolumePath(List<VMSnapshotVolumeTO> 
snapshotVolumeToList) {
+        for (VMSnapshotVolumeTO snapshotVolumeTo : snapshotVolumeToList) {
+            if (snapshotVolumeTo.getNewVolumePath() != null) {
+                VMSnapshotVolumeVO snapshotVolumeVo = _vmSnapshotVolumeDao
+                        .findById(snapshotVolumeTo.getSnapshotVolumeId());
+                VolumeVO volume = _volumeDao.findById(snapshotVolumeVo
+                        .getSnapshotOf());
+                volume.setPath(snapshotVolumeTo.getNewVolumePath());
+                _volumeDao.persist(volume);
+            }
+        }
+    }
+
+    private Answer sendToPool(Long hostId, Command cmd)
+            throws AgentUnavailableException, OperationTimedoutException {
+        long targetHostId = _hvGuruMgr.getGuruProcessedCommandTargetHost(
+                hostId, cmd);
+        Answer answer = _agentMgr.send(targetHostId, cmd);
+        return answer;
+    }
+
+    @Override
+    @DB
+    @ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_DELETE, 
eventDescription = "delete_vm_snapshot", async = true)
+    public boolean deleteVMSnapshot(DeleteVMSnapshotCmd cmd) {
+        Long vmSnapshotId = cmd.getVmSnapShotId();
+        Account caller = UserContext.current().getCaller();
+
+        VMSnapshot vmSnapshotCheck = _vmSnapshotDao.findById(vmSnapshotId);
+        if (vmSnapshotCheck == null) {
+            throw new InvalidParameterValueException(
+                    "unable to find the vm snapshot with id " + vmSnapshotId);
+        }
+
+        _accountMgr.checkAccess(caller, null, true, vmSnapshotCheck);
+
+        if (VMSnapshot.Status.Created != vmSnapshotCheck.getState()
+                && VMSnapshot.Status.Error != vmSnapshotCheck.getState()) {
+            throw new InvalidParameterValueException(
+                    "Can't delete the vm snapshotshot " + vmSnapshotId
+                            + " due to it is not in Created or Error Status");
+        }
+
+        VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(vmSnapshotId);
+        vmSnapshot.setState(VMSnapshot.Status.Expunging);
+        _vmSnapshotDao.persist(vmSnapshot);
+
+        return true;
+    }
+
+    @DB
+    protected boolean deleteSnapshotInternal(Long vmId, Long vmSnapshotId) {
+        VMInstanceVO vmInstanceVo = _vmInstanceDao.findById(vmId);
+        VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(vmSnapshotId);
+        try {
+            Long hostId = pickRunningHost(vmId);
+            String snapshotUUID = vmSnapshot.getSnapshotUUID();
+            if (snapshotUUID == null) {
+                s_logger.warn("snapshotUUID is null, mark as removed");
+                _vmSnapshotDao.remove(vmSnapshotId);
+                return true;
+            }
+
+            List<VMSnapshotVolumeVO> listSnapshotVolume = _vmSnapshotVolumeDao
+                    .findByVMSnapshot(vmSnapshotId);
+            List<VMSnapshotVolumeTO> listSnapshotVolumeTo = new 
ArrayList<VMSnapshotVolumeTO>();
+            for (VMSnapshotVolumeVO snapshotVolume : listSnapshotVolume) {
+                VolumeVO volume = _volumeDao.findById(snapshotVolume
+                        .getSnapshotOf());
+                VMSnapshotVolumeTO vTo = new VMSnapshotVolumeTO(
+                        snapshotVolume.getId(), volume.getPath(),
+                        snapshotVolume.getVolumePath());
+                listSnapshotVolumeTo.add(vTo);
+            }
+            DeleteVMSnapshotCommand ccmd = new DeleteVMSnapshotCommand(
+                    vmInstanceVo.getInstanceName(), vmSnapshot.getName(),
+                    snapshotUUID, listSnapshotVolumeTo);
+            DeleteVMSnapshotAnswer answer = (DeleteVMSnapshotAnswer) 
sendToPool(
+                    hostId, ccmd);
+            if (answer.getResult()) {
+                processAnswer(vmSnapshot, answer);
+            } else {
+                s_logger.error("delete vm snapshot " + vmSnapshotId + " of vm "
+                        + vmId + " failed due to " + answer.getDetails());
+                return false;
+            }
+        } catch (Exception e) {
+            String msg = e.getMessage();
+            s_logger.error("delete vm snapshot " + vmSnapshotId + " of vm "
+                    + vmId + " failed due to " + msg);
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    @DB
+    @ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_REVERT, 
eventDescription = "revert_vm", async = true)
+    public UserVm revertToSnapshot(RevertToSnapshotCmd cmd) {
+        // TODO: timeout
+        Long vmId = cmd.getVmId();
+        Long vmSnapshotId = cmd.getVmSnapShotId();
+
+        Account caller = UserContext.current().getCaller();
+
+        // VMInstanceVO vmInstanceVo = _vmInstanceDao.findById(vmId);
+        UserVmVO userVm = _userVMDao.findById(vmId);
+
+        if (userVm == null) {
+            throw new InvalidParameterValueException("Revert vm to snapshot: "
+                    + vmSnapshotId + " failed due to vm: " + vmId
+                    + " is not found");
+        }
+
+        VMSnapshotVO vmSnapshotVo = _vmSnapshotDao.findById(vmSnapshotId);
+        if (vmSnapshotVo == null) {
+            throw new InvalidParameterValueException(
+                    "unable to find the vm snapshot with id " + vmSnapshotId);
+        }
+
+        if (userVm.getState() != VirtualMachine.State.Running
+                && userVm.getState() != VirtualMachine.State.Stopped) {
+            throw new InvalidParameterValueException(
+                    "VM Snapshot reverting failed due to vm is not in the 
state of Running or Stopped.");
+        }
+
+        if (vmSnapshotVo.getState() != VMSnapshot.Status.Created) {
+            throw new InvalidParameterValueException(
+                    "VM Snapshot reverting failed due to vm snapshot is not in 
the state of Created.");
+        }
+
+        _accountMgr.checkAccess(caller, null, true, vmSnapshotVo);
+
+        List<VMSnapshotVolumeVO> listvsVolumes = _vmSnapshotVolumeDao
+                .findByVMSnapshot(vmSnapshotId);
+        List<VMSnapshotVolumeTO> listVolumeTo = new 
ArrayList<VMSnapshotVolumeTO>();
+
+        Long hostId = pickRunningHost(vmId);
+        boolean reverted = false;
+
+        try {
+            stateTransitTo(userVm, Event.RevertingRequested, hostId, null);
+
+            VMSnapshotVO snapshot = _vmSnapshotDao.findById(vmSnapshotId);
+            for (VMSnapshotVolumeVO snapshotVolume : listvsVolumes) {
+                VolumeVO volume = _volumeDao.findById(snapshotVolume
+                        .getSnapshotOf());
+                VMSnapshotVolumeTO volumeTo = new VMSnapshotVolumeTO(
+                        snapshotVolume.getId(), volume.getPath(),
+                        snapshotVolume.getVolumePath(), volume.getVolumeType(),
+                        volume.getDeviceId());
+                listVolumeTo.add(volumeTo);
+            }
+            String vmInstanceName = userVm.getInstanceName();
+            String vmSnapshotName = vmSnapshotVo.getName();
+            RevertToSnapshotCommand ccmd = new RevertToSnapshotCommand(
+                    vmInstanceName, vmSnapshotName,
+                    vmSnapshotVo.getSnapshotUUID(), listVolumeTo,
+                    snapshot.memory());
+            RevertToSnapshotAnswer answer = (RevertToSnapshotAnswer) 
sendToPool(
+                    hostId, ccmd);
+            if (answer.getResult()) {
+                processAnswer(vmSnapshotVo, answer);
+                reverted = true;
+                stateTransitTo(userVm, Event.OperationSucceeded, hostId, null);
+            } else {
+                reverted = false;
+            }
+        } catch (Exception e) {
+            s_logger.error("revert vm: " + vmId + " to snapshot "
+                    + vmSnapshotId + " failed due to " + e.getMessage(), e);
+            reverted = false;
+        } finally {
+            if (!reverted) {
+                try {
+                    s_logger.error("Revert VM: " + vmId + " to snapshot:"
+                            + vmSnapshotId + "failed. Try to stop vm.");
+                    StopCommand scmd = new 
StopCommand(userVm.getInstanceName());
+                    StopAnswer sanswer = (StopAnswer) sendToPool(hostId, scmd);
+                    if (sanswer == null || !sanswer.getResult()) {
+                        s_logger.warn("Unable to stop "
+                                + userVm
+                                + " due to "
+                                + (sanswer != null ? sanswer.getDetails()
+                                        : "no answers"));
+                        _haMgr.scheduleStop(userVm, hostId, 
WorkType.ForceStop);
+                        throw new ExecutionException(
+                                "Unable to stop "
+                                        + userVm
+                                        + "so we are unable to retry the start 
operation ");
+                    }
+                    stateTransitTo(userVm, Event.OperationFailed, hostId, 
null);
+                } catch (Exception e) {
+                    s_logger.error(
+                            "failed to stop vm after reverting failed due to "
+                                    + e.getMessage(), e);
+                }
+            }
+        }
+        return userVm;
+    }
+
+    protected boolean stateTransitTo(VMInstanceVO vm, VirtualMachine.Event e,
+            Long hostId, String reservationId) throws NoTransitionException {
+        vm.setReservationId(reservationId);
+        return _stateMachine.transitTo(vm, e,
+                new Pair<Long, Long>(vm.getHostId(), hostId), _vmInstanceDao);
+    }
+
+    @Override
+    public VMSnapshot getVMSnapshotById(long id) {
+        VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(id);
+        return vmSnapshot;
+    }
+
+    public String getChecksum(Long hostId, String templatePath) {
+        HostVO ssHost = _hostDao.findById(hostId);
+        Host.Type type = ssHost.getType();
+        if (type != Host.Type.SecondaryStorage
+                && type != Host.Type.LocalSecondaryStorage) {
+            return null;
+        }
+        String secUrl = ssHost.getStorageUrl();
+        Answer answer;
+        answer = _agentMgr.sendToSecStorage(ssHost, new ComputeChecksumCommand(
+                secUrl, templatePath));
+        if (answer != null && answer.getResult()) {
+            return answer.getDetails();
+        }
+        return null;
+    }
+
+    private Long pickRunningHost(Long vmId) {
+        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) {
+        VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(id);
+        Long vmId = vmSnapshot.getvmId();
+        UserVmVO vm = _vmDao.findById(vmId);
+        return vm;
+    }
+
+    @Override
+    public boolean deleteAllVMSnapshots(long vmId) {
+        boolean result = true;
+        List<VMSnapshotVO> listVmSnapshots = _vmSnapshotDao.findByVm(vmId);
+        if (listVmSnapshots == null || listVmSnapshots.isEmpty()) {
+            return true;
+        }
+        for (VMSnapshotVO snapshot : listVmSnapshots) {
+            if (!deleteSnapshotInternal(vmId, snapshot.getId())) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    protected class VMSnapshotGarbageCollector implements Runnable {
+
+        public VMSnapshotGarbageCollector() {
+        }
+
+        @Override
+        public void run() {
+            try {
+                s_logger.trace("VM Snapshot Garbage Collection Thread is 
running.");
+
+                cleanupVMSnapshot(true);
+
+            } catch (Exception e) {
+                s_logger.error("Caught the following Exception", e);
+            }
+        }
+    }
+
+    public void cleanupVMSnapshot(boolean recurring) {
+        s_logger.debug("cleaning up expunging vm snapshot");
+        GlobalLock scanLock = 
GlobalLock.getInternLock("vmsnapshotmgr.cleanup");
+
+        try {
+            if (scanLock.lock(3)) {
+                try {
+                    List<VMSnapshotVO> expungingVMSnapshots = _vmSnapshotDao
+                            .listExpungingSnapshot();
+                    for (VMSnapshotVO vmSnapshot : expungingVMSnapshots) {
+                        Long vmId = vmSnapshot.getvmId();
+                        Long vmSnapshotId = vmSnapshot.getId();
+                        if (!deleteSnapshotInternal(vmId, vmSnapshotId)) {
+                            s_logger.error("delete snapshot: " + vmSnapshotId
+                                    + " of vm: " + vmId + " failed");
+                        }
+                    }
+                } finally {
+                    scanLock.unlock();
+                }
+            }
+        } finally {
+            scanLock.releaseRef();
+        }
+    }
+
+    public void syncVolumePath(Long hostId) {
+        s_logger.warn("begin to sync volume path");
+        HostVO hostVo = _hostDao.findById(hostId);
+        ClusterVO clusterVo = _clusterDao.findById(hostVo.getClusterId());
+        List<VMInstanceVO> vmList = _vmInstanceDao.listLHByClusterId(clusterVo
+                .getId());
+        Map<String, Map<String, VolumeTO>> vmVolumesMap = new HashMap<String, 
Map<String, VolumeTO>>();
+        for (VMInstanceVO vm : vmList) {
+            if (VirtualMachine.State.Destroyed != vm.getState()
+                    && VirtualMachine.State.Error != vm.getState()
+                    && VirtualMachine.State.Expunging != vm.getState()) {
+                List<VolumeVO> volumeList = _volumeDao.findByInstance(vm
+                        .getId());
+                Map<String, VolumeTO> volumeMap = new HashMap<String, 
VolumeTO>();
+                for (VolumeVO volume : volumeList) {
+                    StoragePoolVO storagePool = _storagePoolDao.findById(volume
+                            .getPoolId());
+                    String key = null;
+                    if (vm.getHypervisorType() == HypervisorType.XenServer) {
+                        key = volume.getDeviceId().toString();
+                    } else if (vm.getHypervisorType() == 
HypervisorType.VMware) {
+                        key = volume.getName();
+                    }
+                    volumeMap.put(key, new VolumeTO(volume, storagePool));
+                }
+                vmVolumesMap.put(vm.getInstanceName(), volumeMap);
+            }
+        }
+        try {
+            GetVolumesChangedCommand ccmd = new GetVolumesChangedCommand(
+                    vmVolumesMap);
+            GetVolumesChangedAnswer answer = (GetVolumesChangedAnswer) 
sendToPool(
+                    hostId, ccmd);
+            if (answer.getResult()) {
+                List<VolumeTO> resultVolumeToList = answer.getVmVolumesMap();
+                for (VolumeTO volumeTo : resultVolumeToList) {
+                    VolumeVO volumeVo = _volumeDao.findById(volumeTo.getId());
+                    volumeVo.setPath(volumeTo.getPath());
+                    _volumeDao.persist(volumeVo);
+                }
+            }
+        } catch (AgentUnavailableException e) {
+            String msg = e.getMessage();
+            s_logger.error("sync volume path failed due to " + msg);
+        } catch (OperationTimedoutException e) {
+            String msg = e.getMessage();
+            s_logger.error("sync volume path failed due to " + msg);
+            ;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/3a60d5e1/server/src/com/cloud/vm/snapshot/dao/VMSnapshotDao.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/snapshot/dao/VMSnapshotDao.java 
b/server/src/com/cloud/vm/snapshot/dao/VMSnapshotDao.java
new file mode 100644
index 0000000..5632763
--- /dev/null
+++ b/server/src/com/cloud/vm/snapshot/dao/VMSnapshotDao.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.snapshot.dao;
+
+import java.util.List;
+
+import com.cloud.utils.db.GenericDao;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+import com.cloud.vm.snapshot.VMSnapshot.Status;
+
+public interface VMSnapshotDao extends GenericDao<VMSnapshotVO, Long> {
+
+    List<VMSnapshotVO> findByVm(Long vmId);
+
+    List<VMSnapshotVO> listExpungingSnapshot();
+
+    List<VMSnapshotVO> listByInstanceId(Long vmId, Status... status);
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/3a60d5e1/server/src/com/cloud/vm/snapshot/dao/VMSnapshotDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/snapshot/dao/VMSnapshotDaoImpl.java 
b/server/src/com/cloud/vm/snapshot/dao/VMSnapshotDaoImpl.java
new file mode 100644
index 0000000..fe729f2
--- /dev/null
+++ b/server/src/com/cloud/vm/snapshot/dao/VMSnapshotDaoImpl.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.dao;
+
+import java.util.List;
+
+import javax.ejb.Local;
+
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.vm.snapshot.VMSnapshot.Status;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+
+@Local(value = { VMSnapshotDao.class })
+public class VMSnapshotDaoImpl extends GenericDaoBase<VMSnapshotVO, Long>
+        implements VMSnapshotDao {
+
+    private final SearchBuilder<VMSnapshotVO> SnapshotSearch;
+    private final SearchBuilder<VMSnapshotVO> ExpungingSnapshotSearch;
+    private final SearchBuilder<VMSnapshotVO> SnapshotStatusSearch;
+
+    protected VMSnapshotDaoImpl() {
+        SnapshotSearch = createSearchBuilder();
+        SnapshotSearch.and("vm_id", SnapshotSearch.entity().getvmId(),
+                SearchCriteria.Op.EQ);
+        SnapshotSearch.done();
+
+        ExpungingSnapshotSearch = createSearchBuilder();
+        ExpungingSnapshotSearch.and("state", ExpungingSnapshotSearch.entity()
+                .getState(), SearchCriteria.Op.EQ);
+        ExpungingSnapshotSearch.and("removed", ExpungingSnapshotSearch.entity()
+                .getRemoved(), SearchCriteria.Op.NULL);
+        ExpungingSnapshotSearch.done();
+
+        SnapshotStatusSearch = createSearchBuilder();
+        SnapshotStatusSearch.and("vm_id", SnapshotStatusSearch.entity()
+                .getvmId(), SearchCriteria.Op.EQ);
+        SnapshotStatusSearch.and("state", SnapshotStatusSearch.entity()
+                .getState(), SearchCriteria.Op.IN);
+        SnapshotStatusSearch.done();
+    }
+
+    @Override
+    public List<VMSnapshotVO> findByVm(Long vmId) {
+        SearchCriteria<VMSnapshotVO> sc = SnapshotSearch.create();
+        sc.setParameters("vm_id", vmId);
+        return listBy(sc, null);
+    }
+
+    @Override
+    public List<VMSnapshotVO> listExpungingSnapshot() {
+        SearchCriteria<VMSnapshotVO> sc = ExpungingSnapshotSearch.create();
+        sc.setParameters("state", Status.Expunging);
+        return listBy(sc, null);
+    }
+
+    @Override
+    public List<VMSnapshotVO> listByInstanceId(Long vmId, Status... status) {
+        SearchCriteria<VMSnapshotVO> sc = SnapshotStatusSearch.create();
+        sc.setParameters("vm_id", vmId);
+        sc.setParameters("state", (Object[]) status);
+        return listBy(sc, null);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/3a60d5e1/server/src/com/cloud/vm/snapshot/dao/VMSnapshotVolumeDao.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/snapshot/dao/VMSnapshotVolumeDao.java 
b/server/src/com/cloud/vm/snapshot/dao/VMSnapshotVolumeDao.java
new file mode 100644
index 0000000..e3fbc3f
--- /dev/null
+++ b/server/src/com/cloud/vm/snapshot/dao/VMSnapshotVolumeDao.java
@@ -0,0 +1,30 @@
+// 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 java.util.List;
+
+import com.cloud.utils.db.GenericDao;
+import com.cloud.vm.snapshot.VMSnapshotVolumeVO;
+
+public interface VMSnapshotVolumeDao extends
+        GenericDao<VMSnapshotVolumeVO, Long> {
+    List<VMSnapshotVolumeVO> findByVMSnapshot(Long vmSnapshotId);
+
+    VMSnapshotVolumeVO findRootByVMSnapshot(Long vmSnapshotId);
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/3a60d5e1/server/src/com/cloud/vm/snapshot/dao/VMSnapshotVolumeDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/snapshot/dao/VMSnapshotVolumeDaoImpl.java 
b/server/src/com/cloud/vm/snapshot/dao/VMSnapshotVolumeDaoImpl.java
new file mode 100644
index 0000000..f6765d2
--- /dev/null
+++ b/server/src/com/cloud/vm/snapshot/dao/VMSnapshotVolumeDaoImpl.java
@@ -0,0 +1,65 @@
+// 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 java.util.List;
+
+import javax.ejb.Local;
+
+import com.cloud.storage.Volume;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.vm.snapshot.VMSnapshotVolumeVO;
+
+@Local(value = { VMSnapshotVolumeDao.class })
+public class VMSnapshotVolumeDaoImpl extends
+        GenericDaoBase<VMSnapshotVolumeVO, Long> implements 
VMSnapshotVolumeDao {
+
+    private final SearchBuilder<VMSnapshotVolumeVO> SnapshotIdSearch;
+    private final SearchBuilder<VMSnapshotVolumeVO> RootSnapshotIdSearch;
+
+    @Override
+    public List<VMSnapshotVolumeVO> findByVMSnapshot(Long vmSnapshotId) {
+        SearchCriteria<VMSnapshotVolumeVO> sc = SnapshotIdSearch.create();
+        sc.setParameters("vm_snapshot_id", vmSnapshotId);
+        return listBy(sc, null);
+    }
+
+    protected VMSnapshotVolumeDaoImpl() {
+        SnapshotIdSearch = createSearchBuilder();
+        SnapshotIdSearch.and("vm_snapshot_id", SnapshotIdSearch.entity()
+                .getVmSnapshotId(), SearchCriteria.Op.EQ);
+        SnapshotIdSearch.done();
+
+        RootSnapshotIdSearch = createSearchBuilder();
+        RootSnapshotIdSearch.and("vm_snapshot_id", RootSnapshotIdSearch
+                .entity().getVmSnapshotId(), SearchCriteria.Op.EQ);
+        RootSnapshotIdSearch.and("volume_type", RootSnapshotIdSearch.entity()
+                .getVolumeType(), SearchCriteria.Op.EQ);
+        RootSnapshotIdSearch.done();
+    }
+
+    @Override
+    public VMSnapshotVolumeVO findRootByVMSnapshot(Long vmSnapshotId) {
+        SearchCriteria<VMSnapshotVolumeVO> sc = RootSnapshotIdSearch.create();
+        sc.setParameters("vm_snapshot_id", vmSnapshotId);
+        sc.setParameters("volume_type", Volume.Type.ROOT);
+        return findOneBy(sc);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/3a60d5e1/ui/scripts/vm_snapshots.js
----------------------------------------------------------------------
diff --git a/ui/scripts/vm_snapshots.js b/ui/scripts/vm_snapshots.js
new file mode 100644
index 0000000..cec1e68
--- /dev/null
+++ b/ui/scripts/vm_snapshots.js
@@ -0,0 +1,192 @@
+// 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.
+(function($, cloudStack) {
+  cloudStack.sections.vmsnapshots = {
+    title: 'label.vmsnapshots',
+    id: 'vmsnapshots',
+    listView: {
+      id: 'vmsnapshots',
+      isMaximized: true,
+      fields: {
+        displayname: {
+          label: 'label.name'
+        },
+        created: {
+          label: 'label.date',
+          converter: cloudStack.converters.toLocalDate
+        },
+        state: {
+          label: 'label.state',
+          indicator: {
+            'Created': 'on',
+            'Error': 'off'
+          }
+        }
+      },
+
+      dataProvider: function(args) {
+        var apiCmd = "listVMSnapshot&listAll=true";
+        if (args.context != null) {
+          if ("instances" in args.context) {
+            apiCmd += "&vmid=" + args.context.instances[0].id;
+          }
+        }
+        $.ajax({
+          url: createURL(apiCmd),
+          dataType: "json",
+          async: true,
+          success: function(json) {
+            var jsonObj;
+            jsonObj = json.listvmsnapshotresponse.vmSnapshot;
+            args.response.success({
+              //actionFilter: vmActionfilter,
+              data: jsonObj
+            });
+          }
+        });
+      },
+      //dataProvider end
+      detailView: {
+        tabs: {
+          details: {
+            title: 'label.details',
+            fields: {
+              id: {
+                label: 'label.id'
+              },
+              name: {
+                label: 'label.name'
+              },
+              displayname: {
+                label: 'label.display.name',
+                isEditable: true
+              },
+              description: {
+                label: 'label.description',
+                isEditable: true
+              },
+              created: {
+                label: 'label.date',
+                converter: cloudStack.converters.toLocalDate
+              },
+              state: {
+                label: 'label.state',
+                indicator: {
+                  'Created': 'on',
+                  'Error': 'off'
+                }
+              }
+            },
+            dataProvider: function(args) {
+              $.ajax({
+                url: createURL("listVMSnapshot&id=" + 
args.context.vmsnapshots[0].id),
+                dataType: "json",
+                async: true,
+                success: function(json) {
+                  var jsonObj;
+                  jsonObj = json.listvmsnapshotresponse.vmSnapshot[0];
+                  args.response.success({
+                    //actionFilter: vmActionfilter,
+                    data: jsonObj
+                  });
+                }
+              });
+            },
+            //dateProvider end 
+          }
+        },
+        actions: {
+          //delete a snapshot
+          destroy: {
+            label: 'label.action.delete.snapshot',
+            messages: {
+              confirm: function(args) {
+                return 'message.action.delete.snapshot';
+              },
+              notification: function(args) {
+                return 'label.action.delete.snapshot';
+              }
+            },
+            action: function(args) {
+              $.ajax({
+                url: createURL("deleteVMSnapshot&vmsnapshotid=" + 
args.context.vmsnapshots[0].id),
+                dataType: "json",
+                async: true,
+                success: function(json) {
+                  var jid = json.deletevmsnapshotresponse.success;
+                  args.response.success({
+                    _custom: {
+                      jobId: jid
+                      //        getUpdatedItem: function(json) {
+                      //            return 
json.queryasyncjobresultresponse.jobresult.virtualmachine;
+                      //          }
+                    }
+                  });
+
+                }
+              });
+            },
+            notification: {
+              poll: function(args) {
+                args.complete();
+              }
+            }
+          },
+          restart: {
+            label: 'label.action.vmsnapshot.revert',
+            messages: {
+              confirm: function(args) {
+                return 'label.action.vmsnapshot.revert';
+              },
+              notification: function(args) {
+                return 'message.vmsnapshot.revert';
+              }
+            },
+            action: function(args) {
+              $.ajax({
+                url: createURL("revertToSnapshot&vmsnapshotid=" + 
args.context.vmsnapshots[0].id),
+                dataType: "json",
+                async: true,
+                success: function(json) {
+                  var jid = json.reverttosnapshotresponse.jobid;
+                  args.response.success({
+                    _custom: {
+                      jobId: jid
+                      //          getUpdatedItem: function(json) {
+                      //            return 
json.queryasyncjobresultresponse.jobresult;
+                      //          },
+                      //          getActionFilter: function() {
+                      //            return vmActionfilter;
+                      //          }
+                    }
+                  });
+                }
+              });
+
+            },
+            notification: {
+              poll: function(args) {
+                args.complete();
+              }
+            }
+          }
+        }
+      }
+      //detailview end
+    }
+  }
+})(jQuery, cloudStack);
\ No newline at end of file

Reply via email to