From 699a2f5dce7bb01e0a3f0562ebf0204228171467 Mon Sep 17 00:00:00 2001 From: Sheel Rana Date: Sun, 8 May 2016 17:57:46 +0530 Subject: [PATCH] Support for snapshot force delete Cinder snapshot force delete is supported from cinder server side but cinderclient support is not present. This patchset adds support for cinder snapshot force delete from cinderclient side. Closes-Bug:#1418353 Change-Id: I8c4f02f9c3b855d44b1a3c7da7083d87b3b70da9 Implements: Blueprint snapshot-backup-force-delete --- cinderclient/tests/unit/v2/fakes.py | 2 ++ cinderclient/tests/unit/v2/test_shell.py | 35 +++++++++++++++++++++--- cinderclient/v3/shell.py | 8 +++++- cinderclient/v3/volume_snapshots.py | 12 +++++--- 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/cinderclient/tests/unit/v2/fakes.py b/cinderclient/tests/unit/v2/fakes.py index 40c57d191..b816dd6b9 100644 --- a/cinderclient/tests/unit/v2/fakes.py +++ b/cinderclient/tests/unit/v2/fakes.py @@ -356,6 +356,8 @@ class FakeHTTPClient(base_client.HTTPClient): assert 'status' in body['os-reset_status'] elif action == 'os-update_snapshot_status': assert 'status' in body['os-update_snapshot_status'] + elif action == 'os-force_delete': + assert body[action] is None elif action == 'os-unmanage': assert body[action] is None else: diff --git a/cinderclient/tests/unit/v2/test_shell.py b/cinderclient/tests/unit/v2/test_shell.py index 156df536b..a75c8b94d 100644 --- a/cinderclient/tests/unit/v2/test_shell.py +++ b/cinderclient/tests/unit/v2/test_shell.py @@ -933,17 +933,44 @@ class ShellTest(utils.TestCase): self.assert_called('POST', '/volumes/1234/action', body=expected) def test_snapshot_delete(self): + """Tests delete snapshot without force parameter""" self.run_command('snapshot-delete 1234') self.assert_called('DELETE', '/snapshots/1234') + def test_snapshot_delete_multiple(self): + """Tests delete multiple snapshots without force parameter""" + self.run_command('snapshot-delete 5678 1234') + self.assert_called_anytime('DELETE', '/snapshots/5678') + self.assert_called('DELETE', '/snapshots/1234') + + def test_force_snapshot_delete(self): + """Tests delete snapshot with default force parameter value(True)""" + self.run_command('snapshot-delete 1234 --force') + expected_body = {'os-force_delete': None} + self.assert_called('POST', + '/snapshots/1234/action', + expected_body) + + def test_force_snapshot_delete_multiple(self): + """ + Tests delete multiple snapshots with force parameter + + Snapshot delete with force parameter allows deleting snapshot of a + volume when its status is other than "available" or "error". + """ + self.run_command('snapshot-delete 5678 1234 --force') + expected_body = {'os-force_delete': None} + self.assert_called_anytime('POST', + '/snapshots/5678/action', + expected_body) + self.assert_called_anytime('POST', + '/snapshots/1234/action', + expected_body) + def test_quota_delete(self): self.run_command('quota-delete 1234') self.assert_called('DELETE', '/os-quota-sets/1234') - def test_snapshot_delete_multiple(self): - self.run_command('snapshot-delete 5678') - self.assert_called('DELETE', '/snapshots/5678') - def test_volume_manage(self): self.run_command('manage host1 some_fake_name ' '--name foo --description bar ' diff --git a/cinderclient/v3/shell.py b/cinderclient/v3/shell.py index f28dedb0b..fbdd5452f 100644 --- a/cinderclient/v3/shell.py +++ b/cinderclient/v3/shell.py @@ -780,13 +780,19 @@ def do_snapshot_create(cs, args): @utils.arg('snapshot', metavar='', nargs='+', help='Name or ID of the snapshot(s) to delete.') +@utils.arg('--force', + action="store_true", + help='Allows deleting snapshot of a volume ' + 'when its status is other than "available" or "error". ' + 'Default=False.') @utils.service_type('volumev3') def do_snapshot_delete(cs, args): """Removes one or more snapshots.""" failure_count = 0 + for snapshot in args.snapshot: try: - _find_volume_snapshot(cs, snapshot).delete() + _find_volume_snapshot(cs, snapshot).delete(args.force) except Exception as e: failure_count += 1 print("Delete for snapshot %s failed: %s" % (snapshot, e)) diff --git a/cinderclient/v3/volume_snapshots.py b/cinderclient/v3/volume_snapshots.py index 0039b8dca..c84ee732b 100644 --- a/cinderclient/v3/volume_snapshots.py +++ b/cinderclient/v3/volume_snapshots.py @@ -25,9 +25,9 @@ class Snapshot(base.Resource): def __repr__(self): return "" % self.id - def delete(self): + def delete(self, force=False): """Delete this snapshot.""" - return self.manager.delete(self) + return self.manager.delete(self, force) def update(self, **kwargs): """Update the name or description for this snapshot.""" @@ -118,12 +118,16 @@ class SnapshotManager(base.ManagerWithFind): limit=limit, sort=sort) return self._list(url, resource_type, limit=limit) - def delete(self, snapshot): + def delete(self, snapshot, force=False): """Delete a snapshot. :param snapshot: The :class:`Snapshot` to delete. + :param force: Allow delete in state other than error or available. """ - return self._delete("/snapshots/%s" % base.getid(snapshot)) + if force: + return self._action('os-force_delete', snapshot) + else: + return self._delete("/snapshots/%s" % base.getid(snapshot)) def update(self, snapshot, **kwargs): """Update the name or description for a snapshot.