Merge "Add pre-commit configuration"
diff --git a/doc/requirements.txt b/doc/requirements.txt
index 6fe7c34..12d5b68 100644
--- a/doc/requirements.txt
+++ b/doc/requirements.txt
@@ -1,4 +1,4 @@
reno>=3.1.0 # Apache-2.0
-sphinx>=2.0.0,!=2.1.0 # BSD
+sphinx>=2.2.0 # BSD
openstackdocstheme>=2.2.1 # Apache-2.0
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 88b9718..a5d87bb 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -16,7 +16,10 @@
import sys
def autodoc_skip_member_handler(app, what, name, obj, skip, options):
- return skip or (what == "class" and not name.startswith("test"))
+ return skip or (
+ (what == "class" and not name.startswith("test")) or
+ # NOTE(fnordahl): Sphinx does not like the ASCII art in the docstring.
+ (what == 'module' and name == 'NetworkMultipleGWTest'))
def setup(app):
app.connect('autodoc-skip-member', autodoc_skip_member_handler)
diff --git a/neutron_tempest_plugin/api/admin/test_quotas_negative.py b/neutron_tempest_plugin/api/admin/test_quotas_negative.py
index 9c37d92..2a8e24d 100644
--- a/neutron_tempest_plugin/api/admin/test_quotas_negative.py
+++ b/neutron_tempest_plugin/api/admin/test_quotas_negative.py
@@ -39,6 +39,23 @@
self.admin_client.create_network, **net_args)
@decorators.attr(type='negative')
+ @decorators.idempotent_id('9f676a6e-d729-428b-adcd-4de2867c50e6')
+ def test_set_network_quota_lower_than_networks_amount(self):
+ tenant_id = self.create_project()['id']
+ high_quota = 3
+ low_quota = 1
+ new_quotas = {'network': high_quota}
+ self._setup_quotas(tenant_id, **new_quotas)
+ for _ in range(high_quota - 1):
+ self._create_network(tenant_id)
+ # TODO(mblue): remove check_limit=True when it is default
+ new_quotas.update({'network': low_quota, 'check_limit': True})
+
+ self.assertRaises(lib_exc.BadRequest,
+ self.admin_client.update_quotas,
+ tenant_id, **new_quotas)
+
+ @decorators.attr(type='negative')
@decorators.idempotent_id('0b7f99e3-9f77-45ce-9a89-b39a184de618')
def test_create_subnet_when_quotas_is_full(self):
tenant_id = self.create_project()['id']
diff --git a/neutron_tempest_plugin/api/base.py b/neutron_tempest_plugin/api/base.py
index 7f056d1..99fa946 100644
--- a/neutron_tempest_plugin/api/base.py
+++ b/neutron_tempest_plugin/api/base.py
@@ -875,9 +875,10 @@
association['fixed_port_id'])
@classmethod
- def create_router_interface(cls, router_id, subnet_id):
+ def create_router_interface(cls, router_id, subnet_id, client=None):
"""Wrapper utility that returns a router interface."""
- interface = cls.client.add_router_interface_with_subnet_id(
+ client = client or cls.client
+ interface = client.add_router_interface_with_subnet_id(
router_id, subnet_id)
return interface
@@ -1220,6 +1221,16 @@
client = client or ndp_proxy.get('client') or cls.client
client.delete_ndp_proxy(ndp_proxy['id'])
+ @classmethod
+ def get_loaded_network_extensions(cls):
+ """Return the network service loaded extensions
+
+ :return: list of strings with the alias of the network service loaded
+ extensions.
+ """
+ body = cls.client.list_extensions()
+ return [net_ext['alias'] for net_ext in body['extensions']]
+
class BaseAdminNetworkTest(BaseNetworkTest):
@@ -1350,13 +1361,14 @@
@classmethod
def create_provider_network(cls, physnet_name, start_segmentation_id,
- max_attempts=30):
+ max_attempts=30, external=False):
segmentation_id = start_segmentation_id
for attempts in range(max_attempts):
try:
return cls.create_network(
name=data_utils.rand_name('test_net'),
- shared=True,
+ shared=not external,
+ external=external,
provider_network_type='vlan',
provider_physical_network=physnet_name,
provider_segmentation_id=segmentation_id)
diff --git a/neutron_tempest_plugin/api/test_auto_allocated_topology.py b/neutron_tempest_plugin/api/test_auto_allocated_topology.py
index 4d70bfc..2177402 100644
--- a/neutron_tempest_plugin/api/test_auto_allocated_topology.py
+++ b/neutron_tempest_plugin/api/test_auto_allocated_topology.py
@@ -79,6 +79,14 @@
body = client.list_networks(name='auto_allocated_network')
self.networks.extend(body['networks'])
+ @decorators.idempotent_id('10e4ecef-4309-4bda-9c4d-192e1b5a5831')
+ def test_check_requirements_for_auto_allocate_net_topology(self):
+ body = self.client.validate_auto_allocated_topology_requirements()
+ topology = body['auto_allocated_topology']
+ self.assertIn('dry-run', topology['id'])
+ self.assertIn('tenant_id', topology)
+ self.assertIn('project_id', topology)
+
@decorators.idempotent_id('64bc0b02-cee4-11e5-9f3c-080027605a2b')
def test_get_allocated_net_topology_as_tenant(self):
resources_before = self._count_topology_resources()
diff --git a/neutron_tempest_plugin/api/test_routers.py b/neutron_tempest_plugin/api/test_routers.py
index 66cea78..7758b1a 100644
--- a/neutron_tempest_plugin/api/test_routers.py
+++ b/neutron_tempest_plugin/api/test_routers.py
@@ -329,13 +329,10 @@
class ExternalGWMultihomingRoutersTest(base_routers.BaseRouterTest):
@classmethod
+ @tutils.requires_ext(extension="external-gateway-multihoming",
+ service="network")
def setUpClass(cls):
super().setUpClass()
- ext_alias = 'external-gateway-multihoming'
- try:
- cls.client.get_extension(ext_alias)
- except lib_exc.NotFound:
- raise cls.skipException(f'{ext_alias} extension not available.')
@decorators.idempotent_id('33e9a156-a83f-435f-90ee-1a49dc9c350d')
def test_create_router_enable_default_route_ecmp(self):
diff --git a/neutron_tempest_plugin/api/test_subnets.py b/neutron_tempest_plugin/api/test_subnets.py
index f7a38a4..23574ee 100644
--- a/neutron_tempest_plugin/api/test_subnets.py
+++ b/neutron_tempest_plugin/api/test_subnets.py
@@ -11,7 +11,6 @@
# under the License.
import netaddr
-from tempest.common import utils as tutils
from tempest.lib import decorators
from neutron_tempest_plugin.api import base
@@ -25,8 +24,6 @@
@classmethod
def resource_setup(cls):
- if tutils.is_extension_enabled('subnet-external-network', 'network'):
- cls.list_kwargs['router:external'] = False
super(SubnetsSearchCriteriaTest, cls).resource_setup()
net = cls.create_network(network_name='subnet-search-test-net')
for name in cls.resource_names:
@@ -70,6 +67,8 @@
@decorators.idempotent_id('c0f9280b-9d81-4728-a967-6be22659d4c8')
def test_list_validation_filters(self):
+ if 'subnet-external-network' in self.get_loaded_network_extensions():
+ self.list_kwargs['router:external'] = False
self._test_list_validation_filters(self.list_kwargs)
self._test_list_validation_filters({
'unknown_filter': 'value'}, filter_is_valid=False)
diff --git a/neutron_tempest_plugin/scenario/base.py b/neutron_tempest_plugin/scenario/base.py
index 72139de..6149b06 100644
--- a/neutron_tempest_plugin/scenario/base.py
+++ b/neutron_tempest_plugin/scenario/base.py
@@ -286,6 +286,7 @@
def setup_network_and_server(self, router=None, server_name=None,
network=None, use_stateless_sg=False,
+ create_fip=True, router_client=None,
**kwargs):
"""Create network resources and a server.
@@ -309,7 +310,8 @@
self.security_groups.append(secgroup['security_group'])
if not router:
router = self.create_router_by_client(**kwargs)
- self.create_router_interface(router['id'], self.subnet['id'])
+ self.create_router_interface(router['id'], self.subnet['id'],
+ client=router_client)
self.keypair = self.create_keypair()
self.create_loginable_secgroup_rule(
secgroup_id=secgroup['security_group']['id'])
@@ -331,7 +333,9 @@
self.port = self.client.list_ports(network_id=self.network['id'],
device_id=self.server[
'server']['id'])['ports'][0]
- self.fip = self.create_floatingip(port=self.port)
+
+ if create_fip:
+ self.fip = self.create_floatingip(port=self.port)
def check_connectivity(self, host, ssh_user=None, ssh_key=None,
servers=None, ssh_timeout=None, ssh_client=None):
@@ -696,3 +700,8 @@
except exceptions.SSHScriptFailed:
raise self.skipException(
"%s is not available on server %s" % (cmd, server['id']))
+
+
+class BaseAdminTempestTestCase(base_api.BaseAdminNetworkTest,
+ BaseTempestTestCase):
+ pass
diff --git a/neutron_tempest_plugin/scenario/test_multiple_gws.py b/neutron_tempest_plugin/scenario/test_multiple_gws.py
new file mode 100644
index 0000000..686457d
--- /dev/null
+++ b/neutron_tempest_plugin/scenario/test_multiple_gws.py
@@ -0,0 +1,750 @@
+# Copyright 2023 Canonical
+# All Rights Reserved.
+#
+# 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.
+import json
+import os
+import subprocess
+import time
+import typing
+
+import netaddr
+import testtools
+
+from tempest.common import utils as tutils
+
+from neutron_tempest_plugin import config
+from neutron_tempest_plugin.scenario import base
+
+from neutron_lib import constants as const
+
+from oslo_log import log
+
+from os_ken.tests.integrated.common import docker_base as ctn_base
+
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+
+CONF = config.CONF
+LOG = log.getLogger(__name__)
+
+
+class FRROCIImage(ctn_base.DockerImage):
+ def __init__(
+ self,
+ daemons: typing.Tuple[str],
+ baseimage: typing.Optional[str] = None,
+ use_existing: bool = False,
+ ):
+ super().__init__(baseimage=baseimage or 'ubuntu:22.04')
+ self.daemons = daemons
+ self.tagname = 'frr-' + '-'.join(daemons)
+ if use_existing and self.exist(self.tagname):
+ return
+
+ workdir = os.path.join(ctn_base.TEST_BASE_DIR, self.tagname)
+ pkgs = ' '.join(('telnet', 'tcpdump', 'frr'))
+ c = ctn_base.CmdBuffer()
+ c << f'FROM {self.baseimage}'
+ c << 'RUN apt-get update'
+ c << f'RUN apt-get install -qy --no-install-recommends {pkgs}'
+ c << 'RUN echo "#!/bin/sh" > /frr'
+ c << 'RUN echo mkdir -p /run/frr >> /frr'
+ c << 'RUN echo chmod 755 /run/frr >> /frr'
+ c << 'RUN echo chown frr:frr /run/frr >> /frr'
+ c << (
+ 'RUN echo exec /usr/lib/frr/watchfrr '
+ f'-F traditional {" ".join(self.daemons)}>> /frr'
+ )
+ c << 'RUN chmod +x /frr'
+ c << 'CMD /frr'
+
+ self.cmd.sudo(f'rm -rf {workdir}')
+ self.cmd.execute(f'mkdir -p {workdir}')
+ self.cmd.execute(f"echo '{str(c)}' > {workdir}/Dockerfile")
+ self.build(self.tagname, workdir)
+
+
+class FRRContainer(ctn_base.Container):
+ class veth_info(typing.NamedTuple):
+ bridge_name: str
+ bridge_type: str
+ ctn_ifname: str
+ host_ifname: str
+
+ _veths: typing.List[veth_info]
+
+ class route(typing.NamedTuple):
+ dst: netaddr.IPNetwork
+ next_hop: netaddr.IPNetwork
+
+ _ctn_routes: typing.List[route]
+
+ def __init__(
+ self,
+ name: str,
+ image: FRROCIImage,
+ ):
+ self._veths = []
+ self._ctn_routes = []
+ super().__init__(name, image.tagname)
+
+ # XXX upstream to os-ken
+ def next_if_name(self) -> str:
+ name = 'eth{0}'.format(len(self.eths))
+ self.eths.append(name)
+ return name
+
+ # XXX upstream to os-ken
+ def run(self, network: typing.Optional[str] = None) -> int:
+ c = ctn_base.CmdBuffer(' ')
+ c << "docker run --privileged=true"
+ for sv in self.shared_volumes:
+ c << "-v {0}:{1}".format(sv[0], sv[1])
+ if network:
+ c << "--network {0}".format(network)
+ c << "--name {0} --hostname {0} -id {1}".format(
+ self.docker_name(), self.image
+ )
+ self.id = self.dcexec(str(c), retry=True)
+ self.is_running = True
+ self.exec_on_ctn("ip li set up dev lo")
+ ipv4 = None
+ ipv6 = None
+ if network and network != 'none':
+ ifname = self.next_if_name()
+ for line in self.exec_on_ctn(f"ip a show dev {ifname}").split(
+ '\n'
+ ):
+ if line.strip().startswith("inet "):
+ elems = [e.strip() for e in line.strip().split(' ')]
+ ipv4 = elems[1]
+ elif line.strip().startswith("inet6 "):
+ elems = [e.strip() for e in line.strip().split(' ')]
+ ipv6 = elems[1]
+ self.set_addr_info(
+ bridge='docker0', ipv4=ipv4, ipv6=ipv6, ifname=ifname
+ )
+ return 0
+
+ def wait_for_frr_daemons_up(
+ self,
+ try_times: int = 30,
+ interval: int = 1,
+ ) -> ctn_base.CommandOut:
+ return self.cmd.sudo(
+ f'docker logs {self.docker_name()} '
+ '|grep "WATCHFRR.*all daemons up"',
+ try_times=try_times,
+ interval=interval,
+ )
+
+ @staticmethod
+ def hash_ifname(ifname: str) -> str:
+ # Assuming IFNAMSIZ of 16, with null-termination gives 15 characters.
+ return 'veth' + str(hash(ifname) % 10**11)
+
+ @staticmethod
+ def get_if_mac(ifname: str) -> netaddr.EUI:
+ with open(f'/sys/class/net/{ifname}/address') as faddr:
+ return faddr.readline().rstrip()
+
+ def add_veth_to_bridge(
+ self,
+ bridge_name: str,
+ bridge_type: str,
+ ipv4_cidr: str,
+ ipv6_cidr: str,
+ ipv6_prefix: typing.Optional[netaddr.IPNetwork] = None,
+ vlan: typing.Optional[int] = None,
+ ) -> None:
+ assert self.is_running, (
+ 'the container must be running before '
+ 'calling add_veth_to_bridge'
+ )
+ assert (
+ bridge_type == ctn_base.BRIDGE_TYPE_OVS
+ ), f'bridge_type must be {ctn_base.BRIDGE_TYPE_OVS}'
+ veth_pair = (
+ self.hash_ifname(f'{self.name}-int{len(self._veths)}'),
+ self.hash_ifname(f'{self.name}-ext{len(self._veths)}'),
+ )
+ self.cmd.sudo(
+ f'ip link add {veth_pair[0]} type veth peer name {veth_pair[1]}'
+ )
+ if ipv6_prefix and not ipv6_cidr:
+ eui = netaddr.EUI(self.get_if_mac(veth_pair[0]))
+ ipv6_cidr = (
+ f'{eui.ipv6(ipv6_prefix.first)}/{ipv6_prefix.prefixlen}'
+ )
+
+ self.cmd.sudo(f'ip link set netns {self.get_pid()} dev {veth_pair[0]}')
+ self.cmd.sudo(f'ovs-vsctl add-port {bridge_name} {veth_pair[1]}')
+ if vlan:
+ self.cmd.sudo(f'ovs-vsctl set port {veth_pair[1]} tag={vlan}')
+
+ ifname = self.next_if_name()
+ self.exec_on_ctn(f'ip link set name {ifname} {veth_pair[0]}')
+
+ # Ensure IPv6 is not disabled in container
+ self.exec_on_ctn('sysctl -w net.ipv6.conf.all.disable_ipv6=0')
+
+ for cidr in (ipv4_cidr, ipv6_cidr):
+ if not cidr:
+ continue
+ self.exec_on_ctn(f'ip addr add {cidr} dev {ifname}')
+ self.exec_on_ctn(f'ip link set up dev {ifname}')
+ self.cmd.sudo(f'ip link set up dev {veth_pair[1]}')
+ self.set_addr_info(
+ bridge_name, ipv4=ipv4_cidr, ipv6=ipv6_cidr, ifname=ifname
+ )
+ self._veths.append(
+ self.veth_info(
+ bridge_name=bridge_name,
+ bridge_type=bridge_type,
+ ctn_ifname=ifname,
+ host_ifname=veth_pair[1],
+ )
+ )
+
+ def add_ctn_route(self, route: route) -> None:
+ self.exec_on_ctn(
+ f'ip -{route.dst.version} route add '
+ f'{str(route.dst.cidr)} via {str(route.next_hop.ip)}'
+ )
+ self._ctn_routes.append(route)
+
+ def del_ctn_route(self, route: route) -> None:
+ self.exec_on_ctn(
+ f'ip -{route.dst.version} route del '
+ f'{str(route.dst.cidr)} via {str(route.next_hop.ip)}'
+ )
+ self._ctn_routes.remove(route)
+
+ def remove(self, check_exist=True) -> ctn_base.CommandOut:
+ for veth in self._veths:
+ # The veth pair itself will be destroyed as a side effect of
+ # removing the container, so we only need to clean up the bridge
+ # attachment.
+ if veth.bridge_type == ctn_base.BRIDGE_TYPE_BRCTL:
+ self.cmd.sudo(
+ 'brctl delif ' f'{veth.bridge_name} ' f'{veth.host_ifname}'
+ )
+ elif veth.bridge_type == ctn_base.BRIDGE_TYPE_OVS:
+ self.cmd.sudo(
+ 'ovs-vsctl del-port '
+ f'{veth.bridge_name} '
+ f'{veth.host_ifname}'
+ )
+ super().remove(check_exist=check_exist)
+
+ def vtysh(self, cmd: typing.List[str]) -> ctn_base.CommandOut:
+ cmd_str = ' '.join(f"-c '{c}'" for c in cmd)
+ return self.exec_on_ctn(f'vtysh {cmd_str}', capture=True)
+
+
+class BFDContainer(FRRContainer):
+ def __init__(
+ self,
+ name: str,
+ image: typing.Optional[FRROCIImage] = None,
+ ):
+ image = image or FRROCIImage(
+ daemons=('zebra', 'bfdd'), use_existing=True
+ )
+ super().__init__(name, image)
+ assert 'bfdd' in image.daemons
+
+ def add_bfd_peer(self, ip_address: str) -> None:
+ self.vtysh(
+ [
+ 'enable',
+ 'conf',
+ 'bfd',
+ f'peer {ip_address} interface eth0',
+ ]
+ )
+
+ def del_bfd_peer(self, ip_address: str) -> None:
+ self.vtysh(
+ [
+ 'enable',
+ 'conf',
+ 'bfd',
+ f'no peer {ip_address} interface eth0',
+ ]
+ )
+
+ def show_bfd_peer(self, peer: str) -> typing.Dict[str, typing.Any]:
+ return json.loads(self.vtysh([f'show bfd peer {peer} json']))
+
+ def wait_for_bfd_peer_status(
+ self, peer: str, status: str, try_times=30, interval=1
+ ) -> None:
+ while try_times:
+ peer_data = self.show_bfd_peer(peer)
+ if peer_data['status'] == status:
+ return
+ time.sleep(interval)
+ try_times -= 1
+ raise lib_exc.TimeoutException
+
+
+class NetworkMultipleGWTest(base.BaseAdminTempestTestCase):
+ """Test the following topology
+
+ +------------------------------------------------------------------+
+ | test runner |
+ | |
+ | +-----------+ eth0 public VLAN N |
+ | +-------- br-ex ----------+ | FRR w/BFD | |
+ | | +---------------------+ | +-----------+ eth1 public flat |
+ | | | public physnet | | +-----------+ eth0 public VLAN N |
+ | | +---------------------+ | | FRR w/BFD | |
+ | +-------------------------+ +-----------+ eth1 public flat |
+ | | | |
+ +-----|--------------|---------------------------------------------+
+ | - VLAN N - |
+ +-------------------------+
+ | project router | - enable_default_route_{bfd,ecmp}=True
+ +-------------------------+
+ |
+ +----------+
+ | instance |
+ +----------+
+
+ NOTE(fnordahl) At the time of writing, FRR provides a BFD daemon, but has
+ not integrated it with static routes [0][1]. As a consequence the
+ test will manually add/remove routes on test runner to ensure correct path
+ is chosen for traffic from test runner to instance. On the return path the
+ BFD implementation in OVN will ensure the correct path is chosen
+ automatically.
+
+ In real world usage most vendors have BFD support for static routes.
+
+ 0: https://github.com/FRRouting/frr/wiki/Feature-Requests
+ 1: https://github.com/FRRouting/frr/issues/3369
+ """
+ class host_route(typing.NamedTuple):
+ dst: netaddr.IPNetwork
+ next_hop: netaddr.IPNetwork
+
+ host_routes: typing.List[host_route] = []
+
+ credentials = ['primary', 'admin']
+
+ @classmethod
+ def setup_clients(cls):
+ super().setup_clients()
+ if not cls.admin_client:
+ cls.admin_client = cls.os_admin.network_client
+
+ @classmethod
+ @tutils.requires_ext(extension="external-gateway-multihoming",
+ service="network")
+ def resource_setup(cls):
+ super().resource_setup()
+
+ # Ensure devstack configured public subnets are recorded, so that we
+ # don't attempt to use them again.
+ cls.reserve_external_subnet_cidrs()
+
+ # We need to know prefixlength of the devstack configured public
+ # subnets.
+ for subnet_id in cls.admin_client.show_network(
+ CONF.network.public_network_id)['network']['subnets']:
+ subnet = cls.admin_client.show_subnet(subnet_id)['subnet']
+ if subnet['ip_version'] == 4:
+ cls.public_ipv4_subnet = subnet
+ continue
+ cls.public_ipv6_subnet = subnet
+ cls.ext_networks = []
+ for n in range(0, 2):
+ ext_network = cls.create_provider_network(
+ physnet_name='public',
+ start_segmentation_id=4040 + n,
+ external=True,
+ )
+ ext_ipv6_subnet = cls.create_subnet(
+ ext_network,
+ ip_version=const.IP_VERSION_6,
+ client=cls.admin_client,
+ )
+ ext_ipv4_subnet = cls.create_subnet(
+ ext_network,
+ ip_version=const.IP_VERSION_4,
+ client=cls.admin_client,
+ )
+ cls.ext_networks.append(
+ (ext_network, ext_ipv6_subnet, ext_ipv4_subnet)
+ )
+ cls.host_routes = []
+ cls.resource_setup_container()
+
+ @classmethod
+ def resource_setup_container(cls):
+ cls.containers = []
+ for n in range(0, 2):
+ ext_network, ext_ipv6_subnet, ext_ipv4_subnet = cls.ext_networks[n]
+
+ # frr container
+ bfd_container = BFDContainer(data_utils.rand_name('frr'))
+ cls.containers.append(bfd_container)
+
+ bfd_container.run(network='none')
+ public_ipv6_net = netaddr.IPNetwork(cls.public_ipv6_subnet['cidr'])
+ public_ipv4_net = netaddr.IPNetwork(cls.public_ipv4_subnet['cidr'])
+ ipv6_net = netaddr.IPNetwork(ext_ipv6_subnet['cidr'])
+ ipv4_net = netaddr.IPNetwork(ext_ipv4_subnet['cidr'])
+ # reserve an IP for container on the public network for routing
+ # into the vlan network.
+ fip_address = cls.create_floatingip()['floating_ip_address']
+ cls.veths = [
+ bfd_container.add_veth_to_bridge(
+ 'br-ex',
+ ctn_base.BRIDGE_TYPE_OVS,
+ f'{ext_ipv4_subnet["gateway_ip"]}/{ipv4_net.prefixlen}',
+ f'{ext_ipv6_subnet["gateway_ip"]}/{ipv6_net.prefixlen}',
+ vlan=ext_network['provider:segmentation_id'],
+ ),
+ bfd_container.add_veth_to_bridge(
+ 'br-ex',
+ ctn_base.BRIDGE_TYPE_OVS,
+ f'{fip_address}/{public_ipv4_net.prefixlen}',
+ '',
+ ipv6_prefix=public_ipv6_net,
+ ),
+ ]
+ for subnet in (cls.public_ipv4_subnet, cls.public_ipv6_subnet):
+ bfd_container.exec_on_ctn(
+ f'ip -{subnet["ip_version"]} route add default '
+ f'via {subnet["gateway_ip"]} dev eth1'
+ )
+ for ip_version in (6, 4):
+ for addr_info in bfd_container.get_addr_info(
+ 'br-ex', ip_version
+ ).items():
+ if addr_info[1] == 'eth1':
+ if ip_version == 6:
+ dst_subnet = ext_ipv6_subnet
+ else:
+ dst_subnet = ext_ipv4_subnet
+ cls.add_host_route(
+ cls.host_routes,
+ cls.host_route(
+ netaddr.IPNetwork(dst_subnet["cidr"]),
+ netaddr.IPNetwork(addr_info[0]),
+ ),
+ )
+ bfd_container.wait_for_frr_daemons_up()
+
+ @classmethod
+ def resource_cleanup(cls):
+ # Ensure common cleanup code can clean up resources created by admin
+ cls.client = cls.admin_client
+ super().resource_cleanup()
+ for ctn in cls.containers:
+ try:
+ ctn.stop()
+ except ctn_base.CommandError:
+ pass
+ ctn.remove()
+ # NOTE(fnordahl): the loop body modifies the list, so we need to
+ # iterate on a copy.
+ for route in cls.host_routes.copy():
+ cls.del_host_route(cls.host_routes, route)
+
+ @staticmethod
+ def add_host_route(
+ lst: typing.List[host_route],
+ route: host_route
+ ) -> None:
+ subprocess.run(
+ (
+ 'sudo',
+ 'ip',
+ f'-{route.dst.version}',
+ 'route',
+ 'add',
+ str(route.dst.cidr),
+ 'via',
+ str(route.next_hop.ip),
+ ),
+ capture_output=True,
+ check=True,
+ universal_newlines=True,
+ )
+ lst.append(route)
+
+ @staticmethod
+ def del_host_route(
+ lst: typing.List[host_route],
+ route: host_route
+ ) -> None:
+ subprocess.run(
+ (
+ 'sudo',
+ 'ip',
+ f'-{route.dst.version}',
+ 'route',
+ 'del',
+ str(route.dst.cidr),
+ 'via',
+ str(route.next_hop.ip),
+ ),
+ capture_output=True,
+ check=True,
+ universal_newlines=True,
+ )
+ lst.remove(route)
+
+ def add_ctn_route(
+ self,
+ ctn: BFDContainer,
+ dst: netaddr.IPNetwork,
+ next_hop: netaddr.IPNetwork,
+ ):
+ ctn_route = ctn.route(dst, next_hop)
+ ctn.add_ctn_route(ctn_route)
+ self.per_test_ctn_routes.append((ctn, ctn_route))
+
+ def setUp(self):
+ super().setUp()
+ self.per_test_host_routes = []
+ self.per_test_ctn_routes = []
+
+ def tearDown(self):
+ super().tearDown()
+ # NOTE(fnordahl): the loop body modifies the list, so we need to
+ # iterate on a copy.
+ for ctn_route in self.per_test_ctn_routes.copy():
+ ctn = ctn_route[0]
+ route = ctn_route[1]
+ ctn.del_ctn_route(route)
+ for host_route in self.per_test_host_routes.copy():
+ self.del_host_route(self.per_test_host_routes, host_route)
+
+ def add_routes_for_router(
+ self,
+ router: typing.Dict[str, typing.Any],
+ ctn: FRRContainer,
+ add_ctn_route: bool = True,
+ add_host_route: bool = True,
+ ):
+ for port in self.admin_client.list_router_interfaces(router['id'])[
+ 'ports'
+ ]:
+ if port['device_owner'] != const.DEVICE_OWNER_ROUTER_INTF:
+ continue
+ for fixed_ip in port['fixed_ips']:
+ subnet = self.client.show_subnet(
+ fixed_ip['subnet_id'])['subnet']
+ for addr_info in ctn.get_addr_info(
+ 'br-ex',
+ subnet['ip_version'],
+ ).items():
+ if addr_info[1] == 'eth0':
+ # container route
+ ctn_net = netaddr.IPNetwork(addr_info[0])
+ for gw_info in router['external_gateways']:
+ for ip_info in gw_info['external_fixed_ips']:
+ if (
+ ip_info['ip_address'] in ctn_net and
+ add_ctn_route
+ ):
+ self.add_ctn_route(
+ ctn,
+ netaddr.IPNetwork(subnet['cidr']),
+ netaddr.IPNetwork(
+ ip_info['ip_address']
+ ),
+ )
+ elif addr_info[1] == 'eth1' and add_host_route:
+ self.add_host_route(
+ self.per_test_host_routes,
+ self.host_route(
+ netaddr.IPNetwork(self.subnet['cidr']),
+ netaddr.IPNetwork(addr_info[0]),
+ ),
+ )
+
+ @testtools.skipUnless(
+ CONF.compute.min_compute_nodes == 1,
+ 'More than 1 compute node, test only works on '
+ 'single node configurations.',
+ )
+ @decorators.idempotent_id('9baa05e6-ba10-4850-93e3-695f4d97b8f8')
+ def test_create_router_single_gw_bfd(self):
+ ext_network_id = self.ext_networks[0][0]['id']
+ bfd_container = self.containers[0]
+ router = self.create_admin_router(
+ router_name=data_utils.rand_name('router'),
+ admin_state_up=True,
+ enable_snat=False,
+ enable_default_route_bfd=True,
+ external_network_id=ext_network_id,
+ )
+ self.assertTrue(router['enable_default_route_bfd'])
+
+ # Add BFD peers on bfd_container.
+ for gw_info in router['external_gateways']:
+ for ip_info in gw_info['external_fixed_ips']:
+ bfd_container.add_bfd_peer(ip_info["ip_address"])
+ bfd_container.wait_for_bfd_peer_status(
+ ip_info['ip_address'], 'up'
+ )
+
+ self.setup_network_and_server(
+ router=router,
+ create_fip=False,
+ router_client=self.admin_client,
+ )
+
+ self.add_routes_for_router(router, bfd_container)
+
+ # check connectivity
+ self.check_connectivity(
+ self.port['fixed_ips'][0]['ip_address'],
+ CONF.validation.image_ssh_user,
+ self.keypair['private_key'],
+ )
+
+ @testtools.skipUnless(
+ CONF.compute.min_compute_nodes == 1,
+ 'More than 1 compute node, test only works on '
+ 'single node configurations.',
+ )
+ @decorators.idempotent_id('75202251-c384-4962-8685-60cf2c530906')
+ def test_update_router_single_gw_bfd(self):
+ ext_network_id = self.ext_networks[0][0]['id']
+ bfd_container = self.containers[0]
+ router = self.create_router(
+ router_name=data_utils.rand_name('router'),
+ admin_state_up=True,
+ enable_snat=False,
+ external_network_id=ext_network_id,
+ )
+ self.assertFalse(router['enable_default_route_bfd'])
+
+ self.setup_network_and_server(
+ router=router,
+ create_fip=False,
+ router_client=self.admin_client,
+ )
+
+ self.add_routes_for_router(router, bfd_container)
+
+ # check connectivity
+ self.check_connectivity(
+ self.port['fixed_ips'][0]['ip_address'],
+ CONF.validation.image_ssh_user,
+ self.keypair['private_key'],
+ )
+
+ # Enable BFD on router.
+ #
+ # NOTE(fnordahl): We need to repeat the `enable_snat` state, otherwise
+ # the state will be toggled to the default value of 'True'.
+ router = self.admin_client.update_router_with_snat_gw_info(
+ router['id'],
+ enable_snat=False,
+ enable_default_route_bfd=True,
+ )['router']
+ self.assertTrue(router['enable_default_route_bfd'])
+
+ # Add BFD peers on bfd_container.
+ for gw_info in router['external_gateways']:
+ for ip_info in gw_info['external_fixed_ips']:
+ bfd_container.add_bfd_peer(ip_info["ip_address"])
+ bfd_container.wait_for_bfd_peer_status(
+ ip_info['ip_address'], 'up'
+ )
+
+ # check connectivity
+ self.check_connectivity(
+ self.port['fixed_ips'][0]['ip_address'],
+ CONF.validation.image_ssh_user,
+ self.keypair['private_key'],
+ )
+
+ @testtools.skipUnless(
+ CONF.compute.min_compute_nodes == 1,
+ 'More than 1 compute node, test only works on '
+ 'single node configurations.',
+ )
+ @decorators.idempotent_id('5117587d-9633-48b7-aa8f-ec9d59a601a5')
+ def test_create_router_multiple_gw_bfd_and_ecmp(self):
+ router = self.create_admin_router(
+ router_name=data_utils.rand_name('router'),
+ admin_state_up=True,
+ enable_default_route_bfd=True,
+ enable_default_route_ecmp=True,
+ )
+ router = self.admin_client.router_add_external_gateways(
+ router['id'],
+ [
+ {
+ 'network_id': self.ext_networks[0][0]['id'],
+ 'enable_snat': False,
+ },
+ {
+ 'network_id': self.ext_networks[1][0]['id'],
+ 'enable_snat': False,
+ },
+ ],
+ )['router']
+
+ self.setup_network_and_server(
+ router=router,
+ create_fip=False,
+ router_client=self.admin_client,
+ )
+
+ # Add BFD peers on bfd_containers.
+ for gw_info in router['external_gateways']:
+ for ip_info in gw_info['external_fixed_ips']:
+ ip = netaddr.IPAddress(ip_info['ip_address'])
+ for ctn in self.containers:
+ for addr_info in ctn.get_addr_info(
+ 'br-ex',
+ ip.version,
+ ).items():
+ if addr_info[1] == 'eth0':
+ ctn_net = netaddr.IPNetwork(addr_info[0])
+ if ip not in ctn_net:
+ break
+ ctn.add_bfd_peer(str(ip))
+ ctn.wait_for_bfd_peer_status(str(ip), 'up')
+
+ # Add route to project network on all containers.
+ for ctn in self.containers:
+ self.add_routes_for_router(router, ctn, True, False)
+
+ # Add host route to project network via FRR container and confirm
+ # connectivity one by one.
+ #
+ # We deliberately don't add both host routes at once as that would be
+ # testing test runner configuration and linux kernel ECMP, which is out
+ # of scope for our test.
+ for ctn in self.containers:
+ self.add_routes_for_router(router, ctn, False, True)
+
+ # check connectivity
+ self.check_connectivity(
+ self.port['fixed_ips'][0]['ip_address'],
+ CONF.validation.image_ssh_user,
+ self.keypair['private_key'],
+ )
+ for host_route in self.per_test_host_routes.copy():
+ self.del_host_route(self.per_test_host_routes, host_route)
diff --git a/neutron_tempest_plugin/services/network/json/network_client.py b/neutron_tempest_plugin/services/network/json/network_client.py
index 1153a2a..289ef61 100644
--- a/neutron_tempest_plugin/services/network/json/network_client.py
+++ b/neutron_tempest_plugin/services/network/json/network_client.py
@@ -804,6 +804,14 @@
body = jsonutils.loads(body)
return service_client.ResponseBody(resp, body)
+ def validate_auto_allocated_topology_requirements(self, tenant_id=None):
+ uri = '%s/auto-allocated-topology/%s?fields=dry-run' % (
+ self.uri_prefix, tenant_id)
+ resp, body = self.get(uri)
+ self.expected_success(200, resp.status)
+ body = jsonutils.loads(body)
+ return service_client.ResponseBody(resp, body)
+
def get_auto_allocated_topology(self, tenant_id=None):
uri = '%s/auto-allocated-topology/%s' % (self.uri_prefix, tenant_id)
resp, body = self.get(uri)
diff --git a/playbooks/plugin-ovn-scenario-pre-run.yaml b/playbooks/plugin-ovn-scenario-pre-run.yaml
new file mode 100644
index 0000000..925223e
--- /dev/null
+++ b/playbooks/plugin-ovn-scenario-pre-run.yaml
@@ -0,0 +1,3 @@
+- hosts: all
+ roles:
+ - docker-setup
diff --git a/requirements.txt b/requirements.txt
index 9423079..957f186 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,14 +1,10 @@
-# The order of packages is significant, because pip processes them in the order
-# of appearance. Changing the order has an impact on the overall integration
-# process, which may cause wedges in the gate later.
-
-pbr!=2.1.0,>=2.0.0 # Apache-2.0
+pbr>=3.0.0 # Apache-2.0
neutron-lib>=1.25.0 # Apache-2.0
oslo.config>=5.2.0 # Apache-2.0
netaddr>=0.7.18 # BSD
os-ken>=0.3.0 # Apache-2.0
oslo.log>=3.36.0 # Apache-2.0
-oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
+oslo.serialization>=2.20.0 # Apache-2.0
oslo.utils>=3.33.0 # Apache-2.0
packaging>=20.4 # Apache-2.0
paramiko>=2.0.0 # LGPLv2.1+
@@ -16,5 +12,5 @@
tenacity>=3.2.1 # Apache-2.0
ddt>=1.0.1 # MIT
testtools>=2.2.0 # MIT
-eventlet!=0.18.3,!=0.20.1,>=0.18.2 # MIT
+eventlet>=0.21.0 # MIT
debtcollector>=1.2.0 # Apache-2.0
diff --git a/test-requirements.txt b/test-requirements.txt
index f5bac7c..0151f21 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,10 +1,6 @@
-# The order of packages is significant, because pip processes them in the order
-# of appearance. Changing the order has an impact on the overall integration
-# process, which may cause wedges in the gate later.
-
hacking>=3.2.0,<3.3.0 # Apache-2.0
-coverage!=4.4,>=4.0 # Apache-2.0
+coverage>=4.4.1 # Apache-2.0
flake8-import-order==0.12 # LGPLv3
python-subunit>=1.0.0 # Apache-2.0/BSD
oslotest>=3.2.0 # Apache-2.0
diff --git a/zuul.d/base-nested-switch.yaml b/zuul.d/base-nested-switch.yaml
index 8533e07..f8fa799 100644
--- a/zuul.d/base-nested-switch.yaml
+++ b/zuul.d/base-nested-switch.yaml
@@ -34,9 +34,10 @@
# NOTE(ykarel): seeing issues with host-passthrough mode
# https://bugs.launchpad.net/neutron/+bug/2036603
# LIBVIRT_CPU_MODE: host-passthrough
- CIRROS_VERSION: 0.6.2
- DEFAULT_IMAGE_NAME: cirros-0.6.2-x86_64-disk
- DEFAULT_IMAGE_FILE_NAME: cirros-0.6.2-x86_64-disk.img
+ # TODO(ykarel): switch to 0.6.2+ once lp#2045549 is fixed
+ CIRROS_VERSION: 0.5.3
+ DEFAULT_IMAGE_NAME: cirros-0.5.3-x86_64-disk
+ DEFAULT_IMAGE_FILE_NAME: cirros-0.5.3-x86_64-disk.img
# Base nested switch job for yoga and zed
- job:
diff --git a/zuul.d/master_jobs.yaml b/zuul.d/master_jobs.yaml
index d47ff64..393e772 100644
--- a/zuul.d/master_jobs.yaml
+++ b/zuul.d/master_jobs.yaml
@@ -218,14 +218,24 @@
- ^roles/.*functional.*$
- ^playbooks/.*functional.*$
- ^vagrant/.*$
- - ^zuul.d/(?!(project)).*\.yaml
+ # Ignore everything except for zuul.d/project.yaml
+ - ^zuul.d/2023_1_jobs.yaml
+ - ^zuul.d/2023_2_jobs.yaml
+ - ^zuul.d/2024_1_jobs.yaml
+ - ^zuul.d/base-nested-switch.yaml
+ - ^zuul.d/master_jobs.yaml
+ - ^zuul.d/victoria_jobs.yaml
+ - ^zuul.d/wallaby_jobs.yaml
+ - ^zuul.d/xena_jobs.yaml
+ - ^zuul.d/yoga_jobs.yaml
+ - ^zuul.d/zed_jobs.yaml
- job:
name: neutron-tempest-plugin-openvswitch
parent: neutron-tempest-plugin-base-nested-switch
timeout: 10000
vars:
- configure_swap_size: 2048
+ configure_swap_size: 3072
devstack_services:
# Disable OVN services
br-ex-tcpdump: false
@@ -314,14 +324,24 @@
- ^playbooks/.*functional.*$
- ^playbooks/.*linuxbridge.*$
- ^vagrant/.*$
- - ^zuul.d/(?!(project)).*\.yaml
+ # Ignore everything except for zuul.d/project.yaml
+ - ^zuul.d/2023_1_jobs.yaml
+ - ^zuul.d/2023_2_jobs.yaml
+ - ^zuul.d/2024_1_jobs.yaml
+ - ^zuul.d/base-nested-switch.yaml
+ - ^zuul.d/master_jobs.yaml
+ - ^zuul.d/victoria_jobs.yaml
+ - ^zuul.d/wallaby_jobs.yaml
+ - ^zuul.d/xena_jobs.yaml
+ - ^zuul.d/yoga_jobs.yaml
+ - ^zuul.d/zed_jobs.yaml
- job:
name: neutron-tempest-plugin-openvswitch-iptables_hybrid
parent: neutron-tempest-plugin-base-nested-switch
timeout: 10000
vars:
- configure_swap_size: 2048
+ configure_swap_size: 3072
devstack_services:
# Disable OVN services
br-ex-tcpdump: false
@@ -419,7 +439,17 @@
- ^playbooks/.*functional.*$
- ^playbooks/.*linuxbridge.*$
- ^vagrant/.*$
- - ^zuul.d/(?!(project)).*\.yaml
+ # Ignore everything except for zuul.d/project.yaml
+ - ^zuul.d/2023_1_jobs.yaml
+ - ^zuul.d/2023_2_jobs.yaml
+ - ^zuul.d/2024_1_jobs.yaml
+ - ^zuul.d/base-nested-switch.yaml
+ - ^zuul.d/master_jobs.yaml
+ - ^zuul.d/victoria_jobs.yaml
+ - ^zuul.d/wallaby_jobs.yaml
+ - ^zuul.d/xena_jobs.yaml
+ - ^zuul.d/yoga_jobs.yaml
+ - ^zuul.d/zed_jobs.yaml
- job:
name: neutron-tempest-plugin-openvswitch-enforce-scope-old-defaults
@@ -479,7 +509,7 @@
- zuul: openstack/neutron
pre-run: playbooks/linuxbridge-scenario-pre-run.yaml
vars:
- configure_swap_size: 2048
+ configure_swap_size: 3072
devstack_services:
# Disable OVN services
br-ex-tcpdump: false
@@ -584,7 +614,17 @@
- ^playbooks/.*dynamic-routing.*$
- ^playbooks/.*functional.*$
- ^vagrant/.*$
- - ^zuul.d/(?!(project)).*\.yaml
+ # Ignore everything except for zuul.d/project.yaml
+ - ^zuul.d/2023_1_jobs.yaml
+ - ^zuul.d/2023_2_jobs.yaml
+ - ^zuul.d/2024_1_jobs.yaml
+ - ^zuul.d/base-nested-switch.yaml
+ - ^zuul.d/master_jobs.yaml
+ - ^zuul.d/victoria_jobs.yaml
+ - ^zuul.d/wallaby_jobs.yaml
+ - ^zuul.d/xena_jobs.yaml
+ - ^zuul.d/yoga_jobs.yaml
+ - ^zuul.d/zed_jobs.yaml
# TODO(slaweq): remove that job's definition as soon as new job
# "neutron-tempest-plugin-linuxbridge" will be used in the neutron repo as
@@ -597,9 +637,11 @@
name: neutron-tempest-plugin-ovn
parent: neutron-tempest-plugin-base-nested-switch
timeout: 10800
+ pre-run: playbooks/plugin-ovn-scenario-pre-run.yaml
vars:
network_api_extensions_ovn:
- vlan-transparent
+ - external-gateway-multihoming
# TODO(jlibosva): Remove the NetworkWritableMtuTest test from the list
# once east/west fragmentation is supported in core OVN
tempest_exclude_regex: "\
@@ -661,6 +703,8 @@
/$NEUTRON_CORE_PLUGIN_CONF:
ml2:
type_drivers: local,flat,vlan,geneve
+ ml2_type_vlan:
+ network_vlan_ranges: foo:1:10,public
test-config:
$TEMPEST_CONFIG:
network-feature-enabled:
@@ -672,6 +716,8 @@
zuul_copy_output:
'{{ devstack_base_dir }}/data/ovs': 'logs'
'{{ devstack_base_dir }}/data/ovn': 'logs'
+ '{{ devstack_log_dir }}/ovn-controller.log': 'logs'
+ '{{ devstack_log_dir }}/ovn-northd.log': 'logs'
'{{ devstack_log_dir }}/ovsdb-server-nb.log': 'logs'
'{{ devstack_log_dir }}/ovsdb-server-sb.log': 'logs'
'/var/log/ovn': 'logs'
@@ -722,7 +768,17 @@
- ^playbooks/.*functional.*$
- ^playbooks/.*linuxbridge.*$
- ^vagrant/.*$
- - ^zuul.d/(?!(project)).*\.yaml
+ # Ignore everything except for zuul.d/project.yaml
+ - ^zuul.d/2023_1_jobs.yaml
+ - ^zuul.d/2023_2_jobs.yaml
+ - ^zuul.d/2024_1_jobs.yaml
+ - ^zuul.d/base-nested-switch.yaml
+ - ^zuul.d/master_jobs.yaml
+ - ^zuul.d/victoria_jobs.yaml
+ - ^zuul.d/wallaby_jobs.yaml
+ - ^zuul.d/xena_jobs.yaml
+ - ^zuul.d/yoga_jobs.yaml
+ - ^zuul.d/zed_jobs.yaml
# TODO(slaweq): remove that job's definition as soon as new job
# "neutron-tempest-plugin-ovn" will be used in the neutron-lib repo as
@@ -732,6 +788,22 @@
parent: neutron-tempest-plugin-ovn
- job:
+ name: neutron-tempest-plugin-api-ovs-wsgi
+ parent: neutron-tempest-plugin-openvswitch
+ voting: false
+ vars:
+ devstack_localrc:
+ NEUTRON_DEPLOY_MOD_WSGI: true
+
+- job:
+ name: neutron-tempest-plugin-api-ovn-wsgi
+ parent: neutron-tempest-plugin-ovn
+ voting: false
+ vars:
+ devstack_localrc:
+ NEUTRON_DEPLOY_MOD_WSGI: true
+
+- job:
name: neutron-tempest-plugin-dvr-multinode-scenario
parent: tempest-multinode-full
description: |
@@ -952,7 +1024,17 @@
- ^playbooks/.*functional.*$
- ^playbooks/.*linuxbridge.*$
- ^vagrant/.*$
- - ^zuul.d/(?!(project)).*\.yaml
+ # Ignore everything except for zuul.d/project.yaml
+ - ^zuul.d/2023_1_jobs.yaml
+ - ^zuul.d/2023_2_jobs.yaml
+ - ^zuul.d/2024_1_jobs.yaml
+ - ^zuul.d/base-nested-switch.yaml
+ - ^zuul.d/master_jobs.yaml
+ - ^zuul.d/victoria_jobs.yaml
+ - ^zuul.d/wallaby_jobs.yaml
+ - ^zuul.d/xena_jobs.yaml
+ - ^zuul.d/yoga_jobs.yaml
+ - ^zuul.d/zed_jobs.yaml
- job:
name: neutron-tempest-plugin-designate-scenario
@@ -1001,7 +1083,7 @@
- ^neutron/privileged/.*$
- ^neutron/plugins/ml2/drivers/.*$
- ^neutron/scheduler/.*$
- - ^neutron/services/(?!externaldns).*$
+ - ^neutron/services/.*$
- ^neutron_tempest_plugin/api/test_.*$
- ^neutron_tempest_plugin/(bgpvpn|fwaas|neutron_dynamic_routing|sfc|tap_as_a_service|vpnaas).*$
- ^neutron_tempest_plugin/services/bgp/.*$
@@ -1012,7 +1094,40 @@
- ^playbooks/.*functional.*$
- ^playbooks/.*linuxbridge.*$
- ^vagrant/.*$
- - ^zuul.d/(?!(project)).*\.yaml
+ # Ignore everything except for neutron/services/externaldns/
+ - ^neutron/services/auto_allocate/.*$
+ - ^neutron/services/conntrack_helper/.*$
+ - ^neutron/services/firewall/.*$
+ - ^neutron/services/flavors/.*$
+ - ^neutron/services/l3_router/.*$
+ - ^neutron/services/local_ip/.*$
+ - ^neutron/services/logapi/.*$
+ - ^neutron/services/loki/.*$
+ - ^neutron/services/metering/.*$
+ - ^neutron/services/ndp_proxy/.*$
+ - ^neutron/services/network_ip_availability/.*$
+ - ^neutron/services/network_segment_range/.*$
+ - ^neutron/services/ovn_l3/.*$
+ - ^neutron/services/placement_report/.*$
+ - ^neutron/services/portforwarding/.*$
+ - ^neutron/services/qos/.*$
+ - ^neutron/services/rbac/.*$
+ - ^neutron/services/revisions/.*$
+ - ^neutron/services/segments/.*$
+ - ^neutron/services/tag/.*$
+ - ^neutron/services/timestamp/.*$
+ - ^neutron/services/trunk/.*$
+ # Ignore everything except for zuul.d/project.yaml
+ - ^zuul.d/2023_1_jobs.yaml
+ - ^zuul.d/2023_2_jobs.yaml
+ - ^zuul.d/2024_1_jobs.yaml
+ - ^zuul.d/base-nested-switch.yaml
+ - ^zuul.d/master_jobs.yaml
+ - ^zuul.d/victoria_jobs.yaml
+ - ^zuul.d/wallaby_jobs.yaml
+ - ^zuul.d/xena_jobs.yaml
+ - ^zuul.d/yoga_jobs.yaml
+ - ^zuul.d/zed_jobs.yaml
- job:
name: neutron-tempest-plugin-sfc
@@ -1088,7 +1203,17 @@
- ^playbooks/.*functional.*$
- ^playbooks/.*linuxbridge.*$
- ^vagrant/.*$
- - ^zuul.d/(?!(project)).*\.yaml
+ # Ignore everything except for zuul.d/project.yaml
+ - ^zuul.d/2023_1_jobs.yaml
+ - ^zuul.d/2023_2_jobs.yaml
+ - ^zuul.d/2024_1_jobs.yaml
+ - ^zuul.d/base-nested-switch.yaml
+ - ^zuul.d/master_jobs.yaml
+ - ^zuul.d/victoria_jobs.yaml
+ - ^zuul.d/wallaby_jobs.yaml
+ - ^zuul.d/xena_jobs.yaml
+ - ^zuul.d/yoga_jobs.yaml
+ - ^zuul.d/zed_jobs.yaml
- job:
name: neutron-tempest-plugin-bgpvpn-bagpipe
@@ -1156,7 +1281,17 @@
- ^playbooks/.*functional.*$
- ^playbooks/.*linuxbridge.*$
- ^vagrant/.*$
- - ^zuul.d/(?!(project)).*\.yaml
+ # Ignore everything except for zuul.d/project.yaml
+ - ^zuul.d/2023_1_jobs.yaml
+ - ^zuul.d/2023_2_jobs.yaml
+ - ^zuul.d/2024_1_jobs.yaml
+ - ^zuul.d/base-nested-switch.yaml
+ - ^zuul.d/master_jobs.yaml
+ - ^zuul.d/victoria_jobs.yaml
+ - ^zuul.d/wallaby_jobs.yaml
+ - ^zuul.d/xena_jobs.yaml
+ - ^zuul.d/yoga_jobs.yaml
+ - ^zuul.d/zed_jobs.yaml
- job:
name: neutron-tempest-plugin-dynamic-routing
@@ -1210,14 +1345,23 @@
- ^playbooks/.*functional.*$
- ^playbooks/.*linuxbridge.*$
- ^vagrant/.*$
- - ^zuul.d/(?!(project)).*\.yaml
+ # Ignore everything except for zuul.d/project.yaml
+ - ^zuul.d/2023_1_jobs.yaml
+ - ^zuul.d/2023_2_jobs.yaml
+ - ^zuul.d/2024_1_jobs.yaml
+ - ^zuul.d/base-nested-switch.yaml
+ - ^zuul.d/master_jobs.yaml
+ - ^zuul.d/victoria_jobs.yaml
+ - ^zuul.d/wallaby_jobs.yaml
+ - ^zuul.d/xena_jobs.yaml
+ - ^zuul.d/yoga_jobs.yaml
+ - ^zuul.d/zed_jobs.yaml
- job:
name: neutron-tempest-plugin-fwaas
parent: neutron-tempest-plugin-base
timeout: 10800
required-projects:
- - openstack/devstack-gate
- openstack/neutron-fwaas
- openstack/neutron
- openstack/neutron-tempest-plugin
@@ -1276,7 +1420,17 @@
- ^playbooks/.*functional.*$
- ^playbooks/.*linuxbridge.*$
- ^vagrant/.*$
- - ^zuul.d/(?!(project)).*\.yaml
+ # Ignore everything except for zuul.d/project.yaml
+ - ^zuul.d/2023_1_jobs.yaml
+ - ^zuul.d/2023_2_jobs.yaml
+ - ^zuul.d/2024_1_jobs.yaml
+ - ^zuul.d/base-nested-switch.yaml
+ - ^zuul.d/master_jobs.yaml
+ - ^zuul.d/victoria_jobs.yaml
+ - ^zuul.d/wallaby_jobs.yaml
+ - ^zuul.d/xena_jobs.yaml
+ - ^zuul.d/yoga_jobs.yaml
+ - ^zuul.d/zed_jobs.yaml
- job:
name: neutron-tempest-plugin-vpnaas
@@ -1345,7 +1499,17 @@
- ^playbooks/.*functional.*$
- ^playbooks/.*linuxbridge.*$
- ^vagrant/.*$
- - ^zuul.d/(?!(project)).*\.yaml
+ # Ignore everything except for zuul.d/project.yaml
+ - ^zuul.d/2023_1_jobs.yaml
+ - ^zuul.d/2023_2_jobs.yaml
+ - ^zuul.d/2024_1_jobs.yaml
+ - ^zuul.d/base-nested-switch.yaml
+ - ^zuul.d/master_jobs.yaml
+ - ^zuul.d/victoria_jobs.yaml
+ - ^zuul.d/wallaby_jobs.yaml
+ - ^zuul.d/xena_jobs.yaml
+ - ^zuul.d/yoga_jobs.yaml
+ - ^zuul.d/zed_jobs.yaml
- job:
name: neutron-tempest-plugin-vpnaas-ovn
@@ -1405,7 +1569,17 @@
- ^playbooks/.*functional.*$
- ^playbooks/.*linuxbridge.*$
- ^vagrant/.*$
- - ^zuul.d/(?!(project)).*\.yaml
+ # Ignore everything except for zuul.d/project.yaml
+ - ^zuul.d/2023_1_jobs.yaml
+ - ^zuul.d/2023_2_jobs.yaml
+ - ^zuul.d/2024_1_jobs.yaml
+ - ^zuul.d/base-nested-switch.yaml
+ - ^zuul.d/master_jobs.yaml
+ - ^zuul.d/victoria_jobs.yaml
+ - ^zuul.d/wallaby_jobs.yaml
+ - ^zuul.d/xena_jobs.yaml
+ - ^zuul.d/yoga_jobs.yaml
+ - ^zuul.d/zed_jobs.yaml
- job:
name: neutron-tempest-plugin-tap-as-a-service
@@ -1415,7 +1589,6 @@
roles:
- zuul: openstack/devstack
required-projects:
- - openstack/devstack-gate
- openstack/neutron
- openstack/neutron-tempest-plugin
- openstack/tap-as-a-service
@@ -1515,4 +1688,14 @@
- ^playbooks/.*functional.*$
- ^playbooks/.*linuxbridge.*$
- ^vagrant/.*$
- - ^zuul.d/(?!(project)).*\.yaml
+ # Ignore everything except for zuul.d/project.yaml
+ - ^zuul.d/2023_1_jobs.yaml
+ - ^zuul.d/2023_2_jobs.yaml
+ - ^zuul.d/2024_1_jobs.yaml
+ - ^zuul.d/base-nested-switch.yaml
+ - ^zuul.d/master_jobs.yaml
+ - ^zuul.d/victoria_jobs.yaml
+ - ^zuul.d/wallaby_jobs.yaml
+ - ^zuul.d/xena_jobs.yaml
+ - ^zuul.d/yoga_jobs.yaml
+ - ^zuul.d/zed_jobs.yaml
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 35a3e7f..9a20f80 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -6,7 +6,10 @@
- neutron-tempest-plugin-openvswitch-iptables_hybrid
- neutron-tempest-plugin-openvswitch-enforce-scope-old-defaults
- neutron-tempest-plugin-ovn
- - neutron-tempest-plugin-designate-scenario
+ - neutron-tempest-plugin-designate-scenario:
+ # TODO(slaweq) make job voting again once bug
+ # https://bugs.launchpad.net/designate/+bug/2072627 will be fixed
+ voting: false
gate:
jobs:
- neutron-tempest-plugin-openvswitch
@@ -21,6 +24,8 @@
- neutron-tempest-plugin-dvr-multinode-scenario
- neutron-tempest-plugin-openvswitch-distributed-dhcp
- neutron-tempest-plugin-openvswitch-iptables_hybrid-distributed-dhcp
+ - neutron-tempest-plugin-api-ovs-wsgi
+ - neutron-tempest-plugin-api-ovn-wsgi
- project-template:
@@ -177,7 +182,6 @@
templates:
- build-openstack-docs-pti
- neutron-tempest-plugin-jobs
- - neutron-tempest-plugin-jobs-zed
- neutron-tempest-plugin-jobs-2023-1
- neutron-tempest-plugin-jobs-2023-2
- neutron-tempest-plugin-jobs-2024-1
@@ -186,41 +190,37 @@
- release-notes-jobs-python3
check:
jobs:
- - neutron-tempest-plugin-sfc
- - neutron-tempest-plugin-sfc-zed
+ - neutron-tempest-plugin-sfc:
+ # Note(lajoskatona): make it voting when #2068727
+ # is fixed.
+ voting: false
- neutron-tempest-plugin-sfc-2023-1
- neutron-tempest-plugin-sfc-2023-2
- neutron-tempest-plugin-sfc-2024-1
- neutron-tempest-plugin-bgpvpn-bagpipe
- - neutron-tempest-plugin-bgpvpn-bagpipe-zed
- neutron-tempest-plugin-bgpvpn-bagpipe-2023-1
- neutron-tempest-plugin-bgpvpn-bagpipe-2023-2
- neutron-tempest-plugin-bgpvpn-bagpipe-2024-1
- neutron-tempest-plugin-dynamic-routing
- - neutron-tempest-plugin-dynamic-routing-zed
- neutron-tempest-plugin-dynamic-routing-2023-1
- neutron-tempest-plugin-dynamic-routing-2023-2
- neutron-tempest-plugin-dynamic-routing-2024-1
- neutron-tempest-plugin-fwaas
- - neutron-tempest-plugin-fwaas-zed
- neutron-tempest-plugin-fwaas-2023-1
- neutron-tempest-plugin-fwaas-2023-2
- neutron-tempest-plugin-fwaas-2024-1
- neutron-tempest-plugin-vpnaas
- neutron-tempest-plugin-vpnaas-ovn
- - neutron-tempest-plugin-vpnaas-zed
- neutron-tempest-plugin-vpnaas-2023-1
- neutron-tempest-plugin-vpnaas-2023-2
- neutron-tempest-plugin-vpnaas-2024-1
- neutron-tempest-plugin-tap-as-a-service
- - neutron-tempest-plugin-tap-as-a-service-zed
- neutron-tempest-plugin-tap-as-a-service-2023-1
- neutron-tempest-plugin-tap-as-a-service-2023-2
- neutron-tempest-plugin-tap-as-a-service-2024-1
gate:
jobs:
- - neutron-tempest-plugin-sfc
- neutron-tempest-plugin-bgpvpn-bagpipe
- neutron-tempest-plugin-dynamic-routing
- neutron-tempest-plugin-fwaas
diff --git a/zuul.d/wallaby_jobs.yaml b/zuul.d/wallaby_jobs.yaml
index 8a771b8..48b56b2 100644
--- a/zuul.d/wallaby_jobs.yaml
+++ b/zuul.d/wallaby_jobs.yaml
@@ -2,7 +2,7 @@
name: neutron-tempest-plugin-api-wallaby
parent: neutron-tempest-plugin-base
nodeset: openstack-single-node-focal
- override-checkout: stable/wallaby
+ override-checkout: unmaintained/wallaby
required-projects: &required-projects-wallaby
- openstack/neutron
- name: openstack/neutron-tempest-plugin
@@ -98,7 +98,7 @@
- job:
name: neutron-tempest-plugin-scenario-openvswitch-wallaby
parent: neutron-tempest-plugin-openvswitch
- override-checkout: stable/wallaby
+ override-checkout: unmaintained/wallaby
required-projects: *required-projects-wallaby
vars:
tempest_test_regex: "\
@@ -118,7 +118,7 @@
- job:
name: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-wallaby
parent: neutron-tempest-plugin-openvswitch-iptables_hybrid
- override-checkout: stable/wallaby
+ override-checkout: unmaintained/wallaby
required-projects: *required-projects-wallaby
vars:
tempest_test_regex: "\
@@ -145,7 +145,7 @@
- job:
name: neutron-tempest-plugin-scenario-linuxbridge-wallaby
parent: neutron-tempest-plugin-linuxbridge
- override-checkout: stable/wallaby
+ override-checkout: unmaintained/wallaby
required-projects: *required-projects-wallaby
vars:
tempest_test_regex: "\
@@ -165,7 +165,7 @@
- job:
name: neutron-tempest-plugin-scenario-ovn-wallaby
parent: neutron-tempest-plugin-ovn
- override-checkout: stable/wallaby
+ override-checkout: unmaintained/wallaby
required-projects: *required-projects-wallaby
vars:
tempest_test_regex: "\
@@ -190,7 +190,7 @@
name: neutron-tempest-plugin-dvr-multinode-scenario-wallaby
parent: neutron-tempest-plugin-dvr-multinode-scenario
nodeset: openstack-two-node-focal
- override-checkout: stable/wallaby
+ override-checkout: unmaintained/wallaby
required-projects: *required-projects-wallaby
vars:
network_api_extensions_common: *api_extensions
@@ -198,7 +198,7 @@
- job:
name: neutron-tempest-plugin-designate-scenario-wallaby
parent: neutron-tempest-plugin-designate-scenario
- override-checkout: stable/wallaby
+ override-checkout: unmaintained/wallaby
required-projects:
- openstack/neutron
- name: openstack/neutron-tempest-plugin
@@ -213,7 +213,7 @@
name: neutron-tempest-plugin-sfc-wallaby
parent: neutron-tempest-plugin-sfc
nodeset: openstack-single-node-focal
- override-checkout: stable/wallaby
+ override-checkout: unmaintained/wallaby
required-projects: *required-projects-wallaby
vars:
network_api_extensions_common: *api_extensions
@@ -222,7 +222,7 @@
name: neutron-tempest-plugin-bgpvpn-bagpipe-wallaby
parent: neutron-tempest-plugin-bgpvpn-bagpipe
nodeset: openstack-single-node-focal
- override-checkout: stable/wallaby
+ override-checkout: unmaintained/wallaby
required-projects: *required-projects-wallaby
vars:
network_api_extensions: *api_extensions
@@ -231,7 +231,7 @@
name: neutron-tempest-plugin-dynamic-routing-wallaby
parent: neutron-tempest-plugin-dynamic-routing
nodeset: openstack-single-node-focal
- override-checkout: stable/wallaby
+ override-checkout: unmaintained/wallaby
required-projects: *required-projects-wallaby
vars:
network_api_extensions_common: *api_extensions
@@ -240,7 +240,7 @@
name: neutron-tempest-plugin-vpnaas-wallaby
parent: neutron-tempest-plugin-vpnaas
nodeset: openstack-single-node-focal
- override-checkout: stable/wallaby
+ override-checkout: unmaintained/wallaby
required-projects: *required-projects-wallaby
vars:
network_api_extensions_common: *api_extensions
diff --git a/zuul.d/xena_jobs.yaml b/zuul.d/xena_jobs.yaml
index 9f8e960..fc0b84f 100644
--- a/zuul.d/xena_jobs.yaml
+++ b/zuul.d/xena_jobs.yaml
@@ -2,7 +2,7 @@
name: neutron-tempest-plugin-api-xena
parent: neutron-tempest-plugin-base
nodeset: openstack-single-node-focal
- override-checkout: stable/xena
+ override-checkout: unmaintained/xena
required-projects: &required-projects-xena
- openstack/neutron
- name: openstack/neutron-tempest-plugin
@@ -100,7 +100,7 @@
- job:
name: neutron-tempest-plugin-scenario-openvswitch-xena
parent: neutron-tempest-plugin-openvswitch
- override-checkout: stable/xena
+ override-checkout: unmaintained/xena
required-projects: *required-projects-xena
vars:
tempest_test_regex: "\
@@ -120,7 +120,7 @@
- job:
name: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-xena
parent: neutron-tempest-plugin-openvswitch-iptables_hybrid
- override-checkout: stable/xena
+ override-checkout: unmaintained/xena
required-projects: *required-projects-xena
vars:
tempest_test_regex: "\
@@ -140,7 +140,7 @@
- job:
name: neutron-tempest-plugin-scenario-linuxbridge-xena
parent: neutron-tempest-plugin-linuxbridge
- override-checkout: stable/xena
+ override-checkout: unmaintained/xena
required-projects: *required-projects-xena
vars:
tempest_test_regex: "\
@@ -160,7 +160,7 @@
- job:
name: neutron-tempest-plugin-scenario-ovn-xena
parent: neutron-tempest-plugin-ovn
- override-checkout: stable/xena
+ override-checkout: unmaintained/xena
required-projects: *required-projects-xena
vars:
tempest_test_regex: "\
@@ -183,7 +183,7 @@
name: neutron-tempest-plugin-dvr-multinode-scenario-xena
parent: neutron-tempest-plugin-dvr-multinode-scenario
nodeset: openstack-two-node-focal
- override-checkout: stable/xena
+ override-checkout: unmaintained/xena
required-projects: *required-projects-xena
vars:
network_api_extensions_common: *api_extensions
@@ -191,7 +191,7 @@
- job:
name: neutron-tempest-plugin-designate-scenario-xena
parent: neutron-tempest-plugin-designate-scenario
- override-checkout: stable/xena
+ override-checkout: unmaintained/xena
required-projects: *required-projects-xena
vars:
network_api_extensions_common: *api_extensions
@@ -200,7 +200,7 @@
name: neutron-tempest-plugin-sfc-xena
parent: neutron-tempest-plugin-sfc
nodeset: openstack-single-node-focal
- override-checkout: stable/xena
+ override-checkout: unmaintained/xena
required-projects: *required-projects-xena
vars:
network_api_extensions_common: *api_extensions
@@ -209,7 +209,7 @@
name: neutron-tempest-plugin-bgpvpn-bagpipe-xena
parent: neutron-tempest-plugin-bgpvpn-bagpipe
nodeset: openstack-single-node-focal
- override-checkout: stable/xena
+ override-checkout: unmaintained/xena
required-projects: *required-projects-xena
vars:
network_api_extensions: *api_extensions
@@ -218,7 +218,7 @@
name: neutron-tempest-plugin-dynamic-routing-xena
parent: neutron-tempest-plugin-dynamic-routing
nodeset: openstack-single-node-focal
- override-checkout: stable/xena
+ override-checkout: unmaintained/xena
required-projects: *required-projects-xena
vars:
network_api_extensions_common: *api_extensions
@@ -249,7 +249,7 @@
name: neutron-tempest-plugin-vpnaas-xena
parent: neutron-tempest-plugin-vpnaas
nodeset: openstack-single-node-focal
- override-checkout: stable/xena
+ override-checkout: unmaintained/xena
required-projects: *required-projects-xena
vars:
network_api_extensions_common: *api_extensions
@@ -258,7 +258,7 @@
name: neutron-tempest-plugin-tap-as-a-service-xena
parent: neutron-tempest-plugin-tap-as-a-service
nodeset: openstack-single-node-focal
- override-checkout: stable/xena
+ override-checkout: unmaintained/xena
required-projects: *required-projects-xena
vars:
network_api_extensions_common: *api_extensions
diff --git a/zuul.d/yoga_jobs.yaml b/zuul.d/yoga_jobs.yaml
index 76cac3e..af7f97e 100644
--- a/zuul.d/yoga_jobs.yaml
+++ b/zuul.d/yoga_jobs.yaml
@@ -6,9 +6,7 @@
required-projects: &required-projects-yoga
- openstack/neutron
- name: openstack/neutron-tempest-plugin
- # Move to 2.6.0 once released
- # https://review.opendev.org/c/openstack/releases/+/908369
- override-checkout: 2.5.0
+ override-checkout: 2.6.0
- openstack/tempest
vars:
tempest_concurrency: 4
diff --git a/zuul.d/zed_jobs.yaml b/zuul.d/zed_jobs.yaml
index 7d8b2e1..b002218 100644
--- a/zuul.d/zed_jobs.yaml
+++ b/zuul.d/zed_jobs.yaml
@@ -1,8 +1,13 @@
- job:
name: neutron-tempest-plugin-openvswitch-zed
parent: neutron-tempest-plugin-openvswitch
- override-checkout: stable/zed
+ override-checkout: unmaintained/zed
nodeset: neutron-nested-virt-ubuntu-focal
+ required-projects: &required-projects-zed
+ - openstack/neutron
+ - name: openstack/neutron-tempest-plugin
+ override-checkout: zed-last
+ - openstack/tempest
vars:
network_api_extensions_openvswitch:
- local_ip
@@ -106,7 +111,8 @@
- job:
name: neutron-tempest-plugin-openvswitch-iptables_hybrid-zed
parent: neutron-tempest-plugin-openvswitch-iptables_hybrid
- override-checkout: stable/zed
+ override-checkout: unmaintained/zed
+ required-projects: *required-projects-zed
nodeset: neutron-nested-virt-ubuntu-focal
vars:
network_api_extensions_common: *api_extensions
@@ -140,7 +146,8 @@
- job:
name: neutron-tempest-plugin-linuxbridge-zed
parent: neutron-tempest-plugin-linuxbridge
- override-checkout: stable/zed
+ override-checkout: unmaintained/zed
+ required-projects: *required-projects-zed
nodeset: neutron-nested-virt-ubuntu-focal
vars:
network_api_extensions_common: *api_extensions
@@ -168,7 +175,8 @@
- job:
name: neutron-tempest-plugin-ovn-zed
parent: neutron-tempest-plugin-ovn
- override-checkout: stable/zed
+ override-checkout: unmaintained/zed
+ required-projects: *required-projects-zed
nodeset: neutron-nested-virt-ubuntu-focal
vars:
tempest_test_regex: "\
@@ -196,14 +204,16 @@
name: neutron-tempest-plugin-dvr-multinode-scenario-zed
parent: neutron-tempest-plugin-dvr-multinode-scenario
nodeset: openstack-two-node-focal
- override-checkout: stable/zed
+ override-checkout: unmaintained/zed
+ required-projects: *required-projects-zed
vars:
network_api_extensions_common: *api_extensions
- job:
name: neutron-tempest-plugin-designate-scenario-zed
parent: neutron-tempest-plugin-designate-scenario
- override-checkout: stable/zed
+ override-checkout: unmaintained/zed
+ required-projects: *required-projects-zed
nodeset: neutron-nested-virt-ubuntu-focal
vars:
network_api_extensions_common: *api_extensions
@@ -212,7 +222,8 @@
name: neutron-tempest-plugin-sfc-zed
parent: neutron-tempest-plugin-sfc
nodeset: openstack-single-node-focal
- override-checkout: stable/zed
+ override-checkout: unmaintained/zed
+ required-projects: *required-projects-zed
vars:
network_api_extensions_common: *api_extensions
@@ -220,7 +231,8 @@
name: neutron-tempest-plugin-bgpvpn-bagpipe-zed
parent: neutron-tempest-plugin-bgpvpn-bagpipe
nodeset: openstack-single-node-focal
- override-checkout: stable/zed
+ override-checkout: unmaintained/zed
+ required-projects: *required-projects-zed
vars:
network_api_extensions: *api_extensions
@@ -228,7 +240,8 @@
name: neutron-tempest-plugin-dynamic-routing-zed
parent: neutron-tempest-plugin-dynamic-routing
nodeset: openstack-single-node-focal
- override-checkout: stable/zed
+ override-checkout: unmaintained/zed
+ required-projects: *required-projects-zed
vars:
network_api_extensions_common: *api_extensions
devstack_localrc:
@@ -258,7 +271,8 @@
name: neutron-tempest-plugin-fwaas-zed
parent: neutron-tempest-plugin-fwaas
nodeset: openstack-single-node-focal
- override-checkout: stable/zed
+ override-checkout: unmaintained/zed
+ required-projects: *required-projects-zed
vars:
network_api_extensions_common: *api_extensions
@@ -266,7 +280,8 @@
name: neutron-tempest-plugin-vpnaas-zed
parent: neutron-tempest-plugin-vpnaas
nodeset: openstack-single-node-focal
- override-checkout: stable/zed
+ override-checkout: unmaintained/zed
+ required-projects: *required-projects-zed
vars:
network_api_extensions_common: *api_extensions
@@ -274,6 +289,7 @@
name: neutron-tempest-plugin-tap-as-a-service-zed
parent: neutron-tempest-plugin-tap-as-a-service
nodeset: openstack-single-node-focal
- override-checkout: stable/zed
+ override-checkout: unmaintained/zed
+ required-projects: *required-projects-zed
vars:
network_api_extensions_common: *api_extensions