[OVN] Remove OVN_GATEWAY_INVALID_CHASSIS artifact
This artifact is no longer used in the "Logical_Router" registers (in the "options" field) to mark this "Logical_Router" as unhosted. A "Logical_Router" is considered as unhosted if the gateway "Logical_Router_Ports" have no "chassis" set. This artifact is also used to create a "Gateway_Chassis" register pointing to a inexisting invalid chassis called "neutron-ovn-invalid-chassis". Any "Logical_Router_Port" not bound to a chassis will have no value in "gateway_chassis" (NOTE1). NOTE1: this is valid now with the current two OVN L3 schedulers that use "gateway_chassis" to schedule the "Logical_Router_Port" of a router. In a future, we can consider using "ha_chassis_group" for scheduling. Partial-Bug: #2052821 Related-Bug: #2019217 Change-Id: I12717936fe2bc188545309bacb8a260981f14c88
This commit is contained in:
parent
f73a2515cb
commit
fa3223bb9d
@ -26,10 +26,9 @@ The maximum number of ``Gateway_Chassis`` that can be assigned to a
|
|||||||
the highest priority a ``Gateway_Chassis`` will have is 5.
|
the highest priority a ``Gateway_Chassis`` will have is 5.
|
||||||
|
|
||||||
If no gateway chassis are available during the ``Logical_Router_Port``
|
If no gateway chassis are available during the ``Logical_Router_Port``
|
||||||
scheduling, no ``Gateway_Chassis`` will be assigned and the value
|
scheduling, no ``Gateway_Chassis`` will be assigned and no value will be set
|
||||||
"neutron-ovn-invalid-chassis" will be set in the "options" column of the
|
in the "options" column of the ``Logical_Router`` register; that will be used
|
||||||
``Logical_Router`` register; that value will be used to detect an unhosted
|
to detect an unhosted router gateway port.
|
||||||
router gateway port.
|
|
||||||
|
|
||||||
|
|
||||||
Types of schedulers
|
Types of schedulers
|
||||||
@ -88,7 +87,7 @@ Both the ``OVNGatewayChanceScheduler`` and the
|
|||||||
``OVNGatewayLeastLoadedScheduler`` schedulers have the Availability Zones (AZ)
|
``OVNGatewayLeastLoadedScheduler`` schedulers have the Availability Zones (AZ)
|
||||||
in consideration. If a router has any AZ defined, the schedulers will select
|
in consideration. If a router has any AZ defined, the schedulers will select
|
||||||
only those chassis located in the AZs. If no chassis meets this condition, the
|
only those chassis located in the AZs. If no chassis meets this condition, the
|
||||||
``Logical_Router_Port`` will be assigned to the "neutron-ovn-invalid-chassis".
|
``Logical_Router_Port`` won't be assigned to any chassis and won't be bound.
|
||||||
|
|
||||||
Once the list of candidate ``Chassis`` (depending on the scheduler selected)
|
Once the list of candidate ``Chassis`` (depending on the scheduler selected)
|
||||||
is created, this list is reordered to prioritize these ``Chassis`` from
|
is created, this list is reordered to prioritize these ``Chassis`` from
|
||||||
|
@ -109,12 +109,6 @@ ACL_ACTION_ALLOW_RELATED = 'allow-related'
|
|||||||
ACL_ACTION_ALLOW_STATELESS = 'allow-stateless'
|
ACL_ACTION_ALLOW_STATELESS = 'allow-stateless'
|
||||||
ACL_ACTION_ALLOW = 'allow'
|
ACL_ACTION_ALLOW = 'allow'
|
||||||
|
|
||||||
# When a OVN L3 gateway is created, it needs to be bound to a chassis. In
|
|
||||||
# case a chassis is not found OVN_GATEWAY_INVALID_CHASSIS will be set in
|
|
||||||
# the options column of the Logical Router. This value is used to detect
|
|
||||||
# unhosted router gateways to schedule.
|
|
||||||
OVN_GATEWAY_INVALID_CHASSIS = 'neutron-ovn-invalid-chassis'
|
|
||||||
|
|
||||||
# NOTE(lucasagomes): These options were last synced from
|
# NOTE(lucasagomes): These options were last synced from
|
||||||
# https://github.com/ovn-org/ovn/blob/feb5d6e81d5a0290aa3618a229c860d01200422e/lib/ovn-l7.h
|
# https://github.com/ovn-org/ovn/blob/feb5d6e81d5a0290aa3618a229c860d01200422e/lib/ovn-l7.h
|
||||||
#
|
#
|
||||||
|
@ -669,10 +669,7 @@ def is_gateway_chassis_invalid(chassis_name, gw_chassis,
|
|||||||
@type chassis_with_azs: {}
|
@type chassis_with_azs: {}
|
||||||
@return Boolean
|
@return Boolean
|
||||||
"""
|
"""
|
||||||
|
if chassis_name not in chassis_physnets:
|
||||||
if chassis_name == constants.OVN_GATEWAY_INVALID_CHASSIS:
|
|
||||||
return True
|
|
||||||
elif chassis_name not in chassis_physnets:
|
|
||||||
return True
|
return True
|
||||||
elif physnet and physnet not in chassis_physnets.get(chassis_name):
|
elif physnet and physnet not in chassis_physnets.get(chassis_name):
|
||||||
return True
|
return True
|
||||||
|
@ -412,10 +412,9 @@ class ScheduleNewGatewayCommand(command.BaseCommand):
|
|||||||
chassis = self.scheduler.select(
|
chassis = self.scheduler.select(
|
||||||
self.api, self.sb_api, self.g_name, candidates=candidates,
|
self.api, self.sb_api, self.g_name, candidates=candidates,
|
||||||
target_lrouter=lrouter)
|
target_lrouter=lrouter)
|
||||||
|
if chassis:
|
||||||
setattr(
|
setattr(lrouter_port,
|
||||||
lrouter_port,
|
*_add_gateway_chassis(self.api, txn, self.g_name, chassis))
|
||||||
*_add_gateway_chassis(self.api, txn, self.g_name, chassis))
|
|
||||||
|
|
||||||
|
|
||||||
class AddLRouterPortCommand(command.BaseCommand):
|
class AddLRouterPortCommand(command.BaseCommand):
|
||||||
|
@ -551,8 +551,16 @@ class OvsdbNbOvnIdl(nb_impl_idl.OvnNbApiIdlImpl, Backend):
|
|||||||
|
|
||||||
def get_unhosted_gateways(self, port_physnet_dict, chassis_with_physnets,
|
def get_unhosted_gateways(self, port_physnet_dict, chassis_with_physnets,
|
||||||
all_gw_chassis, chassis_with_azs):
|
all_gw_chassis, chassis_with_azs):
|
||||||
|
"""Return the GW LRPs with no chassis assigned
|
||||||
|
|
||||||
|
If the LRP belongs to a tunnelled network (physnet=None), it won't be
|
||||||
|
hosted to any chassis.
|
||||||
|
"""
|
||||||
unhosted_gateways = set()
|
unhosted_gateways = set()
|
||||||
for port, physnet in port_physnet_dict.items():
|
for port, physnet in port_physnet_dict.items():
|
||||||
|
if not physnet:
|
||||||
|
continue
|
||||||
|
|
||||||
lrp_name = '%s%s' % (ovn_const.LRP_PREFIX, port)
|
lrp_name = '%s%s' % (ovn_const.LRP_PREFIX, port)
|
||||||
original_state = self.get_gateway_chassis_binding(lrp_name)
|
original_state = self.get_gateway_chassis_binding(lrp_name)
|
||||||
az_hints = self.get_gateway_chassis_az_hints(lrp_name)
|
az_hints = self.get_gateway_chassis_az_hints(lrp_name)
|
||||||
|
@ -29,6 +29,7 @@ from neutron_lib.exceptions import l3 as l3_exc
|
|||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
|
from oslo_utils import strutils
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
from ovsdbapp.backend.ovs_idl import event as row_event
|
from ovsdbapp.backend.ovs_idl import event as row_event
|
||||||
|
|
||||||
@ -1204,6 +1205,29 @@ class DBInconsistenciesPeriodics(SchemaAwarePeriodicsBase):
|
|||||||
|
|
||||||
raise periodics.NeverAgain()
|
raise periodics.NeverAgain()
|
||||||
|
|
||||||
|
# TODO(ralonsoh): Remove this method in the C+2 cycle (next SLURP release)
|
||||||
|
@has_lock_periodic(spacing=600, run_immediately=True)
|
||||||
|
def remove_invalid_gateway_chassis_from_unbound_lrp(self):
|
||||||
|
"""Removes all invalid 'Gateway_Chassis' from unbound LRPs"""
|
||||||
|
is_gw = ovn_const.OVN_ROUTER_IS_EXT_GW
|
||||||
|
lrp_list = []
|
||||||
|
for lr in self._nb_idl.lr_list().execute(check_error=True):
|
||||||
|
for lrp in self._nb_idl.lrp_list(lr.uuid).execute(
|
||||||
|
check_error=True):
|
||||||
|
if (is_gw in lrp.external_ids and
|
||||||
|
strutils.bool_from_string(lrp.external_ids[is_gw]) and
|
||||||
|
lrp.gateway_chassis and
|
||||||
|
lrp.gateway_chassis[0].chassis_name ==
|
||||||
|
'neutron-ovn-invalid-chassis'):
|
||||||
|
lrp_list.append(lrp)
|
||||||
|
|
||||||
|
with self._nb_idl.transaction(check_error=True) as txn:
|
||||||
|
for lrp in lrp_list:
|
||||||
|
txn.add(self._nb_idl.lrp_del_gateway_chassis(
|
||||||
|
lrp.uuid, 'neutron-ovn-invalid-chassis'))
|
||||||
|
|
||||||
|
raise periodics.NeverAgain()
|
||||||
|
|
||||||
|
|
||||||
class HashRingHealthCheckPeriodics(object):
|
class HashRingHealthCheckPeriodics(object):
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class OVNGatewayScheduler(object, metaclass=abc.ABCMeta):
|
|||||||
physnet, chassis_physnets,
|
physnet, chassis_physnets,
|
||||||
existing_chassis, az_hints, chassis_with_azs):
|
existing_chassis, az_hints, chassis_with_azs):
|
||||||
chassis_list = copy.copy(existing_chassis)
|
chassis_list = copy.copy(existing_chassis)
|
||||||
for chassis_name in existing_chassis:
|
for chassis_name in existing_chassis or []:
|
||||||
if utils.is_gateway_chassis_invalid(chassis_name, gw_chassis,
|
if utils.is_gateway_chassis_invalid(chassis_name, gw_chassis,
|
||||||
physnet, chassis_physnets,
|
physnet, chassis_physnets,
|
||||||
az_hints, chassis_with_azs):
|
az_hints, chassis_with_azs):
|
||||||
@ -73,7 +73,7 @@ class OVNGatewayScheduler(object, metaclass=abc.ABCMeta):
|
|||||||
if not candidates:
|
if not candidates:
|
||||||
LOG.warning('Gateway %s was not scheduled on any chassis, no '
|
LOG.warning('Gateway %s was not scheduled on any chassis, no '
|
||||||
'candidates are available', gateway_name)
|
'candidates are available', gateway_name)
|
||||||
return [ovn_const.OVN_GATEWAY_INVALID_CHASSIS]
|
return
|
||||||
chassis_count = min(
|
chassis_count = min(
|
||||||
ovn_const.MAX_GW_CHASSIS - len(existing_chassis),
|
ovn_const.MAX_GW_CHASSIS - len(existing_chassis),
|
||||||
len(candidates)
|
len(candidates)
|
||||||
@ -97,8 +97,7 @@ class OVNGatewayScheduler(object, metaclass=abc.ABCMeta):
|
|||||||
azs = set()
|
azs = set()
|
||||||
|
|
||||||
# Check if candidates list valid
|
# Check if candidates list valid
|
||||||
if not candidates or (
|
if not candidates:
|
||||||
candidates == [ovn_const.OVN_GATEWAY_INVALID_CHASSIS]):
|
|
||||||
return candidates
|
return candidates
|
||||||
|
|
||||||
chassis_with_azs = sb_idl.get_chassis_and_azs()
|
chassis_with_azs = sb_idl.get_chassis_and_azs()
|
||||||
|
@ -175,9 +175,9 @@ class _TestMaintenanceHelper(base.TestOVNFunctionalBase):
|
|||||||
res = req.get_response(self.api)
|
res = req.get_response(self.api)
|
||||||
return self.deserialize(self.fmt, res)['router']
|
return self.deserialize(self.fmt, res)['router']
|
||||||
|
|
||||||
def _update_router_name(self, net_id, new_name):
|
def _update_router(self, router_id, router_dict):
|
||||||
data = {'router': {'name': new_name}}
|
data = {'router': router_dict}
|
||||||
req = self.new_update_request('routers', data, net_id, self.fmt)
|
req = self.new_update_request('routers', data, router_id, self.fmt)
|
||||||
res = req.get_response(self.api)
|
res = req.get_response(self.api)
|
||||||
return self.deserialize(self.fmt, res)['router']
|
return self.deserialize(self.fmt, res)['router']
|
||||||
|
|
||||||
@ -591,8 +591,8 @@ class TestMaintenance(_TestMaintenanceHelper):
|
|||||||
|
|
||||||
new_obj_name = 'routertest_updated'
|
new_obj_name = 'routertest_updated'
|
||||||
with mock.patch.object(self._l3_ovn_client, 'update_router'):
|
with mock.patch.object(self._l3_ovn_client, 'update_router'):
|
||||||
new_neutron_obj = self._update_router_name(neutron_obj['id'],
|
new_neutron_obj = self._update_router(neutron_obj['id'],
|
||||||
new_obj_name)
|
{'name': new_obj_name})
|
||||||
|
|
||||||
# Assert the revision numbers are out-of-sync
|
# Assert the revision numbers are out-of-sync
|
||||||
ovn_obj = self._find_router_row_by_name(obj_name)
|
ovn_obj = self._find_router_row_by_name(obj_name)
|
||||||
@ -1190,6 +1190,36 @@ class TestMaintenance(_TestMaintenanceHelper):
|
|||||||
self.assertIn(router1['id'], pra_res_ids)
|
self.assertIn(router1['id'], pra_res_ids)
|
||||||
self.assertIn(router2['id'], pra_res_ids)
|
self.assertIn(router2['id'], pra_res_ids)
|
||||||
|
|
||||||
|
def test_remove_invalid_gateway_chassis_from_unbound_lrp(self):
|
||||||
|
net1 = self._create_network(uuidutils.generate_uuid(), external=True)
|
||||||
|
subnet1 = self._create_subnet(uuidutils.generate_uuid(), net1['id'])
|
||||||
|
external_gateway_info = {
|
||||||
|
'enable_snat': True, 'network_id': net1['id'],
|
||||||
|
'external_fixed_ips': [{'ip_address': '10.0.0.2',
|
||||||
|
'subnet_id': subnet1['id']}]}
|
||||||
|
router = self._create_router(
|
||||||
|
uuidutils.generate_uuid(),
|
||||||
|
external_gateway_info=external_gateway_info)
|
||||||
|
|
||||||
|
# Manually add the LRP.gateway_chassis with name
|
||||||
|
# 'neutron-ovn-invalid-chassis'
|
||||||
|
lr = self.nb_api.lookup('Logical_Router', utils.ovn_name(router['id']))
|
||||||
|
lrp = lr.ports[0]
|
||||||
|
self.nb_api.lrp_set_gateway_chassis(
|
||||||
|
lrp.uuid, 'neutron-ovn-invalid-chassis').execute(check_error=True)
|
||||||
|
gc = self.nb_api.db_find_rows(
|
||||||
|
'Gateway_Chassis',
|
||||||
|
('chassis_name', '=', 'neutron-ovn-invalid-chassis')).execute(
|
||||||
|
check_error=True)[0]
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
periodics.NeverAgain,
|
||||||
|
self.maint.remove_invalid_gateway_chassis_from_unbound_lrp)
|
||||||
|
self.assertIsNone(self.nb_api.lookup('Gateway_Chassis', gc.uuid,
|
||||||
|
default=None))
|
||||||
|
lr = self.nb_api.lookup('Logical_Router', utils.ovn_name(router['id']))
|
||||||
|
self.assertEqual([], lr.ports[0].gateway_chassis)
|
||||||
|
|
||||||
|
|
||||||
class TestLogMaintenance(_TestMaintenanceHelper,
|
class TestLogMaintenance(_TestMaintenanceHelper,
|
||||||
test_log_driver.LogApiTestCaseBase):
|
test_log_driver.LogApiTestCaseBase):
|
||||||
|
@ -20,6 +20,7 @@ import fixtures as og_fixtures
|
|||||||
from neutron_lib.api.definitions import allowedaddresspairs
|
from neutron_lib.api.definitions import allowedaddresspairs
|
||||||
from neutron_lib.api.definitions import external_net
|
from neutron_lib.api.definitions import external_net
|
||||||
from neutron_lib.api.definitions import portbindings
|
from neutron_lib.api.definitions import portbindings
|
||||||
|
from neutron_lib.api.definitions import provider_net
|
||||||
from neutron_lib.plugins import constants as plugin_constants
|
from neutron_lib.plugins import constants as plugin_constants
|
||||||
from neutron_lib.plugins import directory
|
from neutron_lib.plugins import directory
|
||||||
from oslo_concurrency import processutils
|
from oslo_concurrency import processutils
|
||||||
@ -517,8 +518,10 @@ class TestSBDbMonitor(base.TestOVNFunctionalBase, test_l3.L3NatTestCaseMixin):
|
|||||||
|
|
||||||
def setUp(self, **kwargs):
|
def setUp(self, **kwargs):
|
||||||
super().setUp(**kwargs)
|
super().setUp(**kwargs)
|
||||||
self.chassis = self.add_fake_chassis('ovs-host1',
|
self.physnet = 'public'
|
||||||
enable_chassis_as_gw=True)
|
self.chassis = self.add_fake_chassis(
|
||||||
|
'ovs-host1', physical_nets=[self.physnet],
|
||||||
|
enable_chassis_as_gw=True)
|
||||||
self.l3_plugin = directory.get_plugin(plugin_constants.L3)
|
self.l3_plugin = directory.get_plugin(plugin_constants.L3)
|
||||||
ext_mgr = test_l3.L3TestExtensionManager()
|
ext_mgr = test_l3.L3TestExtensionManager()
|
||||||
self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
|
self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
|
||||||
@ -545,10 +548,12 @@ class TestSBDbMonitor(base.TestOVNFunctionalBase, test_l3.L3NatTestCaseMixin):
|
|||||||
return True
|
return True
|
||||||
return lrp.external_ids == pb.external_ids
|
return lrp.external_ids == pb.external_ids
|
||||||
|
|
||||||
kwargs = {'arg_list': (external_net.EXTERNAL,),
|
arg_dict = {external_net.EXTERNAL: True,
|
||||||
external_net.EXTERNAL: True}
|
provider_net.NETWORK_TYPE: 'flat',
|
||||||
|
provider_net.PHYSICAL_NETWORK: self.physnet}
|
||||||
ext_net = self._make_network(self.fmt, 'ext_net', True, as_admin=True,
|
ext_net = self._make_network(self.fmt, 'ext_net', True, as_admin=True,
|
||||||
**kwargs)
|
arg_list=tuple(arg_dict.keys()),
|
||||||
|
**arg_dict)
|
||||||
self._make_subnet(self.fmt, ext_net, '10.251.0.1', '10.251.0.0/24',
|
self._make_subnet(self.fmt, ext_net, '10.251.0.1', '10.251.0.0/24',
|
||||||
enable_dhcp=True)
|
enable_dhcp=True)
|
||||||
router = self._make_router(self.fmt, self._tenant_id)
|
router = self._make_router(self.fmt, self._tenant_id)
|
||||||
|
@ -41,6 +41,7 @@ class TestRouter(base.TestOVNFunctionalBase):
|
|||||||
self.chassis2 = self.add_fake_chassis(
|
self.chassis2 = self.add_fake_chassis(
|
||||||
'ovs-host2', physical_nets=['physnet2', 'physnet3'],
|
'ovs-host2', physical_nets=['physnet2', 'physnet3'],
|
||||||
enable_chassis_as_gw=True, azs=[])
|
enable_chassis_as_gw=True, azs=[])
|
||||||
|
self.physnet_used = ['physnet1', 'physnet2', 'physnet3']
|
||||||
self.cr_lrp_pb_event = events.WaitForCrLrpPortBindingEvent()
|
self.cr_lrp_pb_event = events.WaitForCrLrpPortBindingEvent()
|
||||||
self.sb_api.idl.notify_handler.watch_event(self.cr_lrp_pb_event)
|
self.sb_api.idl.notify_handler.watch_event(self.cr_lrp_pb_event)
|
||||||
|
|
||||||
@ -86,13 +87,11 @@ class TestRouter(base.TestOVNFunctionalBase):
|
|||||||
ip_version=n_consts.IP_VERSION_4)
|
ip_version=n_consts.IP_VERSION_4)
|
||||||
return network
|
return network
|
||||||
|
|
||||||
def _set_redirect_chassis_to_invalid_chassis(self, ovn_client):
|
def _unset_lrp_gw_chassis(self, ovn_client):
|
||||||
with ovn_client._nb_idl.transaction(check_error=True) as txn:
|
with ovn_client._nb_idl.transaction(check_error=True) as txn:
|
||||||
for lrp in self.nb_api.tables[
|
for lrp in self.nb_api.tables['Logical_Router_Port'].rows.values():
|
||||||
'Logical_Router_Port'].rows.values():
|
|
||||||
txn.add(ovn_client._nb_idl.update_lrouter_port(
|
txn.add(ovn_client._nb_idl.update_lrouter_port(
|
||||||
lrp.name,
|
lrp.name, gateway_chassis=[]))
|
||||||
gateway_chassis=[ovn_const.OVN_GATEWAY_INVALID_CHASSIS]))
|
|
||||||
|
|
||||||
def _get_gwc_dict(self):
|
def _get_gwc_dict(self):
|
||||||
sched_info = {}
|
sched_info = {}
|
||||||
@ -117,11 +116,11 @@ class TestRouter(base.TestOVNFunctionalBase):
|
|||||||
# exception occasionally.
|
# exception occasionally.
|
||||||
continue
|
continue
|
||||||
|
|
||||||
gw_port_id = router.get('gw_port_id')
|
|
||||||
logical_port = 'cr-lrp-%s' % gw_port_id
|
|
||||||
self.assertTrue(self.cr_lrp_pb_event.wait(logical_port),
|
|
||||||
msg='lrp %s failed to bind' % logical_port)
|
|
||||||
if bind_chassis:
|
if bind_chassis:
|
||||||
|
gw_port_id = router.get('gw_port_id')
|
||||||
|
logical_port = 'cr-lrp-%s' % gw_port_id
|
||||||
|
self.assertTrue(self.cr_lrp_pb_event.wait(logical_port),
|
||||||
|
msg='lrp %s failed to bind' % logical_port)
|
||||||
self.sb_api.lsp_bind(logical_port, bind_chassis,
|
self.sb_api.lsp_bind(logical_port, bind_chassis,
|
||||||
may_exist=True).execute(check_error=True)
|
may_exist=True).execute(check_error=True)
|
||||||
return routers
|
return routers
|
||||||
@ -165,22 +164,24 @@ class TestRouter(base.TestOVNFunctionalBase):
|
|||||||
def fake_select(*args, **kwargs):
|
def fake_select(*args, **kwargs):
|
||||||
self.assertCountEqual(candidates, kwargs['candidates'])
|
self.assertCountEqual(candidates, kwargs['candidates'])
|
||||||
# We are not interested in further processing, let us return
|
# We are not interested in further processing, let us return
|
||||||
# INVALID_CHASSIS to avoid errors
|
# a random chassis name to avoid errors. If there are no
|
||||||
return [ovn_const.OVN_GATEWAY_INVALID_CHASSIS]
|
# candidates, this method returns None.
|
||||||
|
return ['a-random-chassis'] if candidates else None
|
||||||
|
|
||||||
with mock.patch.object(self.l3_plugin.scheduler, 'select',
|
with mock.patch.object(self.l3_plugin.scheduler, 'select',
|
||||||
side_effect=fake_select) as plugin_select:
|
side_effect=fake_select) as plugin_select:
|
||||||
gw_info = {'network_id': ext1['network']['id']}
|
gw_info = {'network_id': ext1['network']['id']}
|
||||||
self._create_router('router1', gw_info=gw_info,
|
self._create_router('router1', gw_info=gw_info,
|
||||||
az_hints=router_az_hints)
|
az_hints=router_az_hints)
|
||||||
self.assertTrue(plugin_select.called)
|
self.assertTrue(plugin_select.called)
|
||||||
plugin_select.reset_mock()
|
plugin_select.reset_mock()
|
||||||
|
|
||||||
# set redirect-chassis to neutron-ovn-invalid-chassis, so
|
# Unset the redirect-chassis so that schedule_unhosted_gateways
|
||||||
# that schedule_unhosted_gateways will try to schedule it
|
# will try to schedule it.
|
||||||
self._set_redirect_chassis_to_invalid_chassis(ovn_client)
|
self._unset_lrp_gw_chassis(ovn_client)
|
||||||
self.l3_plugin.schedule_unhosted_gateways()
|
self.l3_plugin.schedule_unhosted_gateways()
|
||||||
self.assertTrue(plugin_select.called)
|
check = self.assertTrue if candidates else self.assertFalse
|
||||||
|
check(plugin_select.called)
|
||||||
|
|
||||||
def test_gateway_chassis_with_cms_and_bridge_mappings(self):
|
def test_gateway_chassis_with_cms_and_bridge_mappings(self):
|
||||||
# Both chassis1 and chassis3 are having proper bridge mappings,
|
# Both chassis1 and chassis3 are having proper bridge mappings,
|
||||||
@ -201,7 +202,7 @@ class TestRouter(base.TestOVNFunctionalBase):
|
|||||||
'ext1', 'vlan', 'physnet1', 1, "10.0.0.1", "10.0.0.0/24")
|
'ext1', 'vlan', 'physnet1', 1, "10.0.0.1", "10.0.0.0/24")
|
||||||
# As we have 'gateways' in the system, but without required
|
# As we have 'gateways' in the system, but without required
|
||||||
# chassis we should not schedule gw in that case at all.
|
# chassis we should not schedule gw in that case at all.
|
||||||
self._set_redirect_chassis_to_invalid_chassis(ovn_client)
|
self._unset_lrp_gw_chassis(ovn_client)
|
||||||
with mock.patch.object(self.l3_plugin.scheduler, 'select',
|
with mock.patch.object(self.l3_plugin.scheduler, 'select',
|
||||||
side_effect=[self.chassis1]):
|
side_effect=[self.chassis1]):
|
||||||
gw_info = {'network_id': ext1['network']['id']}
|
gw_info = {'network_id': ext1['network']['id']}
|
||||||
@ -242,7 +243,7 @@ class TestRouter(base.TestOVNFunctionalBase):
|
|||||||
'ext1', 'vlan', 'physnet1', 1, "10.0.0.1", "10.0.0.0/24")
|
'ext1', 'vlan', 'physnet1', 1, "10.0.0.1", "10.0.0.0/24")
|
||||||
# As we have 'gateways' in the system, but without required
|
# As we have 'gateways' in the system, but without required
|
||||||
# chassis we should not schedule gw in that case at all.
|
# chassis we should not schedule gw in that case at all.
|
||||||
self._set_redirect_chassis_to_invalid_chassis(ovn_client)
|
self._unset_lrp_gw_chassis(ovn_client)
|
||||||
with mock.patch.object(self.l3_plugin.scheduler, 'select',
|
with mock.patch.object(self.l3_plugin.scheduler, 'select',
|
||||||
side_effect=[self.chassis1]):
|
side_effect=[self.chassis1]):
|
||||||
gw_info = {'network_id': ext1['network']['id']}
|
gw_info = {'network_id': ext1['network']['id']}
|
||||||
@ -264,7 +265,7 @@ class TestRouter(base.TestOVNFunctionalBase):
|
|||||||
def test_gateway_chassis_no_physnet_tunnelled_network(self):
|
def test_gateway_chassis_no_physnet_tunnelled_network(self):
|
||||||
# The GW network is tunnelled, no physnet defined --> no possible
|
# The GW network is tunnelled, no physnet defined --> no possible
|
||||||
# candidates.
|
# candidates.
|
||||||
self._check_gateway_chassis_candidates([], physnet=None)
|
self._check_gateway_chassis_candidates(None, physnet=None)
|
||||||
|
|
||||||
def test_gateway_chassis_least_loaded_scheduler(self):
|
def test_gateway_chassis_least_loaded_scheduler(self):
|
||||||
# This test will create 4 routers each with its own gateway.
|
# This test will create 4 routers each with its own gateway.
|
||||||
@ -372,11 +373,8 @@ class TestRouter(base.TestOVNFunctionalBase):
|
|||||||
Test cases when subnets are added to an external network after router
|
Test cases when subnets are added to an external network after router
|
||||||
has been configured to use that network via "set --external-gateway"
|
has been configured to use that network via "set --external-gateway"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
with mock.patch.object(self.l3_plugin.scheduler, 'select',
|
with mock.patch.object(self.l3_plugin.scheduler, 'select',
|
||||||
return_value=[
|
return_value=self.chassis1) as plugin_select:
|
||||||
ovn_const.OVN_GATEWAY_INVALID_CHASSIS
|
|
||||||
]) as plugin_select:
|
|
||||||
router1 = self._create_router('router1', gw_info=None)
|
router1 = self._create_router('router1', gw_info=None)
|
||||||
router_id = router1['id']
|
router_id = router1['id']
|
||||||
self.assertIsNone(self._get_gw_port(router_id),
|
self.assertIsNone(self._get_gw_port(router_id),
|
||||||
@ -490,8 +488,8 @@ class TestRouter(base.TestOVNFunctionalBase):
|
|||||||
def fake_select(*args, **kwargs):
|
def fake_select(*args, **kwargs):
|
||||||
self.assertCountEqual(self.candidates, kwargs['candidates'])
|
self.assertCountEqual(self.candidates, kwargs['candidates'])
|
||||||
# We are not interested in further processing, let us return
|
# We are not interested in further processing, let us return
|
||||||
# INVALID_CHASSIS to avoid errors
|
# a random chassis name to avoid errors.
|
||||||
return [ovn_const.OVN_GATEWAY_INVALID_CHASSIS]
|
return ['a-random-chassis']
|
||||||
|
|
||||||
with mock.patch.object(self.l3_plugin.scheduler, 'select',
|
with mock.patch.object(self.l3_plugin.scheduler, 'select',
|
||||||
side_effect=fake_select) as plugin_select:
|
side_effect=fake_select) as plugin_select:
|
||||||
@ -499,9 +497,9 @@ class TestRouter(base.TestOVNFunctionalBase):
|
|||||||
gw_info = {'network_id': ext1['network']['id']}
|
gw_info = {'network_id': ext1['network']['id']}
|
||||||
router1 = self._create_router('router1', gw_info=gw_info)
|
router1 = self._create_router('router1', gw_info=gw_info)
|
||||||
|
|
||||||
# set redirect-chassis to neutron-ovn-invalid-chassis, so
|
# Unset the redirect-chassis so that schedule_unhosted_gateways
|
||||||
# that schedule_unhosted_gateways will try to schedule it
|
# will try to schedule it.
|
||||||
self._set_redirect_chassis_to_invalid_chassis(ovn_client)
|
self._unset_lrp_gw_chassis(ovn_client)
|
||||||
self.l3_plugin.schedule_unhosted_gateways()
|
self.l3_plugin.schedule_unhosted_gateways()
|
||||||
|
|
||||||
self.candidates = [self.chassis1, self.chassis2]
|
self.candidates = [self.chassis1, self.chassis2]
|
||||||
@ -509,7 +507,7 @@ class TestRouter(base.TestOVNFunctionalBase):
|
|||||||
self.l3_plugin.update_router(
|
self.l3_plugin.update_router(
|
||||||
self.context, router1['id'],
|
self.context, router1['id'],
|
||||||
{'router': {l3_apidef.EXTERNAL_GW_INFO: gw_info}})
|
{'router': {l3_apidef.EXTERNAL_GW_INFO: gw_info}})
|
||||||
self._set_redirect_chassis_to_invalid_chassis(ovn_client)
|
self._unset_lrp_gw_chassis(ovn_client)
|
||||||
self.l3_plugin.schedule_unhosted_gateways()
|
self.l3_plugin.schedule_unhosted_gateways()
|
||||||
|
|
||||||
self.candidates = []
|
self.candidates = []
|
||||||
@ -517,17 +515,17 @@ class TestRouter(base.TestOVNFunctionalBase):
|
|||||||
self.l3_plugin.update_router(
|
self.l3_plugin.update_router(
|
||||||
self.context, router1['id'],
|
self.context, router1['id'],
|
||||||
{'router': {l3_apidef.EXTERNAL_GW_INFO: gw_info}})
|
{'router': {l3_apidef.EXTERNAL_GW_INFO: gw_info}})
|
||||||
self._set_redirect_chassis_to_invalid_chassis(ovn_client)
|
self._unset_lrp_gw_chassis(ovn_client)
|
||||||
self.l3_plugin.schedule_unhosted_gateways()
|
self.l3_plugin.schedule_unhosted_gateways()
|
||||||
|
|
||||||
# We can't test call_count for these mocks, as we have disabled
|
# We can't test call_count for these mocks, as we have disabled
|
||||||
# maintenance_worker which will trigger chassis events
|
# maintenance_worker which will trigger chassis events
|
||||||
# and eventually calling schedule_unhosted_gateways.
|
# and eventually calling schedule_unhosted_gateways.
|
||||||
# However, we know for sure that these mocks must have been
|
# The router is created with a gateway port and updated twice.
|
||||||
# called at least 3 times because that is the number of times
|
# However, the "plugin_select" is called only twice because the
|
||||||
# this test invokes them: 1x create_router + 2x update_router;
|
# third gateway network used is type "geneve" and the LRP are not
|
||||||
# and 3x schedule_unhosted_gateways for plugin_select mock.
|
# hosted in any chassis.
|
||||||
self.assertGreaterEqual(plugin_select.call_count, 3)
|
self.assertGreaterEqual(plugin_select.call_count, 2)
|
||||||
|
|
||||||
def test_router_gateway_port_binding_host_id(self):
|
def test_router_gateway_port_binding_host_id(self):
|
||||||
# Test setting chassis on chassisredirect port in Port_Binding table,
|
# Test setting chassis on chassisredirect port in Port_Binding table,
|
||||||
@ -613,7 +611,8 @@ class TestRouter(base.TestOVNFunctionalBase):
|
|||||||
|
|
||||||
def test_create_delete_router_multiple_gw_ports(self):
|
def test_create_delete_router_multiple_gw_ports(self):
|
||||||
ext4 = self._create_ext_network(
|
ext4 = self._create_ext_network(
|
||||||
'ext4', 'flat', 'physnet4', None, "40.0.0.1", "40.0.0.0/24")
|
'ext4', 'flat', self.physnet_used[0], None, '40.0.0.1',
|
||||||
|
'40.0.0.0/24')
|
||||||
router = self._create_router('router4')
|
router = self._create_router('router4')
|
||||||
gws = self._add_external_gateways(
|
gws = self._add_external_gateways(
|
||||||
router['id'],
|
router['id'],
|
||||||
@ -638,7 +637,8 @@ class TestRouter(base.TestOVNFunctionalBase):
|
|||||||
|
|
||||||
def test_create_router_multiple_gw_ports_ecmp(self):
|
def test_create_router_multiple_gw_ports_ecmp(self):
|
||||||
ext5 = self._create_ext_network(
|
ext5 = self._create_ext_network(
|
||||||
'ext5', 'flat', 'physnet5', None, "10.0.50.1", "10.0.50.0/24")
|
'ext5', 'flat', self.physnet_used[1], None, '10.0.50.1',
|
||||||
|
'10.0.50.0/24')
|
||||||
router = self._create_router('router5', enable_ecmp=True)
|
router = self._create_router('router5', enable_ecmp=True)
|
||||||
gws = self._add_external_gateways(
|
gws = self._add_external_gateways(
|
||||||
router['id'],
|
router['id'],
|
||||||
@ -740,12 +740,10 @@ class TestRouter(base.TestOVNFunctionalBase):
|
|||||||
'ext1', 'flat', 'physnet6', None, "10.0.60.1", "10.0.60.0/24")
|
'ext1', 'flat', 'physnet6', None, "10.0.60.1", "10.0.60.0/24")
|
||||||
gw_info = {'network_id': ext1['network']['id']}
|
gw_info = {'network_id': ext1['network']['id']}
|
||||||
|
|
||||||
# Attempt to add 4 routers, since there are no chassis all will be
|
# Attempt to add 4 routers, since there are no chassis, none of them
|
||||||
# scheduled on the ovn_const.OVN_GATEWAY_INVALID_CHASSIS.
|
# will be scheduled on any chassis.
|
||||||
num_routers = len(self._create_routers_wait_pb(1, 4, gw_info))
|
num_routers = len(self._create_routers_wait_pb(1, 4, gw_info=gw_info))
|
||||||
self.assertEqual(
|
self.assertEqual({}, self._get_gwc_dict())
|
||||||
{ovn_const.OVN_GATEWAY_INVALID_CHASSIS: {1: num_routers}},
|
|
||||||
self._get_gwc_dict())
|
|
||||||
|
|
||||||
# Add 2 chassis and rebalance gateways.
|
# Add 2 chassis and rebalance gateways.
|
||||||
#
|
#
|
||||||
@ -758,9 +756,7 @@ class TestRouter(base.TestOVNFunctionalBase):
|
|||||||
with mock.patch.object(
|
with mock.patch.object(
|
||||||
self.l3_plugin, 'schedule_unhosted_gateways'):
|
self.l3_plugin, 'schedule_unhosted_gateways'):
|
||||||
chassis_list.extend(self._add_chassis(1, 2, ['physnet6']))
|
chassis_list.extend(self._add_chassis(1, 2, ['physnet6']))
|
||||||
self.assertEqual(
|
self.assertEqual({}, self._get_gwc_dict())
|
||||||
{ovn_const.OVN_GATEWAY_INVALID_CHASSIS: {1: num_routers}},
|
|
||||||
self._get_gwc_dict())
|
|
||||||
|
|
||||||
# Wrap `self.l3_plugin._nb_ovn.transaction` so that we can assert on
|
# Wrap `self.l3_plugin._nb_ovn.transaction` so that we can assert on
|
||||||
# number of calls.
|
# number of calls.
|
||||||
|
@ -266,7 +266,7 @@ class TestGateWayChassisValidity(base.BaseTestCase):
|
|||||||
|
|
||||||
def test_gateway_chassis_due_to_invalid_chassis_name(self):
|
def test_gateway_chassis_due_to_invalid_chassis_name(self):
|
||||||
# Return True since chassis is invalid
|
# Return True since chassis is invalid
|
||||||
self.chassis_name = constants.OVN_GATEWAY_INVALID_CHASSIS
|
self.chassis_name = None
|
||||||
self.assertTrue(utils.is_gateway_chassis_invalid(
|
self.assertTrue(utils.is_gateway_chassis_invalid(
|
||||||
self.chassis_name, self.gw_chassis, self.physnet,
|
self.chassis_name, self.gw_chassis, self.physnet,
|
||||||
self.chassis_physnets, self.az_hints, self.chassis_azs))
|
self.chassis_physnets, self.az_hints, self.chassis_azs))
|
||||||
|
@ -181,8 +181,7 @@ class TestNBImplIdlOvn(TestDBImplIdlOvn):
|
|||||||
'external_ids': {ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-id-a',
|
'external_ids': {ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'lr-id-a',
|
||||||
ovn_const.OVN_ROUTER_IS_EXT_GW: str(True)},
|
ovn_const.OVN_ROUTER_IS_EXT_GW: str(True)},
|
||||||
'networks': ['10.0.3.0/24'],
|
'networks': ['10.0.3.0/24'],
|
||||||
'options': {ovn_const.OVN_GATEWAY_CHASSIS_KEY:
|
'options': {ovn_const.OVN_GATEWAY_CHASSIS_KEY: None}},
|
||||||
ovn_const.OVN_GATEWAY_INVALID_CHASSIS}},
|
|
||||||
{'name': 'xrp-id-b1',
|
{'name': 'xrp-id-b1',
|
||||||
'external_ids': {}, 'networks': ['20.0.1.0/24']},
|
'external_ids': {}, 'networks': ['20.0.1.0/24']},
|
||||||
{'name': utils.ovn_lrouter_port_name('orp-id-b2'),
|
{'name': utils.ovn_lrouter_port_name('orp-id-b2'),
|
||||||
@ -627,8 +626,7 @@ class TestNBImplIdlOvn(TestDBImplIdlOvn):
|
|||||||
expected = {'host-1': [utils.ovn_lrouter_port_name('orp-id-a1'),
|
expected = {'host-1': [utils.ovn_lrouter_port_name('orp-id-a1'),
|
||||||
utils.ovn_lrouter_port_name('orp-id-a2')],
|
utils.ovn_lrouter_port_name('orp-id-a2')],
|
||||||
'host-2': [utils.ovn_lrouter_port_name('orp-id-b2')],
|
'host-2': [utils.ovn_lrouter_port_name('orp-id-b2')],
|
||||||
ovn_const.OVN_GATEWAY_INVALID_CHASSIS: [
|
}
|
||||||
utils.ovn_name('orp-id-a3')]}
|
|
||||||
self.assertCountEqual(bindings, expected)
|
self.assertCountEqual(bindings, expected)
|
||||||
|
|
||||||
bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings([])
|
bindings = self.nb_ovn_idl.get_all_chassis_gateway_bindings([])
|
||||||
@ -654,7 +652,7 @@ class TestNBImplIdlOvn(TestDBImplIdlOvn):
|
|||||||
self.assertEqual(chassis, ['host-2'])
|
self.assertEqual(chassis, ['host-2'])
|
||||||
chassis = self.nb_ovn_idl.get_gateway_chassis_binding(
|
chassis = self.nb_ovn_idl.get_gateway_chassis_binding(
|
||||||
utils.ovn_lrouter_port_name('orp-id-a3'))
|
utils.ovn_lrouter_port_name('orp-id-a3'))
|
||||||
self.assertEqual(chassis, ['neutron-ovn-invalid-chassis'])
|
self.assertEqual([], chassis)
|
||||||
chassis = self.nb_ovn_idl.get_gateway_chassis_binding(
|
chassis = self.nb_ovn_idl.get_gateway_chassis_binding(
|
||||||
utils.ovn_lrouter_port_name('orp-id-b3'))
|
utils.ovn_lrouter_port_name('orp-id-b3'))
|
||||||
self.assertEqual([], chassis)
|
self.assertEqual([], chassis)
|
||||||
|
@ -50,8 +50,7 @@ class TestOVNGatewayScheduler(base.BaseTestCase):
|
|||||||
self.new_gateway_name = 'lrp_new'
|
self.new_gateway_name = 'lrp_new'
|
||||||
self.fake_chassis_gateway_mappings = {
|
self.fake_chassis_gateway_mappings = {
|
||||||
'None': {'Chassis': [],
|
'None': {'Chassis': [],
|
||||||
'Gateways': {
|
'Gateways': {'g1': None}},
|
||||||
'g1': [ovn_const.OVN_GATEWAY_INVALID_CHASSIS]}},
|
|
||||||
'Multiple1': {'Chassis': ['hv1', 'hv2', 'hv3', 'hv4', 'hv5'],
|
'Multiple1': {'Chassis': ['hv1', 'hv2', 'hv3', 'hv4', 'hv5'],
|
||||||
'Gateways': {
|
'Gateways': {
|
||||||
'g1': ['hv1', 'hv2', 'hv4', 'hv3', 'hv5'],
|
'g1': ['hv1', 'hv2', 'hv4', 'hv3', 'hv5'],
|
||||||
@ -102,6 +101,7 @@ class TestOVNGatewayScheduler(base.BaseTestCase):
|
|||||||
for chassis in details['Chassis']:
|
for chassis in details['Chassis']:
|
||||||
details['Chassis_Bindings'].setdefault(chassis, [])
|
details['Chassis_Bindings'].setdefault(chassis, [])
|
||||||
for gw, chassis_list in details['Gateways'].items():
|
for gw, chassis_list in details['Gateways'].items():
|
||||||
|
chassis_list = chassis_list or []
|
||||||
max_prio = len(chassis_list)
|
max_prio = len(chassis_list)
|
||||||
for idx, chassis in enumerate(chassis_list):
|
for idx, chassis in enumerate(chassis_list):
|
||||||
prio = max_prio - idx
|
prio = max_prio - idx
|
||||||
@ -138,7 +138,7 @@ class OVNGatewayChanceScheduler(TestOVNGatewayScheduler):
|
|||||||
gateway_name = random.choice(list(mapping['Gateways'].keys()))
|
gateway_name = random.choice(list(mapping['Gateways'].keys()))
|
||||||
chassis = self.select(mapping, gateway_name, chassis_and_azs,
|
chassis = self.select(mapping, gateway_name, chassis_and_azs,
|
||||||
candidates=mapping['Chassis'])
|
candidates=mapping['Chassis'])
|
||||||
self.assertEqual([ovn_const.OVN_GATEWAY_INVALID_CHASSIS], chassis)
|
self.assertIsNone(chassis)
|
||||||
|
|
||||||
def test_no_chassis_available_for_new_gateway(self):
|
def test_no_chassis_available_for_new_gateway(self):
|
||||||
mapping = self.fake_chassis_gateway_mappings['None']
|
mapping = self.fake_chassis_gateway_mappings['None']
|
||||||
@ -146,7 +146,7 @@ class OVNGatewayChanceScheduler(TestOVNGatewayScheduler):
|
|||||||
gateway_name = self.new_gateway_name
|
gateway_name = self.new_gateway_name
|
||||||
chassis = self.select(mapping, gateway_name, chassis_and_azs,
|
chassis = self.select(mapping, gateway_name, chassis_and_azs,
|
||||||
candidates=mapping['Chassis'])
|
candidates=mapping['Chassis'])
|
||||||
self.assertEqual([ovn_const.OVN_GATEWAY_INVALID_CHASSIS], chassis)
|
self.assertIsNone(chassis)
|
||||||
|
|
||||||
def test_random_chassis_available_for_new_gateway(self):
|
def test_random_chassis_available_for_new_gateway(self):
|
||||||
mapping = self.fake_chassis_gateway_mappings['Multiple1']
|
mapping = self.fake_chassis_gateway_mappings['Multiple1']
|
||||||
@ -161,7 +161,7 @@ class OVNGatewayChanceScheduler(TestOVNGatewayScheduler):
|
|||||||
chassis_and_azs = self.fake_chassis_and_azs['None']
|
chassis_and_azs = self.fake_chassis_and_azs['None']
|
||||||
gateway_name = self.new_gateway_name
|
gateway_name = self.new_gateway_name
|
||||||
chassis = self.select(mapping, gateway_name, chassis_and_azs)
|
chassis = self.select(mapping, gateway_name, chassis_and_azs)
|
||||||
self.assertEqual([ovn_const.OVN_GATEWAY_INVALID_CHASSIS], chassis)
|
self.assertIsNone(chassis)
|
||||||
self.mock_log.warning.assert_called_once_with(
|
self.mock_log.warning.assert_called_once_with(
|
||||||
'Gateway %s was not scheduled on any chassis, no candidates are '
|
'Gateway %s was not scheduled on any chassis, no candidates are '
|
||||||
'available', gateway_name)
|
'available', gateway_name)
|
||||||
@ -179,15 +179,14 @@ class OVNGatewayChanceScheduler(TestOVNGatewayScheduler):
|
|||||||
nb_idl=nb_idl, gw_chassis=["temp"],
|
nb_idl=nb_idl, gw_chassis=["temp"],
|
||||||
physnet='phys-network-1',
|
physnet='phys-network-1',
|
||||||
chassis_physnets=chassis_physnets,
|
chassis_physnets=chassis_physnets,
|
||||||
existing_chassis=['temp',
|
existing_chassis=['temp', None]))
|
||||||
ovn_const.OVN_GATEWAY_INVALID_CHASSIS]))
|
|
||||||
# Check if invalid is removed -II
|
# Check if invalid is removed -II
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
self.filter_existing_chassis(
|
self.filter_existing_chassis(
|
||||||
nb_idl=nb_idl, gw_chassis=["temp"],
|
nb_idl=nb_idl, gw_chassis=["temp"],
|
||||||
physnet='phys-network-1',
|
physnet='phys-network-1',
|
||||||
chassis_physnets=chassis_physnets,
|
chassis_physnets=chassis_physnets,
|
||||||
existing_chassis=[ovn_const.OVN_GATEWAY_INVALID_CHASSIS]))
|
existing_chassis=None))
|
||||||
# Check if chassis removed when physnet doesnt exist
|
# Check if chassis removed when physnet doesnt exist
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
self.filter_existing_chassis(
|
self.filter_existing_chassis(
|
||||||
@ -236,7 +235,7 @@ class OVNGatewayLeastLoadedScheduler(TestOVNGatewayScheduler):
|
|||||||
gateway_name = random.choice(list(mapping['Gateways'].keys()))
|
gateway_name = random.choice(list(mapping['Gateways'].keys()))
|
||||||
chassis = self.select(mapping, gateway_name, chassis_and_azs,
|
chassis = self.select(mapping, gateway_name, chassis_and_azs,
|
||||||
candidates=mapping['Chassis'])
|
candidates=mapping['Chassis'])
|
||||||
self.assertEqual([ovn_const.OVN_GATEWAY_INVALID_CHASSIS], chassis)
|
self.assertIsNone(chassis)
|
||||||
|
|
||||||
def test_no_chassis_available_for_new_gateway(self):
|
def test_no_chassis_available_for_new_gateway(self):
|
||||||
mapping = self.fake_chassis_gateway_mappings['None']
|
mapping = self.fake_chassis_gateway_mappings['None']
|
||||||
@ -244,7 +243,7 @@ class OVNGatewayLeastLoadedScheduler(TestOVNGatewayScheduler):
|
|||||||
gateway_name = self.new_gateway_name
|
gateway_name = self.new_gateway_name
|
||||||
chassis = self.select(mapping, gateway_name, chassis_and_azs,
|
chassis = self.select(mapping, gateway_name, chassis_and_azs,
|
||||||
candidates=mapping['Chassis'])
|
candidates=mapping['Chassis'])
|
||||||
self.assertEqual([ovn_const.OVN_GATEWAY_INVALID_CHASSIS], chassis)
|
self.assertIsNone(chassis)
|
||||||
|
|
||||||
def test_least_loaded_chassis_available_for_new_gateway1(self):
|
def test_least_loaded_chassis_available_for_new_gateway1(self):
|
||||||
mapping = self.fake_chassis_gateway_mappings['Multiple1']
|
mapping = self.fake_chassis_gateway_mappings['Multiple1']
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
other:
|
||||||
|
- |
|
||||||
|
The artifact of creating a gateway chassis called
|
||||||
|
"neutron-ovn-invalid-chassis" when a "Logical_Router_Port" cannot be
|
||||||
|
assigned to any chassis is removed. Now no gateway chassis is created and
|
||||||
|
the "Logical_Router_Port" field will be empty.
|
||||||
|
upgrade:
|
||||||
|
- |
|
||||||
|
Any "Logical_Router_Port" with a gateway chassis named
|
||||||
|
"neutron-ovn-invalid-chassis" will be updated and this chassis will be
|
||||||
|
deleted. An unhosted (unbound) "Logical_Router_Port" will have no gateway
|
||||||
|
assigned.
|
Loading…
Reference in New Issue
Block a user