Return-Path: X-Original-To: apmail-cloudstack-commits-archive@www.apache.org Delivered-To: apmail-cloudstack-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id C473C10994 for ; Sat, 26 Oct 2013 01:24:56 +0000 (UTC) Received: (qmail 41722 invoked by uid 500); 26 Oct 2013 01:24:56 -0000 Delivered-To: apmail-cloudstack-commits-archive@cloudstack.apache.org Received: (qmail 41669 invoked by uid 500); 26 Oct 2013 01:24:56 -0000 Mailing-List: contact commits-help@cloudstack.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cloudstack.apache.org Delivered-To: mailing list commits@cloudstack.apache.org Received: (qmail 41552 invoked by uid 99); 26 Oct 2013 01:24:56 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 26 Oct 2013 01:24:56 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 107F681E9FC; Sat, 26 Oct 2013 01:24:55 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: edison@apache.org To: commits@cloudstack.apache.org Date: Sat, 26 Oct 2013 01:24:57 -0000 Message-Id: <7ab860dd35a74216b2b2e98e55150ea1@git.apache.org> In-Reply-To: <7f249840190b409498570e33c1832d50@git.apache.org> References: <7f249840190b409498570e33c1832d50@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [3/5] git commit: updated refs/heads/master to 465c9ec Merge branch 'pluggable_vm_snapshot' Conflicts: client/tomcatconf/applicationContext.xml.in engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java engine/storage/integration-test/test/resources/storageContext.xml server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/51a8086c Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/51a8086c Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/51a8086c Branch: refs/heads/master Commit: 51a8086cf6d1cdf7db3f89468e210020a179a57c Parents: 56f1277 a6ce66e Author: Edison Su Authored: Fri Oct 25 16:47:17 2013 -0700 Committer: Edison Su Committed: Fri Oct 25 16:47:17 2013 -0700 ---------------------------------------------------------------------- .../cloud/agent/api/CreateVMSnapshotAnswer.java | 12 +- .../agent/api/CreateVMSnapshotCommand.java | 4 +- .../cloud/agent/api/DeleteVMSnapshotAnswer.java | 12 +- .../agent/api/DeleteVMSnapshotCommand.java | 3 +- .../agent/api/RevertToVMSnapshotAnswer.java | 14 +- .../agent/api/RevertToVMSnapshotCommand.java | 3 +- .../cloud/agent/api/VMSnapshotBaseCommand.java | 10 +- .../cloudstack/storage/to/VolumeObjectTO.java | 12 + .../api/storage/VMSnapshotStrategy.java | 28 ++ .../cloud/vm/snapshot/VMSnapshotDetailsVO.java | 87 ++++ .../src/com/cloud/vm/snapshot/VMSnapshotVO.java | 2 +- .../vm/snapshot/dao/VMSnapshotDetailsDao.java | 28 ++ .../snapshot/dao/VMSnapshotDetailsDaoImpl.java | 52 +++ .../motion/AncientDataMotionStrategy.java | 26 -- .../vm/snapshot/dao/VmSnapshotDaoTest.java | 46 ++ .../storage/test/ChildTestConfiguration.java | 47 +- .../cloudstack/storage/test/SnapshotTest.java | 89 ++-- .../test/resources/storageContext.xml | 5 + engine/storage/snapshot/pom.xml | 32 ++ .../storage/snapshot/SnapshotServiceImpl.java | 44 +- .../snapshot/XenserverSnapshotStrategy.java | 27 +- .../vmsnapshot/DefaultVMSnapshotStrategy.java | 370 +++++++++++++++ .../storage/vmsnapshot/VMSnapshotHelper.java | 38 ++ .../vmsnapshot/VMSnapshotHelperImpl.java | 148 ++++++ .../test/src/VMSnapshotStrategyTest.java | 256 +++++++++++ .../storage/volume/VolumeServiceImpl.java | 85 ++-- .../manager/VmwareStorageManagerImpl.java | 87 ++-- .../xen/resource/CitrixResourceBase.java | 28 +- .../storage/snapshot/SnapshotManagerImpl.java | 93 ---- .../vm/snapshot/VMSnapshotManagerImpl.java | 455 +++---------------- .../vm/snapshot/VMSnapshotManagerTest.java | 7 - setup/db/db/schema-421to430.sql | 9 + 32 files changed, 1390 insertions(+), 769 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/51a8086c/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/51a8086c/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/ChildTestConfiguration.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/51a8086c/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java ---------------------------------------------------------------------- diff --cc engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java index 1407707,36bc912..550a6bf --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java @@@ -406,10 -399,13 +403,11 @@@ public class SnapshotTest extends Cloud SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotVO.getId(), vol.getDataStore()); boolean result = false; - StrategyPriority.sortStrategies(snapshotStrategies, snapshot); + - for (SnapshotStrategy strategy : this.snapshotStrategies) { - if (strategy.canHandle(snapshot) != StrategyPriority.Priority.CANT_HANDLE) { - snapshot = strategy.takeSnapshot(snapshot); - result = true; - } + SnapshotStrategy snapshotStrategy = storageStrategyFactory.getSnapshotStrategy(snapshot, SnapshotOperation.TAKE); + if (snapshotStrategy != null) { + snapshot = snapshotStrategy.takeSnapshot(snapshot); + result = true; } AssertJUnit.assertTrue(result); @@@ -428,9 -424,12 +426,11 @@@ SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotVO.getId(), vol.getDataStore()); SnapshotInfo newSnapshot = null; - StrategyPriority.sortStrategies(snapshotStrategies, newSnapshot); + - for (SnapshotStrategy strategy : this.snapshotStrategies) { - if (strategy.canHandle(snapshot) != StrategyPriority.Priority.CANT_HANDLE) { - newSnapshot = strategy.takeSnapshot(snapshot); - } + SnapshotStrategy snapshotStrategy = storageStrategyFactory.getSnapshotStrategy(snapshot, SnapshotOperation.TAKE); + if (snapshotStrategy != null) { + newSnapshot = snapshotStrategy.takeSnapshot(snapshot); ++ } AssertJUnit.assertNotNull(newSnapshot); @@@ -480,11 -482,13 +480,12 @@@ SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotVO.getId(), vol.getDataStore()); SnapshotInfo newSnapshot = null; - StrategyPriority.sortStrategies(snapshotStrategies, newSnapshot); + - for (SnapshotStrategy strategy : this.snapshotStrategies) { - if (strategy.canHandle(snapshot) != StrategyPriority.Priority.CANT_HANDLE) { - newSnapshot = strategy.takeSnapshot(snapshot); - } + SnapshotStrategy snapshotStrategy = storageStrategyFactory.getSnapshotStrategy(snapshot, SnapshotOperation.TAKE); + if (snapshotStrategy != null) { + newSnapshot = snapshotStrategy.takeSnapshot(snapshot); } + AssertJUnit.assertNotNull(newSnapshot); LocalHostEndpoint ep = new MockLocalHostEndPoint(); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/51a8086c/engine/storage/integration-test/test/resources/storageContext.xml ---------------------------------------------------------------------- diff --cc engine/storage/integration-test/test/resources/storageContext.xml index e4b8274,884e813..0dcd6a8 --- a/engine/storage/integration-test/test/resources/storageContext.xml +++ b/engine/storage/integration-test/test/resources/storageContext.xml @@@ -85,5 -85,6 +85,10 @@@ ++<<<<<<< HEAD + ++======= + + ++>>>>>>> pluggable_vm_snapshot http://git-wip-us.apache.org/repos/asf/cloudstack/blob/51a8086c/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/51a8086c/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java ---------------------------------------------------------------------- diff --cc engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java index 0000000,6b5e5fb..0ef8ebb mode 000000,100644..100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java @@@ -1,0 -1,369 +1,370 @@@ + /* + * 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 java.util.List; + import java.util.Map; + + import javax.inject.Inject; + import javax.naming.ConfigurationException; + + import org.apache.cloudstack.engine.subsystem.api.storage.VMSnapshotStrategy; + import org.apache.cloudstack.framework.config.dao.ConfigurationDao; + import org.apache.cloudstack.storage.to.VolumeObjectTO; + import org.apache.log4j.Logger; + + import com.cloud.agent.AgentManager; + 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.event.EventTypes; + import com.cloud.event.UsageEventUtils; + import com.cloud.exception.AgentUnavailableException; + import com.cloud.exception.OperationTimedoutException; + import com.cloud.storage.DiskOfferingVO; + import com.cloud.storage.GuestOSVO; + import com.cloud.storage.VolumeVO; + import com.cloud.storage.dao.DiskOfferingDao; + import com.cloud.storage.dao.GuestOSDao; + import com.cloud.storage.dao.VolumeDao; + import com.cloud.uservm.UserVm; + import com.cloud.utils.NumbersUtil; + import com.cloud.utils.component.ManagerBase; + import com.cloud.utils.db.DB; + import com.cloud.utils.db.Transaction; ++import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn; ++import com.cloud.utils.db.TransactionStatus; + import com.cloud.utils.exception.CloudRuntimeException; + import com.cloud.utils.fsm.NoTransitionException; + import com.cloud.vm.UserVmVO; + import com.cloud.vm.dao.UserVmDao; + import com.cloud.vm.snapshot.VMSnapshot; + import com.cloud.vm.snapshot.VMSnapshotVO; + import com.cloud.vm.snapshot.dao.VMSnapshotDao; + + public class DefaultVMSnapshotStrategy extends ManagerBase implements VMSnapshotStrategy { + private static final Logger s_logger = Logger.getLogger(DefaultVMSnapshotStrategy.class); + @Inject + VMSnapshotHelper vmSnapshotHelper; + @Inject + GuestOSDao guestOSDao; + @Inject + UserVmDao userVmDao; + @Inject + VMSnapshotDao vmSnapshotDao; + int _wait; + @Inject + ConfigurationDao configurationDao; + @Inject + AgentManager agentMgr; + @Inject + VolumeDao volumeDao; + @Inject + DiskOfferingDao diskOfferingDao; + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + String value = configurationDao.getValue("vmsnapshot.create.wait"); + _wait = NumbersUtil.parseInt(value, 1800); + return true; + } + + public VMSnapshot takeVMSnapshot(VMSnapshot vmSnapshot) { + Long hostId = vmSnapshotHelper.pickRunningHost(vmSnapshot.getVmId()); + UserVm userVm = userVmDao.findById(vmSnapshot.getVmId()); + VMSnapshotVO vmSnapshotVO = (VMSnapshotVO)vmSnapshot; + try { + vmSnapshotHelper.vmSnapshotStateTransitTo(vmSnapshotVO, VMSnapshot.Event.CreateRequested); + } catch (NoTransitionException e) { + throw new CloudRuntimeException(e.getMessage()); + } + + CreateVMSnapshotAnswer answer = null; + boolean result = false; + try { + GuestOSVO guestOS = guestOSDao.findById(userVm.getGuestOSId()); + + List volumeTOs = vmSnapshotHelper.getVolumeTOList(userVm.getId()); + + VMSnapshotTO current = null; + VMSnapshotVO currentSnapshot = vmSnapshotDao.findCurrentSnapshotByVmId(userVm.getId()); + if (currentSnapshot != null) + current = vmSnapshotHelper.getSnapshotWithParents(currentSnapshot); + VMSnapshotTO target = new VMSnapshotTO(vmSnapshot.getId(), vmSnapshot.getName(), vmSnapshot.getType(), null, vmSnapshot.getDescription(), false, + current); + if (current == null) + vmSnapshotVO.setParent(null); + else + vmSnapshotVO.setParent(current.getId()); + + CreateVMSnapshotCommand ccmd = new CreateVMSnapshotCommand(userVm.getInstanceName(),target ,volumeTOs, guestOS.getDisplayName(),userVm.getState()); + ccmd.setWait(_wait); + + answer = (CreateVMSnapshotAnswer)agentMgr.send(hostId, ccmd); + if (answer != null && answer.getResult()) { + processAnswer(vmSnapshotVO, userVm, answer, hostId); + s_logger.debug("Create vm snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName()); + result = true; + + for (VolumeObjectTO volumeTo : answer.getVolumeTOs()){ + publishUsageEvent(EventTypes.EVENT_VM_SNAPSHOT_CREATE,vmSnapshot,userVm,volumeTo); + } + return vmSnapshot; + } 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); + throw new CloudRuntimeException(errMsg); + } + } catch (OperationTimedoutException e) { + s_logger.debug("Creating VM snapshot: " + vmSnapshot.getName() + " failed: " + e.toString()); + throw new CloudRuntimeException("Creating VM snapshot: " + vmSnapshot.getName() + " failed: " + e.toString()); + } catch (AgentUnavailableException e) { + s_logger.debug("Creating VM snapshot: " + vmSnapshot.getName() + " failed", e); + throw new CloudRuntimeException("Creating VM snapshot: " + vmSnapshot.getName() + " failed: " + e.toString()); + } finally{ + if (!result) { + try { + vmSnapshotHelper.vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed); + } catch (NoTransitionException e1) { + s_logger.error("Cannot set vm snapshot state due to: " + e1.getMessage()); + } + } + } + } + + @Override + public boolean deleteVMSnapshot(VMSnapshot vmSnapshot) { + UserVmVO userVm = userVmDao.findById(vmSnapshot.getVmId()); + VMSnapshotVO vmSnapshotVO = (VMSnapshotVO)vmSnapshot; + try { + vmSnapshotHelper.vmSnapshotStateTransitTo(vmSnapshot,VMSnapshot.Event.ExpungeRequested); + } catch (NoTransitionException e) { + s_logger.debug("Failed to change vm snapshot state with event ExpungeRequested"); + throw new CloudRuntimeException("Failed to change vm snapshot state with event ExpungeRequested: " + e.getMessage()); + } + + try { + Long hostId = vmSnapshotHelper.pickRunningHost(vmSnapshot.getVmId()); + + List volumeTOs = vmSnapshotHelper.getVolumeTOList(vmSnapshot.getVmId()); + + String vmInstanceName = userVm.getInstanceName(); + VMSnapshotTO parent = vmSnapshotHelper.getSnapshotWithParents(vmSnapshotVO).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 answer = agentMgr.send(hostId, deleteSnapshotCommand); + + if (answer != null && answer.getResult()) { + DeleteVMSnapshotAnswer deleteVMSnapshotAnswer = (DeleteVMSnapshotAnswer)answer; + processAnswer(vmSnapshotVO, userVm, answer, hostId); + for (VolumeObjectTO volumeTo : deleteVMSnapshotAnswer.getVolumeTOs()){ + publishUsageEvent(EventTypes.EVENT_VM_SNAPSHOT_DELETE,vmSnapshot,userVm,volumeTo); + } + return true; + } else { + String errMsg = (answer == null) ? null : answer.getDetails(); + s_logger.error("Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + errMsg); + throw new CloudRuntimeException("Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + errMsg); + } + } catch (OperationTimedoutException e) { + throw new CloudRuntimeException("Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + e.getMessage()); + } catch (AgentUnavailableException e) { + throw new CloudRuntimeException("Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + e.getMessage()); + } + } + + @DB - protected void processAnswer(VMSnapshotVO vmSnapshot, UserVm userVm, Answer as, Long hostId) { - final Transaction txn = Transaction.currentTxn(); ++ protected void processAnswer(final VMSnapshotVO vmSnapshot, UserVm userVm, final Answer as, Long hostId) { + try { - txn.start(); - if (as instanceof CreateVMSnapshotAnswer) { - CreateVMSnapshotAnswer answer = (CreateVMSnapshotAnswer) as; - finalizeCreate(vmSnapshot, answer.getVolumeTOs()); - vmSnapshotHelper.vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded); - } else if (as instanceof RevertToVMSnapshotAnswer) { - RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) as; - finalizeRevert(vmSnapshot, answer.getVolumeTOs()); - vmSnapshotHelper.vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded); - } else if (as instanceof DeleteVMSnapshotAnswer) { - DeleteVMSnapshotAnswer answer = (DeleteVMSnapshotAnswer) as; - finalizeDelete(vmSnapshot, answer.getVolumeTOs()); - vmSnapshotDao.remove(vmSnapshot.getId()); - } - txn.commit(); ++ Transaction.execute(new TransactionCallbackWithExceptionNoReturn() { ++ @Override ++ public void doInTransactionWithoutResult(TransactionStatus status) throws NoTransitionException { ++ if (as instanceof CreateVMSnapshotAnswer) { ++ CreateVMSnapshotAnswer answer = (CreateVMSnapshotAnswer) as; ++ finalizeCreate(vmSnapshot, answer.getVolumeTOs()); ++ vmSnapshotHelper.vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded); ++ } else if (as instanceof RevertToVMSnapshotAnswer) { ++ RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) as; ++ finalizeRevert(vmSnapshot, answer.getVolumeTOs()); ++ vmSnapshotHelper.vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded); ++ } else if (as instanceof DeleteVMSnapshotAnswer) { ++ DeleteVMSnapshotAnswer answer = (DeleteVMSnapshotAnswer) as; ++ finalizeDelete(vmSnapshot, answer.getVolumeTOs()); ++ vmSnapshotDao.remove(vmSnapshot.getId()); ++ } ++ } ++ }); + } 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 VolumeTOs) { + // update volumes path + updateVolumePath(VolumeTOs); + + // update children's parent snapshots + List 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 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 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 volumeTOs) { + for (VolumeObjectTO volume : volumeTOs) { + if (volume.getPath() != null) { + VolumeVO volumeVO = volumeDao.findById(volume.getId()); + volumeVO.setPath(volume.getPath()); + volumeVO.setVmSnapshotChainSize(volume.getSize()); + volumeDao.persist(volumeVO); + } + } + } + + private void publishUsageEvent(String type, VMSnapshot vmSnapshot, UserVm userVm, VolumeObjectTO 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.getSize(), + VMSnapshot.class.getName(), vmSnapshot.getUuid()); + } + + @Override + public boolean revertVMSnapshot(VMSnapshot vmSnapshot) { + VMSnapshotVO vmSnapshotVO = (VMSnapshotVO)vmSnapshot; + UserVmVO userVm = userVmDao.findById(vmSnapshot.getVmId()); + try { + vmSnapshotHelper.vmSnapshotStateTransitTo(vmSnapshotVO, VMSnapshot.Event.RevertRequested); + } catch (NoTransitionException e) { + throw new CloudRuntimeException(e.getMessage()); + } + + boolean result = false; + try { + VMSnapshotVO snapshot = vmSnapshotDao.findById(vmSnapshotVO.getId()); + List volumeTOs = vmSnapshotHelper.getVolumeTOList(userVm.getId()); + String vmInstanceName = userVm.getInstanceName(); + VMSnapshotTO parent = vmSnapshotHelper.getSnapshotWithParents(snapshot).getParent(); + + VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(snapshot.getId(), snapshot.getName(), snapshot.getType(), + snapshot.getCreated().getTime(), snapshot.getDescription(), snapshot.getCurrent(), parent); + Long hostId = vmSnapshotHelper.pickRunningHost(vmSnapshot.getVmId()); + GuestOSVO guestOS = guestOSDao.findById(userVm.getGuestOSId()); + RevertToVMSnapshotCommand revertToSnapshotCommand = new RevertToVMSnapshotCommand(vmInstanceName, vmSnapshotTO, volumeTOs, guestOS.getDisplayName()); + + RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) agentMgr.send(hostId, revertToSnapshotCommand); + if (answer != null && answer.getResult()) { + processAnswer(vmSnapshotVO, userVm, answer, hostId); + result = true; + } 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); + throw new CloudRuntimeException(errMsg); + } + } catch (OperationTimedoutException e) { + s_logger.debug("Failed to revert vm snapshot", e); + throw new CloudRuntimeException(e.getMessage()); + } catch (AgentUnavailableException e) { + s_logger.debug("Failed to revert vm snapshot", e); + throw new CloudRuntimeException(e.getMessage()); + } finally { + if (!result) { + try { + vmSnapshotHelper.vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed); + } catch (NoTransitionException e1) { + s_logger.error("Cannot set vm snapshot state due to: " + e1.getMessage()); + } + } + } + return result; + } + + @Override + public boolean canHandle(VMSnapshot vmSnapshot) { + return true; + } + } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/51a8086c/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/51a8086c/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/51a8086c/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/51a8086c/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java ---------------------------------------------------------------------- diff --cc server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java index cd064f5,7a200ff..3f473bd --- a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java +++ b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java @@@ -17,40 -17,8 +17,39 @@@ 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 javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; +import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +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.ActionEvent; import com.cloud.event.EventTypes; - import com.cloud.event.UsageEventUtils; - import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InvalidParameterValueException; @@@ -87,16 -44,7 +75,15 @@@ import com.cloud.utils.component.Manage import com.cloud.utils.db.Filter; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; ++ +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.db.TransactionCallbackNoReturn; +import com.cloud.utils.db.TransactionCallbackWithException; +import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn; +import com.cloud.utils.db.TransactionStatus; ++ import com.cloud.utils.exception.CloudRuntimeException; - import com.cloud.utils.fsm.NoTransitionException; - import com.cloud.utils.fsm.StateMachine2; import com.cloud.vm.UserVmVO; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; @@@ -351,165 -330,14 +369,13 @@@ public class VMSnapshotManagerImpl exte 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 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); - } - } - } - } - - 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 getVolumeTOList(Long vmId) { - List volumeTOs = new ArrayList(); - List volumeVos = _volumeDao.findByInstance(vmId); - - for (VolumeVO volume : volumeVos) { - StoragePool pool = (StoragePool)dataStoreMgr.getPrimaryDataStore(volume.getPoolId()); - VolumeTO volumeTO = new VolumeTO(volume, pool); - volumeTOs.add(volumeTO); - } - return volumeTOs; - } - - // get snapshot and its parents recursively - private VMSnapshotTO getSnapshotWithParents(VMSnapshotVO snapshot) { - Map snapshotMap = new HashMap(); - List allSnapshots = _vmSnapshotDao.findByVm(snapshot.getVmId()); - for (VMSnapshotVO vmSnapshotVO : allSnapshots) { - snapshotMap.put(vmSnapshotVO.getId(), vmSnapshotVO); - } - - VMSnapshotTO currentTO = convert2VMSnapshotTO(snapshot); - VMSnapshotTO result = currentTO; - VMSnapshotVO current = snapshot; - while (current.getParent() != null) { - VMSnapshotVO parent = snapshotMap.get(current.getParent()); - currentTO.setParent(convert2VMSnapshotTO(parent)); - current = snapshotMap.get(current.getParent()); - currentTO = currentTO.getParent(); - } - return result; - } - - private VMSnapshotTO convert2VMSnapshotTO(VMSnapshotVO vo) { - return new VMSnapshotTO(vo.getId(), vo.getName(), vo.getType(), vo.getCreated().getTime(), vo.getDescription(), - vo.getCurrent(), null); - } - - protected boolean vmSnapshotStateTransitTo(VMSnapshotVO vsnp, VMSnapshot.Event event) throws NoTransitionException { - return _vmSnapshottateMachine.transitTo(vsnp, event, null, _vmSnapshotDao); - } - - @DB - protected void processAnswer(final VMSnapshotVO vmSnapshot, UserVmVO userVm, final Answer as, Long hostId) { try { - Transaction.execute(new TransactionCallbackWithExceptionNoReturn() { - @Override - public void doInTransactionWithoutResult(TransactionStatus status) throws NoTransitionException { - 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()); - } - } - }); + VMSnapshotStrategy strategy = findVMSnapshotStrategy(vmSnapshot); + VMSnapshot snapshot = strategy.takeVMSnapshot(vmSnapshot); + return snapshot; } catch (Exception e) { - String errMsg = "Error while process answer: " + as.getClass() + " due to " + e.getMessage(); - s_logger.error(errMsg, e); - throw new CloudRuntimeException(errMsg); + s_logger.debug("Failed to create vm snapshot: " + vmSnapshotId ,e); + return null; } } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/51a8086c/setup/db/db/schema-421to430.sql ----------------------------------------------------------------------