Пример #1
0
    def test_snapshot_detail(self, get_all_snapshots, snapshot_get_by_id,
                             volume_get_by_id, snapshot_metadata_get):
        snapshot = {
            'id': UUID,
            'volume_id': 1,
            'status': 'available',
            'volume_size': 100,
            'display_name': 'Default name',
            'display_description': 'Default description',
            'expected_attrs': ['metadata']
        }
        ctx = context.RequestContext('admin', 'fake', True)
        snapshot_obj = fake_snapshot.fake_snapshot_obj(ctx, **snapshot)
        fake_volume_obj = fake_volume.fake_volume_obj(ctx)
        snapshot_get_by_id.return_value = snapshot_obj
        volume_get_by_id.return_value = fake_volume_obj
        snapshots = objects.SnapshotList(objects=[snapshot_obj])
        get_all_snapshots.return_value = snapshots

        req = fakes.HTTPRequest.blank('/v2/snapshots/detail')
        resp_dict = self.controller.detail(req)

        self.assertIn('snapshots', resp_dict)
        resp_snapshots = resp_dict['snapshots']
        self.assertEqual(len(resp_snapshots), 1)

        resp_snapshot = resp_snapshots.pop()
        self.assertEqual(resp_snapshot['id'], UUID)
Пример #2
0
    def test_snapshot_detail(self, get_all_snapshots, snapshot_get_by_id,
                             volume_get_by_id, snapshot_metadata_get):
        snapshot = {
            'id': UUID,
            'volume_id': fake.VOLUME_ID,
            'status': fields.SnapshotStatus.AVAILABLE,
            'volume_size': 100,
            'display_name': 'Default name',
            'display_description': 'Default description',
            'expected_attrs': ['metadata']
        }
        ctx = context.RequestContext(fake.PROJECT_ID, fake.USER_ID, True)
        snapshot_obj = fake_snapshot.fake_snapshot_obj(ctx, **snapshot)
        fake_volume_obj = fake_volume.fake_volume_obj(ctx)
        snapshot_get_by_id.return_value = snapshot_obj
        volume_get_by_id.return_value = fake_volume_obj
        snapshots = objects.SnapshotList(objects=[snapshot_obj])
        get_all_snapshots.return_value = snapshots

        req = fakes.HTTPRequest.blank('/v2/snapshots/detail')
        resp_dict = self.controller.detail(req)

        self.assertIn('snapshots', resp_dict)
        resp_snapshots = resp_dict['snapshots']
        self.assertEqual(1, len(resp_snapshots))
        self.assertIn('updated_at', resp_snapshots[0])

        resp_snapshot = resp_snapshots.pop()
        self.assertEqual(UUID, resp_snapshot['id'])
Пример #3
0
    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
        """Deletes a cgsnapshot.

        If profile isn't found return success.  If failed to delete the
        replay (the snapshot) then raise an exception.

        :param context: the context of the caller.
        :param cgsnapshot: Information about the snapshot to delete.
        :return: Updated model_update, snapshots.
        :raises: VolumeBackendAPIException.
        """
        cgid = cgsnapshot['consistencygroup_id']
        snapshotid = cgsnapshot['id']

        with self._client.open_connection() as api:
            profile = api.find_replay_profile(cgid)
            if profile:
                LOG.info(_LI('Deleting snapshot %(ss)s from %(pro)s'),
                         {'ss': snapshotid,
                          'pro': profile})
                if not api.delete_cg_replay(profile, snapshotid):
                    raise exception.VolumeBackendAPIException(
                        _('Unable to delete Consistency Group snapshot %s') %
                        snapshotid)

            snapshots = objects.SnapshotList().get_all_for_cgsnapshot(
                context, snapshotid)
            for snapshot in snapshots:
                snapshot.status = 'deleted'

            model_update = {'status': 'deleted'}

            return model_update, snapshots
Пример #4
0
    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
        """Takes a snapshot of the consistency group.

        :param context: the context of the caller.
        :param cgsnapshot: Information about the snapshot to take.
        :return: Updated model_update, snapshots.
        :raises: VolumeBackendAPIException.
        """
        cgid = cgsnapshot['consistencygroup_id']
        snapshotid = cgsnapshot['id']

        with self._client.open_connection() as api:
            profile = api.find_replay_profile(cgid)
            if profile:
                LOG.debug('profile %s replayid %s', profile, snapshotid)
                if api.snap_cg_replay(profile, snapshotid, 0):
                    snapshots = objects.SnapshotList().get_all_for_cgsnapshot(
                        context, snapshotid)
                    for snapshot in snapshots:
                        snapshot.status = 'available'

                    model_update = {'status': 'available'}

                    return model_update, snapshots

                # That didn't go well.  Tell them why.  Then bomb out.
                LOG.error(_LE('Failed to snap Consistency Group %s'), cgid)
            else:
                LOG.error(_LE('Cannot find Consistency Group %s'), cgid)

        raise exception.VolumeBackendAPIException(
            _('Unable to snap Consistency Group %s') % cgid)
Пример #5
0
 def test_save_with_snapshots(self):
     db_volume = fake_volume.fake_db_volume()
     volume = objects.Volume._from_db_object(self.context, objects.Volume(),
                                             db_volume)
     volume.display_name = 'foobar'
     volume.snapshots = objects.SnapshotList()
     self.assertRaises(exception.ObjectActionError, volume.save)
Пример #6
0
    def _from_db_object(context, volume, db_volume, expected_attrs=None):
        if expected_attrs is None:
            expected_attrs = []
        for name, field in volume.fields.items():
            if name in Volume.OPTIONAL_FIELDS:
                continue
            value = db_volume.get(name)
            if isinstance(field, fields.IntegerField):
                value = value or 0
            volume[name] = value

        # Get data from db_volume object that was queried by joined query
        # from DB
        if 'metadata' in expected_attrs:
            metadata = db_volume.get('volume_metadata', [])
            volume.metadata = {item['key']: item['value'] for item in metadata}
        if 'admin_metadata' in expected_attrs:
            metadata = db_volume.get('volume_admin_metadata', [])
            volume.admin_metadata = {
                item['key']: item['value']
                for item in metadata
            }
        if 'glance_metadata' in expected_attrs:
            metadata = db_volume.get('volume_glance_metadata', [])
            volume.glance_metadata = {
                item['key']: item['value']
                for item in metadata
            }
        if 'volume_type' in expected_attrs:
            db_volume_type = db_volume.get('volume_type')
            if db_volume_type:
                vt_expected_attrs = []
                if 'volume_type.extra_specs' in expected_attrs:
                    vt_expected_attrs.append('extra_specs')
                volume.volume_type = objects.VolumeType._from_db_object(
                    context,
                    objects.VolumeType(),
                    db_volume_type,
                    expected_attrs=vt_expected_attrs)
        if 'volume_attachment' in expected_attrs:
            attachments = base.obj_make_list(
                context, objects.VolumeAttachmentList(context),
                objects.VolumeAttachment, db_volume.get('volume_attachment'))
            volume.volume_attachment = attachments
        if 'consistencygroup' in expected_attrs:
            consistencygroup = objects.ConsistencyGroup(context)
            consistencygroup._from_db_object(context, consistencygroup,
                                             db_volume['consistencygroup'])
            volume.consistencygroup = consistencygroup
        if 'snapshots' in expected_attrs:
            snapshots = base.obj_make_list(context,
                                           objects.SnapshotList(context),
                                           objects.Snapshot,
                                           db_volume['snapshots'])
            volume.snapshots = snapshots

        volume._context = context
        volume.obj_reset_changes()
        return volume
    def create_cgsnapshot(self, context, cgsnapshot):
        """Creates a consistency group snapshot."""
        client = self._login()
        try:
            # TODO(aorourke): Can't eliminate the DB calls here due to CG API.
            # Will fix in M release
            snapshots = objects.SnapshotList().get_all_for_cgsnapshot(
                context, cgsnapshot['id'])

            snap_set = []
            snapshot_base_name = "snapshot-" + cgsnapshot['id']
            for i, snapshot in enumerate(snapshots):
                volume = snapshot.volume
                volume_name = volume['name']
                try:
                    volume_info = client.getVolumeByName(volume_name)
                except Exception as ex:
                    error = six.text_type(ex)
                    LOG.error(
                        _LE("Could not find volume with name %(name)s. "
                            "Error: %(error)s"), {
                                'name': volume_name,
                                'error': error
                            })
                    raise exception.VolumeBackendAPIException(data=error)

                volume_id = volume_info['id']
                snapshot_name = snapshot_base_name + "-" + six.text_type(i)
                snap_set_member = {
                    'volumeName': volume_name,
                    'volumeId': volume_id,
                    'snapshotName': snapshot_name
                }
                snap_set.append(snap_set_member)
                snapshot.status = 'available'

            source_volume_id = snap_set[0]['volumeId']
            optional = {'inheritAccess': True}
            description = cgsnapshot.get('description', None)
            if description:
                optional['description'] = description

            try:
                client.createSnapshotSet(source_volume_id, snap_set, optional)
            except Exception as ex:
                error = six.text_type(ex)
                LOG.error(_LE("Could not create snapshot set. Error: '%s'"),
                          error)
                raise exception.VolumeBackendAPIException(data=error)

        except Exception as ex:
            raise exception.VolumeBackendAPIException(data=six.text_type(ex))
        finally:
            self._logout(client)

        model_update = {'status': 'available'}

        return model_update, snapshots
Пример #8
0
    def snapshots(self):
        # Lazy loading
        if self._snapshots is None:
            self._snapshots = self.persistence.get_snapshots(volume_id=self.id)
            for snap in self._snapshots:
                snap.volume = self

            ovos = [snap._ovo for snap in self._snapshots]
            self._ovo.snapshots = cinder_objs.SnapshotList(objects=ovos)
            self._ovo.obj_reset_changes(('snapshots', ))
        return self._snapshots
    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
        """Deletes a cgsnapshot."""
        self.client.req('snapshot-sets', 'DELETE',
                        name=self._get_cgsnap_name(cgsnapshot), ver='v2')

        snapshots = objects.SnapshotList().get_all_for_cgsnapshot(
            context, cgsnapshot['id'])

        for snapshot in snapshots:
            snapshot.status = 'deleted'

        model_update = {'status': cgsnapshot.status}

        return model_update, snapshots
    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
        """Creates a cgsnapshot."""
        data = {'consistency-group-id': cgsnapshot['consistencygroup_id'],
                'snapshot-set-name': self._get_cgsnap_name(cgsnapshot)}
        self.client.req('snapshots', 'POST', data, ver='v2')

        snapshots = objects.SnapshotList().get_all_for_cgsnapshot(
            context, cgsnapshot['id'])

        for snapshot in snapshots:
            snapshot.status = 'available'

        model_update = {'status': 'available'}

        return model_update, snapshots
Пример #11
0
    def create_cgsnapshot(self, context, cgsnapshot):
        """Creates a cgsnapshot."""

        cg_id = cgsnapshot.consistencygroup_id
        pgroup_name = self._get_pgroup_name_from_id(cg_id)
        pgsnap_suffix = self._get_pgroup_snap_suffix(cgsnapshot)
        self._array.create_pgroup_snapshot(pgroup_name, suffix=pgsnap_suffix)

        snapshots = objects.SnapshotList().get_all_for_cgsnapshot(
            context, cgsnapshot.id)

        for snapshot in snapshots:
            snapshot.status = 'available'

        model_update = {'status': 'available'}

        return model_update, snapshots
 def test_obj_load_attr(self, snapshotlist_get_for_cgs,
                        consistencygroup_get_by_id):
     cgsnapshot = objects.CGSnapshot._from_db_object(
         self.context, objects.CGSnapshot(), fake_cgsnapshot)
     # Test consistencygroup lazy-loaded field
     consistencygroup = objects.ConsistencyGroup(context=self.context, id=2)
     consistencygroup_get_by_id.return_value = consistencygroup
     self.assertEqual(consistencygroup, cgsnapshot.consistencygroup)
     consistencygroup_get_by_id.assert_called_once_with(
         self.context, cgsnapshot.consistencygroup_id)
     # Test snapshots lazy-loaded field
     snapshots_objs = [objects.Snapshot(context=self.context, id=i)
                       for i in [3, 4, 5]]
     snapshots = objects.SnapshotList(context=self.context,
                                      objects=snapshots_objs)
     snapshotlist_get_for_cgs.return_value = snapshots
     self.assertEqual(snapshots, cgsnapshot.snapshots)
     snapshotlist_get_for_cgs.assert_called_once_with(
         self.context, cgsnapshot.id)
Пример #13
0
 def test_obj_load_attr(self, snapshotlist_get_for_cgs, group_get_by_id):
     group_snapshot = objects.GroupSnapshot._from_db_object(
         self.context, objects.GroupSnapshot(), fake_group_snapshot)
     # Test group lazy-loaded field
     group = objects.Group(context=self.context, id=fake.GROUP_ID)
     group_get_by_id.return_value = group
     self.assertEqual(group, group_snapshot.group)
     group_get_by_id.assert_called_once_with(self.context,
                                             group_snapshot.group_id)
     # Test snapshots lazy-loaded field
     snapshots_objs = [
         objects.Snapshot(context=self.context, id=i)
         for i in [fake.SNAPSHOT_ID, fake.SNAPSHOT2_ID, fake.SNAPSHOT3_ID]
     ]
     snapshots = objects.SnapshotList(context=self.context,
                                      objects=snapshots_objs)
     snapshotlist_get_for_cgs.return_value = snapshots
     self.assertEqual(snapshots, group_snapshot.snapshots)
     snapshotlist_get_for_cgs.assert_called_once_with(
         self.context, group_snapshot.id)
    def delete_cgsnapshot(self, context, cgsnapshot):
        """Deletes a consistency group snapshot."""

        client = self._login()
        try:
            snap_name_base = "snapshot-" + cgsnapshot['id']

            # TODO(aorourke): Can't eliminate the DB calls here due to CG API.
            # Will fix in M release
            snapshots = objects.SnapshotList().get_all_for_cgsnapshot(
                context, cgsnapshot['id'])

            for i, snapshot in enumerate(snapshots):
                try:
                    snap_name = snap_name_base + "-" + six.text_type(i)
                    snap_info = client.getSnapshotByName(snap_name)
                    client.deleteSnapshot(snap_info['id'])
                except hpexceptions.HTTPNotFound:
                    LOG.error(
                        _LE("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(snapshot_name=snap_name)

                    raise exception.VolumeBackendAPIException(
                        data=six.text_type(ex))

        except Exception as ex:
            raise exception.VolumeBackendAPIException(data=six.text_type(ex))
        finally:
            self._logout(client)

        model_update = {'status': cgsnapshot['status']}

        return model_update, snapshots
Пример #15
0
    def test_obj_load_attr(self, mock_sl_get_all_for_volume, mock_cg_get_by_id,
                           mock_va_get_all_by_vol, mock_vt_get_by_id,
                           mock_admin_metadata_get, mock_glance_metadata_get,
                           mock_metadata_get):
        volume = objects.Volume._from_db_object(self.context, objects.Volume(),
                                                fake_volume.fake_db_volume())

        # Test metadata lazy-loaded field
        metadata = {'foo': 'bar'}
        mock_metadata_get.return_value = metadata
        self.assertEqual(metadata, volume.metadata)
        mock_metadata_get.assert_called_once_with(self.context, volume.id)

        # Test glance_metadata lazy-loaded field
        glance_metadata = [{'key': 'foo', 'value': 'bar'}]
        mock_glance_metadata_get.return_value = glance_metadata
        self.assertEqual({'foo': 'bar'}, volume.glance_metadata)
        mock_glance_metadata_get.assert_called_once_with(
            self.context, volume.id)

        # Test volume_type lazy-loaded field
        # Case1. volume.volume_type_id = None
        self.assertIsNone(volume.volume_type)

        # Case2. volume2.volume_type_id = 1
        fake2 = fake_volume.fake_db_volume()
        fake2.update({'volume_type_id': fake.volume_id})
        volume2 = objects.Volume._from_db_object(self.context,
                                                 objects.Volume(), fake2)
        volume_type = objects.VolumeType(context=self.context,
                                         id=fake.volume_type_id)
        mock_vt_get_by_id.return_value = volume_type
        self.assertEqual(volume_type, volume2.volume_type)
        mock_vt_get_by_id.assert_called_once_with(self.context,
                                                  volume2.volume_type_id)

        # Test consistencygroup lazy-loaded field
        consistencygroup = objects.ConsistencyGroup(
            context=self.context, id=fake.consistency_group_id)
        mock_cg_get_by_id.return_value = consistencygroup
        self.assertEqual(consistencygroup, volume.consistencygroup)
        mock_cg_get_by_id.assert_called_once_with(self.context,
                                                  volume.consistencygroup_id)

        # Test snapshots lazy-loaded field
        snapshots = objects.SnapshotList(context=self.context,
                                         id=fake.snapshot_id)
        mock_sl_get_all_for_volume.return_value = snapshots
        self.assertEqual(snapshots, volume.snapshots)
        mock_sl_get_all_for_volume.assert_called_once_with(
            self.context, volume.id)

        # Test volume_attachment lazy-loaded field
        va_objs = [
            objects.VolumeAttachment(context=self.context, id=i)
            for i in [fake.object_id, fake.object2_id, fake.object3_id]
        ]
        va_list = objects.VolumeAttachmentList(context=self.context,
                                               objects=va_objs)
        mock_va_get_all_by_vol.return_value = va_list
        self.assertEqual(va_list, volume.volume_attachment)
        mock_va_get_all_by_vol.assert_called_once_with(self.context, volume.id)

        # Test admin_metadata lazy-loaded field - user context
        adm_metadata = {'bar': 'foo'}
        mock_admin_metadata_get.return_value = adm_metadata
        self.assertEqual({}, volume.admin_metadata)
        self.assertFalse(mock_admin_metadata_get.called)

        # Test admin_metadata lazy-loaded field - admin context
        adm_context = self.context.elevated()
        volume = objects.Volume._from_db_object(adm_context, objects.Volume(),
                                                fake_volume.fake_db_volume())
        adm_metadata = {'bar': 'foo'}
        mock_admin_metadata_get.return_value = adm_metadata
        self.assertEqual(adm_metadata, volume.admin_metadata)
        mock_admin_metadata_get.assert_called_once_with(adm_context, volume.id)
Пример #16
0
    def _from_db_object(cls, context, volume, db_volume, expected_attrs=None):
        if expected_attrs is None:
            expected_attrs = []
        for name, field in volume.fields.items():
            if name in cls.OPTIONAL_FIELDS:
                continue
            value = db_volume.get(name)
            if isinstance(field, fields.IntegerField):
                value = value or 0
            volume[name] = value

        # Get data from db_volume object that was queried by joined query
        # from DB
        if 'metadata' in expected_attrs:
            metadata = db_volume.get('volume_metadata', [])
            volume.metadata = {item['key']: item['value'] for item in metadata}
        if 'admin_metadata' in expected_attrs:
            metadata = db_volume.get('volume_admin_metadata', [])
            volume.admin_metadata = {item['key']: item['value']
                                     for item in metadata}
        if 'glance_metadata' in expected_attrs:
            metadata = db_volume.get('volume_glance_metadata', [])
            volume.glance_metadata = {item['key']: item['value']
                                      for item in metadata}
        if 'volume_type' in expected_attrs:
            db_volume_type = db_volume.get('volume_type')
            if db_volume_type:
                vt_expected_attrs = []
                if 'volume_type.extra_specs' in expected_attrs:
                    vt_expected_attrs.append('extra_specs')
                volume.volume_type = objects.VolumeType._from_db_object(
                    context, objects.VolumeType(), db_volume_type,
                    expected_attrs=vt_expected_attrs)
        if 'volume_attachment' in expected_attrs:
            attachments = base.obj_make_list(
                context, objects.VolumeAttachmentList(context),
                objects.VolumeAttachment,
                db_volume.get('volume_attachment'))
            volume.volume_attachment = attachments
        if volume.consistencygroup_id and 'consistencygroup' in expected_attrs:
            consistencygroup = objects.ConsistencyGroup(context)
            consistencygroup._from_db_object(context,
                                             consistencygroup,
                                             db_volume['consistencygroup'])
            volume.consistencygroup = consistencygroup
        if 'snapshots' in expected_attrs:
            snapshots = base.obj_make_list(
                context, objects.SnapshotList(context),
                objects.Snapshot,
                db_volume['snapshots'])
            volume.snapshots = snapshots
        if 'cluster' in expected_attrs:
            db_cluster = db_volume.get('cluster')
            # If this volume doesn't belong to a cluster the cluster field in
            # the ORM instance will have value of None.
            if db_cluster:
                volume.cluster = objects.Cluster(context)
                objects.Cluster._from_db_object(context, volume.cluster,
                                                db_cluster)
            else:
                volume.cluster = None
        if volume.group_id and 'group' in expected_attrs:
            group = objects.Group(context)
            group._from_db_object(context,
                                  group,
                                  db_volume['group'])
            volume.group = group

        volume._context = context
        volume.obj_reset_changes()
        return volume
Пример #17
0
    def __init__(self, backend_or_vol, pool_name=None, **kwargs):
        # Accept backend name for convenience
        if isinstance(backend_or_vol, six.string_types):
            backend_name = backend_or_vol
            backend_or_vol = self._get_backend(backend_or_vol)
        elif isinstance(backend_or_vol, self.backend_class):
            backend_name = backend_or_vol.id
        elif isinstance(backend_or_vol, Volume):
            backend_str, pool = backend_or_vol._ovo.host.split('#')
            backend_name = backend_str.split('@')[-1]
            pool_name = pool_name or pool
            for key in backend_or_vol._ovo.fields:
                if (backend_or_vol._ovo.obj_attr_is_set(key)
                        and key not in self._ignore_keys):
                    kwargs.setdefault(key, getattr(backend_or_vol._ovo, key))
            if backend_or_vol.volume_type:
                kwargs.setdefault('extra_specs',
                                  backend_or_vol.volume_type.extra_specs)
                if backend_or_vol.volume_type.qos_specs:
                    kwargs.setdefault(
                        'qos_specs',
                        backend_or_vol.volume_type.qos_specs.specs)
            backend_or_vol = backend_or_vol.backend

        if '__ovo' not in kwargs:
            kwargs[CONNECTIONS_OVO_FIELD] = (cinder_objs.VolumeAttachmentList(
                context=self.CONTEXT))
            kwargs['snapshots'] = (cinder_objs.SnapshotList(
                context=self.CONTEXT))
            self._snapshots = []
            self._connections = []

        qos_specs = kwargs.pop('qos_specs', None)
        extra_specs = kwargs.pop('extra_specs', {})

        super(Volume, self).__init__(backend_or_vol, **kwargs)
        self._populate_data()
        self.local_attach = None

        # If we overwrote the host, then we ignore pool_name and don't set a
        # default value or copy the one from the source either.
        if 'host' not in kwargs and '__ovo' not in kwargs:
            # TODO(geguileo): Add pool support
            pool_name = pool_name or backend_or_vol.pool_names[0]
            self._ovo.host = ('%s@%s#%s' %
                              (cfg.CONF.host, backend_name, pool_name))

        if qos_specs or extra_specs:
            if qos_specs:
                qos_specs = cinder_objs.QualityOfServiceSpecs(
                    id=self.id,
                    name=self.id,
                    consumer='back-end',
                    specs=qos_specs)
                qos_specs_id = self.id
            else:
                qos_specs = qos_specs_id = None

            self._ovo.volume_type = cinder_objs.VolumeType(
                context=self.CONTEXT,
                is_public=True,
                id=self.id,
                name=self.id,
                qos_specs_id=qos_specs_id,
                extra_specs=extra_specs,
                qos_specs=qos_specs)
            self._ovo.volume_type_id = self.id