From a3285ac71acb83880c3e055728acff0c5e339062 Mon Sep 17 00:00:00 2001 From: John Davidge Date: Fri, 7 Aug 2015 16:27:47 +0100 Subject: [PATCH] Fix update_subnet for prefix delegation A misnamed function call and execution order issue was causing update_subnet to fail when a PD enabled subnet received a new CIDR. This patch fixes the issues, and introduces an rpc api test to ensure the function works. This includes altering the process_prefix_update RPC handler to expose the issue to the test. Change-Id: Id1e781291f711865fd783ed5e0208694097b7024 Closes-Bug: 1482676 --- neutron/api/rpc/handlers/l3_rpc.py | 8 ++- neutron/db/db_base_plugin_v2.py | 19 +++--- .../unit/api/rpc/handlers/test_l3_rpc.py | 65 +++++++++++++++++++ 3 files changed, 80 insertions(+), 12 deletions(-) create mode 100644 neutron/tests/unit/api/rpc/handlers/test_l3_rpc.py diff --git a/neutron/api/rpc/handlers/l3_rpc.py b/neutron/api/rpc/handlers/l3_rpc.py index 176ddb22974..b1129cc74a6 100644 --- a/neutron/api/rpc/handlers/l3_rpc.py +++ b/neutron/api/rpc/handlers/l3_rpc.py @@ -269,6 +269,10 @@ class L3RpcCallback(object): def process_prefix_update(self, context, **kwargs): subnets = kwargs.get('subnets') + updated_subnets = [] for subnet_id, prefix in subnets.items(): - self.plugin.update_subnet(context, subnet_id, - {'subnet': {'cidr': prefix}}) + updated_subnets.append(self.plugin.update_subnet( + context, + subnet_id, + {'subnet': {'cidr': prefix}})) + return updated_subnets diff --git a/neutron/db/db_base_plugin_v2.py b/neutron/db/db_base_plugin_v2.py index 29ecf806525..11379b04788 100644 --- a/neutron/db/db_base_plugin_v2.py +++ b/neutron/db/db_base_plugin_v2.py @@ -590,9 +590,8 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, def _update_allocation_pools(self, subnet): """Gets new allocation pools and formats them correctly""" - allocation_pools = self.ipam.generate_allocation_pools( - subnet['cidr'], - subnet['gateway_ip']) + allocation_pools = self.ipam.generate_pools(subnet['cidr'], + subnet['gateway_ip']) return [{'start': str(netaddr.IPAddress(p.first, subnet['ip_version'])), 'end': str(netaddr.IPAddress(p.last, subnet['ip_version']))} @@ -619,13 +618,6 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, db_pools = [netaddr.IPRange(p['first_ip'], p['last_ip']) for p in db_subnet.allocation_pools] - range_pools = None - if s.get('allocation_pools') is not None: - # Convert allocation pools to IPRange to simplify future checks - range_pools = self.ipam.pools_to_ip_range(s['allocation_pools']) - self.ipam.validate_allocation_pools(range_pools, s['cidr']) - s['allocation_pools'] = range_pools - update_ports_needed = False if new_cidr and ipv6_utils.is_ipv6_pd_enabled(s): # This is an ipv6 prefix delegation-enabled subnet being given an @@ -637,6 +629,13 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, s['gateway_ip'] = utils.get_first_host_ip(net, s['ip_version']) s['allocation_pools'] = self._update_allocation_pools(s) + range_pools = None + if s.get('allocation_pools') is not None: + # Convert allocation pools to IPRange to simplify future checks + range_pools = self.ipam.pools_to_ip_range(s['allocation_pools']) + self.ipam.validate_allocation_pools(range_pools, s['cidr']) + s['allocation_pools'] = range_pools + # If either gateway_ip or allocation_pools were specified gateway_ip = s.get('gateway_ip') if gateway_ip is not None or s.get('allocation_pools') is not None: diff --git a/neutron/tests/unit/api/rpc/handlers/test_l3_rpc.py b/neutron/tests/unit/api/rpc/handlers/test_l3_rpc.py new file mode 100644 index 00000000000..68ec79d141b --- /dev/null +++ b/neutron/tests/unit/api/rpc/handlers/test_l3_rpc.py @@ -0,0 +1,65 @@ +# Copyright (c) 2015 Cisco Systems +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from oslo_config import cfg + +from neutron.api.rpc.handlers import l3_rpc +from neutron.common import constants +from neutron import context +from neutron import manager +from neutron.tests.unit.db import test_db_base_plugin_v2 +from neutron.tests.unit import testlib_api + + +class TestL3RpcCallback(testlib_api.SqlTestCase): + + def setUp(self): + super(TestL3RpcCallback, self).setUp() + self.setup_coreplugin(test_db_base_plugin_v2.DB_PLUGIN_KLASS) + self.plugin = manager.NeutronManager.get_plugin() + self.ctx = context.get_admin_context() + cfg.CONF.set_override('default_ipv6_subnet_pool', + constants.IPV6_PD_POOL_ID) + self.callbacks = l3_rpc.L3RpcCallback() + self.network = self._prepare_network() + + def _prepare_network(self): + network = {'network': {'name': 'abc', + 'shared': False, + 'admin_state_up': True}} + return self.plugin.create_network(self.ctx, network) + + def _prepare_ipv6_pd_subnet(self): + subnet = {'subnet': {'network_id': self.network['id'], + 'cidr': None, + 'ip_version': 6, + 'name': 'ipv6_pd', + 'enable_dhcp': True, + 'host_routes': None, + 'dns_nameservers': None, + 'allocation_pools': None, + 'ipv6_ra_mode': constants.IPV6_SLAAC, + 'ipv6_address_mode': constants.IPV6_SLAAC}} + return self.plugin.create_subnet(self.ctx, subnet) + + def test_process_prefix_update(self): + subnet = self._prepare_ipv6_pd_subnet() + data = {subnet['id']: '2001:db8::/64'} + allocation_pools = [{'start': '2001:db8::2', + 'end': '2001:db8::ffff:ffff:ffff:ffff'}] + res = self.callbacks.process_prefix_update(self.ctx, subnets=data) + updated_subnet = res[0] + self.assertEqual(updated_subnet['cidr'], data[subnet['id']]) + self.assertEqual(updated_subnet['allocation_pools'], allocation_pools)