Merge "Fix race between create subnet and port requests"

This commit is contained in:
Jenkins 2017-06-21 03:36:31 +00:00 committed by Gerrit Code Review
commit 05c22d6199
2 changed files with 28 additions and 9 deletions

View File

@ -476,12 +476,12 @@ class IpamPluggableBackend(ipam_backend_mixin.IpamBackendMixin):
LOG.debug("Requesting with IP request: %s port: %s ip: %s "
"for subnet %s and ipam_subnet %s", ip_request,
port, ip, subnet, ipam_subnet)
ip_address = ipam_subnet.allocate(ip_request)
allocated = models_v2.IPAllocation(network_id=network_id,
port_id=port['id'],
ip_address=ip_address,
subnet_id=subnet['id'])
try:
ip_address = ipam_subnet.allocate(ip_request)
allocated = models_v2.IPAllocation(network_id=network_id,
port_id=port['id'],
ip_address=ip_address,
subnet_id=subnet['id'])
# Do the insertion of each IP allocation entry within
# the context of a nested transaction, so that the entry
# is rolled back independently of other entries whenever
@ -499,6 +499,10 @@ class IpamPluggableBackend(ipam_backend_mixin.IpamBackendMixin):
except Exception:
LOG.debug("Reverting IP allocation failed for %s",
ip_address)
except ipam_exc.IpAddressAlreadyAllocated:
LOG.debug("Port %s got IPv6 auto-address in a concurrent "
"create or update port request. Ignoring.",
port['id'])
return updated_ports
def allocate_subnet(self, context, network, subnet, subnetpool_id):

View File

@ -56,6 +56,7 @@ from neutron.db.models import securitygroup as sg_models
from neutron.db import models_v2
from neutron.db import rbac_db_models
from neutron.db import standard_attr
from neutron.ipam.drivers.neutrondb_ipam import driver as ipam_driver
from neutron.ipam import exceptions as ipam_exc
from neutron.tests import base
from neutron.tests import tools
@ -4342,7 +4343,8 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
def _test_create_subnet_ipv6_auto_addr_with_port_on_network(
self, addr_mode, device_owner=DEVICE_OWNER_COMPUTE,
insert_db_reference_error=False, insert_port_not_found=False):
insert_db_reference_error=False, insert_port_not_found=False,
insert_address_allocated=False):
# Create a network with one IPv4 subnet and one port
with self.network() as network,\
self.subnet(network=network) as v4_subnet,\
@ -4373,15 +4375,20 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
if insert_port_not_found:
mock_updated_port.side_effect = lib_exc.PortNotFound(
port_id=port['port']['id'])
if insert_address_allocated:
mock.patch.object(
ipam_driver.NeutronDbSubnet, '_verify_ip',
side_effect=ipam_exc.IpAddressAlreadyAllocated(
subnet_id=mock.ANY, ip=mock.ANY)).start()
v6_subnet = self._make_subnet(self.fmt, network, 'fe80::1',
'fe80::/64', ip_version=6,
ipv6_ra_mode=addr_mode,
ipv6_address_mode=addr_mode)
if (insert_db_reference_error
if (insert_db_reference_error or insert_address_allocated
or device_owner == constants.DEVICE_OWNER_ROUTER_SNAT
or device_owner in constants.ROUTER_INTERFACE_OWNERS):
# DVR SNAT and router interfaces should not have been
# updated with addresses from the new auto-address subnet
# DVR SNAT, router interfaces and DHCP ports should not have
# been updated with addresses from the new auto-address subnet
self.assertEqual(1, len(port['port']['fixed_ips']))
else:
# Confirm that the port has been updated with an address
@ -4411,6 +4418,14 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
constants.IPV6_SLAAC,
device_owner=constants.DEVICE_OWNER_DHCP)
def test_create_subnet_dhcpv6_stateless_with_ip_already_allocated(self):
self._test_create_subnet_ipv6_auto_addr_with_port_on_network(
constants.DHCPV6_STATELESS, insert_address_allocated=True)
def test_create_subnet_ipv6_slaac_with_ip_already_allocated(self):
self._test_create_subnet_ipv6_auto_addr_with_port_on_network(
constants.IPV6_SLAAC, insert_address_allocated=True)
def test_create_subnet_ipv6_slaac_with_router_intf_on_network(self):
self._test_create_subnet_ipv6_auto_addr_with_port_on_network(
constants.IPV6_SLAAC,