Example #1
0
    def handle(self, request, response):
        xml_deserializer = wsgi.XMLDeserializer(attributes.get_attr_metadata())
        deserializers = {
            'application/xml': xml_deserializer,
            'application/json': wsgi.JSONDeserializer()
        }
        xml_serializer = wsgi.XMLDictSerializer(attributes.get_attr_metadata())
        serializers = {
            'application/xml': xml_serializer,
            'application/json': wsgi.JSONDictSerializer()
        }
        format_types = {'xml': 'application/xml', 'json': 'application/json'}

        path = [part for part in request.path_url.split("/") if part]
        id = path[-1].split('.')[0]

        content_type = format_types.get(None,
                                        request.best_match_content_type())
        deserializer = deserializers.get(content_type)
        serializer = serializers.get(content_type)

        body = None
        if request.body:
            body = deserializer.deserialize(request.body)['body']

        api_response = self._plugin.post_update_port(request.context, id, body)
        return serializer.serialize({"port": api_response})
Example #2
0
    def test_json_with_unicode(self):
        input_dict = dict(servers=dict(a=(2, u'\u7f51\u7edc')))
        expected_json = b'{"servers":{"a":[2,"\\u7f51\\u7edc"]}}'
        serializer = wsgi.JSONDictSerializer()
        result = serializer.serialize(input_dict)
        result = result.replace(b'\n', b'').replace(b' ', b'')

        self.assertEqual(expected_json, result)
Example #3
0
    def test_json_with_utf8(self):
        input_dict = dict(servers=dict(a=(2, '\xe7\xbd\x91\xe7\xbb\x9c')))
        expected_json = '{"servers":{"a":[2,"\\u7f51\\u7edc"]}}'
        serializer = wsgi.JSONDictSerializer()
        result = serializer.serialize(input_dict)
        result = result.replace('\n', '').replace(' ', '')

        self.assertEqual(expected_json, result)
Example #4
0
    def test_json(self):
        input_dict = dict(servers=dict(a=(2, 3)))
        expected_json = b'{"servers":{"a":[2,3]}}'
        serializer = wsgi.JSONDictSerializer()
        result = serializer.serialize(input_dict)
        result = result.replace(b'\n', b'').replace(b' ', b'')

        self.assertEqual(expected_json, result)
Example #5
0
def convert_exception_to_http_exc(e, faults, language):
    serializer = wsgi.JSONDictSerializer()
    e = translate(e, language)
    body = serializer.serialize(
        {'NeutronError': get_exception_data(e)})
    kwargs = {'body': body, 'content_type': 'application/json'}
    if isinstance(e, exc.HTTPException):
        # already an HTTP error, just update with content type and body
        e.body = body
        e.content_type = kwargs['content_type']
        return e
    if isinstance(e, (exceptions.NeutronException, netaddr.AddrFormatError,
                      oslo_policy.PolicyNotAuthorized)):
        for fault in faults:
            if isinstance(e, fault):
                mapped_exc = faults[fault]
                break
        else:
            mapped_exc = exc.HTTPInternalServerError
        return mapped_exc(**kwargs)
    if isinstance(e, NotImplementedError):
        # NOTE(armando-migliaccio): from a client standpoint
        # it makes sense to receive these errors, because
        # extensions may or may not be implemented by
        # the underlying plugin. So if something goes south,
        # because a plugin does not implement a feature,
        # returning 500 is definitely confusing.
        kwargs['body'] = serializer.serialize(
            {'NotImplementedError': get_exception_data(e)})
        return exc.HTTPNotImplemented(**kwargs)
    # NOTE(jkoelker) Everything else is 500
    # Do not expose details of 500 error to clients.
    msg = _('Request Failed: internal server error while '
            'processing your request.')
    msg = translate(msg, language)
    kwargs['body'] = serializer.serialize(
        {'NeutronError': get_exception_data(exc.HTTPInternalServerError(msg))})
    return exc.HTTPInternalServerError(**kwargs)
Example #6
0
def convert_exception_to_http_exc(e, faults, language):
    serializer = wsgi.JSONDictSerializer()
    if isinstance(e, exceptions.MultipleExceptions):
        converted_exceptions = [
            convert_exception_to_http_exc(inner, faults, language)
            for inner in e.inner_exceptions
        ]
        # if no internal exceptions, will be handled as single exception
        if converted_exceptions:
            codes = {c.code for c in converted_exceptions}
            if len(codes) == 1:
                # all error codes are the same so we can maintain the code
                # and just concatenate the bodies
                joined_msg = "\n".join(
                    (jsonutils.loads(c.body)['NeutronError']['message']
                     for c in converted_exceptions))
                new_body = jsonutils.loads(converted_exceptions[0].body)
                new_body['NeutronError']['message'] = joined_msg
                converted_exceptions[0].body = serializer.serialize(new_body)
                return converted_exceptions[0]
            else:
                # multiple error types so we turn it into a Conflict with the
                # inner codes and bodies packed in
                new_exception = exceptions.Conflict()
                inner_error_strings = []
                for c in converted_exceptions:
                    c_body = jsonutils.loads(c.body)
                    err = ('HTTP %s %s: %s' %
                           (c.code, c_body['NeutronError']['type'],
                            c_body['NeutronError']['message']))
                    inner_error_strings.append(err)
                new_exception.msg = "\n".join(inner_error_strings)
                return convert_exception_to_http_exc(new_exception, faults,
                                                     language)

    e = translate(e, language)
    body = serializer.serialize({'NeutronError': get_exception_data(e)})
    kwargs = {'body': body, 'content_type': 'application/json'}
    if isinstance(e, exc.HTTPException):
        # already an HTTP error, just update with content type and body
        e.body = body
        e.content_type = kwargs['content_type']
        return e
    faults_tuple = tuple(faults.keys()) + (exceptions.NeutronException, )
    if isinstance(e, faults_tuple):
        for fault in faults:
            if isinstance(e, fault):
                mapped_exc = faults[fault]
                break
        else:
            mapped_exc = exc.HTTPInternalServerError
        return mapped_exc(**kwargs)
    if isinstance(e, NotImplementedError):
        # NOTE(armando-migliaccio): from a client standpoint
        # it makes sense to receive these errors, because
        # extensions may or may not be implemented by
        # the underlying plugin. So if something goes south,
        # because a plugin does not implement a feature,
        # returning 500 is definitely confusing.
        kwargs['body'] = serializer.serialize(
            {'NotImplementedError': get_exception_data(e)})
        return exc.HTTPNotImplemented(**kwargs)
    # NOTE(jkoelker) Everything else is 500
    # Do not expose details of 500 error to clients.
    msg = _('Request Failed: internal server error while '
            'processing your request.')
    msg = translate(msg, language)
    kwargs['body'] = serializer.serialize(
        {'NeutronError': get_exception_data(exc.HTTPInternalServerError(msg))})
    return exc.HTTPInternalServerError(**kwargs)
Example #7
0
def Resource(controller,
             faults=None,
             deserializers=None,
             serializers=None,
             action_status=None):
    """Represents an API entity resource and the associated serialization and
    deserialization logic
    """
    default_deserializers = {'application/json': wsgi.JSONDeserializer()}
    default_serializers = {'application/json': wsgi.JSONDictSerializer()}
    format_types = {'json': 'application/json'}
    action_status = action_status or dict(create=201, delete=204)

    default_deserializers.update(deserializers or {})
    default_serializers.update(serializers or {})

    deserializers = default_deserializers
    serializers = default_serializers
    faults = faults or {}

    @webob.dec.wsgify(RequestClass=Request)
    def resource(request):
        route_args = request.environ.get('wsgiorg.routing_args')
        if route_args:
            args = route_args[1].copy()
        else:
            args = {}

        # NOTE(jkoelker) by now the controller is already found, remove
        #                it from the args if it is in the matchdict
        args.pop('controller', None)
        fmt = args.pop('format', None)
        action = args.pop('action', None)
        content_type = format_types.get(fmt, request.best_match_content_type())
        language = request.best_match_language()
        deserializer = deserializers.get(content_type)
        serializer = serializers.get(content_type)

        try:
            if request.body:
                args['body'] = deserializer.deserialize(request.body)['body']

            # Routes library is dumb and cuts off everything after last dot (.)
            # as format. At the same time, it doesn't enforce format suffix,
            # which combined makes it impossible to pass a 'id' with dots
            # included (the last section after the last dot is lost). This is
            # important for some API extensions like tags where the id is
            # really a tag name that can contain special characters.
            #
            # To work around the Routes behaviour, we will attach the suffix
            # back to id if it's not one of supported formats (atm json only).
            # This of course won't work for the corner case of a tag name that
            # actually ends with '.json', but there seems to be no better way
            # to tackle it without breaking API backwards compatibility.
            if fmt is not None and fmt not in format_types:
                args['id'] = '.'.join([args['id'], fmt])

            revision_number = api_common.check_request_for_revision_constraint(
                request)
            if revision_number is not None:
                request.context.set_transaction_constraint(
                    controller._collection, args['id'], revision_number)

            method = getattr(controller, action)
            result = method(request=request, **args)
        except Exception as e:
            mapped_exc = api_common.convert_exception_to_http_exc(
                e, faults, language)
            if hasattr(mapped_exc, 'code') and 400 <= mapped_exc.code < 500:
                LOG.info('%(action)s failed (client error): %(exc)s', {
                    'action': action,
                    'exc': mapped_exc
                })
            else:
                LOG.exception('%(action)s failed: %(details)s', {
                    'action': action,
                    'details': utils.extract_exc_details(e),
                })
            raise mapped_exc

        status = action_status.get(action, 200)
        body = serializer.serialize(result)
        # NOTE(jkoelker) Comply with RFC2616 section 9.7
        if status == 204:
            content_type = ''
            body = None

        return webob.Response(request=request,
                              status=status,
                              content_type=content_type,
                              body=body)

    # NOTE(blogan): this is something that is needed for the transition to
    # pecan.  This will allow the pecan code to have a handle on the controller
    # for an extension so it can reuse the code instead of forcing every
    # extension to rewrite the code for use with pecan.
    setattr(resource, 'controller', controller)
    setattr(resource, 'action_status', action_status)
    return resource
Example #8
0
def Resource(controller, faults=None, deserializers=None, serializers=None):
    """Represents an API entity resource and the associated serialization and
    deserialization logic
    """
    xml_deserializer = wsgi.XMLDeserializer(attributes.get_attr_metadata())
    default_deserializers = {
        'application/xml': xml_deserializer,
        'application/json': wsgi.JSONDeserializer()
    }
    xml_serializer = wsgi.XMLDictSerializer(attributes.get_attr_metadata())
    default_serializers = {
        'application/xml': xml_serializer,
        'application/json': wsgi.JSONDictSerializer()
    }
    format_types = {'xml': 'application/xml', 'json': 'application/json'}
    action_status = dict(create=201, delete=204)

    default_deserializers.update(deserializers or {})
    default_serializers.update(serializers or {})

    deserializers = default_deserializers
    serializers = default_serializers
    faults = faults or {}
    #neutron/api/v2/base.py 789 wsgi_resource.Resource(controller, FAULT_MAP)
    #FAULT_MAP :neutron/api/v2/base.py 38

    @webob.dec.wsgify(RequestClass=Request)
    def resource(request):
        # #brk(host="10.10.12.21", port=49175)
        # #add by xm-2015.7.8:G-cloud7.0区域权限控制,
        # #根据api请求中是否附件resource_type及是否resource_type=0/1来区分用户角色
        # #resource_type = request.params.get('resource_type', None)
        # resource_type = request.environ.get('HTTP_G_AUTH_RESOURCETYPE', None)
        # #resource_type = request.headers.environ.get('HTTP_G_AUTH_RESOURCETYPE', None)
        # LOG.debug(_('resource_type_xm: %(resource_type)s'), {'resource_type': resource_type})
        # if resource_type == '0':
        #     request.context.roles = list(set(request.context.roles) - set(['admin']))
        #     request.context.is_admin = False
        # elif resource_type == '1':
        #     request.context.roles = list(set(request.context.roles) | set(['admin']))
        #     request.context.is_admin = True
        # #end-2015.7.8

        route_args = request.environ.get('wsgiorg.routing_args')
        if route_args:
            args = route_args[1].copy()
        else:
            args = {}

        # NOTE(jkoelker) by now the controller is already found, remove
        #                it from the args if it is in the matchdict
        args.pop('controller', None)
        fmt = args.pop('format', None)
        action = args.pop('action', None)
        content_type = format_types.get(fmt, request.best_match_content_type())
        language = request.best_match_language()
        deserializer = deserializers.get(content_type)
        serializer = serializers.get(content_type)

        try:
            if request.body:
                args['body'] = deserializer.deserialize(request.body)['body']
                #首先进入/usr/lib/python2.7/site-packages/webob/request.py(671)_body__get() 然后return 到/usr/lib/python2.7/site-packages/neutron/wsgi.py(599)deserialize()

            method = getattr(controller, action)
            #pdb.set_trace()
            result = method(request=request, **args)
        except (exceptions.NeutronException, netaddr.AddrFormatError) as e:
            #faults = {<class 'neutron.common.exceptions.NotAuthorized'>: <class 'webob.exc.HTTPForbidden'>,
            # <class 'neutron.common.exceptions.Conflict'>: <class 'webob.exc.HTTPConflict'>,
            # <class 'neutron.common.exceptions.NotFound'>: <class 'webob.exc.HTTPNotFound'>,
            # <class 'neutron.common.exceptions.ServiceUnavailable'>: <class 'webob.exc.HTTPServiceUnavailable'>,
            # <class 'netaddr.core.AddrFormatError'>: <class 'webob.exc.HTTPBadRequest'>,
            # <class 'neutron.common.exceptions.BadRequest'>: <class 'webob.exc.HTTPBadRequest'>,
            # <class 'neutron.common.exceptions.InUse'>: <class 'webob.exc.HTTPConflict'>}
            for fault in faults:
                if isinstance(e, fault):
                    mapped_exc = faults[fault]
                    break
            else:
                if e.code and e.code != 500:
                    mapped_exc = webob.exc.HTTPClientError
                else:
                    mapped_exc = webob.exc.HTTPInternalServerError
            if 400 <= mapped_exc.code < 500:
                LOG.info(_('%(action)s failed (client error): %(exc)s'), {
                    'action': action,
                    'exc': e
                })
            else:
                LOG.exception(_('%s failed'), action)
            e = translate(e, language)
            body = serializer.serialize(
                {'NeutronError': get_exception_data(e)})
            kwargs = {'body': body, 'content_type': content_type}
            raise mapped_exc(**kwargs)
        except webob.exc.HTTPException as e:
            type_, value, tb = sys.exc_info()
            LOG.exception(_('%s failed'), action)
            translate(e, language)
            value.body = serializer.serialize(
                {'NeutronError': get_exception_data(e)})
            value.content_type = content_type
            six.reraise(type_, value, tb)
        except NotImplementedError as e:
            e = translate(e, language)
            # NOTE(armando-migliaccio): from a client standpoint
            # it makes sense to receive these errors, because
            # extensions may or may not be implemented by
            # the underlying plugin. So if something goes south,
            # because a plugin does not implement a feature,
            # returning 500 is definitely confusing.
            body = serializer.serialize(
                {'NotImplementedError': get_exception_data(e)})
            kwargs = {'body': body, 'content_type': content_type}
            raise webob.exc.HTTPNotImplemented(**kwargs)
        except Exception:
            # NOTE(jkoelker) Everything else is 500
            LOG.exception(_('%s failed'), action)
            # Do not expose details of 500 error to clients.
            msg = _('Request Failed: internal server error while '
                    'processing your request.')
            msg = translate(msg, language)
            body = serializer.serialize({
                'NeutronError':
                get_exception_data(webob.exc.HTTPInternalServerError(msg))
            })
            kwargs = {'body': body, 'content_type': content_type}
            raise webob.exc.HTTPInternalServerError(**kwargs)

        status = action_status.get(action, 200)
        body = serializer.serialize(result)
        # NOTE(jkoelker) Comply with RFC2616 section 9.7
        if status == 204:
            content_type = ''
            body = None

        return webob.Response(request=request,
                              status=status,
                              content_type=content_type,
                              body=body)

    return resource
Example #9
0
def Resource(controller, faults=None, deserializers=None, serializers=None):
    """Represents an API entity resource and the associated serialization and
    deserialization logic
    """
    default_deserializers = {'application/json': wsgi.JSONDeserializer()}
    default_serializers = {'application/json': wsgi.JSONDictSerializer()}
    format_types = {'json': 'application/json'}
    action_status = dict(create=201, delete=204)

    default_deserializers.update(deserializers or {})
    default_serializers.update(serializers or {})

    deserializers = default_deserializers
    serializers = default_serializers
    faults = faults or {}

    @webob.dec.wsgify(RequestClass=Request)
    def resource(request):
        route_args = request.environ.get('wsgiorg.routing_args')
        if route_args:
            args = route_args[1].copy()
        else:
            args = {}

        # NOTE(jkoelker) by now the controller is already found, remove
        #                it from the args if it is in the matchdict
        args.pop('controller', None)
        fmt = args.pop('format', None)
        action = args.pop('action', None)
        content_type = format_types.get(fmt, request.best_match_content_type())
        language = request.best_match_language()
        deserializer = deserializers.get(content_type)
        serializer = serializers.get(content_type)

        try:
            if request.body:
                args['body'] = deserializer.deserialize(request.body)['body']

            method = getattr(controller, action)

            result = method(request=request, **args)
        except (exceptions.NeutronException, netaddr.AddrFormatError,
                oslo_policy.PolicyNotAuthorized) as e:
            for fault in faults:
                if isinstance(e, fault):
                    mapped_exc = faults[fault]
                    break
            else:
                mapped_exc = webob.exc.HTTPInternalServerError
            if 400 <= mapped_exc.code < 500:
                LOG.info(_LI('%(action)s failed (client error): %(exc)s'), {
                    'action': action,
                    'exc': e
                })
            else:
                LOG.exception(_LE('%s failed'), action)
            e = translate(e, language)
            body = serializer.serialize(
                {'NeutronError': get_exception_data(e)})
            kwargs = {'body': body, 'content_type': content_type}
            raise mapped_exc(**kwargs)
        except webob.exc.HTTPException as e:
            type_, value, tb = sys.exc_info()
            LOG.exception(_LE('%s failed'), action)
            translate(e, language)
            value.body = serializer.serialize(
                {'NeutronError': get_exception_data(e)})
            value.content_type = content_type
            six.reraise(type_, value, tb)
        except NotImplementedError as e:
            e = translate(e, language)
            # NOTE(armando-migliaccio): from a client standpoint
            # it makes sense to receive these errors, because
            # extensions may or may not be implemented by
            # the underlying plugin. So if something goes south,
            # because a plugin does not implement a feature,
            # returning 500 is definitely confusing.
            body = serializer.serialize(
                {'NotImplementedError': get_exception_data(e)})
            kwargs = {'body': body, 'content_type': content_type}
            raise webob.exc.HTTPNotImplemented(**kwargs)
        except Exception:
            # NOTE(jkoelker) Everything else is 500
            LOG.exception(_LE('%s failed'), action)
            # Do not expose details of 500 error to clients.
            msg = _('Request Failed: internal server error while '
                    'processing your request.')
            msg = translate(msg, language)
            body = serializer.serialize({
                'NeutronError':
                get_exception_data(webob.exc.HTTPInternalServerError(msg))
            })
            kwargs = {'body': body, 'content_type': content_type}
            raise webob.exc.HTTPInternalServerError(**kwargs)

        status = action_status.get(action, 200)
        body = serializer.serialize(result)
        # NOTE(jkoelker) Comply with RFC2616 section 9.7
        if status == 204:
            content_type = ''
            body = None

        return webob.Response(request=request,
                              status=status,
                              content_type=content_type,
                              body=body)

    return resource
Example #10
0
def Resource(controller,
             faults=None,
             deserializers=None,
             serializers=None,
             action_status=None):
    """Represents an API entity resource and the associated serialization and
    deserialization logic
    """
    default_deserializers = {'application/json': wsgi.JSONDeserializer()}
    default_serializers = {'application/json': wsgi.JSONDictSerializer()}
    format_types = {'json': 'application/json'}
    action_status = action_status or dict(create=201, delete=204)

    default_deserializers.update(deserializers or {})
    default_serializers.update(serializers or {})

    deserializers = default_deserializers
    serializers = default_serializers
    faults = faults or {}

    @webob.dec.wsgify(RequestClass=Request)
    def resource(request):
        route_args = request.environ.get('wsgiorg.routing_args')
        if route_args:
            args = route_args[1].copy()
        else:
            args = {}

        # NOTE(jkoelker) by now the controller is already found, remove
        #                it from the args if it is in the matchdict
        args.pop('controller', None)
        fmt = args.pop('format', None)
        action = args.pop('action', None)
        content_type = format_types.get(fmt, request.best_match_content_type())
        language = request.best_match_language()
        deserializer = deserializers.get(content_type)
        serializer = serializers.get(content_type)

        try:
            if request.body:
                args['body'] = deserializer.deserialize(request.body)['body']

            method = getattr(controller, action)

            result = method(request=request, **args)
        except Exception as e:
            mapped_exc = api_common.convert_exception_to_http_exc(
                e, faults, language)
            if hasattr(mapped_exc, 'code') and 400 <= mapped_exc.code < 500:
                LOG.info(_LI('%(action)s failed (client error): %(exc)s'), {
                    'action': action,
                    'exc': mapped_exc
                })
            else:
                LOG.exception(_LE('%(action)s failed: %(details)s'), {
                    'action': action,
                    'details': utils.extract_exc_details(e),
                })
            raise mapped_exc

        status = action_status.get(action, 200)
        body = serializer.serialize(result)
        # NOTE(jkoelker) Comply with RFC2616 section 9.7
        if status == 204:
            content_type = ''
            body = None

        return webob.Response(request=request,
                              status=status,
                              content_type=content_type,
                              body=body)

    # NOTE(blogan): this is something that is needed for the transition to
    # pecan.  This will allow the pecan code to have a handle on the controller
    # for an extension so it can reuse the code instead of forcing every
    # extension to rewrite the code for use with pecan.
    setattr(resource, 'controller', controller)
    return resource
Example #11
0
def Resource(controller, faults=None, deserializers=None, serializers=None):
    """Represents an API entity resource and the associated serialization and
    deserialization logic
    """
    xml_deserializer = wsgi.XMLDeserializer(attributes.get_attr_metadata())
    default_deserializers = {
        'application/xml': xml_deserializer,
        'application/json': wsgi.JSONDeserializer()
    }
    xml_serializer = wsgi.XMLDictSerializer(attributes.get_attr_metadata())
    default_serializers = {
        'application/xml': xml_serializer,
        'application/json': wsgi.JSONDictSerializer()
    }
    format_types = {'xml': 'application/xml', 'json': 'application/json'}
    action_status = dict(create=201, delete=204)

    default_deserializers.update(deserializers or {})
    default_serializers.update(serializers or {})

    deserializers = default_deserializers
    serializers = default_serializers
    faults = faults or {}

    @webob.dec.wsgify(RequestClass=Request)
    def resource(request):
        route_args = request.environ.get('wsgiorg.routing_args')
        if route_args:
            args = route_args[1].copy()
        else:
            args = {}

        # NOTE(jkoelker) by now the controller is already found, remove
        #                it from the args if it is in the matchdict
        args.pop('controller', None)
        fmt = args.pop('format', None)
        action = args.pop('action', None)
        content_type = format_types.get(fmt, request.best_match_content_type())
        language = request.best_match_language()
        deserializer = deserializers.get(content_type)
        serializer = serializers.get(content_type)

        try:
            if request.body:
                args['body'] = deserializer.deserialize(request.body)['body']

            method = getattr(controller, action)

            result = method(request=request, **args)
        except (exceptions.NeutronException, netaddr.AddrFormatError) as e:
            LOG.exception(_('%s failed'), action)
            e = translate(e, language)
            # following structure is expected by python-neutronclient
            err_data = {
                'type': e.__class__.__name__,
                'message': e,
                'detail': ''
            }
            body = serializer.serialize({'NeutronError': err_data})
            kwargs = {'body': body, 'content_type': content_type}
            for fault in faults:
                if isinstance(e, fault):
                    raise faults[fault](**kwargs)
            raise webob.exc.HTTPInternalServerError(**kwargs)
        except webob.exc.HTTPException as e:
            LOG.exception(_('%s failed'), action)
            translate(e, language)
            e.body = serializer.serialize({'NeutronError': e})
            e.content_type = content_type
            raise
        except NotImplementedError as e:
            e = translate(e, language)
            # NOTE(armando-migliaccio): from a client standpoint
            # it makes sense to receive these errors, because
            # extensions may or may not be implemented by
            # the underlying plugin. So if something goes south,
            # because a plugin does not implement a feature,
            # returning 500 is definitely confusing.
            body = serializer.serialize({'NotImplementedError': e.message})
            kwargs = {'body': body, 'content_type': content_type}
            raise webob.exc.HTTPNotImplemented(**kwargs)
        except Exception as e:
            # NOTE(jkoelker) Everything else is 500
            LOG.exception(_('%s failed'), action)
            # Do not expose details of 500 error to clients.
            msg = _('Request Failed: internal server error while '
                    'processing your request.')
            msg = translate(msg, language)
            body = serializer.serialize({'NeutronError': msg})
            kwargs = {'body': body, 'content_type': content_type}
            raise webob.exc.HTTPInternalServerError(**kwargs)

        status = action_status.get(action, 200)
        body = serializer.serialize(result)
        # NOTE(jkoelker) Comply with RFC2616 section 9.7
        if status == 204:
            content_type = ''
            body = None

        return webob.Response(request=request,
                              status=status,
                              content_type=content_type,
                              body=body)

    return resource