From a21c6325ceef2e0f24c24c154088dafbd212bc02 Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Fri, 30 Nov 2012 09:01:15 -0800 Subject: [PATCH] prevent deletion of router interface if it is needed by a floating ip bug 1081325 Change-Id: I33495fd7ee812eded015b2d3783d1cf6a3bf14bc --- quantum/db/l3_db.py | 16 ++++++++++++++++ quantum/extensions/l3.py | 6 ++++++ quantum/tests/unit/test_l3_plugin.py | 27 +++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/quantum/db/l3_db.py b/quantum/db/l3_db.py index 035f10b6d2..893cc98484 100644 --- a/quantum/db/l3_db.py +++ b/quantum/db/l3_db.py @@ -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 diff --git a/quantum/extensions/l3.py b/quantum/extensions/l3.py index 7fe4a54f24..f06425b66b 100644 --- a/quantum/extensions/l3.py +++ b/quantum/extensions/l3.py @@ -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") diff --git a/quantum/tests/unit/test_l3_plugin.py b/quantum/tests/unit/test_l3_plugin.py index 11f7eae1bf..d588e1ff6a 100644 --- a/quantum/tests/unit/test_l3_plugin.py +++ b/quantum/tests/unit/test_l3_plugin.py @@ -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'])