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)
|
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):
|
class OvnDbNotifyHandler(row_event.RowEventHandler):
|
||||||
def __init__(self, driver):
|
def __init__(self, driver):
|
||||||
self.driver = driver
|
self.driver = driver
|
||||||
@ -815,12 +862,14 @@ class OvnNbIdl(OvnIdlDistributedLock):
|
|||||||
self._lsp_lrp_event = (
|
self._lsp_lrp_event = (
|
||||||
LogicalSwitchPortUpdateLogicalRouterPortEvent(driver))
|
LogicalSwitchPortUpdateLogicalRouterPortEvent(driver))
|
||||||
self._fip_create_delete_event = FIPAddDeleteEvent(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.notify_handler.watch_events([self._lsp_create_event,
|
||||||
self._lsp_update_up_event,
|
self._lsp_update_up_event,
|
||||||
self._lsp_update_down_event,
|
self._lsp_update_down_event,
|
||||||
self._fip_create_delete_event,
|
self._fip_create_delete_event,
|
||||||
self._lsp_lrp_event,
|
self._lsp_lrp_event,
|
||||||
|
self._ha_chassis_group_event,
|
||||||
])
|
])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -32,6 +32,7 @@ from ovsdbapp.backend.ovs_idl import idlutils
|
|||||||
import tenacity
|
import tenacity
|
||||||
|
|
||||||
from neutron.common.ovn import constants as ovn_const
|
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.common import utils as n_utils
|
||||||
from neutron.conf.plugins.ml2.drivers.ovn import ovn_conf
|
from neutron.conf.plugins.ml2.drivers.ovn import ovn_conf
|
||||||
from neutron.db import ovn_hash_ring_db as db_hash_ring
|
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]),
|
lambda: self._check_port_host_set(vip['id'], hosts[idx]),
|
||||||
timeout=10)
|
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):
|
class TestNBDbMonitorOverTcp(TestNBDbMonitor):
|
||||||
def get_ovsdb_server_protocol(self):
|
def get_ovsdb_server_protocol(self):
|
||||||
|
@ -74,3 +74,11 @@ class WaitForCreatePortBindingEventPerType(event.WaitEvent):
|
|||||||
timeout=5):
|
timeout=5):
|
||||||
super().__init__((self.ROW_CREATE,), 'Port_Binding',
|
super().__init__((self.ROW_CREATE,), 'Port_Binding',
|
||||||
(('type', '=', port_type),), timeout=timeout)
|
(('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