diff --git a/cinderclient/tests/v1/fakes.py b/cinderclient/tests/v1/fakes.py index 306e8144e..a223d16be 100644 --- a/cinderclient/tests/v1/fakes.py +++ b/cinderclient/tests/v1/fakes.py @@ -281,8 +281,10 @@ class FakeHTTPClient(base_client.HTTPClient): assert body[action] is None elif action == 'os-roll_detaching': assert body[action] is None + elif action == 'os-reset_status': + assert 'status' in body[action] else: - raise AssertionError("Unexpected server action: %s" % action) + raise AssertionError("Unexpected action: %s" % action) return (resp, {}, _body) def post_volumes(self, **kw): diff --git a/cinderclient/tests/v1/test_shell.py b/cinderclient/tests/v1/test_shell.py index bacca9ba8..8b23d6f8c 100644 --- a/cinderclient/tests/v1/test_shell.py +++ b/cinderclient/tests/v1/test_shell.py @@ -179,3 +179,13 @@ class ShellTest(utils.TestCase): self.run_command('metadata 1234 unset key1 key2') self.assert_called('DELETE', '/volumes/1234/metadata/key1') self.assert_called('DELETE', '/volumes/1234/metadata/key2', pos=-2) + + def test_reset_state(self): + self.run_command('reset-state 1234') + expected = {'os-reset_status': {'status': 'available'}} + self.assert_called('POST', '/volumes/1234/action', body=expected) + + def test_reset_state_with_flag(self): + self.run_command('reset-state --state error 1234') + expected = {'os-reset_status': {'status': 'error'}} + self.assert_called('POST', '/volumes/1234/action', body=expected) diff --git a/cinderclient/tests/v2/fakes.py b/cinderclient/tests/v2/fakes.py index 60cc4c170..e888a8b2c 100644 --- a/cinderclient/tests/v2/fakes.py +++ b/cinderclient/tests/v2/fakes.py @@ -288,8 +288,10 @@ class FakeHTTPClient(base_client.HTTPClient): assert body[action] is None elif action == 'os-roll_detaching': assert body[action] is None + elif action == 'os-reset_status': + assert 'status' in body[action] else: - raise AssertionError("Unexpected server action: %s" % action) + raise AssertionError("Unexpected action: %s" % action) return (resp, {}, _body) def post_volumes(self, **kw): diff --git a/cinderclient/tests/v2/test_shell.py b/cinderclient/tests/v2/test_shell.py index 8f6e0742c..ce7842cf6 100644 --- a/cinderclient/tests/v2/test_shell.py +++ b/cinderclient/tests/v2/test_shell.py @@ -157,3 +157,13 @@ class ShellTest(utils.TestCase): self.run_command('metadata 1234 unset key1 key2') self.assert_called('DELETE', '/volumes/1234/metadata/key1') self.assert_called('DELETE', '/volumes/1234/metadata/key2', pos=-2) + + def test_reset_state(self): + self.run_command('reset-state 1234') + expected = {'os-reset_status': {'status': 'available'}} + self.assert_called('POST', '/volumes/1234/action', body=expected) + + def test_reset_state_with_flag(self): + self.run_command('reset-state --state error 1234') + expected = {'os-reset_status': {'status': 'error'}} + self.assert_called('POST', '/volumes/1234/action', body=expected) diff --git a/cinderclient/v1/shell.py b/cinderclient/v1/shell.py index 77cf19686..f42d74e5d 100644 --- a/cinderclient/v1/shell.py +++ b/cinderclient/v1/shell.py @@ -273,6 +273,18 @@ def do_force_delete(cs, args): volume.force_delete() +@utils.arg('volume', metavar='', help='ID of the volume to modify.') +@utils.arg('--state', metavar='', default='available', + help=('Indicate which state to assign the volume. Options include ' + 'available, error, creating, deleting, error_deleting. If no ' + 'state is provided, available will be used.')) +@utils.service_type('volume') +def do_reset_state(cs, args): + """Explicitly update the state of a volume.""" + volume = _find_volume(cs, args.volume) + volume.reset_state(args.state) + + @utils.arg('volume', metavar='', help='ID of the volume to rename.') @utils.arg('display_name', nargs='?', metavar='', help='New display-name for the volume.') diff --git a/cinderclient/v1/volumes.py b/cinderclient/v1/volumes.py index 1302dd833..066890de0 100644 --- a/cinderclient/v1/volumes.py +++ b/cinderclient/v1/volumes.py @@ -101,6 +101,10 @@ class Volume(base.Resource): """ self.manager.force_delete(self) + def reset_state(self, state): + """Update the volume with the provided state.""" + self.manager.reset_state(self, state) + class VolumeManager(base.ManagerWithFind): """ @@ -330,3 +334,7 @@ class VolumeManager(base.ManagerWithFind): def force_delete(self, volume): return self._action('os-force_delete', base.getid(volume)) + + def reset_state(self, volume, state): + """Update the provided volume with the provided state.""" + return self._action('os-reset_status', volume, {'status': state}) diff --git a/cinderclient/v2/shell.py b/cinderclient/v2/shell.py index b4a5dbd6d..b86f7f9be 100644 --- a/cinderclient/v2/shell.py +++ b/cinderclient/v2/shell.py @@ -307,6 +307,18 @@ def do_force_delete(cs, args): volume.force_delete() +@utils.arg('volume', metavar='', help='ID of the volume to modify.') +@utils.arg('--state', metavar='', default='available', + help=('Indicate which state to assign the volume. Options include ' + 'available, error, creating, deleting, error_deleting. If no ' + 'state is provided, available will be used.')) +@utils.service_type('volume') +def do_reset_state(cs, args): + """Explicitly update the state of a volume.""" + volume = _find_volume(cs, args.volume) + volume.reset_state(args.state) + + @utils.arg('volume', metavar='', help='ID of the volume to rename.') diff --git a/cinderclient/v2/volumes.py b/cinderclient/v2/volumes.py index fe77e11e4..3982e4e5c 100644 --- a/cinderclient/v2/volumes.py +++ b/cinderclient/v2/volumes.py @@ -100,6 +100,10 @@ class Volume(base.Resource): """ self.manager.force_delete(self) + def reset_state(self, state): + """Update the volume with the provided state.""" + self.manager.reset_state(self, state) + class VolumeManager(base.ManagerWithFind): """Manage :class:`Volume` resources.""" @@ -313,3 +317,7 @@ class VolumeManager(base.ManagerWithFind): def force_delete(self, volume): return self._action('os-force_delete', base.getid(volume)) + + def reset_state(self, volume, state): + """Update the provided volume with the provided state.""" + return self._action('os-reset_status', volume, {'status': state})