From 8479921e111e1c306db76c52b33115cc5a77c420 Mon Sep 17 00:00:00 2001 From: Eugene Nikanorov Date: Tue, 23 Dec 2014 20:28:12 +0300 Subject: [PATCH] Catch PortNotFound and SubnetNotFound during network_delete In some cases PortNotFound exception during network_delete could be caused by concurrent port deletion by DHCP agent. This condition should not prevent network from deleting. Change-Id: Ie6eae4cecb64120c41de9823d9e72066094ad2ce Closes-Bug: #1405197 --- neutron/plugins/ml2/plugin.py | 43 ++++++++++++++--------- neutron/tests/unit/ml2/test_ml2_plugin.py | 12 ++++++- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py index 18b044ea4..a5c9d68b6 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -564,6 +564,31 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, return [self._fields(net, fields) for net in nets] + def _delete_ports(self, context, ports): + for port in ports: + try: + self.delete_port(context, port.id) + except exc.PortNotFound: + # concurrent port deletion can be performed by + # release_dhcp_port caused by concurrent subnet_delete + LOG.info(_LI("Port %s was deleted concurrently"), port.id) + except Exception: + with excutils.save_and_reraise_exception(): + LOG.exception(_LE("Exception auto-deleting port %s"), + port.id) + + def _delete_subnets(self, context, subnets): + for subnet in subnets: + try: + self.delete_subnet(context, subnet.id) + except exc.SubnetNotFound: + LOG.info(_LI("Subnet %s was deleted concurrently"), + subnet.id) + except Exception: + with excutils.save_and_reraise_exception(): + LOG.exception(_LE("Exception auto-deleting subnet %s"), + subnet.id) + def delete_network(self, context, id): # REVISIT(rkukura) The super(Ml2Plugin, self).delete_network() # function is not used because it auto-deletes ports and @@ -634,22 +659,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, LOG.warning(_LW("A concurrent port creation has " "occurred")) continue - - for port in ports: - try: - self.delete_port(context, port.id) - except Exception: - with excutils.save_and_reraise_exception(): - LOG.exception(_LE("Exception auto-deleting port %s"), - port.id) - - for subnet in subnets: - try: - self.delete_subnet(context, subnet.id) - except Exception: - with excutils.save_and_reraise_exception(): - LOG.exception(_LE("Exception auto-deleting subnet %s"), - subnet.id) + self._delete_ports(context, ports) + self._delete_subnets(context, subnets) try: self.mechanism_manager.delete_network_postcommit(mech_context) diff --git a/neutron/tests/unit/ml2/test_ml2_plugin.py b/neutron/tests/unit/ml2/test_ml2_plugin.py index 4bf311598..d457cff5f 100644 --- a/neutron/tests/unit/ml2/test_ml2_plugin.py +++ b/neutron/tests/unit/ml2/test_ml2_plugin.py @@ -118,7 +118,17 @@ class TestMl2V2HTTPResponse(test_plugin.TestV2HTTPResponse, class TestMl2NetworksV2(test_plugin.TestNetworksV2, Ml2PluginV2TestCase): - pass + def test_port_delete_helper_tolerates_failure(self): + plugin = manager.NeutronManager.get_plugin() + with mock.patch.object(plugin, "delete_port", + side_effect=exc.PortNotFound(port_id="123")): + plugin._delete_ports(None, [mock.MagicMock()]) + + def test_subnet_delete_helper_tolerates_failure(self): + plugin = manager.NeutronManager.get_plugin() + with mock.patch.object(plugin, "delete_subnet", + side_effect=exc.SubnetNotFound(subnet_id="1")): + plugin._delete_subnets(None, [mock.MagicMock()]) class TestMl2SubnetsV2(test_plugin.TestSubnetsV2, -- 2.45.2