Catch DB reference errors in binding DVR ports

A port can be deleted right after get_port is called but before
the binding is created. So we need to catch both PortNotFound
from the get_port and DBReferenceError from the binding creation.

Co-Authored-By: Adolfo Duarte <adolfo.duarte@hpe.com>

Closes-Bug: #1501515
Change-Id: Ieddcb10bb019fe6dd7079255124e48305f406614
(cherry picked from commit 06569179ae)
This commit is contained in:
Kevin Benton 2016-03-08 12:28:41 -08:00 committed by Ihar Hrachyshka
parent e9622b0bb0
commit 362896a7cf
2 changed files with 29 additions and 15 deletions

View File

@ -1282,21 +1282,23 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
binding.vif_type == portbindings.VIF_TYPE_BINDING_FAILED or
router_id != device_id)
if update_required:
with session.begin(subtransactions=True):
try:
orig_port = super(Ml2Plugin, self).get_port(context, id)
except exc.PortNotFound:
LOG.debug("DVR Port %s has been deleted concurrently", id)
return
if not binding:
binding = db.ensure_dvr_port_binding(
session, id, host, router_id=device_id)
network = self.get_network(context, orig_port['network_id'])
levels = db.get_binding_levels(session, id, host)
mech_context = driver_context.PortContext(self,
context, orig_port, network,
binding, levels, original_port=orig_port)
self._process_dvr_port_binding(mech_context, context, attrs)
try:
with session.begin(subtransactions=True):
orig_port = self.get_port(context, id)
if not binding:
binding = db.ensure_dvr_port_binding(
session, id, host, router_id=device_id)
network = self.get_network(context,
orig_port['network_id'])
levels = db.get_binding_levels(session, id, host)
mech_context = driver_context.PortContext(self,
context, orig_port, network,
binding, levels, original_port=orig_port)
self._process_dvr_port_binding(mech_context, context,
attrs)
except (os_db_exception.DBReferenceError, exc.PortNotFound):
LOG.debug("DVR Port %s has been deleted concurrently", id)
return
self._bind_port_if_needed(mech_context)
def _pre_delete_port(self, context, port_id, port_check):

View File

@ -1171,6 +1171,18 @@ class TestMl2PortBinding(Ml2PluginV2TestCase,
mech_context._binding.router_id)
self.assertEqual(host_id, mech_context._binding.host)
def test_update_dvr_port_binding_on_concurrent_port_delete(self):
plugin = manager.NeutronManager.get_plugin()
with self.port() as port:
port = {
'id': port['port']['id'],
portbindings.HOST_ID: 'foo_host',
}
with mock.patch.object(plugin, 'get_port', new=plugin.delete_port):
res = plugin.update_dvr_port_binding(
self.context, 'foo_port_id', {'port': port})
self.assertIsNone(res)
def test_update_dvr_port_binding_on_non_existent_port(self):
plugin = manager.NeutronManager.get_plugin()
port = {