Merge "Do not defer allocation if fixed-ips is in the port create request."

This commit is contained in:
Jenkins 2017-06-14 00:46:00 +00:00 committed by Gerrit Code Review
commit ce33de5f51
3 changed files with 28 additions and 6 deletions

View File

@ -657,14 +657,15 @@ class IpamBackendMixin(db_base_plugin_common.DbBasePluginCommon):
# implementations.
return host and validators.is_attr_set(host)
def _ipam_get_subnets(self, context, network_id, host, service_type=None):
def _ipam_get_subnets(self, context, network_id, host, service_type=None,
fixed_configured=False):
"""Return eligible subnets
If no eligible subnets are found, determine why and potentially raise
an appropriate error.
"""
subnets = self._find_candidate_subnets(
context, network_id, host, service_type)
subnets = self._find_candidate_subnets(context, network_id, host,
service_type, fixed_configured)
if subnets:
subnet_dicts = [self._make_subnet_dict(subnet, context=context)
for subnet in subnets]
@ -697,13 +698,20 @@ class IpamBackendMixin(db_base_plugin_common.DbBasePluginCommon):
raise ipam_exceptions.IpAddressGenerationFailureNoMatchingSubnet()
def _find_candidate_subnets(self, context, network_id, host, service_type):
def _find_candidate_subnets(self, context, network_id, host, service_type,
fixed_configured):
"""Find canditate subnets for the network, host, and service_type"""
query = self._query_subnets_on_network(context, network_id)
query = self._query_filter_service_subnets(query, service_type)
# Select candidate subnets and return them
if not self.is_host_set(host):
if fixed_configured:
# If fixed_ips in request and host is not known all subnets on
# the network are candidates. Host/Segment will be validated
# on port update with binding:host_id set. Allocation _cannot_
# be deferred as requested fixed_ips would then be lost.
return query.all()
# If the host isn't known, we can't allocate on a routed network.
# So, exclude any subnets attached to segments.
return self._query_exclude_subnets_on_segments(query).all()

View File

@ -200,15 +200,16 @@ class IpamPluggableBackend(ipam_backend_mixin.IpamBackendMixin):
a subnet_id then allocate an IP address accordingly.
"""
p = port['port']
fixed_configured = p['fixed_ips'] is not constants.ATTR_NOT_SPECIFIED
subnets = self._ipam_get_subnets(context,
network_id=p['network_id'],
host=p.get(portbindings.HOST_ID),
service_type=p.get('device_owner'))
service_type=p.get('device_owner'),
fixed_configured=fixed_configured)
v4, v6_stateful, v6_stateless = self._classify_subnets(
context, subnets)
fixed_configured = p['fixed_ips'] is not constants.ATTR_NOT_SPECIFIED
if fixed_configured:
ips = self._test_fixed_ips_for_port(context,
p["network_id"],

View File

@ -880,6 +880,19 @@ class TestSegmentAwareIpam(SegmentAwareIpamTestCase):
# Don't allocate IPs in this case because we didn't give binding info
self.assertEqual(0, len(res['port']['fixed_ips']))
def test_port_create_fixed_ips_with_segment_subnets_no_binding_info(self):
"""Fixed IP provided and no binding info, do not defer IP allocation"""
network, segment, subnet = self._create_test_segment_with_subnet()
response = self._create_port(self.fmt,
net_id=network['network']['id'],
tenant_id=network['network']['tenant_id'],
fixed_ips=[
{'subnet_id': subnet['subnet']['id']}
])
res = self.deserialize(self.fmt, response)
# We gave fixed_ips, allocate IPs in this case despite no binding info
self._validate_immediate_ip_allocation(res['port']['id'])
def _assert_one_ip_in_subnet(self, response, cidr):
res = self.deserialize(self.fmt, response)
self.assertEqual(1, len(res['port']['fixed_ips']))