diff --git a/neutron/callbacks/resources.py b/neutron/callbacks/resources.py index 028cc715376..719675ec6bb 100644 --- a/neutron/callbacks/resources.py +++ b/neutron/callbacks/resources.py @@ -18,6 +18,7 @@ NETWORK = 'network' NETWORKS = 'networks' PORT = 'port' PORTS = 'ports' +PORT_DEVICE = 'port_device' PROCESS = 'process' ROUTER = 'router' ROUTER_GATEWAY = 'router_gateway' diff --git a/neutron/plugins/ml2/drivers/agent/_common_agent.py b/neutron/plugins/ml2/drivers/agent/_common_agent.py index ead63bc6f97..d68c4f957c2 100644 --- a/neutron/plugins/ml2/drivers/agent/_common_agent.py +++ b/neutron/plugins/ml2/drivers/agent/_common_agent.py @@ -32,6 +32,9 @@ from neutron.agent.l2 import l2_agent_extensions_manager as ext_manager from neutron.agent import rpc as agent_rpc from neutron.agent import securitygroups_rpc as sg_rpc from neutron.api.rpc.callbacks import resources +from neutron.callbacks import events +from neutron.callbacks import registry +from neutron.callbacks import resources as local_resources from neutron.common import config as common_config from neutron.common import constants as n_const from neutron.common import topics @@ -303,6 +306,10 @@ class CommonAgentLoop(service.Service): device_details['port_id'], device_details['device']) self.ext_manager.handle_port(self.context, device_details) + registry.notify(local_resources.PORT_DEVICE, + events.AFTER_UPDATE, self, + context=self.context, + device_details=device_details) else: LOG.info(_LI("Device %s not defined on plugin"), device) @@ -339,6 +346,9 @@ class CommonAgentLoop(service.Service): self.ext_manager.delete_port(self.context, {'device': device, 'port_id': port_id}) + registry.notify(local_resources.PORT_DEVICE, events.AFTER_DELETE, + self, context=self.context, device=device, + port_id=port_id) if self.prevent_arp_spoofing: self.mgr.delete_arp_spoofing_protection(devices) return resync diff --git a/neutron/tests/unit/plugins/ml2/drivers/agent/test__common_agent.py b/neutron/tests/unit/plugins/ml2/drivers/agent/test__common_agent.py index f55d81f16ee..8db229098d5 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/agent/test__common_agent.py +++ b/neutron/tests/unit/plugins/ml2/drivers/agent/test__common_agent.py @@ -20,6 +20,9 @@ from oslo_config import cfg import testtools from neutron.agent.linux import bridge_lib +from neutron.callbacks import events +from neutron.callbacks import registry +from neutron.callbacks import resources from neutron.common import constants as n_const from neutron.plugins.ml2.drivers.agent import _agent_manager_base as amb from neutron.plugins.ml2.drivers.agent import _common_agent as ca @@ -68,6 +71,36 @@ class TestCommonAgentLoop(base.BaseTestCase): with mock.patch.object(self.agent, "daemon_loop"): self.agent.start() + def test_treat_devices_removed_notify(self): + handler = mock.Mock() + registry.subscribe(handler, resources.PORT_DEVICE, events.AFTER_DELETE) + devices = [DEVICE_1] + self.agent.treat_devices_removed(devices) + handler.assert_called_once_with(mock.ANY, mock.ANY, self.agent, + context=mock.ANY, device=DEVICE_1, + port_id=mock.ANY) + + def test_treat_devices_added_updated_notify(self): + handler = mock.Mock() + registry.subscribe(handler, resources.PORT_DEVICE, events.AFTER_UPDATE) + agent = self.agent + mock_details = {'device': 'dev123', + 'port_id': 'port123', + 'network_id': 'net123', + 'admin_state_up': True, + 'network_type': 'vlan', + 'segmentation_id': 100, + 'physical_network': 'physnet1', + 'device_owner': 'horse'} + agent.plugin_rpc = mock.Mock() + agent.plugin_rpc.get_devices_details_list.return_value = [mock_details] + agent.mgr = mock.Mock() + agent.mgr.plug_interface.return_value = True + agent.treat_devices_added_updated(set(['dev123'])) + handler.assert_called_once_with(mock.ANY, mock.ANY, self.agent, + context=mock.ANY, + device_details=mock_details) + def test_treat_devices_removed_with_existed_device(self): agent = self.agent agent.mgr.ensure_port_admin_state = mock.Mock()