]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Catch ObjectDeletedError and skip port or subnet removal
authorEugene Nikanorov <enikanorov@mirantis.com>
Sat, 9 May 2015 18:56:44 +0000 (22:56 +0400)
committerEugene Nikanorov <enikanorov@mirantis.com>
Mon, 11 May 2015 00:30:11 +0000 (04:30 +0400)
When network is deleted service ports are deleted in the scope of
delete_network. Service ports could also be deleted by other entities
such as DHCP agent releasing dhcp port.
That could rarely lead to a race condition when port object used in
_delete_ports helper is already deleted causing ObjectDeletedError
exception.
Need to handle it and prevent object deletion in that case.

Change-Id: I531251d3211545c82a5bb7a471b7915da9b763b7
Closes-Bug: #1454408

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

index 2f209db7723a58d27d69a9d8ce9882c69e05a5aa..b796d853eff1223c74e3d64d8891fe8c3d277143 100644 (file)
@@ -685,7 +685,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
         for port in ports:
             try:
                 self.delete_port(context, port.id)
-            except exc.PortNotFound:
+            except (exc.PortNotFound, sa_exc.ObjectDeletedError):
+                context.session.expunge(port)
                 # 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)
@@ -698,7 +699,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
         for subnet in subnets:
             try:
                 self.delete_subnet(context, subnet.id)
-            except exc.SubnetNotFound:
+            except (exc.SubnetNotFound, sa_exc.ObjectDeletedError):
+                context.session.expunge(subnet)
                 LOG.info(_LI("Subnet %s was deleted concurrently"),
                          subnet.id)
             except Exception:
index 21b90976a321b0639067c050d85924754c30fd30..af8c44042fc1c9bfc8c4d3922fc211fb0e4bec31 100644 (file)
@@ -23,6 +23,7 @@ import webob
 
 import fixtures
 from oslo_db import exception as db_exc
+from sqlalchemy.orm import exc as sqla_exc
 
 from neutron.callbacks import registry
 from neutron.common import constants
@@ -186,13 +187,19 @@ class TestMl2NetworksV2(test_plugin.TestNetworksV2,
         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()])
+            plugin._delete_ports(mock.MagicMock(), [mock.MagicMock()])
+        with mock.patch.object(plugin, "delete_port",
+                               side_effect=sqla_exc.ObjectDeletedError(None)):
+            plugin._delete_ports(mock.MagicMock(), [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()])
+            plugin._delete_subnets(mock.MagicMock(), [mock.MagicMock()])
+        with mock.patch.object(plugin, "delete_subnet",
+                               side_effect=sqla_exc.ObjectDeletedError(None)):
+            plugin._delete_subnets(mock.MagicMock(), [mock.MagicMock()])
 
     def _create_and_verify_networks(self, networks):
         for net_idx, net in enumerate(networks):