Merge "[OVN] Provide HA functionality to "Logical_Router" chassis pinning"
This commit is contained in:
commit
019294c71d
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user