Merge "Remove "active" attribute from the allowed_address_pairs"
diff --git a/playbooks/devstack-tempest-ipv6.yaml b/playbooks/devstack-tempest-ipv6.yaml
index 4788362..d56fb73 100644
--- a/playbooks/devstack-tempest-ipv6.yaml
+++ b/playbooks/devstack-tempest-ipv6.yaml
@@ -15,5 +15,5 @@
     # IPv6 only env for example Devstack IPv6 settings and services listen
     # address is IPv6 etc. This is invoked before tests are run so that we can
     # fail early if anything missing the IPv6 settings or deployments.
-    - ipv6-only-deployments-verification
+    - devstack-ipv6-only-deployments-verification
     - run-tempest
diff --git a/roles/ipv6-only-deployments-verification/README.rst b/roles/ipv6-only-deployments-verification/README.rst
deleted file mode 100644
index 400a8da..0000000
--- a/roles/ipv6-only-deployments-verification/README.rst
+++ /dev/null
@@ -1,16 +0,0 @@
-Verify the IPv6-only deployments
-
-This role needs to be invoked from a playbook that
-run tests. This role verifies the IPv6 setting on
-devstack side and devstack deploy services on IPv6.
-This role is invoked before tests are run so that
-if any missing IPv6 setting or deployments can fail
-the job early.
-
-
-**Role Variables**
-
-.. zuul:rolevar:: devstack_base_dir
-   :default: /opt/stack
-
-   The devstack base directory.
diff --git a/roles/ipv6-only-deployments-verification/defaults/main.yaml b/roles/ipv6-only-deployments-verification/defaults/main.yaml
deleted file mode 100644
index fea05c8..0000000
--- a/roles/ipv6-only-deployments-verification/defaults/main.yaml
+++ /dev/null
@@ -1 +0,0 @@
-devstack_base_dir: /opt/stack
diff --git a/roles/ipv6-only-deployments-verification/tasks/main.yaml b/roles/ipv6-only-deployments-verification/tasks/main.yaml
deleted file mode 100644
index d73c79c..0000000
--- a/roles/ipv6-only-deployments-verification/tasks/main.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: Verify the ipv6-only deployments
-  become: true
-  become_user: stack
-  shell: "{{ devstack_base_dir }}/tempest/tools/verify-ipv6-only-deployments.sh"
diff --git a/tempest/api/compute/admin/test_create_server.py b/tempest/api/compute/admin/test_create_server.py
index c4a8bf5..ccdfbf3 100644
--- a/tempest/api/compute/admin/test_create_server.py
+++ b/tempest/api/compute/admin/test_create_server.py
@@ -42,6 +42,8 @@
     @decorators.idempotent_id('b3c7bcfc-bb5b-4e22-b517-c7f686b802ca')
     @testtools.skipUnless(CONF.validation.run_validation,
                           'Instance validation tests are disabled.')
+    @testtools.skipIf("aarch64" in CONF.scenario.img_file,
+                      "Aarch64 does not support ephemeral disk test")
     def test_verify_created_server_ephemeral_disk(self):
         """Verify that the ephemeral disk is created when creating server"""
         flavor_base = self.flavors_client.show_flavor(
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 7900b77..bee4716 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -515,6 +515,12 @@
             kwargs['display_name'] = vol_name
         if image_ref is not None:
             kwargs['imageRef'] = image_ref
+        if CONF.volume.volume_type and 'volume_type' not in kwargs:
+            # If volume_type is not provided in config then no need to
+            # add a volume type and
+            # if volume_type has already been added by child class then
+            # no need to override.
+            kwargs['volume_type'] = CONF.volume.volume_type
         if CONF.compute.compute_volume_common_az:
             kwargs.setdefault('availability_zone',
                               CONF.compute.compute_volume_common_az)
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index a9f8c09..354e3b9 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -168,6 +168,8 @@
             raise cls.skipException("IDE bus not available.")
 
     @decorators.idempotent_id('947004c3-e8ef-47d9-9f00-97b74f9eaf96')
+    @testtools.skipIf("aarch64" in CONF.scenario.img_file,
+                      "Aarch64 does not support ide bus for cdrom")
     def test_stable_device_rescue_cdrom_ide(self):
         """Test rescuing server with cdrom and ide as the rescue disk"""
         server_id, rescue_image_id = self._create_server_and_rescue_image(
diff --git a/tempest/lib/api_schema/response/volume/services.py b/tempest/lib/api_schema/response/volume/services.py
index 70de878..216631c 100644
--- a/tempest/lib/api_schema/response/volume/services.py
+++ b/tempest/lib/api_schema/response/volume/services.py
@@ -33,10 +33,6 @@
                         'frozen': {'type': 'boolean'},
                         'updated_at': parameter_types.date_time,
                         'zone': {'type': 'string'},
-                        # TODO(zhufl): cluster is added in 3.7, we should move
-                        # it to the 3.7 schema file when microversion is
-                        # supported in volume interfaces
-                        'cluster': {'type': 'string'},
                         'replication_status': {'type': 'string'},
                         'active_backend_id': {'type': ['string', 'null']},
                         'backend_state': {'type': 'string'},
diff --git a/tempest/lib/api_schema/response/volume/v3_7/__init__.py b/tempest/lib/api_schema/response/volume/v3_7/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/lib/api_schema/response/volume/v3_7/__init__.py
diff --git a/tempest/lib/api_schema/response/volume/v3_7/services.py b/tempest/lib/api_schema/response/volume/v3_7/services.py
new file mode 100644
index 0000000..8d43188
--- /dev/null
+++ b/tempest/lib/api_schema/response/volume/v3_7/services.py
@@ -0,0 +1,34 @@
+# Copyright 2020 ZTE Corporation.  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 copy
+
+from tempest.lib.api_schema.response.volume import services
+
+# Volume microversion 3.7:
+# 1. New optional attribute in 'services' dict.
+#      'cluster'
+
+list_services = copy.deepcopy(services.list_services)
+list_services['response_body']['properties']['services']['items'][
+    'properties'].update({'cluster': {'type': ['string', 'null']}})
+
+# NOTE(zhufl): Below are the unchanged schema in this microversion. We need
+# to keep this schema in this file to have the generic way to select the
+# right schema based on self.schema_versions_info mapping in service client.
+# ****** Schemas unchanged since microversion 3.0 ******
+enable_service = copy.deepcopy(services.enable_service)
+disable_service = copy.deepcopy(services.disable_service)
+disable_log_reason = copy.deepcopy(services.disable_log_reason)
+freeze_host = copy.deepcopy(services.freeze_host)
+thaw_host = copy.deepcopy(services.thaw_host)
diff --git a/tempest/lib/services/volume/base_client.py b/tempest/lib/services/volume/base_client.py
index c7fb21a..c0ac62d 100644
--- a/tempest/lib/services/volume/base_client.py
+++ b/tempest/lib/services/volume/base_client.py
@@ -13,8 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.lib.common import api_version_request
 from tempest.lib.common import api_version_utils
 from tempest.lib.common import rest_client
+from tempest.lib import exceptions
 
 VOLUME_MICROVERSION = None
 
@@ -43,3 +45,39 @@
                 'volume %s' % VOLUME_MICROVERSION,
                 resp)
         return resp, resp_body
+
+    def get_schema(self, schema_versions_info):
+        """Get JSON schema
+
+        This method provides the matching schema for requested
+        microversion.
+
+        :param schema_versions_info: List of dict which provides schema
+                                     information with range of valid versions.
+
+        Example::
+
+         schema_versions_info = [
+             {'min': None, 'max': '2.1', 'schema': schemav21},
+             {'min': '2.2', 'max': '2.9', 'schema': schemav22},
+             {'min': '2.10', 'max': None, 'schema': schemav210}]
+        """
+        schema = None
+        version = api_version_request.APIVersionRequest(VOLUME_MICROVERSION)
+        for items in schema_versions_info:
+            min_version = api_version_request.APIVersionRequest(items['min'])
+            max_version = api_version_request.APIVersionRequest(items['max'])
+            # This is case where COMPUTE_MICROVERSION is None, which means
+            # request without microversion So select base v2.1 schema.
+            if version.is_null() and items['min'] is None:
+                schema = items['schema']
+                break
+            # else select appropriate schema as per COMPUTE_MICROVERSION
+            elif version.matches(min_version, max_version):
+                schema = items['schema']
+                break
+        if schema is None:
+            raise exceptions.JSONSchemaNotFound(
+                version=version.get_string(),
+                schema_versions_info=schema_versions_info)
+        return schema
diff --git a/tempest/lib/services/volume/v3/services_client.py b/tempest/lib/services/volume/v3/services_client.py
index 4672da8..1111f81 100644
--- a/tempest/lib/services/volume/v3/services_client.py
+++ b/tempest/lib/services/volume/v3/services_client.py
@@ -18,12 +18,18 @@
 from oslo_serialization import jsonutils as json
 
 from tempest.lib.api_schema.response.volume import services as schema
+from tempest.lib.api_schema.response.volume.v3_7 import services as schemav37
 from tempest.lib.common import rest_client
+from tempest.lib.services.volume import base_client
 
 
-class ServicesClient(rest_client.RestClient):
+class ServicesClient(base_client.BaseClient):
     """Client class to send CRUD Volume Services API requests"""
 
+    schema_versions_info = [
+        {'min': None, 'max': '3.6', 'schema': schema},
+        {'min': '3.7', 'max': None, 'schema': schemav37}]
+
     def list_services(self, **params):
         """List all Cinder services.
 
@@ -37,6 +43,7 @@
 
         resp, body = self.get(url)
         body = json.loads(body)
+        schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.list_services, resp, body)
         return rest_client.ResponseBody(resp, body)
 
diff --git a/tools/verify-ipv6-only-deployments.sh b/tools/verify-ipv6-only-deployments.sh
index 2596395..bfb1403 100755
--- a/tools/verify-ipv6-only-deployments.sh
+++ b/tools/verify-ipv6-only-deployments.sh
@@ -1,92 +1,8 @@
 #!/bin/bash
-#
-#
-# NOTE(gmann): This script is used in 'devstack-tempest-ipv6' zuul job to verify that
-# services are deployed on IPv6 properly or not. This will capture if any devstck or devstack
-# plugins are missing the required setting to listen on IPv6 address. This is run as part of
-# run phase of zuul job and before test run. Child job of 'devstack-tempest-ipv6'
-# can expand the IPv6 verification specific to project by defining the new post-run script which
-# will run along with this base script.
-# If there are more common verification for IPv6 then we can always extent this script.
 
-# Keep track of the DevStack directory
-TOP_DIR=$(cd $(dirname "$0")/../../devstack && pwd)
-source $TOP_DIR/stackrc
-source $TOP_DIR/openrc admin admin
+# NOTE(yoctozepto): This scripts lives now in devstack where it belongs.
+# It is kept here for the legacy (dsvm) jobs which look for it in tempest still.
+# TODO: Drop it when no legacy jobs use the master tempest.
 
-function verify_devstack_ipv6_setting {
-    local _service_host=''
-    _service_host=$(echo $SERVICE_HOST | tr -d [])
-    local _host_ipv6=''
-    _host_ipv6=$(echo $HOST_IPV6 | tr -d [])
-    local _service_listen_address=''
-    _service_listen_address=$(echo $SERVICE_LISTEN_ADDRESS | tr -d [])
-    local _service_local_host=''
-    _service_local_host=$(echo $SERVICE_LOCAL_HOST | tr -d [])
-    if [[ "$SERVICE_IP_VERSION" != 6 ]]; then
-        echo $SERVICE_IP_VERSION "SERVICE_IP_VERSION is not set to 6 which is must for devstack to deploy services with IPv6 address."
-        exit 1
-    fi
-    is_service_host_ipv6=$(python3 -c 'import oslo_utils.netutils as nutils; print(nutils.is_valid_ipv6("'$_service_host'"))')
-    if [[ "$is_service_host_ipv6" != "True" ]]; then
-        echo $SERVICE_HOST "SERVICE_HOST is not ipv6 which means devstack cannot deploy services on IPv6 address."
-        exit 1
-    fi
-    is_host_ipv6=$(python3 -c 'import oslo_utils.netutils as nutils; print(nutils.is_valid_ipv6("'$_host_ipv6'"))')
-    if [[ "$is_host_ipv6" != "True" ]]; then
-        echo $HOST_IPV6 "HOST_IPV6 is not ipv6 which means devstack cannot deploy services on IPv6 address."
-        exit 1
-    fi
-    is_service_listen_address=$(python3 -c 'import oslo_utils.netutils as nutils; print(nutils.is_valid_ipv6("'$_service_listen_address'"))')
-    if [[ "$is_service_listen_address" != "True" ]]; then
-        echo $SERVICE_LISTEN_ADDRESS "SERVICE_LISTEN_ADDRESS is not ipv6 which means devstack cannot deploy services on IPv6 address."
-        exit 1
-    fi
-    is_service_local_host=$(python3 -c 'import oslo_utils.netutils as nutils; print(nutils.is_valid_ipv6("'$_service_local_host'"))')
-    if [[ "$is_service_local_host" != "True" ]]; then
-        echo $SERVICE_LOCAL_HOST "SERVICE_LOCAL_HOST is not ipv6 which means devstack cannot deploy services on IPv6 address."
-        exit 1
-    fi
-    echo "Devstack is properly configured with IPv6"
-    echo "SERVICE_IP_VERSION: " $SERVICE_IP_VERSION "HOST_IPV6: " $HOST_IPV6 "SERVICE_HOST: " $SERVICE_HOST "SERVICE_LISTEN_ADDRESS: " $SERVICE_LISTEN_ADDRESS "SERVICE_LOCAL_HOST: " $SERVICE_LOCAL_HOST
-}
-
-function sanity_check_system_ipv6_enabled {
-    system_ipv6_enabled=$(python3 -c 'import oslo_utils.netutils as nutils; print(nutils.is_ipv6_enabled())')
-    if [[ $system_ipv6_enabled != "True" ]]; then
-        echo "IPv6 is disabled in system"
-        exit 1
-    fi
-    echo "IPv6 is enabled in system"
-}
-
-function verify_service_listen_address_is_ipv6 {
-    local endpoints_verified=False
-    local all_ipv6=True
-    endpoints=$(openstack endpoint list -f value -c URL)
-    for endpoint in ${endpoints}; do
-        local endpoint_address=''
-        endpoint_address=$(echo "$endpoint" | awk -F/ '{print $3}' | awk -F] '{print $1}')
-        endpoint_address=$(echo $endpoint_address | tr -d [])
-        local is_endpoint_ipv6=''
-        is_endpoint_ipv6=$(python3 -c 'import oslo_utils.netutils as nutils; print(nutils.is_valid_ipv6("'$endpoint_address'"))')
-        if [[ "$is_endpoint_ipv6" != "True" ]]; then
-            all_ipv6=False
-            echo $endpoint ": This is not ipv6 endpoint which means corresponding service is not listening on IPv6 address."
-            continue
-        fi
-        endpoints_verified=True
-    done
-    if [[ "$all_ipv6" == "False"  ]] || [[ "$endpoints_verified" == "False" ]]; then
-        exit 1
-    fi
-    echo "All services deployed by devstack is on IPv6 endpoints"
-    echo $endpoints
-}
-
-#First thing to verify if system has IPv6 enabled or not
-sanity_check_system_ipv6_enabled
-#Verify whether devstack is configured properly with IPv6 setting
-verify_devstack_ipv6_setting
-#Get all registrfed endpoints by devstack in keystone and verify that each endpoints address is IPv6.
-verify_service_listen_address_is_ipv6
+DEVSTACK_DIR=$(cd $(dirname "$0")/../../devstack && pwd)
+$DEVSTACK_DIR/tools/verify-ipv6-only-deployments.sh
diff --git a/zuul.d/integrated-gate.yaml b/zuul.d/integrated-gate.yaml
index d931c55..622bbad 100644
--- a/zuul.d/integrated-gate.yaml
+++ b/zuul.d/integrated-gate.yaml
@@ -62,16 +62,12 @@
 - job:
     name: tempest-full-py3
     parent: devstack-tempest
-    # This job version is with swift disabled on py3
-    # as swift was not ready on py3 until stable/train.
-    branches:
-      - stable/pike
-      - stable/queens
-      - stable/rocky
-      - stable/stein
-      - stable/train
+    # This job version is with swift enabled on py3
+    # as swift is ready on py3 from stable/ussuri onwards.
+    branches: ^(?!stable/(ocata|pike|queens|rocky|stein|train)).*$
     description: |
-      Base integration test with Neutron networking, swift disabled, and py3.
+      Base integration test with Neutron networking, horizon, swift enable,
+      and py3.
       Former names for this job where:
         * legacy-tempest-dsvm-py35
         * gate-tempest-dsvm-py35
@@ -99,41 +95,10 @@
       devstack_services:
         # Enbale horizon so that we can run horizon test.
         horizon: true
-        s-account: false
-        s-container: false
-        s-object: false
-        s-proxy: false
-        # without Swift, c-bak cannot run (in the Gate at least)
-        # NOTE(mriedem): Disable the cinder-backup service from
-        # tempest-full-py3 since tempest-full-py3 is in the integrated-gate-py3
-        # project template but the backup tests do not really involve other
-        # services so they should be run in some more cinder-specific job,
-        # especially because the tests fail at a high rate (see bugs 1483434,
-        # 1813217, 1745168)
-        c-bak: false
         neutron-placement: true
         neutron-qos: true
 
 - job:
-    name: tempest-full-py3
-    parent: devstack-tempest
-    # This job version is with swift enabled on py3
-    # as swift is ready on py3 from stable/ussuri onwards.
-    branches: ^(?!stable/(ocata|pike|queens|rocky|stein|train)).*$
-    description: |
-      Base integration test with Neutron networking, swift enable, and py3.
-      Former names for this job where:
-        * legacy-tempest-dsvm-py35
-        * gate-tempest-dsvm-py35
-    vars:
-      tox_envlist: full
-      devstack_localrc:
-        USE_PYTHON3: true
-        FORCE_CONFIG_DRIVE: true
-        ENABLE_VOLUME_MULTIATTACH: true
-        GLANCE_USE_IMPORT_WORKFLOW: True
-
-- job:
     name: tempest-integrated-networking
     parent: devstack-tempest
     branches: ^(?!stable/ocata).*$
@@ -243,45 +208,6 @@
           USE_PYTHON3: False
 
 - job:
-    name: tempest-multinode-full
-    parent: tempest-multinode-full-base
-    nodeset: openstack-two-node-bionic
-    # This job runs on Bionic and on python2. This is for stable/stein and stable/train.
-    # This job is prepared to make sure all stable branches from stable/stein till stable/train
-    # will keep running on bionic. This can be removed once stable/train is EOL.
-    branches:
-      - stable/stein
-      - stable/train
-      - stable/ussuri
-    vars:
-      devstack_localrc:
-        USE_PYTHON3: False
-    group-vars:
-      subnode:
-        devstack_localrc:
-          USE_PYTHON3: False
-
-- job:
-    name: tempest-multinode-full
-    parent: tempest-multinode-full-base
-    nodeset: openstack-two-node-xenial
-    # This job runs on Xenial and this is for stable/pike, stable/queens
-    # and stable/rocky. This job is prepared to make sure all stable branches
-    # before stable/stein will keep running on xenial. This job can be
-    # removed once stable/rocky is EOL.
-    branches:
-      - stable/pike
-      - stable/queens
-      - stable/rocky
-    vars:
-      devstack_localrc:
-        USE_PYTHON3: False
-    group-vars:
-      subnode:
-        devstack_localrc:
-          USE_PYTHON3: False
-
-- job:
     name: tempest-multinode-full-py3
     parent: tempest-multinode-full
     vars:
@@ -348,62 +274,11 @@
           ENABLE_VOLUME_MULTIATTACH: true
 
 - job:
-    name: tempest-slow
-    parent: tempest-multinode-full
-    description: |
-      This multinode integration job will run all the tests tagged as slow.
-      It enables the lvm multibackend setup to cover few scenario tests.
-      This job will run only slow tests (API or Scenario) serially.
-
-      Former names for this job were:
-        * legacy-tempest-dsvm-neutron-scenario-multinode-lvm-multibackend
-        * tempest-scenario-multinode-lvm-multibackend
-    timeout: 10800
-    branches:
-      - stable/pike
-      - stable/queens
-      - stable/rocky
-    vars:
-      tox_envlist: slow-serial
-      devstack_localrc:
-        CINDER_ENABLED_BACKENDS: lvm:lvmdriver-1,lvm:lvmdriver-2
-        ENABLE_VOLUME_MULTIATTACH: true
-        # to avoid https://bugs.launchpad.net/neutron/+bug/1914037
-        # as we couldn't backport the fix to rocky and older releases
-        IPV6_PUBLIC_RANGE: 2001:db8:0:10::/64
-        IPV6_PUBLIC_NETWORK_GATEWAY: 2001:db8:0:10::2
-        IPV6_ROUTER_GW_IP: 2001:db8:0:10::1
-      devstack_plugins:
-        neutron: https://opendev.org/openstack/neutron
-      devstack_services:
-        neutron-placement: true
-        neutron-qos: true
-      tempest_concurrency: 2
-    group-vars:
-      # NOTE(mriedem): The ENABLE_VOLUME_MULTIATTACH variable is used on both
-      # the controller and subnode prior to Rocky so we have to make sure the
-      # variable is set in both locations.
-      subnode:
-        devstack_localrc:
-          ENABLE_VOLUME_MULTIATTACH: true
-
-- job:
     name: tempest-slow-py3
     parent: tempest-slow
-    vars:
-      devstack_localrc:
-        USE_PYTHON3: true
-      devstack_services:
-        s-account: false
-        s-container: false
-        s-object: false
-        s-proxy: false
-        # without Swift, c-bak cannot run (in the Gate at least)
-        c-bak: false
-    group-vars:
-      subnode:
-        devstack_localrc:
-          USE_PYTHON3: true
+    # This job version is with swift enabled on py3
+    # as swift is ready on py3 from stable/ussuri onwards.
+    branches: ^(?!stable/(ocata|pike|queens|rocky|stein|train)).*$
 
 - job:
     name: tempest-cinder-v2-api
diff --git a/zuul.d/stable-jobs.yaml b/zuul.d/stable-jobs.yaml
index 2f0df66..852bafb 100644
--- a/zuul.d/stable-jobs.yaml
+++ b/zuul.d/stable-jobs.yaml
@@ -20,3 +20,162 @@
     parent: tempest-full-py3
     nodeset: openstack-single-node-bionic
     override-checkout: stable/train
+
+- job:
+    name: tempest-full-py3
+    parent: devstack-tempest
+    # This job version is with swift disabled on py3
+    # as swift was not ready on py3 until stable/train.
+    branches:
+      - stable/pike
+      - stable/queens
+      - stable/rocky
+      - stable/stein
+      - stable/train
+    description: |
+      Base integration test with Neutron networking, swift disabled, and py3.
+      Former names for this job where:
+        * legacy-tempest-dsvm-py35
+        * gate-tempest-dsvm-py35
+    required-projects:
+      - openstack/horizon
+    vars:
+      tox_envlist: full
+      devstack_localrc:
+        USE_PYTHON3: true
+        FORCE_CONFIG_DRIVE: true
+        ENABLE_VOLUME_MULTIATTACH: true
+        GLANCE_USE_IMPORT_WORKFLOW: True
+      devstack_plugins:
+        neutron: https://opendev.org/openstack/neutron
+      devstack_local_conf:
+        post-config:
+          "/$NEUTRON_CORE_PLUGIN_CONF":
+            ovs:
+              bridge_mappings: public:br-ex
+              resource_provider_bandwidths: br-ex:1000000:1000000
+        test-config:
+          $TEMPEST_CONFIG:
+            network-feature-enabled:
+              qos_placement_physnet: public
+      devstack_services:
+        # Enbale horizon so that we can run horizon test.
+        horizon: true
+        s-account: false
+        s-container: false
+        s-object: false
+        s-proxy: false
+        # without Swift, c-bak cannot run (in the Gate at least)
+        # NOTE(mriedem): Disable the cinder-backup service from
+        # tempest-full-py3 since tempest-full-py3 is in the integrated-gate-py3
+        # project template but the backup tests do not really involve other
+        # services so they should be run in some more cinder-specific job,
+        # especially because the tests fail at a high rate (see bugs 1483434,
+        # 1813217, 1745168)
+        c-bak: false
+        neutron-placement: true
+        neutron-qos: true
+
+- job:
+    name: tempest-multinode-full
+    parent: tempest-multinode-full-base
+    nodeset: openstack-two-node-bionic
+    # This job runs on Bionic and on python2. This is for stable/stein and stable/train.
+    # This job is prepared to make sure all stable branches from stable/stein till stable/train
+    # will keep running on bionic. This can be removed once stable/train is EOL.
+    branches:
+      - stable/stein
+      - stable/train
+      - stable/ussuri
+    vars:
+      devstack_localrc:
+        USE_PYTHON3: False
+    group-vars:
+      subnode:
+        devstack_localrc:
+          USE_PYTHON3: False
+
+- job:
+    name: tempest-multinode-full
+    parent: tempest-multinode-full-base
+    nodeset: openstack-two-node-xenial
+    # This job runs on Xenial and this is for stable/pike, stable/queens
+    # and stable/rocky. This job is prepared to make sure all stable branches
+    # before stable/stein will keep running on xenial. This job can be
+    # removed once stable/rocky is EOL.
+    branches:
+      - stable/pike
+      - stable/queens
+      - stable/rocky
+    vars:
+      devstack_localrc:
+        USE_PYTHON3: False
+    group-vars:
+      subnode:
+        devstack_localrc:
+          USE_PYTHON3: False
+
+- job:
+    name: tempest-slow
+    parent: tempest-multinode-full
+    description: |
+      This multinode integration job will run all the tests tagged as slow.
+      It enables the lvm multibackend setup to cover few scenario tests.
+      This job will run only slow tests (API or Scenario) serially.
+      Former names for this job were:
+        * legacy-tempest-dsvm-neutron-scenario-multinode-lvm-multibackend
+        * tempest-scenario-multinode-lvm-multibackend
+    timeout: 10800
+    branches:
+      - stable/pike
+      - stable/queens
+      - stable/rocky
+    vars:
+      tox_envlist: slow-serial
+      devstack_localrc:
+        CINDER_ENABLED_BACKENDS: lvm:lvmdriver-1,lvm:lvmdriver-2
+        ENABLE_VOLUME_MULTIATTACH: true
+        # to avoid https://bugs.launchpad.net/neutron/+bug/1914037
+        # as we couldn't backport the fix to rocky and older releases
+        IPV6_PUBLIC_RANGE: 2001:db8:0:10::/64
+        IPV6_PUBLIC_NETWORK_GATEWAY: 2001:db8:0:10::2
+        IPV6_ROUTER_GW_IP: 2001:db8:0:10::1
+      devstack_plugins:
+        neutron: https://opendev.org/openstack/neutron
+      devstack_services:
+        neutron-placement: true
+        neutron-qos: true
+      tempest_concurrency: 2
+    group-vars:
+      # NOTE(mriedem): The ENABLE_VOLUME_MULTIATTACH variable is used on both
+      # the controller and subnode prior to Rocky so we have to make sure the
+      # variable is set in both locations.
+      subnode:
+        devstack_localrc:
+          ENABLE_VOLUME_MULTIATTACH: true
+
+- job:
+    name: tempest-slow-py3
+    parent: tempest-slow
+    # This job version is with swift disabled on py3
+    # as swift was not ready on py3 until stable/train.
+    branches:
+      - stable/pike
+      - stable/queens
+      - stable/rocky
+      - stable/stein
+      - stable/train
+    vars:
+      devstack_localrc:
+        USE_PYTHON3: true
+      devstack_services:
+        s-account: false
+        s-container: false
+        s-object: false
+        s-proxy: false
+        # without Swift, c-bak cannot run (in the Gate at least)
+        c-bak: false
+    group-vars:
+      subnode:
+        devstack_localrc:
+          USE_PYTHON3: true