def _handle_busy_snapshot(self, vserver_client, share_name, snapshot_name, wait_seconds=60): """Checks for and handles a busy snapshot. If a snapshot is not busy, take no action. If a snapshot is busy for reasons other than a clone dependency, raise immediately. Otherwise, since we always start a clone split operation after cloning a share, wait up to a minute for a clone dependency to clear before giving up. """ snapshot = vserver_client.get_snapshot(share_name, snapshot_name) if not snapshot['busy']: return # Fail fast if snapshot is not busy due to a clone dependency if snapshot['owners'] != {'volume clone'}: raise exception.ShareSnapshotIsBusy(snapshot_name=snapshot_name) # Wait for clone dependency to clear. retry_interval = 3 # seconds for retry in range(int(wait_seconds / retry_interval)): LOG.debug('Snapshot %(snap)s for share %(share)s is busy, waiting ' 'for volume clone dependency to clear.', {'snap': snapshot_name, 'share': share_name}) time.sleep(retry_interval) snapshot = vserver_client.get_snapshot(share_name, snapshot_name) if not snapshot['busy']: return raise exception.ShareSnapshotIsBusy(snapshot_name=snapshot_name)
def _delete_share(self, share, is_snapshot): if is_snapshot: dataset_name = self._make_snapshot_name(share) else: dataset_name = self._make_share_name(share) try: infinidat_filesystem = ( self._get_infinidat_filesystem_by_name(dataset_name)) except exception.ShareResourceNotFound: message = ("share %(share)s not found on Infinibox, skipping " "delete") LOG.warning(message, {"share": share}) return # filesystem not found if infinidat_filesystem.has_children(): # can't delete a filesystem that has a live snapshot if is_snapshot: raise exception.ShareSnapshotIsBusy(snapshot_name=dataset_name) else: reason = _("share has snapshots and cannot be deleted") raise exception.ShareBusyException(reason=reason) try: infinidat_export = self._get_export(infinidat_filesystem) except exception.ShareBackendException: # it's possible that the export has been deleted pass else: infinidat_export.safe_delete() infinidat_filesystem.safe_delete()
def delete_snapshot(self, context, snapshot, share_server=None): """Deletes a snapshot of a share.""" share_name = self._get_valid_share_name(snapshot['share_id']) snapshot_name = self._get_valid_snapshot_name(snapshot['id']) if self._is_snapshot_busy(share_name, snapshot_name): raise exception.ShareSnapshotIsBusy(snapshot_name=snapshot_name) args = {'snapshot': snapshot_name, 'volume': share_name} LOG.debug('Deleting snapshot %s' % snapshot_name) self._client.send_request('snapshot-delete', args)
def delete_snapshot(self, context, snapshot, share_server=None): """Delete a snapshot. Snapshots with existing clones cannot be deleted. """ LOG.debug("ZFSSAShareDriver.delete_snapshot: id=%s", snapshot['id']) lcfg = self.configuration has_clones = self.zfssa.has_clones(lcfg.zfssa_pool, lcfg.zfssa_project, snapshot['share_id'], snapshot['id']) if has_clones: LOG.error(_LE("snapshot %s: has clones"), snapshot['id']) raise exception.ShareSnapshotIsBusy(snapshot_name=snapshot['id']) self.zfssa.delete_snapshot(lcfg.zfssa_pool, lcfg.zfssa_project, snapshot['share_id'], snapshot['id'])
def test_delete_snapshot_busy(self): vserver_client = mock.Mock() self.mock_object( self.library, '_get_vserver', mock.Mock(return_value=(fake.VSERVER1, vserver_client))) mock_handle_busy_snapshot = self.mock_object( self.library, '_handle_busy_snapshot', mock.Mock(side_effect=exception.ShareSnapshotIsBusy( snapshot_name=fake.SNAPSHOT_NAME))) self.assertRaises(exception.ShareSnapshotIsBusy, self.library.delete_snapshot, self.context, fake.SNAPSHOT, share_server=fake.SHARE_SERVER) self.assertTrue(mock_handle_busy_snapshot.called) self.assertFalse(vserver_client.delete_snapshot.called)
def _fake_delete_snapshot(self, *args, **kwargs): raise exception.ShareSnapshotIsBusy(snapshot_name='fakename')
def _raise_share_snapshot_is_busy(self, *args, **kwargs): raise exception.ShareSnapshotIsBusy(snapshot_name='fakename')