Add default values in port forwarding port ranges definitions

Also, add a new common type 'PortRanges' to validate port
ranges fields to the specific format PORT_RANGE:PORT_RANGE.

Implements: blueprint floatingips-portforwarding-ranges
Related-Bug: #1885921
Change-Id: Idd257d6e64ef43ccf7afabd30003986628b0d25a
This commit is contained in:
Pedro Henrique Pereira Martins 2021-09-28 14:15:41 -03:00 committed by Pedro Henrique
parent f9b428667b
commit e686f3d0d3
3 changed files with 86 additions and 4 deletions

View File

@ -30,21 +30,25 @@ SUB_RESOURCE_ATTRIBUTE_MAP = {
'validate': {'type:port_range': None},
'is_visible': True,
'is_sort_key': True,
'is_filter': True},
'is_filter': True,
'default': None},
INTERNAL_PORT_RANGE: {
'allow_post': True, 'allow_put': True,
'validate': {'type:port_range': None},
'is_visible': True},
'is_visible': True,
'default': None},
pfw.EXTERNAL_PORT: {
'allow_post': True, 'allow_put': True,
'validate': {'type:range_or_none': [1, 65535]},
'is_visible': True,
'is_sort_key': True,
'is_filter': True},
'is_filter': True,
'default': None},
pfw.INTERNAL_PORT: {
'allow_post': True, 'allow_put': True,
'validate': {'type:range_or_none': [1, 65535]},
'is_visible': True},
'is_visible': True,
'default': None},
}
}
}

View File

@ -63,6 +63,71 @@ class IPNetworkPrefixLenField(obj_fields.AutoTypedField):
AUTO_TYPE = IPNetworkPrefixLen()
class PortRanges(obj_fields.FieldType):
@staticmethod
def _is_port_acceptable(port):
start = lib_constants.PORT_RANGE_MIN
end = lib_constants.PORT_RANGE_MAX
return start <= port <= end
def get_schema(self):
return {'type': ['string', 'integer']}
def _validate_port(self, attr, value):
if self._is_port_acceptable(value):
return
raise ValueError(
_('The port %(value)s does not respect the '
'range (%(min)s, %(max)s) in field %(attr)s')
% {'attr': attr,
'value': value,
'min': lib_constants.PORT_RANGE_MIN,
'max': lib_constants.PORT_RANGE_MAX})
def coerce(self, obj, attr, value):
if isinstance(value, int):
self._validate_port(attr, value)
return value
if isinstance(value, str):
if value.isnumeric():
self._validate_port(attr, int(value))
return value
values = value.split(':')
if len(values) == 2:
start, end = list(map(int, values))
if start > end:
raise ValueError(
_('The first port %(start)s must be less or equals '
'than the second port %(end)s of the port range '
'configuration %(value)s'
'in field %(attr)s.') % {
'attr': attr,
'value': value,
'start': start,
'end': end})
self._validate_port(attr, start)
self._validate_port(attr, end)
return value
raise ValueError(
_('The field %(attr)s must be in the format PORT_RANGE or'
'PORT_RANGE:PORT_RANGE (two numeric values separated '
'by a colon), and PORT_RANGE must be a numeric '
'value and respect the range '
'(%(min)s, %(max)s).') % {
'attr': attr,
'min': lib_constants.PORT_RANGE_MIN,
'max': lib_constants.PORT_RANGE_MAX})
raise ValueError(
_('An string/int PORT_RANGE or a string with '
'PORT_RANGE:PORT_RANGE format is '
'expected in field %(attr)s, not a %(type)s') % {
'attr': attr, 'type': value})
class PortRangesField(obj_fields.AutoTypedField):
AUTO_TYPE = PortRanges()
class PortRange(RangeConstrainedInteger):
def __init__(self, start=lib_constants.PORT_RANGE_MIN, **kwargs):
super().__init__(start=start,

View File

@ -199,6 +199,19 @@ class FlowDirectionAndAnyEnumFieldTest(test_base.BaseTestCase, TestField):
self.assertEqual("'%s'" % in_val, self.field.stringify(in_val))
class PortRangesFieldTest(test_base.BaseTestCase, TestField):
def setUp(self):
super(PortRangesFieldTest, self).setUp()
self.field = common_types.PortRangesField()
self.coerce_good_values = [(val, val) for val in (
'80:80', '80:90', '80', 80)]
self.coerce_bad_values = ('x', 0, 99999, '99999',
'9999:', ':9999',
'99999:100000', '80:70')
self.to_primitive_values = self.coerce_good_values
self.from_primitive_values = self.coerce_good_values
class DomainNameFieldTest(test_base.BaseTestCase, TestField):
def setUp(self):
super(DomainNameFieldTest, self).setUp()