Add volume multi attach support

This patch adds the new multiattach flag during volume
creation time. This patch adds the attachment_uuid
during detach time so cinder knows which
attachment it should detach.

This patch is needed by Cinder's multi-attach-volume
https://review.openstack.org/#/c/85847/

Change-Id: I98c6150cf548e9d1d8557770dbd3f88ec17a9b41
Implements: blueprint multi-attach-volume
This commit is contained in:
Walter A. Boring IV
2014-04-07 14:55:57 -07:00
committed by Walter A. Boring IV (hemna)
parent 9cb7232655
commit 480afa893a
5 changed files with 34 additions and 14 deletions

View File

@@ -40,6 +40,7 @@ def _stub_volume(**kwargs):
"snapshot_id": None,
"status": "available",
"volume_type": "None",
"multiattach": "false",
"links": [
{
"href": "http://localhost/v2/fake/volumes/1234",
@@ -415,7 +416,7 @@ class FakeHTTPClient(base_client.HTTPClient):
assert (keys == ['instance_uuid', 'mode', 'mountpoint'] or
keys == ['host_name', 'mode', 'mountpoint'])
elif action == 'os-detach':
assert body[action] is None
assert list(body[action]) == ['attachment_id']
elif action == 'os-reserve':
assert body[action] is None
elif action == 'os-unreserve':

View File

@@ -125,7 +125,8 @@ class ShellTest(utils.TestCase):
'snapshot_id': None,
'metadata': {'key1': '"--test1"'},
'volume_type': None,
'description': None}}
'description': None,
'multiattach': False}}
self.assert_called_anytime('POST', '/volumes', expected)
def test_metadata_args_limiter_display_name(self):
@@ -145,7 +146,8 @@ class ShellTest(utils.TestCase):
'snapshot_id': None,
'metadata': {'key1': '"--t1"'},
'volume_type': None,
'description': None}}
'description': None,
'multiattach': False}}
self.assert_called_anytime('POST', '/volumes', expected)
def test_delimit_metadata_args(self):
@@ -165,7 +167,8 @@ class ShellTest(utils.TestCase):
'metadata': {'key1': '"test1"',
'key2': '"test2"'},
'volume_type': None,
'description': None}}
'description': None,
'multiattach': False}}
self.assert_called_anytime('POST', '/volumes', expected)
def test_delimit_metadata_args_display_name(self):
@@ -185,7 +188,8 @@ class ShellTest(utils.TestCase):
'snapshot_id': None,
'metadata': {'key1': '"t1"'},
'volume_type': None,
'description': None}}
'description': None,
'multiattach': False}}
self.assert_called_anytime('POST', '/volumes', expected)
def test_list_filter_status(self):

View File

@@ -95,7 +95,8 @@ class VolumesTest(utils.TestCase):
'project_id': None,
'metadata': {},
'source_replica': None,
'consistencygroup_id': None},
'consistencygroup_id': None,
'multiattach': False},
'OS-SCH-HNT:scheduler_hints': 'uuid'}
cs.assert_called('POST', '/volumes', body=expected)
@@ -111,7 +112,7 @@ class VolumesTest(utils.TestCase):
def test_detach(self):
v = cs.volumes.get('1234')
cs.volumes.detach(v)
cs.volumes.detach(v, 'abc123')
cs.assert_called('POST', '/volumes/1234/action')
def test_reserve(self):

View File

@@ -234,10 +234,12 @@ def do_list(cs, args):
if all_tenants:
key_list = ['ID', 'Tenant ID', 'Status', 'Name',
'Size', 'Volume Type', 'Bootable', 'Attached to']
'Size', 'Volume Type', 'Bootable', 'Multiattach',
'Attached to']
else:
key_list = ['ID', 'Status', 'Name',
'Size', 'Volume Type', 'Bootable', 'Attached to']
'Size', 'Volume Type', 'Bootable',
'Multiattach', 'Attached to']
if args.sort_key or args.sort_dir or args.sort:
sortby_index = None
else:
@@ -348,6 +350,12 @@ class CheckSizeArgForCreate(argparse.Action):
action='append',
default=[],
help='Scheduler hint, like in nova.')
@utils.arg('--allow-multiattach',
dest='multiattach',
action="store_true",
help=('Allow volume to be attached more than once.'
' Default=False'),
default=False)
@utils.service_type('volumev2')
def do_create(cs, args):
"""Creates a volume."""
@@ -391,7 +399,8 @@ def do_create(cs, args):
imageRef=image_ref,
metadata=volume_metadata,
scheduler_hints=hints,
source_replica=args.source_replica)
source_replica=args.source_replica,
multiattach=args.multiattach)
info = dict()
volume = cs.volumes.get(volume.id)

View File

@@ -179,8 +179,8 @@ class VolumeManager(base.ManagerWithFind):
volume_type=None, user_id=None,
project_id=None, availability_zone=None,
metadata=None, imageRef=None, scheduler_hints=None,
source_replica=None):
"""Creates a volume.
source_replica=None, multiattach=False):
"""Create a volume.
:param size: Size of volume in GB
:param consistencygroup_id: ID of the consistencygroup
@@ -197,6 +197,8 @@ class VolumeManager(base.ManagerWithFind):
:param source_replica: ID of source volume to clone replica
:param scheduler_hints: (optional extension) arbitrary key-value pairs
specified by the client to help boot an instance
:param multiattach: Allow the volume to be attached to more than
one instance
:rtype: :class:`Volume`
"""
if metadata is None:
@@ -219,6 +221,7 @@ class VolumeManager(base.ManagerWithFind):
'imageRef': imageRef,
'source_volid': source_volid,
'source_replica': source_replica,
'multiattach': multiattach,
}}
if scheduler_hints:
@@ -393,13 +396,15 @@ class VolumeManager(base.ManagerWithFind):
body.update({'host_name': host_name})
return self._action('os-attach', volume, body)
def detach(self, volume):
def detach(self, volume, attachment_uuid=None):
"""Clear attachment metadata.
:param volume: The :class:`Volume` (or its ID)
you would like to detach.
:param attachment_uuid: The uuid of the volume attachment.
"""
return self._action('os-detach', volume)
return self._action('os-detach', volume,
{'attachment_id': attachment_uuid})
def reserve(self, volume):
"""Reserve this volume.