Neutron requires the allowed address pair ip address to be either an ip or a cidr. https://review.opendev.org/#/c/575265/ made heat verify for cidr only. Change-Id: I2cc2785cb32cf8d788af6262992b1b76107c8292 Story: 2005674 Task: 30985tags/13.0.0.0rc1
@@ -118,6 +118,25 @@ class CIDRConstraint(constraints.BaseCustomConstraint): | |||
return False | |||
class IPCIDRConstraint(constraints.BaseCustomConstraint): | |||
def validate(self, value, context, template=None): | |||
try: | |||
if '/' in value: | |||
msg = validators.validate_subnet(value) | |||
else: | |||
msg = validators.validate_ip_address(value) | |||
if msg is not None: | |||
self._error_message = msg | |||
return False | |||
else: | |||
return True | |||
except Exception: | |||
self._error_message = '{} is not a valid IP or CIDR'.format( | |||
value) | |||
return False | |||
class ISO8601Constraint(constraints.BaseCustomConstraint): | |||
def validate(self, value, context, template=None): |
@@ -266,7 +266,7 @@ class Port(neutron.NeutronResource): | |||
_('IP address to allow through this port.'), | |||
required=True, | |||
constraints=[ | |||
constraints.CustomConstraint('net_cidr') | |||
constraints.CustomConstraint('ip_or_cidr') | |||
] | |||
), | |||
}, |
@@ -141,6 +141,78 @@ class TestCIDRConstraint(common.HeatTestCase): | |||
self.assertEqual(mock_validate_subnet.call_count, 2) | |||
class TestIPCIDRConstraint(common.HeatTestCase): | |||
def setUp(self): | |||
super(TestIPCIDRConstraint, self).setUp() | |||
self.constraint = cc.IPCIDRConstraint() | |||
def test_valid_format(self): | |||
validate_format = [ | |||
'10.0.0.0/24', | |||
'1.1.1.1', | |||
'1.0.1.1', | |||
'255.255.255.255', | |||
'6000::/64', | |||
'2002:2002::20c:29ff:fe7d:811a', | |||
'::1', | |||
'2002::', | |||
'2002::1', | |||
] | |||
for value in validate_format: | |||
self.assertTrue(self.constraint.validate(value, None)) | |||
def test_invalid_format(self): | |||
invalidate_format = [ | |||
'::/129', | |||
'Invalid cidr', | |||
'300.0.0.0/24', | |||
'10.0.0.0/33', | |||
'10.0.0/24', | |||
'10.0/24', | |||
'10.0.a.10/24', | |||
'8.8.8.0/ 24', | |||
None, | |||
123, | |||
'1.1', | |||
'1.1.', | |||
'1.1.1', | |||
'1.1.1.', | |||
'1.1.1.256', | |||
'1.a.1.1', | |||
'2002::2001::1', | |||
'2002::g', | |||
'2001::0::', | |||
'20c:29ff:fe7d:811a' | |||
] | |||
for value in invalidate_format: | |||
self.assertFalse(self.constraint.validate(value, None)) | |||
@mock.patch('neutron_lib.api.validators.validate_subnet') | |||
@mock.patch('neutron_lib.api.validators.validate_ip_address') | |||
def test_validate(self, mock_validate_ip, mock_validate_subnet): | |||
test_formats = [ | |||
'10.0.0/24', | |||
'10.0/24', | |||
'10.0.0.0/33', | |||
] | |||
for cidr in test_formats: | |||
self.assertFalse(self.constraint.validate(cidr, None)) | |||
mock_validate_subnet.assert_called_with(cidr) | |||
self.assertEqual(mock_validate_subnet.call_count, 3) | |||
test_formats = [ | |||
'10.0.0', | |||
'10.0', | |||
'10.0.0.0', | |||
] | |||
for ip in test_formats: | |||
self.assertFalse(self.constraint.validate(ip, None)) | |||
mock_validate_ip.assert_called_with(ip) | |||
self.assertEqual(mock_validate_ip.call_count, 3) | |||
class TestISO8601Constraint(common.HeatTestCase): | |||
def setUp(self): |
@@ -183,6 +183,8 @@ class NeutronPortTest(common.HeatTestCase): | |||
def test_allowed_address_pair(self): | |||
t = template_format.parse(neutron_port_with_address_pair_template) | |||
t['resources']['port']['properties'][ | |||
'allowed_address_pairs'][0]['ip_address'] = '10.0.3.21' | |||
stack = utils.parse_stack(t) | |||
self.find_mock.return_value = 'abcd1234' | |||
@@ -200,7 +202,7 @@ class NeutronPortTest(common.HeatTestCase): | |||
self.create_mock.assert_called_once_with({'port': { | |||
'network_id': u'abcd1234', | |||
'allowed_address_pairs': [{ | |||
'ip_address': u'10.0.3.21/8', | |||
'ip_address': u'10.0.3.21', | |||
'mac_address': u'00-B0-D0-86-BB-F7' | |||
}], | |||
'name': utils.PhysName(stack.name, 'port'), |
@@ -101,6 +101,7 @@ heat.constraints = | |||
iso_8601 = heat.engine.constraint.common_constraints:ISO8601Constraint | |||
mac_addr = heat.engine.constraint.common_constraints:MACConstraint | |||
net_cidr = heat.engine.constraint.common_constraints:CIDRConstraint | |||
ip_or_cidr = heat.engine.constraint.common_constraints:IPCIDRConstraint | |||
test_constr = heat.engine.constraint.common_constraints:TestConstraintDelay | |||
timezone = heat.engine.constraint.common_constraints:TimezoneConstraint | |||
# service constraints |