Merge "Add patch for consistency group update in ProphetStor driver"

This commit is contained in:
Jenkins 2015-05-13 14:41:00 +00:00 committed by Gerrit Code Review
commit 88f4c0f058
2 changed files with 193 additions and 38 deletions

View File

@ -114,6 +114,15 @@ DATA_IN_VOLUME_VG = {'id': 'abc123',
'status': 'available',
'host': "hostname@backend#%s" % POOLUUID}
DATA_IN_REMOVE_VOLUME_VG = {
'id': 'fe2dbc515810451dab2f8c8a48d15bee',
'display_name': 'fe2dbc515810451dab2f8c8a48d15bee',
'display_description': '',
'size': 1,
'consistencygroup_id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee',
'status': 'available',
'host': "hostname@backend#%s" % POOLUUID}
DATA_IN_VOLUME1 = {'id': 'abc456',
'display_name': 'abc456',
'display_description': '',
@ -139,6 +148,42 @@ DATA_OUT_SNAPSHOT_CG = {
'display_description': '',
'cgsnapshot_id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee'}
DATA_OUT_CG = {
"objectType": "application/cdmi-container",
"objectID": "fe2dbc515810451dab2f8c8a48d15bee",
"objectName": "<new_volume_group_uuid>",
"parentURI": "/dpl_volgroup",
"parentID": "fe2dbc515810451dab2f8c8a48d15bee",
"domainURI": "",
"capabilitiesURI": "",
"completionStatus": "Complete",
"percentComplete": 100,
"metadata":
{
"type": "volume|snapshot|replica",
"volume_group_uuid": "<volume_group_uuid>",
"origin_uuid": "<origin_uuid>",
"snapshot_uuid": "<snapshot_uuid>",
"display_name": "<display name>",
"display_description": "<display description>",
"ctime": 12345678,
"total_capacity": 1024,
"snapshot_used_capacity": 0,
"maximum_snapshot": 1024,
"snapshot_quota": 0,
"state": "<state>",
"properties":
{
"snapshot_rotation": True,
}
},
"childrenrange": "<range>",
"children":
[
"fe2dbc515810451dab2f8c8a48d15bee",
],
}
class TestProphetStorDPLVolume(test.TestCase):
@ -290,8 +335,8 @@ class TestProphetStorDPLVolume(test.TestCase):
metadata = {}
params = {}
metadata['display_name'] = DATA_IN_SNAPSHOT['display_name']
metadata['display_description'] = \
DATA_IN_SNAPSHOT['display_description']
metadata['display_description'] = (
DATA_IN_SNAPSHOT['display_description'])
params['metadata'] = metadata
params['snapshot'] = DATA_IN_SNAPSHOT['id']
@ -640,8 +685,8 @@ class TestProphetStorDPLDriver(test.TestCase):
self.assertDictMatch({'status': 'available'}, model_update)
def test_delete_consistency_group(self):
self.DB_MOCK.volume_get_all_by_group.return_value = \
[DATA_IN_VOLUME_VG]
self.DB_MOCK.volume_get_all_by_group.return_value = (
[DATA_IN_VOLUME_VG])
self.DPL_MOCK.delete_vdev.return_value = DATA_OUTPUT
self.DPL_MOCK.delete_cg.return_value = DATA_OUTPUT
model_update, volumes = self.dpldriver.delete_consistencygroup(
@ -652,17 +697,59 @@ class TestProphetStorDPLDriver(test.TestCase):
self._conver_uuid2hex((DATA_IN_VOLUME_VG['id'])))
self.assertDictMatch({'status': 'deleted'}, model_update, )
def test_update_consistencygroup(self):
self.DPL_MOCK.get_vg.return_value = (0, DATA_OUT_CG)
self.DPL_MOCK.join_vg.return_value = DATA_OUTPUT
self.DPL_MOCK.leave_vg.return_value = DATA_OUTPUT
add_vol = DATA_IN_VOLUME_VG
remove_vol = DATA_IN_REMOVE_VOLUME_VG
(model_update, add_vols, remove_vols) = (
self.dpldriver.update_consistencygroup(self.context,
DATA_IN_GROUP,
[add_vol],
[remove_vol]))
self.DPL_MOCK.join_vg.assert_called_once_with(
self._conver_uuid2hex(add_vol['id']),
self._conver_uuid2hex(DATA_IN_GROUP['id']))
self.DPL_MOCK.leave_vg.assert_called_once_with(
self._conver_uuid2hex(remove_vol['id']),
self._conver_uuid2hex(DATA_IN_GROUP['id']))
self.assertDictMatch({'status': 'available'}, model_update)
def test_update_consistencygroup_exception_join(self):
self.DPL_MOCK.get_vg.return_value = (0, DATA_OUT_CG)
self.DPL_MOCK.join_vg.return_value = -1, None
self.DPL_MOCK.leave_vg.return_value = DATA_OUTPUT
add_vol = DATA_IN_VOLUME_VG
self.assertRaises(exception.VolumeBackendAPIException,
self.dpldriver.update_consistencygroup,
context=None,
group=DATA_IN_GROUP,
add_volumes=[add_vol],
remove_volumes=None)
def test_update_consistencygroup_exception_leave(self):
self.DPL_MOCK.get_vg.return_value = (0, DATA_OUT_CG)
self.DPL_MOCK.leave_vg.return_value = -1, None
remove_vol = DATA_IN_REMOVE_VOLUME_VG
self.assertRaises(exception.VolumeBackendAPIException,
self.dpldriver.update_consistencygroup,
context=None,
group=DATA_IN_GROUP,
add_volumes=None,
remove_volumes=[remove_vol])
def test_create_consistency_group_snapshot(self):
self.DB_MOCK.snapshot_get_all_for_cgsnapshot.return_value = \
[DATA_OUT_SNAPSHOT_CG]
self.DB_MOCK.snapshot_get_all_for_cgsnapshot.return_value = (
[DATA_OUT_SNAPSHOT_CG])
self.DPL_MOCK.create_vdev_snapshot.return_value = DATA_OUTPUT
model_update, snapshots = self.dpldriver.create_cgsnapshot(
self.context, DATA_IN_CG_SNAPSHOT)
self.assertDictMatch({'status': 'available'}, model_update)
def test_delete_consistency_group_snapshot(self):
self.DB_MOCK.snapshot_get_all_for_cgsnapshot.return_value = \
[DATA_OUT_SNAPSHOT_CG]
self.DB_MOCK.snapshot_get_all_for_cgsnapshot.return_value = (
[DATA_OUT_SNAPSHOT_CG])
self.DPL_MOCK.delete_cgsnapshot.return_value = DATA_OUTPUT
model_update, snapshots = self.dpldriver.delete_cgsnapshot(
self.context, DATA_IN_CG_SNAPSHOT)

View File

@ -16,6 +16,7 @@
Implementation of the class of ProphetStor DPL storage adapter of Federator.
# v2.0.1 Consistency group support
# v2.0.2 Pool aware scheduler
# v2.0.3 Consistency group modification support
"""
import base64
@ -158,8 +159,8 @@ class DPLCommand(object):
retcode = errno.EFAULT
break
if retcode == 0 and response.status in expected_status and\
response.status == httplib.NOT_FOUND:
if (retcode == 0 and response.status in expected_status
and response.status == httplib.NOT_FOUND):
retcode = errno.ENODATA
elif retcode == 0 and response.status not in expected_status:
LOG.error(_LE('%(method)s %(url)s unexpected response status: '
@ -188,9 +189,9 @@ class DPLCommand(object):
LOG.error(_LE('Read response raised an exception: %s.'),
e)
retcode = errno.ENOEXEC
elif retcode == 0 and \
response.status in [httplib.OK, httplib.CREATED] and \
httplib.NO_CONTENT not in expected_status:
elif (retcode == 0 and
response.status in [httplib.OK, httplib.CREATED] and
httplib.NO_CONTENT not in expected_status):
try:
data = response.read()
data = json.loads(data)
@ -682,8 +683,8 @@ class DPLVolume(object):
class DPLCOMMONDriver(driver.VolumeDriver):
"""class of dpl storage adapter."""
VERSION = '2.0.2'
"""Class of dpl storage adapter."""
VERSION = '2.0.3'
def __init__(self, *args, **kwargs):
super(DPLCOMMONDriver, self).__init__(*args, **kwargs)
@ -714,10 +715,10 @@ class DPLCOMMONDriver(driver.VolumeDriver):
ret = 0
event_uuid = ""
if type(output) is dict and \
output.get("metadata") and output["metadata"]:
if output["metadata"].get("event_uuid") and \
output["metadata"]["event_uuid"]:
if (type(output) is dict and
output.get("metadata") and output["metadata"]):
if (output["metadata"].get("event_uuid") and
output["metadata"]["event_uuid"]):
event_uuid = output["metadata"]["event_uuid"]
else:
ret = errno.EINVAL
@ -773,9 +774,8 @@ class DPLCOMMONDriver(driver.VolumeDriver):
break
return status
def _join_volume_group(self, volume):
def _join_volume_group(self, volume, cgId):
# Join volume group if consistency group id not empty
cgId = volume['consistencygroup_id']
msg = ''
try:
ret, output = self.dpl.join_vg(
@ -797,6 +797,29 @@ class DPLCOMMONDriver(driver.VolumeDriver):
'group %(cgid)s.'),
{'id': volume['id'], 'cgid': cgId})
def _leave_volume_group(self, volume, cgId):
# Leave volume group if consistency group id not empty
msg = ''
try:
ret, output = self.dpl.leave_vg(
self._conver_uuid2hex(volume['id']),
self._conver_uuid2hex(cgId))
except Exception as e:
ret = errno.EFAULT
msg = _('Fexvisor failed to remove volume %(id)s '
'due to %(reason)s.') % {"id": volume['id'],
"reason": six.text_type(e)}
if ret:
if not msg:
msg = _('Flexvisor failed to remove volume %(id)s '
'from group %(cgid)s.') % {'id': volume['id'],
'cgid': cgId}
raise exception.VolumeBackendAPIException(data=msg)
else:
LOG.info(_LI('Flexvisor succeeded to remove volume %(id)s from '
'group %(cgid)s.'),
{'id': volume['id'], 'cgid': cgId})
def _get_snapshotid_of_vgsnapshot(self, vgID, vgsnapshotID, volumeID):
snapshotID = None
ret, out = self.dpl.query_vdev_snapshot(vgID, vgsnapshotID, True)
@ -937,6 +960,51 @@ class DPLCOMMONDriver(driver.VolumeDriver):
model_update['status'] = 'deleted'
return model_update, snapshots
def update_consistencygroup(self, context, group, add_volumes=None,
remove_volumes=None):
addvollist = []
removevollist = []
cgid = group['id']
vid = ''
model_update = {'status': 'available'}
# Get current group info in backend storage.
ret, output = self.dpl.get_vg(self._conver_uuid2hex(cgid))
if ret == 0:
group_members = output.get('children', [])
if add_volumes:
addvollist = add_volumes
if remove_volumes:
removevollist = remove_volumes
# Process join volumes.
try:
for volume in addvollist:
vid = volume['id']
# Verify the volume exists in the group or not.
if self._conver_uuid2hex(vid) in group_members:
continue
self._join_volume_group(volume, cgid)
except exception as e:
msg = _("Fexvisor failed to join the volume %(vol)s in the "
"group %(group)s due to "
"%(ret)s.") % {"vol": vid, "group": cgid,
"ret": six.text_type(e)}
raise exception.VolumeBackendAPIException(data=msg)
# Process leave volumes.
try:
for volume in removevollist:
vid = volume['id']
if self._conver_uuid2hex(vid) in group_members:
self._leave_volume_group(volume, cgid)
except exception as e:
msg = _("Fexvisor failed to remove the volume %(vol)s in the "
"group %(group)s due to "
"%(ret)s.") % {"vol": vid, "group": cgid,
"ret": six.text_type(e)}
raise exception.VolumeBackendAPIException(data=msg)
return model_update, None, None
def create_volume(self, volume):
"""Create a volume."""
pool = volume_utils.extract_host(volume['host'],
@ -983,7 +1051,7 @@ class DPLCOMMONDriver(driver.VolumeDriver):
if volume.get('consistencygroup_id', None):
try:
self._join_volume_group(volume)
self._join_volume_group(volume, volume['consistencygroup_id'])
except Exception:
# Delete volume if volume failed to join group.
self.dpl.delete_vdev(self._conver_uuid2hex(volume['id']))
@ -1066,7 +1134,7 @@ class DPLCOMMONDriver(driver.VolumeDriver):
if volume.get('consistencygroup_id', None):
try:
self._join_volume_group(volume)
self._join_volume_group(volume, volume['consistencygroup_id'])
except Exception:
# Delete volume if volume failed to join group.
self.dpl.delete_vdev(self._conver_uuid2hex(volume['id']))
@ -1154,7 +1222,7 @@ class DPLCOMMONDriver(driver.VolumeDriver):
if volume.get('consistencygroup_id', None):
try:
self._join_volume_group(volume)
self._join_volume_group(volume, volume['consistencygroup_id'])
except Exception:
# Delete volume if volume failed to join group.
self.dpl.delete_vdev(self._conver_uuid2hex(volume['id']))
@ -1252,14 +1320,14 @@ class DPLCOMMONDriver(driver.VolumeDriver):
snapshot['volume_id'],
event_uuid)
if status['state'] != 'available':
msg = _('Flexvisor failed to create snapshot for volume '
'%(id)s: %(status)s.') % \
{'id': snapshot['volume_id'], 'status': ret}
msg = (_('Flexvisor failed to create snapshot for volume '
'%(id)s: %(status)s.') %
{'id': snapshot['volume_id'], 'status': ret})
raise exception.VolumeBackendAPIException(data=msg)
else:
msg = _('Flexvisor failed to create snapshot for volume '
'(failed to get event) %(id)s.') % \
{'id': snapshot['volume_id']}
msg = (_('Flexvisor failed to create snapshot for volume '
'(failed to get event) %(id)s.') %
{'id': snapshot['volume_id']})
raise exception.VolumeBackendAPIException(data=msg)
elif ret != 0:
msg = _('Flexvisor failed to create snapshot for volume %(id)s: '
@ -1334,15 +1402,15 @@ class DPLCOMMONDriver(driver.VolumeDriver):
if ret == 0:
pool = {}
pool['pool_name'] = output['metadata']['pool_uuid']
pool['total_capacity_gb'] = \
pool['total_capacity_gb'] = (
self._convert_size_GB(
int(output['metadata']['total_capacity']))
pool['free_capacity_gb'] = \
int(output['metadata']['total_capacity'])))
pool['free_capacity_gb'] = (
self._convert_size_GB(
int(output['metadata']['available_capacity']))
pool['allocated_capacity_gb'] = \
int(output['metadata']['available_capacity'])))
pool['allocated_capacity_gb'] = (
self._convert_size_GB(
int(output['metadata']['used_capacity']))
int(output['metadata']['used_capacity'])))
pool['QoS_support'] = False
pool['reserved_percentage'] = 0
pools.append(pool)
@ -1358,8 +1426,8 @@ class DPLCOMMONDriver(driver.VolumeDriver):
"""
data = {}
pools = self._get_pools()
data['volume_backend_name'] = \
self.configuration.safe_get('volume_backend_name')
data['volume_backend_name'] = (
self.configuration.safe_get('volume_backend_name'))
location_info = '%(driver)s:%(host)s:%(volume)s' % {
'driver': self.__class__.__name__,
'host': self.configuration.san_ip,