diff --git a/neutron/db/l3_db.py b/neutron/db/l3_db.py index 1df69daa0be..76918f81e3e 100644 --- a/neutron/db/l3_db.py +++ b/neutron/db/l3_db.py @@ -1033,10 +1033,15 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, subnets_id.extend([fixed_ip['subnet_id'] for fixed_ip in port['fixed_ips']]) else: - raise l3_exc.RouterInterfaceNotFound( - router_id=router.id, port_id=rp.port_id) + # due to race conditions maybe the port under analysis is + # deleted, so instead returning a RouterInterfaceNotFound + # we continue the analysis avoiding that port + LOG.debug("Port %s could not be found, it might have been " + "deleted concurrently. Will not be checked for " + "an overlapping router interface.", + rp.port_id) - if subnets_id: + if len(subnets_id) > 1: id_filter = {'id': subnets_id} subnets = self._core_plugin.get_subnets(context.elevated(), filters=id_filter) diff --git a/neutron/tests/base.py b/neutron/tests/base.py index 7e5d9bb7c71..6640fe245b0 100644 --- a/neutron/tests/base.py +++ b/neutron/tests/base.py @@ -492,7 +492,11 @@ class BaseTestCase(DietTestCase): root_helper_daemon=get_rootwrap_daemon_cmd()) def _simulate_concurrent_requests_process_and_raise(self, calls, args): + self._simulate_concurrent_requests_process(calls, args, + raise_on_exception=True) + def _simulate_concurrent_requests_process(self, calls, args, + raise_on_exception=False): class SimpleThread(threading.Thread): def __init__(self, q): super(SimpleThread, self).__init__() @@ -529,10 +533,16 @@ class BaseTestCase(DietTestCase): t.start() q.join() + threads_exceptions = [] for t in threads: e = t.get_exception() if e: - raise e + if raise_on_exception: + raise e + else: + threads_exceptions.append(e) + + return threads_exceptions class PluginFixture(fixtures.Fixture): diff --git a/neutron/tests/fullstack/test_l3_agent.py b/neutron/tests/fullstack/test_l3_agent.py index 84603266dc5..1a39efa844b 100644 --- a/neutron/tests/fullstack/test_l3_agent.py +++ b/neutron/tests/fullstack/test_l3_agent.py @@ -270,25 +270,37 @@ class TestL3Agent(base.BaseFullStackTestCase): def _test_concurrent_router_subnet_attachment_overlapping_cidr(self, ha=False): tenant_id = uuidutils.generate_uuid() - subnet_cidr = '10.100.0.0/24' - network1 = self.safe_client.create_network( - tenant_id, name='foo-network1') - subnet1 = self.safe_client.create_subnet( - tenant_id, network1['id'], subnet_cidr) - network2 = self.safe_client.create_network( - tenant_id, name='foo-network2') - subnet2 = self.safe_client.create_subnet( - tenant_id, network2['id'], subnet_cidr) + subnet_cidr = '10.200.0.0/24' + # to have many port interactions where race conditions would happen + # deleting ports meanwhile find operations to evaluate the overlapping + subnets = 10 + + funcs = [] + args = [] router = self.safe_client.create_router(tenant_id, ha=ha) - funcs = [self.safe_client.add_router_interface, - self.safe_client.add_router_interface] - args = [(router['id'], subnet1['id']), (router['id'], subnet2['id'])] - self.assertRaises( - exceptions.BadRequest, - self._simulate_concurrent_requests_process_and_raise, - funcs, - args) + for i in range(subnets): + network_tmp = self.safe_client.create_network( + tenant_id, name='foo-network' + str(i)) + subnet_tmp = self.safe_client.create_subnet( + tenant_id, network_tmp['id'], subnet_cidr) + funcs.append(self.safe_client.add_router_interface) + args.append((router['id'], subnet_tmp['id'])) + + exception_requests = self._simulate_concurrent_requests_process( + funcs, args) + + if not all(type(e) == exceptions.BadRequest + for e in exception_requests): + self.fail('Unexpected exception adding interfaces to router from ' + 'different subnets overlapping') + + if not len(exception_requests) >= (subnets - 1): + self.fail('If we have tried to associate %s subnets overlapping ' + 'cidr to the router, we should have received at least ' + '%s or %s rejected requests, but we have only received ' + '%s', (str(subnets), str(subnets - 1), str(subnets), + str(len(exception_requests)))) class TestLegacyL3Agent(TestL3Agent): @@ -441,7 +453,7 @@ class TestLegacyL3Agent(TestL3Agent): def test_router_fip_qos_after_admin_state_down_up(self): self._router_fip_qos_after_admin_state_down_up() - def test_concurrent_router_subnet_attachment_overlapping_cidr_(self): + def test_concurrent_router_subnet_attachment_overlapping_cidr(self): self._test_concurrent_router_subnet_attachment_overlapping_cidr() @@ -601,6 +613,6 @@ class TestHAL3Agent(TestL3Agent): def test_router_fip_qos_after_admin_state_down_up(self): self._router_fip_qos_after_admin_state_down_up(ha=True) - def test_concurrent_router_subnet_attachment_overlapping_cidr_(self): + def test_concurrent_router_subnet_attachment_overlapping_cidr(self): self._test_concurrent_router_subnet_attachment_overlapping_cidr( ha=True)