Move registration "ChassisBandwidthConfigEvent" to OvnSbIdl init
The "ChassisBandwidthConfigEvent" event registration is now done in the "OvnSbIdl" class initialization. That ensures this event is registered in a worker thread. If the event is called before the "OVNMechanismDriver"'s "OVNClient" has been instantiated, the event is skipped. When the OVN placement extension is loaded, all chassis configurations are read and loaded, thus any previous event is not relevant. This patch also adds a "match_fn" check to "ChassisBandwidthConfigEvent". If during an update event, the bandwidth options are not modified, this class does not update the resource provider inventories. Closes-Bug: #1998108 Related-Bug: #1578989 Change-Id: I74883041c642b9498299ebf2b5bf885776e241e0
This commit is contained in:
parent
16399a2ce5
commit
49eab7d308
@ -110,8 +110,8 @@ def dict_chassis_config(state):
|
||||
class ChassisBandwidthConfigEvent(row_event.RowEvent):
|
||||
"""Chassis create update event to track the bandwidth config changes."""
|
||||
|
||||
def __init__(self, placement_extension):
|
||||
self._placement_extension = placement_extension
|
||||
def __init__(self, driver):
|
||||
self._driver = driver
|
||||
# NOTE(ralonsoh): BW resource provider information is stored in
|
||||
# "Chassis", not "Chassis_Private".
|
||||
table = 'Chassis'
|
||||
@ -119,9 +119,30 @@ class ChassisBandwidthConfigEvent(row_event.RowEvent):
|
||||
super().__init__(events, table, None)
|
||||
self.event_name = 'ChassisBandwidthConfigEvent'
|
||||
|
||||
@property
|
||||
def placement_extension(self):
|
||||
if self._driver._post_fork_event.is_set():
|
||||
return self._driver._ovn_client.placement_extension
|
||||
|
||||
def match_fn(self, event, row, old=None):
|
||||
# If the OVNMechanismDriver OVNClient has not been instantiated, the
|
||||
# event is skipped. All chassis configurations are read during the
|
||||
# OVN placement extension initialization.
|
||||
if (not self.placement_extension or
|
||||
not self.placement_extension.enabled):
|
||||
return False
|
||||
elif event == self.ROW_CREATE:
|
||||
return True
|
||||
elif event == self.ROW_UPDATE and old and hasattr(old, 'other_config'):
|
||||
row_bw = _parse_ovn_cms_options(row)
|
||||
old_bw = _parse_ovn_cms_options(old)
|
||||
if row_bw != old_bw:
|
||||
return True
|
||||
return False
|
||||
|
||||
def run(self, event, row, old):
|
||||
name2uuid = self._placement_extension.name2uuid()
|
||||
state = self._placement_extension.build_placement_state(row, name2uuid)
|
||||
name2uuid = self.placement_extension.name2uuid()
|
||||
state = self.placement_extension.build_placement_state(row, name2uuid)
|
||||
if not state:
|
||||
return
|
||||
|
||||
@ -153,18 +174,6 @@ class OVNClientPlacementExtension(object):
|
||||
self._plugin = None
|
||||
self.uuid_ns = ovn_const.OVN_RP_UUID
|
||||
self.supported_vnic_types = ovn_const.OVN_SUPPORTED_VNIC_TYPES
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
if not self._config_event:
|
||||
self._config_event = ChassisBandwidthConfigEvent(self)
|
||||
try:
|
||||
self._driver._sb_idl.idl.notify_handler.watch_events(
|
||||
[self._config_event])
|
||||
except AttributeError:
|
||||
# "sb_idl.idl.notify_handler" is not present in the
|
||||
# MaintenanceWorker.
|
||||
pass
|
||||
|
||||
@property
|
||||
def placement_plugin(self):
|
||||
|
@ -35,6 +35,8 @@ from neutron.common.ovn import utils
|
||||
from neutron.conf.plugins.ml2.drivers.ovn import ovn_conf
|
||||
from neutron.db import ovn_hash_ring_db
|
||||
from neutron.plugins.ml2.drivers.ovn.agent import neutron_agent as n_agent
|
||||
from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb.extensions import \
|
||||
placement
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -808,6 +810,7 @@ class OvnSbIdl(OvnIdlDistributedLock):
|
||||
ChassisAgentTypeChangeEvent(self.driver),
|
||||
ChassisMetadataAgentWriteEvent(self.driver),
|
||||
PortBindingUpdateVirtualPortsEvent(driver),
|
||||
placement.ChassisBandwidthConfigEvent(driver),
|
||||
])
|
||||
|
||||
@classmethod
|
||||
|
@ -16,15 +16,18 @@ from unittest import mock
|
||||
|
||||
from neutron_lib import constants as n_const
|
||||
from neutron_lib.plugins import constants as plugins_constants
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from neutron.common.ovn import constants as ovn_const
|
||||
from neutron.common import utils as common_utils
|
||||
from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb.extensions \
|
||||
import placement as placement_extension
|
||||
from neutron.tests.functional import base
|
||||
from neutron.tests.functional.plugins.ml2.drivers.ovn.mech_driver.ovsdb \
|
||||
import test_ovsdb_monitor
|
||||
|
||||
|
||||
class TestOVNClientQosExtension(base.TestOVNFunctionalBase):
|
||||
class TestOVNClientPlacementExtension(base.TestOVNFunctionalBase):
|
||||
|
||||
EMPTY_CHASSIS = {n_const.RP_BANDWIDTHS: {},
|
||||
n_const.RP_INVENTORY_DEFAULTS: {},
|
||||
@ -186,3 +189,39 @@ class TestOVNClientQosExtension(base.TestOVNFunctionalBase):
|
||||
inventory_defaults='allocation_ratio:1.1;min_unit:1',
|
||||
hypervisors='br-provider0:host2')
|
||||
self._check_placement_config({**self.CHASSIS1, **self.CHASSIS2_B})
|
||||
|
||||
@mock.patch.object(placement_extension, '_send_deferred_batch')
|
||||
def test_chassis_bandwidth_config_event(self, mock_send_placement):
|
||||
ch_host = 'fake-chassis-host'
|
||||
ch_name = uuidutils.generate_uuid()
|
||||
ch_event = test_ovsdb_monitor.WaitForChassisPrivateCreateEvent(
|
||||
ch_name, self.mech_driver.agent_chassis_table)
|
||||
self.mech_driver.sb_ovn.idl.notify_handler.watch_event(ch_event)
|
||||
self.chassis_name = self.add_fake_chassis(ch_host, name=ch_name)
|
||||
self.assertTrue(ch_event.wait())
|
||||
common_utils.wait_until_true(lambda: mock_send_placement.called,
|
||||
timeout=2)
|
||||
mock_send_placement.reset_mock()
|
||||
|
||||
# Once the chassis registger has been created, this new event will
|
||||
# catch any chassis BW update.
|
||||
self._update_chassis(
|
||||
ch_name,
|
||||
bandwidths='br-provider0:3000:4000',
|
||||
inventory_defaults='allocation_ratio:3.0;min_unit:1',
|
||||
hypervisors='br-provider0:host2')
|
||||
common_utils.wait_until_true(lambda: mock_send_placement.called,
|
||||
timeout=2)
|
||||
mock_send_placement.reset_mock()
|
||||
|
||||
# The chassis BW information is written again without any change.
|
||||
# That should not trigger the placement update.
|
||||
self._update_chassis(
|
||||
ch_name,
|
||||
bandwidths='br-provider0:3000:4000',
|
||||
inventory_defaults='allocation_ratio:3.0;min_unit:1',
|
||||
hypervisors='br-provider0:host2')
|
||||
self.assertRaises(common_utils.WaitTimeout,
|
||||
common_utils.wait_until_true,
|
||||
lambda: mock_send_placement.called,
|
||||
timeout=2)
|
||||
|
Loading…
Reference in New Issue
Block a user