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)
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
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")
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'])