Example #1
0
    def test_provision_filter_on_size(self):
        volume_types.create(self.ctxt, "type1", {
            "key1": "val1",
            "key2": "val2"
        })
        volume_types.create(self.ctxt, "type2", {
            volume_types.MIN_SIZE_KEY: "12",
            "key3": "val3"
        })
        volume_types.create(self.ctxt, "type3", {
            volume_types.MAX_SIZE_KEY: "99",
            "key4": "val4"
        })
        volume_types.create(
            self.ctxt, "type4", {
                volume_types.MIN_SIZE_KEY: "24",
                volume_types.MAX_SIZE_KEY: "99",
                "key4": "val4"
            })

        # Make sure we don't raise if there are no min/max set
        type1 = volume_types.get_by_name_or_id(self.ctxt, 'type1')
        volume_types.provision_filter_on_size(self.ctxt, type1, "11")

        # verify minimum size requirements
        type2 = volume_types.get_by_name_or_id(self.ctxt, 'type2')
        self.assertRaises(exception.InvalidInput,
                          volume_types.provision_filter_on_size, self.ctxt,
                          type2, "11")
        volume_types.provision_filter_on_size(self.ctxt, type2, "12")
        volume_types.provision_filter_on_size(self.ctxt, type2, "100")

        # verify max size requirements
        type3 = volume_types.get_by_name_or_id(self.ctxt, 'type3')
        self.assertRaises(exception.InvalidInput,
                          volume_types.provision_filter_on_size, self.ctxt,
                          type3, "100")
        volume_types.provision_filter_on_size(self.ctxt, type3, "99")
        volume_types.provision_filter_on_size(self.ctxt, type3, "1")

        # verify min and max
        type4 = volume_types.get_by_name_or_id(self.ctxt, 'type4')
        self.assertRaises(exception.InvalidInput,
                          volume_types.provision_filter_on_size, self.ctxt,
                          type4, "20")
        self.assertRaises(exception.InvalidInput,
                          volume_types.provision_filter_on_size, self.ctxt,
                          type4, "130")
        volume_types.provision_filter_on_size(self.ctxt, type4, "24")
        volume_types.provision_filter_on_size(self.ctxt, type4, "99")
        volume_types.provision_filter_on_size(self.ctxt, type4, "30")
Example #2
0
 def get_by_name_or_id(cls, context, identity):
     orm_obj = volume_types.get_by_name_or_id(context, identity)
     expected_attrs = cls._get_expected_attrs(context)
     return cls._from_db_object(context,
                                cls(context),
                                orm_obj,
                                expected_attrs=expected_attrs)
Example #3
0
 def test_get_volume_type_by_name_with_uuid_name(self):
     """Ensure volume types can be created and found."""
     uuid_format_name = uuidutils.generate_uuid()
     volume_types.create(self.ctxt,
                         uuid_format_name,
                         self.vol_type1_specs,
                         description=self.vol_type1_description)
     type_ref = volume_types.get_by_name_or_id(self.ctxt, uuid_format_name)
     self.assertEqual(uuid_format_name, type_ref['name'])
Example #4
0
 def test_get_volume_type_by_name_with_uuid_name(self):
     """Ensure volume types can be created and found."""
     uuid_format_name = uuidutils.generate_uuid()
     volume_types.create(self.ctxt, uuid_format_name,
                         self.vol_type1_specs,
                         description=self.vol_type1_description)
     type_ref = volume_types.get_by_name_or_id(self.ctxt,
                                               uuid_format_name)
     self.assertEqual(uuid_format_name, type_ref['name'])
Example #5
0
    def get_pools(self, context, filters=None):
        """Returns a dict of all pools on all hosts HostManager knows about."""

        self._update_backend_state_map(context)

        all_pools = {}
        name = volume_type = None
        if filters:
            name = filters.pop('name', None)
            volume_type = filters.pop('volume_type', None)

        for backend_key, state in self.backend_state_map.items():
            for key in state.pools:
                filtered = False
                pool = state.pools[key]
                # use backend_key.pool_name to make sure key is unique
                pool_key = volume_utils.append_host(backend_key,
                                                    pool.pool_name)
                new_pool = dict(name=pool_key)
                new_pool.update(dict(capabilities=pool.capabilities))

                if name and new_pool.get('name') != name:
                    continue

                if filters:
                    # filter all other items in capabilities
                    for (attr, value) in filters.items():
                        cap = new_pool.get('capabilities').get(attr)
                        if not self._equal_after_convert(cap, value):
                            filtered = True
                            break

                if not filtered:
                    all_pools[pool_key] = pool

        # filter pools by volume type
        if volume_type:
            volume_type = volume_types.get_by_name_or_id(context, volume_type)
            all_pools = (self._filter_pools_by_volume_type(
                context, volume_type, all_pools))

        # encapsulate pools in format:{name: XXX, capabilities: XXX}
        return [
            dict(name=key, capabilities=value.capabilities)
            for key, value in all_pools.items()
        ]
Example #6
0
    def get_pools(self, context, filters=None):
        """Returns a dict of all pools on all hosts HostManager knows about."""

        self._update_backend_state_map(context)

        all_pools = {}
        name = volume_type = None
        if filters:
            name = filters.pop('name', None)
            volume_type = filters.pop('volume_type', None)

        for backend_key, state in self.backend_state_map.items():
            for key in state.pools:
                filtered = False
                pool = state.pools[key]
                # use backend_key.pool_name to make sure key is unique
                pool_key = vol_utils.append_host(backend_key, pool.pool_name)
                new_pool = dict(name=pool_key)
                new_pool.update(dict(capabilities=pool.capabilities))

                if name and new_pool.get('name') != name:
                    continue

                if filters:
                    # filter all other items in capabilities
                    for (attr, value) in filters.items():
                        cap = new_pool.get('capabilities').get(attr)
                        if not self._equal_after_convert(cap, value):
                            filtered = True
                            break

                if not filtered:
                    all_pools[pool_key] = pool

        # filter pools by volume type
        if volume_type:
            volume_type = volume_types.get_by_name_or_id(
                context, volume_type)
            all_pools = (
                self._filter_pools_by_volume_type(context,
                                                  volume_type,
                                                  all_pools))

        # encapsulate pools in format:{name: XXX, capabilities: XXX}
        return [dict(name=key, capabilities=value.capabilities)
                for key, value in all_pools.items()]
Example #7
0
 def setUp(self):
     super(VolumeTypesApiTest, self).setUp()
     self.controller = types.VolumeTypesController()
     self.ctxt = context.RequestContext(user_id=fake.USER_ID,
                                        project_id=fake.PROJECT_ID,
                                        is_admin=True)
     self.mock_authorize = self.patch(
         'cinder.context.RequestContext.authorize')
     # since __DEFAULT__ type always exists, total number of volume types
     # is total_types_created + 1. In this case it's 4
     self.type_id1 = self._create_volume_type('volume_type1',
                                              {'key1': 'value1'})
     self.type_id2 = self._create_volume_type('volume_type2',
                                              {'key2': 'value2'})
     self.type_id3 = self._create_volume_type('volume_type3',
                                              {'key3': 'value3'}, False,
                                              [fake.PROJECT_ID])
     self.default_type = volume_types.get_default_volume_type()['id']
     self.vol_type = volume_types.get_by_name_or_id(
         context.get_admin_context(), '__DEFAULT__')['id']
    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>",
             "cluster": "<Cinder cluster on which the 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']
        context.authorize(policy.MANAGE_POLICY)

        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.
        if 'ref' not in volume:
            raise exception.MissingRequired(element='ref')

        cluster_name, host = common.get_cluster_host(req, volume,
                                                     mv.VOLUME_MIGRATE_CLUSTER)

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

        kwargs = {}
        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                kwargs['volume_type'] = volume_types.get_by_name_or_id(
                    context, req_volume_type)
            except exception.VolumeTypeNotFound:
                msg = _("Cannot find requested '%s' "
                        "volume type") % req_volume_type
                raise exception.InvalidVolumeType(reason=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'] = utils.get_bool_param('bootable', volume)

        utils.check_metadata_properties(kwargs['metadata'])

        try:
            new_volume = self.volume_api.manage_existing(
                context, host, cluster_name, volume['ref'], **kwargs)
        except exception.ServiceNotFound:
            msg = _("%(name)s '%(value)s' not found") % {
                'name': 'Host' if host else 'Cluster',
                'value': host or cluster_name
            }
            raise exception.ServiceUnavailable(message=msg)

        utils.add_visible_admin_metadata(new_volume)

        return self._view_builder.detail(req, new_volume)
Example #9
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
            kwargs['volume_type'] = (volume_types.get_by_name_or_id(
                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
Example #10
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
            kwargs['volume_type'] = (
                volume_types.get_by_name_or_id(context, req_volume_type))

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

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            if not uuidutils.is_uuid_like(snapshot_id):
                msg = _("Snapshot ID must be in UUID form.")
                raise exc.HTTPBadRequest(explanation=msg)
            # 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
Example #11
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_manage(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:
            # Not found exception will be handled at the wsgi level
            kwargs['volume_type'] = (
                volume_types.get_by_name_or_id(context, req_volume_type))
        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'] = utils.get_bool_param('bootable', volume)

        utils.check_metadata_properties(kwargs['metadata'])

        # Not found exception will be handled at wsgi level
        new_volume = self.volume_api.manage_existing(context,
                                                     volume['host'],
                                                     volume['ref'],
                                                     **kwargs)

        utils.add_visible_admin_metadata(new_volume)

        return self._view_builder.detail(req, new_volume)
Example #12
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
            kwargs['volume_type'] = (
                volume_types.get_by_name_or_id(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)
        kwargs['multiattach'] = utils.get_bool_param('multiattach', volume)

        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
Example #13
0
 def get_by_name_or_id(cls, context, identity):
     orm_obj = volume_types.get_by_name_or_id(context, identity)
     expected_attrs = cls._get_expected_attrs(context)
     return cls._from_db_object(context, cls(context),
                                orm_obj, expected_attrs=expected_attrs)
Example #14
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:
            # Not found exception will be handled at the wsgi level
            kwargs['volume_type'] = (volume_types.get_by_name_or_id(
                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

        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)
        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}
Example #15
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>",
             "cluster": "<Cinder cluster on which the 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']
        context.authorize(policy.MANAGE_POLICY)
        volume = body['volume']

        cluster_name, host = common.get_cluster_host(
            req, volume, mv.VOLUME_MIGRATE_CLUSTER)

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

        kwargs = {}
        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                kwargs['volume_type'] = volume_types.get_by_name_or_id(
                    context, req_volume_type)
            except exception.VolumeTypeNotFound:
                msg = _("Cannot find requested '%s' "
                        "volume type") % req_volume_type
                raise exception.InvalidVolumeType(reason=msg)
        else:
            kwargs['volume_type'] = {}

        if volume.get('name'):
            kwargs['name'] = volume.get('name').strip()
        if volume.get('description'):
            kwargs['description'] = volume.get('description').strip()

        kwargs['metadata'] = volume.get('metadata', None)
        kwargs['availability_zone'] = volume.get('availability_zone', None)
        bootable = volume.get('bootable', False)
        kwargs['bootable'] = strutils.bool_from_string(bootable, strict=True)

        try:
            new_volume = self.volume_api.manage_existing(context,
                                                         host,
                                                         cluster_name,
                                                         volume['ref'],
                                                         **kwargs)
        except exception.ServiceNotFound:
            msg = _("%(name)s '%(value)s' not found") % {
                'name': 'Host' if host else 'Cluster',
                'value': host or cluster_name}
            raise exception.ServiceUnavailable(message=msg)

        utils.add_visible_admin_metadata(new_volume)

        return self._view_builder.detail(req, new_volume)
Example #16
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_manage(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:
            # Not found exception will be handled at the wsgi level
            kwargs['volume_type'] = (volume_types.get_by_name_or_id(
                context, req_volume_type))
        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'] = utils.get_bool_param('bootable', volume)

        utils.check_metadata_properties(kwargs['metadata'])

        # Not found exception will be handled at wsgi level
        new_volume = self.volume_api.manage_existing(context, volume['host'],
                                                     volume['ref'], **kwargs)

        utils.add_visible_admin_metadata(new_volume)

        return self._view_builder.detail(req, new_volume)
Example #17
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
            kwargs['volume_type'] = (volume_types.get_by_name_or_id(
                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)
        kwargs['multiattach'] = utils.get_bool_param('multiattach', volume)

        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
Example #18
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:
            # Not found exception will be handled at the wsgi level
            kwargs['volume_type'] = (
                volume_types.get_by_name_or_id(context, req_volume_type))

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

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            if not uuidutils.is_uuid_like(snapshot_id):
                msg = _("Snapshot ID must be in UUID form.")
                raise exc.HTTPBadRequest(explanation=msg)
            # 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

        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)
        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}