Merge "[OVN] Sync the LRP Gateway_Chassis with the network HCG"
This commit is contained in:
@@ -89,6 +89,15 @@ class ChassisEvent(row_event.RowEvent):
|
||||
'HA_Chassis_Group').execute(check_error=True):
|
||||
if not hcg.name.startswith(ovn_const.OVN_NAME_PREFIX):
|
||||
continue
|
||||
|
||||
net_id = hcg.external_ids.get(ovn_const.OVN_NETWORK_ID_EXT_ID_KEY)
|
||||
router_id = hcg.external_ids.get(
|
||||
ovn_const.OVN_ROUTER_ID_EXT_ID_KEY)
|
||||
if net_id and router_id:
|
||||
# This HA_Chassis_Group is linked to a router, it will be
|
||||
# updated matching the router Gateway_Chassis registers.
|
||||
continue
|
||||
|
||||
# The filter() is to get rid of the empty string in
|
||||
# the list that is returned because of split()
|
||||
azs = {az for az in
|
||||
|
||||
@@ -75,3 +75,32 @@ class LogicalRouterPortEvent(row_event.RowEvent):
|
||||
else: # LRP gateway port.
|
||||
self.l3_plugin._ovn_client.update_router_ha_chassis_group(
|
||||
self.admin_context, router_id)
|
||||
|
||||
|
||||
class LogicalRouterPortGatewayChassisEvent(row_event.RowEvent):
|
||||
"""Logical_Router_Port Gateway_Chassis change event.
|
||||
|
||||
When the Gateway_Chassis list of a Logical_Router_Port changes, it is
|
||||
needed to update the linked HA_Chassis_Group registers.
|
||||
"""
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.l3_plugin = directory.get_plugin(constants.L3)
|
||||
self.admin_context = neutron_context.get_admin_context()
|
||||
table = 'Logical_Router_Port'
|
||||
events = (self.ROW_UPDATE, )
|
||||
super().__init__(events, table, None)
|
||||
|
||||
def match_fn(self, event, row, old):
|
||||
if hasattr(old, 'gateway_chassis'):
|
||||
# NOTE: when a Gateway_Chassis register is deleted, is no longer
|
||||
# present in the old.gateway_chassis list.
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def run(self, event, row, old=None):
|
||||
lr_name = row.external_ids.get(ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY)
|
||||
router_id = utils.get_neutron_name(lr_name)
|
||||
self.l3_plugin._ovn_client.update_router_ha_chassis_group(
|
||||
self.admin_context, router_id)
|
||||
|
||||
@@ -179,6 +179,7 @@ class OVNL3RouterPlugin(service_base.ServicePluginBase,
|
||||
# Register needed events.
|
||||
self._nb_ovn.idl.notify_handler.watch_events([
|
||||
ovsdb_monitor.LogicalRouterPortEvent(self),
|
||||
ovsdb_monitor.LogicalRouterPortGatewayChassisEvent(self),
|
||||
])
|
||||
|
||||
def _add_neutron_router_interface(self, context, router_id,
|
||||
|
||||
@@ -18,6 +18,7 @@ from neutron_lib.api.definitions import external_net
|
||||
from neutron_lib.plugins import constants as plugin_constants
|
||||
from neutron_lib.plugins import directory
|
||||
|
||||
from neutron.common.ovn import utils as ovn_utils
|
||||
from neutron.common import utils as n_utils
|
||||
from neutron.tests.functional import base
|
||||
from neutron.tests.unit.api import test_extensions
|
||||
@@ -101,3 +102,80 @@ class TestLogicalRouterPortEvent(
|
||||
self._router_interface_action(
|
||||
'remove', self.router_id, self.subnet_id, None)
|
||||
n_utils.wait_until_true(is_called, timeout=10)
|
||||
|
||||
def test_delete_router(self):
|
||||
# The ``Logical_Router`` deletion triggers the
|
||||
# ``LogicalRouterPortEvent`` event, but nothing is executed/called.
|
||||
def is_called():
|
||||
try:
|
||||
mock_update_router.assert_called_once_with(
|
||||
mock.ANY, self.router_id)
|
||||
return True
|
||||
except AssertionError:
|
||||
return False
|
||||
|
||||
with mock.patch.object(
|
||||
self.l3_plugin._ovn_client,
|
||||
'update_router_ha_chassis_group') as mock_update_router:
|
||||
self._add_external_gateway_to_router(self.router_id,
|
||||
self.net_ext_id)
|
||||
n_utils.wait_until_true(is_called, timeout=10)
|
||||
mock_update_router.reset_mock()
|
||||
req = self.new_delete_request('routers', self.router_id)
|
||||
req.get_response(self.api)
|
||||
self.assertRaises(n_utils.WaitTimeout, n_utils.wait_until_true,
|
||||
is_called, timeout=5)
|
||||
|
||||
|
||||
class TestLogicalRouterPortGatewayChassisEvent(
|
||||
base.TestOVNFunctionalBase,
|
||||
test_l3.L3NatTestCaseMixin):
|
||||
|
||||
def setUp(self, **kwargs):
|
||||
super().setUp(**kwargs)
|
||||
self.chassis = self.add_fake_chassis('ovs-host1')
|
||||
self.l3_plugin = directory.get_plugin(plugin_constants.L3)
|
||||
self.l3_plugin._post_fork_initialize(mock.ANY, mock.ANY, mock.ANY)
|
||||
self.ext_api = test_extensions.setup_extensions_middleware(
|
||||
test_l3.L3TestExtensionManager())
|
||||
kwargs = {'arg_list': (external_net.EXTERNAL,),
|
||||
external_net.EXTERNAL: True}
|
||||
self.net_ext = self._make_network(
|
||||
self.fmt, 'net_ext', True, as_admin=True, **kwargs)
|
||||
self.subnet = self._make_subnet(self.fmt, self.net_ext, '20.0.10.1',
|
||||
'20.0.10.0/24')
|
||||
self.router = self._make_router(self.fmt, self._tenant_id)
|
||||
self.router_id = self.router['router']['id']
|
||||
self.net_ext_id = self.net_ext['network']['id']
|
||||
self.subnet_id = self.subnet['subnet']['id']
|
||||
|
||||
def test_add_and_remove_gateway_chassis(self):
|
||||
def is_called():
|
||||
try:
|
||||
mock_update_router.assert_called_once_with(
|
||||
mock.ANY, self.router_id)
|
||||
return True
|
||||
except AssertionError:
|
||||
return False
|
||||
|
||||
ch_list = []
|
||||
for idx in range(5):
|
||||
ch_list.append(self.add_fake_chassis(f'host-{idx}'))
|
||||
self._add_external_gateway_to_router(self.router_id, self.net_ext_id)
|
||||
lr = self.l3_plugin._nb_ovn.lookup('Logical_Router',
|
||||
ovn_utils.ovn_name(self.router_id))
|
||||
lrp_gw = lr.ports[0]
|
||||
with mock.patch.object(
|
||||
self.l3_plugin._ovn_client,
|
||||
'update_router_ha_chassis_group') as mock_update_router:
|
||||
for ch_name in ch_list:
|
||||
self.l3_plugin._nb_ovn.lrp_set_gateway_chassis(
|
||||
lrp_gw.uuid, ch_name).execute(check_error=True)
|
||||
n_utils.wait_until_true(is_called, timeout=10)
|
||||
mock_update_router.reset_mock()
|
||||
|
||||
for ch_name in ch_list:
|
||||
self.l3_plugin._nb_ovn.lrp_del_gateway_chassis(
|
||||
lrp_gw.uuid, ch_name).execute(check_error=True)
|
||||
n_utils.wait_until_true(is_called, timeout=10)
|
||||
mock_update_router.reset_mock()
|
||||
|
||||
Reference in New Issue
Block a user