diff --git a/engine/schema/src/com/cloud/storage/dao/SnapshotDao.java b/engine/schema/src/com/cloud/storage/dao/SnapshotDao.java index ff2e4457441d..586cd5f1dcea 100644 --- a/engine/schema/src/com/cloud/storage/dao/SnapshotDao.java +++ b/engine/schema/src/com/cloud/storage/dao/SnapshotDao.java @@ -57,6 +57,8 @@ public interface SnapshotDao extends GenericDao, StateDao listAllByStatus(Snapshot.State... status); + List listAllByStatusIncludingRemoved(Snapshot.State... status); + void updateVolumeIds(long oldVolId, long newVolId); } diff --git a/engine/schema/src/com/cloud/storage/dao/SnapshotDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/SnapshotDaoImpl.java index 84a92d7bf0d0..605766ec39ba 100644 --- a/engine/schema/src/com/cloud/storage/dao/SnapshotDaoImpl.java +++ b/engine/schema/src/com/cloud/storage/dao/SnapshotDaoImpl.java @@ -316,6 +316,13 @@ public List listAllByStatus(Snapshot.State... status) { return listBy(sc, null); } + @Override + public List listAllByStatusIncludingRemoved(Snapshot.State... status) { + SearchCriteria sc = this.StatusSearch.create(); + sc.setParameters("status", (Object[])status); + return listIncludingRemovedBy(sc, null); + } + @Override public boolean updateState(State currentState, Event event, State nextState, SnapshotVO snapshot, Object data) { TransactionLegacy txn = TransactionLegacy.currentTxn(); diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java index b1d6127e2430..8b0f933a318d 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.storage.datastore; +import java.util.UUID; + import javax.inject.Inject; import org.apache.log4j.Logger; @@ -44,6 +46,7 @@ import com.cloud.agent.api.to.DataObjectType; import com.cloud.agent.api.to.S3TO; import com.cloud.exception.ConcurrentOperationException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.DataStoreRole; import com.cloud.storage.SnapshotVO; import com.cloud.storage.VMTemplateStoragePoolVO; @@ -172,7 +175,11 @@ public DataObject create(DataObject obj, DataStore dataStore) { if (snapshotDataStoreVO != null) { ss.setParentSnapshotId(snapshotDataStoreVO.getSnapshotId()); } - ss.setInstallPath(TemplateConstants.DEFAULT_SNAPSHOT_ROOT_DIR + "/" + snapshotDao.findById(obj.getId()).getAccountId() + "/" + snapshot.getVolumeId()); + String snapshotInstallPath = TemplateConstants.DEFAULT_SNAPSHOT_ROOT_DIR + "/" + snapshotDao.findById(obj.getId()).getAccountId() + "/" + snapshot.getVolumeId(); + if (snapshot.getHypervisorType().equals(HypervisorType.VMware)) { + snapshotInstallPath = snapshotInstallPath.concat("/" + UUID.randomUUID().toString()); + } + ss.setInstallPath(snapshotInstallPath); ss.setState(ObjectInDataStoreStateMachine.State.Allocated); ss = snapshotDataStoreDao.persist(ss); break; @@ -265,7 +272,8 @@ public boolean deleteIfNotReady(DataObject dataObj) { return true; case SNAPSHOT: SnapshotDataStoreVO destSnapshotStore = snapshotDataStoreDao.findByStoreSnapshot(dataStore.getRole(), dataStore.getId(), objId); - if (destSnapshotStore != null && destSnapshotStore.getState() != ObjectInDataStoreStateMachine.State.Ready) { + if (destSnapshotStore != null && destSnapshotStore.getState() != ObjectInDataStoreStateMachine.State.Ready && + destSnapshotStore.getState() != ObjectInDataStoreStateMachine.State.Allocated) { return snapshotDataStoreDao.remove(destSnapshotStore.getId()); } else { s_logger.warn("Snapshot " + objId + " is not found on image store " + dataStore.getId() + ", so no need to delete"); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java index 84f7fc0d95ac..0182db0e9ec1 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java @@ -1351,10 +1351,10 @@ public DeleteVMSnapshotAnswer execute(VmwareHostService hostService, DeleteVMSna s_logger.debug("snapshot: " + vmSnapshotName + " is removed"); // after removed snapshot, the volumes' paths have been changed for the VM, needs to report new paths to manager - - Map mapNewDisk = getNewDiskMap(vmMo); - - setVolumeToPathAndSize(listVolumeTo, mapNewDisk, context, hyperHost, cmd.getVmName()); + if (listVolumeTo != null) { + Map mapNewDisk = getNewDiskMap(vmMo); + setVolumeToPathAndSize(listVolumeTo, mapNewDisk, context, hyperHost, cmd.getVmName()); + } return new DeleteVMSnapshotAnswer(cmd, listVolumeTo); } diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index 72956855974d..9d5057fdb0f7 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -1094,8 +1094,8 @@ private Pair exportVolumeToSecondaryStroage(VirtualMachineMO v // Ternary private Ternary backupSnapshotToSecondaryStorage(VirtualMachineMO vmMo, String installPath, String volumePath, String snapshotUuid, String secStorageUrl, String prevSnapshotUuid, String prevBackupUuid, String workerVmName) throws Exception { - - String backupUuid = UUID.randomUUID().toString(); + String backupUuid = installPath.substring(installPath.lastIndexOf("/") + 1); + installPath = installPath.substring(0, installPath.lastIndexOf("/")); Pair snapshotInfo = exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, installPath, backupUuid, workerVmName); return new Ternary(backupUuid, snapshotInfo.first(), snapshotInfo.second()); } @@ -1184,7 +1184,7 @@ public Answer backupSnapshot(CopyCommand cmd) { // Get snapshot physical size long physicalSize = 0l; String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl); - String snapshotDir = destSnapshot.getPath() + "/" + snapshotBackupUuid; + String snapshotDir = destSnapshot.getPath(); File[] files = new File(secondaryMountPoint + "/" + snapshotDir).listFiles(); if(files != null) { for(File file : files) { diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 2c70b170dc30..51767093ab06 100644 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -98,7 +98,10 @@ import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.DeleteSnapshotsDirCommand; +import com.cloud.agent.api.DeleteVMSnapshotCommand; import com.cloud.agent.api.StoragePoolInfo; +import com.cloud.agent.api.VMSnapshotTO; import com.cloud.agent.manager.Commands; import com.cloud.api.ApiDBUtils; import com.cloud.api.query.dao.TemplateJoinDao; @@ -1120,14 +1123,60 @@ public void cleanupStorage(boolean recurring) { } // remove snapshots in Error state - List snapshots = _snapshotDao.listAllByStatus(Snapshot.State.Error); + List snapshots = _snapshotDao.listAllByStatusIncludingRemoved(Snapshot.State.Error); for (SnapshotVO snapshotVO : snapshots) { try { List storeRefs = _snapshotStoreDao.findBySnapshotId(snapshotVO.getId()); + boolean isVMware = snapshotVO.getHypervisorType().equals(HypervisorType.VMware); + boolean removeSnapshot = true; for (SnapshotDataStoreVO ref : storeRefs) { - _snapshotStoreDao.expunge(ref.getId()); + // Cleanup corresponding items (if any) from secondary storage. + if (isVMware) { + if(ref.getRole().isImageStore()) { // Delete items from secondary storage + DataStore snapshotDataStore = _dataStoreMgr.getDataStore(ref.getDataStoreId(), DataStoreRole.Image); + DeleteSnapshotsDirCommand cmd = new DeleteSnapshotsDirCommand(snapshotDataStore.getTO(), ref.getInstallPath()); + EndPoint ep = _epSelector.select(snapshotDataStore); + if (ep == null) { + s_logger.warn("There is no secondary storage VM for image store: " + snapshotDataStore.getName() + ", cannot cleanup snapshot: " + snapshotVO.getUuid()); + removeSnapshot = false; + continue; + } + Answer deleteSnapshotsDirAnswer = ep.sendMessage(cmd); + if ((deleteSnapshotsDirAnswer != null) && deleteSnapshotsDirAnswer.getResult()) { + s_logger.debug("Deleted snapshot: " + snapshotVO.getUuid() + " from secondary storage: " + snapshotDataStore.getName()); + _snapshotStoreDao.expunge(ref.getId()); + } else { + s_logger.warn("Failed to delete snapshot: " + snapshotVO.getUuid() + " from secondary storage: " + snapshotDataStore.getName()); + removeSnapshot = false; + } + } else if (ref.getRole() == DataStoreRole.Primary) { // Delete worker VM snapshot + VolumeVO volume = _volumeDao.findByIdIncludingRemoved(snapshotVO.getVolumeId()); + if (volume.getInstanceId() == null) + continue; + VMInstanceVO vm = _vmInstanceDao.findById(volume.getInstanceId()); + Long hostId = vm.getHostId() != null ? vm.getHostId() : vm.getLastHostId(); + if (hostId != null) { + VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(); + vmSnapshotTO.setSnapshotName(ref.getInstallPath()); + vmSnapshotTO.setDescription(snapshotVO.getName()); + DeleteVMSnapshotCommand deleteSnapshotCommand = new DeleteVMSnapshotCommand(vm.getInstanceName(), vmSnapshotTO, null, null); + Answer deleteSnapshotAnswer = _agentMgr.send(hostId, deleteSnapshotCommand); + if ((deleteSnapshotAnswer != null) && deleteSnapshotAnswer.getResult()) { + s_logger.debug("Deleted worker VM snapshot: " + snapshotVO.getName()); + _snapshotStoreDao.expunge(ref.getId()); + } else { + s_logger.warn("Failed to delete worker VM snapshot: " + snapshotVO.getName()); + removeSnapshot = false; + } + } + } + } else { + _snapshotStoreDao.expunge(ref.getId()); + } + } + if (removeSnapshot) { + _snapshotDao.expunge(snapshotVO.getId()); } - _snapshotDao.expunge(snapshotVO.getId()); } catch (Exception e) { s_logger.warn("Unable to destroy snapshot " + snapshotVO.getUuid(), e); }