Merge "Fix clean up for test_access_rules tests"
diff --git a/tempest/api/compute/admin/test_assisted_volume_snapshots.py b/tempest/api/compute/admin/test_assisted_volume_snapshots.py
index 5e30444..b7be796 100644
--- a/tempest/api/compute/admin/test_assisted_volume_snapshots.py
+++ b/tempest/api/compute/admin/test_assisted_volume_snapshots.py
@@ -26,6 +26,13 @@
 
     create_default_network = True
 
+    # TODO(gmann): Remove the admin access to service user
+    # once nova change the default of this API to service
+    # role. To merge the nova changing the policy default
+    # we need to use token with admin as well as service
+    # role and later we can use only service token.
+    credentials = ['primary', 'admin', ['service_user', 'admin', 'service']]
+
     @classmethod
     def skip_checks(cls):
         super(VolumesAssistedSnapshotsTest, cls).skip_checks()
@@ -37,7 +44,7 @@
     def setup_clients(cls):
         super(VolumesAssistedSnapshotsTest, cls).setup_clients()
         cls.assisted_v_client = (
-            cls.os_admin.assisted_volume_snapshots_client)
+            cls.os_service_user.assisted_volume_snapshots_client)
         cls.volumes_client = cls.os_admin.volumes_client_latest
         cls.servers_client = cls.os_admin.servers_client
 
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index a02820a..5384fe1 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -258,7 +258,6 @@
         port = self.ports_client.show_port(port_id)['port']
         return port['status'] == 'ACTIVE'
 
-    @decorators.unstable_test(bug='2027605')
     @decorators.attr(type='multinode')
     @decorators.idempotent_id('0022c12e-a482-42b0-be2d-396b5f0cffe3')
     @utils.requires_ext(service='network', extension='trunk')
diff --git a/tempest/api/compute/admin/test_server_external_events.py b/tempest/api/compute/admin/test_server_external_events.py
index 1c5c295..d867a39 100644
--- a/tempest/api/compute/admin/test_server_external_events.py
+++ b/tempest/api/compute/admin/test_server_external_events.py
@@ -19,6 +19,13 @@
 class ServerExternalEventsTest(base.BaseV2ComputeAdminTest):
     """Test server external events test"""
 
+    # TODO(gmann): Remove the admin access to service user
+    # once nova change the default of this API to service
+    # role. To merge the nova changing the policy default
+    # we need to use token with admin as well as service
+    # role and later we can use only service token.
+    credentials = ['primary', 'admin', ['service_user', 'admin', 'service']]
+
     @decorators.idempotent_id('6bbf4723-61d2-4372-af55-7ba27f1c9ba6')
     def test_create_server_external_events(self):
         """Test create a server and add some external events"""
@@ -29,7 +36,7 @@
                 "server_uuid": server_id,
             }
         ]
-        client = self.os_admin.server_external_events_client
+        client = self.os_service_user.server_external_events_client
         events_resp = client.create_server_external_events(
             events=events)['events'][0]
         self.assertEqual(server_id, events_resp['server_uuid'])
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 58ad9d4..8adbe7d 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -18,6 +18,7 @@
 from oslo_log import log
 
 from tempest.common import custom_matchers
+from tempest.common import object_storage
 from tempest.common import waiters
 from tempest import config
 from tempest.lib.common.utils import data_utils
@@ -28,51 +29,6 @@
 LOG = log.getLogger(__name__)
 
 
-def delete_containers(containers, container_client, object_client):
-    """Remove containers and all objects in them.
-
-    The containers should be visible from the container_client given.
-    Will not throw any error if the containers don't exist.
-
-    :param containers: List of containers(or string of a container)
-                       to be deleted
-    :param container_client: Client to be used to delete containers
-    :param object_client: Client to be used to delete objects
-    """
-    if isinstance(containers, str):
-        containers = [containers]
-
-    for cont in containers:
-        try:
-            delete_objects(cont, container_client, object_client)
-            container_client.delete_container(cont)
-            container_client.wait_for_resource_deletion(cont)
-        except lib_exc.NotFound:
-            LOG.warning(f"Container {cont} wasn't deleted as it wasn't found.")
-
-
-def delete_objects(container, container_client, object_client):
-    """Remove all objects from container.
-
-    Will not throw any error if the objects do not exist
-
-    :param container: Name of the container that contains the objects to be
-                      deleted
-    :param container_client: Client to be used to list objects in
-                             the container
-    :param object_client: Client to be used to delete objects
-    """
-    params = {'limit': 9999, 'format': 'json'}
-    _, objlist = container_client.list_container_objects(container, params)
-
-    for obj in objlist:
-        try:
-            object_client.delete_object(container, obj['name'])
-            object_client.wait_for_resource_deletion(obj['name'], container)
-        except lib_exc.NotFound:
-            LOG.warning(f"Object {obj} wasn't deleted as it wasn't found.")
-
-
 class BaseObjectTest(tempest.test.BaseTestCase):
 
     credentials = [['operator', CONF.object_storage.operator_role]]
@@ -160,7 +116,8 @@
             container_client = cls.container_client
         if object_client is None:
             object_client = cls.object_client
-        delete_containers(cls.containers, container_client, object_client)
+        object_storage.delete_containers(cls.containers, container_client,
+                                         object_client)
 
     def assertHeaders(self, resp, target, method):
         """Check the existence and the format of response headers"""
diff --git a/tempest/api/object_storage/test_account_bulk.py b/tempest/api/object_storage/test_account_bulk.py
index 687fe57..0ecae85 100644
--- a/tempest/api/object_storage/test_account_bulk.py
+++ b/tempest/api/object_storage/test_account_bulk.py
@@ -16,6 +16,7 @@
 import tempfile
 
 from tempest.api.object_storage import base
+from tempest.common import object_storage
 from tempest.common import utils
 from tempest.lib import decorators
 
@@ -30,8 +31,9 @@
     def tearDown(self):
         # NOTE(andreaf) BulkTests needs to cleanup containers after each
         # test is executed.
-        base.delete_containers(self.containers, self.container_client,
-                               self.object_client)
+        object_storage.delete_containers(self.containers,
+                                         self.container_client,
+                                         self.object_client)
         super(BulkTest, self).tearDown()
 
     def _create_archive(self):
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index 4966ec4..b7a413e 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -18,6 +18,7 @@
 
 from tempest.api.object_storage import base
 from tempest.common import custom_matchers
+from tempest.common import object_storage
 from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
@@ -43,7 +44,7 @@
         for i in range(ord('a'), ord('f') + 1):
             name = data_utils.rand_name(name='%s-' % bytes((i,)))
             cls.container_client.update_container(name)
-            cls.addClassResourceCleanup(base.delete_containers,
+            cls.addClassResourceCleanup(object_storage.delete_containers,
                                         [name],
                                         cls.container_client,
                                         cls.object_client)
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index b31ff76..9b1d3c7 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -19,6 +19,7 @@
 import testtools
 
 from tempest.api.object_storage import base
+from tempest.common import object_storage
 from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
@@ -74,7 +75,7 @@
             (cls.container_client_alt, cls.object_client_alt)
         for cont_name, client in cls.clients.items():
             client[0].create_container(cont_name)
-            cls.addClassResourceCleanup(base.delete_containers,
+            cls.addClassResourceCleanup(object_storage.delete_containers,
                                         cont_name,
                                         client[0],
                                         client[1])
diff --git a/tempest/api/object_storage/test_object_version.py b/tempest/api/object_storage/test_object_version.py
index b64b172..2a1f63e 100644
--- a/tempest/api/object_storage/test_object_version.py
+++ b/tempest/api/object_storage/test_object_version.py
@@ -16,6 +16,7 @@
 import testtools
 
 from tempest.api.object_storage import base
+from tempest.common import object_storage
 from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
@@ -53,7 +54,7 @@
         # create container
         vers_container_name = data_utils.rand_name(name='TestVersionContainer')
         resp, _ = self.container_client.update_container(vers_container_name)
-        self.addCleanup(base.delete_containers,
+        self.addCleanup(object_storage.delete_containers,
                         [vers_container_name],
                         self.container_client,
                         self.object_client)
@@ -65,7 +66,7 @@
         resp, _ = self.container_client.update_container(
             base_container_name,
             **headers)
-        self.addCleanup(base.delete_containers,
+        self.addCleanup(object_storage.delete_containers,
                         [base_container_name],
                         self.container_client,
                         self.object_client)
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index ad8f573..68bf725 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from tempest.common import compute
+from tempest.common import object_storage
 from tempest.common import waiters
 from tempest import config
 from tempest.lib.common import api_version_utils
@@ -68,6 +69,8 @@
         if CONF.service_available.glance:
             cls.images_client = cls.os_primary.image_client_v2
 
+        cls.container_client = cls.os_primary.container_client
+        cls.object_client = cls.os_primary.object_client
         cls.backups_client = cls.os_primary.backups_client_latest
         cls.volumes_client = cls.os_primary.volumes_client_latest
         cls.messages_client = cls.os_primary.volume_messages_client_latest
@@ -174,16 +177,31 @@
                                                 snapshot['id'], 'available')
         return snapshot
 
-    def create_backup(self, volume_id, backup_client=None, **kwargs):
+    def create_backup(self, volume_id, backup_client=None, object_client=None,
+                      container_client=None, **kwargs):
         """Wrapper utility that returns a test backup."""
         if backup_client is None:
             backup_client = self.backups_client
+        if container_client is None:
+            container_client = self.container_client
+        if object_client is None:
+            object_client = self.object_client
         if 'name' not in kwargs:
             name = data_utils.rand_name(self.__class__.__name__ + '-Backup')
             kwargs['name'] = name
+        if 'container' not in kwargs:
+            cont_name = self.__class__.__name__ + '-backup-container'
+            cont = data_utils.rand_name(cont_name)
+            kwargs['container'] = cont
 
         backup = backup_client.create_backup(
             volume_id=volume_id, **kwargs)['backup']
+
+        if CONF.service_available.swift:
+            self.addCleanup(object_storage.delete_containers,
+                            kwargs['container'], container_client,
+                            object_client)
+
         # addCleanup uses list pop to cleanup. Wait should be added before
         # the backup is deleted
         self.addCleanup(backup_client.wait_for_resource_deletion,
diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
index 89ff497..2ae2bea 100644
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -77,11 +77,13 @@
         # Create a backup
         backup_name = data_utils.rand_name(
             self.__class__.__name__ + '-Backup')
+        container_name = data_utils.rand_name(
+            self.__class__.__name__ + '-Backup-container')
         description = data_utils.rand_name("volume-backup-description")
         backup = self.create_backup(volume_id=volume['id'],
                                     name=backup_name,
                                     description=description,
-                                    container='container')
+                                    container=container_name)
         self.assertEqual(backup_name, backup['name'])
         waiters.wait_for_volume_resource_status(self.volumes_client,
                                                 volume['id'], 'available')
@@ -90,7 +92,7 @@
         backup = self.backups_client.show_backup(backup['id'])['backup']
         self.assertEqual(backup_name, backup['name'])
         self.assertEqual(description, backup['description'])
-        self.assertEqual('container', backup['container'])
+        self.assertEqual(container_name, backup['container'])
 
         # Get all backups with detail
         backups = self.backups_client.list_backups(detail=True)['backups']
diff --git a/tempest/common/object_storage.py b/tempest/common/object_storage.py
new file mode 100644
index 0000000..7ffdc42
--- /dev/null
+++ b/tempest/common/object_storage.py
@@ -0,0 +1,64 @@
+#    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.
+
+from oslo_log import log
+
+from tempest import config
+from tempest.lib import exceptions as lib_exc
+
+CONF = config.CONF
+LOG = log.getLogger(__name__)
+
+
+def delete_containers(containers, container_client, object_client):
+    """Remove containers and all objects in them.
+
+    The containers should be visible from the container_client given.
+    Will not throw any error if the containers don't exist.
+
+    :param containers: List of containers(or string of a container)
+                       to be deleted
+    :param container_client: Client to be used to delete containers
+    :param object_client: Client to be used to delete objects
+    """
+    if isinstance(containers, str):
+        containers = [containers]
+
+    for cont in containers:
+        try:
+            delete_objects(cont, container_client, object_client)
+            container_client.delete_container(cont)
+            container_client.wait_for_resource_deletion(cont)
+        except lib_exc.NotFound:
+            LOG.warning(f"Container {cont} wasn't deleted as it wasn't found.")
+
+
+def delete_objects(container, container_client, object_client):
+    """Remove all objects from container.
+
+    Will not throw any error if the objects do not exist
+
+    :param container: Name of the container that contains the objects to be
+                      deleted
+    :param container_client: Client to be used to list objects in
+                             the container
+    :param object_client: Client to be used to delete objects
+    """
+    params = {'limit': 9999, 'format': 'json'}
+    _, objlist = container_client.list_container_objects(container, params)
+
+    for obj in objlist:
+        try:
+            object_client.delete_object(container, obj['name'])
+            object_client.wait_for_resource_deletion(obj['name'], container)
+        except lib_exc.NotFound:
+            LOG.warning(f"Object {obj} wasn't deleted as it wasn't found.")
diff --git a/tempest/lib/common/utils/test_utils.py b/tempest/lib/common/utils/test_utils.py
index 4cf8351..c79db15 100644
--- a/tempest/lib/common/utils/test_utils.py
+++ b/tempest/lib/common/utils/test_utils.py
@@ -93,6 +93,7 @@
             if attempt >= 3:
                 raise
             LOG.warning('Got ServerFault while running %s, retrying...', func)
+            time.sleep(1)
 
 
 def call_until_true(func, duration, sleep_for, *args, **kwargs):
diff --git a/tox.ini b/tox.ini
index 47ef5eb..fc882cf 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,10 +1,8 @@
 [tox]
 envlist = pep8,py39,bashate,pip-check-reqs
 minversion = 3.18.0
-ignore_basepython_conflict = True
 
 [tempestenv]
-basepython = python3
 sitepackages = False
 setenv =
     VIRTUAL_ENV={envdir}
@@ -15,7 +13,6 @@
     -r{toxinidir}/requirements.txt
 
 [testenv]
-basepython = python3
 setenv =
     VIRTUAL_ENV={envdir}
     OS_LOG_CAPTURE=1
@@ -72,7 +69,6 @@
 [testenv:all]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 # 'all' includes slow tests
 setenv =
     {[tempestenv]setenv}
@@ -93,7 +89,6 @@
 # 'all' includes slow tests
 setenv =
     {[tempestenv]setenv}
-basepython = {[tempestenv]basepython}
 deps = {[tempestenv]deps}
 commands =
     echo "WARNING: The all-plugin env is deprecated and will be removed"
@@ -106,7 +101,6 @@
 # 'all' includes slow tests
 setenv =
     {[tempestenv]setenv}
-basepython = {[tempestenv]basepython}
 deps = {[tempestenv]deps}
 commands =
     find . -type f -name "*.pyc" -delete
@@ -115,7 +109,6 @@
 [testenv:full]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 # The regex below is used to select which tests to run and exclude the slow tag:
@@ -129,7 +122,6 @@
 [testenv:integrated-full]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 # The regex below is used to select which tests to run. It exclude the extra
@@ -146,7 +138,6 @@
 [testenv:extra-tests]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 # The regex below is used to select extra tests mentioned in
@@ -161,7 +152,6 @@
 [testenv:full-parallel]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 # But exlcude the extra tests mentioned in tools/tempest-extra-tests-list.txt
@@ -173,7 +163,6 @@
 [testenv:api-microversion-tests]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 regex = '(^tempest\.api\.compute)|(^tempest\.api\.volume)'
@@ -186,7 +175,6 @@
 [testenv:integrated-network]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 regex1 = '(?!.*\[.*\bslow\b.*\])(^tempest\.api)'
@@ -201,7 +189,6 @@
 [testenv:integrated-compute]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 regex1 = '(?!.*\[.*\bslow\b.*\])(^tempest\.api)'
@@ -216,7 +203,6 @@
 [testenv:integrated-placement]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 regex1 = '(?!.*\[.*\bslow\b.*\])(^tempest\.api)'
@@ -231,7 +217,6 @@
 [testenv:integrated-storage]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 regex1 = '(?!.*\[.*\bslow\b.*\])(^tempest\.api)'
@@ -246,7 +231,6 @@
 [testenv:integrated-object-storage]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 regex1 = '(?!.*\[.*\bslow\b.*\])(^tempest\.api)'
@@ -261,7 +245,6 @@
 [testenv:full-serial]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 regex = '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|serial_tests))'
@@ -275,7 +258,6 @@
 [testenv:scenario]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 regex = '(^tempest\.scenario)'
@@ -287,7 +269,6 @@
 [testenv:smoke]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 regex = '\[.*\bsmoke\b.*\]'
@@ -298,7 +279,6 @@
 [testenv:smoke-serial]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 regex = '\[.*\bsmoke\b.*\]'
@@ -312,7 +292,6 @@
 [testenv:slow-serial]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 regex = '\[.*\bslow\b.*\]'
@@ -324,7 +303,6 @@
 [testenv:slow]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 # The regex below is used to select the slow tagged tests:
@@ -336,7 +314,6 @@
 [testenv:multinode]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 # The regex below is used to select the multinode and smoke tagged tests
@@ -348,7 +325,6 @@
 [testenv:ipv6-only]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 regex = '\[.*\bsmoke|ipv6|test_network_v6\b.*\]'
@@ -369,7 +345,6 @@
 [testenv:venv-tempest]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 commands = {posargs}
@@ -513,7 +488,6 @@
 [testenv:stestr-master]
 envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
-basepython = {[tempestenv]basepython}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
 regex = '\[.*\bsmoke\b.*\]'