From 2affc39d3ad2d30c54e3373249446f61ee59f881 Mon Sep 17 00:00:00 2001 From: armando-migliaccio Date: Mon, 11 Aug 2014 22:43:31 -0700 Subject: [PATCH] Fix PortNotFound exception during sync_routers This trace is observed when an L3 agent invokes sync_routers right about the same time a port interface is removed from a router. Related-bug: #1355409 Change-Id: I825b25080cbf054462318fc01248692b9e0e4ecb --- neutron/db/l3_rpc_base.py | 10 ++++++-- neutron/tests/unit/test_l3_plugin.py | 36 ++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/neutron/db/l3_rpc_base.py b/neutron/db/l3_rpc_base.py index e238e7be9..2886f886d 100644 --- a/neutron/db/l3_rpc_base.py +++ b/neutron/db/l3_rpc_base.py @@ -16,6 +16,7 @@ from oslo.config import cfg from neutron.common import constants +from neutron.common import exceptions from neutron.common import utils from neutron import context as neutron_context from neutron.extensions import l3 @@ -106,8 +107,13 @@ class L3RpcCallbackMixin(object): portbindings.VIF_TYPE_BINDING_FAILED)): # All ports, including ports created for SNAT'ing for # DVR are handled here - self.plugin.update_port(context, port['id'], - {'port': {portbindings.HOST_ID: host}}) + try: + self.plugin.update_port(context, port['id'], + {'port': {portbindings.HOST_ID: host}}) + except exceptions.PortNotFound: + LOG.debug("Port %(port)s not found while updating " + "agent binding for router %(router)s." + % {"port": port['id'], "router": router_id}) elif (port and port.get('device_owner') == constants.DEVICE_OWNER_DVR_INTERFACE): diff --git a/neutron/tests/unit/test_l3_plugin.py b/neutron/tests/unit/test_l3_plugin.py index 7dc665674..50f7ba7dc 100644 --- a/neutron/tests/unit/test_l3_plugin.py +++ b/neutron/tests/unit/test_l3_plugin.py @@ -38,6 +38,7 @@ from neutron.db import l3_rpc_base from neutron.db import model_base from neutron.extensions import external_net from neutron.extensions import l3 +from neutron.extensions import portbindings from neutron import manager from neutron.openstack.common import importutils from neutron.openstack.common import log as logging @@ -2048,6 +2049,41 @@ class L3NatDBIntAgentSchedulingTestCase(L3BaseForIntTests, expected_code=exc.HTTPBadRequest.code) +class L3RpcCallbackMixinTestCase(base.BaseTestCase): + + def setUp(self): + super(L3RpcCallbackMixinTestCase, self).setUp() + self.mock_plugin = mock.patch.object( + l3_rpc_base.L3RpcCallbackMixin, + 'plugin', new_callable=mock.PropertyMock).start() + self.mock_l3plugin = mock.patch.object( + l3_rpc_base.L3RpcCallbackMixin, + 'l3plugin', new_callable=mock.PropertyMock).start() + self.mixin = l3_rpc_base.L3RpcCallbackMixin() + + def test__ensure_host_set_on_port_update_on_concurrent_delete(self): + port_id = 'foo_port_id' + port = { + 'id': port_id, + 'device_owner': 'compute:None', + portbindings.HOST_ID: '', + portbindings.VIF_TYPE: portbindings.VIF_TYPE_BINDING_FAILED + } + router_id = 'foo_router_id' + self.mixin.plugin.update_port.side_effect = n_exc.PortNotFound( + port_id=port_id) + with mock.patch.object(l3_rpc_base.LOG, 'debug') as mock_log: + self.mixin._ensure_host_set_on_port( + mock.ANY, mock.ANY, port, router_id) + self.mixin.plugin.update_port.assert_called_once_with( + mock.ANY, port_id, {'port': {'binding:host_id': mock.ANY}}) + self.assertTrue(mock_log.call_count) + expected_message = ('Port foo_port_id not found while updating ' + 'agent binding for router foo_router_id.') + actual_message = mock_log.call_args[0][0] + self.assertEqual(expected_message, actual_message) + + class L3AgentDbIntTestCase(L3BaseForIntTests, L3AgentDbTestCaseBase): """Unit tests for methods called by the L3 agent for -- 2.45.2