From 991bcd671161f398cb77c6f96efb1638eddf35ae Mon Sep 17 00:00:00 2001 From: Moshe Levi Date: Mon, 10 Aug 2015 14:43:55 +0300 Subject: [PATCH] Add delete_port api to agent extension manager This commit add delete_port api to the agent extension manager, the agent extension and the qos etension, and it update the ovs agent to call it upon delete port. Change-Id: Ia4e96c7c734cf4abe9a35c813bd8330b15b68f4c Partially-Implements: bluerint ml2-qos --- neutron/agent/l2/agent_extension.py | 14 +++++++++++++- neutron/agent/l2/extensions/manager.py | 16 ++++++++++++++-- neutron/agent/l2/extensions/qos.py | 3 +++ .../openvswitch/agent/ovs_neutron_agent.py | 3 +++ .../unit/agent/l2/extensions/test_manager.py | 7 +++++++ .../tests/unit/agent/l2/extensions/test_qos.py | 16 ++++++++++++++++ 6 files changed, 56 insertions(+), 3 deletions(-) diff --git a/neutron/agent/l2/agent_extension.py b/neutron/agent/l2/agent_extension.py index 125a9bc05..9399f4237 100644 --- a/neutron/agent/l2/agent_extension.py +++ b/neutron/agent/l2/agent_extension.py @@ -34,7 +34,19 @@ class AgentCoreResourceExtension(object): @abc.abstractmethod def handle_port(self, context, data): - """handle agent extension for port. + """Handle agent extension for port. + + This can be called on either create or update, depending on the + code flow. Thus, it's this function's responsibility to check what + actually changed. + + :param context - rpc context + :param data - port data + """ + + @abc.abstractmethod + def delete_port(self, context, data): + """Delete port from agent extension. :param context - rpc context :param data - port data diff --git a/neutron/agent/l2/extensions/manager.py b/neutron/agent/l2/extensions/manager.py index 2c77adbf8..ba9b45952 100644 --- a/neutron/agent/l2/extensions/manager.py +++ b/neutron/agent/l2/extensions/manager.py @@ -61,5 +61,17 @@ class AgentExtensionsManager(stevedore.named.NamedExtensionManager): "while handling port update"), {'name': extension.name} ) - #TODO(Qos) we are missing how to handle delete. we can pass action - #type in all the handle methods or add handle_delete_resource methods + + def delete_port(self, context, data): + """Notify all agent extensions to delete port.""" + for extension in self: + try: + extension.obj.delete_port(context, data) + # TODO(QoS) add agent extensions exception and catch them here + # instead of AttributeError + except AttributeError: + LOG.exception( + _LE("Agent Extension '%(name)s' failed " + "while handling port deletion"), + {'name': extension.name} + ) diff --git a/neutron/agent/l2/extensions/qos.py b/neutron/agent/l2/extensions/qos.py index 736cc1458..4b860a1a2 100644 --- a/neutron/agent/l2/extensions/qos.py +++ b/neutron/agent/l2/extensions/qos.py @@ -133,6 +133,9 @@ class QosAgentExtension(agent_extension.AgentCoreResourceExtension): context, resources.QOS_POLICY, qos_policy_id) self.qos_driver.create(port, qos_policy) + def delete_port(self, context, port): + self._process_reset_port(port) + def _process_update_policy(self, qos_policy): for port_id, port in self.qos_policy_ports[qos_policy.id].items(): # TODO(QoS): for now, just reflush the rules on the port. Later, we diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py index a5190f9a3..211e51761 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py @@ -403,6 +403,9 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, # longer have access to the network self.sg_agent.remove_devices_filter([port_id]) port = self.int_br.get_vif_port_by_id(port_id) + self.ext_manager.delete_port(self.context, + {"vif_port": port, + "port_id": port_id}) if port: # don't log errors since there is a chance someone will be # removing the port from the bridge at the same time diff --git a/neutron/tests/unit/agent/l2/extensions/test_manager.py b/neutron/tests/unit/agent/l2/extensions/test_manager.py index 3aa8ea58b..85f853380 100644 --- a/neutron/tests/unit/agent/l2/extensions/test_manager.py +++ b/neutron/tests/unit/agent/l2/extensions/test_manager.py @@ -43,3 +43,10 @@ class TestAgentExtensionsManager(base.BaseTestCase): self.manager.handle_port(context, data) ext = self._get_extension() ext.handle_port.assert_called_once_with(context, data) + + def test_delete_port(self): + context = object() + data = object() + self.manager.delete_port(context, data) + ext = self._get_extension() + ext.delete_port.assert_called_once_with(context, data) diff --git a/neutron/tests/unit/agent/l2/extensions/test_qos.py b/neutron/tests/unit/agent/l2/extensions/test_qos.py index d78fc3121..4ed3090b8 100755 --- a/neutron/tests/unit/agent/l2/extensions/test_qos.py +++ b/neutron/tests/unit/agent/l2/extensions/test_qos.py @@ -98,6 +98,22 @@ class QosExtensionRpcTestCase(QosExtensionBaseTestCase): #TODO(QoS): handle qos_driver.update call check when # we do that + def test_delete_known_port(self): + port = self._create_test_port_dict() + port_id = port['port_id'] + self.qos_ext.handle_port(self.context, port) + self.qos_ext.qos_driver.reset_mock() + self.qos_ext.delete_port(self.context, port) + self.qos_ext.qos_driver.delete.assert_called_with(port, None) + self.assertNotIn(port_id, self.qos_ext.known_ports) + + def test_delete_unknown_port(self): + port = self._create_test_port_dict() + port_id = port['port_id'] + self.qos_ext.delete_port(self.context, port) + self.assertFalse(self.qos_ext.qos_driver.delete.called) + self.assertNotIn(port_id, self.qos_ext.known_ports) + def test__handle_notification_ignores_all_event_types_except_updated(self): with mock.patch.object( self.qos_ext, '_process_update_policy') as update_mock: -- 2.45.2