diff --git a/neutron/plugins/ml2/drivers/ovn/agent/neutron_agent.py b/neutron/plugins/ml2/drivers/ovn/agent/neutron_agent.py index 4282f568837..23960424288 100644 --- a/neutron/plugins/ml2/drivers/ovn/agent/neutron_agent.py +++ b/neutron/plugins/ml2/drivers/ovn/agent/neutron_agent.py @@ -140,10 +140,23 @@ class ControllerAgent(NeutronAgent): return self.chassis_private.external_ids.get( ovn_const.OVN_AGENT_DESC_KEY, '') + def update(self, chassis_private, updated_at=None, clear_down=False): + super().update(chassis_private, updated_at, clear_down) + external_ids = self.chassis_from_private(chassis_private).external_ids + if 'enable-chassis-as-gw' in external_ids.get('ovn-cms-options', []): + self.__class__ = ControllerGatewayAgent + class ControllerGatewayAgent(ControllerAgent): agent_type = ovn_const.OVN_CONTROLLER_GW_AGENT + def update(self, chassis_private, updated_at=None, clear_down=False): + super().update(chassis_private, updated_at, clear_down) + external_ids = self.chassis_from_private(chassis_private).external_ids + if ('enable-chassis-as-gw' not in + external_ids.get('ovn-cms-options', [])): + self.__class__ = ControllerAgent + class MetadataAgent(NeutronAgent): agent_type = ovn_const.OVN_METADATA_AGENT diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovsdb_monitor.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovsdb_monitor.py index d1df24f8e4a..f26711e322c 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovsdb_monitor.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovsdb_monitor.py @@ -334,6 +334,24 @@ class ChassisAgentWriteEvent(ChassisAgentEvent): clear_down=event == self.ROW_CREATE) +class ChassisAgentTypeChangeEvent(ChassisEvent): + """Chassis Agent class change event""" + GLOBAL = True + events = (BaseEvent.ROW_UPDATE,) + + def match_fn(self, event, row, old=None): + if not getattr(old, 'external_ids', False): + return False + agent_type_change = n_agent.NeutronAgent.chassis_from_private( + row).external_ids.get('ovn-cms-options', []) != ( + old.external_ids.get('ovn-cms-options', [])) + return agent_type_change + + def run(self, event, row, old): + n_agent.AgentCache().update(ovn_const.OVN_CONTROLLER_AGENT, row, + clear_down=event == self.ROW_CREATE) + + class ChassisMetadataAgentWriteEvent(ChassisAgentEvent): events = (BaseEvent.ROW_CREATE, BaseEvent.ROW_UPDATE) @@ -705,6 +723,7 @@ class OvnSbIdl(OvnIdlDistributedLock): ChassisAgentDeleteEvent(self.driver), ChassisAgentDownEvent(self.driver), ChassisAgentWriteEvent(self.driver), + ChassisAgentTypeChangeEvent(self.driver), ChassisMetadataAgentWriteEvent(self.driver)]) @classmethod diff --git a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovsdb_monitor.py b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovsdb_monitor.py index 2763430edc4..d40f7b9ec72 100644 --- a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovsdb_monitor.py +++ b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovsdb_monitor.py @@ -21,6 +21,7 @@ from neutron.common.ovn import constants as ovn_const from neutron.common import utils as n_utils from neutron.conf.plugins.ml2.drivers.ovn import ovn_conf from neutron.db import ovn_hash_ring_db as db_hash_ring +from neutron.plugins.ml2.drivers.ovn.agent import neutron_agent from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb import ovsdb_monitor from neutron.tests.functional import base from neutron.tests.functional.resources.ovsdb import fixtures @@ -286,6 +287,38 @@ class TestNBDbMonitorOverSsl(TestNBDbMonitor): return 'ssl' +class TestAgentMonitor(base.TestOVNFunctionalBase): + FAKE_CHASSIS_HOST = 'fake-chassis-host' + + def setUp(self): + super(TestAgentMonitor, self).setUp() + self.l3_plugin = directory.get_plugin(plugin_constants.L3) + self.mock_ovsdb_idl = mock.Mock() + self.handler = self.sb_api.idl.notify_handler + self.mock_ovsdb_idl = mock.Mock() + self.chassis_name = self.add_fake_chassis(self.FAKE_CHASSIS_HOST, + external_ids={'ovn-cms-options': 'enable-chassis-as-gw'}) + + def test_network_agent_present(self): + chassis_row = self.sb_api.db_find( + 'Chassis', ('name', '=', self.chassis_name)).execute( + check_error=True) + self.assertTrue(chassis_row) + self.assertEqual(neutron_agent.ControllerGatewayAgent, + type(neutron_agent.AgentCache()[self.chassis_name])) + + def test_agent_change_controller(self): + self.assertEqual(neutron_agent.ControllerGatewayAgent, + type(neutron_agent.AgentCache()[self.chassis_name])) + self.sb_api.db_set('Chassis', self.chassis_name, ('external_ids', + {'ovn-cms-options': ''})).execute(check_error=True) + n_utils.wait_until_true(lambda: + neutron_agent.AgentCache()[self.chassis_name]. + chassis.external_ids['ovn-cms-options'] == '') + self.assertEqual(neutron_agent.ControllerAgent, + type(neutron_agent.AgentCache()[self.chassis_name])) + + class TestOvnIdlProbeInterval(base.TestOVNFunctionalBase): def setUp(self): # We need an OvsdbServer that uses TCP because probe_interval is always