Exemplo n.º 1
0
    def prepare_request_body(context,
                             body,
                             is_create,
                             resource,
                             attr_info,
                             allow_bulk=False):
        """Verifies required attributes are in request body.

        Also checking that an attribute is only specified if it is allowed
        for the given operation (create/update).

        Attribute with default values are considered to be optional.

        body argument must be the deserialized body.
        """
        collection = resource + "s"
        if not body:
            raise webob.exc.HTTPBadRequest(_("Resource body required"))

        LOG.debug("Request body: %(body)s", {'body': body})
        try:
            if collection in body:
                if not allow_bulk:
                    raise webob.exc.HTTPBadRequest(
                        _("Bulk operation "
                          "not supported"))
                if not body[collection]:
                    raise webob.exc.HTTPBadRequest(_("Resources required"))
                bulk_body = [
                    Controller.prepare_request_body(
                        context,
                        item if resource in item else {resource: item},
                        is_create, resource, attr_info, allow_bulk)
                    for item in body[collection]
                ]
                return {collection: bulk_body}
            res_dict = body.get(resource)
        except (AttributeError, TypeError):
            msg = _("Body contains invalid data")
            raise webob.exc.HTTPBadRequest(msg)
        if res_dict is None:
            msg = _("Unable to find '%s' in request body") % resource
            raise webob.exc.HTTPBadRequest(msg)

        attr_ops = attributes.AttributeInfo(attr_info)
        attr_ops.populate_project_id(context, res_dict, is_create)
        attributes.populate_project_info(attr_info)
        attr_ops.verify_attributes(res_dict)

        if is_create:  # POST
            attr_ops.fill_post_defaults(res_dict,
                                        exc_cls=webob.exc.HTTPBadRequest)
        else:  # PUT
            for attr, attr_vals in attr_info.items():
                if attr in res_dict and not attr_vals['allow_put']:
                    msg = _("Cannot update read-only attribute %s") % attr
                    raise webob.exc.HTTPBadRequest(msg)

        attr_ops.convert_values(res_dict, exc_cls=webob.exc.HTTPBadRequest)
        return body
Exemplo n.º 2
0
 def test_verify_attributes_unrecognized(self):
     with testtools.ExpectedException(exc.HTTPBadRequest) as bad_req:
         attributes.AttributeInfo(
             {'attr1': 'foo'}).verify_attributes(
             {'attr1': 'foo', 'attr2': 'bar'})
         self.assertEqual(bad_req.message,
                          "Unrecognized attribute(s) 'attr2'")
Exemplo n.º 3
0
 def test_populate_project_id_not_mandatory(self):
     ctx = context.Context(user_id=None)
     # if the tenant_id is not mandatory for the resource it should be
     # OK if it is not in the request.
     res_dict = {'name': 'test_port'}
     attr_inst = attributes.AttributeInfo({})
     ctx.tenant_id = None
     attr_inst.populate_project_id(ctx, res_dict, True)
Exemplo n.º 4
0
    def test_convert_value(self):
        attr_info = {
            'key': {},
        }
        attr_inst = attributes.AttributeInfo(attr_info)
        self._test_convert_value(attr_inst,
                                 {'key': constants.ATTR_NOT_SPECIFIED},
                                 {'key': constants.ATTR_NOT_SPECIFIED})
        self._test_convert_value(attr_inst, {'key': 'X'}, {'key': 'X'})
        self._test_convert_value(attr_inst, {'other_key': 'X'},
                                 {'other_key': 'X'})

        attr_info = {
            'key': {
                'convert_to': converters.convert_to_int,
            },
        }
        attr_inst = attributes.AttributeInfo(attr_info)
        self._test_convert_value(attr_inst,
                                 {'key': constants.ATTR_NOT_SPECIFIED},
                                 {'key': constants.ATTR_NOT_SPECIFIED})
        self._test_convert_value(attr_inst, {'key': 1}, {'key': '1'})
        self._test_convert_value(attr_inst, {'key': 1}, {'key': 1})
        self.assertRaises(exceptions.InvalidInput, self._test_convert_value,
                          attr_inst, {'key': 1}, {'key': 'a'})

        attr_info = {
            'key': {
                'validate': {
                    'type:uuid': None
                },
            },
        }
        attr_inst = attributes.AttributeInfo(attr_info)
        self._test_convert_value(attr_inst,
                                 {'key': constants.ATTR_NOT_SPECIFIED},
                                 {'key': constants.ATTR_NOT_SPECIFIED})
        uuid_str = '01234567-1234-1234-1234-1234567890ab'
        self._test_convert_value(attr_inst, {'key': uuid_str},
                                 {'key': uuid_str})
        self.assertRaises(exceptions.InvalidInput, self._test_convert_value,
                          attr_inst, {'key': 1}, {'key': 1})
        self.assertRaises(self._EXC_CLS, attr_inst.convert_values, {'key': 1},
                          self._EXC_CLS)
Exemplo n.º 5
0
 def test_fill_none_overridden_by_default(self):
     attr_info = {
         'key': {
             'allow_post': True,
             'default': 42,
             'default_overrides_none': True,
         },
     }
     attr_inst = attributes.AttributeInfo(attr_info)
     self._test_fill_default_value(attr_inst, {'key': 42}, {'key': None})
Exemplo n.º 6
0
 def test_override_no_allow_post(self):
     attr_info = {
         'key': {
             'allow_post': False,
             'default': constants.ATTR_NOT_SPECIFIED,
         },
     }
     attr_inst = attributes.AttributeInfo(attr_info)
     self._test_fill_default_value(attr_inst, {'key': 'X'}, {'key': 'X'},
                                   check_allow_post=False)
Exemplo n.º 7
0
 def test_fill_default_value_ok(self):
     attr_info = {
         'key': {
             'allow_post': True,
             'default': constants.ATTR_NOT_SPECIFIED,
         },
     }
     attr_inst = attributes.AttributeInfo(attr_info)
     self._test_fill_default_value(attr_inst, {'key': 'X'}, {'key': 'X'})
     self._test_fill_default_value(
         attr_inst, {'key': constants.ATTR_NOT_SPECIFIED}, {})
Exemplo n.º 8
0
 def test_populate_project_id_from_context(self):
     tenant_id = uuidutils.generate_uuid()
     ctx = context.Context(user_id=None, tenant_id=tenant_id)
     # for each create request, the tenant_id should be added to the
     # req body
     res_dict = {}
     attr_inst = attributes.AttributeInfo({})
     attr_inst.populate_project_id(ctx, res_dict, is_create=True)
     self.assertEqual(
         {'tenant_id': ctx.tenant_id, 'project_id': ctx.tenant_id},
         res_dict)
Exemplo n.º 9
0
 def test_populate_project_id_mandatory_not_specified(self):
     tenant_id = uuidutils.generate_uuid()
     ctx = context.Context(user_id=None, tenant_id=tenant_id)
     # if the tenant_id is mandatory for the resource and not specified
     # in the request nor in the context, an exception should be raised
     res_dict = {}
     attr_info = {'tenant_id': {'allow_post': True}}
     ctx.tenant_id = None
     attr_inst = attributes.AttributeInfo(attr_info)
     self.assertRaises(exc.HTTPBadRequest, attr_inst.populate_project_id,
                       ctx, res_dict, True)
Exemplo n.º 10
0
 def test_populate_project_id_admin_req(self):
     tenant_id_1 = uuidutils.generate_uuid()
     tenant_id_2 = uuidutils.generate_uuid()
     # non-admin users can't create a res on behalf of another project
     ctx = context.Context(user_id=None, tenant_id=tenant_id_1)
     res_dict = {'tenant_id': tenant_id_2}
     attr_inst = attributes.AttributeInfo({})
     self.assertRaises(exc.HTTPBadRequest, attr_inst.populate_project_id,
                       ctx, res_dict, None)
     # but admin users can
     ctx.is_admin = True
     attr_inst.populate_project_id(ctx, res_dict, is_create=False)
Exemplo n.º 11
0
 def test_fill_no_default_value_no_allow_post(self):
     attr_info = {
         'key': {
             'allow_post': False,
         },
     }
     attr_inst = attributes.AttributeInfo(attr_info)
     self.assertRaises(exceptions.InvalidInput,
                       self._test_fill_default_value,
                       attr_inst, {'key': 'X'}, {'key': 'X'})
     self._test_fill_default_value(attr_inst, {}, {})
     self.assertRaises(self._EXC_CLS, attr_inst.fill_post_defaults,
                       {'key': 'X'}, self._EXC_CLS)
Exemplo n.º 12
0
def _fixup_res_dict(context, attr_name, res_dict, check_allow_post=True):
    attr_info = attributes.RESOURCE_ATTRIBUTE_MAP[attr_name]
    attr_ops = lib_attrs.AttributeInfo(attr_info)
    try:
        attr_ops.populate_project_id(context, res_dict, True)
        lib_attrs.populate_project_info(attr_info)
        attr_ops.verify_attributes(res_dict)
    except webob.exc.HTTPBadRequest as e:
        # convert webob exception into ValueError as these functions are
        # for internal use. webob exception doesn't make sense.
        raise ValueError(e.detail)
    attr_ops.fill_post_defaults(res_dict, check_allow_post=check_allow_post)
    attr_ops.convert_values(res_dict)
    return res_dict
Exemplo n.º 13
0
def _fixup_res_dict(context, attr_name, res_dict, check_allow_post=True):
    # This method is a replacement of _fixup_res_dict which is used in
    # neutron.plugin.common.utils. All this mock does is insert a uuid
    # for the id field if one is not found ONLY if running in api_replay_mode.
    if cfg.CONF.api_replay_mode and 'id' not in res_dict:
        res_dict['id'] = uuidutils.generate_uuid()
    attr_info = attributes.RESOURCE_ATTRIBUTE_MAP[attr_name]
    attr_ops = lib_attrs.AttributeInfo(attr_info)
    try:
        attr_ops.populate_project_id(context, res_dict, True)
        lib_attrs.populate_project_info(attr_info)
        attr_ops.verify_attributes(res_dict)
    except webob.exc.HTTPBadRequest as e:
        # convert webob exception into ValueError as these functions are
        # for internal use. webob exception doesn't make sense.
        raise ValueError(e.detail)

    attr_ops.fill_post_defaults(res_dict, check_allow_post=check_allow_post)
    attr_ops.convert_values(res_dict)
    return res_dict
Exemplo n.º 14
0
from neutron.api.v2 import resource_helper

from networking_sfc._i18n import _
from networking_sfc import extensions as sfc_extensions

cfg.CONF.import_opt('api_extensions_path', 'neutron.common.config')
neutron_ext.append_api_extensions_path(sfc_extensions.__path__)
FLOW_CLASSIFIER_EXT = "flow_classifier"
FLOW_CLASSIFIER_PREFIX = "/sfc"

fc_supported_protocols = [
    const.PROTO_NAME_TCP, const.PROTO_NAME_UDP, const.PROTO_NAME_ICMP
]
fc_supported_ethertypes = ['IPv4', 'IPv6']
SUPPORTED_L7_PARAMETERS = {}
_l7_param_attrs = attr.AttributeInfo(SUPPORTED_L7_PARAMETERS)


# Flow Classifier Exceptions
class FlowClassifierNotFound(neutron_exc.NotFound):
    message = _("Flow Classifier %(id)s not found.")


class FlowClassifierPortNotFound(neutron_exc.NotFound):
    message = _("Flow Classifier Neutron Port %(id)s not found.")


class FlowClassifierInvalidPortRange(neutron_exc.InvalidInput):
    message = _("Invalid IP protocol port range. min_port_range="
                "%(port_range_min)s must be lesser or equal to "
                "max_port_range=%(port_range_max)s.")
Exemplo n.º 15
0
 def test_verify_attributes_null(self):
     attributes.AttributeInfo({}).verify_attributes({})
Exemplo n.º 16
0
 def test_verify_attributes_ok_with_project_id(self):
     attributes.AttributeInfo(
         {'tenant_id': 'foo', 'project_id': 'foo'}).verify_attributes(
         {'tenant_id': 'foo'})
Exemplo n.º 17
0
 def test_create_from_api_def(self):
     self.assertEqual(
         port.RESOURCE_ATTRIBUTE_MAP,
         attributes.AttributeInfo(port.RESOURCE_ATTRIBUTE_MAP).attributes)
Exemplo n.º 18
0
    def test_create_from_attribute_info_instance(self):
        cloned_attrs = attributes.AttributeInfo(
            TestAttributeInfo._ATTRS_INSTANCE)

        self.assertEqual(TestAttributeInfo._ATTRS_INSTANCE.attributes,
                         cloned_attrs.attributes)
Exemplo n.º 19
0
class TestAttributeInfo(base.BaseTestCase):

    class _MyException(Exception):
        pass

    _EXC_CLS = _MyException
    _RESOURCE_NAME = 'thing'
    _RESOURCE_ATTRS = {'name': {}, 'type': {}}
    _RESOURCE_MAP = {_RESOURCE_NAME: _RESOURCE_ATTRS}
    _ATTRS_INSTANCE = attributes.AttributeInfo(_RESOURCE_MAP)

    def test_create_from_attribute_info_instance(self):
        cloned_attrs = attributes.AttributeInfo(
            TestAttributeInfo._ATTRS_INSTANCE)

        self.assertEqual(TestAttributeInfo._ATTRS_INSTANCE.attributes,
                         cloned_attrs.attributes)

    def test_create_from_api_def(self):
        self.assertEqual(
            port.RESOURCE_ATTRIBUTE_MAP,
            attributes.AttributeInfo(port.RESOURCE_ATTRIBUTE_MAP).attributes)

    def _test_fill_default_value(self, attr_inst, expected, res_dict,
                                 check_allow_post=True):
        attr_inst.fill_post_defaults(
            res_dict, check_allow_post=check_allow_post)
        self.assertEqual(expected, res_dict)

    def test_fill_default_value_ok(self):
        attr_info = {
            'key': {
                'allow_post': True,
                'default': constants.ATTR_NOT_SPECIFIED,
            },
        }
        attr_inst = attributes.AttributeInfo(attr_info)
        self._test_fill_default_value(attr_inst, {'key': 'X'}, {'key': 'X'})
        self._test_fill_default_value(
            attr_inst, {'key': constants.ATTR_NOT_SPECIFIED}, {})

    def test_override_no_allow_post(self):
        attr_info = {
            'key': {
                'allow_post': False,
                'default': constants.ATTR_NOT_SPECIFIED,
            },
        }
        attr_inst = attributes.AttributeInfo(attr_info)
        self._test_fill_default_value(attr_inst, {'key': 'X'}, {'key': 'X'},
                                      check_allow_post=False)

    def test_fill_no_default_value_allow_post(self):
        attr_info = {
            'key': {
                'allow_post': True,
            },
        }
        attr_inst = attributes.AttributeInfo(attr_info)
        self._test_fill_default_value(attr_inst, {'key': 'X'}, {'key': 'X'})
        self.assertRaises(exceptions.InvalidInput,
                          self._test_fill_default_value,
                          attr_inst, {'key': 'X'}, {})
        self.assertRaises(self._EXC_CLS, attr_inst.fill_post_defaults,
                          {}, self._EXC_CLS)

    def test_fill_no_default_value_no_allow_post(self):
        attr_info = {
            'key': {
                'allow_post': False,
            },
        }
        attr_inst = attributes.AttributeInfo(attr_info)
        self.assertRaises(exceptions.InvalidInput,
                          self._test_fill_default_value,
                          attr_inst, {'key': 'X'}, {'key': 'X'})
        self._test_fill_default_value(attr_inst, {}, {})
        self.assertRaises(self._EXC_CLS, attr_inst.fill_post_defaults,
                          {'key': 'X'}, self._EXC_CLS)

    def _test_convert_value(self, attr_inst, expected, res_dict):
        attr_inst.convert_values(res_dict)
        self.assertEqual(expected, res_dict)

    def test_convert_value(self):
        attr_info = {
            'key': {
            },
        }
        attr_inst = attributes.AttributeInfo(attr_info)
        self._test_convert_value(attr_inst,
                                 {'key': constants.ATTR_NOT_SPECIFIED},
                                 {'key': constants.ATTR_NOT_SPECIFIED})
        self._test_convert_value(attr_inst, {'key': 'X'}, {'key': 'X'})
        self._test_convert_value(attr_inst,
                                 {'other_key': 'X'}, {'other_key': 'X'})

        attr_info = {
            'key': {
                'convert_to': converters.convert_to_int,
            },
        }
        attr_inst = attributes.AttributeInfo(attr_info)
        self._test_convert_value(attr_inst,
                                 {'key': constants.ATTR_NOT_SPECIFIED},
                                 {'key': constants.ATTR_NOT_SPECIFIED})
        self._test_convert_value(attr_inst, {'key': 1}, {'key': '1'})
        self._test_convert_value(attr_inst, {'key': 1}, {'key': 1})
        self.assertRaises(exceptions.InvalidInput, self._test_convert_value,
                          attr_inst, {'key': 1}, {'key': 'a'})

        attr_info = {
            'key': {
                'validate': {'type:uuid': None},
            },
        }
        attr_inst = attributes.AttributeInfo(attr_info)
        self._test_convert_value(attr_inst,
                                 {'key': constants.ATTR_NOT_SPECIFIED},
                                 {'key': constants.ATTR_NOT_SPECIFIED})
        uuid_str = '01234567-1234-1234-1234-1234567890ab'
        self._test_convert_value(attr_inst,
                                 {'key': uuid_str}, {'key': uuid_str})
        self.assertRaises(exceptions.InvalidInput, self._test_convert_value,
                          attr_inst, {'key': 1}, {'key': 1})
        self.assertRaises(self._EXC_CLS, attr_inst.convert_values,
                          {'key': 1}, self._EXC_CLS)

    def test_populate_project_id_admin_req(self):
        tenant_id_1 = uuidutils.generate_uuid()
        tenant_id_2 = uuidutils.generate_uuid()
        # non-admin users can't create a res on behalf of another project
        ctx = context.Context(user_id=None, tenant_id=tenant_id_1)
        res_dict = {'tenant_id': tenant_id_2}
        attr_inst = attributes.AttributeInfo({})
        self.assertRaises(exc.HTTPBadRequest,
                          attr_inst.populate_project_id,
                          ctx, res_dict, None)
        # but admin users can
        ctx.is_admin = True
        attr_inst.populate_project_id(ctx, res_dict, is_create=False)

    def test_populate_project_id_from_context(self):
        tenant_id = uuidutils.generate_uuid()
        ctx = context.Context(user_id=None, tenant_id=tenant_id)
        # for each create request, the tenant_id should be added to the
        # req body
        res_dict = {}
        attr_inst = attributes.AttributeInfo({})
        attr_inst.populate_project_id(ctx, res_dict, is_create=True)
        self.assertEqual(
            {'tenant_id': ctx.tenant_id, 'project_id': ctx.tenant_id},
            res_dict)

    def test_populate_project_id_mandatory_not_specified(self):
        tenant_id = uuidutils.generate_uuid()
        ctx = context.Context(user_id=None, tenant_id=tenant_id)
        # if the tenant_id is mandatory for the resource and not specified
        # in the request nor in the context, an exception should be raised
        res_dict = {}
        attr_info = {'tenant_id': {'allow_post': True}}
        ctx.tenant_id = None
        attr_inst = attributes.AttributeInfo(attr_info)
        self.assertRaises(exc.HTTPBadRequest,
                          attr_inst.populate_project_id,
                          ctx, res_dict, True)

    def test_populate_project_id_not_mandatory(self):
        ctx = context.Context(user_id=None)
        # if the tenant_id is not mandatory for the resource it should be
        # OK if it is not in the request.
        res_dict = {'name': 'test_port'}
        attr_inst = attributes.AttributeInfo({})
        ctx.tenant_id = None
        attr_inst.populate_project_id(ctx, res_dict, True)

    def test_verify_attributes_null(self):
        attributes.AttributeInfo({}).verify_attributes({})

    def test_verify_attributes_ok_with_project_id(self):
        attributes.AttributeInfo(
            {'tenant_id': 'foo', 'project_id': 'foo'}).verify_attributes(
            {'tenant_id': 'foo'})

    def test_verify_attributes_ok_subset(self):
        attributes.AttributeInfo(
            {'attr1': 'foo', 'attr2': 'bar'}).verify_attributes(
            {'attr1': 'foo'})

    def test_verify_attributes_unrecognized(self):
        with testtools.ExpectedException(exc.HTTPBadRequest) as bad_req:
            attributes.AttributeInfo(
                {'attr1': 'foo'}).verify_attributes(
                {'attr1': 'foo', 'attr2': 'bar'})
            self.assertEqual(bad_req.message,
                             "Unrecognized attribute(s) 'attr2'")
Exemplo n.º 20
0
 def test_verify_attributes_ok_subset(self):
     attributes.AttributeInfo(
         {'attr1': 'foo', 'attr2': 'bar'}).verify_attributes(
         {'attr1': 'foo'})