From a397792ff7ac03f4f021e8d7df62d04d6641aa14 Mon Sep 17 00:00:00 2001 From: Kevin Benton Date: Tue, 13 Sep 2016 20:23:42 -0700 Subject: [PATCH] Catch DBReferenceError in IPAM and convert to SubnetNotFound If a subnet is removed after lookup but before IP allocation insert, we can end up getting a DBReferenceError in the IPAM system. Since this can occur on any flush we force a flush with a session context manager to get the DBReference error in a desired spot (in multi-writer galera this is a deadlock much later, which we retry). We then convert it to SubnetNotFound, which is an expected exception. Closes-Bug: #1623402 Change-Id: I65632b174f8692cd465c721e285526827842a740 --- neutron/ipam/drivers/neutrondb_ipam/driver.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/neutron/ipam/drivers/neutrondb_ipam/driver.py b/neutron/ipam/drivers/neutrondb_ipam/driver.py index fdbfd1dd4b3..5cdd50b8937 100644 --- a/neutron/ipam/drivers/neutrondb_ipam/driver.py +++ b/neutron/ipam/drivers/neutrondb_ipam/driver.py @@ -18,6 +18,7 @@ import random import netaddr from neutron_lib import exceptions as n_exc +from oslo_db import exception as db_exc from oslo_log import log from oslo_utils import uuidutils @@ -203,7 +204,16 @@ class NeutronDbSubnet(ipam_base.Subnet): # Create IP allocation request object # The only defined status at this stage is 'ALLOCATED'. # More states will be available in the future - e.g.: RECYCLABLE - self.subnet_manager.create_allocation(session, ip_address) + try: + with session.begin(subtransactions=True): + # NOTE(kevinbenton): we use a subtransaction to force + # a flush here so we can capture DBReferenceErrors due + # to concurrent subnet deletions. (galera would deadlock + # later on final commit) + self.subnet_manager.create_allocation(session, ip_address) + except db_exc.DBReferenceError: + raise n_exc.SubnetNotFound( + subnet_id=self.subnet_manager.neutron_id) return ip_address def deallocate(self, address):