summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cinderclient/tests/unit/v2/test_shell.py19
-rw-r--r--cinderclient/tests/unit/v2/test_volumes.py6
-rw-r--r--cinderclient/v2/shell.py15
-rw-r--r--cinderclient/v2/volumes.py33
4 files changed, 66 insertions, 7 deletions
diff --git a/cinderclient/tests/unit/v2/test_shell.py b/cinderclient/tests/unit/v2/test_shell.py
index 3a88691..d183564 100644
--- a/cinderclient/tests/unit/v2/test_shell.py
+++ b/cinderclient/tests/unit/v2/test_shell.py
@@ -496,6 +496,25 @@ class ShellTest(utils.TestCase):
expected = {'os-reset_status': {'status': 'error'}}
self.assert_called('POST', '/volumes/1234/action', body=expected)
+ def test_reset_state_with_attach_status(self):
+ self.run_command('reset-state --attach-status detached 1234')
+ expected = {'os-reset_status': {'status': 'available',
+ 'attach_status': 'detached'}}
+ self.assert_called('POST', '/volumes/1234/action', body=expected)
+
+ def test_reset_state_with_attach_status_with_flag(self):
+ self.run_command('reset-state --state in-use '
+ '--attach-status attached 1234')
+ expected = {'os-reset_status': {'status': 'in-use',
+ 'attach_status': 'attached'}}
+ self.assert_called('POST', '/volumes/1234/action', body=expected)
+
+ def test_reset_state_with_reset_migration_status(self):
+ self.run_command('reset-state --reset-migration-status 1234')
+ expected = {'os-reset_status': {'status': 'available',
+ 'migration_status': 'none'}}
+ self.assert_called('POST', '/volumes/1234/action', body=expected)
+
def test_reset_state_multiple(self):
self.run_command('reset-state 1234 5678 --state error')
expected = {'os-reset_status': {'status': 'error'}}
diff --git a/cinderclient/tests/unit/v2/test_volumes.py b/cinderclient/tests/unit/v2/test_volumes.py
index 08b9678..5260238 100644
--- a/cinderclient/tests/unit/v2/test_volumes.py
+++ b/cinderclient/tests/unit/v2/test_volumes.py
@@ -160,6 +160,12 @@ class VolumesTest(utils.TestCase):
cs.volumes.extend(v, 2)
cs.assert_called('POST', '/volumes/1234/action')
+ def test_reset_state(self):
+ v = cs.volumes.get('1234')
+ cs.volumes.reset_state(v, 'in-use', attach_status='detached',
+ migration_status='none')
+ cs.assert_called('POST', '/volumes/1234/action')
+
def test_get_encryption_metadata(self):
cs.volumes.get_encryption_metadata('1234')
cs.assert_called('GET', '/volumes/1234/encryption')
diff --git a/cinderclient/v2/shell.py b/cinderclient/v2/shell.py
index c2ac8bf..ee5de76 100644
--- a/cinderclient/v2/shell.py
+++ b/cinderclient/v2/shell.py
@@ -464,6 +464,16 @@ def do_force_delete(cs, args):
'NOTE: This command simply changes the state of the '
'Volume in the DataBase with no regard to actual status, '
'exercise caution when using. Default=available.'))
+@utils.arg('--attach-status', metavar='<attach-status>', default=None,
+ help=('The attach status to assign to the volume in the DataBase, '
+ 'with no regard to the actual status. Valid values are '
+ '"attached" and "detached". Default=None, that means the '
+ 'status is unchanged.'))
+@utils.arg('--reset-migration-status',
+ action='store_true',
+ help=('Clears the migration status of the volume in the DataBase '
+ 'that indicates the volume is source or destination of '
+ 'volume migration, with no regard to the actual status.'))
@utils.service_type('volumev2')
def do_reset_state(cs, args):
"""Explicitly updates the volume state in the Cinder database.
@@ -475,10 +485,13 @@ def do_reset_state(cs, args):
unusable in the case of change to the 'available' state.
"""
failure_flag = False
+ migration_status = 'none' if args.reset_migration_status else None
for volume in args.volume:
try:
- utils.find_volume(cs, volume).reset_state(args.state)
+ utils.find_volume(cs, volume).reset_state(args.state,
+ args.attach_status,
+ migration_status)
except Exception as e:
failure_flag = True
msg = "Reset state for volume %s failed: %s" % (volume, e)
diff --git a/cinderclient/v2/volumes.py b/cinderclient/v2/volumes.py
index 76bf293..d5eb8d0 100644
--- a/cinderclient/v2/volumes.py
+++ b/cinderclient/v2/volumes.py
@@ -127,9 +127,16 @@ 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)
+ def reset_state(self, state, attach_status=None, migration_status=None):
+ """Update the volume with the provided state.
+
+ :param state: The state of the volume to set.
+ :param attach_status: The attach_status of the volume to be set,
+ or None to keep the current status.
+ :param migration_status: The migration_status of the volume to be set,
+ or None to keep the current status.
+ """
+ self.manager.reset_state(self, state, attach_status, migration_status)
def extend(self, volume, new_size):
"""Extend the size of the specified volume.
@@ -531,9 +538,23 @@ class VolumeManager(base.ManagerWithFind):
"""
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})
+ def reset_state(self, volume, state, attach_status=None,
+ migration_status=None):
+ """Update the provided volume with the provided state.
+
+ :param volume: The :class:`Volume` to set the state.
+ :param state: The state of the volume to be set.
+ :param attach_status: The attach_status of the volume to be set,
+ or None to keep the current status.
+ :param migration_status: The migration_status of the volume to be set,
+ or None to keep the current status.
+ """
+ body = {'status': state}
+ if attach_status:
+ body.update({'attach_status': attach_status})
+ if migration_status:
+ body.update({'migration_status': migration_status})
+ return self._action('os-reset_status', volume, body)
def extend(self, volume, new_size):
"""Extend the size of the specified volume.