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