Fix cleanup for volume backup tests

Volume backup tests create a container when swift is used as
a backup driver. This causes a failure of an object storage
test [1] as it expects no containers being present before
the testing.

This patch fixes the cleanup of volume backup tests by making
sure that containers created during testing are deleted.

The containers cleanup is called only when swift is present.
When Swift is not used as a back up driver but is present,
the cleanup tries to delete the containers anyway. This will
not cause a failure as the delete_containers function catches
the NotFound [2] error.

[1] https://opendev.org/openstack/tempest/src/tempest/api/object_storage/test_account_services.py#L67
[2] https://opendev.org/openstack/tempest/src/tempest/api/object_storage/base.py#L50

Closes-Bug: #2028671
Change-Id: If94facd5a926f7eadd092dfc8f0368d8e4b8d630
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 a31390a..df7801d 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
@@ -64,6 +65,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
@@ -170,16 +173,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 85e4bb2..8e89a0a 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.")