Example #1
0
    def delete(self, _id):
        """Marks volume types as deleted.

        :param _id: id of volume type to be deleted
        """
        context = t_context.extract_context_from_environ()

        if not context.is_admin:
            return utils.format_cinder_error(
                403,
                _("Policy doesn't allow volume_extension:types_manage "
                  "to be performed."))

        session = core.get_session()
        with session.begin():
            try:
                db_api.volume_type_get(context, _id, session)
            except exceptions.VolumeTypeNotFound as e:
                return utils.format_cinder_error(404, e.message)
            try:
                db_api.volume_type_delete(context, _id, session)
            except Exception as e:
                LOG.exception(
                    _LE('Fail to update volume type: %(id)s,'
                        '%(exception)s'), {
                            'id': _id,
                            'exception': e
                        })
                return utils.format_cinder_error(
                    500, _('Fail to delete volume type.'))

        pecan.response.status = 202
        return pecan.response
Example #2
0
    def delete(self, _id):
        context = t_context.extract_context_from_environ()

        # TODO(joehuang): get the release of top and bottom
        t_release = cons.R_MITAKA
        b_release = cons.R_MITAKA

        s_ctx = hclient.get_res_routing_ref(context, _id, request.url,
                                            cons.ST_CINDER)
        if not s_ctx:
            return utils.format_cinder_error(
                404,
                _('Volume %s could not be found.') % _id)

        if s_ctx['b_url'] == '':
            return utils.format_cinder_error(
                404, _('Bottom Pod endpoint incorrect'))

        b_headers = hclient.convert_header(t_release, b_release,
                                           request.headers)

        resp = hclient.forward_req(context, 'DELETE', b_headers,
                                   s_ctx['b_url'], request.body)

        response.status = resp.status_code

        # don't remove the resource routing for delete is async. operation
        # remove the routing when query is executed but not find
        # No content in the resp actually
        return response
Example #3
0
    def get_one(self, _id):
        context = t_context.extract_context_from_environ()

        if _id == 'detail':
            return {'volumes': self._get_all(context)}

        # TODO(joehuang): get the release of top and bottom
        t_release = cons.R_MITAKA
        b_release = cons.R_MITAKA

        b_headers = hclient.convert_header(t_release, b_release,
                                           request.headers)

        s_ctx = hclient.get_res_routing_ref(context, _id, request.url,
                                            cons.ST_CINDER)
        if not s_ctx:
            return utils.format_cinder_error(
                404,
                _('Volume %s could not be found.') % _id)

        if s_ctx['b_url'] == '':
            return utils.format_cinder_error(
                404, _('Bottom Pod endpoint incorrect'))

        resp = hclient.forward_req(context, 'GET', b_headers, s_ctx['b_url'],
                                   request.body)

        b_ret_body = jsonutils.loads(resp.content)

        b_status = resp.status_code
        response.status = b_status
        if b_status == 200:
            if b_ret_body.get('volume') is not None:
                b_vol_ret = b_ret_body['volume']
                ret_vol = hclient.convert_object(b_release,
                                                 t_release,
                                                 b_vol_ret,
                                                 res_type=cons.RT_VOLUME)

                pod = utils.get_pod_by_top_id(context, _id)
                if pod:
                    ret_vol['availability_zone'] = pod['az_name']

                return {'volume': ret_vol}

        # resource not find but routing exist, remove the routing
        if b_status == 404:
            filters = [{
                'key': 'top_id',
                'comparator': 'eq',
                'value': _id
            }, {
                'key': 'resource_type',
                'comparator': 'eq',
                'value': cons.RT_VOLUME
            }]
            with context.session.begin():
                core.delete_resources(context, models.ResourceRouting, filters)
        return b_ret_body
Example #4
0
    def get_one(self):
        """Get all metadata associated with a volume."""
        context = t_context.extract_context_from_environ()

        t_release = cons.R_MITAKA
        b_release = cons.R_MITAKA

        b_headers = hclient.convert_header(t_release,
                                           b_release,
                                           request.headers)

        try:
            s_ctx = hclient.get_res_routing_ref(context, self.volume_id,
                                                request.url, cons.ST_CINDER)
            if not s_ctx:
                return utils.format_cinder_error(
                    500, _('Fail to find resource'))
        except Exception as e:
            LOG.exception(_LE('Fail to get metadata for a volume:'
                              '%(volume_id)s'
                              '%(exception)s'),
                          {'volume_id': self.volume_id,
                           'exception': e})
            return utils.format_cinder_error(500, _('Fail to get metadata'))

        if s_ctx['b_url'] == '':
            return utils.format_cinder_error(
                500, _('Bottom pod endpoint incorrect'))

        resp = hclient.forward_req(context, 'GET',
                                   b_headers,
                                   s_ctx['b_url'],
                                   request.body)

        b_body_ret = jsonutils.loads(resp.content)

        b_status = resp.status_code
        response.status = b_status
        if b_status == 200:
            if b_body_ret.get('metadata') is not None:
                b_metadata_ret = b_body_ret['metadata']
                vol_ret = hclient.convert_object(b_release, t_release,
                                                 b_metadata_ret,
                                                 res_type=cons.
                                                 RT_VOl_METADATA)
                return {'metadata': vol_ret}

        return b_body_ret
Example #5
0
    def _reset_status(self, context, pod_name, kw):
        """Update the provided volume with the provided state.

        :param pod_name: the bottom pod name.
        :param kw: request body.
        """
        try:
            status = None
            if 'status' in kw['os-reset_status']:
                status = kw['os-reset_status']['status']
            attach_status = None
            if 'attach_status' in kw['os-reset_status']:
                attach_status = kw['os-reset_status']['attach_status']
            migration_status = None
            if 'migration_status' in kw['os-reset_status']:
                migration_status = kw['os-reset_status']['migration_status']
        except (TypeError, KeyError, ValueError):
            msg = _('The server has either erred or is incapable of '
                    'performing the requested operation.')
            return utils.format_cinder_error(500, msg)

        body = {'status': status} if status else {}
        if attach_status:
            body.update({'attach_status': attach_status})
        if migration_status:
            body.update({'migration_status': migration_status})
        return self._action(context, pod_name, 'os-reset_status', body)
Example #6
0
    def _attach(self, context, pod_name, kw):
        """Add attachment metadata.

        :param pod_name: the bottom pod name.
        :param kw: request body.
        """
        try:
            mountpoint = None
            if 'mountpoint' in kw['os-attach']:
                mountpoint = kw['os-attach']['mountpoint']
            body = {'mountpoint': mountpoint}
            instance_uuid = None
            if 'instance_uuid' in kw['os-attach']:
                instance_uuid = kw['os-attach']['instance_uuid']
            host_name = None
            if 'host_name' in kw['os-attach']:
                host_name = kw['os-attach']['host_name']
        except (KeyError, ValueError, TypeError):
            msg = _('The server could not comply with the request since '
                    'it is either malformed or otherwise incorrect.')
            return utils.format_cinder_error(400, msg)

        if instance_uuid is not None:
            body.update({'instance_uuid': instance_uuid})
        if host_name is not None:
            body.update({'host_name': host_name})
        return self._action(context, pod_name, 'os-attach', body)
Example #7
0
    def delete(self, key):
        """Delete the given metadata item from a volume."""
        context = t_context.extract_context_from_environ()

        t_release = cons.R_MITAKA
        b_release = cons.R_MITAKA

        try:
            s_ctx = hclient.get_res_routing_ref(context, self.volume_id,
                                                request.url, cons.ST_CINDER)
            if not s_ctx:
                return utils.format_cinder_error(
                    404, _('Fail to find resource'))
        except Exception as e:
            LOG.exception(_LE('Fail to delete metadata from a volume: '
                              '%(volume_id)s'
                              '%(exception)s'),
                          {'volume_id': self.volume_id,
                           'exception': e})
            return utils.format_cinder_error(
                500, _('Fail to delete metadata'))

        if s_ctx['b_url'] == '':
            return utils.format_cinder_error(
                500, _('Bottom pod endpoint incorrect'))

        b_headers = hclient.convert_header(t_release,
                                           b_release,
                                           request.headers)

        resp = hclient.forward_req(context, 'DELETE',
                                   b_headers,
                                   s_ctx['b_url'],
                                   request.body)

        response.status = resp.status_code

        # don't remove the resource routing for delete is async. operation
        # remove the routing when query is executed but not found
        # No content in the resp actually
        return response
Example #8
0
    def _extend(self, context, pod_name, kw):
        """Extend the size of the specified volume.

        :param pod_name: the bottom pod name.
        :param kw: request body.
        """
        try:
            new_size = int(kw['os-extend']['new_size'])
        except (KeyError, ValueError, TypeError):
            msg = _("New volume size must be specified as an integer.")
            return utils.format_cinder_error(400, msg)
        return self._action(context, pod_name, 'os-extend',
                            {'new_size': new_size})
Example #9
0
    def _set_image_metadata(self, context, pod_name, kw):
        """Set a volume's image metadata.

        :param pod_name: the bottom pod name.
        :param kw: request body.
        """
        try:
            metadata = kw['os-set_image_metadata']['metadata']
        except (KeyError, TypeError):
            msg = _("Malformed request body.")
            return utils.format_cinder_error(400, msg)
        return self._action(context, pod_name, 'os-set_image_metadata',
                            {'metadata': metadata})
Example #10
0
    def _unset_image_metadata(self, context, pod_name, kw):
        """Unset specified keys from volume's image metadata.

        :param pod_name: the bottom pod name.
        :param kw: request body.
        """
        try:
            key = kw['os-unset_image_metadata']['key']
        except (KeyError, TypeError):
            msg = _("Malformed request body.")
            return utils.format_cinder_error(400, msg)
        return self._action(context, pod_name, 'os-unset_image_metadata',
                            {'key': key})
Example #11
0
    def get_one(self, _id):
        """Retrieves single volume type by id.

        :param _id: id of volume type to be retrieved
        :returns: retrieved volume type
        """
        context = t_context.extract_context_from_environ()
        try:
            result = db_api.volume_type_get(context, _id)
        except exceptions.VolumeTypeNotFound as e:
            return utils.format_cinder_error(404, e.message)
        except Exception as e:
            LOG.exception(
                _LE('Volume type not found: %(id)s,'
                    '%(exception)s'), {
                        'id': _id,
                        'exception': e
                    })
            return utils.format_cinder_error(
                404,
                _("Volume type %(id)s could not be found.") % {'id': _id})
        return {'volume_type': result}
Example #12
0
    def get_all(self):
        """Get all non-deleted volume_types."""
        filters = {}
        context = t_context.extract_context_from_environ()
        if not context.is_admin:
            # Only admin has query access to all volume types
            filters['is_public'] = True
        try:
            list_result = db_api.volume_type_get_all(context,
                                                     list_result=True,
                                                     filters=filters)
        except Exception as e:
            LOG.exception(_LE('Fail to retrieve volume types: %(exception)s'),
                          {'exception': e})
            return utils.format_cinder_error(500, e)

        return {'volume_types': list_result}
Example #13
0
    def post(self, **kw):
        context = t_context.extract_context_from_environ()

        if 'volume' not in kw:
            return utils.format_cinder_error(
                400, _("Missing required element 'volume' in request body."))

        az = kw['volume'].get('availability_zone', '')
        pod, pod_az = az_ag.get_pod_by_az_tenant(context,
                                                 az_name=az,
                                                 tenant_id=self.tenant_id)
        if not pod:
            LOG.error(_LE("Pod not configured or scheduling failure"))
            return utils.format_cinder_error(
                500, _('Pod not configured or scheduling failure'))

        t_pod = db_api.get_top_pod(context)
        if not t_pod:
            LOG.error(_LE("Top Pod not configured"))
            return utils.format_cinder_error(500, _('Top Pod not configured'))

        # TODO(joehuang): get release from pod configuration,
        # to convert the content
        # b_release = pod['release']
        # t_release = t_pod['release']
        t_release = cons.R_MITAKA
        b_release = cons.R_MITAKA

        s_ctx = hclient.get_pod_service_ctx(context,
                                            request.url,
                                            pod['pod_name'],
                                            s_type=cons.ST_CINDER)

        if s_ctx['b_url'] == '':
            LOG.error(
                _LE("Bottom Pod endpoint incorrect %s") % pod['pod_name'])
            return utils.format_cinder_error(
                500, _('Bottom Pod endpoint incorrect'))

        b_headers = hclient.convert_header(t_release, b_release,
                                           request.headers)

        t_vol = kw['volume']

        # add or remove key-value in the request for diff. version
        b_vol_req = hclient.convert_object(t_release,
                                           b_release,
                                           t_vol,
                                           res_type=cons.RT_VOLUME)

        # convert az to the configured one
        # remove the AZ parameter to bottom request for default one
        b_vol_req['availability_zone'] = pod['pod_az_name']
        if b_vol_req['availability_zone'] == '':
            b_vol_req.pop("availability_zone", None)

        b_body = jsonutils.dumps({'volume': b_vol_req})

        resp = hclient.forward_req(context, 'POST', b_headers, s_ctx['b_url'],
                                   b_body)
        b_status = resp.status_code
        b_ret_body = jsonutils.loads(resp.content)

        # build routing and convert response from the bottom pod
        # for different version.
        response.status = b_status
        if b_status == 202:
            if b_ret_body.get('volume') is not None:
                b_vol_ret = b_ret_body['volume']

                try:
                    with context.session.begin():
                        core.create_resource(
                            context, models.ResourceRouting, {
                                'top_id': b_vol_ret['id'],
                                'bottom_id': b_vol_ret['id'],
                                'pod_id': pod['pod_id'],
                                'project_id': self.tenant_id,
                                'resource_type': cons.RT_VOLUME
                            })
                except Exception as e:
                    LOG.exception(
                        _LE('Failed to create volume '
                            'resource routing'
                            'top_id: %(top_id)s ,'
                            'bottom_id: %(bottom_id)s ,'
                            'pod_id: %(pod_id)s ,'
                            '%(exception)s '), {
                                'top_id': b_vol_ret['id'],
                                'bottom_id': b_vol_ret['id'],
                                'pod_id': pod['pod_id'],
                                'exception': e
                            })
                    return utils.format_cinder_error(
                        500, _('Failed to create volume resource routing'))

                ret_vol = hclient.convert_object(b_release,
                                                 t_release,
                                                 b_vol_ret,
                                                 res_type=cons.RT_VOLUME)

                ret_vol['availability_zone'] = pod['az_name']

                return {'volume': ret_vol}

        return b_ret_body
Example #14
0
    def put(self, _id, **kw):
        context = t_context.extract_context_from_environ()

        # TODO(joehuang): Implement API multi-version compatibility
        # currently _convert_header and _convert_object are both dummy
        # functions and API versions are hard coded. After multi-version
        # compatibility is implemented, API versions will be retrieved from
        # top and bottom API server, also, _convert_header and _convert_object
        # will do the real job to convert the request header and body
        # according to the API versions.
        t_release = cons.R_MITAKA
        b_release = cons.R_MITAKA

        s_ctx = hclient.get_res_routing_ref(context, _id, request.url,
                                            cons.ST_CINDER)
        if not s_ctx:
            return utils.format_cinder_error(
                404,
                _('Volume %s could not be found.') % _id)

        if s_ctx['b_url'] == '':
            return utils.format_cinder_error(
                404, _('Bottom Pod endpoint incorrect'))

        b_headers = hclient.convert_header(t_release, b_release,
                                           request.headers)

        t_vol = kw['volume']

        # add or remove key-value in the request for diff. version
        b_vol_req = hclient.convert_object(t_release,
                                           b_release,
                                           t_vol,
                                           res_type=cons.RT_VOLUME)

        b_body = jsonutils.dumps({'volume': b_vol_req})

        resp = hclient.forward_req(context, 'PUT', b_headers, s_ctx['b_url'],
                                   b_body)

        b_status = resp.status_code
        b_ret_body = jsonutils.loads(resp.content)
        response.status = b_status

        if b_status == 200:
            if b_ret_body.get('volume') is not None:
                b_vol_ret = b_ret_body['volume']
                ret_vol = hclient.convert_object(b_release,
                                                 t_release,
                                                 b_vol_ret,
                                                 res_type=cons.RT_VOLUME)

                pod = utils.get_pod_by_top_id(context, _id)
                if pod:
                    ret_vol['availability_zone'] = pod['az_name']

                return {'volume': ret_vol}

        # resource not found but routing exist, remove the routing
        if b_status == 404:
            filters = [{
                'key': 'top_id',
                'comparator': 'eq',
                'value': _id
            }, {
                'key': 'resource_type',
                'comparator': 'eq',
                'value': cons.RT_VOLUME
            }]
            with context.session.begin():
                core.delete_resources(context, models.ResourceRouting, filters)
        return b_ret_body
Example #15
0
    def post(self, **kw):
        """Create volume metadata associated with a volume.

        :param kw: dictionary of values to be created
        :returns: created volume metadata
        """
        context = t_context.extract_context_from_environ()

        if 'metadata' not in kw:
            return utils.format_cinder_error(
                400, _("Missing required element 'metadata' in "
                       "request body."))

        try:
            pod = utils.get_pod_by_top_id(context, self.volume_id)
            if pod is None:
                return utils.format_cinder_error(
                    404, _('Volume %(volume_id)s could not be found.') % {
                        'volume_id': self.volume_id
                    })

            t_pod = db_api.get_top_pod(context)
            if not t_pod:
                LOG.error(_LE("Top Pod not configured"))
                return utils.format_cinder_error(
                    500, _('Top Pod not configured'))
        except Exception as e:
            LOG.exception(_LE('Fail to create metadata for a volume:'
                              '%(volume_id)s'
                              '%(exception)s'),
                          {'volume_id': self.volume_id,
                           'exception': e})
            return utils.format_cinder_error(500, _('Fail to create metadata'))

        t_release = cons.R_MITAKA
        b_release = cons.R_MITAKA

        s_ctx = hclient.get_pod_service_ctx(
            context,
            request.url,
            pod['pod_name'],
            s_type=cons.ST_CINDER)

        if s_ctx['b_url'] == '':
            LOG.error(_LE("Bottom pod endpoint incorrect %s") %
                      pod['pod_name'])
            return utils.format_cinder_error(
                500, _('Bottom pod endpoint incorrect'))

        b_headers = hclient.convert_header(t_release, b_release,
                                           request.headers)

        t_metadata = kw['metadata']

        # add or remove key-value in the request for diff. version
        b_vol_req = hclient.convert_object(t_release, b_release, t_metadata,
                                           res_type=cons.RT_VOl_METADATA)

        b_body = jsonutils.dumps({'metadata': b_vol_req})

        resp = hclient.forward_req(
            context,
            'POST',
            b_headers,
            s_ctx['b_url'],
            b_body)
        b_status = resp.status_code
        b_body_ret = jsonutils.loads(resp.content)

        # convert response from the bottom pod
        # for different version.
        response.status = b_status
        if b_status == 200:
            if b_body_ret.get('metadata') is not None:
                b_metadata_ret = b_body_ret['metadata']

                vol_ret = hclient.convert_object(b_release, t_release,
                                                 b_metadata_ret,
                                                 res_type=cons.
                                                 RT_VOl_METADATA)

                return {'metadata': vol_ret}

        return b_body_ret
Example #16
0
    def post(self, **kw):
        context = t_context.extract_context_from_environ()

        action_handle = None
        action_type = None
        for _type in self.handle_map:
            if _type in kw:
                action_handle = self.handle_map[_type]
                action_type = _type
        if not action_handle:
            return utils.format_cinder_error(400,
                                             _('Volume action not supported'))

        volume_mappings = db_api.get_bottom_mappings_by_top_id(
            context, self.volume_id, constants.RT_VOLUME)
        if not volume_mappings:
            return utils.format_cinder_error(
                404,
                _('Volume %(volume_id)s could not be found.') %
                {'volume_id': self.volume_id})

        pod_name = volume_mappings[0][0]['pod_name']

        if action_type == 'os-attach':
            instance_uuid = kw['os-attach'].get('instance_uuid')
            if instance_uuid is not None:
                server_mappings = db_api.get_bottom_mappings_by_top_id(
                    context, instance_uuid, constants.RT_SERVER)
                if not server_mappings:
                    return utils.format_cinder_error(404,
                                                     _('Server not found'))
                server_pod_name = server_mappings[0][0]['pod_name']
                if server_pod_name != pod_name:
                    LOG.error(
                        _LE('Server %(server)s is in pod %(server_pod)s'
                            'and volume %(volume)s is in pod'
                            '%(volume_pod)s, which '
                            'are not the same.'), {
                                'server': instance_uuid,
                                'server_pod': server_pod_name,
                                'volume': self.volume_id,
                                'volume_pod': pod_name
                            })
                    return utils.format_cinder_error(
                        400, _('Server and volume not in the same pod'))

        try:
            resp, body = action_handle(context, pod_name, kw)
            pecan.response.status = resp.status_code
            if not body:
                return pecan.response
            else:
                return body
        except Exception as e:
            code = 500
            message = _('Action %(action)s on volume %(volume_id)s fails') % {
                'action': action_type,
                'volume_id': self.volume_id
            }
            if hasattr(e, 'code'):
                code = e.code
            ex_message = str(e)
            if ex_message:
                message = ex_message
            LOG.error(message)
            return utils.format_cinder_error(code, message)
Example #17
0
    def put(self, **kw):
        """Update volume metadata.

        :param kw: dictionary of values to be updated
        :returns: updated volume type
        """
        context = t_context.extract_context_from_environ()

        if 'metadata' not in kw:
            return utils.format_cinder_error(
                400, _("Missing required element 'metadata' in "
                       "request body."))

        t_release = cons.R_MITAKA
        b_release = cons.R_MITAKA

        try:
            s_ctx = hclient.get_res_routing_ref(context, self.volume_id,
                                                request.url, cons.ST_CINDER)
            if not s_ctx:
                return utils.format_cinder_error(
                    404, _('Resource not found'))
        except Exception as e:
            LOG.exception(_LE('Fail to update metadata for a volume: '
                              '%(volume_id)s'
                              '%(exception)s'),
                          {'volume_id': self.volume_id,
                           'exception': e})
            return utils.format_cinder_error(
                500, _('Fail to update metadata'))

        if s_ctx['b_url'] == '':
            return utils.format_cinder_error(
                500, _('Bottom pod endpoint incorrect'))

        b_headers = hclient.convert_header(t_release,
                                           b_release,
                                           request.headers)

        t_metadata = kw['metadata']

        # add or remove key/value in the request for diff. version
        b_vol_req = hclient.convert_object(t_release, b_release, t_metadata,
                                           res_type=cons.RT_VOl_METADATA)

        b_body = jsonutils.dumps({'metadata': b_vol_req})

        resp = hclient.forward_req(context, 'PUT',
                                   b_headers,
                                   s_ctx['b_url'],
                                   b_body)

        b_status = resp.status_code
        b_body_ret = jsonutils.loads(resp.content)
        response.status = b_status

        if b_status == 200:
            if b_body_ret.get('metadata') is not None:
                b_metadata_ret = b_body_ret['metadata']
                vol_ret = hclient.convert_object(b_release, t_release,
                                                 b_metadata_ret,
                                                 res_type=cons.
                                                 RT_VOl_METADATA)
                return {'metadata': vol_ret}

        return b_body_ret
Example #18
0
    def post(self, **kw):
        """Creates volume types."""
        context = t_context.extract_context_from_environ()

        if not context.is_admin:
            return utils.format_cinder_error(
                403,
                _("Policy doesn't allow volume_extension:types_manage "
                  "to be performed."))

        if 'volume_type' not in kw:
            return utils.format_cinder_error(
                400,
                _("Missing required element 'volume_type' in "
                  "request body."))

        projects = []

        if self.tenant_id is not None:
            projects = [self.tenant_id]

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

        if name is None or len(name.strip()) == 0:
            return utils.format_cinder_error(
                400, _("Volume type name can not be empty."))

        try:
            utils.check_string_length(name,
                                      'Type name',
                                      min_len=1,
                                      max_len=255)
        except exceptions.InvalidInput as e:
            return utils.format_cinder_error(400, e.message)

        if description is not None:
            try:
                utils.check_string_length(description,
                                          'Type description',
                                          min_len=0,
                                          max_len=255)
            except exceptions.InvalidInput as e:
                return utils.format_cinder_error(400, e.message)

        if not utils.is_valid_boolstr(is_public):
            msg = _("Invalid value '%(is_public)s' for is_public. "
                    "Accepted values: True or False.") % {
                        'is_public': is_public
                    }
            return utils.format_cinder_error(400, msg)

        vol_type['extra_specs'] = specs
        vol_type['is_public'] = is_public
        vol_type['id'] = uuidutils.generate_uuid()

        session = core.get_session()
        with session.begin():
            try:
                db_api.volume_type_get_by_name(context, vol_type['name'],
                                               session)
                return utils.format_cinder_error(
                    409,
                    _("Volume Type %(id)s already exists.") %
                    {'id': vol_type['id']})
            except exceptions.VolumeTypeNotFoundByName:
                pass
            try:
                extra_specs = vol_type['extra_specs']
                vol_type['extra_specs'] = \
                    self._metadata_refs(vol_type.get('extra_specs'),
                                        models.VolumeTypeExtraSpecs)
                volume_type_ref = models.VolumeTypes()
                volume_type_ref.update(vol_type)
                session.add(volume_type_ref)
                for project in set(projects):
                    access_ref = models.VolumeTypeProjects()
                    access_ref.update({
                        "volume_type_id": volume_type_ref.id,
                        "project_id": project
                    })
                    access_ref.save(session=session)
            except Exception as e:
                LOG.exception(
                    _LE('Fail to create volume type: %(name)s,'
                        '%(exception)s'), {
                            'name': vol_type['name'],
                            'exception': e
                        })
                return utils.format_cinder_error(
                    500, _('Fail to create volume type'))

            vol_type['extra_specs'] = extra_specs
            return {'volume_type': vol_type}
Example #19
0
    def put(self, _id, **kw):
        """Update volume type by id.

        :param _id: id of volume type to be updated
        :param kw: dictionary of values to be updated
        :returns: updated volume type
        """
        context = t_context.extract_context_from_environ()

        if not context.is_admin:
            return utils.format_cinder_error(
                403,
                _("Policy doesn't allow volume_extension:types_manage "
                  "to be performed."))

        if 'volume_type' not in kw:
            return utils.format_cinder_error(
                400,
                _("Missing required element 'volume_type' in "
                  "request body."))

        values = kw['volume_type']
        name = values.get('name')
        description = values.get('description')
        is_public = values.get('os-volume-type-access:is_public')

        # Name and description can not be both None.
        # If name specified, name can not be empty.
        if name and len(name.strip()) == 0:
            return utils.format_cinder_error(
                400, _("Volume type name can not be empty."))

        if name is None and description is None and is_public is None:
            msg = _("Specify volume type name, description, is_public or "
                    "a combination thereof.")
            return utils.format_cinder_error(400, msg)

        if is_public is not None and not utils.is_valid_boolstr(is_public):
            msg = _("Invalid value '%(is_public)s' for is_public. Accepted "
                    "values: True or False.") % {
                        'is_public': is_public
                    }
            return utils.format_cinder_error(400, msg)

        if name:
            try:
                utils.check_string_length(name,
                                          'Type name',
                                          min_len=1,
                                          max_len=255)
            except exceptions.InvalidInput as e:
                return utils.format_cinder_error(400, e.message)

        if description is not None:
            try:
                utils.check_string_length(description,
                                          'Type description',
                                          min_len=0,
                                          max_len=255)
            except exceptions.InvalidInput as e:
                return utils.format_cinder_error(400, e.message)

        try:
            type_updated = \
                db_api.volume_type_update(context, _id,
                                          dict(name=name,
                                               description=description,
                                               is_public=is_public))
        except exceptions.VolumeTypeNotFound as e:
            return utils.format_cinder_error(404, e.message)
        except exceptions.VolumeTypeExists as e:
            return utils.format_cinder_error(409, e.message)
        except exceptions.VolumeTypeUpdateFailed as e:
            return utils.format_cinder_error(500, e.message)
        except Exception as e:
            LOG.exception(
                _LE('Fail to update volume type: %(name)s,'
                    '%(exception)s'), {
                        'name': values['name'],
                        'exception': e
                    })
            return utils.format_cinder_error(500,
                                             _("Fail to update volume type."))
        return {'volume_type': type_updated}