You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ed...@apache.org on 2013/10/15 03:09:12 UTC
[27/29] git commit: updated refs/heads/pluggable_vm_snapshot to
77fca0c
move a lot of code into vmsnapshot strategy
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/73274629
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/73274629
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/73274629
Branch: refs/heads/pluggable_vm_snapshot
Commit: 732746290d1074d672deedd589780eacc98e2149
Parents: aad1cda
Author: Edison Su <su...@gmail.com>
Authored: Thu Oct 10 18:00:21 2013 -0700
Committer: Edison Su <su...@gmail.com>
Committed: Mon Oct 14 18:06:17 2013 -0700
----------------------------------------------------------------------
.../api/storage/VMSnapshotStrategy.java | 28 ++
.../cloud/vm/snapshot/VMSnapshotDetailsVO.java | 81 ++++
.../vm/snapshot/dao/VMSnapshotDetailsDao.java | 28 ++
.../snapshot/dao/VMSnapshotDetailsDaoImpl.java | 52 +++
.../vmsnapshot/DefaultVMSnapshotStrategy.java | 371 ++++++++++++++++++
.../storage/vmsnapshot/VMSnapshotHelper.java | 27 ++
.../vmsnapshot/VMSnapshotHelperImpl.java | 40 ++
.../vm/snapshot/VMSnapshotManagerImpl.java | 374 +++----------------
8 files changed, 672 insertions(+), 329 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/73274629/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VMSnapshotStrategy.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VMSnapshotStrategy.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VMSnapshotStrategy.java
new file mode 100644
index 0000000..8dd6eca
--- /dev/null
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VMSnapshotStrategy.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.engine.subsystem.api.storage;
+
+import com.cloud.vm.snapshot.VMSnapshot;
+
+public interface VMSnapshotStrategy {
+ VMSnapshot takeVMSnapshot(VMSnapshot vmSnapshot);
+ boolean deleteVMSnapshot(VMSnapshot vmSnapshot);
+ boolean revertVMSnapshot(VMSnapshot vmSnapshot);
+ boolean canHandle(VMSnapshot vmSnapshot);
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/73274629/engine/schema/src/com/cloud/vm/snapshot/VMSnapshotDetailsVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/vm/snapshot/VMSnapshotDetailsVO.java b/engine/schema/src/com/cloud/vm/snapshot/VMSnapshotDetailsVO.java
new file mode 100644
index 0000000..7ab7c72
--- /dev/null
+++ b/engine/schema/src/com/cloud/vm/snapshot/VMSnapshotDetailsVO.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.cloud.vm.snapshot;
+
+import org.apache.cloudstack.api.InternalIdentity;
+
+import javax.persistence.Column;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+public class VMSnapshotDetailsVO implements InternalIdentity {
+ @Id
+ @GeneratedValue(strategy= GenerationType.IDENTITY)
+ @Column(name="id")
+ private long id;
+
+ @Column(name = "vm_snapshot_id")
+ Long vmSnapshotId;
+
+ @Column(name = "name")
+ String name;
+
+ @Column(name = "value")
+ String value;
+
+ public VMSnapshotDetailsVO() {
+
+ }
+
+ public VMSnapshotDetailsVO(Long vmSnapshotId, String name, String value) {
+ this.vmSnapshotId = vmSnapshotId;
+ this.name = name;
+ this.value = value;
+ }
+
+ public Long getVmSnapshotId() {
+ return this.vmSnapshotId;
+ }
+
+ public void setVmSnapshotId(Long vmSnapshotId) {
+ this.vmSnapshotId = vmSnapshotId;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getValue() {
+ return this.value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/73274629/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDetailsDao.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDetailsDao.java b/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDetailsDao.java
new file mode 100644
index 0000000..e84178c
--- /dev/null
+++ b/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDetailsDao.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.cloud.vm.snapshot.dao;
+
+import com.cloud.utils.db.GenericDao;
+import com.cloud.vm.snapshot.VMSnapshotDetailsVO;
+
+import java.util.Map;
+
+public interface VMSnapshotDetailsDao extends GenericDao<VMSnapshotDetailsVO, Long> {
+ Map<String, String> getDetails(Long vmSnapshotId);
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/73274629/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDetailsDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDetailsDaoImpl.java b/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDetailsDaoImpl.java
new file mode 100644
index 0000000..b528b39
--- /dev/null
+++ b/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDetailsDaoImpl.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.cloud.vm.snapshot.dao;
+
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.vm.snapshot.VMSnapshotDetailsVO;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class VMSnapshotDetailsDaoImpl extends GenericDaoBase<VMSnapshotDetailsVO, Long> implements VMSnapshotDetailsDao {
+ protected final SearchBuilder<VMSnapshotDetailsVO> searchDetails;
+
+ protected VMSnapshotDetailsDaoImpl() {
+ super();
+ searchDetails = createSearchBuilder();
+ searchDetails.and("vmsnapshotId", searchDetails.entity().getVmSnapshotId(), SearchCriteria.Op.EQ);
+ searchDetails.done();
+ }
+ @Override
+ public Map<String, String> getDetails(Long vmSnapshotId) {
+ SearchCriteria<VMSnapshotDetailsVO> sc = searchDetails.create();
+ sc.setParameters("vmsnapshotId", vmSnapshotId);
+
+ List<VMSnapshotDetailsVO> details = listBy(sc);
+ Map<String, String> detailsMap = new HashMap<String, String>();
+ for (VMSnapshotDetailsVO detail : details) {
+ detailsMap.put(detail.getName(), detail.getValue());
+ }
+
+ return detailsMap;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/73274629/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java
new file mode 100644
index 0000000..054f28c
--- /dev/null
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java
@@ -0,0 +1,371 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.storage.vmsnapshot;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.CreateVMSnapshotAnswer;
+import com.cloud.agent.api.CreateVMSnapshotCommand;
+import com.cloud.agent.api.DeleteVMSnapshotAnswer;
+import com.cloud.agent.api.DeleteVMSnapshotCommand;
+import com.cloud.agent.api.RevertToVMSnapshotAnswer;
+import com.cloud.agent.api.RevertToVMSnapshotCommand;
+import com.cloud.agent.api.VMSnapshotTO;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.event.EventTypes;
+import com.cloud.event.UsageEventUtils;
+import com.cloud.exception.AgentUnavailableException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.storage.DiskOfferingVO;
+import com.cloud.storage.GuestOSVO;
+import com.cloud.storage.VolumeVO;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.fsm.NoTransitionException;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+import org.apache.cloudstack.engine.subsystem.api.storage.VMSnapshotStrategy;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
+
+import javax.inject.Inject;
+import java.util.List;
+
+public class DefaultVMSnapshotStrategy implements VMSnapshotStrategy {
+ @Inject
+ VMSnapshotHelper vmSnapshotHelper;
+ @Override
+ public VMSnapshot takeVMSnapshot(VMSnapshot vmSnapshot) {
+ Long hostId = pickRunningHost(vmId);
+ try {
+ vmSnapshotHelper.vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.CreateRequested);
+ } catch (NoTransitionException e) {
+ throw new CloudRuntimeException(e.getMessage());
+ }
+
+ CreateVMSnapshotAnswer answer = null;
+ try {
+ GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId());
+
+ // prepare snapshotVolumeTos
+ List<VolumeTO> volumeTOs = getVolumeTOList(userVm.getId());
+
+ // prepare target snapshotTO and its parent snapshot (current snapshot)
+ VMSnapshotTO current = null;
+ VMSnapshotVO currentSnapshot = _vmSnapshotDao.findCurrentSnapshotByVmId(userVm.getId());
+ if (currentSnapshot != null)
+ current = getSnapshotWithParents(currentSnapshot);
+ VMSnapshotTO target = new VMSnapshotTO(vmSnapshot.getId(), vmSnapshot.getName(), vmSnapshot.getType(), null, vmSnapshot.getDescription(), false,
+ current);
+ if (current == null)
+ vmSnapshot.setParent(null);
+ else
+ vmSnapshot.setParent(current.getId());
+
+ CreateVMSnapshotCommand ccmd = new CreateVMSnapshotCommand(userVm.getInstanceName(),target ,volumeTOs, guestOS.getDisplayName(),userVm.getState());
+ ccmd.setWait(_wait);
+
+ answer = (CreateVMSnapshotAnswer) sendToPool(hostId, ccmd);
+ if (answer != null && answer.getResult()) {
+ processAnswer(vmSnapshot, userVm, answer, hostId);
+ s_logger.debug("Create vm snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName());
+ }else{
+
+ String errMsg = "Creating VM snapshot: " + vmSnapshot.getName() + " failed";
+ if(answer != null && answer.getDetails() != null)
+ errMsg = errMsg + " due to " + answer.getDetails();
+ s_logger.error(errMsg);
+ vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed);
+ throw new CloudRuntimeException(errMsg);
+ }
+ return vmSnapshot;
+ } catch (Exception e) {
+ if(e instanceof AgentUnavailableException){
+ try {
+ vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed);
+ } catch (NoTransitionException e1) {
+ s_logger.error("Cannot set vm snapshot state due to: " + e1.getMessage());
+ }
+ }
+ String msg = e.getMessage();
+ s_logger.error("Create vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName() + " due to " + msg);
+ throw new CloudRuntimeException(msg);
+ } finally{
+ if(vmSnapshot.getState() == VMSnapshot.State.Allocated){
+ s_logger.warn("Create vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName());
+ _vmSnapshotDao.remove(vmSnapshot.getId());
+ }
+ if(vmSnapshot.getState() == VMSnapshot.State.Ready && answer != null){
+ for (VolumeTO volumeTo : answer.getVolumeTOs()){
+ publishUsageEvent(EventTypes.EVENT_VM_SNAPSHOT_CREATE,vmSnapshot,userVm,volumeTo);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean deleteVMSnapshot(VMSnapshot vmSnapshot) {
+ UserVmVO userVm = _userVMDao.findById(vmSnapshot.getVmId());
+ DeleteVMSnapshotAnswer answer = null;
+ try {
+ vmSnapshotStateTransitTo(vmSnapshot,VMSnapshot.Event.ExpungeRequested);
+ Long hostId = pickRunningHost(vmSnapshot.getVmId());
+
+ // prepare snapshotVolumeTos
+ List<VolumeTO> volumeTOs = getVolumeTOList(vmSnapshot.getVmId());
+
+ // prepare DeleteVMSnapshotCommand
+ String vmInstanceName = userVm.getInstanceName();
+ VMSnapshotTO parent = getSnapshotWithParents(vmSnapshot).getParent();
+ VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(vmSnapshot.getId(), vmSnapshot.getName(), vmSnapshot.getType(),
+ vmSnapshot.getCreated().getTime(), vmSnapshot.getDescription(), vmSnapshot.getCurrent(), parent);
+ GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId());
+ DeleteVMSnapshotCommand deleteSnapshotCommand = new DeleteVMSnapshotCommand(vmInstanceName, vmSnapshotTO, volumeTOs,guestOS.getDisplayName());
+
+ answer = (DeleteVMSnapshotAnswer) sendToPool(hostId, deleteSnapshotCommand);
+
+ if (answer != null && answer.getResult()) {
+ processAnswer(vmSnapshot, userVm, answer, hostId);
+ s_logger.debug("Delete VM snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName());
+ return true;
+ } else {
+ s_logger.error("Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + answer.getDetails());
+ return false;
+ }
+ } catch (Exception e) {
+ String msg = "Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + e.getMessage();
+ s_logger.error(msg , e);
+ throw new CloudRuntimeException(e.getMessage());
+ } finally{
+ if(answer != null && answer.getResult()){
+ for (VolumeTO volumeTo : answer.getVolumeTOs()){
+ publishUsageEvent(EventTypes.EVENT_VM_SNAPSHOT_DELETE,vmSnapshot,userVm,volumeTo);
+ }
+ }
+ }
+ }
+
+ @DB
+ protected void processAnswer(VMSnapshotVO vmSnapshot, UserVmVO userVm, Answer as, Long hostId) {
+ final Transaction txn = Transaction.currentTxn();
+ try {
+ txn.start();
+ if (as instanceof CreateVMSnapshotAnswer) {
+ CreateVMSnapshotAnswer answer = (CreateVMSnapshotAnswer) as;
+ finalizeCreate(vmSnapshot, answer.getVolumeTOs());
+ vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded);
+ } else if (as instanceof RevertToVMSnapshotAnswer) {
+ RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) as;
+ finalizeRevert(vmSnapshot, answer.getVolumeTOs());
+ vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded);
+ } else if (as instanceof DeleteVMSnapshotAnswer) {
+ DeleteVMSnapshotAnswer answer = (DeleteVMSnapshotAnswer) as;
+ finalizeDelete(vmSnapshot, answer.getVolumeTOs());
+ _vmSnapshotDao.remove(vmSnapshot.getId());
+ }
+ txn.commit();
+ } catch (Exception e) {
+ String errMsg = "Error while process answer: " + as.getClass() + " due to " + e.getMessage();
+ s_logger.error(errMsg, e);
+ txn.rollback();
+ throw new CloudRuntimeException(errMsg);
+ } finally {
+ txn.close();
+ }
+ }
+
+ protected void finalizeDelete(VMSnapshotVO vmSnapshot, List<VolumeTO> VolumeTOs) {
+ // update volumes path
+ updateVolumePath(VolumeTOs);
+
+ // update children's parent snapshots
+ List<VMSnapshotVO> children= _vmSnapshotDao.listByParent(vmSnapshot.getId());
+ for (VMSnapshotVO child : children) {
+ child.setParent(vmSnapshot.getParent());
+ _vmSnapshotDao.persist(child);
+ }
+
+ // update current snapshot
+ VMSnapshotVO current = _vmSnapshotDao.findCurrentSnapshotByVmId(vmSnapshot.getVmId());
+ if(current != null && current.getId() == vmSnapshot.getId() && vmSnapshot.getParent() != null){
+ VMSnapshotVO parent = _vmSnapshotDao.findById(vmSnapshot.getParent());
+ parent.setCurrent(true);
+ _vmSnapshotDao.persist(parent);
+ }
+ vmSnapshot.setCurrent(false);
+ _vmSnapshotDao.persist(vmSnapshot);
+ }
+
+ protected void finalizeCreate(VMSnapshotVO vmSnapshot, List<VolumeTO> VolumeTOs) {
+ // update volumes path
+ updateVolumePath(VolumeTOs);
+
+ vmSnapshot.setCurrent(true);
+
+ // change current snapshot
+ if (vmSnapshot.getParent() != null) {
+ VMSnapshotVO previousCurrent = _vmSnapshotDao.findById(vmSnapshot.getParent());
+ previousCurrent.setCurrent(false);
+ _vmSnapshotDao.persist(previousCurrent);
+ }
+ _vmSnapshotDao.persist(vmSnapshot);
+ }
+
+ protected void finalizeRevert(VMSnapshotVO vmSnapshot, List<VolumeTO> volumeToList) {
+ // update volumes path
+ updateVolumePath(volumeToList);
+
+ // update current snapshot, current snapshot is the one reverted to
+ VMSnapshotVO previousCurrent = _vmSnapshotDao.findCurrentSnapshotByVmId(vmSnapshot.getVmId());
+ if(previousCurrent != null){
+ previousCurrent.setCurrent(false);
+ _vmSnapshotDao.persist(previousCurrent);
+ }
+ vmSnapshot.setCurrent(true);
+ _vmSnapshotDao.persist(vmSnapshot);
+ }
+
+ private void updateVolumePath(List<VolumeTO> volumeTOs) {
+ for (VolumeTO volume : volumeTOs) {
+ if (volume.getPath() != null) {
+ VolumeVO volumeVO = _volumeDao.findById(volume.getId());
+ volumeVO.setPath(volume.getPath());
+ volumeVO.setVmSnapshotChainSize(volume.getChainSize());
+ _volumeDao.persist(volumeVO);
+ }
+ }
+ }
+
+ protected Long pickRunningHost(Long vmId) {
+ UserVmVO vm = _userVMDao.findById(vmId);
+ // use VM's host if VM is running
+ if(vm.getState() == VirtualMachine.State.Running)
+ return vm.getHostId();
+
+ // check if lastHostId is available
+ if(vm.getLastHostId() != null){
+ HostVO lastHost = _hostDao.findById(vm.getLastHostId());
+ if(lastHost.getStatus() == com.cloud.host.Status.Up && !lastHost.isInMaintenanceStates())
+ return lastHost.getId();
+ }
+
+ List<VolumeVO> listVolumes = _volumeDao.findByInstance(vmId);
+ if (listVolumes == null || listVolumes.size() == 0) {
+ throw new InvalidParameterValueException("vmInstance has no volumes");
+ }
+ VolumeVO volume = listVolumes.get(0);
+ Long poolId = volume.getPoolId();
+ if (poolId == null) {
+ throw new InvalidParameterValueException("pool id is not found");
+ }
+ StoragePoolVO storagePool = _storagePoolDao.findById(poolId);
+ if (storagePool == null) {
+ throw new InvalidParameterValueException("storage pool is not found");
+ }
+ List<HostVO> listHost = _hostDao.listAllUpAndEnabledNonHAHosts(Host.Type.Routing, storagePool.getClusterId(), storagePool.getPodId(),
+ storagePool.getDataCenterId(), null);
+ if (listHost == null || listHost.size() == 0) {
+ throw new InvalidParameterValueException("no host in up state is found");
+ }
+ return listHost.get(0).getId();
+ }
+
+
+ private void publishUsageEvent(String type, VMSnapshot vmSnapshot, UserVm userVm, VolumeTO volumeTo){
+ VolumeVO volume = _volumeDao.findById(volumeTo.getId());
+ Long diskOfferingId = volume.getDiskOfferingId();
+ Long offeringId = null;
+ if (diskOfferingId != null) {
+ DiskOfferingVO offering = _diskOfferingDao.findById(diskOfferingId);
+ if (offering != null
+ && (offering.getType() == DiskOfferingVO.Type.Disk)) {
+ offeringId = offering.getId();
+ }
+ }
+ UsageEventUtils.publishUsageEvent(
+ type,
+ vmSnapshot.getAccountId(),
+ userVm.getDataCenterId(),
+ userVm.getId(),
+ vmSnapshot.getName(),
+ offeringId,
+ volume.getId(), // save volume's id into templateId field
+ volumeTo.getChainSize(),
+ VMSnapshot.class.getName(), vmSnapshot.getUuid());
+ }
+
+ @Override
+ public boolean revertVMSnapshot(VMSnapshot vmSnapshot) {
+ userVm = _userVMDao.findById(userVm.getId());
+ try {
+ vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.RevertRequested);
+ } catch (NoTransitionException e) {
+ throw new CloudRuntimeException(e.getMessage());
+ }
+
+ try {
+ VMSnapshotVO snapshot = _vmSnapshotDao.findById(vmSnapshotVo.getId());
+ // prepare RevertToSnapshotCommand
+ List<VolumeTO> volumeTOs = getVolumeTOList(userVm.getId());
+ String vmInstanceName = userVm.getInstanceName();
+ VMSnapshotTO parent = getSnapshotWithParents(snapshot).getParent();
+ VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(snapshot.getId(), snapshot.getName(), snapshot.getType(),
+ snapshot.getCreated().getTime(), snapshot.getDescription(), snapshot.getCurrent(), parent);
+
+ GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId());
+ RevertToVMSnapshotCommand revertToSnapshotCommand = new RevertToVMSnapshotCommand(vmInstanceName, vmSnapshotTO, volumeTOs, guestOS.getDisplayName());
+
+ RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) sendToPool(hostId, revertToSnapshotCommand);
+ if (answer != null && answer.getResult()) {
+ processAnswer(vmSnapshotVo, userVm, answer, hostId);
+ s_logger.debug("RevertTo " + vmSnapshotVo.getName() + " succeeded for vm: " + userVm.getInstanceName());
+ } else {
+ String errMsg = "Revert VM: " + userVm.getInstanceName() + " to snapshot: "+ vmSnapshotVo.getName() + " failed";
+ if(answer != null && answer.getDetails() != null)
+ errMsg = errMsg + " due to " + answer.getDetails();
+ s_logger.error(errMsg);
+ // agent report revert operation fails
+ vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.OperationFailed);
+ throw new CloudRuntimeException(errMsg);
+ }
+ } catch (Exception e) {
+ if(e instanceof AgentUnavailableException){
+ try {
+ vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.OperationFailed);
+ } catch (NoTransitionException e1) {
+ s_logger.error("Cannot set vm snapshot state due to: " + e1.getMessage());
+ }
+ }
+ // for other exceptions, do not change VM snapshot state, leave it for snapshotSync
+ String errMsg = "revert vm: " + userVm.getInstanceName() + " to snapshot " + vmSnapshotVo.getName() + " failed due to " + e.getMessage();
+ s_logger.error(errMsg);
+ throw new CloudRuntimeException(e.getMessage());
+ }
+ return userVm;
+ }
+
+ @Override
+ public boolean canHandle(VMSnapshot vmSnapshot) {
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/73274629/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotHelper.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotHelper.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotHelper.java
new file mode 100644
index 0000000..4330498
--- /dev/null
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotHelper.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.storage.vmsnapshot;
+
+import com.cloud.utils.fsm.NoTransitionException;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+
+public interface VMSnapshotHelper {
+ boolean vmSnapshotStateTransitTo(VMSnapshot vsnp, VMSnapshot.Event event) throws NoTransitionException;
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/73274629/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotHelperImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotHelperImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotHelperImpl.java
new file mode 100644
index 0000000..c96b8ef
--- /dev/null
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/vmsnapshot/VMSnapshotHelperImpl.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.storage.vmsnapshot;
+
+import com.cloud.utils.fsm.NoTransitionException;
+import com.cloud.utils.fsm.StateMachine2;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
+
+import javax.inject.Inject;
+
+public class VMSnapshotHelperImpl implements VMSnapshotHelper {
+ @Inject
+ VMSnapshotDao _vmSnapshotDao;
+ StateMachine2<VMSnapshot.State, VMSnapshot.Event, VMSnapshot> _vmSnapshottateMachine ;
+ public VMSnapshotHelperImpl() {
+ _vmSnapshottateMachine = VMSnapshot.State.getStateMachine();
+ }
+ @Override
+ public boolean vmSnapshotStateTransitTo(VMSnapshot vsnp, VMSnapshot.Event event) throws NoTransitionException {
+ return _vmSnapshottateMachine.transitTo(vsnp, event, null, _vmSnapshotDao);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/73274629/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
index aa772fe..dc5d9ed 100644
--- a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
+++ b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
@@ -27,6 +27,7 @@ import javax.ejb.Local;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
+import org.apache.cloudstack.engine.subsystem.api.storage.VMSnapshotStrategy;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@@ -127,9 +128,20 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
@Inject HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
@Inject DiskOfferingDao _diskOfferingDao;
@Inject ServiceOfferingDao _serviceOfferingDao;
+ @Inject List<VMSnapshotStrategy> vmSnapshotStrategies;
+
+ public List<VMSnapshotStrategy> getVmSnapshotStrategies() {
+ return vmSnapshotStrategies;
+ }
+
+ @Inject
+ public void setVmSnapshotStrategies(List<VMSnapshotStrategy> vmSnapshotStrategies) {
+ this.vmSnapshotStrategies = vmSnapshotStrategies;
+ }
+
int _vmSnapshotMax;
int _wait;
- StateMachine2<VMSnapshot.State, VMSnapshot.Event, VMSnapshot> _vmSnapshottateMachine ;
+
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
@@ -144,7 +156,6 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
String value = _configDao.getValue("vmsnapshot.create.wait");
_wait = NumbersUtil.parseInt(value, 1800);
- _vmSnapshottateMachine = VMSnapshot.State.getStateMachine();
return true;
}
@@ -336,6 +347,22 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
return _name;
}
+ private VMSnapshotStrategy findVMSnapshotStrategy(VMSnapshot vmSnapshot) {
+ VMSnapshotStrategy snapshotStrategy = null;
+ for(VMSnapshotStrategy strategy : vmSnapshotStrategies) {
+ if (strategy.canHandle(vmSnapshot)) {
+ snapshotStrategy = strategy;
+ break;
+ }
+ }
+
+ if (snapshotStrategy == null) {
+ throw new CloudRuntimeException("can't find vm snapshot strategy for vmsnapshot: " + vmSnapshot.getId());
+ }
+
+ return snapshotStrategy;
+ }
+
@Override
@ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_CREATE, eventDescription = "creating VM snapshot", async = true)
public VMSnapshot creatVMSnapshot(Long vmId, Long vmSnapshotId) {
@@ -347,99 +374,12 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
if(vmSnapshot == null){
throw new CloudRuntimeException("VM snapshot id: " + vmSnapshotId + " can not be found");
}
- Long hostId = pickRunningHost(vmId);
- try {
- vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.CreateRequested);
- } catch (NoTransitionException e) {
- throw new CloudRuntimeException(e.getMessage());
- }
- return createVmSnapshotInternal(userVm, vmSnapshot, hostId);
- }
- protected VMSnapshot createVmSnapshotInternal(UserVmVO userVm, VMSnapshotVO vmSnapshot, Long hostId) {
- CreateVMSnapshotAnswer answer = null;
- try {
- GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId());
-
- // prepare snapshotVolumeTos
- List<VolumeTO> volumeTOs = getVolumeTOList(userVm.getId());
-
- // prepare target snapshotTO and its parent snapshot (current snapshot)
- VMSnapshotTO current = null;
- VMSnapshotVO currentSnapshot = _vmSnapshotDao.findCurrentSnapshotByVmId(userVm.getId());
- if (currentSnapshot != null)
- current = getSnapshotWithParents(currentSnapshot);
- VMSnapshotTO target = new VMSnapshotTO(vmSnapshot.getId(), vmSnapshot.getName(), vmSnapshot.getType(), null, vmSnapshot.getDescription(), false,
- current);
- if (current == null)
- vmSnapshot.setParent(null);
- else
- vmSnapshot.setParent(current.getId());
-
- CreateVMSnapshotCommand ccmd = new CreateVMSnapshotCommand(userVm.getInstanceName(),target ,volumeTOs, guestOS.getDisplayName(),userVm.getState());
- ccmd.setWait(_wait);
-
- answer = (CreateVMSnapshotAnswer) sendToPool(hostId, ccmd);
- if (answer != null && answer.getResult()) {
- processAnswer(vmSnapshot, userVm, answer, hostId);
- s_logger.debug("Create vm snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName());
- }else{
-
- String errMsg = "Creating VM snapshot: " + vmSnapshot.getName() + " failed";
- if(answer != null && answer.getDetails() != null)
- errMsg = errMsg + " due to " + answer.getDetails();
- s_logger.error(errMsg);
- vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed);
- throw new CloudRuntimeException(errMsg);
- }
- return vmSnapshot;
- } catch (Exception e) {
- if(e instanceof AgentUnavailableException){
- try {
- vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed);
- } catch (NoTransitionException e1) {
- s_logger.error("Cannot set vm snapshot state due to: " + e1.getMessage());
- }
- }
- String msg = e.getMessage();
- s_logger.error("Create vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName() + " due to " + msg);
- throw new CloudRuntimeException(msg);
- } finally{
- if(vmSnapshot.getState() == VMSnapshot.State.Allocated){
- s_logger.warn("Create vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName());
- _vmSnapshotDao.remove(vmSnapshot.getId());
- }
- if(vmSnapshot.getState() == VMSnapshot.State.Ready && answer != null){
- for (VolumeTO volumeTo : answer.getVolumeTOs()){
- publishUsageEvent(EventTypes.EVENT_VM_SNAPSHOT_CREATE,vmSnapshot,userVm,volumeTo);
- }
- }
- }
+ VMSnapshotStrategy strategy = findVMSnapshotStrategy(vmSnapshot);
+ VMSnapshot snapshot = strategy.takeVMSnapshot(vmSnapshot);
+ return snapshot;
}
- private void publishUsageEvent(String type, VMSnapshot vmSnapshot, UserVm userVm, VolumeTO volumeTo){
- VolumeVO volume = _volumeDao.findById(volumeTo.getId());
- Long diskOfferingId = volume.getDiskOfferingId();
- Long offeringId = null;
- if (diskOfferingId != null) {
- DiskOfferingVO offering = _diskOfferingDao.findById(diskOfferingId);
- if (offering != null
- && (offering.getType() == DiskOfferingVO.Type.Disk)) {
- offeringId = offering.getId();
- }
- }
- UsageEventUtils.publishUsageEvent(
- type,
- vmSnapshot.getAccountId(),
- userVm.getDataCenterId(),
- userVm.getId(),
- vmSnapshot.getName(),
- offeringId,
- volume.getId(), // save volume's id into templateId field
- volumeTo.getChainSize(),
- VMSnapshot.class.getName(), vmSnapshot.getUuid());
- }
-
protected List<VolumeTO> getVolumeTOList(Long vmId) {
List<VolumeTO> volumeTOs = new ArrayList<VolumeTO>();
List<VolumeVO> volumeVos = _volumeDao.findByInstance(vmId);
@@ -477,111 +417,10 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
vo.getCurrent(), null);
}
- protected boolean vmSnapshotStateTransitTo(VMSnapshotVO vsnp, VMSnapshot.Event event) throws NoTransitionException {
- return _vmSnapshottateMachine.transitTo(vsnp, event, null, _vmSnapshotDao);
- }
-
- @DB
- protected void processAnswer(VMSnapshotVO vmSnapshot, UserVmVO userVm, Answer as, Long hostId) {
- final Transaction txn = Transaction.currentTxn();
- try {
- txn.start();
- if (as instanceof CreateVMSnapshotAnswer) {
- CreateVMSnapshotAnswer answer = (CreateVMSnapshotAnswer) as;
- finalizeCreate(vmSnapshot, answer.getVolumeTOs());
- vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded);
- } else if (as instanceof RevertToVMSnapshotAnswer) {
- RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) as;
- finalizeRevert(vmSnapshot, answer.getVolumeTOs());
- vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded);
- } else if (as instanceof DeleteVMSnapshotAnswer) {
- DeleteVMSnapshotAnswer answer = (DeleteVMSnapshotAnswer) as;
- finalizeDelete(vmSnapshot, answer.getVolumeTOs());
- _vmSnapshotDao.remove(vmSnapshot.getId());
- }
- txn.commit();
- } catch (Exception e) {
- String errMsg = "Error while process answer: " + as.getClass() + " due to " + e.getMessage();
- s_logger.error(errMsg, e);
- txn.rollback();
- throw new CloudRuntimeException(errMsg);
- } finally {
- txn.close();
- }
- }
-
- protected void finalizeDelete(VMSnapshotVO vmSnapshot, List<VolumeTO> VolumeTOs) {
- // update volumes path
- updateVolumePath(VolumeTOs);
-
- // update children's parent snapshots
- List<VMSnapshotVO> children= _vmSnapshotDao.listByParent(vmSnapshot.getId());
- for (VMSnapshotVO child : children) {
- child.setParent(vmSnapshot.getParent());
- _vmSnapshotDao.persist(child);
- }
-
- // update current snapshot
- VMSnapshotVO current = _vmSnapshotDao.findCurrentSnapshotByVmId(vmSnapshot.getVmId());
- if(current != null && current.getId() == vmSnapshot.getId() && vmSnapshot.getParent() != null){
- VMSnapshotVO parent = _vmSnapshotDao.findById(vmSnapshot.getParent());
- parent.setCurrent(true);
- _vmSnapshotDao.persist(parent);
- }
- vmSnapshot.setCurrent(false);
- _vmSnapshotDao.persist(vmSnapshot);
- }
-
- protected void finalizeCreate(VMSnapshotVO vmSnapshot, List<VolumeTO> VolumeTOs) {
- // update volumes path
- updateVolumePath(VolumeTOs);
-
- vmSnapshot.setCurrent(true);
-
- // change current snapshot
- if (vmSnapshot.getParent() != null) {
- VMSnapshotVO previousCurrent = _vmSnapshotDao.findById(vmSnapshot.getParent());
- previousCurrent.setCurrent(false);
- _vmSnapshotDao.persist(previousCurrent);
- }
- _vmSnapshotDao.persist(vmSnapshot);
- }
-
- protected void finalizeRevert(VMSnapshotVO vmSnapshot, List<VolumeTO> volumeToList) {
- // update volumes path
- updateVolumePath(volumeToList);
-
- // update current snapshot, current snapshot is the one reverted to
- VMSnapshotVO previousCurrent = _vmSnapshotDao.findCurrentSnapshotByVmId(vmSnapshot.getVmId());
- if(previousCurrent != null){
- previousCurrent.setCurrent(false);
- _vmSnapshotDao.persist(previousCurrent);
- }
- vmSnapshot.setCurrent(true);
- _vmSnapshotDao.persist(vmSnapshot);
- }
-
- private void updateVolumePath(List<VolumeTO> volumeTOs) {
- for (VolumeTO volume : volumeTOs) {
- if (volume.getPath() != null) {
- VolumeVO volumeVO = _volumeDao.findById(volume.getId());
- volumeVO.setPath(volume.getPath());
- volumeVO.setVmSnapshotChainSize(volume.getChainSize());
- _volumeDao.persist(volumeVO);
- }
- }
- }
-
public VMSnapshotManagerImpl() {
}
-
- protected Answer sendToPool(Long hostId, Command cmd) throws AgentUnavailableException, OperationTimedoutException {
- long targetHostId = _hvGuruMgr.getGuruProcessedCommandTargetHost(hostId, cmd);
- Answer answer = _agentMgr.send(targetHostId, cmd);
- return answer;
- }
-
+
@Override
public boolean hasActiveVMSnapshotTasks(Long vmId){
List<VMSnapshotVO> activeVMSnapshots = _vmSnapshotDao.listByInstanceId(vmId,
@@ -617,50 +456,9 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
if(vmSnapshot.getState() == VMSnapshot.State.Allocated){
return _vmSnapshotDao.remove(vmSnapshot.getId());
- }else{
- return deleteSnapshotInternal(vmSnapshot);
- }
- }
-
- @DB
- protected boolean deleteSnapshotInternal(VMSnapshotVO vmSnapshot) {
- UserVmVO userVm = _userVMDao.findById(vmSnapshot.getVmId());
- DeleteVMSnapshotAnswer answer = null;
- try {
- vmSnapshotStateTransitTo(vmSnapshot,VMSnapshot.Event.ExpungeRequested);
- Long hostId = pickRunningHost(vmSnapshot.getVmId());
-
- // prepare snapshotVolumeTos
- List<VolumeTO> volumeTOs = getVolumeTOList(vmSnapshot.getVmId());
-
- // prepare DeleteVMSnapshotCommand
- String vmInstanceName = userVm.getInstanceName();
- VMSnapshotTO parent = getSnapshotWithParents(vmSnapshot).getParent();
- VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(vmSnapshot.getId(), vmSnapshot.getName(), vmSnapshot.getType(),
- vmSnapshot.getCreated().getTime(), vmSnapshot.getDescription(), vmSnapshot.getCurrent(), parent);
- GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId());
- DeleteVMSnapshotCommand deleteSnapshotCommand = new DeleteVMSnapshotCommand(vmInstanceName, vmSnapshotTO, volumeTOs,guestOS.getDisplayName());
-
- answer = (DeleteVMSnapshotAnswer) sendToPool(hostId, deleteSnapshotCommand);
-
- if (answer != null && answer.getResult()) {
- processAnswer(vmSnapshot, userVm, answer, hostId);
- s_logger.debug("Delete VM snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName());
- return true;
- } else {
- s_logger.error("Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + answer.getDetails());
- return false;
- }
- } catch (Exception e) {
- String msg = "Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + e.getMessage();
- s_logger.error(msg , e);
- throw new CloudRuntimeException(e.getMessage());
- } finally{
- if(answer != null && answer.getResult()){
- for (VolumeTO volumeTo : answer.getVolumeTOs()){
- publishUsageEvent(EventTypes.EVENT_VM_SNAPSHOT_DELETE,vmSnapshot,userVm,volumeTo);
- }
- }
+ } else{
+ VMSnapshotStrategy strategy = findVMSnapshotStrategy(vmSnapshot);
+ return strategy.deleteVMSnapshot(vmSnapshot);
}
}
@@ -726,108 +524,24 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
throw new CloudRuntimeException(e.getMessage());
}
}
- hostId = pickRunningHost(userVm.getId());
}
-
- if(hostId == null)
- throw new CloudRuntimeException("Can not find any host to revert snapshot " + vmSnapshotVo.getName());
-
+
// check if there are other active VM snapshot tasks
if (hasActiveVMSnapshotTasks(userVm.getId())) {
throw new InvalidParameterValueException("There is other active vm snapshot tasks on the instance, please try again later");
}
- userVm = _userVMDao.findById(userVm.getId());
- try {
- vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.RevertRequested);
- } catch (NoTransitionException e) {
- throw new CloudRuntimeException(e.getMessage());
- }
- return revertInternal(userVm, vmSnapshotVo, hostId);
- }
-
- private UserVm revertInternal(UserVmVO userVm, VMSnapshotVO vmSnapshotVo, Long hostId) {
- try {
- VMSnapshotVO snapshot = _vmSnapshotDao.findById(vmSnapshotVo.getId());
- // prepare RevertToSnapshotCommand
- List<VolumeTO> volumeTOs = getVolumeTOList(userVm.getId());
- String vmInstanceName = userVm.getInstanceName();
- VMSnapshotTO parent = getSnapshotWithParents(snapshot).getParent();
- VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(snapshot.getId(), snapshot.getName(), snapshot.getType(),
- snapshot.getCreated().getTime(), snapshot.getDescription(), snapshot.getCurrent(), parent);
-
- GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId());
- RevertToVMSnapshotCommand revertToSnapshotCommand = new RevertToVMSnapshotCommand(vmInstanceName, vmSnapshotTO, volumeTOs, guestOS.getDisplayName());
-
- RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) sendToPool(hostId, revertToSnapshotCommand);
- if (answer != null && answer.getResult()) {
- processAnswer(vmSnapshotVo, userVm, answer, hostId);
- s_logger.debug("RevertTo " + vmSnapshotVo.getName() + " succeeded for vm: " + userVm.getInstanceName());
- } else {
- String errMsg = "Revert VM: " + userVm.getInstanceName() + " to snapshot: "+ vmSnapshotVo.getName() + " failed";
- if(answer != null && answer.getDetails() != null)
- errMsg = errMsg + " due to " + answer.getDetails();
- s_logger.error(errMsg);
- // agent report revert operation fails
- vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.OperationFailed);
- throw new CloudRuntimeException(errMsg);
- }
- } catch (Exception e) {
- if(e instanceof AgentUnavailableException){
- try {
- vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.OperationFailed);
- } catch (NoTransitionException e1) {
- s_logger.error("Cannot set vm snapshot state due to: " + e1.getMessage());
- }
- }
- // for other exceptions, do not change VM snapshot state, leave it for snapshotSync
- String errMsg = "revert vm: " + userVm.getInstanceName() + " to snapshot " + vmSnapshotVo.getName() + " failed due to " + e.getMessage();
- s_logger.error(errMsg);
- throw new CloudRuntimeException(e.getMessage());
- }
+ VMSnapshotStrategy strategy = findVMSnapshotStrategy(vmSnapshotVo);
+ strategy.revertVMSnapshot(vmSnapshotVo);
return userVm;
}
-
@Override
public VMSnapshot getVMSnapshotById(Long id) {
VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(id);
return vmSnapshot;
}
- protected Long pickRunningHost(Long vmId) {
- UserVmVO vm = _userVMDao.findById(vmId);
- // use VM's host if VM is running
- if(vm.getState() == State.Running)
- return vm.getHostId();
-
- // check if lastHostId is available
- if(vm.getLastHostId() != null){
- HostVO lastHost = _hostDao.findById(vm.getLastHostId());
- if(lastHost.getStatus() == com.cloud.host.Status.Up && !lastHost.isInMaintenanceStates())
- return lastHost.getId();
- }
-
- List<VolumeVO> listVolumes = _volumeDao.findByInstance(vmId);
- if (listVolumes == null || listVolumes.size() == 0) {
- throw new InvalidParameterValueException("vmInstance has no volumes");
- }
- VolumeVO volume = listVolumes.get(0);
- Long poolId = volume.getPoolId();
- if (poolId == null) {
- throw new InvalidParameterValueException("pool id is not found");
- }
- StoragePoolVO storagePool = _storagePoolDao.findById(poolId);
- if (storagePool == null) {
- throw new InvalidParameterValueException("storage pool is not found");
- }
- List<HostVO> listHost = _hostDao.listAllUpAndEnabledNonHAHosts(Host.Type.Routing, storagePool.getClusterId(), storagePool.getPodId(),
- storagePool.getDataCenterId(), null);
- if (listHost == null || listHost.size() == 0) {
- throw new InvalidParameterValueException("no host in up state is found");
- }
- return listHost.get(0).getId();
- }
@Override
public VirtualMachine getVMBySnapshotId(Long id) {
@@ -851,7 +565,8 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
VMSnapshotVO target = _vmSnapshotDao.findById(snapshot.getId());
if(type != null && target.getType() != type)
continue;
- if (!deleteSnapshotInternal(target)) {
+ VMSnapshotStrategy strategy = findVMSnapshotStrategy(target);
+ if (!strategy.deleteVMSnapshot(target)) {
result = false;
break;
}
@@ -869,12 +584,13 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana
List<VMSnapshotVO> vmSnapshotsInExpungingStates = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging, VMSnapshot.State.Reverting, VMSnapshot.State.Creating);
for (VMSnapshotVO vmSnapshotVO : vmSnapshotsInExpungingStates) {
+ VMSnapshotStrategy strategy = findVMSnapshotStrategy(vmSnapshotVO);
if(vmSnapshotVO.getState() == VMSnapshot.State.Expunging){
- return deleteSnapshotInternal(vmSnapshotVO);
+ return strategy.deleteVMSnapshot(vmSnapshotVO);
}else if(vmSnapshotVO.getState() == VMSnapshot.State.Creating){
- return createVmSnapshotInternal(userVm, vmSnapshotVO, hostId) != null;
+ return strategy.takeVMSnapshot(vmSnapshotVO) != null;
}else if(vmSnapshotVO.getState() == VMSnapshot.State.Reverting){
- return revertInternal(userVm, vmSnapshotVO, hostId) != null;
+ return strategy.revertVMSnapshot(vmSnapshotVO);
}
}
}catch (Exception e) {