]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Fix auto-deletion of ports and subnets in ML2
authorBob Kukura <rkukura@redhat.com>
Fri, 27 Sep 2013 21:54:45 +0000 (17:54 -0400)
committerBob Kukura <rkukura@redhat.com>
Fri, 27 Sep 2013 22:49:07 +0000 (18:49 -0400)
When a network is deleted, certain ports and any subnets referencing
it are auto-deleted. The implementation of
NeutronDBPluginV2.delete_network() does this at the DB level, so ML2's
mechanism drivers were not being called.

Ml2Plugin.delete_network() is changed to not use the base class's
method, and to auto-delete ports and subnets by calling its own
delete_port() and delete_subnet() methods outside of the
transaction. A loop avoids race conditions with ports or subnets being
asynchronously added to the network.

Closes-Bug: 1230330
Change-Id: Icf21400c9938eec29d70da8497b9ef92642131e2

neutron/plugins/ml2/plugin.py

index fbdfb38ca8806ccbd9d95ec98d292af342fc0f5b..3c8a7d5f28e453e7173ed211175cc2e7a094c4b4 100644 (file)
@@ -368,17 +368,53 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
         return [self._fields(net, fields) for net in nets]
 
     def delete_network(self, context, id):
+        # REVISIT(rkukura) The super(Ml2Plugin, self).delete_network()
+        # function is not used because it auto-deletes ports and
+        # subnets from the DB without invoking the derived class's
+        # delete_port() or delete_subnet(), preventing mechanism
+        # drivers from being called. This approach should be revisited
+        # when the API layer is reworked during icehouse.
+
         session = context.session
-        with session.begin(subtransactions=True):
-            network = self.get_network(context, id)
-            mech_context = driver_context.NetworkContext(self, context,
-                                                         network)
-            self.mechanism_manager.delete_network_precommit(mech_context)
-            super(Ml2Plugin, self).delete_network(context, id)
-            for segment in mech_context.network_segments:
-                self.type_manager.release_segment(session, segment)
-            # The segment records are deleted via cascade from the
-            # network record, so explicit removal is not necessary.
+        while True:
+            with session.begin(subtransactions=True):
+                filter = {'network_id': [id]}
+
+                # Get ports to auto-delete.
+                ports = self.get_ports(context, filters=filter)
+                only_auto_del = all(p['device_owner']
+                                    in db_base_plugin_v2.
+                                    AUTO_DELETE_PORT_OWNERS
+                                    for p in ports)
+                if not only_auto_del:
+                    raise exc.NetworkInUse(net_id=id)
+
+                # Get subnets to auto-delete.
+                subnets = self.get_subnets(context, filters=filter)
+
+                if not ports or subnets:
+                    network = self.get_network(context, id)
+                    mech_context = driver_context.NetworkContext(self,
+                                                                 context,
+                                                                 network)
+                    self.mechanism_manager.delete_network_precommit(
+                        mech_context)
+
+                    record = self._get_network(context, id)
+                    context.session.delete(record)
+
+                    for segment in mech_context.network_segments:
+                        self.type_manager.release_segment(session, segment)
+
+                    # The segment records are deleted via cascade from the
+                    # network record, so explicit removal is not necessary.
+                    break
+
+            for port in ports:
+                self.delete_port(context, port['id'])
+
+            for subnet in subnets:
+                self.delete_subnet(context, subnet['id'])
 
         try:
             self.mechanism_manager.delete_network_postcommit(mech_context)