fix same mechanism driver called twice bug

when a mechinism driver calls context.continue_binding to
continue binding, it will be called again because
_check_driver_to_bind compares driver name with driver.

Closes-Bug: #1745572
Change-Id: I62b32c9b9d01dd929fe8cd3634c78dc0cbe325b6
This commit is contained in:
Bo Chi 2017-12-28 21:35:31 +08:00
parent 639b83264c
commit 892c1ec690
3 changed files with 62 additions and 19 deletions

View File

@ -854,8 +854,12 @@ class MechanismManager(stevedore.named.NamedExtensionManager):
segment_ids_to_bind = {s[api.SEGMENTATION_ID]
for s in segments_to_bind}
for level in binding_levels:
if (level.driver == driver and
level.segment_id in segment_ids_to_bind):
if (level.driver == driver.name and
level.segment_id in segment_ids_to_bind):
LOG.debug("segment %(segment)s is already bound "
"by driver %(driver)s",
{"segment": level.segment_id,
"driver": level.driver})
return False
return True

View File

@ -52,6 +52,7 @@ class FakePortContext(api.PortContext):
self._bound_vif_type = None
self._bound_vif_details = None
self._original = original
self._binding_levels = []
@property
def current(self):
@ -75,14 +76,24 @@ class FakePortContext(api.PortContext):
def network(self):
return self._network_context
def _prepare_to_bind(self, segments_to_bind):
self._segments_to_bind = segments_to_bind
self._new_bound_segment = None
self._next_segments_to_bind = None
def _push_binding_level(self, binding_level):
self._binding_levels.append(binding_level)
def _pop_binding_level(self):
return self._binding_levels.pop()
@property
def binding_levels(self):
if self._bound_segment:
if self._binding_levels:
return [{
api.BOUND_DRIVER: 'fake_driver',
api.BOUND_SEGMENT: self._expand_segment(
self._bound_segment)
}]
api.BOUND_DRIVER: level.driver,
api.BOUND_SEGMENT: self._expand_segment(level.segment_id)
} for level in self._binding_levels]
@property
def original_binding_levels(self):
@ -90,7 +101,8 @@ class FakePortContext(api.PortContext):
@property
def top_bound_segment(self):
return self._expand_segment(self._bound_segment)
if self._binding_levels:
return self._expand_segment(self._binding_levels[0].segment_id)
@property
def original_top_bound_segment(self):
@ -98,7 +110,8 @@ class FakePortContext(api.PortContext):
@property
def bottom_bound_segment(self):
return self._expand_segment(self._bound_segment)
if self._binding_levels:
return self._expand_segment(self._binding_levels[-1].segment_id)
@property
def original_bottom_bound_segment(self):

View File

@ -23,24 +23,50 @@ from oslo_db import exception as db_exc
from neutron.plugins.ml2.common import exceptions as ml2_exc
from neutron.plugins.ml2 import managers
from neutron.tests import base
from neutron.tests.unit.plugins.ml2._test_mech_agent import FakePortContext
from neutron.tests.unit.plugins.ml2.drivers import mech_fake_agent
from neutron.tests.unit.plugins.ml2.drivers import mechanism_test
class TestManagers(base.BaseTestCase):
def setUp(self):
super(TestManagers, self).setUp()
self.segment_id = 49
self.segments_to_bind = [{api.ID: "id1",
'network_type': 'vlan',
'physical_network': 'public',
api.SEGMENTATION_ID: self.segment_id}]
self.context = FakePortContext(None,
None,
self.segments_to_bind)
self.context._binding = mock.Mock()
self.context._binding_levels = []
self.context._new_bound_segment = self.segment_id
self.context._next_segments_to_bind = None
def test__check_driver_to_bind(self):
cfg.CONF.set_override('mechanism_drivers', ['fake_agent'],
group='ml2')
manager = managers.MechanismManager()
bindinglevel = mock.Mock()
bindinglevel.driver = 'fake_driver'
bindinglevel.segment_id = 'fake_seg_id'
binding_levels = [bindinglevel]
segments_to_bind = [{api.SEGMENTATION_ID: 'fake_seg_id'}]
self.assertFalse(manager._check_driver_to_bind(
'fake_driver', segments_to_bind, binding_levels))
bindinglevel.segment_id = 'fake_seg_id1'
self.assertTrue(manager._check_driver_to_bind(
'fake_driver', segments_to_bind, binding_levels))
with mock.patch.object(mech_fake_agent.FakeAgentMechanismDriver,
'bind_port') as bind_port:
manager._bind_port_level(self.context, 0, self.segments_to_bind)
self.assertEqual(1, bind_port.call_count)
def test__check_driver_to_bind2(self):
cfg.CONF.set_override('mechanism_drivers', ['fake_agent'],
group='ml2')
manager = managers.MechanismManager()
self.context._binding_levels = [mock.Mock(port_id="port_id",
level=0,
driver='fake_agent',
segment_id=self.segment_id)]
with mock.patch.object(mech_fake_agent.FakeAgentMechanismDriver,
'bind_port') as bind_port:
manager._bind_port_level(self.context, 0, self.segments_to_bind)
self.assertEqual(0, bind_port.call_count)
@mock.patch.object(managers.LOG, 'critical')
@mock.patch.object(managers.MechanismManager, '_driver_not_loaded')