Merge "Fix stable/train testing with tempest 26.1.0"
diff --git a/playbooks/enable-fips.yaml b/playbooks/enable-fips.yaml
new file mode 100644
index 0000000..c8f042d
--- /dev/null
+++ b/playbooks/enable-fips.yaml
@@ -0,0 +1,4 @@
+- hosts: all
+ tasks:
+ - include_role:
+ name: enable-fips
diff --git a/releasenotes/notes/add-ssh-key-type-38d7a2f900d79842.yaml b/releasenotes/notes/add-ssh-key-type-38d7a2f900d79842.yaml
new file mode 100644
index 0000000..fef3004
--- /dev/null
+++ b/releasenotes/notes/add-ssh-key-type-38d7a2f900d79842.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Add parameter to specify the SSH key type. Current options are 'rsa'
+ (which is the default) and 'ecdsa'. Tempest now supports the importing
+ and generation of both 'rsa' and 'ecdsa' SSH key types.
diff --git a/requirements.txt b/requirements.txt
index c71cabe..bc8358b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,6 +6,7 @@
jsonschema>=3.2.0 # MIT
testtools>=2.2.0 # MIT
paramiko>=2.7.0 # LGPLv2.1+
+cryptography>=2.1 # BSD/Apache-2.0
netaddr>=0.7.18 # BSD
oslo.concurrency>=3.26.0 # Apache-2.0
oslo.config>=5.2.0 # Apache-2.0
diff --git a/tempest/api/compute/admin/test_agents.py b/tempest/api/compute/admin/test_agents.py
index 4cc5fdd..f54fb22 100644
--- a/tempest/api/compute/admin/test_agents.py
+++ b/tempest/api/compute/admin/test_agents.py
@@ -119,3 +119,5 @@
self.assertIn(agent_id_xen, map(lambda x: x['agent_id'], agents))
self.assertNotIn(body['agent_id'], map(lambda x: x['agent_id'],
agents))
+ for agent in agents:
+ self.assertEqual(agent_xen['hypervisor'], agent['hypervisor'])
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 2716259..a6c6535 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -17,6 +17,7 @@
from tempest.api.compute import base
from tempest.common import tempest_fixtures as fixtures
+from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
@@ -237,6 +238,10 @@
wait_until='ACTIVE')
server_host = self.get_host_for_server(server['id'])
self.assertEqual(host, server_host)
+ self.servers_client.delete_server(server['id'])
+ # NOTE(gmann): We need to wait for the server to delete before
+ # addCleanup remove the host from aggregate.
+ waiters.wait_for_server_termination(self.servers_client, server['id'])
class AggregatesAdminTestV241(AggregatesAdminTestBase):
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index ac18442..efecd6c 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -68,7 +68,8 @@
self.image_ssh_password,
validation_resources['keypair']['private_key'],
server=server,
- servers_client=self.servers_client)
+ servers_client=self.servers_client,
+ ssh_key_type=CONF.validation.ssh_key_type)
linux_client.validate_authentication()
def _create_server_get_interfaces(self):
diff --git a/tempest/api/volume/admin/test_group_type_specs.py b/tempest/api/volume/admin/test_group_type_specs.py
index 63c3546..181926e 100644
--- a/tempest/api/volume/admin/test_group_type_specs.py
+++ b/tempest/api/volume/admin/test_group_type_specs.py
@@ -73,10 +73,11 @@
self.assertEqual(list_specs, body)
# Delete specified item of group type specs
- delete_key = 'key1'
- self.admin_group_types_client.delete_group_type_specs_item(
- group_type['id'], delete_key)
- self.assertRaises(
- lib_exc.NotFound,
- self.admin_group_types_client.show_group_type_specs_item,
- group_type['id'], delete_key)
+ delete_keys = ['key1', 'key2', 'key3']
+ for it in delete_keys:
+ self.admin_group_types_client.delete_group_type_specs_item(
+ group_type['id'], it)
+ self.assertRaises(
+ lib_exc.NotFound,
+ self.admin_group_types_client.show_group_type_specs_item,
+ group_type['id'], it)
diff --git a/tempest/clients.py b/tempest/clients.py
index 327f0da..4c3d875 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -118,7 +118,8 @@
self.server_groups_client = self.compute.ServerGroupsClient()
self.limits_client = self.compute.LimitsClient()
self.compute_images_client = self.compute.ImagesClient()
- self.keypairs_client = self.compute.KeyPairsClient()
+ self.keypairs_client = self.compute.KeyPairsClient(
+ ssh_key_type=CONF.validation.ssh_key_type)
self.quotas_client = self.compute.QuotasClient()
self.quota_classes_client = self.compute.QuotaClassesClient()
self.flavors_client = self.compute.FlavorsClient()
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 5d6e129..9d9fab7 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -48,7 +48,8 @@
console_output_enabled=CONF.compute_feature_enabled.console_output,
ssh_shell_prologue=CONF.validation.ssh_shell_prologue,
ping_count=CONF.validation.ping_count,
- ping_size=CONF.validation.ping_size)
+ ping_size=CONF.validation.ping_size,
+ ssh_key_type=CONF.validation.ssh_key_type)
# Note that this method will not work on SLES11 guests, as they do
# not support the TYPE column on lsblk
diff --git a/tempest/config.py b/tempest/config.py
index a840a97..03ddbf5 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -970,6 +970,10 @@
default='public',
help="Network used for SSH connections. Ignored if "
"connect_method=floating."),
+ cfg.StrOpt('ssh_key_type',
+ default='rsa',
+ help='Type of key to use for ssh connections. '
+ 'Valid types are rsa, ecdsa'),
]
volume_group = cfg.OptGroup(name='volume',
diff --git a/tempest/lib/common/ssh.py b/tempest/lib/common/ssh.py
index ee15375..cb59a82 100644
--- a/tempest/lib/common/ssh.py
+++ b/tempest/lib/common/ssh.py
@@ -21,6 +21,7 @@
import warnings
from oslo_log import log as logging
+from oslo_utils.secretutils import md5
from tempest.lib import exceptions
@@ -33,11 +34,26 @@
LOG = logging.getLogger(__name__)
+def get_fingerprint(self):
+ """Patch paramiko
+
+ This method needs to be patched to allow paramiko to work under FIPS.
+ Until the patch to do this merges, patch paramiko here.
+
+ TODO(alee) Remove this when paramiko is patched.
+ See https://github.com/paramiko/paramiko/pull/1928
+ """
+ return md5(self.asbytes(), usedforsecurity=False).digest()
+
+
+paramiko.pkey.PKey.get_fingerprint = get_fingerprint
+
+
class Client(object):
def __init__(self, host, username, password=None, timeout=300, pkey=None,
channel_timeout=10, look_for_keys=False, key_filename=None,
- port=22, proxy_client=None):
+ port=22, proxy_client=None, ssh_key_type='rsa'):
"""SSH client.
Many of parameters are just passed to the underlying implementation
@@ -59,6 +75,7 @@
:param proxy_client: Another SSH client to provide a transport
for ssh-over-ssh. The default is None, which means
not to use ssh-over-ssh.
+ :param ssh_key_type: ssh key type (rsa, ecdsa)
:type proxy_client: ``tempest.lib.common.ssh.Client`` object
"""
self.host = host
@@ -66,8 +83,15 @@
self.port = port
self.password = password
if isinstance(pkey, str):
- pkey = paramiko.RSAKey.from_private_key(
- io.StringIO(str(pkey)))
+ if ssh_key_type == 'rsa':
+ pkey = paramiko.RSAKey.from_private_key(
+ io.StringIO(str(pkey)))
+ elif ssh_key_type == 'ecdsa':
+ pkey = paramiko.ECDSAKey.from_private_key(
+ io.StringIO(str(pkey)))
+ else:
+ raise exceptions.SSHClientUnsupportedKeyType(
+ key_type=ssh_key_type)
self.pkey = pkey
self.look_for_keys = look_for_keys
self.key_filename = key_filename
diff --git a/tempest/lib/common/utils/linux/remote_client.py b/tempest/lib/common/utils/linux/remote_client.py
index d84dd28..224f3bf 100644
--- a/tempest/lib/common/utils/linux/remote_client.py
+++ b/tempest/lib/common/utils/linux/remote_client.py
@@ -69,7 +69,7 @@
server=None, servers_client=None, ssh_timeout=300,
connect_timeout=60, console_output_enabled=True,
ssh_shell_prologue="set -eu -o pipefail; PATH=$PATH:/sbin;",
- ping_count=1, ping_size=56):
+ ping_count=1, ping_size=56, ssh_key_type='rsa'):
"""Executes commands in a VM over ssh
:param ip_address: IP address to ssh to
@@ -84,6 +84,7 @@
:param ssh_shell_prologue: Shell fragments to use before command
:param ping_count: Number of ping packets
:param ping_size: Packet size for ping packets
+ :param ssh_key_type: ssh key type (rsa, ecdsa)
"""
self.server = server
self.servers_client = servers_client
@@ -92,10 +93,12 @@
self.ssh_shell_prologue = ssh_shell_prologue
self.ping_count = ping_count
self.ping_size = ping_size
+ self.ssh_key_type = ssh_key_type
self.ssh_client = ssh.Client(ip_address, username, password,
ssh_timeout, pkey=pkey,
- channel_timeout=connect_timeout)
+ channel_timeout=connect_timeout,
+ ssh_key_type=ssh_key_type)
@debug_ssh
def exec_command(self, cmd):
diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py
index abe68d2..dd7885e 100644
--- a/tempest/lib/exceptions.py
+++ b/tempest/lib/exceptions.py
@@ -256,6 +256,10 @@
"%(port)s and username: %(username)s as parent")
+class SSHClientUnsupportedKeyType(TempestException):
+ message = ("SSH client: unsupported key type %(key_type)s")
+
+
class UnknownServiceClient(TempestException):
message = "Service clients named %(services)s are not known"
diff --git a/tempest/lib/services/compute/keypairs_client.py b/tempest/lib/services/compute/keypairs_client.py
index 9d7b7fc..51a4583 100644
--- a/tempest/lib/services/compute/keypairs_client.py
+++ b/tempest/lib/services/compute/keypairs_client.py
@@ -15,6 +15,10 @@
from urllib import parse as urllib
+from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.primitives.asymmetric import ec
+from cryptography.hazmat.primitives import serialization
+
from oslo_serialization import jsonutils as json
from tempest.lib.api_schema.response.compute.v2_1 import keypairs as schemav21
@@ -28,6 +32,12 @@
schema_versions_info = [{'min': None, 'max': '2.1', 'schema': schemav21},
{'min': '2.2', 'max': None, 'schema': schemav22}]
+ def __init__(self, auth_provider, service, region,
+ ssh_key_type='rsa', **kwargs):
+ super(KeyPairsClient, self).__init__(
+ auth_provider, service, region, **kwargs)
+ self.ssh_key_type = ssh_key_type
+
def list_keypairs(self, **params):
"""Lists keypairs that are associated with the account.
@@ -67,12 +77,30 @@
API reference:
https://docs.openstack.org/api-ref/compute/#create-or-import-keypair
"""
+ pkey = None
+ if (self.ssh_key_type == 'ecdsa' and 'public_key' not in kwargs and
+ ('type' not in kwargs or kwargs['type'] == 'ssh')):
+ # create a ecdsa key and pass the public key into the request
+ pkey = ec.generate_private_key(ec.SECP384R1(), default_backend())
+ pubkey = pkey.public_key().public_bytes(
+ encoding=serialization.Encoding.OpenSSH,
+ format=serialization.PublicFormat.OpenSSH)
+ kwargs['public_key'] = pubkey
+
post_body = json.dumps({'keypair': kwargs})
resp, body = self.post("os-keypairs", body=post_body)
body = json.loads(body)
schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.create_keypair, resp, body)
- return rest_client.ResponseBody(resp, body)
+ resp_body = rest_client.ResponseBody(resp, body)
+ if pkey:
+ # add the privkey to the response as it was generated here
+ privkey = pkey.private_bytes(
+ encoding=serialization.Encoding.PEM,
+ format=serialization.PrivateFormat.TraditionalOpenSSL,
+ encryption_algorithm=serialization.NoEncryption())
+ resp_body['keypair']['private_key'] = privkey.decode('utf-8')
+ return resp_body
def delete_keypair(self, keypair_name, **params):
"""Deletes a keypair.
diff --git a/tempest/scenario/test_network_qos_placement.py b/tempest/scenario/test_network_qos_placement.py
index a8e9174..adb0ee3 100644
--- a/tempest/scenario/test_network_qos_placement.py
+++ b/tempest/scenario/test_network_qos_placement.py
@@ -49,8 +49,10 @@
compute_max_microversion = 'latest'
INGRESS_DIRECTION = 'ingress'
+ EGRESS_DIRECTION = 'egress'
ANY_DIRECTION = 'any'
- BW_RESOURCE_CLASS = "NET_BW_IGR_KILOBIT_PER_SEC"
+ INGRESS_RESOURCE_CLASS = "NET_BW_IGR_KILOBIT_PER_SEC"
+ EGRESS_RESOURCE_CLASS = "NET_BW_EGR_KILOBIT_PER_SEC"
# For any realistic inventory value (that is inventory != MAX_INT) an
# allocation candidate request of MAX_INT is expected to be rejected, see:
@@ -107,7 +109,9 @@
super(MinBwAllocationPlacementTest, self).setUp()
self._check_if_allocation_is_possible()
- def _create_policy_and_min_bw_rule(self, name_prefix, min_kbps):
+ def _create_policy_and_min_bw_rule(
+ self, name_prefix, min_kbps, direction="ingress"
+ ):
policy = self.qos_client.create_qos_policy(
name=data_utils.rand_name(name_prefix),
shared=True)['policy']
@@ -117,7 +121,7 @@
policy['id'],
**{
'min_kbps': min_kbps,
- 'direction': self.INGRESS_DIRECTION
+ 'direction': direction,
})['minimum_bandwidth_rule']
self.addCleanup(
test_utils.call_and_ignore_notfound_exc,
@@ -167,20 +171,20 @@
def _check_if_allocation_is_possible(self):
alloc_candidates = self.placement_client.list_allocation_candidates(
- resources1='%s:%s' % (self.BW_RESOURCE_CLASS,
+ resources1='%s:%s' % (self.INGRESS_RESOURCE_CLASS,
self.SMALLEST_POSSIBLE_BW))
if len(alloc_candidates['provider_summaries']) == 0:
self.fail('No allocation candidates are available for %s:%s' %
- (self.BW_RESOURCE_CLASS, self.SMALLEST_POSSIBLE_BW))
+ (self.INGRESS_RESOURCE_CLASS, self.SMALLEST_POSSIBLE_BW))
# Just to be sure check with impossible high (placement max_int),
# allocation
alloc_candidates = self.placement_client.list_allocation_candidates(
- resources1='%s:%s' % (self.BW_RESOURCE_CLASS,
+ resources1='%s:%s' % (self.INGRESS_RESOURCE_CLASS,
self.PLACEMENT_MAX_INT))
if len(alloc_candidates['provider_summaries']) != 0:
self.fail('For %s:%s there should be no available candidate!' %
- (self.BW_RESOURCE_CLASS, self.PLACEMENT_MAX_INT))
+ (self.INGRESS_RESOURCE_CLASS, self.PLACEMENT_MAX_INT))
def _boot_vm_with_min_bw(self, qos_policy_id, status='ACTIVE'):
wait_until = (None if status == 'ERROR' else status)
@@ -194,22 +198,28 @@
status=status, ready_wait=False, raise_on_error=False)
return server, port
- def _assert_allocation_is_as_expected(self, consumer, port_ids,
- min_kbps=SMALLEST_POSSIBLE_BW):
+ def _assert_allocation_is_as_expected(
+ self, consumer, port_ids, min_kbps=SMALLEST_POSSIBLE_BW,
+ expected_rc=NetworkQoSPlacementTestBase.INGRESS_RESOURCE_CLASS,
+ ):
allocations = self.placement_client.list_allocations(
consumer)['allocations']
self.assertGreater(len(allocations), 0)
bw_resource_in_alloc = False
allocation_rp = None
for rp, resources in allocations.items():
- if self.BW_RESOURCE_CLASS in resources['resources']:
+ if expected_rc in resources['resources']:
self.assertEqual(
min_kbps,
- resources['resources'][self.BW_RESOURCE_CLASS])
+ resources['resources'][expected_rc])
bw_resource_in_alloc = True
allocation_rp = rp
if min_kbps:
- self.assertTrue(bw_resource_in_alloc)
+ self.assertTrue(
+ bw_resource_in_alloc,
+ f"expected {min_kbps} bandwidth allocation from {expected_rc} "
+ f"but instance has allocation {allocations} instead."
+ )
# Check binding_profile of the port is not empty and equals with
# the rp uuid
@@ -510,6 +520,60 @@
self._assert_allocation_is_as_expected(server1['id'], [port['id']],
self.BANDWIDTH_1)
+ @decorators.idempotent_id('372b2728-cfed-469a-b5f6-b75779e1ccbe')
+ @utils.services('compute', 'network')
+ def test_qos_min_bw_allocation_update_policy_direction_change(self):
+ """Test QoS min bw direction change on a bound port
+
+ Related RFE in neutron: #1882804
+ The scenario is the following:
+ * Have a port with QoS policy and minimum bandwidth rule with ingress
+ direction
+ * Boot a VM with the port.
+ * Update the port with a new policy to egress direction in
+ minimum bandwidth rule.
+ * The allocation on placement side should be according to the new
+ rules.
+ """
+ if not utils.is_network_feature_enabled('update_port_qos'):
+ raise self.skipException("update_port_qos feature is not enabled")
+
+ def create_policies():
+ self.qos_policy_ingress = self._create_policy_and_min_bw_rule(
+ name_prefix='test_policy_ingress',
+ min_kbps=self.BANDWIDTH_1,
+ direction=self.INGRESS_DIRECTION,
+ )
+ self.qos_policy_egress = self._create_policy_and_min_bw_rule(
+ name_prefix='test_policy_egress',
+ min_kbps=self.BANDWIDTH_1,
+ direction=self.EGRESS_DIRECTION,
+ )
+
+ self._create_network_and_qos_policies(create_policies)
+
+ port = self.create_port(
+ self.prov_network['id'],
+ qos_policy_id=self.qos_policy_ingress['id'])
+
+ server1 = self.create_server(
+ networks=[{'port': port['id']}])
+
+ self._assert_allocation_is_as_expected(
+ server1['id'], [port['id']], self.BANDWIDTH_1,
+ expected_rc=self.INGRESS_RESOURCE_CLASS)
+
+ self.ports_client.update_port(
+ port['id'],
+ qos_policy_id=self.qos_policy_egress['id'])
+
+ self._assert_allocation_is_as_expected(
+ server1['id'], [port['id']], self.BANDWIDTH_1,
+ expected_rc=self.EGRESS_RESOURCE_CLASS)
+ self._assert_allocation_is_as_expected(
+ server1['id'], [port['id']], 0,
+ expected_rc=self.INGRESS_RESOURCE_CLASS)
+
class QoSBandwidthAndPacketRateTests(NetworkQoSPlacementTestBase):
@@ -625,9 +689,9 @@
if expected_min_kbps > 0:
bw_rp_allocs = {
- rp: alloc['resources'][self.BW_RESOURCE_CLASS]
+ rp: alloc['resources'][self.INGRESS_RESOURCE_CLASS]
for rp, alloc in allocations.items()
- if self.BW_RESOURCE_CLASS in alloc['resources']
+ if self.INGRESS_RESOURCE_CLASS in alloc['resources']
}
self.assertEqual(1, len(bw_rp_allocs))
bw_rp, bw_alloc = list(bw_rp_allocs.items())[0]
diff --git a/tempest/tests/lib/services/image/v2/test_schemas_client.py b/tempest/tests/lib/services/image/v2/test_schemas_client.py
index 4c4b86a..eef5b41 100644
--- a/tempest/tests/lib/services/image/v2/test_schemas_client.py
+++ b/tempest/tests/lib/services/image/v2/test_schemas_client.py
@@ -81,6 +81,14 @@
self.client = schemas_client.SchemasClient(fake_auth,
'image', 'regionOne')
+ def _test_show_schema_members(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_schema,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_SHOW_SCHEMA,
+ bytes_body,
+ schema="members")
+
def _test_show_schema(self, bytes_body=False):
self.check_service_client_function(
self.client.show_schema,
@@ -89,6 +97,12 @@
bytes_body,
schema="member")
+ def test_show_schema_members_with_str_body(self):
+ self._test_show_schema_members()
+
+ def test_show_schema_members_with_bytes_body(self):
+ self._test_show_schema_members(bytes_body=True)
+
def test_show_schema_with_str_body(self):
self._test_show_schema()
diff --git a/zuul.d/integrated-gate.yaml b/zuul.d/integrated-gate.yaml
index b86268a..fad17dd 100644
--- a/zuul.d/integrated-gate.yaml
+++ b/zuul.d/integrated-gate.yaml
@@ -131,6 +131,8 @@
- job:
name: tempest-integrated-compute-centos-8-stream
parent: tempest-integrated-compute
+ # TODO(gmann): Make this job non voting until bug#1957941 if fixed.
+ voting: false
nodeset: devstack-single-node-centos-8-stream
branches: ^(?!stable/(ocata|pike|queens|rocky|stein|train|ussuri|victoria)).*$
description: |
@@ -296,6 +298,22 @@
TEMPEST_VOLUME_TYPE: volumev2
- job:
+ name: tempest-centos8-stream-fips
+ parent: devstack-tempest
+ description: |
+ Integration testing for a FIPS enabled Centos 8 system
+ nodeset: devstack-single-node-centos-8-stream
+ pre-run: playbooks/enable-fips.yaml
+ vars:
+ tox_envlist: full
+ configure_swap_size: 4096
+ devstack_local_conf:
+ test-config:
+ "$TEMPEST_CONFIG":
+ validation:
+ ssh_key_type: 'ecdsa'
+
+- job:
name: tempest-pg-full
parent: tempest-full-py3
description: |
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 9ab10d7..731a72a 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -159,7 +159,7 @@
irrelevant-files: *tempest-irrelevant-files
- tempest-pg-full:
irrelevant-files: *tempest-irrelevant-files
- - tempest-full-py3-opensuse15:
+ - tempest-centos8-stream-fips:
irrelevant-files: *tempest-irrelevant-files
periodic-stable:
jobs:
diff --git a/zuul.d/stable-jobs.yaml b/zuul.d/stable-jobs.yaml
index da6cc46..5cc0dd0 100644
--- a/zuul.d/stable-jobs.yaml
+++ b/zuul.d/stable-jobs.yaml
@@ -178,3 +178,24 @@
subnode:
devstack_localrc:
USE_PYTHON3: true
+
+- job:
+ name: tempest-full-py3-opensuse15
+ parent: tempest-full-py3
+ nodeset: devstack-single-node-opensuse-15
+ description: |
+ Base integration test with Neutron networking and py36 running
+ on openSUSE Leap 15.x
+ voting: false
+ # This job is not used after stable/xena and can be
+ # removed once stable/xena is EOL.
+ branches:
+ - stable/pike
+ - stable/queens
+ - stable/rocky
+ - stable/stein
+ - stable/train
+ - stable/ussuri
+ - stable/victoria
+ - stable/wallaby
+ - stable/xena
diff --git a/zuul.d/tempest-specific.yaml b/zuul.d/tempest-specific.yaml
index 051d8b0..5b6b702 100644
--- a/zuul.d/tempest-specific.yaml
+++ b/zuul.d/tempest-specific.yaml
@@ -69,17 +69,10 @@
c-bak: false
- job:
- name: tempest-full-py3-opensuse15
- parent: tempest-full-py3
- nodeset: devstack-single-node-opensuse-15
- description: |
- Base integration test with Neutron networking and py36 running
- on openSUSE Leap 15.x
- voting: false
-
-- job:
name: tempest-full-py3-centos-8-stream
parent: tempest-full-py3
+ # TODO(gmann): Make this job non voting until bug#1957941 if fixed.
+ voting: false
nodeset: devstack-single-node-centos-8-stream
description: |
Base integration test with Neutron networking and py36 running