]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Auto-update gateway port after subnet-create
authorAndrew Boik <dboik@cisco.com>
Wed, 4 Mar 2015 03:39:57 +0000 (22:39 -0500)
committerAndrew Boik <dboik@cisco.com>
Sat, 28 Mar 2015 05:16:34 +0000 (05:16 +0000)
(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

neutron/db/db_base_plugin_v2.py
neutron/tests/unit/test_l3_plugin.py

index 73d7f45cb78bc08791d6a3dd3b1261acbad3da24..3b3573dafd1e213eea61dc5716b02282093067b1 100644 (file)
@@ -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):
index 0690e7a812aff1f3f0a38ae57f990a0626df0824..cd5282d4026de800fc1f36eb74c7c903914b50d0 100644 (file)
@@ -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',