Fix auto-deletion of ports and subnets in ML2

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
This commit is contained in:
Bob Kukura 2013-09-27 17:54:45 -04:00
parent 86feb8e4a8
commit f69b25e73c

View 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
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,
mech_context = driver_context.NetworkContext(self,
context,
network)
self.mechanism_manager.delete_network_precommit(mech_context)
super(Ml2Plugin, self).delete_network(context, id)
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)