]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Don't fail when trying to unbind a router
authorEd Bak <ed.bak2@hp.com>
Mon, 29 Sep 2014 20:15:52 +0000 (14:15 -0600)
committerCarl Baldwin <carl.baldwin@hp.com>
Tue, 7 Oct 2014 14:19:16 +0000 (14:19 +0000)
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

neutron/plugins/ml2/plugin.py
neutron/tests/unit/ml2/test_ml2_plugin.py

index 422cbff86ed9f34620f5fa2cfdc636db474cf3cb..d744f19fe1f32a9b8a14b5cee7d7ff95622a37ec 100644 (file)
@@ -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
index 5cb6df44bcff35ae25e6cea675773597785698a9..0d43145d2c976e49041488fe3fb63a1e406e389b 100644 (file)
@@ -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)