Merge "Add common method for advanced image configuration"
diff --git a/neutron_tempest_plugin/common/ip.py b/neutron_tempest_plugin/common/ip.py
index bab9064..d5966d2 100644
--- a/neutron_tempest_plugin/common/ip.py
+++ b/neutron_tempest_plugin/common/ip.py
@@ -184,6 +184,11 @@
if mac_address in nic_line:
return nic_line.split(":")[1].strip()
+ def has_dadfailed(self, device):
+ """Check if device has any IPv6 addresses in dadfailed state"""
+ output = self.execute('address', 'show', 'dev', device)
+ return 'dadfailed' in output
+
def parse_addresses(command_output):
address = device = None
diff --git a/neutron_tempest_plugin/config.py b/neutron_tempest_plugin/config.py
index 1f5c34c..98fd48e 100644
--- a/neutron_tempest_plugin/config.py
+++ b/neutron_tempest_plugin/config.py
@@ -185,7 +185,7 @@
FwaasGroup = [
cfg.StrOpt('driver',
default=None,
- choices=['openvswitch', 'ovn'],
+ choices=['iptables_v2', 'ovn'],
help='Driver used by the FWaaS plugin.'),
]
fwaas_group = cfg.OptGroup(
diff --git a/neutron_tempest_plugin/fwaas/scenario/test_fwaas_v2.py b/neutron_tempest_plugin/fwaas/scenario/test_fwaas_v2.py
index 6af27fc..c60f8b4 100644
--- a/neutron_tempest_plugin/fwaas/scenario/test_fwaas_v2.py
+++ b/neutron_tempest_plugin/fwaas/scenario/test_fwaas_v2.py
@@ -37,6 +37,12 @@
- public_network_id
"""
+ @classmethod
+ def setup_credentials(cls):
+ # Create no default network resources; tests create their own topology.
+ cls.set_network_resources()
+ super(TestFWaaS_v2, cls).setup_credentials()
+
def setUp(self):
LOG.debug("Initializing FWaaSScenarioTest Setup")
super(TestFWaaS_v2, self).setUp()
@@ -126,10 +132,15 @@
subnet_id=subnet_id)
return resp
- def _create_network_subnet(self):
- network = self.create_network()
- subnet_kwargs = dict(network=network)
- subnet = self.create_subnet(**subnet_kwargs)
+ def _create_network_subnet(self, prefix="smoke-",
+ port_security_enabled=True):
+ network_prefix = "network-%s" % prefix
+ subnet_prefix = "subnet-%s" % prefix
+ network = self.create_network(
+ namestart=network_prefix,
+ port_security_enabled=port_security_enabled)
+ subnet = self.create_subnet(
+ network=network, namestart=subnet_prefix)
return network, subnet
def _create_test_server(self, network, security_group):
@@ -310,3 +321,108 @@
# Disassociate ports of this firewall group for cleanup resources
self.update_firewall_group_and_wait(fw_group['id'], ports=[])
+
+ def _create_fip_topology(self):
+ """Create topology: network, subnet, router, VM with FIP.
+
+ VM is created without security group (network has
+ port_security_enabled=False).
+
+ +--------+ +-------------+
+ |"server"| | "subnet" |
+ | VM +-------------+ "network" |
+ +--------+ +----+--------+
+ |
+ | router interface port
+ +----+-----+
+ | "router"|
+ +----+-----+
+ |
+ | external gateway
+ |
+ [external network]
+ """
+ # No security group: network has port_security_enabled=False
+ network, subnet = self._create_network_subnet(
+ prefix='fwaas-ssh-fip-',
+ port_security_enabled=False)
+ router = self._create_router(namestart='fwaas-ssh-fip-router')
+ pub_network_id = CONF.network.public_network_id
+ router = self.routers_client.update_router(
+ router['id'],
+ external_gateway_info=dict(network_id=pub_network_id))['router']
+ resp = self._add_router_interface(
+ router['id'], subnet_id=subnet['id'])
+ router_port_id = resp['port_id']
+ server, keys = self._create_server(network)
+ floating_ip = self.create_floating_ip(server, pub_network_id)
+
+ return {
+ 'server': server,
+ 'private_key': keys['private_key'],
+ 'floating_ip': floating_ip,
+ 'router_port_id': router_port_id,
+ }
+
+ @decorators.idempotent_id('a8c2e1f4-9b3d-4f5a-8e6c-7d9f2b1a0c3e')
+ def test_ssh_via_fip_with_fwaas_rules(self):
+ """Test SSH access to VM with FIP controlled by FWaaS rules.
+
+ Verifies that:
+ 1. FWaaS is enabled (skipped in setUp if not)
+ 2. Baseline: VM reachable before firewall (SSH works)
+ 3. Firewall group with empty policy denies all traffic (SSH blocked)
+ 4. Adding allow SSH rules to ingress and egress policy permits SSH
+ """
+ topology = self._create_fip_topology()
+ fip_address = topology['floating_ip']['floating_ip_address']
+ ssh_login = CONF.validation.image_ssh_user
+ private_key = topology['private_key']
+
+ # Baseline: Ensure VM is reachable before applying firewall
+ self.check_vm_connectivity(
+ ip_address=fip_address,
+ username=ssh_login,
+ private_key=private_key)
+
+ # Phase 1: Attach firewall group with empty policy - SSH blocked
+ fw_policy = self.create_firewall_policy()
+ fw_group = self.create_firewall_group(
+ ports=[topology['router_port_id']],
+ ingress_firewall_policy_id=fw_policy['id'],
+ egress_firewall_policy_id=fw_policy['id'])
+ self.addCleanup(self.update_firewall_group_and_wait, fw_group['id'],
+ ports=[])
+ self._wait_firewall_group_ready(fw_group['id'])
+ LOG.debug('Firewall group with empty policy attached to router port')
+
+ self.check_connectivity(
+ ip_address=fip_address,
+ username=ssh_login,
+ private_key=private_key,
+ should_connect=False,
+ check_icmp=False,
+ check_ssh=True)
+
+ # Phase 2: Add allow SSH rules - ingress dport 22, egress sport 22
+ fw_allow_ssh_rule = self.create_firewall_rule(
+ action="allow", protocol="tcp", destination_port=22)
+ fw_allow_egress_ssh_rule = self.create_firewall_rule(
+ action="allow", protocol="tcp", source_port=22)
+ self.insert_firewall_rule_in_policy_and_wait(
+ firewall_group_id=fw_group['id'],
+ firewall_rule_id=fw_allow_ssh_rule['id'],
+ firewall_policy_id=fw_policy['id'])
+ self.insert_firewall_rule_in_policy_and_wait(
+ firewall_group_id=fw_group['id'],
+ firewall_rule_id=fw_allow_egress_ssh_rule['id'],
+ firewall_policy_id=fw_policy['id'])
+ LOG.debug('Added allow SSH rules to ingress and egress policy')
+
+ self.check_connectivity(
+ ip_address=fip_address,
+ username=ssh_login,
+ private_key=private_key,
+ should_connect=True,
+ check_icmp=False,
+ check_ssh=True)
diff --git a/neutron_tempest_plugin/scenario/admin/test_floatingip.py b/neutron_tempest_plugin/scenario/admin/test_floatingip.py
index d9abaf5..52218ea 100644
--- a/neutron_tempest_plugin/scenario/admin/test_floatingip.py
+++ b/neutron_tempest_plugin/scenario/admin/test_floatingip.py
@@ -57,14 +57,31 @@
secgroup_id=cls.secgroup['id'],
client=network_client),
- def _list_hypervisors(self):
- # List of hypervisors
- return self.os_admin.hv_client.list_hypervisors()['hypervisors']
-
- def _list_availability_zones(self):
- # List of availability zones
- func = self.os_admin.az_client.list_availability_zones
- return func()['availabilityZoneInfo']
+ def _choose_az_and_node(self):
+ az_list = self.os_admin.az_client.list_availability_zones(
+ detail=True)['availabilityZoneInfo']
+ hv_list = self.os_admin.hv_client.list_hypervisors()['hypervisors']
+ for az in az_list:
+ if not az['zoneState']['available']:
+ continue
+ for host, services in az['hosts'].items():
+ for service, info in services.items():
+ if (
+ service == 'nova-compute' and
+ info['active'] and info['available']
+ ):
+ hv = [
+ h for h in hv_list
+ if (
+ h['hypervisor_hostname'].startswith(host) and
+ h["state"] == "up" and
+ h["status"] == "enabled"
+ )
+ ]
+ if not hv:
+ continue
+ return az['zoneName'], hv[0]['hypervisor_hostname']
+ return None, None
def _create_vms(self, hyper, avail_zone, num_servers=2):
servers, fips, server_ssh_clients = ([], [], [])
@@ -103,10 +120,9 @@
that were created in the same compute node and same availability zone
to reach each other.
"""
- # Get hypervisor list to pass it for vm creation
- hyper = self._list_hypervisors()[0]['hypervisor_hostname']
- # Get availability zone list to pass it for vm creation
- avail_zone = self._list_availability_zones()[0]['zoneName']
+ avail_zone, hyper = self._choose_az_and_node()
+ if not (avail_zone and hyper):
+ self.fail("No compute host is available")
servers, server_ssh_clients, fips = self._create_vms(hyper, avail_zone)
self.check_remote_connectivity(
server_ssh_clients[0], fips[1]['floating_ip_address'],
diff --git a/neutron_tempest_plugin/scenario/base.py b/neutron_tempest_plugin/scenario/base.py
index 36d15d8..1be8afe 100644
--- a/neutron_tempest_plugin/scenario/base.py
+++ b/neutron_tempest_plugin/scenario/base.py
@@ -686,7 +686,7 @@
body = client.show_router(router_id)
return body['router']
elif network_id:
- router = self.create_router_by_client()
+ router = self.create_router_by_client(tenant_id=tenant_id)
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
client.delete_router, router['id'])
kwargs = {'external_gateway_info': dict(network_id=network_id)}
diff --git a/neutron_tempest_plugin/scenario/test_dns_integration.py b/neutron_tempest_plugin/scenario/test_dns_integration.py
index d6bafef..2784dc1 100644
--- a/neutron_tempest_plugin/scenario/test_dns_integration.py
+++ b/neutron_tempest_plugin/scenario/test_dns_integration.py
@@ -13,10 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
+import importlib
import ipaddress
-import testtools
-
from oslo_log import log
from tempest.common import utils
from tempest.common import waiters
@@ -37,9 +36,21 @@
# Note(jh): Need to do a bit of juggling here in order to avoid failures
# when designate_tempest_plugin is not available
-dns_base = testtools.try_import('designate_tempest_plugin.tests.base')
-dns_waiters = testtools.try_import('designate_tempest_plugin.common.waiters')
-dns_data_utils = testtools.try_import('designate_tempest_plugin.data_utils')
+try:
+ dns_base = importlib.import_module('designate_tempest_plugin.tests.base')
+except ImportError:
+ dns_base = None
+try:
+ dns_waiters = importlib.import_module(
+ 'designate_tempest_plugin.common.waiters')
+except ImportError:
+ dns_waiters = None
+try:
+ dns_data_utils = importlib.import_module(
+ 'designate_tempest_plugin.data_utils')
+except ImportError:
+ dns_data_utils = None
+
if dns_base:
DNSMixin = dns_base.BaseDnsV2Test
diff --git a/neutron_tempest_plugin/scenario/test_ipv6.py b/neutron_tempest_plugin/scenario/test_ipv6.py
index 41ac2e6..3239417 100644
--- a/neutron_tempest_plugin/scenario/test_ipv6.py
+++ b/neutron_tempest_plugin/scenario/test_ipv6.py
@@ -33,21 +33,21 @@
LOG = log.getLogger(__name__)
-def turn_nic6_on(ssh, ipv6_port, config_nic=True):
+def turn_nic6_on(ssh, nic, config_nic=True):
"""Turns the IPv6 vNIC on
Required because guest images usually set only the first vNIC on boot.
- Searches for the IPv6 vNIC's MAC and brings it up.
+ Brings the specified NIC up.
# NOTE(slaweq): on RHEL based OS ifcfg file for new interface is
# needed to make IPv6 working on it, so if
# /etc/sysconfig/network-scripts directory exists ifcfg-%(nic)s file
# should be added in it
@param ssh: RemoteClient ssh instance to server
- @param ipv6_port: port from IPv6 network attached to the server
+ @param nic: network interface name
+ @param config_nic: whether to configure with NetworkManager
"""
ip_command = ip.IPCommand(ssh)
- nic = ip_command.get_nic_name_by_mac(ipv6_port['mac_address'])
if config_nic:
try:
@@ -150,16 +150,26 @@
def _test_ipv6_address_configured(self, ssh_client, vm, ipv6_port):
ipv6_address = ipv6_port['fixed_ips'][0]['ip_address']
ip_command = ip.IPCommand(ssh_client)
+ nic = ip_command.get_nic_name_by_mac(ipv6_port['mac_address'])
def guest_has_address(expected_address):
ip_addresses = [a.address for a in ip_command.list_addresses()]
for ip_address in ip_addresses:
if expected_address in ip_address:
return True
+
+ # NOTE(ykarel): Sometimes with the cirros VM a race is seen with
+ # ovs_create_tap feature https://launchpad.net/bugs/2069718 and
+ # ipv6 is not configured, adding nic restart if dad failure is
+ # detected to workaround this
+ if ip_command.has_dadfailed(nic):
+ LOG.debug('DAD failure detected on %s, restarting', nic)
+ ip_command.set_link(nic, "down")
+ ip_command.set_link(nic, "up")
return False
# Set NIC with IPv6 to be UP and wait until IPv6 address
# will be configured on this NIC
- turn_nic6_on(ssh_client, ipv6_port, False)
+ turn_nic6_on(ssh_client, nic, False)
# And check if IPv6 address will be properly configured
# on this NIC
try:
@@ -179,7 +189,7 @@
try:
# Set NIC with IPv6 to be UP and wait until IPv6 address
# will be configured on this NIC
- turn_nic6_on(ssh_client, ipv6_port)
+ turn_nic6_on(ssh_client, nic)
# And check if IPv6 address will be properly configured
# on this NIC
utils.wait_until_true(
diff --git a/neutron_tempest_plugin/tap_as_a_service/scenario/test_tap_mirror.py b/neutron_tempest_plugin/tap_as_a_service/scenario/test_tap_mirror.py
index d4a482c..31e5aa7 100644
--- a/neutron_tempest_plugin/tap_as_a_service/scenario/test_tap_mirror.py
+++ b/neutron_tempest_plugin/tap_as_a_service/scenario/test_tap_mirror.py
@@ -111,6 +111,9 @@
self.monitor_client.validate_authentication()
r_ip = vm_mon_fip['floating_ip_address']
+ directions = {'IN': '101', 'OUT': '102'}
+ if utils.is_extension_enabled('tap-mirror-both-direction', 'network'):
+ directions['BOTH'] = '103'
# Create GRE mirror, as tcpdump cant extract ERSPAN
# it is just visible as a type of GRE traffic.
# direction IN and that the test pings from vm0 to vm1
@@ -119,7 +122,7 @@
tap_mirror = self.tap_mirrors_client.create_tap_mirror(
name=data_utils.rand_name("tap_mirror"),
port_id=vm1_port['id'],
- directions={'IN': '101', 'OUT': '102'},
+ directions=directions,
remote_ip=r_ip,
mirror_type='gre',
)
@@ -139,3 +142,54 @@
self.assertIn('key=0x65', output)
# GRE Key for Direction OUT:102
self.assertIn('key=0x66', output)
+ if 'BOTH' in directions:
+ # GRE Key for Direction BOTH:103
+ self.assertIn('key=0x67', output)
+
+ vm0_ip = vm0_port['fixed_ips'][0]['ip_address']
+ output_lines = output.splitlines()
+
+ self._check_icmp_mirror_direction(output_lines, vm0_ip, vm1_ip, "IN",
+ "key=0x65")
+ self._check_icmp_mirror_direction(output_lines, vm0_ip, vm1_ip, "OUT",
+ "key=0x66")
+ if 'BOTH' in directions:
+ self._check_icmp_mirror_direction(output_lines, vm0_ip, vm1_ip,
+ "BOTH", "key=0x67")
+
+ def _check_icmp_mirror_direction(self, output_lines, ip_sender,
+ ip_receiver, direction, key):
+ """Check direction of the mirroring is consistent with what is expected
+
+ output_lines[i+2] should have the following format for OUT:
+ [ip_receiver] > [ip_sender]: ICMP echo reply, id ...
+
+ output_lines[i+2] should have the following format for IN:
+ [ip_sender] > [ip_receiver]: ICMP echo request, id ...
+
+ BOTH direction should have at least one iteration of each.
+ """
+
+ directions = [direction] if direction != "BOTH" else ['IN', 'OUT']
+ for d in directions:
+ found_log = False
+ if d == 'IN':
+ left_ip, right_ip = ip_sender, ip_receiver
+ icmp_msg = 'ICMP echo request'
+ elif d == 'OUT':
+ left_ip, right_ip = ip_receiver, ip_sender
+ icmp_msg = 'ICMP echo reply'
+ for i, line in enumerate(output_lines):
+ icmp_log = None
+ if key not in line:
+ continue
+ icmp_log = output_lines[i + 2].split(':')
+ if icmp_msg in icmp_log[1]:
+ self.assertIn(left_ip + ' > ' + right_ip, icmp_log[0])
+ found_log = True
+ break
+ # Make sure we have found at least one coincidence of the target
+ # string for this direction.
+ self.assertTrue(found_log, msg=f"Did not find direction "
+ f"{direction} and key {key} in the tcpdump log. ICMP "
+ f"log: {icmp_log}")
diff --git a/requirements.txt b/requirements.txt
index eee78f8..7c8b715 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -11,5 +11,5 @@
tempest>=29.2.0 # Apache-2.0
tenacity>=3.2.1 # Apache-2.0
ddt>=1.0.1 # MIT
-testtools>=2.2.0 # MIT
+testtools>=2.8.4 # MIT
debtcollector>=1.2.0 # Apache-2.0
diff --git a/setup.cfg b/setup.cfg
index 0962924..d35b58a 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -6,7 +6,7 @@
author = OpenStack
author_email = openstack-discuss@lists.openstack.org
home_page = https://opendev.org/openstack/neutron-tempest-plugin
-python_requires = >=3.9
+python_requires = >=3.10
classifier =
Environment :: OpenStack
Intended Audience :: Information Technology
@@ -15,10 +15,11 @@
Operating System :: POSIX :: Linux
Programming Language :: Python
Programming Language :: Python :: 3
- Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Programming Language :: Python :: 3.12
+ Programming Language :: Python :: 3.13
+ Programming Language :: Python :: 3 :: Only
[files]
packages =
diff --git a/test-requirements.txt b/test-requirements.txt
index ee399b8..d23827a 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,6 +1,6 @@
hacking>=6.1.0,<6.2.0 # Apache-2.0
-flake8-import-order>=0.18.0,<0.19.0 # LGPLv3
+flake8-import-order>=0.19.0 # LGPLv3
oslotest>=3.2.0 # Apache-2.0
stestr>=1.0.0 # Apache-2.0
testtools>=2.2.0 # MIT
diff --git a/zuul.d/2024_1_jobs.yaml b/zuul.d/2024_1_jobs.yaml
index 1e313fa..fcaf6dc 100644
--- a/zuul.d/2024_1_jobs.yaml
+++ b/zuul.d/2024_1_jobs.yaml
@@ -2,17 +2,17 @@
name: neutron-tempest-plugin-openvswitch-2024-1
parent: neutron-tempest-plugin-openvswitch
nodeset: neutron-nested-virt-ubuntu-jammy
+ override-checkout: unmaintained/2024.1
required-projects: &required-projects-2024-1
- openstack/neutron
- name: openstack/neutron-tempest-plugin
- override-checkout: 2024.1-last
+ override-checkout: 2.12.0
- openstack/tempest
vars:
network_api_extensions_openvswitch: &api_extensions_openvswitch
- dhcp_agent_scheduler
- local_ip
- qos-bw-minimum-ingress
- stable_constraints_file: "https://releases.openstack.org/constraints/upper/master"
tempest_test_regex: "\
(^neutron_tempest_plugin.api)|\
(^neutron_tempest_plugin.scenario)|\
@@ -104,7 +104,6 @@
devstack_localrc:
NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_openvswitch) | join(',') }}"
NEUTRON_DEPLOY_MOD_WSGI: false
- TEMPEST_VENV_UPPER_CONSTRAINTS: master
devstack_local_conf:
test-config:
$TEMPEST_CONFIG:
@@ -120,7 +119,6 @@
network_api_extensions_common: *api_extensions
network_api_extensions_openvswitch: *api_extensions_openvswitch
network_available_features: *available_features
- stable_constraints_file: "https://releases.openstack.org/constraints/upper/master"
tempest_test_regex: "\
(^neutron_tempest_plugin.api)|\
(^neutron_tempest_plugin.scenario)|\
@@ -137,7 +135,6 @@
devstack_localrc:
NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_openvswitch) | join(',') }}"
NEUTRON_DEPLOY_MOD_WSGI: false
- TEMPEST_VENV_UPPER_CONSTRAINTS: master
devstack_local_conf:
test-config:
$TEMPEST_CONFIG:
@@ -175,7 +172,6 @@
- dhcp_agent_scheduler
- vlan-transparent
network_available_features: *available_features
- stable_constraints_file: "https://releases.openstack.org/constraints/upper/master"
tempest_test_regex: "\
(^neutron_tempest_plugin.api)|\
(^neutron_tempest_plugin.scenario)|\
@@ -198,7 +194,6 @@
devstack_localrc:
NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_linuxbridge) | join(',') }}"
NEUTRON_DEPLOY_MOD_WSGI: false
- TEMPEST_VENV_UPPER_CONSTRAINTS: master
devstack_local_conf:
test-config:
$TEMPEST_CONFIG:
@@ -217,7 +212,6 @@
vars:
network_api_extensions_ovn:
- vlan-transparent
- stable_constraints_file: "https://releases.openstack.org/constraints/upper/master"
tempest_test_regex: "\
(^neutron_tempest_plugin.api)|\
(^neutron_tempest_plugin.scenario)|\
@@ -226,7 +220,6 @@
devstack_localrc:
NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_ovn) | join(',') }}"
NEUTRON_DEPLOY_MOD_WSGI: false
- TEMPEST_VENV_UPPER_CONSTRAINTS: master
devstack_local_conf:
test-config:
$TEMPEST_CONFIG:
@@ -247,11 +240,9 @@
network_api_extensions_dvr:
- dhcp_agent_scheduler
- dvr
- stable_constraints_file: "https://releases.openstack.org/constraints/upper/master"
devstack_localrc:
NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_dvr) | join(',') }}"
NEUTRON_DEPLOY_MOD_WSGI: false
- TEMPEST_VENV_UPPER_CONSTRAINTS: master
- job:
name: neutron-tempest-plugin-designate-scenario-2024-1
@@ -260,10 +251,8 @@
required-projects: *required-projects-2024-1
vars:
network_api_extensions_common: *api_extensions
- stable_constraints_file: "https://releases.openstack.org/constraints/upper/master"
devstack_localrc:
NEUTRON_DEPLOY_MOD_WSGI: false
- TEMPEST_VENV_UPPER_CONSTRAINTS: master
- job:
name: neutron-tempest-plugin-sfc-2024-1
@@ -271,10 +260,8 @@
nodeset: openstack-single-node-jammy
required-projects: *required-projects-2024-1
vars:
- stable_constraints_file: "https://releases.openstack.org/constraints/upper/master"
devstack_localrc:
NEUTRON_DEPLOY_MOD_WSGI: false
- TEMPEST_VENV_UPPER_CONSTRAINTS: master
- job:
name: neutron-tempest-plugin-bgpvpn-bagpipe-2024-1
@@ -282,10 +269,8 @@
nodeset: openstack-single-node-jammy
required-projects: *required-projects-2024-1
vars:
- stable_constraints_file: "https://releases.openstack.org/constraints/upper/master"
devstack_localrc:
NEUTRON_DEPLOY_MOD_WSGI: false
- TEMPEST_VENV_UPPER_CONSTRAINTS: master
- job:
name: neutron-tempest-plugin-dynamic-routing-2024-1
@@ -294,10 +279,8 @@
nodeset: openstack-single-node-jammy
required-projects: *required-projects-2024-1
vars:
- stable_constraints_file: "https://releases.openstack.org/constraints/upper/master"
devstack_localrc:
NEUTRON_DEPLOY_MOD_WSGI: false
- TEMPEST_VENV_UPPER_CONSTRAINTS: master
- job:
name: neutron-tempest-plugin-fwaas-2024-1
@@ -305,10 +288,8 @@
nodeset: openstack-single-node-jammy
required-projects: *required-projects-2024-1
vars:
- stable_constraints_file: "https://releases.openstack.org/constraints/upper/master"
devstack_localrc:
NEUTRON_DEPLOY_MOD_WSGI: false
- TEMPEST_VENV_UPPER_CONSTRAINTS: master
- job:
name: neutron-tempest-plugin-vpnaas-2024-1
@@ -316,10 +297,8 @@
nodeset: openstack-single-node-jammy
required-projects: *required-projects-2024-1
vars:
- stable_constraints_file: "https://releases.openstack.org/constraints/upper/master"
devstack_localrc:
NEUTRON_DEPLOY_MOD_WSGI: false
- TEMPEST_VENV_UPPER_CONSTRAINTS: master
- job:
name: neutron-tempest-plugin-tap-as-a-service-2024-1
@@ -327,11 +306,9 @@
nodeset: openstack-single-node-jammy
required-projects: *required-projects-2024-1
vars:
- stable_constraints_file: "https://releases.openstack.org/constraints/upper/master"
network_api_extensions_common: *api_extensions
network_api_extensions_tempest:
- taas
- taas-vlan-filter
devstack_localrc:
NEUTRON_DEPLOY_MOD_WSGI: false
- TEMPEST_VENV_UPPER_CONSTRAINTS: master
diff --git a/zuul.d/2025_1_jobs.yaml b/zuul.d/2025_1_jobs.yaml
index 793d8e3..7b295e4 100644
--- a/zuul.d/2025_1_jobs.yaml
+++ b/zuul.d/2025_1_jobs.yaml
@@ -259,3 +259,6 @@
parent: neutron-tempest-plugin-tap-as-a-service-ovn
nodeset: openstack-single-node-noble
override-checkout: stable/2025.1
+ vars:
+ network_api_extensions_tempest:
+ - tap-mirror
diff --git a/zuul.d/2025_2_jobs.yaml b/zuul.d/2025_2_jobs.yaml
index 516e993..839f9c3 100644
--- a/zuul.d/2025_2_jobs.yaml
+++ b/zuul.d/2025_2_jobs.yaml
@@ -237,3 +237,6 @@
parent: neutron-tempest-plugin-tap-as-a-service-ovn
nodeset: openstack-single-node-noble
override-checkout: stable/2025.2
+ vars:
+ network_api_extensions_tempest:
+ - tap-mirror
diff --git a/zuul.d/2026_1_jobs.yaml b/zuul.d/2026_1_jobs.yaml
new file mode 100644
index 0000000..f2d3c7f
--- /dev/null
+++ b/zuul.d/2026_1_jobs.yaml
@@ -0,0 +1,242 @@
+- job:
+ name: neutron-tempest-plugin-openvswitch-2026-1
+ parent: neutron-tempest-plugin-openvswitch
+ nodeset: neutron-nested-virt-ubuntu-noble
+ override-checkout: stable/2026.1
+ vars:
+ network_api_extensions_openvswitch: &api_extensions_openvswitch
+ - dhcp_agent_scheduler
+ - local_ip
+ - qos-bw-minimum-ingress
+ tempest_test_regex: "\
+ (^neutron_tempest_plugin.api)|\
+ (^neutron_tempest_plugin.scenario)|\
+ (^tempest.api.compute.servers.test_attach_interfaces)|\
+ (^tempest.api.compute.servers.test_multiple_create)"
+ network_available_features: &available_features
+ - ipv6_metadata
+ network_api_extensions_common: &api_extensions
+ - address-group
+ - address-scope
+ - agent
+ - allowed-address-pairs
+ - auto-allocated-topology
+ - availability_zone
+ - binding
+ - default-subnetpools
+ - dns-domain-ports
+ - dns-integration
+ - dns-integration-domain-keywords
+ - empty-string-filtering
+ - expose-port-forwarding-in-fip
+ - expose-l3-conntrack-helper
+ - ext-gw-mode
+ - external-net
+ - extra_dhcp_opt
+ - extraroute
+ - extraroute-atomic
+ - filter-validation
+ - fip-port-details
+ - flavors
+ - floating-ip-port-forwarding
+ - floating-ip-port-forwarding-detail
+ - floatingip-pools
+ - ip-substring-filtering
+ - l3-conntrack-helper
+ - l3-ext-ndp-proxy
+ - l3-flavors
+ - l3-ha
+ - l3-ndp-proxy
+ - l3_agent_scheduler
+ - metering
+ - multi-provider
+ - net-mtu
+ - net-mtu-writable
+ - network-ip-availability
+ - network_availability_zone
+ - network-segment-range
+ - pagination
+ - port-device-profile
+ - port-mac-address-regenerate
+ - port-trusted-vif
+ - port-resource-request
+ - port-resource-request-groups
+ - port-security
+ - port-security-groups-filtering
+ - project-id
+ - provider
+ - qos
+ - qos-fip
+ - quotas
+ - quota_details
+ - rbac-address-group
+ - rbac-address-scope
+ - rbac-policies
+ - rbac-security-groups
+ - rbac-subnetpool
+ - router
+ - router_availability_zone
+ - security-group
+ - security-groups-default-rules
+ - security-groups-normalized-cidr
+ - security-groups-remote-address-group
+ - segment
+ - service-type
+ - sorting
+ - standard-attr-description
+ - standard-attr-revisions
+ - standard-attr-segment
+ - standard-attr-tag
+ - standard-attr-timestamp
+ - stateful-security-group
+ - subnet_allocation
+ - subnet-dns-publish-fixed-ip
+ - subnet-service-types
+ - subnetpool-prefix-ops
+ - tag-ports-during-bulk-creation
+ - trunk
+ - trunk-details
+ - uplink-status-propagation
+ - uplink-status-propagation-updatable
+ devstack_localrc:
+ NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_openvswitch) | join(',') }}"
+ devstack_local_conf:
+ test-config:
+ $TEMPEST_CONFIG:
+ network-feature-enabled:
+ available_features: "{{ network_available_features | join(',') }}"
+
+- job:
+ name: neutron-tempest-plugin-openvswitch-iptables_hybrid-2026-1
+ parent: neutron-tempest-plugin-openvswitch-iptables_hybrid
+ nodeset: neutron-nested-virt-ubuntu-noble
+ override-checkout: stable/2026.1
+ vars:
+ network_api_extensions_common: *api_extensions
+ network_api_extensions_openvswitch: *api_extensions_openvswitch
+ network_available_features: *available_features
+ tempest_test_regex: "\
+ (^neutron_tempest_plugin.api)|\
+ (^neutron_tempest_plugin.scenario)|\
+ (^tempest.api.compute.servers.test_attach_interfaces)|\
+ (^tempest.api.compute.servers.test_multiple_create)"
+ # TODO(slaweq): remove trunks subport_connectivity test from blacklist
+ # when bug https://bugs.launchpad.net/neutron/+bug/1838760 will be fixed
+ # TODO(akatz): remove established tcp session verification test when the
+ # bug https://bugzilla.redhat.com/show_bug.cgi?id=1965036 will be fixed
+ tempest_exclude_regex: "\
+ (^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)|\
+ (^neutron_tempest_plugin.scenario.test_security_groups.StatefulNetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)|\
+ (^neutron_tempest_plugin.scenario.test_security_groups.StatelessNetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)"
+ devstack_localrc:
+ NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_openvswitch) | join(',') }}"
+ devstack_local_conf:
+ test-config:
+ $TEMPEST_CONFIG:
+ network-feature-enabled:
+ available_features: "{{ network_available_features | join(',') }}"
+ neutron_plugin_options:
+ available_type_drivers: flat,vlan,local,vxlan
+ firewall_driver: iptables_hybrid
+
+- job:
+ name: neutron-tempest-plugin-ovn-enforce-scope-old-defaults-2026-1
+ parent: neutron-tempest-plugin-ovn-2026-1
+ nodeset: neutron-nested-virt-ubuntu-noble
+ override-checkout: stable/2026.1
+ vars:
+ devstack_localrc:
+ NEUTRON_ENFORCE_SCOPE: false
+
+- job:
+ name: neutron-tempest-plugin-ovn-2026-1
+ parent: neutron-tempest-plugin-ovn
+ nodeset: neutron-nested-virt-ubuntu-noble
+ override-checkout: stable/2026.1
+ vars:
+ network_api_extensions_ovn:
+ - vlan-transparent
+ - qinq
+ - external-gateway-multihoming
+ tempest_test_regex: "\
+ (^neutron_tempest_plugin.api)|\
+ (^neutron_tempest_plugin.scenario)|\
+ (^tempest.api.compute.servers.test_attach_interfaces)|\
+ (^tempest.api.compute.servers.test_multiple_create)"
+ devstack_localrc:
+ NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_ovn) | join(',') }}"
+ devstack_local_conf:
+ test-config:
+ $TEMPEST_CONFIG:
+ network-feature-enabled:
+ available_features: ""
+ neutron_plugin_options:
+ available_type_drivers: local,flat,vlan,geneve
+ is_igmp_snooping_enabled: True
+ firewall_driver: ovn
+
+- job:
+ name: neutron-tempest-plugin-dvr-multinode-scenario-2026-1
+ parent: neutron-tempest-plugin-dvr-multinode-scenario
+ nodeset: openstack-two-node-noble
+ override-checkout: stable/2026.1
+ vars:
+ network_api_extensions_common: *api_extensions
+ network_api_extensions_dvr:
+ - dhcp_agent_scheduler
+ - dvr
+ devstack_localrc:
+ NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_dvr) | join(',') }}"
+
+- job:
+ name: neutron-tempest-plugin-designate-scenario-2026-1
+ parent: neutron-tempest-plugin-designate-scenario
+ nodeset: neutron-nested-virt-ubuntu-noble
+ override-checkout: stable/2026.1
+ vars:
+ network_api_extensions_common: *api_extensions
+
+- job:
+ name: neutron-tempest-plugin-sfc-2026-1
+ parent: neutron-tempest-plugin-sfc
+ nodeset: openstack-single-node-noble
+ override-checkout: stable/2026.1
+
+- job:
+ name: neutron-tempest-plugin-bgpvpn-bagpipe-2026-1
+ parent: neutron-tempest-plugin-bgpvpn-bagpipe
+ nodeset: openstack-single-node-noble
+ override-checkout: stable/2026.1
+
+- job:
+ name: neutron-tempest-plugin-dynamic-routing-2026-1
+ parent: neutron-tempest-plugin-dynamic-routing
+ nodeset: openstack-single-node-noble
+ override-checkout: stable/2026.1
+
+- job:
+ name: neutron-tempest-plugin-fwaas-2026-1
+ parent: neutron-tempest-plugin-fwaas-openvswitch
+ nodeset: openstack-single-node-noble
+ override-checkout: stable/2026.1
+
+- job:
+ name: neutron-tempest-plugin-vpnaas-2026-1
+ parent: neutron-tempest-plugin-vpnaas
+ nodeset: openstack-single-node-noble
+ override-checkout: stable/2026.1
+
+- job:
+ name: neutron-tempest-plugin-tap-as-a-service-2026-1
+ parent: neutron-tempest-plugin-tap-as-a-service
+ nodeset: openstack-single-node-noble
+ override-checkout: stable/2026.1
+
+- job:
+ name: neutron-tempest-plugin-tap-as-a-service-ovn-2026-1
+ parent: neutron-tempest-plugin-tap-as-a-service-ovn
+ nodeset: openstack-single-node-noble
+ override-checkout: stable/2026.1
+ vars:
+ network_api_extensions_tempest:
+ - tap-mirror
diff --git a/zuul.d/master_jobs.yaml b/zuul.d/master_jobs.yaml
index 62e76d7..28cfb11 100644
--- a/zuul.d/master_jobs.yaml
+++ b/zuul.d/master_jobs.yaml
@@ -1369,12 +1369,11 @@
q-meta: true
q-metering: true
q-l3: true
- neutron-log: false
devstack_local_conf:
test-config:
$TEMPEST_CONFIG:
fwaas:
- driver: openvswitch
+ driver: iptables_v2
irrelevant-files: *fwaas_irrelevant_files
- job:
@@ -1534,6 +1533,7 @@
tempest_test_regex: ^neutron_tempest_plugin\.tap_as_a_service
tox_envlist: all
network_api_extensions_tempest:
+ # taas extension (tap-service and tap-flow) is only supported in ML2/OVS
- taas
- taas-vlan-filter
- tap-mirror
@@ -1651,8 +1651,8 @@
tempest_test_regex: ^neutron_tempest_plugin\.tap_as_a_service
tox_envlist: all
network_api_extensions_tempest:
- - taas
- tap-mirror
+ - tap-mirror-both-direction
devstack_localrc:
Q_AGENT: ovn
NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 5841ee5..e905c71 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -210,6 +210,23 @@
jobs:
- neutron-tempest-plugin-dvr-multinode-scenario-2025-2
+- project-template:
+ name: neutron-tempest-plugin-jobs-2026-1
+ check:
+ jobs:
+ - neutron-tempest-plugin-openvswitch-2026-1
+ - neutron-tempest-plugin-openvswitch-iptables_hybrid-2026-1
+ - neutron-tempest-plugin-ovn-2026-1
+ - neutron-tempest-plugin-designate-scenario-2026-1
+ gate:
+ jobs:
+ - neutron-tempest-plugin-ovn-2026-1
+ #TODO(slaweq): Move neutron-tempest-plugin-dvr-multinode-scenario out of
+ # the experimental queue when it will be more stable
+ experimental:
+ jobs:
+ - neutron-tempest-plugin-dvr-multinode-scenario-2026-1
+
- project:
templates:
- build-openstack-docs-pti
@@ -217,6 +234,7 @@
- neutron-tempest-plugin-jobs-2024-2
- neutron-tempest-plugin-jobs-2025-1
- neutron-tempest-plugin-jobs-2025-2
+ - neutron-tempest-plugin-jobs-2026-1
- check-requirements
- tempest-plugin-jobs
- release-notes-jobs-python3
@@ -226,38 +244,43 @@
- neutron-tempest-plugin-sfc-2024-2
- neutron-tempest-plugin-sfc-2025-1
- neutron-tempest-plugin-sfc-2025-2
+ - neutron-tempest-plugin-sfc-2026-1
- neutron-tempest-plugin-bgpvpn-bagpipe
- neutron-tempest-plugin-bgpvpn-bagpipe-2024-2
- neutron-tempest-plugin-bgpvpn-bagpipe-2025-1
- neutron-tempest-plugin-bgpvpn-bagpipe-2025-2
- - neutron-tempest-plugin-dynamic-routing:
- voting: false # See LP#2130631
+ - neutron-tempest-plugin-bgpvpn-bagpipe-2026-1
+ - neutron-tempest-plugin-dynamic-routing
- neutron-tempest-plugin-dynamic-routing-2024-2
- neutron-tempest-plugin-dynamic-routing-2025-1
- neutron-tempest-plugin-dynamic-routing-2025-2
+ - neutron-tempest-plugin-dynamic-routing-2026-1
- neutron-tempest-plugin-fwaas-ovn
- neutron-tempest-plugin-fwaas-openvswitch
- neutron-tempest-plugin-fwaas-2024-2
- neutron-tempest-plugin-fwaas-2025-1
- neutron-tempest-plugin-fwaas-2025-2
+ - neutron-tempest-plugin-fwaas-2026-1
- neutron-tempest-plugin-vpnaas
- neutron-tempest-plugin-vpnaas-ovn
- neutron-tempest-plugin-vpnaas-2024-2
- neutron-tempest-plugin-vpnaas-2025-1
- neutron-tempest-plugin-vpnaas-2025-2
+ - neutron-tempest-plugin-vpnaas-2026-1
- neutron-tempest-plugin-tap-as-a-service
- neutron-tempest-plugin-tap-as-a-service-ovn
- neutron-tempest-plugin-tap-as-a-service-2024-2
- neutron-tempest-plugin-tap-as-a-service-2025-1
- neutron-tempest-plugin-tap-as-a-service-2025-2
+ - neutron-tempest-plugin-tap-as-a-service-2026-1
- neutron-tempest-plugin-tap-as-a-service-ovn-2025-1
- neutron-tempest-plugin-tap-as-a-service-ovn-2025-2
+ - neutron-tempest-plugin-tap-as-a-service-ovn-2026-1
gate:
jobs:
- neutron-tempest-plugin-sfc
- neutron-tempest-plugin-bgpvpn-bagpipe
- - neutron-tempest-plugin-dynamic-routing:
- voting: false # See LP#2130631
+ - neutron-tempest-plugin-dynamic-routing
- neutron-tempest-plugin-fwaas-ovn
- neutron-tempest-plugin-vpnaas-ovn