From 749b33e41bc905a3bec9d356c78a477e9b8aa87d Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Thu, 11 Apr 2019 12:49:20 +0000 Subject: [PATCH] Check in "_update_segmentation_id" that the mech_driver has an agent In [1] it is assumed that all mechanism drivers have an agent, but the mech driver API [2] doesn't enforce it. VIF types will be retrieved only from those mechanism drivers with an associated agent. [1]https://review.openstack.org/#/c/633165/20/neutron/plugins/ml2/plugin.py@814 [2]https://github.com/openstack/neutron-lib/blob/stable/stein/neutron_lib/plugins/ml2/api.py#L37 Change-Id: I5c334f31259871ed5251d5d4a2ba8cae36bd2355 Closes-Bug: #1824346 --- neutron/plugins/ml2/plugin.py | 9 ++-- .../plugins/ml2/drivers/mechanism_test.py | 49 ++++++++++++++++--- neutron/tests/unit/plugins/ml2/test_plugin.py | 42 ++++++++++++++-- .../services/placement_report/test_plugin.py | 4 ++ setup.cfg | 1 + 5 files changed, 90 insertions(+), 15 deletions(-) diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py index 6397826e002..b2d99faaf52 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -115,6 +115,7 @@ from neutron.objects import ports as ports_obj from neutron.plugins.ml2.common import exceptions as ml2_exc from neutron.plugins.ml2 import db from neutron.plugins.ml2 import driver_context +from neutron.plugins.ml2.drivers import mech_agent from neutron.plugins.ml2.extensions import qos as qos_ext from neutron.plugins.ml2 import managers from neutron.plugins.ml2 import models @@ -809,11 +810,13 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, vif_types = [portbindings.VIF_TYPE_UNBOUND, portbindings.VIF_TYPE_BINDING_FAILED] for mech_driver in self.mechanism_manager.ordered_mech_drivers: - if (provider_net.SEGMENTATION_ID in mech_driver.obj. + if (isinstance(mech_driver.obj, + mech_agent.AgentMechanismDriverBase) and + provider_net.SEGMENTATION_ID in mech_driver.obj. provider_network_attribute_updates_supported()): agent_type = mech_driver.obj.agent_type - agents = self.get_agents(context, - filters={'agent_type': [agent_type]}) + agents = self.get_agents( + context, filters={'agent_type': [agent_type]}) for agent in agents: vif_types.append(mech_driver.obj.get_vif_type( context, agent, segments[0])) diff --git a/neutron/tests/unit/plugins/ml2/drivers/mechanism_test.py b/neutron/tests/unit/plugins/ml2/drivers/mechanism_test.py index c8a5b7837b9..b0c7cbad8e4 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/mechanism_test.py +++ b/neutron/tests/unit/plugins/ml2/drivers/mechanism_test.py @@ -16,9 +16,12 @@ import uuid from neutron_lib.api.definitions import portbindings +from neutron_lib.api.definitions import provider_net as pnet from neutron_lib import constants as const from neutron_lib.plugins.ml2 import api +from neutron.plugins.ml2.drivers import mech_agent + VIF_TYPE_TEST = 'vif_type_test' @@ -26,6 +29,10 @@ VIF_TYPE_TEST = 'vif_type_test' class TestMechanismDriver(api.MechanismDriver): """Test mechanism driver for testing mechanism driver api.""" + def __init__(self, *args, **kwargs): + super(TestMechanismDriver, self).__init__(*args, **kwargs) + self._supported_vnic_types = ('test_mechanism_driver_vnic_type', ) + def initialize(self): self.bound_ports = set() @@ -249,24 +256,50 @@ class TestMechanismDriver(api.MechanismDriver): self, context, segments, candidate_hosts, agent_getter): return set() - def get_vif_type(self, context, agent, segment): - return VIF_TYPE_TEST - @property def resource_provider_uuid5_namespace(self): return uuid.UUID('7f0ce65c-1f13-11e9-8921-3c6aa7b21d17') - @property - def agent_type(self): - return 'test_mechanism_driver_agent' - @property def supported_vnic_types(self): - return ('test_mechanism_driver_vnic_type',) + return self._supported_vnic_types def get_standard_device_mappings(self, agent): return {} + # NOTE(ralonsoh): to be removed with neutron-lib >= 1.26.0 @staticmethod def provider_network_attribute_updates_supported(): return [] + + +class TestMechanismDriverWithAgent(mech_agent.AgentMechanismDriverBase, + TestMechanismDriver): + """Test mechanism driver with agent for testing mechanism driver api.""" + + def __init__(self): + super(TestMechanismDriverWithAgent, self).__init__('test_agent_type') + self.bound_ports = set() + self._agent_type = 'test_mechanism_driver_agent' + + def get_vif_type(self, context, agent, segment): + return VIF_TYPE_TEST + + @staticmethod + def provider_network_attribute_updates_supported(): + return [pnet.SEGMENTATION_ID] + + def try_to_bind_segment_for_agent(self, context, segment, agent): + pass + + @property + def agent_type(self): + return self._agent_type + + @agent_type.setter + def agent_type(self, agent_type): + self._agent_type = agent_type + + @TestMechanismDriver.supported_vnic_types.setter + def supported_vnic_types(self, vnic_types): + self._supported_vnic_types = vnic_types diff --git a/neutron/tests/unit/plugins/ml2/test_plugin.py b/neutron/tests/unit/plugins/ml2/test_plugin.py index ff91636b745..cca4ea48037 100644 --- a/neutron/tests/unit/plugins/ml2/test_plugin.py +++ b/neutron/tests/unit/plugins/ml2/test_plugin.py @@ -473,6 +473,44 @@ class TestMl2NetworksV2(test_plugin.TestNetworksV2, exc.InvalidInput, plugin._update_segmentation_id, self.context, net['network'], {}) + def test__update_segmentation_id_agentless_mech_drivers(self): + plugin = directory.get_plugin() + segments = [{pnet.NETWORK_TYPE: 'vlan', + pnet.PHYSICAL_NETWORK: 'physnet1', + pnet.SEGMENTATION_ID: 1}] + mech_drivers = plugin.mechanism_manager.ordered_mech_drivers + for mech_driver in (md.obj for md in mech_drivers if + hasattr(md.obj, 'agent_type')): + mock.patch.object(type(mech_driver), 'agent_type', + new_callable=mock.PropertyMock(return_value=None)).start() + + with self.network(**{'arg_list': (mpnet_apidef.SEGMENTS, ), + mpnet_apidef.SEGMENTS: segments}) as net, \ + mock.patch.object(db_base_plugin_v2.NeutronDbPluginV2, + 'get_ports_count') as mock_get_ports_count, \ + mock.patch.object(plugin.type_manager, + 'update_network_segment'), \ + mock.patch.object(plugin, 'get_agents') as mock_get_agents, \ + mock.patch.object(obj_utils, 'NotIn') as mock_not_in: + mock_get_ports_count.return_value = 0 + net_data = {pnet.SEGMENTATION_ID: 1000} + plugin._update_segmentation_id(self.context, net['network'], + net_data) + + mock_get_agents.assert_not_called() + mock_not_in.assert_called_once_with([ + portbindings.VIF_TYPE_UNBOUND, + portbindings.VIF_TYPE_BINDING_FAILED]) + filters = {portbindings.VIF_TYPE: mock.ANY, + 'network_id': [net['network']['id']]} + mock_get_ports_count.assert_called_once_with( + self.context, filters=filters) + + +class TestMl2NetworksV2AgentMechDrivers(Ml2PluginV2TestCase): + + _mechanism_drivers = ['logger', 'test', 'test_with_agent'] + def test__update_segmentation_id_ports(self): plugin = directory.get_plugin() segments = [{pnet.NETWORK_TYPE: 'vlan', @@ -484,10 +522,6 @@ class TestMl2NetworksV2(test_plugin.TestNetworksV2, 'get_ports_count') as mock_get_ports_count, \ mock.patch.object(plugin.type_manager, 'update_network_segment'), \ - mock.patch.object( - mech_test.TestMechanismDriver, - 'provider_network_attribute_updates_supported', - return_value=[pnet.SEGMENTATION_ID]), \ mock.patch.object(plugin, 'get_agents', return_value=[mock.ANY]), \ mock.patch.object(obj_utils, 'NotIn') as mock_not_in: diff --git a/neutron/tests/unit/services/placement_report/test_plugin.py b/neutron/tests/unit/services/placement_report/test_plugin.py index 8eaa350931b..2f5d3fe84e5 100644 --- a/neutron/tests/unit/services/placement_report/test_plugin.py +++ b/neutron/tests/unit/services/placement_report/test_plugin.py @@ -27,6 +27,8 @@ LOG = logging.getLogger(__name__) class PlacementReportPluginTestCases(test_plugin.Ml2PluginV2TestCase): + _mechanism_drivers = ['logger', 'test_with_agent'] + def setUp(self): super(PlacementReportPluginTestCases, self).setUp() self.service_plugin = plugin.PlacementReportPlugin() @@ -223,6 +225,8 @@ class PlacementReportPluginTestCases(test_plugin.Ml2PluginV2TestCase): class PlacementReporterAgentsTestCases(test_plugin.Ml2PluginV2TestCase): + _mechanism_drivers = ['logger', 'test_with_agent'] + def test_supported_agent_types(self): self.agents = plugin.PlacementReporterAgents(ml2_plugin=self.plugin) self.assertEqual( diff --git a/setup.cfg b/setup.cfg index f03a1675d00..c0718eb7e96 100644 --- a/setup.cfg +++ b/setup.cfg @@ -86,6 +86,7 @@ neutron.ml2.type_drivers = neutron.ml2.mechanism_drivers = logger = neutron.tests.unit.plugins.ml2.drivers.mechanism_logger:LoggerMechanismDriver test = neutron.tests.unit.plugins.ml2.drivers.mechanism_test:TestMechanismDriver + test_with_agent = neutron.tests.unit.plugins.ml2.drivers.mechanism_test:TestMechanismDriverWithAgent linuxbridge = neutron.plugins.ml2.drivers.linuxbridge.mech_driver.mech_linuxbridge:LinuxbridgeMechanismDriver macvtap = neutron.plugins.ml2.drivers.macvtap.mech_driver.mech_macvtap:MacvtapMechanismDriver openvswitch = neutron.plugins.ml2.drivers.openvswitch.mech_driver.mech_openvswitch:OpenvswitchMechanismDriver