diff --git a/neutron/db/l3_db.py b/neutron/db/l3_db.py index 4e57ab85308..4e11f71d925 100644 --- a/neutron/db/l3_db.py +++ b/neutron/db/l3_db.py @@ -382,32 +382,36 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, if self.router_gw_port_has_floating_ips(admin_ctx, router_id): raise l3.RouterExternalGatewayInUseByFloatingIp( router_id=router_id, net_id=router.gw_port['network_id']) - gw_ips = [x['ip_address'] for x in router.gw_port.fixed_ips] + gw_ips = [x['ip_address'] for x in router.gw_port['fixed_ips']] + gw_port_id = router.gw_port['id'] + self._delete_router_gw_port_db(context, router) + self._core_plugin.delete_port( + admin_ctx, gw_port_id, l3_port_check=False) + registry.notify(resources.ROUTER_GATEWAY, + events.AFTER_DELETE, self, + router_id=router_id, + context=context, + router=router, + network_id=old_network_id, + gateway_ips=gw_ips) + + def _delete_router_gw_port_db(self, context, router): with context.session.begin(subtransactions=True): gw_port = router.gw_port router.gw_port = None context.session.add(router) context.session.expire(gw_port) - self._check_router_gw_port_in_use(context, router_id) - self._core_plugin.delete_port( - admin_ctx, gw_port['id'], l3_port_check=False) - registry.notify(resources.ROUTER_GATEWAY, - events.AFTER_DELETE, self, - router_id=router_id, - network_id=old_network_id, - gateway_ips=gw_ips) - - def _check_router_gw_port_in_use(self, context, router_id): - try: - kwargs = {'context': context, 'router_id': router_id} - registry.notify( - resources.ROUTER_GATEWAY, events.BEFORE_DELETE, self, **kwargs) - except exceptions.CallbackFailure as e: - with excutils.save_and_reraise_exception(): - # NOTE(armax): preserve old check's behavior - if len(e.errors) == 1: - raise e.errors[0].error - raise l3.RouterInUse(router_id=router_id, reason=e) + try: + kwargs = {'context': context, 'router_id': router.id} + registry.notify( + resources.ROUTER_GATEWAY, events.BEFORE_DELETE, self, + **kwargs) + except exceptions.CallbackFailure as e: + with excutils.save_and_reraise_exception(): + # NOTE(armax): preserve old check's behavior + if len(e.errors) == 1: + raise e.errors[0].error + raise l3.RouterInUse(router_id=router.id, reason=e) def _create_gw_port(self, context, router_id, router, new_network_id, ext_ips): diff --git a/neutron/db/l3_dvr_db.py b/neutron/db/l3_dvr_db.py index 514217c38a5..7bbeb6143cf 100644 --- a/neutron/db/l3_dvr_db.py +++ b/neutron/db/l3_dvr_db.py @@ -77,6 +77,8 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin, resources.ROUTER, events.AFTER_UPDATE) registry.subscribe(n._create_snat_interfaces_after_change, resources.ROUTER, events.AFTER_CREATE) + registry.subscribe(n._delete_dvr_internal_ports, + resources.ROUTER_GATEWAY, events.AFTER_DELETE) return n def _create_router_db(self, context, router, tenant_id): @@ -173,39 +175,33 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin, router_db['id']) return router_db - def _delete_current_gw_port(self, context, router_id, router, new_network): + def _delete_dvr_internal_ports(self, event, trigger, resource, + context, router, network_id, **kwargs): """ - Overridden here to handle deletion of dvr internal ports. + GW port AFTER_DELETE event handler to cleanup DVR ports. - If there is a valid router update with gateway port to be deleted, - then go ahead and delete the csnat ports and the floatingip + This event is emitted when a router gateway port is being deleted, + so go ahead and delete the csnat ports and the floatingip agent gateway port associated with the dvr router. """ - gw_ext_net_id = ( - router.gw_port['network_id'] if router.gw_port else None) - - super(L3_NAT_with_dvr_db_mixin, - self)._delete_current_gw_port(context, router_id, - router, new_network) - if (is_distributed_router(router) and - gw_ext_net_id != new_network and gw_ext_net_id is not None): - self.delete_csnat_router_interface_ports( - context.elevated(), router) - # NOTE(Swami): Delete the Floatingip agent gateway port - # on all hosts when it is the last gateway port in the - # given external network. - filters = {'network_id': [gw_ext_net_id], - 'device_owner': [const.DEVICE_OWNER_ROUTER_GW]} - ext_net_gw_ports = self._core_plugin.get_ports( - context.elevated(), filters) - if not ext_net_gw_ports: - self.delete_floatingip_agent_gateway_port( - context.elevated(), None, gw_ext_net_id) - # Send the information to all the L3 Agent hosts - # to clean up the fip namespace as it is no longer required. - self.l3_rpc_notifier.delete_fipnamespace_for_ext_net( - context, gw_ext_net_id) + if not is_distributed_router(router): + return + self.delete_csnat_router_interface_ports(context.elevated(), router) + # NOTE(Swami): Delete the Floatingip agent gateway port + # on all hosts when it is the last gateway port in the + # given external network. + filters = {'network_id': [network_id], + 'device_owner': [const.DEVICE_OWNER_ROUTER_GW]} + ext_net_gw_ports = self._core_plugin.get_ports( + context.elevated(), filters) + if not ext_net_gw_ports: + self.delete_floatingip_agent_gateway_port( + context.elevated(), None, network_id) + # Send the information to all the L3 Agent hosts + # to clean up the fip namespace as it is no longer required. + self.l3_rpc_notifier.delete_fipnamespace_for_ext_net( + context, network_id) def _get_device_owner(self, context, router=None): """Get device_owner for the specified router.""" diff --git a/neutron/tests/unit/db/test_l3_dvr_db.py b/neutron/tests/unit/db/test_l3_dvr_db.py index 677ae30cfce..7129643ae18 100644 --- a/neutron/tests/unit/db/test_l3_dvr_db.py +++ b/neutron/tests/unit/db/test_l3_dvr_db.py @@ -303,7 +303,8 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase): gw_port_db = { 'id': 'my_gw_id', 'network_id': 'ext_net_id', - 'device_owner': const.DEVICE_OWNER_ROUTER_GW + 'device_owner': const.DEVICE_OWNER_ROUTER_GW, + 'fixed_ips': [{'ip_address': '1.2.3.4'}] } router.gw_port = gw_port_db else: @@ -312,7 +313,10 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase): plugin = mock.Mock() directory.add_plugin(const.CORE, plugin) with mock.patch.object(l3_dvr_db.l3_db.L3_NAT_db_mixin, - '_delete_current_gw_port'),\ + 'router_gw_port_has_floating_ips', + return_value=False),\ + mock.patch.object(l3_dvr_db.l3_db.L3_NAT_db_mixin, + '_delete_router_gw_port_db'),\ mock.patch.object( self.mixin, '_get_router') as grtr,\