diff --git a/neutron/db/l3_dvrscheduler_db.py b/neutron/db/l3_dvrscheduler_db.py index 236d86e2358..5f31a4d91bf 100644 --- a/neutron/db/l3_dvrscheduler_db.py +++ b/neutron/db/l3_dvrscheduler_db.py @@ -428,6 +428,13 @@ def _notify_l3_agent_port_update(resource, event, trigger, **kwargs): } _notify_port_delete( event, resource, trigger, **removed_router_args) + fip = l3plugin._get_floatingip_on_port(context, + port_id=original_port['id']) + if fip and not (removed_routers and + fip['router_id'] in removed_routers): + l3plugin.l3_rpc_notifier.routers_updated_on_host( + context, [fip['router_id']], + original_port[portbindings.HOST_ID]) if not is_new_device_dvr_serviced: return is_new_port_binding_changed = ( diff --git a/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py b/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py index 2c8206f565d..6adf623266f 100644 --- a/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py +++ b/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py @@ -1116,7 +1116,29 @@ class L3DvrSchedulerTestCase(testlib_api.SqlTestCase): self.adminContext, kwargs.get('port')) self.assertFalse(l3plugin.dvr_handle_new_service_port.called) - def test__notify_l3_agent_update_port_with_port_binding_change(self): + def test__notify_l3_agent_port_binding_change(self): + self._test__notify_l3_agent_port_binding_change() + + def test__notify_l3_agent_port_binding_change_removed_routers(self): + router_to_remove = [{'agent_id': 'foo_agent', + 'router_id': 'foo_id', + 'host': 'vm-host1'}] + self._test__notify_l3_agent_port_binding_change(router_to_remove) + + def test__notify_l3_agent_port_binding_change_removed_routers_fip(self): + fip = {'router_id': 'router_id'} + router_to_remove = [{'agent_id': 'foo_agent', + 'router_id': 'foo_id', + 'host': 'vm-host1'}] + self._test__notify_l3_agent_port_binding_change(router_to_remove, fip) + + def test__notify_l3_agent_port_binding_change_with_fip(self): + fip = {'router_id': 'router_id'} + self._test__notify_l3_agent_port_binding_change(None, fip) + + def _test__notify_l3_agent_port_binding_change(self, + routers_to_remove=None, + fip=None): source_host = 'vm-host1' kwargs = { 'context': self.adminContext, @@ -1135,17 +1157,22 @@ class L3DvrSchedulerTestCase(testlib_api.SqlTestCase): 'get_service_plugins', return_value={'L3_ROUTER_NAT': l3plugin}),\ mock.patch.object(l3plugin, 'get_dvr_routers_to_remove', - return_value=[{'agent_id': 'foo_agent', - 'router_id': 'foo_id', - 'host': source_host}]): + return_value=routers_to_remove),\ + mock.patch.object(l3plugin, '_get_floatingip_on_port', + return_value=fip): l3_dvrscheduler_db._notify_l3_agent_port_update( 'port', 'after_update', mock.ANY, **kwargs) - (l3plugin.l3_rpc_notifier.router_removed_from_agent. - assert_called_once_with(mock.ANY, 'foo_id', source_host)) + if routers_to_remove: + (l3plugin.l3_rpc_notifier.router_removed_from_agent. + assert_called_once_with(mock.ANY, 'foo_id', source_host)) + self.assertEqual( + 1, + l3plugin.delete_arp_entry_for_dvr_service_port.call_count) + if fip and not routers_to_remove: + (l3plugin.l3_rpc_notifier.routers_updated_on_host. + assert_called_once_with(mock.ANY, ['router_id'], source_host)) self.assertEqual( 1, l3plugin.update_arp_entry_for_dvr_service_port.call_count) - self.assertEqual( - 1, l3plugin.delete_arp_entry_for_dvr_service_port.call_count) l3plugin.dvr_handle_new_service_port.assert_called_once_with( self.adminContext, kwargs.get('port'), dest_host=None) @@ -1181,7 +1208,9 @@ class L3DvrSchedulerTestCase(testlib_api.SqlTestCase): mock.patch.object(l3plugin, 'get_dvr_routers_to_remove', return_value=[{'agent_id': 'foo_agent', 'router_id': 'foo_id', - 'host': source_host}]): + 'host': source_host}]),\ + mock.patch.object(l3plugin, '_get_floatingip_on_port', + return_value=None): l3_dvrscheduler_db._notify_l3_agent_port_update( 'port', 'after_update', plugin, **kwargs)