Add client work for new cinder extensions.

* #5 of blueprint volume-decoupling
 * Fix pep8

Change-Id: Icad4eada0cf16a0f49d9a52e593bede0fc0c5289
This commit is contained in:
Anthony Young
2012-05-31 14:47:30 -07:00
parent 7816b3dc31
commit 12d162d0ee
3 changed files with 190 additions and 0 deletions

View File

@@ -33,6 +33,49 @@ class Volume(base.Resource):
"""
self.manager.delete(self)
def attach(self, instance_uuid, mountpoint):
"""
Set attachment metadata.
:param instance_uuid: uuid of the attaching instance.
:param mountpoint: mountpoint on the attaching instance.
"""
return self.manager.attach(self, instance_uuid, mountpoint)
def detach(self):
"""
Clear attachment metadata.
"""
return self.manager.detach(self)
def reserve(self, volume):
"""
Reserve this volume.
"""
return self.manager.reserve(self)
def unreserve(self, volume):
"""
Unreserve this volume.
"""
return self.manager.unreserve(self)
def initialize_connection(self, volume, connector):
"""
Initialize a volume connection.
:param connector: connector dict from nova.
"""
return self.manager.initialize_connection(self, connector)
def terminate_connection(self, volume, connector):
"""
Terminate a volume connection.
:param connector: connector dict from nova.
"""
return self.manager.terminate_connection(self, connector)
class VolumeManager(base.ManagerWithFind):
"""
@@ -133,3 +176,73 @@ class VolumeManager(base.ManagerWithFind):
"""
self._delete("/servers/%s/os-volume_attachments/%s" %
(server_id, attachment_id,))
def _action(self, action, volume, info=None, **kwargs):
"""
Perform a volume "action."
"""
body = {action: info}
self.run_hooks('modify_body_for_action', body, **kwargs)
url = '/volumes/%s/action' % base.getid(volume)
return self.api.client.post(url, body=body)
def attach(self, volume, instance_uuid, mountpoint):
"""
Set attachment metadata.
:param server: 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.
"""
return self._action('os-attach',
volume,
{'instance_uuid': instance_uuid,
'mountpoint': mountpoint})
def detach(self, volume):
"""
Clear attachment metadata.
:param server: The :class:`Volume` (or its ID)
you would like to detach.
"""
return self._action('os-detach', volume)
def reserve(self, volume):
"""
Reserve this volume.
:param server: The :class:`Volume` (or its ID)
you would like to reserve.
"""
return self._action('os-reserve', volume)
def unreserve(self, volume):
"""
Unreserve this volume.
:param server: The :class:`Volume` (or its ID)
you would like to unreserve.
"""
return self._action('os-unreserve', volume)
def initialize_connection(self, volume, connector):
"""
Initialize a volume connection.
:param server: The :class:`Volume` (or its ID).
:param connector: connector dict from nova.
"""
return self._action('os-initialize_connection', volume,
{'connector': connector})[1]['connection_info']
def terminate_connection(self, volume, connector):
"""
Terminate a volume connection.
:param server: The :class:`Volume` (or its ID).
:param connector: connector dict from nova.
"""
self._action('os-terminate_connection', volume,
{'connector': connector})

View File

@@ -145,6 +145,28 @@ class FakeHTTPClient(base_client.HTTPClient):
r = {'volume': self.get_volumes_detail()[1]['volumes'][0]}
return (200, r)
def post_volumes_1234_action(self, body, **kw):
_body = None
resp = 202
assert len(body.keys()) == 1
action = body.keys()[0]
if action == 'os-attach':
assert body[action].keys() == ['instance_uuid', 'mountpoint']
elif action == 'os-detach':
assert body[action] == None
elif action == 'os-reserve':
assert body[action] == None
elif action == 'os-unreserve':
assert body[action] == None
elif action == 'os-initialize_connection':
assert body[action].keys() == ['connector']
return (202, {'connection_info': 'foos'})
elif action == 'os-terminate_connection':
assert body[action].keys() == ['connector']
else:
raise AssertionError("Unexpected server action: %s" % action)
return (resp, _body)
def post_servers(self, body, **kw):
assert set(body.keys()) <= set(['server', 'os:scheduler_hints'])
fakes.assert_has_keys(body['server'],
@@ -168,6 +190,9 @@ class FakeHTTPClient(base_client.HTTPClient):
fakes.assert_has_keys(body['server'], optional=['name', 'adminPass'])
return (204, None)
def post_volumes(self, **kw):
return (202, {'volume': {}})
def delete_servers_1234(self, **kw):
return (202, None)

52
tests/v1/test_volumes.py Normal file
View File

@@ -0,0 +1,52 @@
from cinderclient.v1 import volumes
from tests import utils
from tests.v1 import fakes
cs = fakes.FakeClient()
class VolumesTest(utils.TestCase):
def test_delete_volume(self):
v = cs.volumes.list()[0]
v.delete()
cs.assert_called('DELETE', '/volumes/1234')
cs.volumes.delete('1234')
cs.assert_called('DELETE', '/volumes/1234')
cs.volumes.delete(v)
cs.assert_called('DELETE', '/volumes/1234')
def test_create_keypair(self):
kp = cs.volumes.create(1)
cs.assert_called('POST', '/volumes')
def test_attach(self):
v = cs.volumes.get('1234')
cs.volumes.attach(v, 1, '/dev/vdc')
cs.assert_called('POST', '/volumes/1234/action')
def test_detach(self):
v = cs.volumes.get('1234')
cs.volumes.detach(v)
cs.assert_called('POST', '/volumes/1234/action')
def test_reserve(self):
v = cs.volumes.get('1234')
cs.volumes.reserve(v)
cs.assert_called('POST', '/volumes/1234/action')
def test_unreserve(self):
v = cs.volumes.get('1234')
cs.volumes.reserve(v)
cs.assert_called('POST', '/volumes/1234/action')
def test_initialize_connection(self):
v = cs.volumes.get('1234')
cs.volumes.initialize_connection(v, {})
cs.assert_called('POST', '/volumes/1234/action')
def test_terminate_connection(self):
v = cs.volumes.get('1234')
cs.volumes.terminate_connection(v, {})
cs.assert_called('POST', '/volumes/1234/action')