diff --git a/neutron/api/rpc/agentnotifiers/dhcp_rpc_agent_api.py b/neutron/api/rpc/agentnotifiers/dhcp_rpc_agent_api.py index a5bd071eb83..5f543b93be7 100644 --- a/neutron/api/rpc/agentnotifiers/dhcp_rpc_agent_api.py +++ b/neutron/api/rpc/agentnotifiers/dhcp_rpc_agent_api.py @@ -17,6 +17,9 @@ from oslo_config import cfg from oslo_log import log as logging import oslo_messaging +from neutron.callbacks import events +from neutron.callbacks import registry +from neutron.callbacks import resources from neutron.common import constants from neutron.common import rpc as n_rpc from neutron.common import topics @@ -51,6 +54,11 @@ class DhcpAgentNotifyAPI(object): self._plugin = plugin target = oslo_messaging.Target(topic=topic, version='1.0') self.client = n_rpc.get_client(target) + # register callbacks for router interface changes + registry.subscribe(self._after_router_interface_created, + resources.ROUTER_INTERFACE, events.AFTER_CREATE) + registry.subscribe(self._after_router_interface_deleted, + resources.ROUTER_INTERFACE, events.AFTER_DELETE) @property def plugin(self): @@ -169,6 +177,18 @@ class DhcpAgentNotifyAPI(object): self._cast_message(context, 'agent_updated', {'admin_state_up': admin_state_up}, host) + def _after_router_interface_created(self, resource, event, trigger, + **kwargs): + self._notify_agents(kwargs['context'], 'port_create_end', + {'port': kwargs['port']}, + kwargs['port']['network_id']) + + def _after_router_interface_deleted(self, resource, event, trigger, + **kwargs): + self._notify_agents(kwargs['context'], 'port_delete_end', + {'port_id': kwargs['port']['id']}, + kwargs['port']['network_id']) + def notify(self, context, data, method_name): # data is {'key' : 'value'} with only one key if method_name not in self.VALID_METHOD_NAMES: diff --git a/neutron/db/l3_db.py b/neutron/db/l3_db.py index e9ff59d6360..7bddf8146c9 100644 --- a/neutron/db/l3_db.py +++ b/neutron/db/l3_db.py @@ -664,6 +664,12 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase): ) context.session.add(router_port) + registry.notify(resources.ROUTER_INTERFACE, + events.AFTER_CREATE, + self, + context=context, + port=port) + return self._make_router_interface_info( router.id, port['tenant_id'], port['id'], subnets[-1]['id'], [subnet['id'] for subnet in subnets]) @@ -768,6 +774,11 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase): port, subnets = self._remove_interface_by_subnet( context, router_id, subnet_id, device_owner) + registry.notify(resources.ROUTER_INTERFACE, + events.AFTER_DELETE, + self, + context=context, + port=port) return self._make_router_interface_info(router_id, port['tenant_id'], port['id'], subnets[0]['id'], [subnet['id'] for subnet in diff --git a/neutron/db/l3_dvr_db.py b/neutron/db/l3_dvr_db.py index b3d25af8788..9fdcf89c75b 100644 --- a/neutron/db/l3_dvr_db.py +++ b/neutron/db/l3_dvr_db.py @@ -292,6 +292,20 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin, [subnet['id'] for subnet in subnets]) self.notify_router_interface_action( context, router_interface_info, 'add') + if router.gw_port: + gw_network_id = router.gw_port.network_id + gw_ips = [x['ip_address'] for x in router.gw_port.fixed_ips] + registry.notify(resources.ROUTER_INTERFACE, + events.AFTER_CREATE, + self, + context=context, + network_id=gw_network_id, + gateway_ips=gw_ips, + cidrs=[x['cidr'] for x in subnets], + port_id=port['id'], + router_id=router_id, + port=port, + interface_info=interface_info) return router_interface_info def _port_has_ipv6_address(self, port): diff --git a/neutron/tests/unit/api/rpc/agentnotifiers/test_dhcp_rpc_agent_api.py b/neutron/tests/unit/api/rpc/agentnotifiers/test_dhcp_rpc_agent_api.py index cd2ab2aee55..5d02de7786d 100644 --- a/neutron/tests/unit/api/rpc/agentnotifiers/test_dhcp_rpc_agent_api.py +++ b/neutron/tests/unit/api/rpc/agentnotifiers/test_dhcp_rpc_agent_api.py @@ -138,20 +138,25 @@ class TestDhcpAgentNotifyAPI(base.BaseTestCase): mock.ANY, 'foo_network_id') self.assertEqual(1, self.mock_fanout.call_count) - def _test__notify_agents(self, method, - expected_scheduling=0, expected_casts=0): + def _test__notify_agents_with_function( + self, function, expected_scheduling=0, expected_casts=0): with mock.patch.object(self.notifier, '_schedule_network') as f: with mock.patch.object(self.notifier, '_get_enabled_agents') as g: agent = agents_db.Agent() agent.admin_state_up = True agent.heartbeat_timestamp = timeutils.utcnow() g.return_value = [agent] - dummy_payload = {'port': {}} - self.notifier._notify_agents(mock.Mock(), method, - dummy_payload, 'foo_network_id') + function() self.assertEqual(expected_scheduling, f.call_count) self.assertEqual(expected_casts, self.mock_cast.call_count) + def _test__notify_agents(self, method, + expected_scheduling=0, expected_casts=0): + self._test__notify_agents_with_function( + lambda: self.notifier._notify_agents( + mock.Mock(), method, {'port': {}}, 'foo_network_id'), + expected_scheduling, expected_casts) + def test__notify_agents_cast_required_with_scheduling(self): self._test__notify_agents('port_create_end', expected_scheduling=1, expected_casts=1) @@ -168,6 +173,20 @@ class TestDhcpAgentNotifyAPI(base.BaseTestCase): self._test__notify_agents('network_create_end', expected_scheduling=0, expected_casts=0) + def test__notify_agents_with_router_interface_add(self): + self._test__notify_agents_with_function( + lambda: self.notifier._after_router_interface_created( + mock.ANY, mock.ANY, mock.ANY, context=mock.Mock(), + port={'id': 'foo_port_id', 'network_id': 'foo_network_id'}), + expected_scheduling=1, expected_casts=1) + + def test__notify_agents_with_router_interface_delete(self): + self._test__notify_agents_with_function( + lambda: self.notifier._after_router_interface_deleted( + mock.ANY, mock.ANY, mock.ANY, context=mock.Mock(), + port={'id': 'foo_port_id', 'network_id': 'foo_network_id'}), + expected_scheduling=0, expected_casts=1) + def test__fanout_message(self): self.notifier._fanout_message(mock.ANY, mock.ANY, mock.ANY) self.assertEqual(1, self.mock_fanout.call_count) diff --git a/neutron/tests/unit/extensions/test_l3.py b/neutron/tests/unit/extensions/test_l3.py index f1ecae6c30d..b9c6c35a35e 100644 --- a/neutron/tests/unit/extensions/test_l3.py +++ b/neutron/tests/unit/extensions/test_l3.py @@ -1619,6 +1619,10 @@ class L3NatTestCaseBase(L3NatTestCaseMixin): with self.router() as r,\ self.subnet() as s,\ mock.patch.object(registry, 'notify') as notify: + self._router_interface_action('add', + r['router']['id'], + s['subnet']['id'], + None) errors = [ exceptions.NotificationError( 'foo_callback_id', n_exc.InUse()), @@ -1628,10 +1632,6 @@ class L3NatTestCaseBase(L3NatTestCaseMixin): notify.side_effect = [ exceptions.CallbackFailure(errors=errors), None ] - self._router_interface_action('add', - r['router']['id'], - s['subnet']['id'], - None) self._router_interface_action( 'remove', r['router']['id'],