Adding backup-reset-state to CLI

This patch adds the ability to reset the state of
a backup with the command backup-reset-state.

DocImpact

Change-Id: I5851bb21c62252f61ad6a09f01859582e774a9db
Closes-Bug: #1279764
This commit is contained in:
Nate Potter
2015-10-19 20:17:35 +00:00
parent cfecd8ebe0
commit 8690e41c22
5 changed files with 96 additions and 0 deletions

View File

@@ -766,6 +766,20 @@ class FakeHTTPClient(base_client.HTTPClient):
return (200, {},
{'backup': _stub_backup_full(backup1, base_uri, tenant_id)})
def get_backups_1234(self, **kw):
base_uri = 'http://localhost:8776'
tenant_id = '0fa851f6668144cf9cd8c8419c1646c1'
backup1 = '1234'
return (200, {},
{'backup': _stub_backup_full(backup1, base_uri, tenant_id)})
def get_backups_5678(self, **kw):
base_uri = 'http://localhost:8776'
tenant_id = '0fa851f6668144cf9cd8c8419c1646c1'
backup1 = '5678'
return (200, {},
{'backup': _stub_backup_full(backup1, base_uri, tenant_id)})
def get_backups_detail(self, **kw):
base_uri = 'http://localhost:8776'
tenant_id = '0fa851f6668144cf9cd8c8419c1646c1'
@@ -794,6 +808,15 @@ class FakeHTTPClient(base_client.HTTPClient):
return (200, {},
{'restore': _stub_restore()})
def post_backups_76a17945_3c6f_435c_975b_b5685db10b62_action(self, **kw):
return(200, {}, None)
def post_backups_1234_action(self, **kw):
return(200, {}, None)
def post_backups_5678_action(self, **kw):
return(200, {}, None)
def get_backups_76a17945_3c6f_435c_975b_b5685db10b62_export_record(self,
**kw):
return (200,

View File

@@ -552,6 +552,24 @@ class ShellTest(utils.TestCase):
self.assert_called_anytime('POST', '/snapshots/5678/action',
body=expected)
def test_backup_reset_state(self):
self.run_command('backup-reset-state 1234')
expected = {'os-reset_status': {'status': 'available'}}
self.assert_called('POST', '/backups/1234/action', body=expected)
def test_backup_reset_state_with_flag(self):
self.run_command('backup-reset-state --state error 1234')
expected = {'os-reset_status': {'status': 'error'}}
self.assert_called('POST', '/backups/1234/action', body=expected)
def test_backup_reset_state_multiple(self):
self.run_command('backup-reset-state 1234 5678')
expected = {'os-reset_status': {'status': 'available'}}
self.assert_called_anytime('POST', '/backups/1234/action',
body=expected)
self.assert_called_anytime('POST', '/backups/5678/action',
body=expected)
def test_type_list(self):
self.run_command('type-list')
self.assert_called_anytime('GET', '/types?is_public=None')

View File

@@ -78,6 +78,17 @@ class VolumeBackupsTest(utils.TestCase):
self.assertIsInstance(info,
volume_backups_restore.VolumeBackupsRestore)
def test_reset_state(self):
b = cs.backups.list()[0]
api = '/backups/76a17945-3c6f-435c-975b-b5685db10b62/action'
b.reset_state(state='error')
cs.assert_called('POST', api)
cs.backups.reset_state('76a17945-3c6f-435c-975b-b5685db10b62',
state='error')
cs.assert_called('POST', api)
cs.backups.reset_state(b, state='error')
cs.assert_called('POST', api)
def test_record_export(self):
backup_id = '76a17945-3c6f-435c-975b-b5685db10b62'
cs.backups.export_record(backup_id)

View File

@@ -1429,6 +1429,36 @@ def do_backup_import(cs, args):
utils.print_dict(info)
@utils.arg('backup', metavar='<backup>', nargs='+',
help='Name or ID of the backup to modify.')
@utils.arg('--state', metavar='<state>',
default='available',
help='The state to assign to the backup. Valid values are '
'"available", "error", "creating", "deleting", and '
'"error_deleting". Default=available.')
@utils.service_type('volumev2')
def do_backup_reset_state(cs, args):
"""Explicitly updates the backup state."""
failure_count = 0
single = (len(args.backup) == 1)
for backup in args.backup:
try:
_find_backup(cs, backup).reset_state(args.state)
except Exception as e:
failure_count += 1
msg = "Reset state for backup %s failed: %s" % (backup, e)
if not single:
print(msg)
if failure_count == len(args.backup):
if not single:
msg = ("Unable to reset the state for any of the specified "
"backups.")
raise exceptions.CommandError(msg)
@utils.arg('volume', metavar='<volume>',
help='Name or ID of volume to transfer.')
@utils.arg('--name',

View File

@@ -29,6 +29,9 @@ class VolumeBackup(base.Resource):
"""Delete this volume backup."""
return self.manager.delete(self)
def reset_state(self, state):
self.manager.reset_state(self, state)
class VolumeBackupManager(base.ManagerWithFind):
"""Manage :class:`VolumeBackup` resources."""
@@ -82,6 +85,17 @@ class VolumeBackupManager(base.ManagerWithFind):
"""
self._delete("/backups/%s" % base.getid(backup))
def reset_state(self, backup, state):
"""Update the specified volume backup with the provided state."""
return self._action('os-reset_status', backup, {'status': state})
def _action(self, action, backup, info=None, **kwargs):
"""Perform a volume backup action."""
body = {action: info}
self.run_hooks('modify_body_for_action', body, **kwargs)
url = '/backups/%s/action' % base.getid(backup)
return self.api.client.post(url, body=body)
def export_record(self, backup_id):
"""Export volume backup metadata record.