From: Kevin Benton Date: Thu, 28 May 2015 00:38:32 +0000 (-0700) Subject: Process port IP requests before subnet requests X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=717cf4599baeb42e89663b0167192d89b1df892c;p=openstack-build%2Fneutron-build.git Process port IP requests before subnet requests When a port requests multiple fixed IPs, process the requests for specific IP addresses before the ones asking for a subnet. This prevents an error where the IP that was requested happens to be the next up for allocation so the subnet request takes it and causes a DBDuplicateEntry. Closes-Bug: #1459467 Change-Id: I645565c7fe0c47c58d686b25020bb49a0b9089f5 (cherry picked from commit 817b45b6406d9730859535ac54d73ec5c85451d0) --- diff --git a/neutron/db/db_base_plugin_v2.py b/neutron/db/db_base_plugin_v2.py index 24c251340..e75dd4cbb 100644 --- a/neutron/db/db_base_plugin_v2.py +++ b/neutron/db/db_base_plugin_v2.py @@ -458,6 +458,11 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2, def _allocate_fixed_ips(self, context, fixed_ips, mac_address): """Allocate IP addresses according to the configured fixed_ips.""" ips = [] + + # we need to start with entries that asked for a specific IP in case + # those IPs happen to be next in the line for allocation for ones that + # didn't ask for a specific IP + fixed_ips.sort(key=lambda x: 'ip_address' not in x) for fixed in fixed_ips: subnet = self._get_subnet(context, fixed['subnet_id']) is_auto_addr = ipv6_utils.is_auto_address_subnet(subnet) diff --git a/neutron/tests/unit/db/test_db_base_plugin_v2.py b/neutron/tests/unit/db/test_db_base_plugin_v2.py index 0804e9047..ec97c9aed 100644 --- a/neutron/tests/unit/db/test_db_base_plugin_v2.py +++ b/neutron/tests/unit/db/test_db_base_plugin_v2.py @@ -909,6 +909,16 @@ class TestPortsV2(NeutronDbPluginV2TestCase): self.assertIn('mac_address', port['port']) self._delete('ports', port['port']['id']) + def test_create_port_anticipating_allocation(self): + with self.network(shared=True) as network: + with self.subnet(network=network, cidr='10.0.0.0/24') as subnet: + fixed_ips = [{'subnet_id': subnet['subnet']['id']}, + {'subnet_id': subnet['subnet']['id'], + 'ip_address': '10.0.0.2'}] + self._create_port(self.fmt, network['network']['id'], + webob.exc.HTTPCreated.code, + fixed_ips=fixed_ips) + def test_create_port_public_network_with_invalid_ip_no_subnet_id(self, expected_error='InvalidIpForNetwork'): with self.network(shared=True) as network: