From 817b45b6406d9730859535ac54d73ec5c85451d0 Mon Sep 17 00:00:00 2001 From: Kevin Benton Date: Wed, 27 May 2015 17:38:32 -0700 Subject: [PATCH] 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 --- neutron/db/db_base_plugin_v2.py | 5 +++++ neutron/tests/unit/db/test_db_base_plugin_v2.py | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/neutron/db/db_base_plugin_v2.py b/neutron/db/db_base_plugin_v2.py index dab525befb0..29ffa85b4f2 100644 --- a/neutron/db/db_base_plugin_v2.py +++ b/neutron/db/db_base_plugin_v2.py @@ -459,6 +459,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 7af0122d06a..f34beb85a30 100644 --- a/neutron/tests/unit/db/test_db_base_plugin_v2.py +++ b/neutron/tests/unit/db/test_db_base_plugin_v2.py @@ -903,6 +903,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: