From e1ff87378a8a7b9c00eb7cf75a24c5a442d92217 Mon Sep 17 00:00:00 2001 From: Tomoki Sekiyama Date: Tue, 31 Mar 2015 18:30:14 -0400 Subject: [PATCH] Support host-attach of volumes This patch adds the host_name optional argument to attach API in order to enable users of cinderclient to attach volumes not only to the instances but also to the hosts. The API interface is implemented in https://review.openstack.org/#/c/34125/ . Change-Id: I0ff8ef19d1e3073fee1b9ec0f60609c37dfab9ab Implements: blueprint host-attach --- cinderclient/tests/unit/v1/fakes.py | 6 ++--- cinderclient/tests/unit/v1/test_volumes.py | 5 +++++ cinderclient/tests/unit/v2/fakes.py | 6 ++--- cinderclient/tests/unit/v2/test_volumes.py | 5 +++++ cinderclient/v1/volumes.py | 26 +++++++++++++--------- cinderclient/v2/volumes.py | 25 ++++++++++++--------- 6 files changed, 47 insertions(+), 26 deletions(-) diff --git a/cinderclient/tests/unit/v1/fakes.py b/cinderclient/tests/unit/v1/fakes.py index e391dc927..35043d2c1 100644 --- a/cinderclient/tests/unit/v1/fakes.py +++ b/cinderclient/tests/unit/v1/fakes.py @@ -330,9 +330,9 @@ class FakeHTTPClient(base_client.HTTPClient): assert len(list(body)) == 1 action = list(body)[0] if action == 'os-attach': - assert sorted(list(body[action])) == ['instance_uuid', - 'mode', - 'mountpoint'] + keys = sorted(list(body[action])) + assert (keys == ['instance_uuid', 'mode', 'mountpoint'] or + keys == ['host_name', 'mode', 'mountpoint']) elif action == 'os-detach': assert body[action] is None elif action == 'os-reserve': diff --git a/cinderclient/tests/unit/v1/test_volumes.py b/cinderclient/tests/unit/v1/test_volumes.py index 75c81bd5f..8906a4eba 100644 --- a/cinderclient/tests/unit/v1/test_volumes.py +++ b/cinderclient/tests/unit/v1/test_volumes.py @@ -38,6 +38,11 @@ class VolumesTest(utils.TestCase): cs.volumes.attach(v, 1, '/dev/vdc', mode='rw') cs.assert_called('POST', '/volumes/1234/action') + def test_attach_to_host(self): + v = cs.volumes.get('1234') + cs.volumes.attach(v, None, None, host_name='test', mode='rw') + cs.assert_called('POST', '/volumes/1234/action') + def test_detach(self): v = cs.volumes.get('1234') cs.volumes.detach(v) diff --git a/cinderclient/tests/unit/v2/fakes.py b/cinderclient/tests/unit/v2/fakes.py index 82cdc9c57..a9e404143 100644 --- a/cinderclient/tests/unit/v2/fakes.py +++ b/cinderclient/tests/unit/v2/fakes.py @@ -411,9 +411,9 @@ class FakeHTTPClient(base_client.HTTPClient): assert len(list(body)) == 1 action = list(body)[0] if action == 'os-attach': - assert sorted(list(body[action])) == ['instance_uuid', - 'mode', - 'mountpoint'] + keys = sorted(list(body[action])) + assert (keys == ['instance_uuid', 'mode', 'mountpoint'] or + keys == ['host_name', 'mode', 'mountpoint']) elif action == 'os-detach': assert body[action] is None elif action == 'os-reserve': diff --git a/cinderclient/tests/unit/v2/test_volumes.py b/cinderclient/tests/unit/v2/test_volumes.py index d94b47187..8ddb59ed8 100644 --- a/cinderclient/tests/unit/v2/test_volumes.py +++ b/cinderclient/tests/unit/v2/test_volumes.py @@ -104,6 +104,11 @@ class VolumesTest(utils.TestCase): cs.volumes.attach(v, 1, '/dev/vdc', mode='ro') cs.assert_called('POST', '/volumes/1234/action') + def test_attach_to_host(self): + v = cs.volumes.get('1234') + cs.volumes.attach(v, None, None, host_name='test', mode='rw') + cs.assert_called('POST', '/volumes/1234/action') + def test_detach(self): v = cs.volumes.get('1234') cs.volumes.detach(v) diff --git a/cinderclient/v1/volumes.py b/cinderclient/v1/volumes.py index 3ef3181c2..22cf5aad2 100644 --- a/cinderclient/v1/volumes.py +++ b/cinderclient/v1/volumes.py @@ -40,14 +40,17 @@ class Volume(base.Resource): """Update the display_name or display_description for this volume.""" self.manager.update(self, **kwargs) - def attach(self, instance_uuid, mountpoint, mode='rw'): + def attach(self, instance_uuid, mountpoint, mode='rw', + host_name=None): """Set attachment metadata. :param instance_uuid: uuid of the attaching instance. - :param mountpoint: mountpoint on the attaching instance. + :param mountpoint: mountpoint on the attaching instance or host. :param mode: the access mode + :param host_name: name of the attaching host. """ - return self.manager.attach(self, instance_uuid, mountpoint, mode) + return self.manager.attach(self, instance_uuid, mountpoint, mode, + host_name) def detach(self): """Clear attachment metadata.""" @@ -255,21 +258,24 @@ class VolumeManager(base.ManagerWithFind): url = '/volumes/%s/action' % base.getid(volume) return self.api.client.post(url, body=body) - def attach(self, volume, instance_uuid, mountpoint, mode='rw'): + def attach(self, volume, instance_uuid, mountpoint, mode='rw', + host_name=None): """ Set attachment metadata. :param volume: The :class:`Volume` (or its ID) you would like to attach. - :param instance_uuid: uuid of the attaching instance. + :param instance_uuid: uuid of the attaching instance or host. :param mountpoint: mountpoint on the attaching instance. :param mode: the access mode. + :param host_name: name of the attaching host. """ - return self._action('os-attach', - volume, - {'instance_uuid': instance_uuid, - 'mountpoint': mountpoint, - 'mode': mode}) + body = {'mountpoint': mountpoint, 'mode': mode} + if instance_uuid is not None: + body.update({'instance_uuid': instance_uuid}) + if host_name is not None: + body.update({'host_name': host_name}) + return self._action('os-attach', volume, body) def detach(self, volume): """ diff --git a/cinderclient/v2/volumes.py b/cinderclient/v2/volumes.py index 28e812954..e2e5368b6 100644 --- a/cinderclient/v2/volumes.py +++ b/cinderclient/v2/volumes.py @@ -45,14 +45,16 @@ class Volume(base.Resource): """Update the name or description for this volume.""" self.manager.update(self, **kwargs) - def attach(self, instance_uuid, mountpoint, mode='rw'): + def attach(self, instance_uuid, mountpoint, mode='rw', host_name=None): """Set attachment metadata. :param instance_uuid: uuid of the attaching instance. - :param mountpoint: mountpoint on the attaching instance. + :param mountpoint: mountpoint on the attaching instance or host. :param mode: the access mode. + :param host_name: name of the attaching host. """ - return self.manager.attach(self, instance_uuid, mountpoint, mode) + return self.manager.attach(self, instance_uuid, mountpoint, mode, + host_name) def detach(self): """Clear attachment metadata.""" @@ -374,20 +376,23 @@ class VolumeManager(base.ManagerWithFind): url = '/volumes/%s/action' % base.getid(volume) return self.api.client.post(url, body=body) - def attach(self, volume, instance_uuid, mountpoint, mode='rw'): + def attach(self, volume, instance_uuid, mountpoint, mode='rw', + host_name=None): """Set attachment metadata. :param volume: The :class:`Volume` (or its ID) you would like to attach. :param instance_uuid: uuid of the attaching instance. - :param mountpoint: mountpoint on the attaching instance. + :param mountpoint: mountpoint on the attaching instance or host. :param mode: the access mode. + :param host_name: name of the attaching host. """ - return self._action('os-attach', - volume, - {'instance_uuid': instance_uuid, - 'mountpoint': mountpoint, - 'mode': mode}) + body = {'mountpoint': mountpoint, 'mode': mode} + if instance_uuid is not None: + body.update({'instance_uuid': instance_uuid}) + if host_name is not None: + body.update({'host_name': host_name}) + return self._action('os-attach', volume, body) def detach(self, volume): """Clear attachment metadata.