diff --git a/neutron/services/trunk/rules.py b/neutron/services/trunk/rules.py index 8454174d213..b8bef71e77a 100644 --- a/neutron/services/trunk/rules.py +++ b/neutron/services/trunk/rules.py @@ -105,10 +105,11 @@ class TrunkPortValidator(object): # can be determined based on the vif type, whether or not the # driver is agent-based, and whether the host is running the agent # associated to the driver itself. + host_agent_types = utils.get_agent_types_by_host(context, binding_host) drivers = [ driver for driver in trunk_plugin.registered_drivers if utils.is_driver_compatible( - context, driver, vif_type, binding_host) + context, driver, vif_type, host_agent_types) ] if len(drivers) > 1: raise trunk_exc.TrunkPluginDriverConflict() diff --git a/neutron/services/trunk/utils.py b/neutron/services/trunk/utils.py index e4ff9525d96..cfafd45209d 100644 --- a/neutron/services/trunk/utils.py +++ b/neutron/services/trunk/utils.py @@ -24,18 +24,19 @@ def gen_trunk_br_name(trunk_id): [:constants.DEVICE_NAME_MAX_LEN - 1]) -def are_agent_types_available_on_host(context, agent_types, host): - """Return true if agent types are present on the host.""" +def get_agent_types_by_host(context, host): + """Return the agent types registered on the host.""" + agent_types = [] core_plugin = manager.NeutronManager.get_plugin() if utils.is_extension_supported(core_plugin, 'agent'): - return bool(core_plugin.get_agents( - context.elevated(), - filters={'host': [host], 'agent_type': agent_types})) - return False + agents = core_plugin.get_agents( + context.elevated(), filters={'host': [host]}) + agent_types = [a['agent_type'] for a in agents] + return agent_types -def is_driver_compatible(context, driver, interface, binding_host): - """Return true if the driver is compatible with the interface and host. +def is_driver_compatible(context, driver, interface, host_agent_types): + """True if the driver is compatible with interface and host_agent_types. There may be edge cases where a stale view or the deployment may make the following test fail to detect the right driver in charge of the bound port. @@ -56,7 +57,4 @@ def is_driver_compatible(context, driver, interface, binding_host): return is_interface_compatible # For an agent-based driver, both interface and agent compat is required. - return ( - is_interface_compatible and - are_agent_types_available_on_host( - context, [driver.agent_type], binding_host)) + return is_interface_compatible and driver.agent_type in host_agent_types diff --git a/neutron/tests/unit/services/trunk/test_utils.py b/neutron/tests/unit/services/trunk/test_utils.py index 96dfa5859b8..5f7a7aa8520 100644 --- a/neutron/tests/unit/services/trunk/test_utils.py +++ b/neutron/tests/unit/services/trunk/test_utils.py @@ -20,50 +20,49 @@ from neutron.tests.unit.services.trunk import fakes class UtilsTestCase(test_plugin.Ml2PluginV2TestCase): - def test_are_agent_types_available_on_host_returns_false(self): + def test_get_agent_types_by_host_returns_empty(self): self.assertFalse( - utils.are_agent_types_available_on_host( - self.context, ['foo_type'], 'foo_host')) + utils.get_agent_types_by_host( + self.context, 'foo_host')) - def test_are_agent_types_available_on_host_returns_true(self): + def test_get_agent_types_by_host_returns_agents(self): with mock.patch("neutron.db.agents_db.AgentDbMixin.get_agents") as f: - f.return_value = ['foo_agent'] - self.assertTrue( - utils.are_agent_types_available_on_host( - self.context, ['foo_type'], 'foo_host')) + f.return_value = [{'agent_type': 'foo_type'}] + self.assertEqual( + ['foo_type'], + utils.get_agent_types_by_host( + self.context, 'foo_host')) - def _test_is_driver_compatible(self, driver, interface, host, agents=None): - with mock.patch("neutron.db.agents_db.AgentDbMixin.get_agents") as f: - f.return_value = agents or [] - return utils.is_driver_compatible(self.context, - driver, - interface, - host) + def _test_is_driver_compatible(self, driver, interface, agent_types): + return utils.is_driver_compatible(self.context, + driver, + interface, + agent_types) def test_is_driver_compatible(self): driver = fakes.FakeDriverWithAgent.create() self.assertTrue(self._test_is_driver_compatible( - driver, 'foo_intfs', 'foo_host', [{'agent_type': 'foo_type'}])) + driver, 'foo_intfs', ['foo_type'])) def test_is_driver_compatible_agent_based_agent_mismatch(self): driver = fakes.FakeDriverWithAgent.create() self.assertFalse(self._test_is_driver_compatible( - driver, 'foo_intfs', 'foo_host')) + driver, 'foo_intfs', ['foo_type_unknown'])) def test_is_driver_incompatible_because_of_interface_mismatch(self): driver = fakes.FakeDriverWithAgent.create() self.assertFalse(self._test_is_driver_compatible( - driver, 'not_my_interface', 'foo_host')) + driver, 'not_my_interface', ['foo_type'])) def test_is_driver_compatible_agentless(self): driver = fakes.FakeDriver.create() self.assertTrue(self._test_is_driver_compatible( - driver, 'foo_intfs', 'foo_host')) + driver, 'foo_intfs', ['foo_type'])) def test_is_driver_compatible_multiple_drivers(self): driver1 = fakes.FakeDriverWithAgent.create() driver2 = fakes.FakeDriver2.create() self.assertTrue(self._test_is_driver_compatible( - driver1, 'foo_intfs', 'foo_host', [{'agent_type': 'foo_type'}])) + driver1, 'foo_intfs', ['foo_type'])) self.assertFalse(self._test_is_driver_compatible( - driver2, 'foo_intfs', 'foo_host', [{'agent_type': 'foo_type'}])) + driver2, 'foo_intfs', ['foo_type']))