From: Ed Bak Date: Mon, 29 Sep 2014 20:15:52 +0000 (-0600) Subject: Don't fail when trying to unbind a router X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=75f34fbbd930a143ed2c4b868f33c117e467e98e;p=openstack-build%2Fneutron-build.git Don't fail when trying to unbind a router If a router is already unbound from an l3 agent, don't fail. Log the condition and go on. This is harmless since it can happen due to a delete race condition between multiple neutron-server processes. One delete request can determine that it needs to unbind the router. A second process may also determine that it needs to unbind the router. The exception thrown will result in a port delete failure and cause nova to mark a deleted instance as ERROR. Change-Id: Ia667ea77a0a483deff8acfdcf90ca84cd3adf44f Closes-Bug: 1367892 --- diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py index 422cbff86..d744f19fe 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -45,6 +45,7 @@ from neutron.db import quota_db # noqa from neutron.db import securitygroups_rpc_base as sg_db_rpc from neutron.extensions import allowedaddresspairs as addr_pair from neutron.extensions import extra_dhcp_opt as edo_ext +from neutron.extensions import l3agentscheduler from neutron.extensions import portbindings from neutron.extensions import providernet as provider from neutron import manager @@ -1019,9 +1020,14 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, if l3plugin: l3plugin.notify_routers_updated(context, router_ids) for router in removed_routers: - l3plugin.remove_router_from_l3_agent( - context, router['agent_id'], router['router_id']) - + try: + l3plugin.remove_router_from_l3_agent( + context, router['agent_id'], router['router_id']) + except l3agentscheduler.RouterNotHostedByL3Agent: + # router may have been removed by another process + LOG.debug("Router %(id)s not hosted by L3 agent %(agent)s", + {'id': router['router_id'], + 'agent': router['agent_id']}) try: # for both normal and DVR Interface ports, only one invocation of # delete_port_postcommit. We use gather/scatter technique for DVR diff --git a/neutron/tests/unit/ml2/test_ml2_plugin.py b/neutron/tests/unit/ml2/test_ml2_plugin.py index 5cb6df44b..0d43145d2 100644 --- a/neutron/tests/unit/ml2/test_ml2_plugin.py +++ b/neutron/tests/unit/ml2/test_ml2_plugin.py @@ -25,6 +25,7 @@ from neutron.common import utils from neutron import context from neutron.db import db_base_plugin_v2 as base_plugin from neutron.extensions import external_net as external_net +from neutron.extensions import l3agentscheduler from neutron.extensions import multiprovidernet as mpnet from neutron.extensions import portbindings from neutron.extensions import providernet as pnet @@ -267,6 +268,30 @@ class TestMl2DvrPortsV2(TestMl2PortsV2): self._test_delete_dvr_serviced_port(device_owner='compute:None', floating_ip=True) + def test_delete_vm_port_namespace_already_deleted(self): + ns_to_delete = {'host': 'myhost', + 'agent_id': 'vm_l3_agent', + 'router_id': 'my_router'} + + with contextlib.nested( + mock.patch.object(manager.NeutronManager, + 'get_service_plugins', + return_value=self.service_plugins), + self.port(do_delete=False, + device_owner='compute:None'), + mock.patch.object(self.l3plugin, 'dvr_deletens_if_no_port', + return_value=[ns_to_delete]), + mock.patch.object(self.l3plugin, 'remove_router_from_l3_agent', + side_effect=l3agentscheduler.RouterNotHostedByL3Agent( + router_id=ns_to_delete['router_id'], + agent_id=ns_to_delete['agent_id'])) + ) as (get_service_plugin, port, dvr_delns_ifno_port, + remove_router_from_l3_agent): + + self.plugin.delete_port(self.context, port['port']['id']) + remove_router_from_l3_agent.assert_called_once_with(self.context, + ns_to_delete['agent_id'], ns_to_delete['router_id']) + def test_delete_lbaas_vip_port(self): self._test_delete_dvr_serviced_port( device_owner=constants.DEVICE_OWNER_LOADBALANCER)