Merge ""--wait" option added for snapshot create/revert/delete commands"

This commit is contained in:
Zuul 2024-04-01 14:55:23 +00:00 committed by Gerrit Code Review
commit 9e81815674
3 changed files with 102 additions and 0 deletions

View File

@ -1054,6 +1054,7 @@ class ShellTest(test_utils.TestCase):
self.shell.cs, expected_snapshot, 'deleted', self.shell.cs, expected_snapshot, 'deleted',
resource_type='snapshot') resource_type='snapshot')
@mock.patch.object(shell_v2, '_wait_for_share_status', mock.Mock())
def test_revert_to_snapshot(self): def test_revert_to_snapshot(self):
fake_share_snapshot = type( fake_share_snapshot = type(
@ -1066,6 +1067,25 @@ class ShellTest(test_utils.TestCase):
self.assert_called('POST', '/shares/1234/action', self.assert_called('POST', '/shares/1234/action',
body={'revert': {'snapshot_id': '5678'}}) body={'revert': {'snapshot_id': '5678'}})
# _wait_for_share_status should not be trigerred
self.assertEqual(0, shell_v2._wait_for_share_status.call_count)
@mock.patch.object(shell_v2, '_wait_for_share_status', mock.Mock())
def test_revert_to_snapshot_with_wait(self):
fake_share_snapshot = type(
'FakeShareSnapshot', (object,), {'id': '5678', 'share_id': '1234'})
self.mock_object(
shell_v2, '_find_share_snapshot',
mock.Mock(return_value=fake_share_snapshot))
self.run_command('revert-to-snapshot 5678 --wait')
self.assert_called('POST', '/shares/1234/action',
body={'revert': {'snapshot_id': '5678'}})
# _wait_for_share_status should be trigerred once
shell_v2._wait_for_share_status.assert_called_once_with(
self.shell.cs, mock.ANY)
def test_delete(self): def test_delete(self):
self.run_command('delete 1234') self.run_command('delete 1234')
@ -3693,6 +3713,39 @@ class ShellTest(test_utils.TestCase):
'DELETE', '/share-networks/%s' % sn.id, 'DELETE', '/share-networks/%s' % sn.id,
clear_callstack=False) clear_callstack=False)
@mock.patch.object(shell_v2, '_find_share', mock.Mock())
@mock.patch.object(shell_v2, '_wait_for_snapshot_status', mock.Mock())
def test_snapshot_create(self):
share_to_create_snapshot = shares.Share('fake_share', {'id': '1234'})
shell_v2._find_share.return_value = share_to_create_snapshot
self.run_command(
'snapshot-create fake_share --name testshare1snapshot')
shell_v2._find_share.assert_has_calls([
mock.call(self.shell.cs, 'fake_share')])
self.assert_called_anytime(
'POST', '/snapshots', clear_callstack=False)
# _wait_for_snapshot_status should not be trigerred
self.assertEqual(0, shell_v2._wait_for_snapshot_status.call_count)
@mock.patch.object(shell_v2, '_find_share', mock.Mock())
@mock.patch.object(shell_v2, '_wait_for_snapshot_status', mock.Mock())
def test_snapshot_create_with_wait(self):
share_to_create_snapshot = shares.Share('fake_share', {'id': '1234'})
shell_v2._find_share.return_value = share_to_create_snapshot
self.run_command(
'snapshot-create fake_share --name testshare1snapshot --wait')
shell_v2._find_share.assert_has_calls([
mock.call(self.shell.cs, 'fake_share')])
self.assert_called_anytime(
'POST', '/snapshots', clear_callstack=False)
# _wait_for_snapshot_status should be trigerred once
shell_v2._wait_for_snapshot_status.assert_called_once_with(
self.shell.cs, mock.ANY, expected_status='available')
@ddt.data(('fake_snapshot1', ), ('fake_snapshot1', 'fake_snapshot2')) @ddt.data(('fake_snapshot1', ), ('fake_snapshot1', 'fake_snapshot2'))
def test_snapshot_delete(self, snapshot_ids): def test_snapshot_delete(self, snapshot_ids):
fake_snapshots = [ fake_snapshots = [
@ -3713,6 +3766,23 @@ class ShellTest(test_utils.TestCase):
'DELETE', '/snapshots/%s' % snapshot.id, 'DELETE', '/snapshots/%s' % snapshot.id,
clear_callstack=False) clear_callstack=False)
@mock.patch.object(shell_v2, '_find_share_snapshot', mock.Mock())
@mock.patch.object(shell_v2, '_wait_for_snapshot_status', mock.Mock())
def test_snapshot_delete_with_wait(self):
fake_snapshot = share_snapshots.ShareSnapshot(
'fake', {'id': 'fake_snapshot1'}, True)
shell_v2._find_share_snapshot.return_value = fake_snapshot
self.run_command('snapshot-delete fake_snapshot1 --wait')
shell_v2._find_share_snapshot.assert_has_calls([
mock.call(self.shell.cs, 'fake_snapshot1')])
self.assert_called_anytime(
'DELETE', '/snapshots/fake_snapshot1', clear_callstack=False)
# _wait_for_resource_status should be trigerred once
shell_v2._wait_for_snapshot_status.assert_called_once_with(
self.shell.cs, 'fake_snapshot1', expected_status='deleted')
@ddt.data(('snapshot_xyz', ), ('snapshot_abc', 'snapshot_xyz')) @ddt.data(('snapshot_xyz', ), ('snapshot_abc', 'snapshot_xyz'))
def test_snapshot_force_delete_wait(self, snapshots_to_delete): def test_snapshot_force_delete_wait(self, snapshots_to_delete):
fake_manager = mock.Mock() fake_manager = mock.Mock()

View File

@ -1817,11 +1817,18 @@ def do_snapshot_unmanage(cs, args):
metavar='<snapshot>', metavar='<snapshot>',
help='Name or ID of the snapshot to restore. The snapshot must be the ' help='Name or ID of the snapshot to restore. The snapshot must be the '
'most recent one known to manila.') 'most recent one known to manila.')
@cliutils.arg(
'--wait',
action='store_true',
default=False,
help='Wait for share to be reverted from snapshot.')
def do_revert_to_snapshot(cs, args): def do_revert_to_snapshot(cs, args):
"""Revert a share to the specified snapshot.""" """Revert a share to the specified snapshot."""
snapshot = _find_share_snapshot(cs, args.snapshot) snapshot = _find_share_snapshot(cs, args.snapshot)
share = _find_share(cs, snapshot.share_id) share = _find_share(cs, snapshot.share_id)
share.revert_to_snapshot(snapshot) share.revert_to_snapshot(snapshot)
if args.wait:
_wait_for_share_status(cs, share)
@cliutils.arg( @cliutils.arg(
@ -3061,6 +3068,11 @@ def do_snapshot_instance_export_location_show(cs, args):
metavar='<description>', metavar='<description>',
default=None, default=None,
help='Optional snapshot description. (Default=None)') help='Optional snapshot description. (Default=None)')
@cliutils.arg(
'--wait',
action='store_true',
default=False,
help='Wait for snapshot to be created.')
def do_snapshot_create(cs, args): def do_snapshot_create(cs, args):
"""Add a new snapshot.""" """Add a new snapshot."""
share = _find_share(cs, args.share) share = _find_share(cs, args.share)
@ -3068,6 +3080,12 @@ def do_snapshot_create(cs, args):
args.force, args.force,
args.name, args.name,
args.description) args.description)
if args.wait:
try:
_wait_for_snapshot_status(cs, snapshot,
expected_status='available')
except exceptions.CommandError as e:
print(e, file=sys.stderr)
_print_share_snapshot(cs, snapshot) _print_share_snapshot(cs, snapshot)
@ -3143,6 +3161,11 @@ def do_snapshot_rename(cs, args):
metavar='<snapshot>', metavar='<snapshot>',
nargs='+', nargs='+',
help='Name or ID of the snapshot(s) to delete.') help='Name or ID of the snapshot(s) to delete.')
@cliutils.arg(
'--wait',
action='store_true',
default=False,
help='Wait for snapshot to be deleted')
def do_snapshot_delete(cs, args): def do_snapshot_delete(cs, args):
"""Remove one or more snapshots.""" """Remove one or more snapshots."""
failure_count = 0 failure_count = 0
@ -3152,6 +3175,9 @@ def do_snapshot_delete(cs, args):
snapshot_ref = _find_share_snapshot( snapshot_ref = _find_share_snapshot(
cs, snapshot) cs, snapshot)
cs.share_snapshots.delete(snapshot_ref) cs.share_snapshots.delete(snapshot_ref)
if args.wait:
_wait_for_snapshot_status(cs, snapshot,
expected_status='deleted')
except Exception as e: except Exception as e:
failure_count += 1 failure_count += 1
print("Delete for snapshot %s failed: %s" % ( print("Delete for snapshot %s failed: %s" % (

View File

@ -0,0 +1,6 @@
---
features:
- |
The commands "snapshot-create", "snapshot-delete" and "revert-to-snapshot"
now accept an optional "--wait" option that allows users to let the
client poll for the completion of the operation.