Reduce DB hit when checking for trunk-able ports
We can hit the DB once to fetch all agent types for the host rather than going back and forth for all the drivers available in the deployment. That lets us save N-1 queries where N is the number of drivers installed. Change-Id: I5db0d73245b4e1c1bc46c063c0689ac3c5ea2bea
This commit is contained in:
@@ -105,10 +105,11 @@ class TrunkPortValidator(object):
|
|||||||
# can be determined based on the vif type, whether or not the
|
# can be determined based on the vif type, whether or not the
|
||||||
# driver is agent-based, and whether the host is running the agent
|
# driver is agent-based, and whether the host is running the agent
|
||||||
# associated to the driver itself.
|
# associated to the driver itself.
|
||||||
|
host_agent_types = utils.get_agent_types_by_host(context, binding_host)
|
||||||
drivers = [
|
drivers = [
|
||||||
driver for driver in trunk_plugin.registered_drivers
|
driver for driver in trunk_plugin.registered_drivers
|
||||||
if utils.is_driver_compatible(
|
if utils.is_driver_compatible(
|
||||||
context, driver, vif_type, binding_host)
|
context, driver, vif_type, host_agent_types)
|
||||||
]
|
]
|
||||||
if len(drivers) > 1:
|
if len(drivers) > 1:
|
||||||
raise trunk_exc.TrunkPluginDriverConflict()
|
raise trunk_exc.TrunkPluginDriverConflict()
|
||||||
|
|||||||
@@ -24,18 +24,19 @@ def gen_trunk_br_name(trunk_id):
|
|||||||
[:constants.DEVICE_NAME_MAX_LEN - 1])
|
[:constants.DEVICE_NAME_MAX_LEN - 1])
|
||||||
|
|
||||||
|
|
||||||
def are_agent_types_available_on_host(context, agent_types, host):
|
def get_agent_types_by_host(context, host):
|
||||||
"""Return true if agent types are present on the host."""
|
"""Return the agent types registered on the host."""
|
||||||
|
agent_types = []
|
||||||
core_plugin = manager.NeutronManager.get_plugin()
|
core_plugin = manager.NeutronManager.get_plugin()
|
||||||
if utils.is_extension_supported(core_plugin, 'agent'):
|
if utils.is_extension_supported(core_plugin, 'agent'):
|
||||||
return bool(core_plugin.get_agents(
|
agents = core_plugin.get_agents(
|
||||||
context.elevated(),
|
context.elevated(), filters={'host': [host]})
|
||||||
filters={'host': [host], 'agent_type': agent_types}))
|
agent_types = [a['agent_type'] for a in agents]
|
||||||
return False
|
return agent_types
|
||||||
|
|
||||||
|
|
||||||
def is_driver_compatible(context, driver, interface, binding_host):
|
def is_driver_compatible(context, driver, interface, host_agent_types):
|
||||||
"""Return true if the driver is compatible with the interface and host.
|
"""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
|
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.
|
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
|
return is_interface_compatible
|
||||||
|
|
||||||
# For an agent-based driver, both interface and agent compat is required.
|
# For an agent-based driver, both interface and agent compat is required.
|
||||||
return (
|
return is_interface_compatible and driver.agent_type in host_agent_types
|
||||||
is_interface_compatible and
|
|
||||||
are_agent_types_available_on_host(
|
|
||||||
context, [driver.agent_type], binding_host))
|
|
||||||
|
|||||||
@@ -20,50 +20,49 @@ from neutron.tests.unit.services.trunk import fakes
|
|||||||
|
|
||||||
class UtilsTestCase(test_plugin.Ml2PluginV2TestCase):
|
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(
|
self.assertFalse(
|
||||||
utils.are_agent_types_available_on_host(
|
utils.get_agent_types_by_host(
|
||||||
self.context, ['foo_type'], 'foo_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:
|
with mock.patch("neutron.db.agents_db.AgentDbMixin.get_agents") as f:
|
||||||
f.return_value = ['foo_agent']
|
f.return_value = [{'agent_type': 'foo_type'}]
|
||||||
self.assertTrue(
|
self.assertEqual(
|
||||||
utils.are_agent_types_available_on_host(
|
['foo_type'],
|
||||||
self.context, ['foo_type'], 'foo_host'))
|
utils.get_agent_types_by_host(
|
||||||
|
self.context, 'foo_host'))
|
||||||
|
|
||||||
def _test_is_driver_compatible(self, driver, interface, host, agents=None):
|
def _test_is_driver_compatible(self, driver, interface, agent_types):
|
||||||
with mock.patch("neutron.db.agents_db.AgentDbMixin.get_agents") as f:
|
return utils.is_driver_compatible(self.context,
|
||||||
f.return_value = agents or []
|
driver,
|
||||||
return utils.is_driver_compatible(self.context,
|
interface,
|
||||||
driver,
|
agent_types)
|
||||||
interface,
|
|
||||||
host)
|
|
||||||
|
|
||||||
def test_is_driver_compatible(self):
|
def test_is_driver_compatible(self):
|
||||||
driver = fakes.FakeDriverWithAgent.create()
|
driver = fakes.FakeDriverWithAgent.create()
|
||||||
self.assertTrue(self._test_is_driver_compatible(
|
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):
|
def test_is_driver_compatible_agent_based_agent_mismatch(self):
|
||||||
driver = fakes.FakeDriverWithAgent.create()
|
driver = fakes.FakeDriverWithAgent.create()
|
||||||
self.assertFalse(self._test_is_driver_compatible(
|
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):
|
def test_is_driver_incompatible_because_of_interface_mismatch(self):
|
||||||
driver = fakes.FakeDriverWithAgent.create()
|
driver = fakes.FakeDriverWithAgent.create()
|
||||||
self.assertFalse(self._test_is_driver_compatible(
|
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):
|
def test_is_driver_compatible_agentless(self):
|
||||||
driver = fakes.FakeDriver.create()
|
driver = fakes.FakeDriver.create()
|
||||||
self.assertTrue(self._test_is_driver_compatible(
|
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):
|
def test_is_driver_compatible_multiple_drivers(self):
|
||||||
driver1 = fakes.FakeDriverWithAgent.create()
|
driver1 = fakes.FakeDriverWithAgent.create()
|
||||||
driver2 = fakes.FakeDriver2.create()
|
driver2 = fakes.FakeDriver2.create()
|
||||||
self.assertTrue(self._test_is_driver_compatible(
|
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(
|
self.assertFalse(self._test_is_driver_compatible(
|
||||||
driver2, 'foo_intfs', 'foo_host', [{'agent_type': 'foo_type'}]))
|
driver2, 'foo_intfs', ['foo_type']))
|
||||||
|
|||||||
Reference in New Issue
Block a user