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
This commit is contained in:
Rodolfo Alonso Hernandez 2019-04-11 12:49:20 +00:00
parent 5d607a13ba
commit 749b33e41b
5 changed files with 90 additions and 15 deletions

View File

@ -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]))

View File

@ -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

View File

@ -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:

View File

@ -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(

View File

@ -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