Beispiel #1
0
 def delete_snapshot(self, snapshot):
     ldev = self.get_ldev(snapshot)
     if ldev is None:
         LOG.warning(
             basic_lib.set_msg(304,
                               method='delete_snapshot',
                               id=snapshot['id']))
         return
     self.add_volinfo(ldev, id=snapshot['id'], type='snapshot')
     if not self.volume_info[ldev]['in_use'].lock.acquire(False):
         desc = self.volume_info[ldev]['in_use'].desc
         basic_lib.output_err(660, desc=desc)
         raise exception.SnapshotIsBusy(snapshot_name=snapshot['name'])
     try:
         is_vvol = self.get_snapshot_is_vvol(snapshot)
         try:
             self.delete_ldev(ldev, is_vvol)
         except exception.HBSDNotFound:
             with self.volinfo_lock:
                 if ldev in self.volume_info:
                     self.volume_info.pop(ldev)
             LOG.warning(
                 basic_lib.set_msg(305, type='snapshot', id=snapshot['id']))
         except exception.HBSDBusy:
             raise exception.SnapshotIsBusy(snapshot_name=snapshot['name'])
     finally:
         if ldev in self.volume_info:
             self.volume_info[ldev]['in_use'].lock.release()
Beispiel #2
0
    def test_delete_no_dev_fails(self):
        """Test delete snapshot with no dev file fails."""
        self.mock_object(os.path, 'exists', lambda x: False)
        self.volume.driver.vg = fake_lvm.FakeBrickLVM('cinder-volumes',
                                                      False,
                                                      None,
                                                      'default')

        volume = tests_utils.create_volume(self.context, **self.volume_params)
        volume_id = volume['id']
        self.volume.create_volume(self.context, volume)
        snapshot = create_snapshot(volume_id)
        snapshot_id = snapshot.id
        self.volume.create_snapshot(self.context, snapshot)

        with mock.patch.object(self.volume.driver, 'delete_snapshot',
                               side_effect=exception.SnapshotIsBusy(
                                   snapshot_name='fake')) as mock_del_snap:
            self.volume.delete_snapshot(self.context, snapshot)
            snapshot_ref = objects.Snapshot.get_by_id(self.context,
                                                      snapshot_id)
            self.assertEqual(snapshot_id, snapshot_ref.id)
            self.assertEqual(fields.SnapshotStatus.AVAILABLE,
                             snapshot_ref.status)
            mock_del_snap.assert_called_once_with(snapshot)
Beispiel #3
0
 def delete_vol_or_snap(self,
                        volume_url,
                        volume_name='',
                        ignore_non_exist=False):
     try:
         try:
             volume = self._get_volume(volume_url)
         except sushy_exceptions.ResourceNotFoundError:
             if ignore_non_exist:
                 LOG.warning("Deleted non existent vol/snap %s", volume_url)
             else:
                 raise
         if volume.links.endpoints:
             LOG.warning("Delete vol/snap failed, attached: %s", volume_url)
             raise exception.VolumeIsBusy(_("Volume is already attached"),
                                          volume_name=volume_name)
         volume.delete()
     except sushy_exceptions.BadRequestError as e:
         try:
             msg = e.body['@Message.ExtendedInfo'][0]['Message']
             if (msg == "Cannot delete source snapshot volume when "
                     "other clone volumes are based on this snapshot."):
                 LOG.warning("Delete vol/snap failed, has-deps: %s",
                             volume_url)
                 raise exception.SnapshotIsBusy(snapshot_name=volume_name)
         except Exception:
             LOG.exception("Delete vol/snap failed")
             raise exception.VolumeBackendAPIException(
                 data=(_('Unable to delete volume %s.') % volume_url))
     except Exception:
         LOG.exception("Delete vol/snap failed")
         raise exception.VolumeBackendAPIException(
             data=(_('Unable to delete volume %s.') % volume_url))
     LOG.info("RSD volume deleted: %s", volume_url)
Beispiel #4
0
    def delete_snapshot(self, snapshot):
        """Deletes an rbd snapshot."""
        # NOTE(dosaboy): this was broken by commit cbe1d5f. Ensure names are
        #                utf-8 otherwise librbd will barf.
        volume_name = utils.convert_str(snapshot['volume_name'])
        snap_name = utils.convert_str(snapshot['name'])

        with RBDVolumeProxy(self, volume_name) as volume:
            try:
                volume.unprotect_snap(snap_name)
            except self.rbd.ImageBusy:
                children_list = self._get_children_info(volume, snap_name)

                if children_list:
                    for (pool, image) in children_list:
                        LOG.info(
                            _LI('Image %(pool)s/%(image)s is dependent '
                                'on the snapshot %(snap)s.'), {
                                    'pool': pool,
                                    'image': image,
                                    'snap': snap_name
                                })

                raise exception.SnapshotIsBusy(snapshot_name=snap_name)
            volume.remove_snap(snap_name)
    def test_create_cgsnapshot_busy_snapshot(self):
        snapshot = fake.CG_SNAPSHOT
        snapshot['volume'] = fake.CG_VOLUME

        mock_extract_host = self.mock_object(volume_utils,
                                             'extract_host',
                                             return_value=fake.POOL_NAME)
        mock_clone_lun = self.mock_object(self.library, '_clone_lun')
        mock_busy = self.mock_object(self.zapi_client,
                                     'wait_for_busy_snapshot')
        mock_busy.side_effect = exception.SnapshotIsBusy(snapshot['name'])
        mock_delete_snapshot = self.mock_object(self.zapi_client,
                                                'delete_snapshot')
        mock_mark_snapshot_for_deletion = self.mock_object(
            self.zapi_client, 'mark_snapshot_for_deletion')

        self.library.create_cgsnapshot(fake.CG_SNAPSHOT, [snapshot])

        mock_extract_host.assert_called_once_with(fake.CG_VOLUME['host'],
                                                  level='pool')
        self.zapi_client.create_cg_snapshot.assert_called_once_with(
            set([fake.POOL_NAME]), fake.CG_SNAPSHOT_ID)
        mock_clone_lun.assert_called_once_with(
            fake.CG_VOLUME_NAME,
            fake.CG_SNAPSHOT_NAME,
            source_snapshot=fake.CG_SNAPSHOT_ID)
        mock_delete_snapshot.assert_not_called()
        mock_mark_snapshot_for_deletion.assert_called_once_with(
            fake.POOL_NAME, fake.CG_SNAPSHOT_ID)
Beispiel #6
0
        def _wait_for_snap_delete(snapshot, start_time):
            # defining CLI command
            snapshotname = snapshot['name']
            volumename = snapshot['volume_name']
            snap_destroy = ('snap', '-destroy', '-id', snapshotname, '-o')
            # executing CLI command
            out, rc = self._cli_execute(*snap_destroy)

            LOG.debug('Delete Snapshot: Volume: %(volumename)s  Snapshot: '
                      '%(snapshotname)s  Output: %(out)s'
                      % {'volumename': volumename,
                         'snapshotname': snapshotname,
                         'out': out})

            if rc not in [0, 9, 5]:
                if rc == 13:
                    if int(time.time()) - start_time < \
                            self.timeout * 60:
                        LOG.info(_('Snapshot %s is in use'), snapshotname)
                    else:
                        msg = (_('Failed to destroy %s '
                               ' because snapshot is in use.'), snapshotname)
                        LOG.error(msg)
                        raise exception.SnapshotIsBusy(data=msg)
                else:
                    msg = (_('Failed to destroy %s'), snapshotname)
                    LOG.error(msg)
                    raise exception.VolumeBackendAPIException(data=msg)
            else:
                raise loopingcall.LoopingCallDone()
Beispiel #7
0
    def test_delete_busy_snapshot(self, mock_clean):
        """Test snapshot can be created and deleted."""

        self.volume.driver.vg = fake_lvm.FakeBrickLVM('cinder-volumes', False,
                                                      None, 'default')

        volume = tests_utils.create_volume(self.context, **self.volume_params)
        volume_id = volume['id']
        self.volume.create_volume(self.context, volume)
        snapshot = create_snapshot(volume_id, size=volume['size'])
        self.volume.create_snapshot(self.context, snapshot)

        with mock.patch.object(self.volume.driver,
                               'delete_snapshot',
                               side_effect=exception.SnapshotIsBusy(
                                   snapshot_name='fake')) as mock_del_snap:
            snapshot_id = snapshot.id
            self.volume.delete_snapshot(self.context, snapshot)
            snapshot_ref = objects.Snapshot.get_by_id(self.context,
                                                      snapshot_id)
            self.assertEqual(snapshot_id, snapshot_ref.id)
            self.assertEqual(fields.SnapshotStatus.AVAILABLE,
                             snapshot_ref.status)
            mock_del_snap.assert_called_once_with(snapshot)
        mock_clean.assert_not_called()
Beispiel #8
0
    def test_create_cgsnapshot_busy_snapshot(self):
        snapshot = fake.CG_SNAPSHOT
        snapshot['volume'] = fake.CG_VOLUME
        mock_get_snapshot_flexvols = self.mock_object(
            self.driver, '_get_flexvol_names_from_hosts')
        mock_get_snapshot_flexvols.return_value = (set([fake.CG_POOL_NAME]))
        mock_clone_backing_file = self.mock_object(
            self.driver, '_clone_backing_file_for_volume')
        mock_busy = self.mock_object(
            self.driver.zapi_client, 'wait_for_busy_snapshot')
        mock_busy.side_effect = exception.SnapshotIsBusy(snapshot['name'])
        mock_mark_snapshot_for_deletion = self.mock_object(
            self.driver.zapi_client, 'mark_snapshot_for_deletion')

        self.driver.create_cgsnapshot(
            fake.CG_CONTEXT, fake.CG_SNAPSHOT, [snapshot])

        mock_get_snapshot_flexvols.assert_called_once_with(
            [snapshot['volume']['host']])
        self.driver.zapi_client.create_cg_snapshot.assert_called_once_with(
            set([fake.CG_POOL_NAME]), fake.CG_SNAPSHOT_ID)
        mock_clone_backing_file.assert_called_once_with(
            snapshot['volume']['name'], snapshot['name'],
            snapshot['volume']['id'], source_snapshot=fake.CG_SNAPSHOT_ID)
        mock_busy.assert_called_once_with(
            fake.CG_POOL_NAME, fake.CG_SNAPSHOT_ID)
        self.driver.zapi_client.delete_snapshot.assert_not_called()
        mock_mark_snapshot_for_deletion.assert_called_once_with(
            fake.CG_POOL_NAME, fake.CG_SNAPSHOT_ID)
Beispiel #9
0
    def _gc_delete(self, vname):
        """Delete volume and its hidden parents

        Deletes volume by going recursively to the first active
        parent and cals recursive deletion on storage side
        """
        vol = None
        try:
            vol = self.ra.get_lun(vname)
        except jexc.JDSSResourceNotFoundException:
            LOG.debug('volume %s does not exist, it was already '
                      'deleted.', vname)
            return
        except jexc.JDSSException as err:
            raise exception.VolumeBackendAPIException(err)

        if vol['is_clone']:
            self._delete_back_recursively(jcom.origin_volume(vol['origin']),
                                          jcom.origin_snapshot(vol['origin']))
        else:
            try:
                self.ra.delete_lun(vname)
            except jexc.JDSSRESTException as err:
                LOG.debug(
                    "Unable to delete physical volume %(volume)s "
                    "with error %(err)s.", {
                        "volume": vname,
                        "err": err})
                raise exception.SnapshotIsBusy(err)
Beispiel #10
0
 def delete_snapshot(self, snapshot):
     """Deletes an rbd snapshot."""
     with RBDVolumeProxy(self, snapshot['volume_name']) as volume:
         snap = str(snapshot['name'])
         if self._supports_layering():
             try:
                 volume.unprotect_snap(snap)
             except self.rbd.ImageBusy:
                 raise exception.SnapshotIsBusy(snapshot_name=snap)
         volume.remove_snap(snap)
Beispiel #11
0
 def delete_snapshot(self, snapshot):
     """Deletes an rbd snapshot"""
     if self._supports_layering():
         try:
             self._try_execute('rbd', 'snap', 'unprotect', '--pool',
                               FLAGS.rbd_pool, '--snap', snapshot['name'],
                               snapshot['volume_name'])
         except exception.ProcessExecutionError:
             raise exception.SnapshotIsBusy(snapshot_name=snapshot['name'])
     self._try_execute('rbd', 'snap', 'rm', '--pool', FLAGS.rbd_pool,
                       '--snap', snapshot['name'], snapshot['volume_name'])
Beispiel #12
0
 def delete_snapshot(self, snapshot):
     """Deletes an rbd snapshot."""
     # NOTE(dosaboy): this was broken by commit cbe1d5f. Ensure names are
     #                utf-8 otherwise librbd will barf.
     volume_name = encodeutils.safe_encode(snapshot['volume_name'])
     snap_name = encodeutils.safe_encode(snapshot['name'])
     with RBDVolumeProxy(self, volume_name) as volume:
         try:
             volume.unprotect_snap(snap_name)
         except self.rbd.ImageBusy:
             raise exception.SnapshotIsBusy(snapshot_name=snap_name)
         volume.remove_snap(snap_name)
Beispiel #13
0
 def delete_snapshot(self, snapshot):
     """Delete the specified snapshot."""
     ldev = utils.get_ldev(snapshot)
     if ldev is None:
         utils.output_log(MSG.INVALID_LDEV_FOR_DELETION,
                          method='delete_snapshot',
                          id=snapshot['id'])
         return
     try:
         self.delete_ldev(ldev)
     except utils.HBSDBusy:
         raise exception.SnapshotIsBusy(snapshot_name=snapshot['name'])
    def delete_snapshot(self, snapshot):
        """Deletes a snapshot."""
        root_helper = utils.get_root_helper()
        zvol_snapshot = self._zfs_snapshot(snapshot)

        try:
            self._execute('zfs',
                          'list',
                          '-H',
                          zvol_snapshot,
                          root_helper=root_helper,
                          run_as_root=True)
        except processutils.ProcessExecutionError:
            # If the snapshot isn't present, then don't attempt to delete
            LOG.warning(
                _("snapshot: %s not found, "
                  "skipping delete operations"), snapshot['name'])
            LOG.info(_('Successfully deleted snapshot: %s'), snapshot['id'])
            return True

        try:
            out, err = self._execute('zfs',
                                     'list',
                                     '-H',
                                     '-t',
                                     'volume',
                                     '-o',
                                     'name,origin',
                                     root_helper=root_helper,
                                     run_as_root=True)
        except processutils.ProcessExecutionError as exc:
            exception_message = (_("Failed to list origins, "
                                   "error message was: %s") %
                                 six.text_type(exc.stderr))
            raise exception.VolumeBackendAPIException(data=exception_message)

        for i in out.splitlines():
            name, origin = i.strip().split('\t')
            if origin == zvol_snapshot:
                raise exception.SnapshotIsBusy(snapshot_name=snapshot['name'])

        try:
            self._execute('zfs',
                          'destroy',
                          zvol_snapshot,
                          root_helper=root_helper,
                          run_as_root=True)
        except processutils.ProcessExecutionError as exc:
            exception_message = (_("Failed to delete snapshot, "
                                   "error message was: %s") %
                                 six.text_type(exc.stderr))
            raise exception.VolumeBackendAPIException(data=exception_message)
Beispiel #15
0
    def delete_snapshot(self, snapshot):
        """Deletes a snapshot."""
        LOG.debug('zfssa.delete_snapshot: snapshot=' + snapshot['name'])
        lcfg = self.configuration
        has_clones = self.zfssa.has_clones(lcfg.zfssa_pool, lcfg.zfssa_project,
                                           snapshot['volume_name'],
                                           snapshot['name'])
        if has_clones:
            LOG.error(_LE('Snapshot %s: has clones') % snapshot['name'])
            raise exception.SnapshotIsBusy(snapshot_name=snapshot['name'])

        self.zfssa.delete_snapshot(lcfg.zfssa_pool, lcfg.zfssa_project,
                                   snapshot['volume_name'], snapshot['name'])
Beispiel #16
0
    def delete_snapshot(self, snapshot):
        """Delete volume's snapshot on appliance.

        :param snapshot: shapshot reference
        """
        try:
            self.nms.snapshot.destroy(
                '%s@%s' % (self._get_zvol_name(
                    snapshot['volume_name']), snapshot['name']), '')
        except nexenta.NexentaException as exc:
            if "snapshot has dependent clones" in exc.args[1]:
                raise exception.SnapshotIsBusy(snapshot_name=snapshot['name'])
            else:
                raise
Beispiel #17
0
 def delete_snapshot(self, snapshot):
     """Delete the specified snapshot."""
     ldev = utils.get_ldev(snapshot)
     # When 'ldev' is 0, it should be true.
     # Therefore, it cannot remove 'is None'.
     if ldev is None:
         utils.output_log(MSG.INVALID_LDEV_FOR_DELETION,
                          method='delete_snapshot',
                          id=snapshot['id'])
         return
     try:
         self._delete_ldev(ldev)
     except exception.VSPBusy:
         raise exception.SnapshotIsBusy(snapshot_name=snapshot['name'])
Beispiel #18
0
    def delete_snapshot(self, volume, snapshot_uuid, user, api_version=None):
        if api_version is None:
            api_version = self.default_api_version

        kwargs = dict(
            Version=api_version,
            User=user,
            File=volume,
            UUID=snapshot_uuid
        )

        try:
            return self._do_request('DeleteSnapshot', **kwargs)
        except ImageBusy:
            raise exception.SnapshotIsBusy(snapshot_name=snapshot_uuid)
Beispiel #19
0
 def delete_snapshot(self, snapshot):
     """Delete the specified snapshot."""
     ldev = utils.get_ldev(snapshot)
     if ldev is None:
         utils.output_log(MSG.INVALID_LDEV_FOR_DELETION,
                          method='delete_snapshot',
                          id=snapshot['id'])
         return
     try:
         self.delete_ldev(ldev)
     except exception.VolumeDriverException as ex:
         if ex.msg == utils.BUSY_MESSAGE:
             raise exception.SnapshotIsBusy(snapshot_name=snapshot['name'])
         else:
             raise ex
Beispiel #20
0
    def delete_snapshot(self, snapshot):
        """Deletes a snapshot."""

        meta = snapshot.get('metadata')
        if 'force' in meta.keys():
            LOG.debug("Found force flag for snapshot metadata."
                      " Not sending call to datanode ")
            LOG.debug('snapshot metadata %s', meta)
            return

        if 'is_busy' in meta.keys():
            LOG.warning("Snapshot %s is being used, skipping delete",
                        snapshot['id'])
            raise exception.SnapshotIsBusy(snapshot_name=snapshot['id'])
        else:
            LOG.warning("Snapshot %s is being deleted,"
                        " is_busy key not present", snapshot['id'])

        message_body = {}
        message_body['volume_guid'] = (
            util.get_guid_with_curly_brackets(snapshot['volume_id']))
        message_body['snapshot_id'] = (
            util.get_guid_with_curly_brackets(snapshot['id']))

        # HyperScale snapshots whether Episodic or User initiated, all resides
        # in the data plane.
        # Hence delete snapshot operation will go to datanode
        rt_key = None

        # Get metadata for volume
        snapshot_volume = snapshot.get('volume')
        metadata = snapshot_volume['metadata']
        rt_key = self._get_volume_metadata_value(metadata,
                                                 'current_dn_owner')
        if rt_key is None:
            rt_key = self.dn_routing_key

        try:
            # send message to data node
            util.message_data_plane(
                rt_key,
                'hyperscale.storage.dm.version.delete',
                **message_body)

        except (exception.UnableToExecuteHyperScaleCmd,
                exception.UnableToProcessHyperScaleCmdOutput):
            with excutils.save_and_reraise_exception():
                LOG.exception('Exception in delete snapshot')
Beispiel #21
0
    def _delete_snapshot(self, snapshot_name):
        svol_name = {'scSnapName': snapshot_name}

        ret = self._call_method('DelSvol', svol_name)
        if ret['returncode'] not in [zte_pub.ZTE_ERR_CLONE_OR_SNAP_NOT_EXIST,
                                     zte_pub.ZTE_ERR_VAS_OBJECT_NOT_EXIST,
                                     zte_pub.ZTE_SUCCESS]:
            err_msg = (_('_delete_snapshot:Failed to delete snap.'
                         'snap name: %(snapname)s with Return code: '
                         '%(ret)s.') %
                       {'snapname': snapshot_name,
                        'ret': ret['returncode']})
            if ret['returncode'] == zte_pub.ZTE_ERR_SNAP_EXIST_CLONE:
                raise exception.SnapshotIsBusy(snapshot_name=snapshot_name)
            else:
                raise exception.VolumeBackendAPIException(data=err_msg)
Beispiel #22
0
    def delete_snapshot(self, snapshot):
        """Deletes a snapshot."""
        try:
            snap_info = self.client.getSnapshotByName(snapshot['name'])
            self.client.deleteSnapshot(snap_info['id'])
        except hpexceptions.HTTPNotFound:
            LOG.error(_("Snapshot did not exist. It will not be deleted"))
        except hpexceptions.HTTPServerError as ex:
            in_use_msg = 'cannot be deleted because it is a clone point'
            if in_use_msg in ex.get_description():
                raise exception.SnapshotIsBusy(ex)

            raise exception.VolumeBackendAPIException(ex)

        except Exception as ex:
            raise exception.VolumeBackendAPIException(ex)
Beispiel #23
0
 def _delete_cvol(self, cloned_name, issnapshot):
     cvol_name = {'scCvolName': cloned_name}
     ret = self._call_method('SyncForceDelCvol', cvol_name)
     if ret['returncode'] not in [zte_pub.ZTE_ERR_CLONE_OR_SNAP_NOT_EXIST,
                                  zte_pub.ZTE_ERR_VAS_OBJECT_NOT_EXIST,
                                  zte_pub.ZTE_SUCCESS]:
         err_msg = (_('_delete_cvol: Failed to delete clone vol. '
                      'cloned name: %(name)s with Return code: '
                      '%(ret)s.') %
                    {'name': cloned_name, 'ret': ret['returncode']})
         if ret['returncode'] == zte_pub.ZTE_VOLUME_TASK_NOT_FINISHED:
             if issnapshot:
                 raise exception.SnapshotIsBusy(snapshot_name=cloned_name)
             else:
                 raise exception.VolumeIsBusy(volume_name=cloned_name)
         else:
             raise exception.VolumeBackendAPIException(data=err_msg)
Beispiel #24
0
    def delete_snapshot(self, snapshot):
        """Delete volume's snapshot on appliance.

        :param snapshot: snapshot reference
        """
        volume_name = self._get_zvol_name(snapshot['volume_name'])
        snapshot_name = '%s@%s' % (volume_name, snapshot['name'])
        try:
            self.nms.snapshot.destroy(snapshot_name, '')
        except nexenta.NexentaException as exc:
            if "does not exist" in exc.args[0]:
                LOG.info(_('Snapshot %s does not exist, it seems it was '
                           'already deleted.'), snapshot_name)
                return
            if "snapshot has dependent clones" in exc.args[0]:
                raise exception.SnapshotIsBusy(snapshot_name=snapshot['name'])
            raise
Beispiel #25
0
    def wait_for_busy_snapshot(self, flexvol, snapshot_name):
        """Checks for and handles a busy snapshot.

        If a snapshot is busy, for reasons other than cloning, an exception is
        raised immediately. Otherwise, wait for a period of time for the clone
        dependency to finish before giving up. If the snapshot is not busy then
        no action is taken and the method exits.
        """
        snapshot = self.get_snapshot(flexvol, snapshot_name)
        if not snapshot['busy']:
            LOG.debug("Backing consistency group snapshot %s available for "
                      "deletion.", snapshot_name)
            return
        else:
            LOG.debug("Snapshot %(snap)s for vol %(vol)s is busy, waiting "
                      "for volume clone dependency to clear.",
                      {"snap": snapshot_name, "vol": flexvol})
            raise exception.SnapshotIsBusy(snapshot_name=snapshot_name)
Beispiel #26
0
    def delete_snapshot(self, snapshot):
        """Deletes a snapshot."""
        cliq_args = {}
        cliq_args['snapshotName'] = snapshot['name']
        cliq_args['prompt'] = 'false'  # Don't confirm
        try:
            volume_info = self._cliq_get_snapshot_info(snapshot['name'])
        except processutils.ProcessExecutionError:
            LOG.error(_("Snapshot did not exist. It will not be deleted"))
            return
        try:
            self._cliq_run_xml("deleteSnapshot", cliq_args)
        except Exception as ex:
            in_use_msg = 'cannot be deleted because it is a clone point'
            if in_use_msg in ex.message:
                raise exception.SnapshotIsBusy(str(ex))

            raise exception.VolumeBackendAPIException(str(ex))
Beispiel #27
0
    def test_delete_snapshot_when_busy_generates_user_message(
            self, fake_notify, fake_init, fake_msg_create):
        manager = vol_manager.VolumeManager()

        fake_snapshot = mock.MagicMock(id='0', project_id='1')
        fake_context = mock.MagicMock()
        fake_context.elevated.return_value = fake_context
        fake_exp = exception.SnapshotIsBusy(snapshot_name='Fred')
        fake_init.side_effect = fake_exp

        manager.delete_snapshot(fake_context, fake_snapshot)

        # make sure a user message was generated
        fake_msg_create.assert_called_once_with(
            fake_context,
            action=message_field.Action.SNAPSHOT_DELETE,
            resource_type=message_field.Resource.VOLUME_SNAPSHOT,
            resource_uuid=fake_snapshot['id'],
            exception=fake_exp)
Beispiel #28
0
    def _handle_busy_snapshot(self, flexvol, snapshot_name):
        """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 = self.zapi_client.get_snapshot(flexvol, snapshot_name)
        if not snapshot['busy']:
            LOG.info(_LI("Backing consistency group snapshot %s "
                         "available for deletion"), snapshot_name)
            return
        else:
            LOG.debug('Snapshot %(snap)s for vol %(vol)s is busy, waiting '
                      'for volume clone dependency to clear.',
                      {'snap': snapshot_name, 'vol': flexvol})

            raise exception.SnapshotIsBusy(snapshot_name=snapshot_name)
Beispiel #29
0
    def delete_snapshot(self, snapshot):
        LOG.debug("Delete Snapshot id %s %s" % (snapshot['id'],
                                                pprint.pformat(snapshot)))

        try:
            snap_name = self._get_3par_snap_name(snapshot['id'])
            self.client.deleteVolume(snap_name)
        except hpexceptions.HTTPForbidden as ex:
            LOG.error(str(ex))
            raise exception.NotAuthorized()
        except hpexceptions.HTTPNotFound as ex:
            # We'll let this act as if it worked
            # it helps clean up the cinder entries.
            msg = _("Delete Snapshot id not found. Removing from cinder: "
                    "%(id)s Ex: %(msg)s") % {'id': snapshot['id'], 'msg': ex}
            LOG.warning(msg)
        except hpexceptions.HTTPConflict as ex:
            LOG.error(str(ex))
            raise exception.SnapshotIsBusy(snapshot_name=snapshot['id'])
    def test_delete_busy_snapshot(self):
        """Test snapshot can be created and deleted."""
        volume = self._create_volume()
        volume_id = volume['id']
        self.volume.create_volume(self.context, volume_id)
        snapshot_id = self._create_snapshot(volume_id)['id']
        self.volume.create_snapshot(self.context, volume_id, snapshot_id)

        self.mox.StubOutWithMock(self.volume.driver, 'delete_snapshot')
        self.volume.driver.delete_snapshot(mox.IgnoreArg()).AndRaise(
            exception.SnapshotIsBusy(snapshot_name='fake'))
        self.mox.ReplayAll()
        self.volume.delete_snapshot(self.context, snapshot_id)
        snapshot_ref = db.snapshot_get(self.context, snapshot_id)
        self.assertEqual(snapshot_id, snapshot_ref.id)
        self.assertEqual("available", snapshot_ref.status)

        self.mox.UnsetStubs()
        self.volume.delete_snapshot(self.context, snapshot_id)
        self.volume.delete_volume(self.context, volume_id)