Пример #1
0
    def do_setup(self, ctxt):
        LOG.debug('enter: do_setup')
        self._context = ctxt
        # Ensure that the default volume type exists
        vtn = self.configuration.default_volume_type
        vtn = vtn.decode('utf-8') if vtn else vtn
        try:
            volume_types.get_volume_type_by_name(ctxt, vtn)
        except exception.VolumeTypeNotFoundByName:
            # If the default volume type does not exist, we create it here.
            LOG.info(_("Creating default volume type '%s'") % vtn)
            self._create_default_volume_type(ctxt, vtn)

        LOG.debug('leave: do_setup')
Пример #2
0
    def test_volume_type_create_then_destroy_with_non_admin(self):
        """Ensure volume types can be created and deleted by non-admin user.

        If a non-admn user is authorized at API, volume type operations
        should be permitted.
        """
        prev_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.ctxt = context.RequestContext("fake", "fake", is_admin=False)

        # create
        type_ref = volume_types.create(
            self.ctxt, self.vol_type1_name, self.vol_type1_specs, description=self.vol_type1_description
        )
        new = volume_types.get_volume_type_by_name(self.ctxt, self.vol_type1_name)
        self.assertEqual(self.vol_type1_description, new["description"])
        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(len(prev_all_vtypes) + 1, len(new_all_vtypes), "drive type was not created")

        # update
        new_type_name = self.vol_type1_name + "_updated"
        new_type_desc = self.vol_type1_description + "_updated"
        type_ref_updated = volume_types.update(self.ctxt, type_ref.id, new_type_name, new_type_desc)
        self.assertEqual(new_type_name, type_ref_updated["name"])
        self.assertEqual(new_type_desc, type_ref_updated["description"])

        # destroy
        volume_types.destroy(self.ctxt, type_ref["id"])
        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(prev_all_vtypes, new_all_vtypes, "drive type was not deleted")
Пример #3
0
    def _create(self, req, body):
        """Creates a new volume type."""
        context = req.environ["cinder.context"]
        authorize(context)

        if not self.is_valid_body(body, "volume_type"):
            raise webob.exc.HTTPBadRequest()

        vol_type = body["volume_type"]
        name = vol_type.get("name", None)
        specs = vol_type.get("extra_specs", {})

        if name is None or name == "":
            raise webob.exc.HTTPBadRequest()

        try:
            volume_types.create(context, name, specs)
            vol_type = volume_types.get_volume_type_by_name(context, name)
            notifier_info = dict(volume_types=vol_type)
            notifier_api.notify(context, "volumeType", "volume_type.create", notifier_api.INFO, notifier_info)

        except exception.VolumeTypeExists as err:
            notifier_err = dict(volume_types=vol_type, error_message=str(err))
            self._notify_volume_type_error(context, "volume_type.create", notifier_err)

            raise webob.exc.HTTPConflict(explanation=str(err))
        except exception.NotFound as err:
            notifier_err = dict(volume_types=vol_type, error_message=str(err))
            self._notify_volume_type_error(context, "volume_type.create", notifier_err)
            raise webob.exc.HTTPNotFound()

        return self._view_builder.show(req, vol_type)
Пример #4
0
    def test_volume_type_create_then_destroy(self):
        """Ensure volume types can be created and deleted."""
        prev_all_vtypes = volume_types.get_all_types(self.ctxt)

        type_ref = volume_types.create(self.ctxt, self.vol_type1_name,
                                       self.vol_type1_specs)
        new = volume_types.get_volume_type_by_name(self.ctxt,
                                                   self.vol_type1_name)

        LOG.info(_("Given data: %s"), self.vol_type1_specs)
        LOG.info(_("Result data: %s"), new)

        for k, v in self.vol_type1_specs.iteritems():
            self.assertEqual(v, new['extra_specs'][k],
                             'one of fields doesnt match')

        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(
            len(prev_all_vtypes) + 1, len(new_all_vtypes),
            'drive type was not created')

        volume_types.destroy(self.ctxt, type_ref['id'])
        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(prev_all_vtypes, new_all_vtypes,
                         'drive type was not deleted')
Пример #5
0
    def test_v2_restore_factory(self):
        fact = self.bak_meta_api._v2_restore_factory()

        keys = [self.bak_meta_api.TYPE_TAG_VOL_BASE_META,
                self.bak_meta_api.TYPE_TAG_VOL_META,
                self.bak_meta_api.TYPE_TAG_VOL_GLANCE_META]

        self.assertEqual(set([]),
                         set(keys).symmetric_difference(set(fact.keys())))

        volume_types.create(self.ctxt, 'faketype')
        vol_type = volume_types.get_volume_type_by_name(self.ctxt, 'faketype')

        meta_container = {self.bak_meta_api.TYPE_TAG_VOL_BASE_META:
                          {'encryption_key_id': '123',
                           'volume_type_id': vol_type.get('id'),
                           'display_name': 'vol-2',
                           'display_description': 'description'},
                          self.bak_meta_api.TYPE_TAG_VOL_META: {},
                          self.bak_meta_api.TYPE_TAG_VOL_GLANCE_META: {}}

        for f in fact:
            func = fact[f][0]
            fields = fact[f][1]
            func(meta_container[f], self.volume_id, fields)

        vol = db.volume_get(self.ctxt, self.volume_id)
        self.assertEqual(self.volume_display_name, vol['display_name'])
        self.assertEqual(self.volume_display_description,
                         vol['display_description'])
        self.assertEqual('123', vol['encryption_key_id'])
Пример #6
0
    def _create(self, req, body):
        """Creates a new volume type."""
        context = req.environ['cinder.context']
        authorize(context)

        if not self.is_valid_body(body, 'volume_type'):
            raise webob.exc.HTTPBadRequest()

        vol_type = body['volume_type']
        name = vol_type.get('name', None)
        specs = vol_type.get('extra_specs', {})

        if name is None or name == "":
            raise webob.exc.HTTPBadRequest()

        try:
            volume_types.create(context, name, specs)
            vol_type = volume_types.get_volume_type_by_name(context, name)
            notifier_info = dict(volume_types=vol_type)
            rpc.get_notifier('volumeType').info(context, 'volume_type.create',
                                                notifier_info)

        except exception.VolumeTypeExists as err:
            notifier_err = dict(volume_types=vol_type, error_message=err)
            self._notify_volume_type_error(context, 'volume_type.create',
                                           notifier_err)

            raise webob.exc.HTTPConflict(explanation=six.text_type(err))
        except exception.NotFound as err:
            notifier_err = dict(volume_types=vol_type, error_message=err)
            self._notify_volume_type_error(context, 'volume_type.create',
                                           notifier_err)
            raise webob.exc.HTTPNotFound()

        return self._view_builder.show(req, vol_type)
Пример #7
0
    def _create(self, req, body):
        """Creates a new volume type."""
        context = req.environ['cinder.context']
        authorize(context)

        self.assert_valid_body(body, 'volume_type')

        vol_type = body['volume_type']
        name = vol_type.get('name', None)
        description = vol_type.get('description')
        specs = vol_type.get('extra_specs', {})
        utils.validate_dictionary_string_length(specs)
        is_public = vol_type.get('os-volume-type-access:is_public', True)

        if name is None or len(name.strip()) == 0:
            msg = _("Volume type name can not be empty.")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        utils.check_string_length(name,
                                  'Type name',
                                  min_length=1,
                                  max_length=255)

        if description is not None:
            utils.check_string_length(description,
                                      'Type description',
                                      min_length=0,
                                      max_length=255)

        if not strutils.is_valid_boolstr(is_public):
            msg = _("Invalid value '%s' for is_public. Accepted values: "
                    "True or False.") % is_public
            raise webob.exc.HTTPBadRequest(explanation=msg)

        try:
            volume_types.create(context,
                                name,
                                specs,
                                is_public,
                                description=description)
            vol_type = volume_types.get_volume_type_by_name(context, name)
            req.cache_resource(vol_type, name='types')
            self._notify_volume_type_info(context, 'volume_type.create',
                                          vol_type)

        except exception.VolumeTypeExists as err:
            self._notify_volume_type_error(context,
                                           'volume_type.create',
                                           err,
                                           volume_type=vol_type)
            raise webob.exc.HTTPConflict(explanation=six.text_type(err))
        except exception.VolumeTypeNotFoundByName as err:
            self._notify_volume_type_error(context,
                                           'volume_type.create',
                                           err,
                                           name=name)
            # Not found exception will be handled at the wsgi level
            raise

        return self._view_builder.show(req, vol_type)
Пример #8
0
    def _create(self, req, body):
        """Creates a new volume type."""
        context = req.environ['cinder.context']
        authorize(context)

        if not body or body == "":
            raise webob.exc.HTTPUnprocessableEntity()

        vol_type = body.get('volume_type', None)
        if vol_type is None or vol_type == "":
            raise webob.exc.HTTPUnprocessableEntity()

        name = vol_type.get('name', None)
        specs = vol_type.get('extra_specs', {})

        if name is None or name == "":
            raise webob.exc.HTTPUnprocessableEntity()

        try:
            volume_types.create(context, name, specs)
            vol_type = volume_types.get_volume_type_by_name(context, name)
        except exception.VolumeTypeExists as err:
            raise webob.exc.HTTPConflict(explanation=str(err))
        except exception.NotFound:
            raise webob.exc.HTTPNotFound()

        return self._view_builder.show(req, vol_type)
Пример #9
0
    def _create(self, req, body):
        """Creates a new volume type."""
        context = req.environ["cinder.context"]
        authorize(context)

        if not self.is_valid_body(body, "volume_type"):
            raise webob.exc.HTTPBadRequest()

        vol_type = body["volume_type"]
        name = vol_type.get("name", None)
        description = vol_type.get("description")
        specs = vol_type.get("extra_specs", {})
        is_public = vol_type.get("os-volume-type-access:is_public", True)

        if name is None or len(name.strip()) == 0:
            msg = _("Volume type name can not be empty.")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        try:
            volume_types.create(context, name, specs, is_public, description=description)
            vol_type = volume_types.get_volume_type_by_name(context, name)
            req.cache_resource(vol_type, name="types")
            self._notify_volume_type_info(context, "volume_type.create", vol_type)

        except exception.VolumeTypeExists as err:
            self._notify_volume_type_error(context, "volume_type.create", err, volume_type=vol_type)
            raise webob.exc.HTTPConflict(explanation=six.text_type(err))
        except exception.NotFound as err:
            self._notify_volume_type_error(context, "volume_type.create", err, name=name)
            raise webob.exc.HTTPNotFound()

        return self._view_builder.show(req, vol_type)
Пример #10
0
    def test_volume_type_create_then_destroy(self):
        """Ensure volume types can be created and deleted."""
        prev_all_vtypes = volume_types.get_all_types(self.ctxt)

        # create
        type_ref = volume_types.create(
            self.ctxt, self.vol_type1_name, self.vol_type1_specs, description=self.vol_type1_description
        )
        new = volume_types.get_volume_type_by_name(self.ctxt, self.vol_type1_name)

        LOG.info(_("Given data: %s"), self.vol_type1_specs)
        LOG.info(_("Result data: %s"), new)

        self.assertEqual(self.vol_type1_description, new["description"])

        for k, v in self.vol_type1_specs.items():
            self.assertEqual(v, new["extra_specs"][k], "one of fields does not match")

        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(len(prev_all_vtypes) + 1, len(new_all_vtypes), "drive type was not created")

        # update
        new_type_name = self.vol_type1_name + "_updated"
        new_type_desc = self.vol_type1_description + "_updated"
        type_ref_updated = volume_types.update(self.ctxt, type_ref.id, new_type_name, new_type_desc)
        self.assertEqual(new_type_name, type_ref_updated["name"])
        self.assertEqual(new_type_desc, type_ref_updated["description"])

        # destroy
        volume_types.destroy(self.ctxt, type_ref["id"])
        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(prev_all_vtypes, new_all_vtypes, "drive type was not deleted")
Пример #11
0
    def create(self, req, body):
        """Creates a new volume."""
        if not self.is_valid_body(body, 'volume'):
            raise exc.HTTPUnprocessableEntity()

        context = req.environ['cinder.context']
        volume = body['volume']

        kwargs = {}

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                kwargs['volume_type'] = volume_types.get_volume_type_by_name(
                        context, req_volume_type)
            except exception.VolumeTypeNotFound:
                explanation = 'Volume type not found.'
                raise exc.HTTPNotFound(explanation=explanation)

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            kwargs['snapshot'] = self.volume_api.get_snapshot(context,
                                                              snapshot_id)
        else:
            kwargs['snapshot'] = None

        size = volume.get('size', None)
        if size is None and kwargs['snapshot'] is not None:
            size = kwargs['snapshot']['volume_size']

        LOG.audit(_("Create volume of %s GB"), size, context=context)

        image_href = None
        image_uuid = None
        if self.ext_mgr.is_loaded('os-image-create'):
            image_href = volume.get('imageRef')
            if snapshot_id and image_href:
                msg = _("Snapshot and image cannot be specified together.")
                raise exc.HTTPBadRequest(explanation=msg)
            if image_href:
                image_uuid = self._image_uuid_from_href(image_href)
                kwargs['image_id'] = image_uuid

        kwargs['availability_zone'] = volume.get('availability_zone', None)

        new_volume = self.volume_api.create(context,
                                            size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        # TODO(vish): Instance should be None at db layer instead of
        #             trying to lazy load, but for now we turn it into
        #             a dict to avoid an error.
        retval = _translate_volume_detail_view(context, dict(new_volume),
                                               image_uuid)

        return {'volume': retval}
Пример #12
0
    def _create(self, req, body):
        """Creates a new volume type."""
        context = req.environ['cinder.context']
        context.authorize(policy.MANAGE_POLICY)
        vol_type = body['volume_type']
        name = vol_type['name']
        description = vol_type.get('description')
        specs = vol_type.get('extra_specs', {})
        is_public = vol_type.get('os-volume-type-access:is_public', True)
        is_public = strutils.bool_from_string(is_public, strict=True)
        try:
            volume_types.create(context,
                                name,
                                specs,
                                is_public,
                                description=description)
            vol_type = volume_types.get_volume_type_by_name(context, name)
            req.cache_resource(vol_type, name='types')
            self._notify_volume_type_info(
                context, 'volume_type.create', vol_type)

        except exception.VolumeTypeExists as err:
            self._notify_volume_type_error(
                context, 'volume_type.create', err, volume_type=vol_type)
            raise webob.exc.HTTPConflict(explanation=six.text_type(err))
        except exception.VolumeTypeNotFoundByName as err:
            self._notify_volume_type_error(
                context, 'volume_type.create', err, name=name)
            # Not found exception will be handled at the wsgi level
            raise

        return self._view_builder.show(req, vol_type)
Пример #13
0
    def test_v2_restore_factory(self):
        fact = self.bak_meta_api._v2_restore_factory()

        keys = [self.bak_meta_api.TYPE_TAG_VOL_BASE_META,
                self.bak_meta_api.TYPE_TAG_VOL_META,
                self.bak_meta_api.TYPE_TAG_VOL_GLANCE_META]

        self.assertEqual(set([]),
                         set(keys).symmetric_difference(set(fact.keys())))

        volume_types.create(self.ctxt, 'faketype')
        vol_type = volume_types.get_volume_type_by_name(self.ctxt, 'faketype')

        meta_container = {self.bak_meta_api.TYPE_TAG_VOL_BASE_META:
                          {'encryption_key_id': '123',
                           'volume_type_id': vol_type.get('id'),
                           'display_name': 'vol-2',
                           'display_description': 'description'},
                          self.bak_meta_api.TYPE_TAG_VOL_META: {},
                          self.bak_meta_api.TYPE_TAG_VOL_GLANCE_META: {}}

        for f in fact:
            func = fact[f][0]
            fields = fact[f][1]
            func(meta_container[f], self.volume_id, fields)

        vol = db.volume_get(self.ctxt, self.volume_id)
        self.assertEqual(self.volume_display_name, vol['display_name'])
        self.assertEqual(self.volume_display_description,
                         vol['display_description'])
        self.assertEqual('123', vol['encryption_key_id'])
Пример #14
0
    def test_volume_type_get_by_id_and_name(self):
        """Ensure volume types get returns same entry."""
        volume_types.create(self.ctxt, self.vol_type1_name, self.vol_type1_specs)
        new = volume_types.get_volume_type_by_name(self.ctxt, self.vol_type1_name)

        new2 = volume_types.get_volume_type(self.ctxt, new["id"])
        self.assertEqual(new, new2)
Пример #15
0
    def test_volume_type_create_then_destroy(self):
        """Ensure volume types can be created and deleted."""
        prev_all_vtypes = volume_types.get_all_types(self.ctxt)

        type_ref = volume_types.create(self.ctxt,
                                       self.vol_type1_name,
                                       self.vol_type1_specs)
        new = volume_types.get_volume_type_by_name(self.ctxt,
                                                   self.vol_type1_name)

        LOG.info(_("Given data: %s"), self.vol_type1_specs)
        LOG.info(_("Result data: %s"), new)

        for k, v in self.vol_type1_specs.iteritems():
            self.assertEqual(v, new['extra_specs'][k],
                             'one of fields does not match')

        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(len(prev_all_vtypes) + 1,
                         len(new_all_vtypes),
                         'drive type was not created')

        volume_types.destroy(self.ctxt, type_ref['id'])
        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(prev_all_vtypes,
                         new_all_vtypes,
                         'drive type was not deleted')
Пример #16
0
 def _get_volume_type_id(self, volume_type_name):
     try:
         return volume_types.get_volume_type_by_name(
             get_admin_context(), volume_type_name)['id']
     except exception.VolumeTypeNotFoundByName:
         LOG.exception("Unknown volume type '%s';"
                       " not valid volume type?" % volume_type_name)
         raise
Пример #17
0
 def test_ensure_no_extra_specs_for_non_admin(self):
     # non-admin users shouldn't get extra-specs back in type-get/list etc
     ctxt = context.RequestContext(
         "average-joe", "d802f078-0af1-4e6b-8c02-7fac8d4339aa", auth_token="token", is_admin=False
     )
     volume_types.create(self.ctxt, "type-test", is_public=False)
     vtype = volume_types.get_volume_type_by_name(ctxt, "type-test")
     self.assertIsNone(vtype.get("extra_specs", None))
Пример #18
0
 def _get_volume_type_id(self, volume_type_name):
     try:
         return volume_types.get_volume_type_by_name(
             get_admin_context(), volume_type_name)['id']
     except exception.VolumeTypeNotFoundByName:
         LOG.exception("Unknown volume type '%s';"
                       " not valid volume type?" % volume_type_name)
         raise
Пример #19
0
    def create(self, req, body):
        """Creates a new volume."""
        if not self.is_valid_body(body, 'volume'):
            raise exc.HTTPUnprocessableEntity()

        context = req.environ['cinder.context']
        volume = body['volume']

        kwargs = {}

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                kwargs['volume_type'] = volume_types.get_volume_type_by_name(
                    context, req_volume_type)
            except exception.NotFound:
                raise exc.HTTPNotFound()

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            kwargs['snapshot'] = self.volume_api.get_snapshot(
                context, snapshot_id)
        else:
            kwargs['snapshot'] = None

        size = volume.get('size', None)
        if size is None and kwargs['snapshot'] is not None:
            size = kwargs['snapshot']['volume_size']

        LOG.audit(_("Create volume of %s GB"), size, context=context)

        image_href = None
        image_uuid = None
        if self.ext_mgr.is_loaded('os-image-create'):
            image_href = volume.get('imageRef')
            if snapshot_id and image_href:
                msg = _("Snapshot and image cannot be specified together.")
                raise exc.HTTPBadRequest(explanation=msg)
            if image_href:
                image_uuid = self._image_uuid_from_href(image_href)
                kwargs['image_id'] = image_uuid

        kwargs['availability_zone'] = volume.get('availability_zone', None)

        new_volume = self.volume_api.create(context, size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        # TODO(vish): Instance should be None at db layer instead of
        #             trying to lazy load, but for now we turn it into
        #             a dict to avoid an error.
        retval = _translate_volume_detail_view(context, dict(new_volume),
                                               image_uuid)

        return {'volume': retval}
Пример #20
0
 def test_ensure__extra_specs_for_non_admin(self):
     # non-admin users get extra-specs back in type-get/list etc at DB layer
     ctxt = context.RequestContext('average-joe',
                                   'd802f078-0af1-4e6b-8c02-7fac8d4339aa',
                                   auth_token='token',
                                   is_admin=False)
     volume_types.create(self.ctxt, "type-test", is_public=False)
     vtype = volume_types.get_volume_type_by_name(ctxt, 'type-test')
     self.assertIsNotNone(vtype.get('extra_specs', None))
Пример #21
0
    def test_volume_type_get_by_id_and_name(self):
        """Ensure volume types get returns same entry."""
        volume_types.create(self.ctxt, self.vol_type1_name,
                            self.vol_type1_specs)
        new = volume_types.get_volume_type_by_name(self.ctxt,
                                                   self.vol_type1_name)

        new2 = volume_types.get_volume_type(self.ctxt, new['id'])
        self.assertEqual(new, new2)
Пример #22
0
 def test_ensure__extra_specs_for_non_admin(self):
     # non-admin users get extra-specs back in type-get/list etc at DB layer
     ctxt = context.RequestContext('average-joe',
                                   'd802f078-0af1-4e6b-8c02-7fac8d4339aa',
                                   auth_token='token',
                                   is_admin=False)
     volume_types.create(self.ctxt, "type-test", is_public=False)
     vtype = volume_types.get_volume_type_by_name(ctxt, 'type-test')
     self.assertIsNotNone(vtype.get('extra_specs', None))
Пример #23
0
    def create(self, req, body):
        """Creates a new volume."""
        context = req.environ['cinder.context']

        if not body:
            raise exc.HTTPUnprocessableEntity()

        volume = body['volume']

        def as_int(s):
            try:
                return int(s)
            except ValueError:
                return s

        # NOTE(eglynn): we're tolerant of non-int sizes here, as type
        # integrity is enforced later in the creation codepath
        size = as_int(volume['size'])

        LOG.audit(_("Create volume of %s GB"), size, context=context)

        kwargs = {}

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                kwargs['volume_type'] = volume_types.get_volume_type_by_name(
                        context, req_volume_type)
            except exception.NotFound:
                raise exc.HTTPNotFound()

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            kwargs['snapshot'] = self.volume_api.get_snapshot(context,
                                                              snapshot_id)
        else:
            kwargs['snapshot'] = None

        kwargs['availability_zone'] = volume.get('availability_zone', None)

        new_volume = self.volume_api.create(context,
                                            size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        # TODO(vish): Instance should be None at db layer instead of
        #             trying to lazy load, but for now we turn it into
        #             a dict to avoid an error.
        retval = _translate_volume_detail_view(context, dict(new_volume))

        return {'volume': retval}
Пример #24
0
    def _create(self, req, body):
        """Creates a new volume type."""
        context = req.environ['cinder.context']
        authorize(context)

        self.assert_valid_body(body, 'volume_type')

        vol_type = body['volume_type']
        name = vol_type.get('name', None)
        description = vol_type.get('description')
        specs = vol_type.get('extra_specs', {})
        utils.validate_dictionary_string_length(specs)
        is_public = vol_type.get('os-volume-type-access:is_public', True)

        if name is None or len(name.strip()) == 0:
            msg = _("Volume type name can not be empty.")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        utils.check_string_length(name, 'Type name',
                                  min_length=1, max_length=255)

        if description is not None:
            utils.check_string_length(description, 'Type description',
                                      min_length=0, max_length=255)

        if not strutils.is_valid_boolstr(is_public):
            msg = _("Invalid value '%s' for is_public. Accepted values: "
                    "True or False.") % is_public
            raise webob.exc.HTTPBadRequest(explanation=msg)

        try:
            volume_types.create(context,
                                name,
                                specs,
                                is_public,
                                description=description)
            vol_type = volume_types.get_volume_type_by_name(context, name)
            req.cache_resource(vol_type, name='types')
            self._notify_volume_type_info(
                context, 'volume_type.create', vol_type)

        except exception.VolumeTypeExists as err:
            self._notify_volume_type_error(
                context, 'volume_type.create', err, volume_type=vol_type)
            raise webob.exc.HTTPConflict(explanation=six.text_type(err))
        except exception.VolumeTypeNotFoundByName as err:
            self._notify_volume_type_error(
                context, 'volume_type.create', err, name=name)
            # Not found exception will be handled at the wsgi level
            raise

        return self._view_builder.show(req, vol_type)
Пример #25
0
    def test_volume_type_create_then_destroy(self):
        """Ensure volume types can be created and deleted."""
        project_id = fake.PROJECT_ID
        prev_all_vtypes = volume_types.get_all_types(self.ctxt)

        # create
        type_ref = volume_types.create(self.ctxt,
                                       self.vol_type1_name,
                                       self.vol_type1_specs,
                                       description=self.vol_type1_description,
                                       projects=[project_id], is_public=False)
        new = volume_types.get_volume_type_by_name(self.ctxt,
                                                   self.vol_type1_name)

        self.assertEqual(self.vol_type1_description, new['description'])

        for k, v in self.vol_type1_specs.items():
            self.assertEqual(v, new['extra_specs'][k],
                             'one of fields does not match')

        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(len(prev_all_vtypes) + 1,
                         len(new_all_vtypes),
                         'drive type was not created')
        # Assert that volume type is associated to a project
        vol_type_access = db.volume_type_access_get_all(self.ctxt,
                                                        type_ref['id'])
        self.assertIn(project_id, [a.project_id for a in vol_type_access])

        # update
        new_type_name = self.vol_type1_name + '_updated'
        new_type_desc = self.vol_type1_description + '_updated'
        type_ref_updated = volume_types.update(self.ctxt,
                                               type_ref.id,
                                               new_type_name,
                                               new_type_desc)
        self.assertEqual(new_type_name, type_ref_updated['name'])
        self.assertEqual(new_type_desc, type_ref_updated['description'])

        # destroy
        volume_types.destroy(self.ctxt, type_ref['id'])
        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(prev_all_vtypes,
                         new_all_vtypes,
                         'drive type was not deleted')
        # Assert that associated volume type access is deleted successfully
        # on destroying the volume type
        vol_type_access = db_api._volume_type_access_query(
            self.ctxt).filter_by(volume_type_id=type_ref['id']).all()
        self.assertFalse(vol_type_access)
Пример #26
0
    def test_volume_type_create_then_destroy(self):
        """Ensure volume types can be created and deleted."""
        project_id = fake.PROJECT_ID
        prev_all_vtypes = volume_types.get_all_types(self.ctxt)

        # create
        type_ref = volume_types.create(self.ctxt,
                                       self.vol_type1_name,
                                       self.vol_type1_specs,
                                       description=self.vol_type1_description,
                                       projects=[project_id],
                                       is_public=False)
        new = volume_types.get_volume_type_by_name(self.ctxt,
                                                   self.vol_type1_name)

        self.assertEqual(self.vol_type1_description, new['description'])

        for k, v in self.vol_type1_specs.items():
            self.assertEqual(v, new['extra_specs'][k],
                             'one of fields does not match')

        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(
            len(prev_all_vtypes) + 1, len(new_all_vtypes),
            'drive type was not created')
        # Assert that volume type is associated to a project
        vol_type_access = db.volume_type_access_get_all(
            self.ctxt, type_ref['id'])
        self.assertIn(project_id, [a.project_id for a in vol_type_access])

        # update
        new_type_name = self.vol_type1_name + '_updated'
        new_type_desc = self.vol_type1_description + '_updated'
        volume_types.update(self.ctxt, type_ref.id, new_type_name,
                            new_type_desc)
        type_ref_updated = volume_types.get_volume_type(self.ctxt, type_ref.id)
        self.assertEqual(new_type_name, type_ref_updated['name'])
        self.assertEqual(new_type_desc, type_ref_updated['description'])

        # destroy
        volume_types.destroy(self.ctxt, type_ref['id'])
        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(prev_all_vtypes, new_all_vtypes,
                         'drive type was not deleted')
        # Assert that associated volume type access is deleted successfully
        # on destroying the volume type
        with db_api.main_context_manager.reader.using(self.ctxt):
            vol_type_access = db_api._volume_type_access_query(
                self.ctxt).filter_by(volume_type_id=type_ref['id']).all()
        self.assertEqual([], vol_type_access)
Пример #27
0
    def get_extra_specs_by_volume_type_name(self, volumeTypeName):
        """Gets the extra specs associated with a volume type.

        Given the string value of the volume type name, get the extra specs
        object associated with the volume type

        :param volumeTypeName: string value of the volume type name
        :returns: extra_specs - extra specs object
        """
        ctxt = context.get_admin_context()
        volume_type = volume_types.get_volume_type_by_name(
            ctxt, volumeTypeName)
        extra_specs = volume_type['extra_specs']
        return extra_specs
Пример #28
0
    def get_extra_specs_by_volume_type_name(self, volumeTypeName):
        """Gets the extra specs associated with a volume type.

        Given the string value of the volume type name, get the extra specs
        object associated with the volume type

        :param volumeTypeName: string value of the volume type name
        :returns: extra_specs - extra specs object
        """
        ctxt = context.get_admin_context()
        volume_type = volume_types.get_volume_type_by_name(
            ctxt, volumeTypeName)
        extra_specs = volume_type['extra_specs']
        return extra_specs
Пример #29
0
    def _create(self, req, body):
        """Creates a new volume type."""
        context = req.environ['cinder.context']
        authorize(context)

        if not self.is_valid_body(body, 'volume_type'):
            raise webob.exc.HTTPBadRequest()

        vol_type = body['volume_type']
        name = vol_type.get('name', None)
        description = vol_type.get('description')
        specs = vol_type.get('extra_specs', {})
        is_public = vol_type.get('os-volume-type-access:is_public', True)

        if name is None or len(name.strip()) == 0:
            msg = _("Volume type name can not be empty.")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        utils.check_string_length(name, 'Type name',
                                  min_length=1, max_length=255)

        if description is not None:
            utils.check_string_length(description, 'Type description',
                                      min_length=0, max_length=255)

        try:
            volume_types.create(context,
                                name,
                                specs,
                                is_public,
                                description=description)
            vol_type = volume_types.get_volume_type_by_name(context, name)
            req.cache_resource(vol_type, name='types')
            self._notify_volume_type_info(
                context, 'volume_type.create', vol_type)

        except exception.VolumeTypeExists as err:
            self._notify_volume_type_error(
                context, 'volume_type.create', err, volume_type=vol_type)
            raise webob.exc.HTTPConflict(explanation=six.text_type(err))
        except exception.NotFound as err:
            self._notify_volume_type_error(
                context, 'volume_type.create', err, name=name)
            raise webob.exc.HTTPNotFound()

        return self._view_builder.show(req, vol_type)
Пример #30
0
    def _get_image_volume_type(self, context, image_id):
        """Get cinder_img_volume_type property from the image metadata."""

        # Check image existence
        if image_id is None:
            return None

        image_meta = self.image_service.show(context, image_id)

        # check whether image is active
        if image_meta['status'] != 'active':
            msg = (_('Image %(image_id)s is not active.') % {
                'image_id': image_id
            })
            raise exception.InvalidInput(reason=msg)

        # Retrieve 'cinder_img_volume_type' property from glance image
        # metadata.
        image_volume_type = "cinder_img_volume_type"
        properties = image_meta.get('properties')
        if properties:
            try:
                img_vol_type = properties.get(image_volume_type)
                if img_vol_type is None:
                    return None
                volume_type = volume_types.get_volume_type_by_name(
                    context, img_vol_type)
            except exception.VolumeTypeNotFoundByName:
                LOG.warning(
                    _LW("Failed to retrieve volume_type from image "
                        "metadata. '%(img_vol_type)s' doesn't match "
                        "any volume types."), {'img_vol_type': img_vol_type})
                return None

            LOG.debug(
                "Retrieved volume_type from glance image metadata. "
                "image_id: %(image_id)s, "
                "image property: %(image_volume_type)s, "
                "volume_type: %(volume_type)s." % {
                    'image_id': image_id,
                    'image_volume_type': image_volume_type,
                    'volume_type': volume_type
                })
            return volume_type
Пример #31
0
    def _get_image_volume_type(self, context, image_id):
        """Get cinder_img_volume_type property from the image metadata."""

        # Check image existence
        if image_id is None:
            return None

        image_meta = self.image_service.show(context, image_id)

        # check whether image is active
        if image_meta['status'] != 'active':
            msg = (_('Image %(image_id)s is not active.') %
                   {'image_id': image_id})
            raise exception.InvalidInput(reason=msg)

        # Retrieve 'cinder_img_volume_type' property from glance image
        # metadata.
        image_volume_type = "cinder_img_volume_type"
        properties = image_meta.get('properties')
        if properties:
            try:
                img_vol_type = properties.get(image_volume_type)
                if img_vol_type is None:
                    return None
                volume_type = volume_types.get_volume_type_by_name(
                    context,
                    img_vol_type)
            except exception.VolumeTypeNotFoundByName:
                LOG.warning(_LW("Failed to retrieve volume_type from image "
                                "metadata. '%(img_vol_type)s' doesn't match "
                                "any volume types."),
                            {'img_vol_type': img_vol_type})
                return None

            LOG.debug("Retrieved volume_type from glance image metadata. "
                      "image_id: %(image_id)s, "
                      "image property: %(image_volume_type)s, "
                      "volume_type: %(volume_type)s." %
                      {'image_id': image_id,
                       'image_volume_type': image_volume_type,
                       'volume_type': volume_type})
            return volume_type
Пример #32
0
    def test_volume_type_create_then_destroy(self):
        """Ensure volume types can be created and deleted."""
        prev_all_vtypes = volume_types.get_all_types(self.ctxt)

        # create
        type_ref = volume_types.create(self.ctxt,
                                       self.vol_type1_name,
                                       self.vol_type1_specs,
                                       description=self.vol_type1_description)
        new = volume_types.get_volume_type_by_name(self.ctxt,
                                                   self.vol_type1_name)

        LOG.info(_("Given data: %s"), self.vol_type1_specs)
        LOG.info(_("Result data: %s"), new)

        self.assertEqual(self.vol_type1_description, new['description'])

        for k, v in self.vol_type1_specs.iteritems():
            self.assertEqual(v, new['extra_specs'][k],
                             'one of fields does not match')

        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(len(prev_all_vtypes) + 1,
                         len(new_all_vtypes),
                         'drive type was not created')

        # update
        new_type_name = self.vol_type1_name + '_updated'
        new_type_desc = self.vol_type1_description + '_updated'
        type_ref_updated = volume_types.update(self.ctxt,
                                               type_ref.id,
                                               new_type_name,
                                               new_type_desc)
        self.assertEqual(new_type_name, type_ref_updated['name'])
        self.assertEqual(new_type_desc, type_ref_updated['description'])

        # destroy
        volume_types.destroy(self.ctxt, type_ref['id'])
        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(prev_all_vtypes,
                         new_all_vtypes,
                         'drive type was not deleted')
Пример #33
0
 def test_update_volume_type_name_with_db_error(self, mock_update_quota):
     type_ref = volume_types.create(self.ctxt,
                                    self.vol_type1_name,
                                    self.vol_type1_specs,
                                    description=self.vol_type1_description)
     mock_update_quota.side_effect = db_exc.DBError
     new_type_name = self.vol_type1_name + '_updated'
     description = 'new_test'
     is_public = False
     self.assertRaises(exception.VolumeTypeUpdateFailed,
                       volume_types.update, self.ctxt, type_ref.id,
                       new_type_name, description, is_public)
     mock_update_quota.assert_called_once_with(self.ctxt,
                                               self.vol_type1_name,
                                               new_type_name)
     new = volume_types.get_volume_type_by_name(self.ctxt,
                                                self.vol_type1_name)
     self.assertEqual(self.vol_type1_name, new.get('name'))
     self.assertEqual(self.vol_type1_description, new.get('description'))
     self.assertTrue(new.get('is_public'))
     volume_types.destroy(self.ctxt, type_ref.id)
Пример #34
0
 def test_update_volume_type_name_with_db_error(self, mock_update_quota):
     type_ref = volume_types.create(self.ctxt,
                                    self.vol_type1_name,
                                    self.vol_type1_specs,
                                    description=self.vol_type1_description)
     mock_update_quota.side_effect = db_exc.DBError
     new_type_name = self.vol_type1_name + '_updated'
     description = 'new_test'
     is_public = False
     self.assertRaises(exception.VolumeTypeUpdateFailed,
                       volume_types.update, self.ctxt, type_ref.id,
                       new_type_name, description, is_public)
     mock_update_quota.assert_called_once_with(self.ctxt,
                                               self.vol_type1_name,
                                               new_type_name)
     new = volume_types.get_volume_type_by_name(self.ctxt,
                                                self.vol_type1_name)
     self.assertEqual(self.vol_type1_name, new.get('name'))
     self.assertEqual(self.vol_type1_description, new.get('description'))
     self.assertTrue(new.get('is_public'))
     volume_types.destroy(self.ctxt, type_ref.id)
Пример #35
0
    def create(self, req, body):
        """Creates a new volume."""
        context = req.environ["cinder.context"]

        if not body:
            raise exc.HTTPUnprocessableEntity()

        volume = body["volume"]
        size = volume["size"]
        LOG.audit(_("Create volume of %s GB"), size, context=context)

        kwargs = {}

        req_volume_type = volume.get("volume_type", None)
        if req_volume_type:
            try:
                kwargs["volume_type"] = volume_types.get_volume_type_by_name(context, req_volume_type)
            except exception.NotFound:
                raise exc.HTTPNotFound()

        kwargs["metadata"] = volume.get("metadata", None)

        snapshot_id = volume.get("snapshot_id")
        if snapshot_id is not None:
            kwargs["snapshot"] = self.volume_api.get_snapshot(context, snapshot_id)
        else:
            kwargs["snapshot"] = None

        kwargs["availability_zone"] = volume.get("availability_zone", None)

        new_volume = self.volume_api.create(
            context, size, volume.get("display_name"), volume.get("display_description"), **kwargs
        )

        # TODO(vish): Instance should be None at db layer instead of
        #             trying to lazy load, but for now we turn it into
        #             a dict to avoid an error.
        retval = _translate_volume_detail_view(context, dict(new_volume))

        return {"volume": retval}
    def test_volume_type_create_then_destroy(self):
        """Ensure volume types can be created and deleted."""
        prev_all_vtypes = volume_types.get_all_types(self.ctxt)

        # create
        type_ref = volume_types.create(self.ctxt,
                                       self.vol_type1_name,
                                       self.vol_type1_specs,
                                       description=self.vol_type1_description)
        new = volume_types.get_volume_type_by_name(self.ctxt,
                                                   self.vol_type1_name)

        self.assertEqual(self.vol_type1_description, new['description'])

        for k, v in self.vol_type1_specs.items():
            self.assertEqual(v, new['extra_specs'][k],
                             'one of fields does not match')

        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(len(prev_all_vtypes) + 1,
                         len(new_all_vtypes),
                         'drive type was not created')

        # update
        new_type_name = self.vol_type1_name + '_updated'
        new_type_desc = self.vol_type1_description + '_updated'
        type_ref_updated = volume_types.update(self.ctxt,
                                               type_ref.id,
                                               new_type_name,
                                               new_type_desc)
        self.assertEqual(new_type_name, type_ref_updated['name'])
        self.assertEqual(new_type_desc, type_ref_updated['description'])

        # destroy
        volume_types.destroy(self.ctxt, type_ref['id'])
        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(prev_all_vtypes,
                         new_all_vtypes,
                         'drive type was not deleted')
Пример #37
0
    def _create(self, req, body):
        """Creates a new volume type."""
        context = req.environ['cinder.context']
        authorize(context)

        if not self.is_valid_body(body, 'volume_type'):
            raise webob.exc.HTTPBadRequest()

        vol_type = body['volume_type']
        name = vol_type.get('name', None)
        specs = vol_type.get('extra_specs', {})
        is_public = vol_type.get('os-volume-type-access:is_public', True)

        if name is None or name == "":
            raise webob.exc.HTTPBadRequest()

        try:
            volume_types.create(context, name, specs, is_public)
            vol_type = volume_types.get_volume_type_by_name(context, name)
            req.cache_resource(vol_type, name='types')
            notifier_info = dict(volume_types=vol_type)
            rpc.get_notifier('volumeType').info(context, 'volume_type.create',
                                                notifier_info)

        except exception.VolumeTypeExists as err:
            notifier_err = dict(volume_types=vol_type, error_message=err)
            self._notify_volume_type_error(context,
                                           'volume_type.create',
                                           notifier_err)

            raise webob.exc.HTTPConflict(explanation=six.text_type(err))
        except exception.NotFound as err:
            notifier_err = dict(volume_types=vol_type, error_message=err)
            self._notify_volume_type_error(context,
                                           'volume_type.create',
                                           notifier_err)
            raise webob.exc.HTTPNotFound()

        return self._view_builder.show(req, vol_type)
Пример #38
0
    def test_volume_type_create_then_destroy_with_non_admin(self):
        """Ensure volume types can be created and deleted by non-admin user.

        If a non-admn user is authorized at API, volume type operations
        should be permitted.
        """
        prev_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.ctxt = context.RequestContext('fake', 'fake', is_admin=False)

        # create
        type_ref = volume_types.create(self.ctxt,
                                       self.vol_type1_name,
                                       self.vol_type1_specs,
                                       description=self.vol_type1_description)
        new = volume_types.get_volume_type_by_name(self.ctxt,
                                                   self.vol_type1_name)
        self.assertEqual(self.vol_type1_description, new['description'])
        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(len(prev_all_vtypes) + 1,
                         len(new_all_vtypes),
                         'drive type was not created')

        # update
        new_type_name = self.vol_type1_name + '_updated'
        new_type_desc = self.vol_type1_description + '_updated'
        type_ref_updated = volume_types.update(self.ctxt,
                                               type_ref.id,
                                               new_type_name,
                                               new_type_desc)
        self.assertEqual(new_type_name, type_ref_updated['name'])
        self.assertEqual(new_type_desc, type_ref_updated['description'])

        # destroy
        volume_types.destroy(self.ctxt, type_ref['id'])
        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(prev_all_vtypes,
                         new_all_vtypes,
                         'drive type was not deleted')
Пример #39
0
    def _create(self, req, body):
        """Creates a new volume type."""
        context = req.environ['cinder.context']
        authorize(context)

        if not self.is_valid_body(body, 'volume_type'):
            raise webob.exc.HTTPUnprocessableEntity()

        vol_type = body['volume_type']
        name = vol_type.get('name', None)
        specs = vol_type.get('extra_specs', {})

        if name is None or name == "":
            raise webob.exc.HTTPUnprocessableEntity()

        try:
            volume_types.create(context, name, specs)
            vol_type = volume_types.get_volume_type_by_name(context, name)
        except exception.VolumeTypeExists as err:
            raise webob.exc.HTTPConflict(explanation=str(err))
        except exception.NotFound:
            raise webob.exc.HTTPNotFound()

        return self._view_builder.show(req, vol_type)
Пример #40
0
    def _create(self, req, body):
        """Creates a new volume type."""
        context = req.environ['cinder.context']
        authorize(context)

        if not self.is_valid_body(body, 'volume_type'):
            raise webob.exc.HTTPBadRequest()

        vol_type = body['volume_type']
        name = vol_type.get('name', None)
        specs = vol_type.get('extra_specs', {})

        if name is None or name == "":
            raise webob.exc.HTTPBadRequest()

        try:
            volume_types.create(context, name, specs)
            vol_type = volume_types.get_volume_type_by_name(context, name)
        except exception.VolumeTypeExists as err:
            raise webob.exc.HTTPConflict(explanation=str(err))
        except exception.NotFound:
            raise webob.exc.HTTPNotFound()

        return self._view_builder.show(req, vol_type)
Пример #41
0
 def test_ensure_extra_specs_for_admin(self):
     # admin users should get extra-specs back in type-get/list etc
     volume_types.create(self.ctxt, "type-test", is_public=False)
     vtype = volume_types.get_volume_type_by_name(self.ctxt, 'type-test')
     self.assertIsNotNone(vtype.get('extra_specs', None))
Пример #42
0
    def create(self, req, body):
        """Instruct Cinder to manage a storage object.

        Manages an existing backend storage object (e.g. a Linux logical
        volume or a SAN disk) by creating the Cinder objects required to manage
        it, and possibly renaming the backend storage object
        (driver dependent)

        From an API perspective, this operation behaves very much like a
        volume creation operation, except that properties such as image,
        snapshot and volume references don't make sense, because we are taking
        an existing storage object into Cinder management.

        Required HTTP Body:

        .. code-block:: json

         {
           'volume':
           {
             'host': <Cinder host on which the existing storage resides>,
             'ref':  <Driver-specific reference to existing storage object>,
           }
         }

        See the appropriate Cinder drivers' implementations of the
        manage_volume method to find out the accepted format of 'ref'.

        This API call will return with an error if any of the above elements
        are missing from the request, or if the 'host' element refers to a
        cinder host that is not registered.

        The volume will later enter the error state if it is discovered that
        'ref' is bad.

        Optional elements to 'volume' are::

         name               A name for the new volume.
         description        A description for the new volume.
         volume_type        ID or name of a volume type to associate with
                            the new Cinder volume. Does not necessarily
                            guarantee that the managed volume will have the
                            properties described in the volume_type. The
                            driver may choose to fail if it identifies that
                            the specified volume_type is not compatible with
                            the backend storage object.
         metadata           Key/value pairs to be associated with the new
                            volume.
         availability_zone  The availability zone to associate with the new
                            volume.
         bootable           If set to True, marks the volume as bootable.

        """
        context = req.environ['cinder.context']
        authorize(context)

        self.assert_valid_body(body, 'volume')

        volume = body['volume']
        self.validate_name_and_description(volume)

        # Check that the required keys are present, return an error if they
        # are not.
        required_keys = set(['ref', 'host'])
        missing_keys = list(required_keys - set(volume.keys()))

        if missing_keys:
            msg = _("The following elements are required: %s") % \
                ', '.join(missing_keys)
            raise exc.HTTPBadRequest(explanation=msg)

        LOG.debug('Manage volume request body: %s', body)

        kwargs = {}
        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                if not uuidutils.is_uuid_like(req_volume_type):
                    kwargs['volume_type'] = \
                        volume_types.get_volume_type_by_name(
                            context, req_volume_type)
                else:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, req_volume_type)
            except exception.VolumeTypeNotFound as error:
                raise exc.HTTPNotFound(explanation=error.msg)
        else:
            kwargs['volume_type'] = {}

        kwargs['name'] = volume.get('name', None)
        kwargs['description'] = volume.get('description', None)
        kwargs['metadata'] = volume.get('metadata', None)
        kwargs['availability_zone'] = volume.get('availability_zone', None)
        kwargs['bootable'] = volume.get('bootable', False)
        try:
            new_volume = self.volume_api.manage_existing(context,
                                                         volume['host'],
                                                         volume['ref'],
                                                         **kwargs)
        except exception.ServiceNotFound:
            msg = _("Service not found.")
            raise exc.HTTPNotFound(explanation=msg)

        utils.add_visible_admin_metadata(new_volume)

        return self._view_builder.detail(req, new_volume)
Пример #43
0
    def retype(self, context, volume, new_type, migration_policy=None):
        """Attempt to modify the type associated with an existing volume."""
        if volume['status'] not in ['available', 'in-use']:
            msg = _('Unable to update type due to incorrect status '
                    'on volume: %s') % volume['id']
            LOG.error(msg)
            raise exception.InvalidVolume(reason=msg)

        if volume['migration_status'] is not None:
            msg = (_("Volume %s is already part of an active migration.")
                   % volume['id'])
            LOG.error(msg)
            raise exception.InvalidVolume(reason=msg)

        if migration_policy and migration_policy not in ['on-demand', 'never']:
            msg = _('migration_policy must be \'on-demand\' or \'never\', '
                    'passed: %s') % new_type
            LOG.error(msg)
            raise exception.InvalidInput(reason=msg)

        # Support specifying volume type by ID or name
        try:
            if uuidutils.is_uuid_like(new_type):
                vol_type = volume_types.get_volume_type(context, new_type)
            else:
                vol_type = volume_types.get_volume_type_by_name(context,
                                                                new_type)
        except exception.InvalidVolumeType:
            msg = _('Invalid volume_type passed: %s') % new_type
            LOG.error(msg)
            raise exception.InvalidInput(reason=msg)

        vol_type_id = vol_type['id']
        vol_type_qos_id = vol_type['qos_specs_id']

        old_vol_type = None
        old_vol_type_id = volume['volume_type_id']
        old_vol_type_qos_id = None

        # Error if the original and new type are the same
        if volume['volume_type_id'] == vol_type_id:
            msg = (_('New volume_type same as original: %s') % new_type)
            LOG.error(msg)
            raise exception.InvalidInput(reason=msg)

        if volume['volume_type_id']:
            old_vol_type = volume_types.get_volume_type(
                context, old_vol_type_id)
            old_vol_type_qos_id = old_vol_type['qos_specs_id']

        # We don't support changing encryption requirements yet
        old_enc = volume_types.get_volume_type_encryption(context,
                                                          old_vol_type_id)
        new_enc = volume_types.get_volume_type_encryption(context,
                                                          vol_type_id)
        if old_enc != new_enc:
            msg = _('Retype cannot change encryption requirements')
            raise exception.InvalidInput(reason=msg)

        # We don't support changing QoS at the front-end yet for in-use volumes
        # TODO(avishay): Call Nova to change QoS setting (libvirt has support
        # - virDomainSetBlockIoTune() - Nova does not have support yet).
        if (volume['status'] != 'available' and
                old_vol_type_qos_id != vol_type_qos_id):
            for qos_id in [old_vol_type_qos_id, vol_type_qos_id]:
                if qos_id:
                    specs = qos_specs.get_qos_specs(context.elevated(), qos_id)
                    if specs['qos_specs']['consumer'] != 'back-end':
                        msg = _('Retype cannot change front-end qos specs for '
                                'in-use volumes')
                        raise exception.InvalidInput(reason=msg)

        # We're checking here in so that we can report any quota issues as
        # early as possible, but won't commit until we change the type. We
        # pass the reservations onward in case we need to roll back.
        reservations = quota_utils.get_volume_type_reservation(context, volume,
                                                               vol_type_id)

        self.update(context, volume, {'status': 'retyping'})

        request_spec = {'volume_properties': volume,
                        'volume_id': volume['id'],
                        'volume_type': vol_type,
                        'migration_policy': migration_policy,
                        'quota_reservations': reservations}

        self.scheduler_rpcapi.retype(context, CONF.volume_topic, volume['id'],
                                     request_spec=request_spec,
                                     filter_properties={})
Пример #44
0
    def create(self, req, body):
        """Creates a new volume.

        :param req: the request
        :param body: the request body
        :returns: dict -- the new volume dictionary
        :raises: HTTPNotFound, HTTPBadRequest
        """
        self.assert_valid_body(body, 'volume')

        LOG.debug('Create volume request body: %s', body)
        context = req.environ['cinder.context']

        req_version = req.api_version_request
        # Remove group_id from body if max version is less than 3.13.
        if req_version.matches(None, "3.12"):
            # NOTE(xyang): The group_id is from a group created with a
            # group_type. So with this group_id, we've got a group_type
            # for this volume. Also if group_id is passed in, that means
            # we already know which backend is hosting the group and the
            # volume will be created on the same backend as well. So it
            # won't go through the scheduler again if a group_id is
            # passed in.
            try:
                body.get('volume', {}).pop('group_id', None)
            except AttributeError:
                msg = (_("Invalid body provided for creating volume. "
                         "Request API version: %s.") % req_version)
                raise exc.HTTPBadRequest(explanation=msg)

        volume = body['volume']
        kwargs = {}
        self.validate_name_and_description(volume)

        # NOTE(thingee): v2 API allows name instead of display_name
        if 'name' in volume:
            volume['display_name'] = volume.pop('name')

        # NOTE(thingee): v2 API allows description instead of
        #                display_description
        if 'description' in volume:
            volume['display_description'] = volume.pop('description')

        if 'image_id' in volume:
            volume['imageRef'] = volume.pop('image_id')

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            # Not found exception will be handled at the wsgi level
            if not uuidutils.is_uuid_like(req_volume_type):
                kwargs['volume_type'] = (volume_types.get_volume_type_by_name(
                    context, req_volume_type))
            else:
                kwargs['volume_type'] = volume_types.get_volume_type(
                    context, req_volume_type)

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            # Not found exception will be handled at the wsgi level
            kwargs['snapshot'] = self.volume_api.get_snapshot(
                context, snapshot_id)
        else:
            kwargs['snapshot'] = None

        source_volid = volume.get('source_volid')
        if source_volid is not None:
            # Not found exception will be handled at the wsgi level
            kwargs['source_volume'] = (self.volume_api.get_volume(
                context, source_volid))
        else:
            kwargs['source_volume'] = None

        source_replica = volume.get('source_replica')
        if source_replica is not None:
            # Not found exception will be handled at the wsgi level
            src_vol = self.volume_api.get_volume(context, source_replica)
            if src_vol['replication_status'] == 'disabled':
                explanation = _('source volume id:%s is not'
                                ' replicated') % source_replica
                raise exc.HTTPBadRequest(explanation=explanation)
            kwargs['source_replica'] = src_vol
        else:
            kwargs['source_replica'] = None

        consistencygroup_id = volume.get('consistencygroup_id')
        if consistencygroup_id is not None:
            # Not found exception will be handled at the wsgi level
            kwargs['consistencygroup'] = (self.consistencygroup_api.get(
                context, consistencygroup_id))
        else:
            kwargs['consistencygroup'] = None

        # Get group_id if volume is in a group.
        group_id = volume.get('group_id')
        if group_id is not None:
            try:
                kwargs['group'] = self.group_api.get(context, group_id)
            except exception.GroupNotFound as error:
                raise exc.HTTPNotFound(explanation=error.msg)

        size = volume.get('size', None)
        if size is None and kwargs['snapshot'] is not None:
            size = kwargs['snapshot']['volume_size']
        elif size is None and kwargs['source_volume'] is not None:
            size = kwargs['source_volume']['size']
        elif size is None and kwargs['source_replica'] is not None:
            size = kwargs['source_replica']['size']

        LOG.info(_LI("Create volume of %s GB"), size)

        if self.ext_mgr.is_loaded('os-image-create'):
            image_ref = volume.get('imageRef')
            if image_ref is not None:
                image_uuid = self._image_uuid_from_ref(image_ref, context)
                kwargs['image_id'] = image_uuid

        kwargs['availability_zone'] = volume.get('availability_zone', None)
        kwargs['scheduler_hints'] = volume.get('scheduler_hints', None)
        multiattach = volume.get('multiattach', False)
        kwargs['multiattach'] = multiattach

        new_volume = self.volume_api.create(context, size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        retval = self._view_builder.detail(req, new_volume)

        return retval
Пример #45
0
    def create(self, req, body):
        """Instruct Cinder to manage a storage object.

        Manages an existing backend storage object (e.g. a Linux logical
        volume or a SAN disk) by creating the Cinder objects required to manage
        it, and possibly renaming the backend storage object
        (driver dependent)

        From an API perspective, this operation behaves very much like a
        volume creation operation, except that properties such as image,
        snapshot and volume references don't make sense, because we are taking
        an existing storage object into Cinder management.

        Required HTTP Body:

        {
         'volume':
          {
           'host': <Cinder host on which the existing storage resides>,
           'ref':  <Driver-specific reference to the existing storage object>,
          }
        }

        See the appropriate Cinder drivers' implementations of the
        manage_volume method to find out the accepted format of 'ref'.

        This API call will return with an error if any of the above elements
        are missing from the request, or if the 'host' element refers to a
        cinder host that is not registered.

        The volume will later enter the error state if it is discovered that
        'ref' is bad.

        Optional elements to 'volume' are:
            name               A name for the new volume.
            description        A description for the new volume.
            volume_type        ID or name of a volume type to associate with
                               the new Cinder volume.  Does not necessarily
                               guarantee that the managed volume will have the
                               properties described in the volume_type.  The
                               driver may choose to fail if it identifies that
                               the specified volume_type is not compatible with
                               the backend storage object.
            metadata           Key/value pairs to be associated with the new
                               volume.
            availability_zone  The availability zone to associate with the new
                               volume.
            bootable           If set to True, marks the volume as bootable.
        """
        context = req.environ['cinder.context']
        authorize(context)

        self.assert_valid_body(body, 'volume')

        volume = body['volume']

        # Check that the required keys are present, return an error if they
        # are not.
        required_keys = set(['ref', 'host'])
        missing_keys = list(required_keys - set(volume.keys()))

        if missing_keys:
            msg = _("The following elements are required: %s") % \
                ', '.join(missing_keys)
            raise exc.HTTPBadRequest(explanation=msg)

        LOG.debug('Manage volume request body: %s', body)

        kwargs = {}
        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                if not uuidutils.is_uuid_like(req_volume_type):
                    kwargs['volume_type'] = \
                        volume_types.get_volume_type_by_name(
                            context, req_volume_type)
                else:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, req_volume_type)
            except exception.VolumeTypeNotFound as error:
                raise exc.HTTPNotFound(explanation=error.msg)
        else:
            kwargs['volume_type'] = {}

        kwargs['name'] = volume.get('name', None)
        kwargs['description'] = volume.get('description', None)
        kwargs['metadata'] = volume.get('metadata', None)
        kwargs['availability_zone'] = volume.get('availability_zone', None)
        kwargs['bootable'] = volume.get('bootable', False)
        try:
            new_volume = self.volume_api.manage_existing(
                context, volume['host'], volume['ref'], **kwargs)
        except exception.ServiceNotFound:
            msg = _("Service not found.")
            raise exc.HTTPNotFound(explanation=msg)

        new_volume = dict(new_volume)
        utils.add_visible_admin_metadata(new_volume)

        return self._view_builder.detail(req, new_volume)
Пример #46
0
    def retype(self, context, volume, new_type, migration_policy=None):
        """Attempt to modify the type associated with an existing volume."""
        if volume['status'] not in ['available', 'in-use']:
            msg = _('Unable to update type due to incorrect status '
                    'on volume: %s') % volume['id']
            LOG.error(msg)
            raise exception.InvalidVolume(reason=msg)

        if volume['migration_status'] is not None:
            msg = (_("Volume %s is already part of an active migration.") %
                   volume['id'])
            LOG.error(msg)
            raise exception.InvalidVolume(reason=msg)

        if migration_policy and migration_policy not in ['on-demand', 'never']:
            msg = _('migration_policy must be \'on-demand\' or \'never\', '
                    'passed: %s') % new_type
            LOG.error(msg)
            raise exception.InvalidInput(reason=msg)

        # Support specifying volume type by ID or name
        try:
            if uuidutils.is_uuid_like(new_type):
                vol_type = volume_types.get_volume_type(context, new_type)
            else:
                vol_type = volume_types.get_volume_type_by_name(
                    context, new_type)
        except exception.InvalidVolumeType:
            msg = _('Invalid volume_type passed: %s') % new_type
            LOG.error(msg)
            raise exception.InvalidInput(reason=msg)

        vol_type_id = vol_type['id']
        vol_type_qos_id = vol_type['qos_specs_id']

        old_vol_type = None
        old_vol_type_id = volume['volume_type_id']
        old_vol_type_qos_id = None

        # Error if the original and new type are the same
        if volume['volume_type_id'] == vol_type_id:
            msg = (_('New volume_type same as original: %s') % new_type)
            LOG.error(msg)
            raise exception.InvalidInput(reason=msg)

        if volume['volume_type_id']:
            old_vol_type = volume_types.get_volume_type(
                context, old_vol_type_id)
            old_vol_type_qos_id = old_vol_type['qos_specs_id']

        # We don't support changing encryption requirements yet
        old_enc = volume_types.get_volume_type_encryption(
            context, old_vol_type_id)
        new_enc = volume_types.get_volume_type_encryption(context, vol_type_id)
        if old_enc != new_enc:
            msg = _('Retype cannot change encryption requirements')
            raise exception.InvalidInput(reason=msg)

        # We don't support changing QoS at the front-end yet for in-use volumes
        # TODO(avishay): Call Nova to change QoS setting (libvirt has support
        # - virDomainSetBlockIoTune() - Nova does not have support yet).
        if (volume['status'] != 'available'
                and old_vol_type_qos_id != vol_type_qos_id):
            for qos_id in [old_vol_type_qos_id, vol_type_qos_id]:
                if qos_id:
                    specs = qos_specs.get_qos_specs(context.elevated(), qos_id)
                    if specs['qos_specs']['consumer'] != 'back-end':
                        msg = _('Retype cannot change front-end qos specs for '
                                'in-use volumes')
                        raise exception.InvalidInput(reason=msg)

        # We're checking here in so that we can report any quota issues as
        # early as possible, but won't commit until we change the type. We
        # pass the reservations onward in case we need to roll back.
        reservations = quota_utils.get_volume_type_reservation(
            context, volume, vol_type_id)

        self.update(context, volume, {'status': 'retyping'})

        request_spec = {
            'volume_properties': volume,
            'volume_id': volume['id'],
            'volume_type': vol_type,
            'migration_policy': migration_policy,
            'quota_reservations': reservations
        }

        self.scheduler_rpcapi.retype(context,
                                     CONF.volume_topic,
                                     volume['id'],
                                     request_spec=request_spec,
                                     filter_properties={})
Пример #47
0
    def create(self, req, body):
        """Creates a new volume."""
        if not self.is_valid_body(body, 'volume'):
            raise exc.HTTPUnprocessableEntity()

        LOG.debug('Create volume request body: %s', body)
        context = req.environ['cinder.context']
        volume = body['volume']

        kwargs = {}

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                if not uuidutils.is_uuid_like(req_volume_type):
                    kwargs['volume_type'] = \
                        volume_types.get_volume_type_by_name(
                            context, req_volume_type)
                else:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, req_volume_type)
            except exception.VolumeTypeNotFound:
                explanation = 'Volume type not found.'
                raise exc.HTTPNotFound(explanation=explanation)

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            try:
                kwargs['snapshot'] = self.volume_api.get_snapshot(context,
                                                                  snapshot_id)
            except exception.NotFound:
                explanation = _('snapshot id:%s not found') % snapshot_id
                raise exc.HTTPNotFound(explanation=explanation)

        else:
            kwargs['snapshot'] = None

        source_volid = volume.get('source_volid')
        if source_volid is not None:
            try:
                kwargs['source_volume'] = \
                    self.volume_api.get_volume(context,
                                               source_volid)
            except exception.NotFound:
                explanation = _('source vol id:%s not found') % source_volid
                raise exc.HTTPNotFound(explanation=explanation)
        else:
            kwargs['source_volume'] = None

        size = volume.get('size', None)
        if size is None and kwargs['snapshot'] is not None:
            size = kwargs['snapshot']['volume_size']
        elif size is None and kwargs['source_volume'] is not None:
            size = kwargs['source_volume']['size']

        LOG.audit(_("Create volume of %s GB"), size, context=context)

        image_href = None
        image_uuid = None
        if self.ext_mgr.is_loaded('os-image-create'):
            # NOTE(jdg): misleading name "imageRef" as it's an image-id
            image_href = volume.get('imageRef')
            if image_href:
                image_uuid = self._image_uuid_from_href(image_href)
                kwargs['image_id'] = image_uuid

        kwargs['availability_zone'] = volume.get('availability_zone', None)

        new_volume = self.volume_api.create(context,
                                            size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        # TODO(vish): Instance should be None at db layer instead of
        #             trying to lazy load, but for now we turn it into
        #             a dict to avoid an error.
        new_volume = dict(new_volume.iteritems())

        self._add_visible_admin_metadata(context, new_volume)

        retval = _translate_volume_detail_view(context, new_volume, image_uuid)

        return {'volume': retval}
Пример #48
0
 def test_ensure_extra_specs_for_admin(self):
     # admin users should get extra-specs back in type-get/list etc
     volume_types.create(self.ctxt, "type-test", is_public=False)
     vtype = volume_types.get_volume_type_by_name(self.ctxt, 'type-test')
     self.assertIsNotNone(vtype.get('extra_specs', None))
Пример #49
0
    def create(self, req, body):
        """Creates a new volume."""
        if not self.is_valid_body(body, 'volume'):
            raise exc.HTTPUnprocessableEntity()

        LOG.debug('Create volume request body: %s', body)
        context = req.environ['cinder.context']
        volume = body['volume']

        kwargs = {}

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                if not uuidutils.is_uuid_like(req_volume_type):
                    kwargs['volume_type'] = \
                        volume_types.get_volume_type_by_name(
                            context, req_volume_type)
                else:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, req_volume_type)
            except exception.VolumeTypeNotFound:
                explanation = 'Volume type not found.'
                raise exc.HTTPNotFound(explanation=explanation)

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            kwargs['snapshot'] = self.volume_api.get_snapshot(context,
                                                              snapshot_id)
        else:
            kwargs['snapshot'] = None

        source_volid = volume.get('source_volid')
        if source_volid is not None:
            kwargs['source_volume'] = self.volume_api.get_volume(context,
                                                                 source_volid)
        else:
            kwargs['source_volume'] = None

        size = volume.get('size', None)
        if size is None and kwargs['snapshot'] is not None:
            size = kwargs['snapshot']['volume_size']
        elif size is None and kwargs['source_volume'] is not None:
            size = kwargs['source_volume']['size']

        LOG.audit(_("Create volume of %s GB"), size, context=context)

        image_href = None
        image_uuid = None
        if self.ext_mgr.is_loaded('os-image-create'):
            # NOTE(jdg): misleading name "imageRef" as it's an image-id
            image_href = volume.get('imageRef')
            if image_href:
                image_uuid = self._image_uuid_from_href(image_href)
                kwargs['image_id'] = image_uuid

        kwargs['availability_zone'] = volume.get('availability_zone', None)

        new_volume = self.volume_api.create(context,
                                            size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        # TODO(vish): Instance should be None at db layer instead of
        #             trying to lazy load, but for now we turn it into
        #             a dict to avoid an error.
        new_volume = dict(new_volume.iteritems())

        self._add_visible_admin_metadata(context, new_volume)

        retval = _translate_volume_detail_view(context, new_volume, image_uuid)

        return {'volume': retval}
Пример #50
0
    def create(self, req, body):
        """Creates a new volume."""
        self.assert_valid_body(body, 'volume')

        LOG.debug('Create volume request body: %s', body)
        context = req.environ['cinder.context']
        volume = body['volume']

        kwargs = {}
        self.validate_name_and_description(volume)

        # NOTE(thingee): v2 API allows name instead of display_name
        if 'name' in volume:
            volume['display_name'] = volume.pop('name')

        # NOTE(thingee): v2 API allows description instead of
        #                display_description
        if 'description' in volume:
            volume['display_description'] = volume.pop('description')

        if 'image_id' in volume:
            volume['imageRef'] = volume.pop('image_id')

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            # Not found exception will be handled at the wsgi level
            if not uuidutils.is_uuid_like(req_volume_type):
                kwargs['volume_type'] = \
                    volume_types.get_volume_type_by_name(
                        context, req_volume_type)
            else:
                kwargs['volume_type'] = volume_types.get_volume_type(
                    context, req_volume_type)

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            # Not found exception will be handled at the wsgi level
            kwargs['snapshot'] = self.volume_api.get_snapshot(
                context, snapshot_id)
        else:
            kwargs['snapshot'] = None

        source_volid = volume.get('source_volid')
        if source_volid is not None:
            # Not found exception will be handled at the wsgi level
            kwargs['source_volume'] = \
                self.volume_api.get_volume(context,
                                           source_volid)
        else:
            kwargs['source_volume'] = None

        source_replica = volume.get('source_replica')
        if source_replica is not None:
            # Not found exception will be handled at the wsgi level
            src_vol = self.volume_api.get_volume(context, source_replica)
            if src_vol['replication_status'] == 'disabled':
                explanation = _('source volume id:%s is not'
                                ' replicated') % source_replica
                raise exc.HTTPBadRequest(explanation=explanation)
            kwargs['source_replica'] = src_vol
        else:
            kwargs['source_replica'] = None

        consistencygroup_id = volume.get('consistencygroup_id')
        if consistencygroup_id is not None:
            # Not found exception will be handled at the wsgi level
            kwargs['consistencygroup'] = \
                self.consistencygroup_api.get(context,
                                              consistencygroup_id)
        else:
            kwargs['consistencygroup'] = None

        size = volume.get('size', None)
        if size is None and kwargs['snapshot'] is not None:
            size = kwargs['snapshot']['volume_size']
        elif size is None and kwargs['source_volume'] is not None:
            size = kwargs['source_volume']['size']
        elif size is None and kwargs['source_replica'] is not None:
            size = kwargs['source_replica']['size']

        LOG.info(_LI("Create volume of %s GB"), size)

        if self.ext_mgr.is_loaded('os-image-create'):
            image_ref = volume.get('imageRef')
            if image_ref is not None:
                image_uuid = self._image_uuid_from_ref(image_ref, context)
                kwargs['image_id'] = image_uuid

        kwargs['availability_zone'] = volume.get('availability_zone', None)
        kwargs['scheduler_hints'] = volume.get('scheduler_hints', None)
        multiattach = volume.get('multiattach', False)
        kwargs['multiattach'] = multiattach

        new_volume = self.volume_api.create(context, size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        retval = self._view_builder.detail(req, new_volume)

        return retval
Пример #51
0
    def create(self, req, body):
        """Creates a new volume."""
        if not self.is_valid_body(body, 'volume'):
            msg = _("Missing required element '%s' in request body") % 'volume'
            raise exc.HTTPBadRequest(explanation=msg)

        LOG.debug('Create volume request body: %s', body)
        context = req.environ['cinder.context']
        volume = body['volume']

        kwargs = {}

        # NOTE(thingee): v2 API allows name instead of display_name
        if volume.get('name'):
            volume['display_name'] = volume.get('name')
            del volume['name']

        # NOTE(thingee): v2 API allows description instead of
        #                display_description
        if volume.get('description'):
            volume['display_description'] = volume.get('description')
            del volume['description']

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                if not uuidutils.is_uuid_like(req_volume_type):
                    kwargs['volume_type'] = \
                        volume_types.get_volume_type_by_name(
                            context, req_volume_type)
                else:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, req_volume_type)
            except exception.VolumeTypeNotFound:
                msg = _("Volume type not found.")
                raise exc.HTTPNotFound(explanation=msg)

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            try:
                kwargs['snapshot'] = self.volume_api.get_snapshot(
                    context, snapshot_id)
            except exception.NotFound:
                explanation = _('snapshot id:%s not found') % snapshot_id
                raise exc.HTTPNotFound(explanation=explanation)
        else:
            kwargs['snapshot'] = None

        source_volid = volume.get('source_volid')
        if source_volid is not None:
            try:
                kwargs['source_volume'] = \
                    self.volume_api.get_volume(context,
                                               source_volid)
            except exception.NotFound:
                explanation = _('source volume id:%s not found') % source_volid
                raise exc.HTTPNotFound(explanation=explanation)
        else:
            kwargs['source_volume'] = None

        size = volume.get('size', None)
        if size is None and kwargs['snapshot'] is not None:
            size = kwargs['snapshot']['volume_size']
        elif size is None and kwargs['source_volume'] is not None:
            size = kwargs['source_volume']['size']

        LOG.audit(_("Create volume of %s GB"), size, context=context)

        if self.ext_mgr.is_loaded('os-image-create'):
            image_href = volume.get('imageRef')
            if image_href:
                image_uuid = self._image_uuid_from_href(image_href)
                kwargs['image_id'] = image_uuid

        kwargs['availability_zone'] = volume.get('availability_zone', None)
        kwargs['scheduler_hints'] = volume.get('scheduler_hints', None)

        new_volume = self.volume_api.create(context, size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        # TODO(vish): Instance should be None at db layer instead of
        #             trying to lazy load, but for now we turn it into
        #             a dict to avoid an error.
        new_volume = dict(new_volume.iteritems())

        self._add_visible_admin_metadata(context, new_volume)

        retval = self._view_builder.detail(req, new_volume)

        return retval
Пример #52
0
    def create(self, req, body):
        """Creates a new volume."""
        self.assert_valid_body(body, 'volume')

        LOG.debug('Create volume request body: %s', body)
        context = req.environ['cinder.context']
        volume = body['volume']

        kwargs = {}

        # NOTE(thingee): v2 API allows name instead of display_name
        if volume.get('name'):
            volume['display_name'] = volume.get('name')
            del volume['name']

        # NOTE(thingee): v2 API allows description instead of
        #                display_description
        if volume.get('description'):
            volume['display_description'] = volume.get('description')
            del volume['description']

        if 'image_id' in volume:
            volume['imageRef'] = volume.get('image_id')
            del volume['image_id']

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                if not uuidutils.is_uuid_like(req_volume_type):
                    kwargs['volume_type'] = \
                        volume_types.get_volume_type_by_name(
                            context, req_volume_type)
                else:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, req_volume_type)
            except exception.VolumeTypeNotFound as error:
                raise exc.HTTPNotFound(explanation=error.msg)

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            try:
                kwargs['snapshot'] = self.volume_api.get_snapshot(context,
                                                                  snapshot_id)
            except exception.SnapshotNotFound as error:
                raise exc.HTTPNotFound(explanation=error.msg)
        else:
            kwargs['snapshot'] = None

        source_volid = volume.get('source_volid')
        if source_volid is not None:
            try:
                kwargs['source_volume'] = \
                    self.volume_api.get_volume(context,
                                               source_volid)
            except exception.VolumeNotFound as error:
                raise exc.HTTPNotFound(explanation=error.msg)
        else:
            kwargs['source_volume'] = None

        source_replica = volume.get('source_replica')
        if source_replica is not None:
            try:
                src_vol = self.volume_api.get_volume(context,
                                                     source_replica)
                if src_vol['replication_status'] == 'disabled':
                    explanation = _('source volume id:%s is not'
                                    ' replicated') % source_volid
                    raise exc.HTTPBadRequest(explanation=explanation)
                kwargs['source_replica'] = src_vol
            except exception.VolumeNotFound as error:
                raise exc.HTTPNotFound(explanation=error.msg)
        else:
            kwargs['source_replica'] = None

        consistencygroup_id = volume.get('consistencygroup_id')
        if consistencygroup_id is not None:
            try:
                kwargs['consistencygroup'] = \
                    self.consistencygroup_api.get(context,
                                                  consistencygroup_id)
            except exception.ConsistencyGroupNotFound as error:
                raise exc.HTTPNotFound(explanation=error.msg)
        else:
            kwargs['consistencygroup'] = None

        size = volume.get('size', None)
        if size is None and kwargs['snapshot'] is not None:
            size = kwargs['snapshot']['volume_size']
        elif size is None and kwargs['source_volume'] is not None:
            size = kwargs['source_volume']['size']
        elif size is None and kwargs['source_replica'] is not None:
            size = kwargs['source_replica']['size']

        LOG.info(_LI("Create volume of %s GB"), size, context=context)

        if self.ext_mgr.is_loaded('os-image-create'):
            image_ref = volume.get('imageRef')
            if image_ref is not None:
                image_uuid = self._image_uuid_from_ref(image_ref, context)
                kwargs['image_id'] = image_uuid

        kwargs['availability_zone'] = volume.get('availability_zone', None)
        kwargs['scheduler_hints'] = volume.get('scheduler_hints', None)
        multiattach = volume.get('multiattach', False)
        kwargs['multiattach'] = multiattach

        new_volume = self.volume_api.create(context,
                                            size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        # TODO(vish): Instance should be None at db layer instead of
        #             trying to lazy load, but for now we turn it into
        #             a dict to avoid an error.
        new_volume = dict(new_volume)
        retval = self._view_builder.detail(req, new_volume)

        return retval
Пример #53
0
    def create(self, req, body):
        """Creates a new volume."""
        if not self.is_valid_body(body, 'volume'):
            msg = _("Missing required element '%s' in request body") % 'volume'
            raise exc.HTTPBadRequest(explanation=msg)

        LOG.debug('Create volume request body: %s', body)
        context = req.environ['cinder.context']
        volume = body['volume']

        kwargs = {}

        # NOTE(thingee): v2 API allows name instead of display_name
        if volume.get('name'):
            volume['display_name'] = volume.get('name')
            del volume['name']

        # NOTE(thingee): v2 API allows description instead of
        #                display_description
        if volume.get('description'):
            volume['display_description'] = volume.get('description')
            del volume['description']

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                if not uuidutils.is_uuid_like(req_volume_type):
                    kwargs['volume_type'] = \
                        volume_types.get_volume_type_by_name(
                            context, req_volume_type)
                else:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, req_volume_type)
            except exception.VolumeTypeNotFound:
                msg = _("Volume type not found.")
                raise exc.HTTPNotFound(explanation=msg)

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            try:
                kwargs['snapshot'] = self.volume_api.get_snapshot(context,
                                                                  snapshot_id)
            except exception.NotFound:
                explanation = _('snapshot id:%s not found') % snapshot_id
                raise exc.HTTPNotFound(explanation=explanation)
        else:
            kwargs['snapshot'] = None

        source_volid = volume.get('source_volid')
        if source_volid is not None:
            try:
                kwargs['source_volume'] = \
                    self.volume_api.get_volume(context,
                                               source_volid)
            except exception.NotFound:
                explanation = _('source volume id:%s not found') % source_volid
                raise exc.HTTPNotFound(explanation=explanation)
        else:
            kwargs['source_volume'] = None

        size = volume.get('size', None)
        if size is None and kwargs['snapshot'] is not None:
            size = kwargs['snapshot']['volume_size']
        elif size is None and kwargs['source_volume'] is not None:
            size = kwargs['source_volume']['size']

        LOG.audit(_("Create volume of %s GB"), size, context=context)

        if self.ext_mgr.is_loaded('os-image-create'):
            image_href = volume.get('imageRef')
            if image_href:
                image_uuid = self._image_uuid_from_href(image_href)
                kwargs['image_id'] = image_uuid

        kwargs['availability_zone'] = volume.get('availability_zone', None)
        kwargs['scheduler_hints'] = volume.get('scheduler_hints', None)

        new_volume = self.volume_api.create(context,
                                            size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        # TODO(vish): Instance should be None at db layer instead of
        #             trying to lazy load, but for now we turn it into
        #             a dict to avoid an error.
        new_volume = dict(new_volume.iteritems())
        retval = self._view_builder.detail(req, new_volume)

        return retval
Пример #54
0
    def create(self, req, body):
        """Creates a new volume."""
        if not self.is_valid_body(body, 'volume'):
            raise exc.HTTPUnprocessableEntity()

        LOG.debug('Create volume request body: %s', body)
        context = req.environ['cinder.context']
        volume = body['volume']

        kwargs = {}

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                if not uuidutils.is_uuid_like(req_volume_type):
                    kwargs['volume_type'] = \
                        volume_types.get_volume_type_by_name(
                            context, req_volume_type)
                else:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, req_volume_type)
            except exception.VolumeTypeNotFound:
                explanation = 'Volume type not found.'
                raise exc.HTTPNotFound(explanation=explanation)

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            try:
                kwargs['snapshot'] = self.volume_api.get_snapshot(
                    context, snapshot_id)
            except exception.NotFound:
                explanation = _('snapshot id:%s not found') % snapshot_id
                raise exc.HTTPNotFound(explanation=explanation)

        else:
            kwargs['snapshot'] = None

        source_volid = volume.get('source_volid')
        if source_volid is not None:
            try:
                kwargs['source_volume'] = \
                    self.volume_api.get_volume(context,
                                               source_volid)
            except exception.NotFound:
                explanation = _('source vol id:%s not found') % source_volid
                raise exc.HTTPNotFound(explanation=explanation)
        else:
            kwargs['source_volume'] = None

        size = volume.get('size', None)
        if size is None and kwargs['snapshot'] is not None:
            size = kwargs['snapshot']['volume_size']
        elif size is None and kwargs['source_volume'] is not None:
            size = kwargs['source_volume']['size']

        LOG.info(_LI("Create volume of %s GB"), size, context=context)
        multiattach = volume.get('multiattach', False)
        kwargs['multiattach'] = multiattach

        image_href = None
        image_uuid = None
        if self.ext_mgr.is_loaded('os-image-create'):
            # NOTE(jdg): misleading name "imageRef" as it's an image-id
            image_href = volume.get('imageRef')
            if image_href is not None:
                image_uuid = self._image_uuid_from_href(image_href)
                kwargs['image_id'] = image_uuid

        kwargs['availability_zone'] = volume.get('availability_zone', None)

        new_volume = self.volume_api.create(context, size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        retval = _translate_volume_detail_view(context, new_volume, image_uuid)

        return {'volume': retval}