diff --git a/neutron/db/ipam_pluggable_backend.py b/neutron/db/ipam_pluggable_backend.py index 2c4a72eee28..d4f758493f3 100644 --- a/neutron/db/ipam_pluggable_backend.py +++ b/neutron/db/ipam_pluggable_backend.py @@ -295,7 +295,7 @@ class IpamPluggableBackend(ipam_backend_mixin.IpamBackendMixin): try: subnets = self._ipam_get_subnets( context, network_id=port['network_id'], host=host, - service_type=port.get('device_owner')) + service_type=port.get('device_owner'), fixed_configured=True) except ipam_exc.DeferIpam: subnets = [] diff --git a/neutron/tests/unit/db/test_ipam_pluggable_backend.py b/neutron/tests/unit/db/test_ipam_pluggable_backend.py index c3c41b717c7..b49fca1086f 100644 --- a/neutron/tests/unit/db/test_ipam_pluggable_backend.py +++ b/neutron/tests/unit/db/test_ipam_pluggable_backend.py @@ -660,8 +660,8 @@ class TestDbBasePluginIpam(test_db_base.NeutronDbPluginV2TestCase): original_ips, new_ips, mac) mocks['driver'].get_address_request_factory.assert_called_once_with() mocks['ipam']._ipam_get_subnets.assert_called_once_with( - context, network_id=port_dict['network_id'], host=None, - service_type=port_dict['device_owner']) + context, network_id=port_dict['network_id'], fixed_configured=True, + host=None, service_type=port_dict['device_owner']) # Validate port_dict is passed into address_factory address_factory.get_request.assert_called_once_with(context, port_dict, diff --git a/neutron/tests/unit/extensions/test_segment.py b/neutron/tests/unit/extensions/test_segment.py index 55e8378c411..bcf8b3cd21a 100644 --- a/neutron/tests/unit/extensions/test_segment.py +++ b/neutron/tests/unit/extensions/test_segment.py @@ -1020,8 +1020,8 @@ class TestSegmentAwareIpam(SegmentAwareIpamTestCase): self.assertEqual(segment_exc.HostConnectedToMultipleSegments.__name__, res['NeutronError']['type']) - def test_port_update_excludes_hosts_on_segments(self): - """No binding information is provided, subnets on segments""" + def test_port_update_with_fixed_ips_ok_if_no_binding_host(self): + """No binding host information is provided, subnets on segments""" with self.network() as network: segment = self._test_create_segment( network_id=network['network']['id'], @@ -1041,7 +1041,33 @@ class TestSegmentAwareIpam(SegmentAwareIpamTestCase): port_req = self.new_update_request('ports', data, port_id) response = port_req.get_response(self.api) - # Gets bad request because there are no eligible subnets. + # The IP is allocated since there is no binding host info any + # subnet can be used for allocation. + self.assertEqual(webob.exc.HTTPOk.code, response.status_int) + + def test_port_update_with_fixed_ips_fail_if_host_not_on_segment(self): + """Binding information is provided, subnets on segments. Update to + subnet on different segment fails. + """ + network, segments, subnets = self._create_test_segments_with_subnets(2) + + # Setup host mappings + self._setup_host_mappings([(segments[0]['segment']['id'], 'fakehost')]) + + # Create a port and validate immediate ip allocation + res = self._create_port_and_show(network, + arg_list=(portbindings.HOST_ID,), + **{portbindings.HOST_ID: 'fakehost'}) + self._validate_immediate_ip_allocation(res['port']['id']) + + # Try requesting an new IP, but the subnet does not match host segment + port_id = res['port']['id'] + data = {'port': { + 'fixed_ips': [{'subnet_id': subnets[1]['subnet']['id']}]}} + port_req = self.new_update_request('ports', data, port_id) + response = port_req.get_response(self.api) + + # Port update fails. self.assertEqual(webob.exc.HTTPBadRequest.code, response.status_int) def _create_port_and_show(self, network, **kwargs): diff --git a/releasenotes/notes/fix-update-port-fixed-ips-on-routed-provider-networks-c54a54844d9a3926.yaml b/releasenotes/notes/fix-update-port-fixed-ips-on-routed-provider-networks-c54a54844d9a3926.yaml new file mode 100644 index 00000000000..a0320ed7ba0 --- /dev/null +++ b/releasenotes/notes/fix-update-port-fixed-ips-on-routed-provider-networks-c54a54844d9a3926.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + When updating the fixed-ips of a port residing on a routed provider + network the port update would always fail if *host* was not set. + See bug: `1844124 `_. +