]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
prevent deletion of router interface if it is needed by a floating ip
authorDan Wendlandt <dan@nicira.com>
Fri, 30 Nov 2012 17:01:15 +0000 (09:01 -0800)
committerDan Wendlandt <dan@nicira.com>
Fri, 30 Nov 2012 17:01:15 +0000 (09:01 -0800)
bug 1081325

Change-Id: I33495fd7ee812eded015b2d3783d1cf6a3bf14bc

quantum/db/l3_db.py
quantum/extensions/l3.py
quantum/tests/unit/test_l3_plugin.py

index 035f10b6d23c4512f4e6bacbc5d3f358541a7623..893cc9848461112d7263468c7699445628c7ba87 100644 (file)
@@ -342,6 +342,16 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
         return {'port_id': port['id'],
                 'subnet_id': port['fixed_ips'][0]['subnet_id']}
 
+    def _confirm_router_interface_not_in_use(self, context, router_id,
+                                             subnet_id):
+        subnet_db = self._get_subnet(context, subnet_id)
+        subnet_cidr = netaddr.IPNetwork(subnet_db['cidr'])
+        fip_qry = context.session.query(FloatingIP)
+        for fip_db in fip_qry.filter_by(router_id=router_id):
+            if netaddr.IPAddress(fip_db['fixed_ip_address']) in subnet_cidr:
+                raise l3.RouterInterfaceInUseByFloatingIP(
+                    router_id=router_id, subnet_id=subnet_id)
+
     def remove_router_interface(self, context, router_id, interface_info):
         # make sure router exists
         router = self._get_router(context, router_id)
@@ -373,9 +383,15 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
             if port_db['device_id'] != router_id:
                 raise w_exc.HTTPConflict("port_id %s not used by router" %
                                          port_db['id'])
+            self._confirm_router_interface_not_in_use(
+                context, router_id,
+                port_db['fixed_ips'][0]['subnet_id'])
             self.delete_port(context, port_db['id'], l3_port_check=False)
         elif 'subnet_id' in interface_info:
             subnet_id = interface_info['subnet_id']
+            self._confirm_router_interface_not_in_use(context, router_id,
+                                                      subnet_id)
+
             subnet = self._get_subnet(context, subnet_id)
             found = False
 
index 7fe4a54f24d5f08ba3b0d9e280569bf1ef18e105..f06425b66b8637c37f04d7b91d3d40b1d7d36745 100644 (file)
@@ -39,6 +39,12 @@ class RouterInUse(qexception.InUse):
     message = _("Router %(router_id)s still has active ports")
 
 
+class RouterInterfaceInUseByFloatingIP(qexception.InUse):
+    message = _("Router interface for subnet %(subnet_id)s on router "
+                "%(router_id)s cannot be deleted, as it is required "
+                "by one or more floating IPs.")
+
+
 class FloatingIPNotFound(qexception.NotFound):
     message = _("Floating IP %(floatingip_id)s could not be found")
 
index 11f7eae1bf8cb365c84d13e8e9f6946aa9caf81a..d588e1ff6a3c73c77eea8609b3c027f1a0d28d0e 100644 (file)
@@ -1029,6 +1029,33 @@ class L3NatDBTestCase(test_db_plugin.QuantumDbPluginV2TestCase):
                                       utils.str_uuid(), 'iamnotnanip')
         self.assertEqual(res.status_int, 400)
 
+    def test_floatingip_delete_router_intf_with_subnet_id_returns_409(self):
+        found = False
+        with self.floatingip_with_assoc() as fip:
+            for p in self._list('ports')['ports']:
+                if p['device_owner'] == 'network:router_interface':
+                    subnet_id = p['fixed_ips'][0]['subnet_id']
+                    router_id = p['device_id']
+                    self._router_interface_action(
+                        'remove', router_id, subnet_id, None,
+                        expected_code=exc.HTTPConflict.code)
+                    found = True
+                    break
+        self.assertTrue(found)
+
+    def test_floatingip_delete_router_intf_with_port_id_returns_409(self):
+        found = False
+        with self.floatingip_with_assoc() as fip:
+            for p in self._list('ports')['ports']:
+                if p['device_owner'] == 'network:router_interface':
+                    router_id = p['device_id']
+                    self._router_interface_action(
+                        'remove', router_id, None, p['id'],
+                        expected_code=exc.HTTPConflict.code)
+                    found = True
+                    break
+        self.assertTrue(found)
+
     def test_list_nets_external(self):
         with self.network() as n1:
             self._set_net_external(n1['network']['id'])