Merge "[OVN] Provide HA functionality to "Logical_Router" chassis pinning"

This commit is contained in:
Zuul 2024-04-11 11:01:43 +00:00 committed by Gerrit Code Review
commit 019294c71d
3 changed files with 108 additions and 0 deletions

View File

@ -662,6 +662,53 @@ class FIPAddDeleteEvent(row_event.RowEvent):
self.driver.delete_mac_binding_entries(row.external_ip)
class HAChassisGroupRouterEvent(row_event.RowEvent):
"""Row update event - the HA_Chassis list changes in a router HCG
When the HA_Chassis list changes (a chassis has been added, deleted or
updated), those routers with a HA_Chassis_Group related should update the
"LR.options.chassis" value.
"""
def __init__(self, driver):
self.driver = driver
table = 'HA_Chassis_Group'
events = (self.ROW_UPDATE,)
super().__init__(events, table, None)
self.event_name = 'HAChassisGroupRouterEvent'
def match_fn(self, event, row, old):
if ovn_const.OVN_ROUTER_ID_EXT_ID_KEY not in row.external_ids:
# "HA_Chassis_Group" not assigned to a router.
return False
elif getattr(old, 'ha_chassis', None) is None:
# No changes in the "ha_chassis" list has been done.
return False
return True
def run(self, event, row, old):
router_id = row.external_ids[ovn_const.OVN_ROUTER_ID_EXT_ID_KEY]
router_name = utils.ovn_name(router_id)
if not row.ha_chassis:
# No GW chassis are present in the environment.
self.driver.nb_ovn.db_remove(
'Logical_Router', router_name, 'options', 'chassis',
if_exists=True).execute(check_error=True)
LOG.info('Router %s is not pinned to any gateway chassis',
router_id)
return
highest_prio_hc = None
for hc in row.ha_chassis:
if not highest_prio_hc or hc.priority > highest_prio_hc.priority:
highest_prio_hc = hc
options = {'chassis': highest_prio_hc.chassis_name}
self.driver.nb_ovn.db_set(
'Logical_Router', router_name, ('options', options)).execute(
check_error=True)
class OvnDbNotifyHandler(row_event.RowEventHandler):
def __init__(self, driver):
self.driver = driver
@ -815,12 +862,14 @@ class OvnNbIdl(OvnIdlDistributedLock):
self._lsp_lrp_event = (
LogicalSwitchPortUpdateLogicalRouterPortEvent(driver))
self._fip_create_delete_event = FIPAddDeleteEvent(driver)
self._ha_chassis_group_event = HAChassisGroupRouterEvent(driver)
self.notify_handler.watch_events([self._lsp_create_event,
self._lsp_update_up_event,
self._lsp_update_down_event,
self._fip_create_delete_event,
self._lsp_lrp_event,
self._ha_chassis_group_event,
])
@classmethod

View File

@ -32,6 +32,7 @@ from ovsdbapp.backend.ovs_idl import idlutils
import tenacity
from neutron.common.ovn import constants as ovn_const
from neutron.common.ovn import utils as ovn_utils
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
@ -524,6 +525,56 @@ class TestNBDbMonitor(base.TestOVNFunctionalBase):
lambda: self._check_port_host_set(vip['id'], hosts[idx]),
timeout=10)
def _create_router(self):
net_args = {external_net.EXTERNAL: True,
provider_net.NETWORK_TYPE: 'geneve'}
net = self._make_network(self.fmt, 'e1', True, as_admin=True,
arg_list=tuple(net_args.keys()), **net_args)
res = self._create_subnet(self.fmt, net['network']['id'],
'120.0.0.0/24')
subnet = self.deserialize(self.fmt, res)
external_gateway_info = {
'enable_snat': True, 'network_id': net['network']['id'],
'external_fixed_ips': [{'ip_address': '120.0.0.2',
'subnet_id': subnet['subnet']['id']}]}
router = self.l3_plugin.create_router(
self.context,
{'router': {'name': uuidutils.generate_uuid(),
'admin_state_up': True, 'tenant_id': self._tenant_id,
'external_gateway_info': external_gateway_info}})
return router
def test_ha_chassis_group_router_event(self):
def _check_high_prio_chassis(num_chassis):
lr = self.nb_api.lookup('Logical_Router', ovn_r_name)
hp_chassis_lr = lr.options['chassis']
hcg = self.nb_api.lookup('HA_Chassis_Group', ovn_r_name)
self.assertEqual(num_chassis, len(hcg.ha_chassis))
hp_chassis_hcg = None
for hc in hcg.ha_chassis:
if not hp_chassis_hcg or hc.priority > hp_chassis_hcg.priority:
hp_chassis_hcg = hc
self.assertEqual(hp_chassis_lr, hp_chassis_hcg.chassis_name)
chassis_list = []
num_chassis = 5
for idx in range(num_chassis):
chassis_list.append(
self.add_fake_chassis('host-%s' % str(idx), azs=[],
enable_chassis_as_gw=True))
router = self._create_router()
ovn_r_name = ovn_utils.ovn_name(router['id'])
_check_high_prio_chassis(len(chassis_list))
lr = self.nb_api.lookup('Logical_Router', ovn_r_name)
row_event = test_events.WaitForLogicalRouterUpdate()
self.mech_driver.nb_ovn.idl.notify_handler.watch_event(row_event)
self.del_fake_chassis(lr.options['chassis'])
self.assertTrue(row_event.wait())
_check_high_prio_chassis(num_chassis - 1)
class TestNBDbMonitorOverTcp(TestNBDbMonitor):
def get_ovsdb_server_protocol(self):

View File

@ -74,3 +74,11 @@ class WaitForCreatePortBindingEventPerType(event.WaitEvent):
timeout=5):
super().__init__((self.ROW_CREATE,), 'Port_Binding',
(('type', '=', port_type),), timeout=timeout)
class WaitForLogicalRouterUpdate(event.WaitEvent):
event_name = 'WaitForLogicalRouterUpdate'
def __init__(self):
super().__init__((self.ROW_UPDATE,), 'Logical_Router', None,
timeout=30)