Merge "waiters: Add wait_for_volume_attachment_remove"
diff --git a/.zuul.yaml b/.zuul.yaml
index 0035f7c..f749b74 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -603,8 +603,6 @@
       - integrated-gate
       - integrated-gate-py3
       - openstack-cover-jobs
-      - openstack-python-jobs
-      - openstack-python35-jobs
       - openstack-python3-train-jobs
       - publish-openstack-docs-pti
       - release-notes-jobs-python3
@@ -651,8 +649,10 @@
             irrelevant-files: *tempest-irrelevant-files
         - tempest-full-rocky:
             irrelevant-files: *tempest-irrelevant-files
+            voting: false
         - tempest-full-rocky-py3:
             irrelevant-files: *tempest-irrelevant-files
+            voting: false
         - tempest-multinode-full:
             irrelevant-files: *tempest-irrelevant-files
         - tempest-multinode-full-py3:
diff --git a/doc/source/supported_version.rst b/doc/source/supported_version.rst
index 60e7b97..a97ec5b 100644
--- a/doc/source/supported_version.rst
+++ b/doc/source/supported_version.rst
@@ -32,6 +32,5 @@
 Tempest master supports the below python versions:
 
 * Python 2.7
-* Python 3.5
 * Python 3.6
 * Python 3.7
diff --git a/releasenotes/notes/change-default-region-for-placement-to-empty-string-394f1132c28345bb.yaml b/releasenotes/notes/change-default-region-for-placement-to-empty-string-394f1132c28345bb.yaml
new file mode 100644
index 0000000..a28e4e2
--- /dev/null
+++ b/releasenotes/notes/change-default-region-for-placement-to-empty-string-394f1132c28345bb.yaml
@@ -0,0 +1,13 @@
+---
+upgrade:
+  - |
+     Default value of config option ``CONF.placement.region`` is updated
+     from ``RegionOne`` to empty string.
+
+     As per tempest design, if tempest conf is not having any region for
+     a service then identity region should be used. In case of placement
+     the default value is "RegionOne" which is considered as placement
+     region if region missing in tempest conf. In order to have identity
+     region to be used as default we need to change to empty string for
+     placement service. Empty string can be seen being used in other
+     services like volume, image etc.
diff --git a/releasenotes/notes/drop-py-3-5-support-76ca78f1a650fcad.yaml b/releasenotes/notes/drop-py-3-5-support-76ca78f1a650fcad.yaml
new file mode 100644
index 0000000..99ef31e
--- /dev/null
+++ b/releasenotes/notes/drop-py-3-5-support-76ca78f1a650fcad.yaml
@@ -0,0 +1,8 @@
+---
+prelude: >
+    Remove the support of python3.5.
+    Tempest, its plugins dependencies in ussuri cycle
+    are python-requires>=py3.6 which makes distro not
+    having python 3.6 to do hack to install py3.6 etc.
+    It time to drop the py3.5 from Tempest. Last supported
+    version of Tempest for py3.5 is 23.0.0.
diff --git a/roles/run-tempest/README.rst b/roles/run-tempest/README.rst
index d4b253a..1f7fb70 100644
--- a/roles/run-tempest/README.rst
+++ b/roles/run-tempest/README.rst
@@ -72,3 +72,16 @@
    :default: ''
 
    The timeout (in seconds) for each test.
+
+.. zuul:rolevar:: stable_constraints_file
+   :default: ''
+
+   Upper constraints file to be used for stable branch till stable/rocky.
+
+.. zuul:rolevar:: tempest_tox_environment
+   :default: ''
+
+   Environment variable to set for run-tempst task.
+
+   Env variables set in this variable will be combined with some more
+   defaults env variable set at runtime.
diff --git a/roles/run-tempest/defaults/main.yaml b/roles/run-tempest/defaults/main.yaml
index 79df3e1..5867b6c 100644
--- a/roles/run-tempest/defaults/main.yaml
+++ b/roles/run-tempest/defaults/main.yaml
@@ -4,3 +4,6 @@
 tempest_black_regex: ''
 tox_extra_args: ''
 tempest_test_timeout: ''
+stable_constraints_file: "{{ devstack_base_dir }}/requirements/upper-constraints.txt"
+target_branch: "{{ zuul.branch }}"
+tempest_tox_environment: {}
diff --git a/roles/run-tempest/tasks/main.yaml b/roles/run-tempest/tasks/main.yaml
index 24bd4db..8686f9a 100644
--- a/roles/run-tempest/tasks/main.yaml
+++ b/roles/run-tempest/tasks/main.yaml
@@ -20,6 +20,21 @@
     default_concurrency: "{{ num_cores|int // 2 }}"
   when: num_cores|int > 3
 
+- name: Override target branch
+  set_fact:
+    target_branch: "{{ zuul.override_checkout }}"
+  when: zuul.override_checkout is defined
+
+- name: Use stable branch upper-constraints till stable/rocky
+  set_fact:
+    tempest_tox_environment: "{{ tempest_tox_environment | combine({'UPPER_CONSTRAINTS_FILE': stable_constraints_file}) }}"
+  when: target_branch in ["stable/ocata", "stable/pike", "stable/queens", "stable/rocky"]
+
+- name: Set OS_TEST_TIMEOUT if requested
+  set_fact:
+    tempest_tox_environment: "{{ tempest_tox_environment | combine({'OS_TEST_TIMEOUT': tempest_test_timeout}) }}"
+  when: tempest_test_timeout != ''
+
 - when:
     - tempest_test_blacklist is defined
   block:
@@ -42,4 +57,4 @@
     chdir: "{{devstack_base_dir}}/tempest"
   become: true
   become_user: tempest
-  environment: '{{ {"OS_TEST_TIMEOUT": tempest_test_timeout} if tempest_test_timeout else {} }}'
+  environment: "{{ tempest_tox_environment }}"
diff --git a/setup.cfg b/setup.cfg
index 1e9b8e9..dd30069 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -16,7 +16,6 @@
     Programming Language :: Python :: 2
     Programming Language :: Python :: 2.7
     Programming Language :: Python :: 3
-    Programming Language :: Python :: 3.5
     Programming Language :: Python :: 3.6
     Programming Language :: Python :: 3.7
 
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 7c2d9d2..dd6d593 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -52,12 +52,15 @@
         super(BaseV2ComputeTest, cls).skip_checks()
         if not CONF.service_available.nova:
             raise cls.skipException("Nova is not available")
-        cfg_min_version = CONF.compute.min_microversion
-        cfg_max_version = CONF.compute.max_microversion
-        api_version_utils.check_skip_with_microversion(cls.min_microversion,
-                                                       cls.max_microversion,
-                                                       cfg_min_version,
-                                                       cfg_max_version)
+        api_version_utils.check_skip_with_microversion(
+            cls.min_microversion, cls.max_microversion,
+            CONF.compute.min_microversion, CONF.compute.max_microversion)
+        api_version_utils.check_skip_with_microversion(
+            cls.volume_min_microversion, cls.volume_max_microversion,
+            CONF.volume.min_microversion, CONF.volume.max_microversion)
+        api_version_utils.check_skip_with_microversion(
+            cls.placement_min_microversion, cls.placement_max_microversion,
+            CONF.placement.min_microversion, CONF.placement.max_microversion)
 
     @classmethod
     def setup_credentials(cls):
@@ -151,6 +154,14 @@
             api_version_utils.select_request_microversion(
                 cls.min_microversion,
                 CONF.compute.min_microversion))
+        cls.volume_request_microversion = (
+            api_version_utils.select_request_microversion(
+                cls.volume_min_microversion,
+                CONF.volume.min_microversion))
+        cls.placement_request_microversion = (
+            api_version_utils.select_request_microversion(
+                cls.placement_min_microversion,
+                CONF.placement.min_microversion))
         cls.build_interval = CONF.compute.build_interval
         cls.build_timeout = CONF.compute.build_timeout
         cls.image_ref = CONF.compute.image_ref
@@ -476,7 +487,9 @@
     def setUp(self):
         super(BaseV2ComputeTest, self).setUp()
         self.useFixture(api_microversion_fixture.APIMicroversionFixture(
-            compute_microversion=self.request_microversion))
+            compute_microversion=self.request_microversion,
+            volume_microversion=self.volume_request_microversion,
+            placement_microversion=self.placement_request_microversion))
 
     @classmethod
     def create_volume(cls, image_ref=None, **kwargs):
diff --git a/tempest/config.py b/tempest/config.py
index 32cebc5..4e08a11 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -390,7 +390,7 @@
                default='placement',
                help="Catalog type of the Placement service."),
     cfg.StrOpt('region',
-               default='RegionOne',
+               default='',
                help="The placement region name to use. If empty, the value "
                     "of [identity]/region is used instead. If no such region "
                     "is found in the service catalog, the first region found "
diff --git a/tempest/lib/common/api_version_utils.py b/tempest/lib/common/api_version_utils.py
index d29362d..80dbc1d 100644
--- a/tempest/lib/common/api_version_utils.py
+++ b/tempest/lib/common/api_version_utils.py
@@ -32,6 +32,10 @@
     # (min_microversion, max_microversion) on each test class if necessary.
     min_microversion = None
     max_microversion = LATEST_MICROVERSION
+    volume_min_microversion = None
+    volume_max_microversion = LATEST_MICROVERSION
+    placement_min_microversion = None
+    placement_max_microversion = LATEST_MICROVERSION
 
 
 def check_skip_with_microversion(test_min_version, test_max_version,
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index db8da84..cb7acbf 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -810,6 +810,42 @@
         server_details = cls.os_admin.servers_client.show_server(server_id)
         return server_details['server']['OS-EXT-SRV-ATTR:host']
 
+    def _get_bdm(self, source_id, source_type, delete_on_termination=False):
+        bd_map_v2 = [{
+            'uuid': source_id,
+            'source_type': source_type,
+            'destination_type': 'volume',
+            'boot_index': 0,
+            'delete_on_termination': delete_on_termination}]
+        return {'block_device_mapping_v2': bd_map_v2}
+
+    def boot_instance_from_resource(self, source_id,
+                                    source_type,
+                                    keypair=None,
+                                    security_group=None,
+                                    delete_on_termination=False,
+                                    name=None):
+        create_kwargs = dict()
+        if keypair:
+            create_kwargs['key_name'] = keypair['name']
+        if security_group:
+            create_kwargs['security_groups'] = [
+                {'name': security_group['name']}]
+        create_kwargs.update(self._get_bdm(
+            source_id,
+            source_type,
+            delete_on_termination=delete_on_termination))
+        if name:
+            create_kwargs['name'] = name
+
+        return self.create_server(image_id='', **create_kwargs)
+
+    def create_volume_from_image(self):
+        img_uuid = CONF.compute.image_ref
+        vol_name = data_utils.rand_name(
+            self.__class__.__name__ + '-volume-origin')
+        return self.create_volume(name=vol_name, imageRef=img_uuid)
+
 
 class NetworkScenarioTest(ScenarioTest):
     """Base class for network scenario tests.
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 6ed7e30..ec44b13 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -31,42 +31,6 @@
     # breathing room to get through deletes in the time allotted.
     TIMEOUT_SCALING_FACTOR = 2
 
-    def _create_volume_from_image(self):
-        img_uuid = CONF.compute.image_ref
-        vol_name = data_utils.rand_name(
-            self.__class__.__name__ + '-volume-origin')
-        return self.create_volume(name=vol_name, imageRef=img_uuid)
-
-    def _get_bdm(self, source_id, source_type, delete_on_termination=False):
-        bd_map_v2 = [{
-            'uuid': source_id,
-            'source_type': source_type,
-            'destination_type': 'volume',
-            'boot_index': 0,
-            'delete_on_termination': delete_on_termination}]
-        return {'block_device_mapping_v2': bd_map_v2}
-
-    def _boot_instance_from_resource(self, source_id,
-                                     source_type,
-                                     keypair=None,
-                                     security_group=None,
-                                     delete_on_termination=False,
-                                     name=None):
-        create_kwargs = dict()
-        if keypair:
-            create_kwargs['key_name'] = keypair['name']
-        if security_group:
-            create_kwargs['security_groups'] = [
-                {'name': security_group['name']}]
-        create_kwargs.update(self._get_bdm(
-            source_id,
-            source_type,
-            delete_on_termination=delete_on_termination))
-        if name:
-            create_kwargs['name'] = name
-
-        return self.create_server(image_id='', **create_kwargs)
-
     def _delete_server(self, server):
         self.servers_client.delete_server(server['id'])
         waiters.wait_for_server_termination(self.servers_client, server['id'])
@@ -104,8 +68,8 @@
 
         # create an instance from volume
         LOG.info("Booting instance 1 from volume")
-        volume_origin = self._create_volume_from_image()
-        instance_1st = self._boot_instance_from_resource(
+        volume_origin = self.create_volume_from_image()
+        instance_1st = self.boot_instance_from_resource(
             source_id=volume_origin['id'],
             source_type='volume',
             keypair=keypair,
@@ -124,7 +88,7 @@
         self._delete_server(instance_1st)
 
         # create a 2nd instance from volume
-        instance_2nd = self._boot_instance_from_resource(
+        instance_2nd = self.boot_instance_from_resource(
             source_id=volume_origin['id'],
             source_type='volume',
             keypair=keypair,
@@ -149,10 +113,10 @@
                                     size=snapshot['size'])
         LOG.info("Booting third instance from snapshot")
         server_from_snapshot = (
-            self._boot_instance_from_resource(source_id=volume['id'],
-                                              source_type='volume',
-                                              keypair=keypair,
-                                              security_group=security_group))
+            self.boot_instance_from_resource(source_id=volume['id'],
+                                             source_type='volume',
+                                             keypair=keypair,
+                                             security_group=security_group))
         LOG.info("Booted third instance %s", server_from_snapshot)
 
         # check the content of written file
@@ -171,13 +135,13 @@
     @utils.services('compute', 'image', 'volume')
     def test_create_server_from_volume_snapshot(self):
         # Create a volume from an image
-        boot_volume = self._create_volume_from_image()
+        boot_volume = self.create_volume_from_image()
 
         # Create a snapshot
         boot_snapshot = self.create_volume_snapshot(boot_volume['id'])
 
         # Create a server from a volume snapshot
-        server = self._boot_instance_from_resource(
+        server = self.boot_instance_from_resource(
             source_id=boot_snapshot['id'],
             source_type='snapshot',
             delete_on_termination=True)
@@ -209,10 +173,10 @@
     @utils.services('compute', 'volume', 'image')
     def test_image_defined_boot_from_volume(self):
         # create an instance from image-backed volume
-        volume_origin = self._create_volume_from_image()
+        volume_origin = self.create_volume_from_image()
         name = data_utils.rand_name(self.__class__.__name__ +
                                     '-volume-backed-server')
-        instance1 = self._boot_instance_from_resource(
+        instance1 = self.boot_instance_from_resource(
             source_id=volume_origin['id'],
             source_type='volume',
             delete_on_termination=True,
@@ -288,7 +252,7 @@
         self.volumes_client.set_bootable_volume(volume['id'], bootable=True)
 
         # Boot a server from the encrypted volume
-        server = self._boot_instance_from_resource(
+        server = self.boot_instance_from_resource(
             source_id=volume['id'],
             source_type='volume',
             delete_on_termination=False)
diff --git a/tox.ini b/tox.ini
index ff31fe8..401bbfe 100644
--- a/tox.ini
+++ b/tox.ini
@@ -5,7 +5,7 @@
 ignore_basepython_conflict = True
 
 [tempestenv]
-basepython = python3.6
+basepython = python3
 sitepackages = False
 setenv =
     VIRTUAL_ENV={envdir}