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/object_store_migration
Commit: 51a8086cf6d1cdf7db3f89468e210020a179a57c
Parents: 56f1277 a6ce66e
Author: Edison Su <[email protected]>
Authored: Fri Oct 25 16:47:17 2013 -0700
Committer: Edison Su <[email protected]>
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 @@@
<bean id="AccountGuestVlanMapDaoImpl"
class="com.cloud.network.dao.AccountGuestVlanMapDaoImpl" />
<bean id="StorageCacheReplacementAlgorithm"
class="org.apache.cloudstack.storage.cache.manager.StorageCacheReplacementAlgorithmLRU"
/>
<bean id="ServiceOfferingDetailsDao"
class="com.cloud.service.dao.ServiceOfferingDetailsDaoImpl" />
++<<<<<<< HEAD
+ <bean id="storageStrategyFactoryImpl"
class="org.apache.cloudstack.storage.helper.StorageStrategyFactoryImpl" />
++=======
+ <bean id="vmsnapshotDetailsDao"
class="com.cloud.vm.snapshot.dao.VMSnapshotDetailsDaoImpl" />
+ <bean id="snapshotManager"
class="com.cloud.storage.snapshot.SnapshotManagerImpl" />
++>>>>>>> pluggable_vm_snapshot
</beans>
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<String, Object> 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<VolumeObjectTO> 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<VolumeObjectTO> 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<NoTransitionException>() {
++ @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<VolumeObjectTO> VolumeTOs) {
+ // update volumes path
+ updateVolumePath(VolumeTOs);
+
+ // update children's parent snapshots
+ List<VMSnapshotVO> children=
vmSnapshotDao.listByParent(vmSnapshot.getId());
+ for (VMSnapshotVO child : children) {
+ child.setParent(vmSnapshot.getParent());
+ vmSnapshotDao.persist(child);
+ }
+
+ // update current snapshot
+ VMSnapshotVO current =
vmSnapshotDao.findCurrentSnapshotByVmId(vmSnapshot.getVmId());
+ if(current != null && current.getId() == vmSnapshot.getId() &&
vmSnapshot.getParent() != null){
+ VMSnapshotVO parent =
vmSnapshotDao.findById(vmSnapshot.getParent());
+ parent.setCurrent(true);
+ vmSnapshotDao.persist(parent);
+ }
+ vmSnapshot.setCurrent(false);
+ vmSnapshotDao.persist(vmSnapshot);
+ }
+
+ protected void finalizeCreate(VMSnapshotVO vmSnapshot,
List<VolumeObjectTO> 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<VolumeObjectTO> 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<VolumeObjectTO> 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<VolumeObjectTO> 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<VolumeTO> volumeTOs = getVolumeTOList(userVm.getId());
-
- // prepare target snapshotTO and its parent snapshot (current
snapshot)
- VMSnapshotTO current = null;
- VMSnapshotVO currentSnapshot =
_vmSnapshotDao.findCurrentSnapshotByVmId(userVm.getId());
- if (currentSnapshot != null)
- current = getSnapshotWithParents(currentSnapshot);
- VMSnapshotTO target = new VMSnapshotTO(vmSnapshot.getId(),
vmSnapshot.getName(), vmSnapshot.getType(), null, vmSnapshot.getDescription(),
false,
- current);
- if (current == null)
- vmSnapshot.setParent(null);
- else
- vmSnapshot.setParent(current.getId());
-
- CreateVMSnapshotCommand ccmd = new
CreateVMSnapshotCommand(userVm.getInstanceName(),target ,volumeTOs,
guestOS.getDisplayName(),userVm.getState());
- ccmd.setWait(_wait);
-
- answer = (CreateVMSnapshotAnswer) sendToPool(hostId, ccmd);
- if (answer != null && answer.getResult()) {
- processAnswer(vmSnapshot, userVm, answer, hostId);
- s_logger.debug("Create vm snapshot " + vmSnapshot.getName() +
" succeeded for vm: " + userVm.getInstanceName());
- }else{
-
- String errMsg = "Creating VM snapshot: " +
vmSnapshot.getName() + " failed";
- if(answer != null && answer.getDetails() != null)
- errMsg = errMsg + " due to " + answer.getDetails();
- s_logger.error(errMsg);
- vmSnapshotStateTransitTo(vmSnapshot,
VMSnapshot.Event.OperationFailed);
- throw new CloudRuntimeException(errMsg);
- }
- return vmSnapshot;
- } catch (Exception e) {
- if(e instanceof AgentUnavailableException){
- try {
- vmSnapshotStateTransitTo(vmSnapshot,
VMSnapshot.Event.OperationFailed);
- } catch (NoTransitionException e1) {
- s_logger.error("Cannot set vm snapshot state due to: " +
e1.getMessage());
- }
- }
- String msg = e.getMessage();
- s_logger.error("Create vm snapshot " + vmSnapshot.getName() + "
failed for vm: " + userVm.getInstanceName() + " due to " + msg);
- throw new CloudRuntimeException(msg);
- } finally{
- if(vmSnapshot.getState() == VMSnapshot.State.Allocated){
- s_logger.warn("Create vm snapshot " + vmSnapshot.getName() +
" failed for vm: " + userVm.getInstanceName());
- _vmSnapshotDao.remove(vmSnapshot.getId());
- }
- if(vmSnapshot.getState() == VMSnapshot.State.Ready && answer !=
null){
- for (VolumeTO volumeTo : answer.getVolumeTOs()){
-
publishUsageEvent(EventTypes.EVENT_VM_SNAPSHOT_CREATE,vmSnapshot,userVm,volumeTo);
- }
- }
- }
- }
-
- private void publishUsageEvent(String type, VMSnapshot vmSnapshot, UserVm
userVm, VolumeTO volumeTo){
- VolumeVO volume = _volumeDao.findById(volumeTo.getId());
- Long diskOfferingId = volume.getDiskOfferingId();
- Long offeringId = null;
- if (diskOfferingId != null) {
- DiskOfferingVO offering =
_diskOfferingDao.findById(diskOfferingId);
- if (offering != null
- && (offering.getType() == DiskOfferingVO.Type.Disk)) {
- offeringId = offering.getId();
- }
- }
- UsageEventUtils.publishUsageEvent(
- type,
- vmSnapshot.getAccountId(),
- userVm.getDataCenterId(),
- userVm.getId(),
- vmSnapshot.getName(),
- offeringId,
- volume.getId(), // save volume's id into templateId field
- volumeTo.getChainSize(),
- VMSnapshot.class.getName(), vmSnapshot.getUuid());
- }
-
- protected List<VolumeTO> getVolumeTOList(Long vmId) {
- List<VolumeTO> volumeTOs = new ArrayList<VolumeTO>();
- List<VolumeVO> volumeVos = _volumeDao.findByInstance(vmId);
-
- 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<Long, VMSnapshotVO> snapshotMap = new HashMap<Long,
VMSnapshotVO>();
- List<VMSnapshotVO> 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<NoTransitionException>() {
- @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
----------------------------------------------------------------------