diff --git a/cinderclient/v1/shell.py b/cinderclient/v1/shell.py index f30e816ac..7a202f155 100644 --- a/cinderclient/v1/shell.py +++ b/cinderclient/v1/shell.py @@ -240,6 +240,23 @@ def do_delete(cs, args): volume.delete() +@utils.arg('volume', metavar='', help='ID of the volume to rename.') +@utils.arg('display_name', nargs='?', metavar='', + help='New display-name for the volume.') +@utils.arg('--display-description', metavar='', + help='Optional volume description. (Default=None)', + default=None) +@utils.service_type('volume') +def do_rename(cs, args): + """Rename a volume.""" + kwargs = {} + if args.display_name is not None: + kwargs['display_name'] = args.display_name + if args.display_description is not None: + kwargs['display_description'] = args.display_description + _find_volume(cs, args.volume).update(**kwargs) + + @utils.arg( '--all-tenants', dest='all_tenants', @@ -340,6 +357,23 @@ def do_snapshot_delete(cs, args): snapshot.delete() +@utils.arg('snapshot', metavar='', help='ID of the snapshot.') +@utils.arg('display_name', nargs='?', metavar='', + help='New display-name for the snapshot.') +@utils.arg('--display-description', metavar='', + help='Optional snapshot description. (Default=None)', + default=None) +@utils.service_type('volume') +def do_snapshot_rename(cs, args): + """Rename a snapshot.""" + kwargs = {} + if args.display_name is not None: + kwargs['display_name'] = args.display_name + if args.display_description is not None: + kwargs['display_description'] = args.display_description + _find_volume_snapshot(cs, args.snapshot).update(**kwargs) + + def _print_volume_type_list(vtypes): utils.print_list(vtypes, ['ID', 'Name']) diff --git a/cinderclient/v1/volume_snapshots.py b/cinderclient/v1/volume_snapshots.py index 59725503b..50fa56645 100644 --- a/cinderclient/v1/volume_snapshots.py +++ b/cinderclient/v1/volume_snapshots.py @@ -34,6 +34,12 @@ class Snapshot(base.Resource): """ self.manager.delete(self) + def update(self, **kwargs): + """ + Update the display_name or display_description for this snapshot. + """ + self.manager.update(self, **kwargs) + @property def progress(self): return self._info.get('os-extended-snapshot-attributes:progress') @@ -109,3 +115,16 @@ class SnapshotManager(base.ManagerWithFind): :param snapshot: The :class:`Snapshot` to delete. """ self._delete("/snapshots/%s" % base.getid(snapshot)) + + def update(self, snapshot, **kwargs): + """ + Update the display_name or display_description for a snapshot. + + :param snapshot: The :class:`Snapshot` to delete. + """ + if not kwargs: + return + + body = {"snapshot": kwargs} + + self._update("/snapshots/%s" % base.getid(snapshot), body) diff --git a/cinderclient/v1/volumes.py b/cinderclient/v1/volumes.py index ec1bf1a67..fee82eb64 100644 --- a/cinderclient/v1/volumes.py +++ b/cinderclient/v1/volumes.py @@ -34,6 +34,12 @@ class Volume(base.Resource): """ self.manager.delete(self) + def update(self, **kwargs): + """ + Update the display_name or display_description for this volume. + """ + self.manager.update(self, **kwargs) + def attach(self, instance_uuid, mountpoint): """ Set attachment metadata. @@ -178,6 +184,19 @@ class VolumeManager(base.ManagerWithFind): """ self._delete("/volumes/%s" % base.getid(volume)) + def update(self, volume, **kwargs): + """ + Update the display_name or display_description for a volume. + + :param volume: The :class:`Volume` to delete. + """ + if not kwargs: + return + + body = {"volume": kwargs} + + self._update("/volumes/%s" % base.getid(volume), body) + def create_server_volume(self, server_id, volume_id, device): """ Attach a volume identified by the volume ID to the given server ID diff --git a/tests/v1/fakes.py b/tests/v1/fakes.py index 57fa31f73..de6c552a0 100644 --- a/tests/v1/fakes.py +++ b/tests/v1/fakes.py @@ -21,6 +21,27 @@ from cinderclient.v1 import client from tests import fakes +def _stub_volume(**kwargs): + volume = { + 'id': '1234', + 'display_name': None, + 'display_description': None, + "attachments": [], + "availability_zone": "cinder", + "created_at": "2012-08-27T00:00:00.000000", + "display_description": None, + "display_name": None, + "id": '00000000-0000-0000-0000-000000000000', + "metadata": {}, + "size": 1, + "snapshot_id": None, + "status": "available", + "volume_type": "None", + } + volume.update(kwargs) + return volume + + def _stub_snapshot(**kwargs): snapshot = { "created_at": "2012-08-28T16:30:31.000000", @@ -90,10 +111,23 @@ class FakeHTTPClient(base_client.HTTPClient): _stub_snapshot(), ]}) + def get_snapshots_1234(self, **kw): + return (200, {'snapshot': _stub_snapshot(id='1234')}) + + def put_snapshots_1234(self, **kw): + snapshot = _stub_snapshot(id='1234') + snapshot.update(kw['body']['snapshot']) + return (200, {'snapshot': snapshot}) + # - # volumes + # Volumes # + def put_volumes_1234(self, **kw): + volume = _stub_volume(id='1234') + volume.update(kw['body']['volume']) + return (200, {'volume': volume}) + def get_volumes(self, **kw): return (200, {"volumes": [ {'id': 1234, 'name': 'sample-volume'}, diff --git a/tests/v1/test_shell.py b/tests/v1/test_shell.py index 007afc73c..0bb8de8db 100644 --- a/tests/v1/test_shell.py +++ b/tests/v1/test_shell.py @@ -87,6 +87,7 @@ class ShellTest(utils.TestCase): def test_delete(self): self.run_command('delete 1234') + self.assert_called('DELETE', '/volumes/1234') def test_snapshot_list_filter_volume_id(self): self.run_command('snapshot-list --volume-id=1234') @@ -96,3 +97,46 @@ class ShellTest(utils.TestCase): self.run_command('snapshot-list --status=available --volume-id=1234') self.assert_called('GET', '/snapshots/detail?' 'status=available&volume_id=1234') + + def test_rename(self): + # basic rename with positional agruments + self.run_command('rename 1234 new-name') + expected = {'volume': {'display_name': 'new-name'}} + self.assert_called('PUT', '/volumes/1234', body=expected) + # change description only + self.run_command('rename 1234 --display-description=new-description') + expected = {'volume': {'display_description': 'new-description'}} + self.assert_called('PUT', '/volumes/1234', body=expected) + # rename and change description + self.run_command('rename 1234 new-name ' + '--display-description=new-description') + expected = {'volume': { + 'display_name': 'new-name', + 'display_description': 'new-description', + }} + self.assert_called('PUT', '/volumes/1234', body=expected) + # noop, the only all will be the lookup + self.run_command('rename 1234') + self.assert_called('GET', '/volumes/1234') + + def test_rename_snapshot(self): + # basic rename with positional agruments + self.run_command('snapshot-rename 1234 new-name') + expected = {'snapshot': {'display_name': 'new-name'}} + self.assert_called('PUT', '/snapshots/1234', body=expected) + # change description only + self.run_command('snapshot-rename 1234 ' + '--display-description=new-description') + expected = {'snapshot': {'display_description': 'new-description'}} + self.assert_called('PUT', '/snapshots/1234', body=expected) + # snapshot-rename and change description + self.run_command('snapshot-rename 1234 new-name ' + '--display-description=new-description') + expected = {'snapshot': { + 'display_name': 'new-name', + 'display_description': 'new-description', + }} + self.assert_called('PUT', '/snapshots/1234', body=expected) + # noop, the only all will be the lookup + self.run_command('snapshot-rename 1234') + self.assert_called('GET', '/snapshots/1234')