Handle PortNotFound when deleting a network

Tempest has some tests which fail during network cleanup
because they are racing with the subnet delete which cleans
up the neutron:dhcp owned port, which the network delete code
also tries to delete.

This change handles the PortNotFound for these types of auto-deleted
ports so we don't fail to delete the network when the ports are
already gone.

Change-Id: I54ebf2be14e82f288a9bf177967f1136b72b289e
Closes-Bug: #1691176
This commit is contained in:
Matt Riedemann 2017-05-16 13:35:52 -04:00 committed by Kevin Benton
parent dfcfbc0aac
commit 37b84c4c73
2 changed files with 36 additions and 1 deletions

View File

@ -435,7 +435,12 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
models_v2.Port.id).filter_by(network_id=id).filter(
models_v2.Port.device_owner.in_(AUTO_DELETE_PORT_OWNERS))]
for port_id in auto_delete_port_ids:
self.delete_port(context.elevated(), port_id)
try:
self.delete_port(context.elevated(), port_id)
except exc.PortNotFound:
# Don't raise if something else concurrently deleted the port
LOG.debug("Ignoring PortNotFound when deleting port '%s'. "
"The port has already been deleted.", port_id)
# clean up subnets
subnets = self._get_subnets_by_network(context, id)
with db_api.exc_to_retry(os_db_exc.DBReferenceError):

View File

@ -1581,6 +1581,36 @@ fixed_ips=ip_address%%3D%s&fixed_ips=ip_address%%3D%s&fixed_ips=subnet_id%%3D%s
res = req.get_response(self.api)
self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
def test_delete_network_port_exists_owned_by_network_port_not_found(self):
"""Tests that we continue to gracefully delete the network even if
a neutron:dhcp-owned port was deleted concurrently.
"""
res = self._create_network(fmt=self.fmt, name='net',
admin_state_up=True)
network = self.deserialize(self.fmt, res)
network_id = network['network']['id']
self._create_port(self.fmt, network_id,
device_owner=constants.DEVICE_OWNER_DHCP)
# Raise PortNotFound when trying to delete the port to simulate a
# concurrent delete race; note that we actually have to delete the port
# "out of band" otherwise deleting the network will fail because of
# constraints in the data model.
plugin = directory.get_plugin()
orig_delete = plugin.delete_port
def fake_delete_port(context, id):
# Delete the port for real from the database and then raise
# PortNotFound to simulate the race.
self.assertIsNone(orig_delete(context, id))
raise lib_exc.PortNotFound(port_id=id)
p = mock.patch.object(plugin, 'delete_port')
mock_del_port = p.start()
mock_del_port.side_effect = fake_delete_port
req = self.new_delete_request('networks', network_id)
res = req.get_response(self.api)
self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
def test_update_port_delete_ip(self):
with self.subnet() as subnet:
with self.port(subnet=subnet) as port: