Remove nested transaction from ipam driver

Using nested transaction in reference ipam driver causes rewriting
original exception due failure to restore to safepoint in case of
DeadLock.

DBDeadlock exception gets replaced with DBAPIError. It prevents db_retry
wrapper from working correctly.

This patch removed nested transaction block from reference ipam driver.

Change-Id: Ib710e87b0132aae3cd3afd12c5448961f1a3b25c
Partial-Bug: #1571666
This commit is contained in:
Pavel Bondar 2016-04-18 17:56:08 +03:00
parent acca136721
commit ad2d7d3a8f

View File

@ -21,7 +21,6 @@ from oslo_utils import uuidutils
from neutron._i18n import _, _LE from neutron._i18n import _, _LE
from neutron.common import ipv6_utils from neutron.common import ipv6_utils
from neutron.db import api as db_api
from neutron.ipam import driver as ipam_base from neutron.ipam import driver as ipam_base
from neutron.ipam.drivers.neutrondb_ipam import db_api as ipam_db_api from neutron.ipam.drivers.neutrondb_ipam import db_api as ipam_db_api
from neutron.ipam import exceptions as ipam_exc from neutron.ipam import exceptions as ipam_exc
@ -326,34 +325,31 @@ class NeutronDbSubnet(ipam_base.Subnet):
return ip_address, ip_range['allocation_pool_id'] return ip_address, ip_range['allocation_pool_id']
def allocate(self, address_request): def allocate(self, address_request):
# NOTE(salv-orlando): Creating a new db session might be a rather # NOTE(pbondar): Ipam driver is always called in context of already
# dangerous thing to do, if executed from within another database # running transaction, which is started on create_port or upper level.
# transaction. Therefore the IPAM driver should never be # To be able to do rollback/retry actions correctly ipam driver
# called from within a database transaction, which is also good # should not create new nested transaction blocks.
# practice since in the general case these drivers may interact
# with remote backends
session = self._context.session session = self._context.session
all_pool_id = None all_pool_id = None
auto_generated = False auto_generated = False
with db_api.autonested_transaction(session): # NOTE(salv-orlando): It would probably better to have a simpler
# NOTE(salv-orlando): It would probably better to have a simpler # model for address requests and just check whether there is a
# model for address requests and just check whether there is a # specific IP address specified in address_request
# specific IP address specified in address_request if isinstance(address_request, ipam_req.SpecificAddressRequest):
if isinstance(address_request, ipam_req.SpecificAddressRequest): # This handles both specific and automatic address requests
# This handles both specific and automatic address requests # Check availability of requested IP
# Check availability of requested IP ip_address = str(address_request.address)
ip_address = str(address_request.address) self._verify_ip(session, ip_address)
self._verify_ip(session, ip_address) else:
else: ip_address, all_pool_id = self._generate_ip(session)
ip_address, all_pool_id = self._generate_ip(session) auto_generated = True
auto_generated = True self._allocate_specific_ip(session, ip_address, all_pool_id,
self._allocate_specific_ip(session, ip_address, all_pool_id, auto_generated)
auto_generated) # Create IP allocation request object
# Create IP allocation request object # The only defined status at this stage is 'ALLOCATED'.
# The only defined status at this stage is 'ALLOCATED'. # More states will be available in the future - e.g.: RECYCLABLE
# More states will be available in the future - e.g.: RECYCLABLE self.subnet_manager.create_allocation(session, ip_address)
self.subnet_manager.create_allocation(session, ip_address) return ip_address
return ip_address
def deallocate(self, address): def deallocate(self, address):
# This is almost a no-op because the Neutron DB IPAM driver does not # This is almost a no-op because the Neutron DB IPAM driver does not