From: Andrew Boik Date: Wed, 4 Mar 2015 03:39:57 +0000 (-0500) Subject: Auto-update gateway port after subnet-create X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=df7aa02aa5235b389ed8ad013acf9fccd7e877cd;p=openstack-build%2Fneutron-build.git Auto-update gateway port after subnet-create (Patch set #6 for the multiple-ipv6-prefixes blueprint) In the multi-prefix scenario, one can add two subnets to an external gateway port by adding the two subnets to the external network and using router-gateway-set. However, if there is only one subnet on the port and the user wishes to add another later, it is desirable to have the newly-created external subnet automatically added to the port. This patch adds this functionality. Change-Id: I9395834f673038dc23b25eaeefe14895fe154e0e Partially-implements: blueprint multiple-ipv6-prefixes --- diff --git a/neutron/db/db_base_plugin_v2.py b/neutron/db/db_base_plugin_v2.py index 73d7f45cb..3b3573daf 100644 --- a/neutron/db/db_base_plugin_v2.py +++ b/neutron/db/db_base_plugin_v2.py @@ -122,6 +122,11 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2, route_qry = context.session.query(models_v2.SubnetRoute) return route_qry.filter_by(subnet_id=subnet_id).all() + def _get_router_gw_ports_by_network(self, context, network_id): + port_qry = context.session.query(models_v2.Port) + return port_qry.filter_by(network_id=network_id, + device_owner=constants.DEVICE_OWNER_ROUTER_GW).all() + def _get_subnets_by_network(self, context, network_id): subnet_qry = context.session.query(models_v2.Subnet) return subnet_qry.filter_by(network_id=network_id).all() @@ -1086,6 +1091,23 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2, pool=pool_range, ip_address=gateway_ip) + def _update_router_gw_ports(self, context, subnet_id, network_id): + l3plugin = manager.NeutronManager.get_service_plugins().get( + service_constants.L3_ROUTER_NAT) + if l3plugin: + gw_ports = self._get_router_gw_ports_by_network(context, + network_id) + router_ids = [p['device_id'] for p in gw_ports] + ctx_admin = ctx.get_admin_context() + for id in router_ids: + router = l3plugin.get_router(ctx_admin, id) + external_gateway_info = router['external_gateway_info'] + external_gateway_info['external_fixed_ips'].append( + {'subnet_id': subnet_id}) + info = {'router': {'external_gateway_info': + external_gateway_info}} + l3plugin.update_router(context, id, info) + def create_subnet(self, context, subnet): net = netaddr.IPNetwork(subnet['subnet']['cidr']) @@ -1108,13 +1130,14 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2, self._validate_subnet(context, s) tenant_id = self._get_tenant_id_for_create(context, s) + subnet_id = s.get('id') or uuidutils.generate_uuid() with context.session.begin(subtransactions=True): network = self._get_network(context, s["network_id"]) self._validate_subnet_cidr(context, network, s['cidr']) # The 'shared' attribute for subnets is for internal plugin # use only. It is not exposed through the API args = {'tenant_id': tenant_id, - 'id': s.get('id') or uuidutils.generate_uuid(), + 'id': subnet_id, 'name': s['name'], 'network_id': s['network_id'], 'ip_version': s['ip_version'], @@ -1155,6 +1178,9 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2, last_ip=pool['end']) context.session.add(ip_range) + if network.external: + self._update_router_gw_ports(context, subnet_id, s['network_id']) + return self._make_subnet_dict(subnet) def _update_subnet_dns_nameservers(self, context, id, s): diff --git a/neutron/tests/unit/test_l3_plugin.py b/neutron/tests/unit/test_l3_plugin.py index 0690e7a81..cd5282d40 100644 --- a/neutron/tests/unit/test_l3_plugin.py +++ b/neutron/tests/unit/test_l3_plugin.py @@ -877,6 +877,30 @@ class L3NatTestCaseBase(L3NatTestCaseMixin): self.assertNotEqual(fip1['ip_address'], fip2['ip_address']) + def test_router_update_gateway_upon_subnet_create_ipv6(self): + with self.network() as n: + with self.subnet(network=n) as s1, self.router() as r: + self._set_net_external(n['network']['id']) + res1 = self._add_external_gateway_to_router( + r['router']['id'], + n['network']['id'], + ext_ips=[{'subnet_id': s1['subnet']['id']}]) + fip1 = (res1['router']['external_gateway_info'] + ['external_fixed_ips'][0]) + sres = self._create_subnet(self.fmt, net_id=n['network']['id'], + ip_version=6, cidr='2001:db8::/32', + expected_res_status=( + exc.HTTPCreated.code)) + s2 = self.deserialize(self.fmt, sres) + res2 = self._show('routers', r['router']['id']) + self.assertEqual(fip1, res2['router']['external_gateway_info'] + ['external_fixed_ips'][0]) + fip2 = (res2['router']['external_gateway_info'] + ['external_fixed_ips'][1]) + self.assertEqual(s2['subnet']['id'], fip2['subnet_id']) + self.assertNotEqual(fip1['subnet_id'], fip2['subnet_id']) + self.assertNotEqual(fip1['ip_address'], fip2['ip_address']) + def _test_router_add_interface_subnet(self, router, subnet, msg=None): exp_notifications = ['router.create.start', 'router.create.end',