cinder backup force-delete when backup is error

Update testcases to force delete a backup when the state is error

steps:
- create a backup
- reset backup state to error
- force delete the backup

Fixed create backup cleanup

Added API:
- force_delete_backup

Change-Id: I2495e9c10e888f5a01d2a3e7f09a4b6dfc3d58a0
diff --git a/releasenotes/notes/add-volume-backup-force-delete-af0156651a0cbf7f.yaml b/releasenotes/notes/add-volume-backup-force-delete-af0156651a0cbf7f.yaml
new file mode 100644
index 0000000..71bbfcb
--- /dev/null
+++ b/releasenotes/notes/add-volume-backup-force-delete-af0156651a0cbf7f.yaml
@@ -0,0 +1,9 @@
+---
+features:
+  - |
+    As in the [doc]:
+    https://developer.openstack.org/api-ref/block-storage/v3/
+    #force-delete-a-backup.
+
+      * Force-deletes a backup(v2)
+
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
index 29c79f9..7d2127f 100644
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -121,7 +121,7 @@
                                                 'available')
 
     @decorators.idempotent_id('47a35425-a891-4e13-961c-c45deea21e94')
-    def test_volume_backup_reset_status(self):
+    def test_volume_backup_reset_status_force_delete(self):
         # Create a volume
         volume = self.create_volume()
         # Create a backup
@@ -136,3 +136,6 @@
                                                       status="error")
         waiters.wait_for_volume_resource_status(self.admin_backups_client,
                                                 backup['id'], 'error')
+        # Force delete a backup volume when backup is in error state.
+        self.admin_backups_client.force_delete_backup(backup['id'])
+        self.admin_backups_client.wait_for_resource_deletion(backup['id'])
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 5e4fada..2362d30 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -125,16 +125,20 @@
                                                 snapshot['id'], 'available')
         return snapshot
 
-    def create_backup(self, volume_id, backup_client=None, **kwargs):
+    def create_backup(self, volume_id, backup_client=None,
+                      wait_until="available", **kwargs):
         """Wrapper utility that returns a test backup."""
         if backup_client is None:
             backup_client = self.backups_client
 
         backup = backup_client.create_backup(
             volume_id=volume_id, **kwargs)['backup']
-        self.addCleanup(backup_client.delete_backup, backup['id'])
-        waiters.wait_for_volume_resource_status(backup_client, backup['id'],
-                                                'available')
+
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        backup_client.delete_backup, backup['id'])
+        waiters.wait_for_volume_resource_status(backup_client,
+                                                backup['id'],
+                                                wait_until)
         return backup
 
     # NOTE(afazekas): these create_* and clean_* could be defined
diff --git a/tempest/lib/services/volume/v2/backups_client.py b/tempest/lib/services/volume/v2/backups_client.py
index 2b5e82d..197d57e 100644
--- a/tempest/lib/services/volume/v2/backups_client.py
+++ b/tempest/lib/services/volume/v2/backups_client.py
@@ -55,6 +55,14 @@
         self.expected_success(202, resp.status)
         return rest_client.ResponseBody(resp, body)
 
+    def force_delete_backup(self, backup_id):
+        """Force delete a backup volume."""
+        post_body = json.dumps({'os-force_delete': {}})
+        url = 'backups/%s/action' % backup_id
+        resp, body = self.post(url, post_body)
+        self.expected_success(202, resp.status)
+        return rest_client.ResponseBody(resp)
+
     def show_backup(self, backup_id):
         """Returns the details of a single backup."""
         url = "backups/%s" % backup_id