This is an automated email from the ASF dual-hosted git repository. gabriel pushed a commit to branch snapshot-deletion-issues in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit afd060b54f48744caf4836e4a6334dc1711b2b17 Author: GabrielBrascher <gabr...@apache.org> AuthorDate: Thu Oct 17 17:16:48 2019 -0300 Fixes snapshot deletion --- .../src/test/resources/fakeDriverTestContext.xml | 2 +- .../src/test/resources/storageContext.xml | 2 +- ...tStrategy.java => DefaultSnapshotStrategy.java} | 114 +++++++++++---------- ...ing-engine-storage-snapshot-storage-context.xml | 4 +- 4 files changed, 66 insertions(+), 56 deletions(-) diff --git a/engine/storage/integration-test/src/test/resources/fakeDriverTestContext.xml b/engine/storage/integration-test/src/test/resources/fakeDriverTestContext.xml index 944196d..b8a2274 100644 --- a/engine/storage/integration-test/src/test/resources/fakeDriverTestContext.xml +++ b/engine/storage/integration-test/src/test/resources/fakeDriverTestContext.xml @@ -49,7 +49,7 @@ <bean id="dataStoreProviderManagerImpl" class="org.apache.cloudstack.storage.datastore.provider.DataStoreProviderManagerImpl" /> <bean id="storageCacheManagerImpl" class="org.apache.cloudstack.storage.cache.manager.StorageCacheManagerImpl" /> <bean id="storageCacheRandomAllocator" class="org.apache.cloudstack.storage.cache.allocator.StorageCacheRandomAllocator" /> - <bean id="xenserverSnapshotStrategy" class="org.apache.cloudstack.storage.snapshot.XenserverSnapshotStrategy" /> + <bean id="defaultSnapshotStrategy" class="org.apache.cloudstack.storage.snapshot.DefaultSnapshotStrategy" /> <bean id="bAREMETAL" class="org.apache.cloudstack.storage.image.format.BAREMETAL" /> <bean id="dataMotionServiceImpl" class="org.apache.cloudstack.storage.motion.DataMotionServiceImpl" /> <bean id="dataObjectManagerImpl" class="org.apache.cloudstack.storage.datastore.DataObjectManagerImpl" /> diff --git a/engine/storage/integration-test/src/test/resources/storageContext.xml b/engine/storage/integration-test/src/test/resources/storageContext.xml index abf0876..f65e2ac 100644 --- a/engine/storage/integration-test/src/test/resources/storageContext.xml +++ b/engine/storage/integration-test/src/test/resources/storageContext.xml @@ -50,7 +50,7 @@ <bean id="ancientDataMotionStrategy" class="org.apache.cloudstack.storage.motion.AncientDataMotionStrategy" /> <bean id="storageCacheManagerImpl" class="org.apache.cloudstack.storage.cache.manager.StorageCacheManagerImpl" /> <bean id="storageCacheRandomAllocator" class="org.apache.cloudstack.storage.cache.allocator.StorageCacheRandomAllocator" /> - <bean id="xenserverSnapshotStrategy" class="org.apache.cloudstack.storage.snapshot.XenserverSnapshotStrategy" /> + <bean id="defaultSnapshotStrategy" class="org.apache.cloudstack.storage.snapshot.DefaultSnapshotStrategy" /> <bean id="bAREMETAL" class="org.apache.cloudstack.storage.image.format.BAREMETAL" /> <bean id="dataMotionServiceImpl" class="org.apache.cloudstack.storage.motion.DataMotionServiceImpl" /> <bean id="dataObjectManagerImpl" class="org.apache.cloudstack.storage.datastore.DataObjectManagerImpl" /> diff --git a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/DefaultSnapshotStrategy.java similarity index 84% rename from engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java rename to engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/DefaultSnapshotStrategy.java index 3ab2129..2651162 100644 --- a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java +++ b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/DefaultSnapshotStrategy.java @@ -34,7 +34,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.jobs.AsyncJob; -import org.apache.cloudstack.framework.jobs.dao.SyncQueueItemDao; import org.apache.cloudstack.storage.command.CreateObjectAnswer; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; @@ -72,8 +71,8 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; @Component -public class XenserverSnapshotStrategy extends SnapshotStrategyBase { - private static final Logger s_logger = Logger.getLogger(XenserverSnapshotStrategy.class); +public class DefaultSnapshotStrategy extends SnapshotStrategyBase { + private static final Logger s_logger = Logger.getLogger(DefaultSnapshotStrategy.class); @Inject SnapshotService snapshotSvr; @@ -90,12 +89,8 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase { @Inject SnapshotDataFactory snapshotDataFactory; @Inject - private SnapshotDao _snapshotDao; - @Inject private SnapshotDetailsDao _snapshotDetailsDao; @Inject - private SyncQueueItemDao _syncQueueItemDao; - @Inject VolumeDetailsDao _volumeDetailsDaoImpl; @Override @@ -269,63 +264,78 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase { throw new InvalidParameterValueException("Can't delete snapshotshot " + snapshotId + " due to it is in " + snapshotVO.getState() + " Status"); } - // first mark the snapshot as destroyed, so that ui can't see it, but we - // may not destroy the snapshot on the storage, as other snapshots may - // depend on it. SnapshotInfo snapshotOnImage = snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Image); - if (snapshotOnImage == null) { - s_logger.debug("Can't find snapshot on backup storage, delete it in db"); - snapshotDao.remove(snapshotId); - return true; - } - - SnapshotObject obj = (SnapshotObject)snapshotOnImage; - try { - obj.processEvent(Snapshot.Event.DestroyRequested); - List<VolumeDetailVO> volumesFromSnapshot; - volumesFromSnapshot = _volumeDetailsDaoImpl.findDetails("SNAPSHOT_ID", String.valueOf(snapshotId), null); - if (volumesFromSnapshot.size() > 0) { - try { - obj.processEvent(Snapshot.Event.OperationFailed); - } catch (NoTransitionException e1) { - s_logger.debug("Failed to change snapshot state: " + e1.toString()); + boolean deletedOnSecondary = false; + if (snapshotOnImage == null) { + s_logger.debug(String.format("Can't find snapshot [snapshot id: %d] on backup storage")); + } else { + SnapshotObject obj = (SnapshotObject)snapshotOnImage; + try { + deletedOnSecondary = deleteSnapshotOnSecundaryStorage(snapshotId, snapshotOnImage, obj); + if (!deletedOnSecondary) { + s_logger.debug( + String.format("Failed to find/delete snapshot (id: %d) on secondary storage. Still necessary to check and delete snapshot on primary storage.", + snapshotId)); + } else { + s_logger.debug(String.format("Snapshot (id: %d) has been deleted on secondary storage.", snapshotId)); } - throw new InvalidParameterValueException("Unable to perform delete operation, Snapshot with id: " + snapshotId + " is in use "); + } catch (NoTransitionException e) { + s_logger.debug("Failed to set the state to destroying: ", e); + return false; } - } catch (NoTransitionException e) { - s_logger.debug("Failed to set the state to destroying: ", e); - return false; } - try { - boolean result = deleteSnapshotChain(snapshotOnImage); - obj.processEvent(Snapshot.Event.OperationSucceeded); - if (result) { - //snapshot is deleted on backup storage, need to delete it on primary storage - SnapshotDataStoreVO snapshotOnPrimary = snapshotStoreDao.findBySnapshot(snapshotId, DataStoreRole.Primary); - if (snapshotOnPrimary != null) { - SnapshotInfo snapshotOnPrimaryInfo = snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary); - long volumeId = snapshotOnPrimary.getVolumeId(); - VolumeVO volumeVO = volumeDao.findById(volumeId); - if (((PrimaryDataStoreImpl)snapshotOnPrimaryInfo.getDataStore()).getPoolType() == StoragePoolType.RBD && volumeVO != null) { - snapshotSvr.deleteSnapshot(snapshotOnPrimaryInfo); - } - snapshotOnPrimary.setState(State.Destroyed); - snapshotStoreDao.update(snapshotOnPrimary.getId(), snapshotOnPrimary); - } - } - } catch (Exception e) { - s_logger.debug("Failed to delete snapshot: ", e); + boolean deletedOnPrimary = deleteSnapshotOnPrimary(snapshotId); + if (deletedOnPrimary) { + s_logger.debug(String.format("Successfully deleted snapshot (id: %d) on primary storage.", snapshotId)); + } else if (deletedOnSecondary) { + s_logger.debug(String.format("The snapshot was deleted on secondary storage. Could not find/delete snapshot (id: %d) on primary storage.", snapshotId)); + } + return deletedOnSecondary || deletedOnPrimary; + } + + /** + * Deletes the snapshot on secondary storage. + * It can return false when the snapshot was stored on primary storage and not backed up on secondary; therefore, the snapshot should also be deleted on primary storage even when this method returns false. + */ + private boolean deleteSnapshotOnSecundaryStorage(Long snapshotId, SnapshotInfo snapshotOnImage, SnapshotObject obj) throws NoTransitionException { + obj.processEvent(Snapshot.Event.DestroyRequested); + List<VolumeDetailVO> volumesFromSnapshot; + volumesFromSnapshot = _volumeDetailsDaoImpl.findDetails("SNAPSHOT_ID", String.valueOf(snapshotId), null); + + if (volumesFromSnapshot.size() > 0) { try { obj.processEvent(Snapshot.Event.OperationFailed); } catch (NoTransitionException e1) { - s_logger.debug("Failed to change snapshot state: " + e.toString()); + s_logger.debug("Failed to change snapshot state: " + e1.toString()); } - return false; + throw new InvalidParameterValueException("Unable to perform delete operation, Snapshot with id: " + snapshotId + " is in use "); } - return true; + boolean result = deleteSnapshotChain(snapshotOnImage); + obj.processEvent(Snapshot.Event.OperationSucceeded); + return result; + } + + /** + * Deletes the snapshot on primary storage. It can return false when the snapshot was not stored on primary storage; however this does not means that it failed to delete the snapshot. </br> + * In case of failure, it will throw one of the following exceptions: CloudRuntimeException, InterruptedException, or ExecutionException. </br> + */ + private boolean deleteSnapshotOnPrimary(Long snapshotId) { + boolean result = false; + SnapshotDataStoreVO snapshotOnPrimary = snapshotStoreDao.findBySnapshot(snapshotId, DataStoreRole.Primary); + if (snapshotOnPrimary != null) { + SnapshotInfo snapshotOnPrimaryInfo = snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary); + long volumeId = snapshotOnPrimary.getVolumeId(); + VolumeVO volumeVO = volumeDao.findById(volumeId); + if (((PrimaryDataStoreImpl)snapshotOnPrimaryInfo.getDataStore()).getPoolType() == StoragePoolType.RBD && volumeVO != null) { + result = snapshotSvr.deleteSnapshot(snapshotOnPrimaryInfo); + } + snapshotOnPrimary.setState(State.Destroyed); + snapshotStoreDao.update(snapshotOnPrimary.getId(), snapshotOnPrimary); + } + return result; } @Override diff --git a/engine/storage/snapshot/src/main/resources/META-INF/cloudstack/storage/spring-engine-storage-snapshot-storage-context.xml b/engine/storage/snapshot/src/main/resources/META-INF/cloudstack/storage/spring-engine-storage-snapshot-storage-context.xml index b295398..2bfb3c3 100644 --- a/engine/storage/snapshot/src/main/resources/META-INF/cloudstack/storage/spring-engine-storage-snapshot-storage-context.xml +++ b/engine/storage/snapshot/src/main/resources/META-INF/cloudstack/storage/spring-engine-storage-snapshot-storage-context.xml @@ -27,8 +27,8 @@ http://www.springframework.org/schema/context/spring-context.xsd" > - <bean id="xenserverSnapshotStrategy" - class="org.apache.cloudstack.storage.snapshot.XenserverSnapshotStrategy" /> + <bean id="defaultSnapshotStrategy" + class="org.apache.cloudstack.storage.snapshot.DefaultSnapshotStrategy" /> <bean id="storageSystemSnapshotStrategy" class="org.apache.cloudstack.storage.snapshot.StorageSystemSnapshotStrategy" />