diff --git a/cinderclient/tests/unit/v2/test_volume_backups.py b/cinderclient/tests/unit/v2/test_volume_backups.py index ac8be24eb..d493080a8 100644 --- a/cinderclient/tests/unit/v2/test_volume_backups.py +++ b/cinderclient/tests/unit/v2/test_volume_backups.py @@ -92,6 +92,32 @@ class VolumeBackupsTest(utils.TestCase): '/backups/76a17945-3c6f-435c-975b-b5685db10b62') self._assert_request_id(del_back) + def test_force_delete_with_True_force_param_value(self): + """Tests delete backup with force parameter set to True""" + b = cs.backups.list()[0] + del_back = b.delete(force=True) + expected_body = {'os-force_delete': None} + cs.assert_called('POST', + '/backups/76a17945-3c6f-435c-975b-b5685db10b62/action', + expected_body) + self._assert_request_id(del_back) + + def test_force_delete_with_false_force_param_vaule(self): + """To delete backup with force parameter set to False""" + b = cs.backups.list()[0] + del_back = b.delete(force=False) + cs.assert_called('DELETE', + '/backups/76a17945-3c6f-435c-975b-b5685db10b62') + self._assert_request_id(del_back) + del_back = cs.backups.delete('76a17945-3c6f-435c-975b-b5685db10b62') + cs.assert_called('DELETE', + '/backups/76a17945-3c6f-435c-975b-b5685db10b62') + self._assert_request_id(del_back) + del_back = cs.backups.delete(b) + cs.assert_called('DELETE', + '/backups/76a17945-3c6f-435c-975b-b5685db10b62') + self._assert_request_id(del_back) + def test_restore(self): backup_id = '76a17945-3c6f-435c-975b-b5685db10b62' info = cs.restores.restore(backup_id) diff --git a/cinderclient/v3/shell.py b/cinderclient/v3/shell.py index 96d27481f..b0fa4483a 100644 --- a/cinderclient/v3/shell.py +++ b/cinderclient/v3/shell.py @@ -1472,6 +1472,11 @@ def do_backup_list(cs, args): utils.print_list(backups, columns, sortby_index=sortby_index) +@utils.arg('--force', + action="store_true", + help='Allows deleting backup of a volume ' + 'when its status is other than "available" or "error". ' + 'Default=False.') @utils.arg('backup', metavar='', nargs='+', help='Name or ID of backup(s) to delete.') @utils.service_type('volumev3') @@ -1480,7 +1485,7 @@ def do_backup_delete(cs, args): failure_count = 0 for backup in args.backup: try: - _find_backup(cs, backup).delete() + _find_backup(cs, backup).delete(args.force) print("Request to delete backup %s has been accepted." % (backup)) except Exception as e: failure_count += 1 diff --git a/cinderclient/v3/volume_backups.py b/cinderclient/v3/volume_backups.py index b264dec89..0941fb86b 100644 --- a/cinderclient/v3/volume_backups.py +++ b/cinderclient/v3/volume_backups.py @@ -26,9 +26,9 @@ class VolumeBackup(base.Resource): def __repr__(self): return "" % self.id - def delete(self): + def delete(self, force=False): """Delete this volume backup.""" - return self.manager.delete(self) + return self.manager.delete(self, force) def reset_state(self, state): return self.manager.reset_state(self, state) @@ -81,12 +81,16 @@ class VolumeBackupManager(base.ManagerWithFind): limit=limit, sort=sort) return self._list(url, resource_type, limit=limit) - def delete(self, backup): + def delete(self, backup, force=False): """Delete a volume backup. :param backup: The :class:`VolumeBackup` to delete. + :param force: Allow delete in state other than error or available. """ - return self._delete("/backups/%s" % base.getid(backup)) + if force: + return self._action('os-force_delete', backup) + else: + return self._delete("/backups/%s" % base.getid(backup)) def reset_state(self, backup, state): """Update the specified volume backup with the provided state."""