Implement experimental features framework

During the Zed PTG it was decided to handle unsupported features in
Neutron as experimental. See section titled "When we say something is
not supported?", day 2 in [1]. The agreement was:

"We keep existing jobs for linuxbridge driver for example, but when the
tests start to fail we skip them and finally we stop the job also.
To make it clear for operators we add warning logs highlighting that the
given feature/driver is experimental, and introduce cfg option to enable
such features explicitly."

This commit implements this agreement, initially with Linuxbridge

Depends-On: https://review.opendev.org/c/openstack/neutron-tempest-plugin/+/845646

[1] https://lists.openstack.org/pipermail/openstack-discuss/2022-April/028164.html

Change-Id: Ib18efa3f472736b58c8967847b1061da0e3897d7
This commit is contained in:
Miguel Lavalle 2022-06-08 18:23:25 -05:00
parent 7ebc8281e5
commit 7f0413c84c
15 changed files with 181 additions and 8 deletions

View File

@ -0,0 +1,37 @@
.. _config-experimental-framework:
===============================
Experimental features framework
===============================
Some Neutron features are not supported because the community doesn't have
the resources and/or technical expertise to maintain them anymore. As they
arise, the Neutron team designates these features as experimental. Deployers
can continue using these features at their own risk, by explicitly enabling
them in the ``experimental`` section of ``neutron.conf``.
.. note::
Of course, the Neutron core team would love to return experimetal features
to the supported status, if interested parties step up to maintain them. If
you are interested in maintaining any of the experimental features listed
below, please contact the PTL shown in the
`Neutron project page
<https://governance.openstack.org/tc/reference/projects/neutron.html>`_.
The following table shows the Neutron features currently designated as
experimetal:
.. table:: **Neutron Experimental features**
========================= ===================================
Feature Option in neutron.conf to enable
========================= ===================================
ML2 Linuxbridge driver linuxbridge
========================= ===================================
This is an example of how to enable the use of an experimental feature:
.. code-block:: none
[experimental]
linuxbridge = true

View File

@ -18,6 +18,7 @@ Configuration
config-dns-int-ext-serv config-dns-int-ext-serv
config-dns-res config-dns-res
config-dvr-ha-snat config-dvr-ha-snat
config-experimental-framework
config-fip-port-forwardings config-fip-port-forwardings
config-ipam config-ipam
config-ipv6 config-ipv6

View File

@ -5,6 +5,7 @@ wrap_width = 79
namespace = neutron namespace = neutron
namespace = neutron.agent namespace = neutron.agent
namespace = neutron.db namespace = neutron.db
namespace = neutron.experimental
namespace = neutron.extensions namespace = neutron.extensions
namespace = nova.auth namespace = nova.auth
namespace = ironic.auth namespace = ironic.auth

View File

@ -0,0 +1,39 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_config import cfg
from oslo_log import log
from neutron.conf import experimental
LOG = log.getLogger(__name__)
CONF = cfg.CONF
experimental.register_experimental_opts()
def validate_experimental_enabled(feature):
try:
is_enabled = cfg.CONF.experimental[feature]
except cfg.NoSuchOptError:
LOG.error("Experimental feature '%s' doesn't exist", feature)
raise SystemExit(1)
if is_enabled:
LOG.warning("Feature '%s' is unsupported and is treated as "
"experimental. Use at your own risk.", feature)
else:
LOG.error("Feature '%s' is experimental and has to be explicitly "
"enabled in 'cfg.CONF.experimental'", feature)
raise SystemExit(1)

View File

@ -0,0 +1,29 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_config import cfg
from neutron._i18n import _
EXPERIMENTAL_CFG_GROUP = 'experimental'
EXPERIMENTAL_LINUXBRIDGE = 'linuxbridge'
experimental_opts = [
cfg.BoolOpt(EXPERIMENTAL_LINUXBRIDGE,
default=False,
help=_('Enable execution of the experimental Linuxbridge '
'agent.')),
]
def register_experimental_opts(cfg=cfg.CONF):
cfg.register_opts(experimental_opts, EXPERIMENTAL_CFG_GROUP)

View File

@ -37,6 +37,7 @@ import neutron.conf.db.l3_agentschedulers_db
import neutron.conf.db.l3_dvr_db import neutron.conf.db.l3_dvr_db
import neutron.conf.db.l3_gwmode_db import neutron.conf.db.l3_gwmode_db
import neutron.conf.db.l3_hamode_db import neutron.conf.db.l3_hamode_db
import neutron.conf.experimental
import neutron.conf.extensions.allowedaddresspairs import neutron.conf.extensions.allowedaddresspairs
import neutron.conf.extensions.conntrack_helper import neutron.conf.extensions.conntrack_helper
import neutron.conf.plugins.ml2.config import neutron.conf.plugins.ml2.config
@ -361,3 +362,11 @@ def list_sriov_agent_opts():
('agent', ('agent',
neutron.conf.agent.agent_extensions_manager.AGENT_EXT_MANAGER_OPTS) neutron.conf.agent.agent_extensions_manager.AGENT_EXT_MANAGER_OPTS)
] ]
def list_experimental_opts():
return [
(neutron.conf.experimental.EXPERIMENTAL_CFG_GROUP,
itertools.chain(neutron.conf.experimental.experimental_opts)
),
]

View File

@ -17,6 +17,8 @@ from neutron_lib.api.definitions import portbindings
from neutron_lib import constants from neutron_lib import constants
from neutron.agent import securitygroups_rpc from neutron.agent import securitygroups_rpc
from neutron.common import experimental
from neutron.conf import experimental as c_experimental
from neutron.plugins.ml2.drivers import mech_agent from neutron.plugins.ml2.drivers import mech_agent
from neutron.services.qos.drivers.linuxbridge import driver as lb_qos_driver from neutron.services.qos.drivers.linuxbridge import driver as lb_qos_driver
@ -32,6 +34,8 @@ class LinuxbridgeMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
""" """
def __init__(self): def __init__(self):
experimental.validate_experimental_enabled(
c_experimental.EXPERIMENTAL_LINUXBRIDGE)
sg_enabled = securitygroups_rpc.is_firewall_enabled() sg_enabled = securitygroups_rpc.is_firewall_enabled()
vif_details = {portbindings.CAP_PORT_FILTER: sg_enabled, vif_details = {portbindings.CAP_PORT_FILTER: sg_enabled,
portbindings.VIF_DETAILS_CONNECTIVITY: portbindings.VIF_DETAILS_CONNECTIVITY:

View File

@ -97,6 +97,9 @@ class NeutronConfigFixture(ConfigFixture):
'quotas': { 'quotas': {
'quota_driver': env_desc.quota_driver 'quota_driver': env_desc.quota_driver
}, },
'experimental': {
'linuxbridge': str(env_desc.allow_experimental_linuxbridge)
},
}) })
if use_local_apipaste: if use_local_apipaste:

View File

@ -44,7 +44,8 @@ class EnvironmentDescription(object):
dhcp_scheduler_class=None, ml2_extension_drivers=None, dhcp_scheduler_class=None, ml2_extension_drivers=None,
api_workers=1, api_workers=1,
enable_traditional_dhcp=True, local_ip_ext=False, enable_traditional_dhcp=True, local_ip_ext=False,
quota_driver=quota_conf.QUOTA_DB_DRIVER): quota_driver=quota_conf.QUOTA_DB_DRIVER,
allow_experimental_linuxbridge=True):
self.network_type = network_type self.network_type = network_type
self.l2_pop = l2_pop self.l2_pop = l2_pop
self.qos = qos self.qos = qos
@ -72,6 +73,7 @@ class EnvironmentDescription(object):
if self.local_ip_ext: if self.local_ip_ext:
self.service_plugins += ',local_ip' self.service_plugins += ',local_ip'
self.quota_driver = quota_driver self.quota_driver = quota_driver
self.allow_experimental_linuxbridge = allow_experimental_linuxbridge
@property @property
def tunneling_enabled(self): def tunneling_enabled(self):

View File

@ -36,6 +36,7 @@ from oslo_config import cfg
from oslo_utils import uuidutils from oslo_utils import uuidutils
import webob.exc import webob.exc
from neutron.conf import experimental as c_experimental
from neutron.conf.plugins.ml2 import config as ml2_config from neutron.conf.plugins.ml2 import config as ml2_config
from neutron.conf.plugins.ml2.drivers import driver_type from neutron.conf.plugins.ml2.drivers import driver_type
from neutron.db import agents_db from neutron.db import agents_db
@ -874,6 +875,11 @@ class TestMl2HostSegmentMappingOVS(HostSegmentMappingTestCase):
class TestMl2HostSegmentMappingLinuxBridge(TestMl2HostSegmentMappingOVS): class TestMl2HostSegmentMappingLinuxBridge(TestMl2HostSegmentMappingOVS):
_mechanism_drivers = ['linuxbridge', 'logger'] _mechanism_drivers = ['linuxbridge', 'logger']
def setUp(self, plugin=None):
cfg.CONF.set_override(c_experimental.EXPERIMENTAL_LINUXBRIDGE, True,
group=c_experimental.EXPERIMENTAL_CFG_GROUP)
super(TestMl2HostSegmentMappingLinuxBridge, self).setUp(plugin=plugin)
def _register_agent(self, host, mappings=None, plugin=None): def _register_agent(self, host, mappings=None, plugin=None):
helpers.register_linuxbridge_agent(host=host, helpers.register_linuxbridge_agent(host=host,
bridge_mappings=mappings, bridge_mappings=mappings,

View File

@ -15,7 +15,9 @@
from neutron_lib.api.definitions import portbindings from neutron_lib.api.definitions import portbindings
from neutron_lib import constants from neutron_lib import constants
from oslo_config import cfg
from neutron.conf import experimental as c_experimental
from neutron.plugins.ml2.drivers.linuxbridge.mech_driver \ from neutron.plugins.ml2.drivers.linuxbridge.mech_driver \
import mech_linuxbridge import mech_linuxbridge
from neutron.tests.unit.plugins.ml2 import _test_mech_agent as base from neutron.tests.unit.plugins.ml2 import _test_mech_agent as base
@ -65,24 +67,44 @@ class LinuxbridgeMechanismBaseTestCase(base.AgentMechanismBaseTestCase):
class LinuxbridgeMechanismGenericTestCase(LinuxbridgeMechanismBaseTestCase, class LinuxbridgeMechanismGenericTestCase(LinuxbridgeMechanismBaseTestCase,
base.AgentMechanismGenericTestCase): base.AgentMechanismGenericTestCase):
pass
def setUp(self):
cfg.CONF.set_override(c_experimental.EXPERIMENTAL_LINUXBRIDGE, True,
group=c_experimental.EXPERIMENTAL_CFG_GROUP)
super(LinuxbridgeMechanismGenericTestCase, self).setUp()
class LinuxbridgeMechanismLocalTestCase(LinuxbridgeMechanismBaseTestCase, class LinuxbridgeMechanismLocalTestCase(LinuxbridgeMechanismBaseTestCase,
base.AgentMechanismLocalTestCase): base.AgentMechanismLocalTestCase):
pass
def setUp(self):
cfg.CONF.set_override(c_experimental.EXPERIMENTAL_LINUXBRIDGE, True,
group=c_experimental.EXPERIMENTAL_CFG_GROUP)
super(LinuxbridgeMechanismLocalTestCase, self).setUp()
class LinuxbridgeMechanismFlatTestCase(LinuxbridgeMechanismBaseTestCase, class LinuxbridgeMechanismFlatTestCase(LinuxbridgeMechanismBaseTestCase,
base.AgentMechanismFlatTestCase): base.AgentMechanismFlatTestCase):
pass
def setUp(self):
cfg.CONF.set_override(c_experimental.EXPERIMENTAL_LINUXBRIDGE, True,
group=c_experimental.EXPERIMENTAL_CFG_GROUP)
super(LinuxbridgeMechanismFlatTestCase, self).setUp()
class LinuxbridgeMechanismVlanTestCase(LinuxbridgeMechanismBaseTestCase, class LinuxbridgeMechanismVlanTestCase(LinuxbridgeMechanismBaseTestCase,
base.AgentMechanismVlanTestCase): base.AgentMechanismVlanTestCase):
pass
def setUp(self):
cfg.CONF.set_override(c_experimental.EXPERIMENTAL_LINUXBRIDGE, True,
group=c_experimental.EXPERIMENTAL_CFG_GROUP)
super(LinuxbridgeMechanismVlanTestCase, self).setUp()
class LinuxbridgeMechanismGreTestCase(LinuxbridgeMechanismBaseTestCase, class LinuxbridgeMechanismGreTestCase(LinuxbridgeMechanismBaseTestCase,
base.AgentMechanismGreTestCase): base.AgentMechanismGreTestCase):
pass
def setUp(self):
cfg.CONF.set_override(c_experimental.EXPERIMENTAL_LINUXBRIDGE, True,
group=c_experimental.EXPERIMENTAL_CFG_GROUP)
super(LinuxbridgeMechanismGreTestCase, self).setUp()

View File

@ -0,0 +1,19 @@
---
prelude: >
Introduce the experimental features framework.
features:
- |
Some Neutron features are not supported due to lack of resources or
technical expertise to maintain them. As they arise, those features will
be marked as experimental by the Neutron core team.
Deployers will be able to continue using experimental features by
explicitly enabling them in the 'experimental' section of neutron.conf.
The ML2 linuxbridge driver is the first feature to be marked as
experimental. To continue using it, deployers have to set to True the
'linuxbridge' option in the 'experimental' section of neutron.conf.
deprecations:
- |
The ML2 linuxbridge agent has been marked as experimental due to lack
of resources to maintain it. To continue using it, deployers have to set
to True the 'linuxbridge' option in the 'experimental' section of
neutron.conf

View File

@ -157,6 +157,7 @@ oslo.config.opts =
neutron.base.agent = neutron.opts:list_base_agent_opts neutron.base.agent = neutron.opts:list_base_agent_opts
neutron.db = neutron.opts:list_db_opts neutron.db = neutron.opts:list_db_opts
neutron.dhcp.agent = neutron.opts:list_dhcp_agent_opts neutron.dhcp.agent = neutron.opts:list_dhcp_agent_opts
neutron.experimental = neutron.opts:list_experimental_opts
neutron.extensions = neutron.opts:list_extension_opts neutron.extensions = neutron.opts:list_extension_opts
neutron.l3.agent = neutron.opts:list_l3_agent_opts neutron.l3.agent = neutron.opts:list_l3_agent_opts
neutron.metadata.agent = neutron.opts:list_metadata_agent_opts neutron.metadata.agent = neutron.opts:list_metadata_agent_opts

View File

@ -10,7 +10,7 @@
OSPROFILER_COLLECTOR: redis OSPROFILER_COLLECTOR: redis
OSPROFILER_HMAC_KEYS: "neutron-hmac-key-used-in-zuul-ci" OSPROFILER_HMAC_KEYS: "neutron-hmac-key-used-in-zuul-ci"
Q_ML2_TENANT_NETWORK_TYPE: vxlan Q_ML2_TENANT_NETWORK_TYPE: vxlan
Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch,linuxbridge Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
Q_AGENT: openvswitch Q_AGENT: openvswitch
KEYSTONE_ADMIN_ENDPOINT: true KEYSTONE_ADMIN_ENDPOINT: true
rally_task: rally-jobs/task-neutron.yaml rally_task: rally-jobs/task-neutron.yaml

View File

@ -178,7 +178,7 @@
DEFAULT_IMAGE_NAME: cirros-0.5.1-x86_64-uec DEFAULT_IMAGE_NAME: cirros-0.5.1-x86_64-uec
DEFAULT_IMAGE_FILE_NAME: cirros-0.5.1-x86_64-uec.tar.gz DEFAULT_IMAGE_FILE_NAME: cirros-0.5.1-x86_64-uec.tar.gz
Q_ML2_TENANT_NETWORK_TYPE: vxlan Q_ML2_TENANT_NETWORK_TYPE: vxlan
Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch,linuxbridge Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
Q_AGENT: openvswitch Q_AGENT: openvswitch
devstack_plugins: devstack_plugins:
neutron: https://opendev.org/openstack/neutron.git neutron: https://opendev.org/openstack/neutron.git