# Used by range check to indicate no limit for a bound.
UNLIMITED = None
+# TODO(watanabe.isao): A fix like in neutron/db/models_v2.py needs to be
+# done in other db modules, to reuse the following constants.
+# Common definitions for maximum string field length
+NAME_MAX_LEN = 255
+TENANT_ID_MAX_LEN = 255
+DESCRIPTION_MAX_LEN = 255
+DEVICE_ID_MAX_LEN = 255
+DEVICE_OWNER_MAX_LEN = 255
+
def _verify_dict_keys(expected_keys, target_dict, strict=True):
"""Allows to verify keys in a dictionary.
'is_visible': True,
'primary_key': True},
'name': {'allow_post': True, 'allow_put': True,
- 'validate': {'type:string': None},
+ 'validate': {'type:string': NAME_MAX_LEN},
'default': '', 'is_visible': True},
'subnets': {'allow_post': False, 'allow_put': False,
'default': [],
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
- 'validate': {'type:string': None},
+ 'validate': {'type:string': TENANT_ID_MAX_LEN},
'required_by_policy': True,
'is_visible': True},
SHARED: {'allow_post': True,
'is_visible': True,
'primary_key': True},
'name': {'allow_post': True, 'allow_put': True, 'default': '',
- 'validate': {'type:string': None},
+ 'validate': {'type:string': NAME_MAX_LEN},
'is_visible': True},
'network_id': {'allow_post': True, 'allow_put': False,
'required_by_policy': True,
'enforce_policy': True,
'is_visible': True},
'device_id': {'allow_post': True, 'allow_put': True,
- 'validate': {'type:string': None},
+ 'validate': {'type:string': DEVICE_ID_MAX_LEN},
'default': '',
'is_visible': True},
'device_owner': {'allow_post': True, 'allow_put': True,
- 'validate': {'type:string': None},
+ 'validate': {'type:string': DEVICE_OWNER_MAX_LEN},
'default': '',
'is_visible': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
- 'validate': {'type:string': None},
+ 'validate': {'type:string': TENANT_ID_MAX_LEN},
'required_by_policy': True,
'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True,
'primary_key': True},
'name': {'allow_post': True, 'allow_put': True, 'default': '',
- 'validate': {'type:string': None},
+ 'validate': {'type:string': NAME_MAX_LEN},
'is_visible': True},
'ip_version': {'allow_post': True, 'allow_put': False,
'convert_to': convert_to_int,
'validate': {'type:hostroutes': None},
'is_visible': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
- 'validate': {'type:string': None},
+ 'validate': {'type:string': TENANT_ID_MAX_LEN},
'required_by_policy': True,
'is_visible': True},
'enable_dhcp': {'allow_post': True, 'allow_put': True,
import sqlalchemy as sa
from sqlalchemy import orm
+from neutron.api.v2 import attributes as attr
from neutron.common import constants
from neutron.db import model_base
from neutron.openstack.common import uuidutils
"""Tenant mixin, add to subclasses that have a tenant."""
# NOTE(jkoelker) tenant_id is just a free form string ;(
- tenant_id = sa.Column(sa.String(255), index=True)
+ tenant_id = sa.Column(sa.String(attr.TENANT_ID_MAX_LEN), index=True)
class HasId(object):
"""Status with description mixin."""
status = sa.Column(sa.String(16), nullable=False)
- status_description = sa.Column(sa.String(255))
+ status_description = sa.Column(sa.String(attr.DESCRIPTION_MAX_LEN))
class IPAvailabilityRange(model_base.BASEV2):
class Port(model_base.BASEV2, HasId, HasTenant):
"""Represents a port on a Neutron v2 network."""
- name = sa.Column(sa.String(255))
+ name = sa.Column(sa.String(attr.NAME_MAX_LEN))
network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id"),
nullable=False)
fixed_ips = orm.relationship(IPAllocation, backref='ports', lazy='joined')
mac_address = sa.Column(sa.String(32), nullable=False)
admin_state_up = sa.Column(sa.Boolean(), nullable=False)
status = sa.Column(sa.String(16), nullable=False)
- device_id = sa.Column(sa.String(255), nullable=False)
- device_owner = sa.Column(sa.String(255), nullable=False)
+ device_id = sa.Column(sa.String(attr.DEVICE_ID_MAX_LEN), nullable=False)
+ device_owner = sa.Column(sa.String(attr.DEVICE_OWNER_MAX_LEN),
+ nullable=False)
__table_args__ = (
sa.UniqueConstraint(
network_id, mac_address,
are used for the IP allocation.
"""
- name = sa.Column(sa.String(255))
+ name = sa.Column(sa.String(attr.NAME_MAX_LEN))
network_id = sa.Column(sa.String(36), sa.ForeignKey('networks.id'))
ip_version = sa.Column(sa.Integer, nullable=False)
cidr = sa.Column(sa.String(64), nullable=False)
class Network(model_base.BASEV2, HasId, HasTenant):
"""Represents a v2 neutron network."""
- name = sa.Column(sa.String(255))
+ name = sa.Column(sa.String(attr.NAME_MAX_LEN))
ports = orm.relationship(Port, backref='networks')
subnets = orm.relationship(Subnet, backref='networks',
lazy="joined")
'is_visible': True},
'description': {'allow_post': False, 'allow_put': True,
'is_visible': True,
- 'validate': {'type:string': None}},
+ 'validate': {'type:string': attr.DESCRIPTION_MAX_LEN}},
},
}
# Attribute Map
EXTRADHCPOPTS = 'extra_dhcp_opts'
+# Common definitions for maximum string field length
+DHCP_OPT_NAME_MAX_LEN = 64
+DHCP_OPT_VALUE_MAX_LEN = 255
+
EXTENDED_ATTRIBUTES_2_0 = {
'ports': {
EXTRADHCPOPTS:
'validate': {
'type:list_of_dict_or_none': {
'id': {'type:uuid': None, 'required': False},
- 'opt_name': {'type:not_empty_string': None,
+ 'opt_name': {'type:not_empty_string': DHCP_OPT_NAME_MAX_LEN,
'required': True},
- 'opt_value': {'type:not_empty_string_or_none': None,
+ 'opt_value': {'type:not_empty_string_or_none':
+ DHCP_OPT_VALUE_MAX_LEN,
'required': True},
'ip_version': {'convert_to': attr.convert_to_int,
'type:values': [4, 6],
'is_visible': True,
'primary_key': True},
'name': {'allow_post': True, 'allow_put': True,
- 'validate': {'type:string': None},
+ 'validate': {'type:string': attr.NAME_MAX_LEN},
'is_visible': True, 'default': ''},
'admin_state_up': {'allow_post': True, 'allow_put': True,
'default': True,
'is_visible': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
'required_by_policy': True,
- 'validate': {'type:string': None},
+ 'validate': {'type:string': attr.TENANT_ID_MAX_LEN},
'is_visible': True},
EXTERNAL_GW_INFO: {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': None,
'is_visible': True, 'default': None},
'tenant_id': {'allow_post': True, 'allow_put': False,
'required_by_policy': True,
- 'validate': {'type:string': None},
+ 'validate': {'type:string': attr.TENANT_ID_MAX_LEN},
'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
PHYSICAL_NETWORK = 'provider:physical_network'
SEGMENTATION_ID = 'provider:segmentation_id'
ATTRIBUTES = (NETWORK_TYPE, PHYSICAL_NETWORK, SEGMENTATION_ID)
+
+# Common definitions for maximum string field length
+NETWORK_TYPE_MAX_LEN = 32
+PHYSICAL_NETWORK_MAX_LEN = 64
+
EXTENDED_ATTRIBUTES_2_0 = {
'networks': {
NETWORK_TYPE: {'allow_post': True, 'allow_put': True,
- 'validate': {'type:string': None},
+ 'validate': {'type:string': NETWORK_TYPE_MAX_LEN},
'default': attributes.ATTR_NOT_SPECIFIED,
'enforce_policy': True,
'is_visible': True},
PHYSICAL_NETWORK: {'allow_post': True, 'allow_put': True,
- 'validate': {'type:string': None},
+ 'validate': {'type:string':
+ PHYSICAL_NETWORK_MAX_LEN},
'default': attributes.ATTR_NOT_SPECIFIED,
'enforce_policy': True,
'is_visible': True},
'primary_key': True},
'name': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': '',
- 'validate': {'type:name_not_default': None}},
+ 'validate': {'type:name_not_default': attr.NAME_MAX_LEN}},
'description': {'allow_post': True, 'allow_put': True,
+ 'validate': {'type:string': attr.DESCRIPTION_MAX_LEN},
'is_visible': True, 'default': ''},
'tenant_id': {'allow_post': True, 'allow_put': False,
'required_by_policy': True,
'validate': {'type:uuid': None},
'is_visible': True},
'name': {'allow_post': True, 'allow_put': True, 'default': '',
- 'validate': {'type:string': None},
+ 'validate': {'type:string': attributes.NAME_MAX_LEN},
'is_visible': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
- 'validate': {'type:string': None},
+ 'validate': {'type:string': attributes.TENANT_ID_MAX_LEN},
'required_by_policy': True,
'is_visible': True},
'network_id': {'allow_post': True, 'allow_put': False,
'id': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'name': {'allow_post': True, 'allow_put': True,
- 'validate': {'type:string': None},
+ 'validate': {'type:string': attributes.NAME_MAX_LEN},
'is_visible': True, 'default': ''},
'default': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'default': [],
'is_visible': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
- 'validate': {'type:string': None},
+ 'validate': {'type:string':
+ attributes.TENANT_ID_MAX_LEN},
'required_by_policy': True,
'is_visible': True}
},
'id': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'name': {'allow_post': True, 'allow_put': True,
- 'validate': {'type:string': None},
+ 'validate': {'type:string': attributes.NAME_MAX_LEN},
'is_visible': True, 'default': ''},
'client_certificate': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'validate': {'type:ip_address': None},
'is_visible': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
- 'validate': {'type:string': None},
+ 'validate': {'type:string':
+ attributes.TENANT_ID_MAX_LEN},
'required_by_policy': True,
'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'convert_to': attr.convert_to_boolean,
'is_visible': True, 'default': False},
'name': {'allow_post': True, 'allow_put': False,
- 'validate': {'type:string': None},
+ 'validate': {'type:string': attr.NAME_MAX_LEN},
'is_visible': True, 'default': ''},
'min': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': '0',
'convert_to': convert_to_unsigned_int_or_none_max_63},
'tenant_id': {'allow_post': True, 'allow_put': False,
'required_by_policy': True,
- 'validate': {'type:string': None},
+ 'validate': {'type:string': attr.TENANT_ID_MAX_LEN},
'is_visible': True},
},
}
'status': "ACTIVE"}}
self._test_create_failure_bad_request('networks', data)
+ def test_create_with_too_long_name(self):
+ data = {'network': {'name': "12345678" * 32,
+ 'admin_state_up': True,
+ 'tenant_id': _uuid()}}
+ res = self.api.post(_get_path('networks', fmt=self.fmt),
+ self.serialize(data),
+ content_type='application/' + self.fmt,
+ expect_errors=True)
+ self.assertEqual(res.status_int, exc.HTTPBadRequest.code)
+
def test_create_bulk(self):
data = {'networks': [{'name': 'net1',
'admin_state_up': True,