From f2800097d6e3d8262a93b62dec2026499d13d1e7 Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Wed, 15 Oct 2025 09:31:53 -0500 Subject: [PATCH 1/3] chore(neutron-understack): drop old ml2_type_understack config section These options are all inside of ml2_understack and that should be where everything is loaded from. Drop the backwards support as its been deprecated long enough and there's no user of it. --- .../neutron-understack/neutron_understack/config.py | 12 ------------ .../neutron_understack/neutron_understack_mech.py | 7 +------ 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/python/neutron-understack/neutron_understack/config.py b/python/neutron-understack/neutron_understack/config.py index 0c2484060..5ac50b65d 100644 --- a/python/neutron-understack/neutron_understack/config.py +++ b/python/neutron-understack/neutron_understack/config.py @@ -1,13 +1,5 @@ from oslo_config import cfg -type_understack_opts = [ - cfg.StrOpt( - "provisioning_network", - help="provisioning_network ID as configured in ironic.conf", - default="change_me", - ), -] - mech_understack_opts = [ cfg.StrOpt( "nb_url", @@ -115,10 +107,6 @@ ] -def register_ml2_type_understack_opts(config): - config.register_opts(type_understack_opts, "ml2_type_understack") - - def register_ml2_understack_opts(config): config.register_opts(mech_understack_opts, "ml2_understack") diff --git a/python/neutron-understack/neutron_understack/neutron_understack_mech.py b/python/neutron-understack/neutron_understack/neutron_understack_mech.py index fb6cec593..e47f7d289 100644 --- a/python/neutron-understack/neutron_understack/neutron_understack_mech.py +++ b/python/neutron-understack/neutron_understack/neutron_understack_mech.py @@ -22,7 +22,6 @@ LOG = logging.getLogger(__name__) -config.register_ml2_type_understack_opts(cfg.CONF) config.register_ml2_understack_opts(cfg.CONF) @@ -296,8 +295,4 @@ def check_vlan_transparency(self, context): def is_provisioning_network(network_id: str) -> bool: - provisioning_network = ( - cfg.CONF.ml2_understack.provisioning_network - or cfg.CONF.ml2_type_understack.provisioning_network - ) - return network_id == provisioning_network + return network_id == cfg.CONF.ml2_understack.provisioning_network From 194e966e97eced524707ff5f39647105ea738728 Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Wed, 15 Oct 2025 09:50:29 -0500 Subject: [PATCH 2/3] chore(neutron-understack): switch oslo_config overrides to a fixture Rather than patching the global scoped oslo_config, switch to using a fixture which resets between tests to ensure that things are cleaned up appropriately. This will be necessary when we no longer initialize oslo_config in the global/import scope of the module. While moving this it pointed out an issue with one of the tests missing a mock which attempted to hit the DB, which now couldn't be initialized because we didn't setup our configs because the data had the wrong types which is being fixed in this as well. --- .../neutron_understack/tests/conftest.py | 35 +++++++++++++------ .../neutron_understack/tests/test_trunk.py | 17 ++++++--- .../neutron_understack/tests/test_utils.py | 21 ++++++----- 3 files changed, 49 insertions(+), 24 deletions(-) diff --git a/python/neutron-understack/neutron_understack/tests/conftest.py b/python/neutron-understack/neutron_understack/tests/conftest.py index 18b5cea41..5e336e6f5 100644 --- a/python/neutron-understack/neutron_understack/tests/conftest.py +++ b/python/neutron-understack/neutron_understack/tests/conftest.py @@ -22,7 +22,9 @@ from neutron_lib import constants as p_const from neutron_lib.api.definitions import portbindings from neutron_lib.callbacks.events import DBEventPayload +from oslo_config import fixture as config_fixture +from neutron_understack import config as understack_config from neutron_understack.ironic import IronicClient from neutron_understack.neutron_understack_mech import UnderstackDriver from neutron_understack.tests.helpers import Ml2PluginNoInit @@ -276,7 +278,7 @@ def ironic_client(mocker) -> IronicClient: @pytest.fixture -def understack_driver(ironic_client) -> UnderstackDriver: +def understack_driver(oslo_config, ironic_client) -> UnderstackDriver: driver = UnderstackDriver() driver.undersync = Undersync("auth_token", "api_url") driver.ironic_client = ironic_client @@ -341,18 +343,29 @@ def port_db_payload(network) -> DBEventPayload: @pytest.fixture -def ml2_understack_conf(mocker, ucvni_group_id) -> None: - mocker.patch( - "neutron_understack.neutron_understack_mech.cfg.CONF.ml2_understack.ucvni_group", - str(ucvni_group_id), +def oslo_config(): + """CONF from oslo_config is global but we need to override it sometimes.""" + conf_fixture = config_fixture.Config() + conf_fixture.setUp() + # register the ml2_understack options + understack_config.register_ml2_understack_opts(conf_fixture.conf) + yield conf_fixture + conf_fixture.cleanUp() + + +@pytest.fixture +def ml2_understack_conf(oslo_config, ucvni_group_id) -> None: + oslo_config.config( + ucvni_group=str(ucvni_group_id), + group="ml2_understack", ) - mocker.patch( - "neutron_understack.neutron_understack_mech.cfg.CONF.ml2_understack.network_node_switchport_uuid", - "a27f7260-a7c5-4f0c-ac70-6258b026d368", + oslo_config.config( + network_node_switchport_uuid="a27f7260-a7c5-4f0c-ac70-6258b026d368", + group="ml2_understack", ) - mocker.patch( - "neutron_understack.neutron_understack_mech.cfg.CONF.ml2_understack.undersync_dry_run", - False, + oslo_config.config( + undersync_dry_run=False, + group="ml2_understack", ) diff --git a/python/neutron-understack/neutron_understack/tests/test_trunk.py b/python/neutron-understack/neutron_understack/tests/test_trunk.py index c3b5d1ed0..9540f6e5d 100644 --- a/python/neutron-understack/neutron_understack/tests/test_trunk.py +++ b/python/neutron-understack/neutron_understack/tests/test_trunk.py @@ -336,14 +336,23 @@ class TestCheckSubportsSegmentationId: def test_when_trunk_id_is_network_node_trunk_id( self, mocker, + oslo_config, understack_trunk_driver, trunk_id, ): - mocker.patch( - "oslo_config.cfg.CONF.ml2_understack.network_node_trunk_uuid", - trunk_id, + oslo_config.config( + network_node_trunk_uuid=str(trunk_id), + group="ml2_understack", + ) + # Mock to ensure the function returns early and doesn't call this + allowed_ranges_mock = mocker.patch( + "neutron_understack.utils.allowed_tenant_vlan_id_ranges" + ) + result = understack_trunk_driver._check_subports_segmentation_id( + [], str(trunk_id) ) - result = understack_trunk_driver._check_subports_segmentation_id([], trunk_id) + # Should not call allowed_tenant_vlan_id_ranges because it returns early + allowed_ranges_mock.assert_not_called() assert result is None def test_when_segmentation_id_is_in_allowed_range( diff --git a/python/neutron-understack/neutron_understack/tests/test_utils.py b/python/neutron-understack/neutron_understack/tests/test_utils.py index 58e028493..711a2ec52 100644 --- a/python/neutron-understack/neutron_understack/tests/test_utils.py +++ b/python/neutron-understack/neutron_understack/tests/test_utils.py @@ -189,10 +189,11 @@ class TestAllowedTenantVlanIdRanges: def test_multiple_non_overlapping_ranges( self, mocker, + oslo_config, ): - mocker.patch( - "oslo_config.cfg.CONF.ml2_understack.default_tenant_vlan_id_range", - [1, 2000], + oslo_config.config( + default_tenant_vlan_id_range=[1, 2000], + group="ml2_understack", ) mocker.patch( "neutron_understack.utils.fetch_vlan_network_segment_ranges", @@ -205,10 +206,11 @@ def test_multiple_non_overlapping_ranges( def test_multiple_overlapping_ranges( self, mocker, + oslo_config, ): - mocker.patch( - "oslo_config.cfg.CONF.ml2_understack.default_tenant_vlan_id_range", - [1, 2000], + oslo_config.config( + default_tenant_vlan_id_range=[1, 2000], + group="ml2_understack", ) mocker.patch( "neutron_understack.utils.fetch_vlan_network_segment_ranges", @@ -221,10 +223,11 @@ def test_multiple_overlapping_ranges( def test_single_range( self, mocker, + oslo_config, ): - mocker.patch( - "oslo_config.cfg.CONF.ml2_understack.default_tenant_vlan_id_range", - [1, 2000], + oslo_config.config( + default_tenant_vlan_id_range=[1, 2000], + group="ml2_understack", ) mocker.patch( "neutron_understack.utils.fetch_vlan_network_segment_ranges", From 0f6f187e8834daee10ff3982ca13a984e8e8c7fa Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Wed, 15 Oct 2025 16:32:27 -0500 Subject: [PATCH 3/3] feat(neutron-understack): move the config initialization out of global Upstream mechanisms don't initialize the config options in the global scope and this appears to cause issues in a 2025.2 world so follow how upstream behaves. --- .../neutron_understack/neutron_understack_mech.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/neutron-understack/neutron_understack/neutron_understack_mech.py b/python/neutron-understack/neutron_understack/neutron_understack_mech.py index e47f7d289..d7ce95ce9 100644 --- a/python/neutron-understack/neutron_understack/neutron_understack_mech.py +++ b/python/neutron-understack/neutron_understack/neutron_understack_mech.py @@ -22,8 +22,6 @@ LOG = logging.getLogger(__name__) -config.register_ml2_understack_opts(cfg.CONF) - SUPPORTED_VNIC_TYPES = [portbindings.VNIC_BAREMETAL, portbindings.VNIC_NORMAL] @@ -37,6 +35,7 @@ def connectivity(self): # type: ignore return portbindings.CONNECTIVITY_L2 def initialize(self): + config.register_ml2_understack_opts(cfg.CONF) conf = cfg.CONF.ml2_understack self.undersync = Undersync(conf.undersync_token, conf.undersync_url) self.ironic_client = IronicClient()