3PAR: Create consistency group from source CG

Supports creating a consistency group from a source consistency group
in the HPE 3PAR driver.

This makes use of temporary snapshots, which are not managed by Cinder.
Upon volume/CG deleteion, these temp snapshots will automatically be
cleaned up.

Change-Id: I033c2c4d45689d02dec96a0e58794629053efbc4
Implements: blueprint hpe-3par-create-cg-from-source
DocImpact
This commit is contained in:
Alex O'Rourke 2016-02-01 13:58:33 -08:00
parent 839a32ee04
commit c9e5562dfd
3 changed files with 111 additions and 25 deletions

View File

@ -91,11 +91,13 @@ class Comment(object):
class HPE3PARBaseDriver(object): class HPE3PARBaseDriver(object):
VOLUME_ID = 'd03338a9-9115-48a3-8dfc-35cdfcdc15a7' VOLUME_ID = 'd03338a9-9115-48a3-8dfc-35cdfcdc15a7'
SRC_CG_VOLUME_ID = 'bd21d11b-c765-4c68-896c-6b07f63cfcb6'
CLONE_ID = 'd03338a9-9115-48a3-8dfc-000000000000' CLONE_ID = 'd03338a9-9115-48a3-8dfc-000000000000'
VOLUME_TYPE_ID_REPLICATED = 'be9181f1-4040-46f2-8298-e7532f2bf9db' VOLUME_TYPE_ID_REPLICATED = 'be9181f1-4040-46f2-8298-e7532f2bf9db'
VOLUME_TYPE_ID_DEDUP = 'd03338a9-9115-48a3-8dfc-11111111111' VOLUME_TYPE_ID_DEDUP = 'd03338a9-9115-48a3-8dfc-11111111111'
VOLUME_TYPE_ID_FLASH_CACHE = 'd03338a9-9115-48a3-8dfc-22222222222' VOLUME_TYPE_ID_FLASH_CACHE = 'd03338a9-9115-48a3-8dfc-22222222222'
VOLUME_NAME = 'volume-' + VOLUME_ID VOLUME_NAME = 'volume-' + VOLUME_ID
SRC_CG_VOLUME_NAME = 'volume-' + SRC_CG_VOLUME_ID
VOLUME_NAME_3PAR = 'osv-0DM4qZEVSKON-DXN-NwVpw' VOLUME_NAME_3PAR = 'osv-0DM4qZEVSKON-DXN-NwVpw'
SNAPSHOT_ID = '2f823bdc-e36e-4dc8-bd15-de1c7a28ff31' SNAPSHOT_ID = '2f823bdc-e36e-4dc8-bd15-de1c7a28ff31'
SNAPSHOT_NAME = 'snapshot-2f823bdc-e36e-4dc8-bd15-de1c7a28ff31' SNAPSHOT_NAME = 'snapshot-2f823bdc-e36e-4dc8-bd15-de1c7a28ff31'
@ -104,6 +106,8 @@ class HPE3PARBaseDriver(object):
RCG_3PAR_NAME = 'rcg-0DM4qZEVSKON-DXN-N' RCG_3PAR_NAME = 'rcg-0DM4qZEVSKON-DXN-N'
CONSIS_GROUP_ID = '6044fedf-c889-4752-900f-2039d247a5df' CONSIS_GROUP_ID = '6044fedf-c889-4752-900f-2039d247a5df'
CONSIS_GROUP_NAME = 'vvs-YET.38iJR1KQDyA50kel3w' CONSIS_GROUP_NAME = 'vvs-YET.38iJR1KQDyA50kel3w'
SRC_CONSIS_GROUP_ID = '7d7dfa02-ac6e-48cb-96af-8a0cd3008d47'
SRC_CONSIS_GROUP_NAME = 'vvs-fX36AqxuSMuWr4oM0wCNRw'
CGSNAPSHOT_ID = 'e91c5ed5-daee-4e84-8724-1c9e31e7a1f2' CGSNAPSHOT_ID = 'e91c5ed5-daee-4e84-8724-1c9e31e7a1f2'
CGSNAPSHOT_BASE_NAME = 'oss-6Rxe1druToSHJByeMeeh8g' CGSNAPSHOT_BASE_NAME = 'oss-6Rxe1druToSHJByeMeeh8g'
CLIENT_ID = "12345" CLIENT_ID = "12345"
@ -148,6 +152,14 @@ class HPE3PARBaseDriver(object):
'volume_type': None, 'volume_type': None,
'volume_type_id': None} 'volume_type_id': None}
volume_src_cg = {'name': SRC_CG_VOLUME_NAME,
'id': SRC_CG_VOLUME_ID,
'display_name': 'Foo Volume',
'size': 2,
'host': FAKE_CINDER_HOST,
'volume_type': None,
'volume_type_id': None}
volume_replicated = {'name': VOLUME_NAME, volume_replicated = {'name': VOLUME_NAME,
'id': VOLUME_ID, 'id': VOLUME_ID,
'display_name': 'Foo Volume', 'display_name': 'Foo Volume',
@ -585,18 +597,20 @@ class HPE3PARBaseDriver(object):
mock.call.logout()] mock.call.logout()]
class fake_consistencygroup_object(object): class fake_consistencygroup_object(object):
volume_type_id = '49fa96b5-828e-4653-b622-873a1b7e6f1c' def __init__(self, cg_id='6044fedf-c889-4752-900f-2039d247a5df'):
name = 'cg_name' self.id = cg_id
cgsnapshot_id = None self.volume_type_id = '49fa96b5-828e-4653-b622-873a1b7e6f1c'
host = 'fakehost@foo#OpenStackCPG' self.name = 'cg_name'
id = '6044fedf-c889-4752-900f-2039d247a5df' self.cgsnapshot_id = None
description = 'consistency group' self.host = 'fakehost@foo#OpenStackCPG'
self.description = 'consistency group'
class fake_cgsnapshot_object(object): class fake_cgsnapshot_object(object):
consistencygroup_id = '6044fedf-c889-4752-900f-2039d247a5df' def __init__(self, cgsnap_id='e91c5ed5-daee-4e84-8724-1c9e31e7a1f2'):
description = 'cgsnapshot' self.id = cgsnap_id
id = 'e91c5ed5-daee-4e84-8724-1c9e31e7a1f2' self.consistencygroup_id = '6044fedf-c889-4752-900f-2039d247a5df'
readOnly = False self.description = 'cgsnapshot'
self.readOnly = False
def setup_configuration(self): def setup_configuration(self):
configuration = mock.MagicMock() configuration = mock.MagicMock()
@ -3926,6 +3940,60 @@ class HPE3PARBaseDriver(object):
expected + expected +
self.standard_logout) self.standard_logout)
def test_create_consistency_group_from_src_cg(self):
mock_client = self.setup_driver()
mock_client.getStorageSystemInfo.return_value = {'id': self.CLIENT_ID}
volume = self.volume
source_volume = self.volume_src_cg
cgsnap_optional = (
{'expirationHours': 1})
cg_comment = Comment({
'display_name': 'cg_name',
'consistency_group_id': self.CONSIS_GROUP_ID,
'description': 'consistency group'})
with mock.patch.object(hpecommon.HPE3PARCommon,
'_create_client') as mock_create_client:
mock_create_client.return_value = mock_client
mock_client.getCPG.return_value = {'domain': None}
group = self.fake_consistencygroup_object()
source_group = self.fake_consistencygroup_object(
cg_id=self.SRC_CONSIS_GROUP_ID)
expected = [
mock.call.getCPG(HPE3PAR_CPG),
mock.call.createVolumeSet(
self.CONSIS_GROUP_NAME,
domain=None,
comment=cg_comment),
mock.call.createSnapshotOfVolumeSet(
mock.ANY,
self.SRC_CONSIS_GROUP_NAME,
optional=cgsnap_optional),
mock.call.copyVolume(
mock.ANY,
self.VOLUME_NAME_3PAR,
HPE3PAR_CPG,
{'snapCPG': HPE3PAR_CPG, 'online': True}),
mock.call.addVolumeToVolumeSet(
self.CONSIS_GROUP_NAME,
self.VOLUME_NAME_3PAR)]
# Create a consistency group from a source consistency group.
self.driver.create_consistencygroup_from_src(
context.get_admin_context(), group,
[volume], source_cg=source_group,
source_vols=[source_volume])
mock_client.assert_has_calls(
self.get_id_login +
self.standard_logout +
self.standard_login +
expected +
self.standard_logout)
def test_delete_consistency_group(self): def test_delete_consistency_group(self):
mock_client = self.setup_driver() mock_client = self.setup_driver()
mock_client.getStorageSystemInfo.return_value = {'id': self.CLIENT_ID} mock_client.getStorageSystemInfo.return_value = {'id': self.CLIENT_ID}

View File

@ -225,10 +225,11 @@ class HPE3PARCommon(object):
3.0.10 - Added additional volumes checks to the manage snapshot API 3.0.10 - Added additional volumes checks to the manage snapshot API
3.0.11 - Fix the image cache capability bug #1491088 3.0.11 - Fix the image cache capability bug #1491088
3.0.12 - Remove client version checks for replication 3.0.12 - Remove client version checks for replication
3.0.13 - Support creating a cg from a source cg
""" """
VERSION = "3.0.12" VERSION = "3.0.13"
stats = {} stats = {}
@ -512,22 +513,35 @@ class HPE3PARCommon(object):
cgsnapshot=None, snapshots=None, cgsnapshot=None, snapshots=None,
source_cg=None, source_vols=None): source_cg=None, source_vols=None):
if cgsnapshot and snapshots:
self.create_consistencygroup(context, group) self.create_consistencygroup(context, group)
vvs_name = self._get_3par_vvs_name(group.id) vvs_name = self._get_3par_vvs_name(group.id)
if cgsnapshot and snapshots:
cgsnap_name = self._get_3par_snap_name(cgsnapshot.id) cgsnap_name = self._get_3par_snap_name(cgsnapshot.id)
for i, (volume, snapshot) in enumerate(zip(volumes, snapshots)): snap_base = cgsnap_name
snap_name = cgsnap_name + "-" + six.text_type(i) elif source_cg and source_vols:
cg_id = source_cg.id
# Create a brand new uuid for the temp snap.
snap_uuid = uuid.uuid4().hex
# Create a temporary snapshot of the volume set in order to
# perform an online copy. These temp snapshots will be deleted
# when the source consistency group is deleted.
temp_snap = self._get_3par_snap_name(snap_uuid, temp_snap=True)
snap_shot_name = temp_snap + "-@count@"
copy_of_name = self._get_3par_vvs_name(cg_id)
optional = {'expirationHours': 1}
self.client.createSnapshotOfVolumeSet(snap_shot_name, copy_of_name,
optional=optional)
snap_base = temp_snap
for i, volume in enumerate(volumes):
snap_name = snap_base + "-" + six.text_type(i)
volume_name = self._get_3par_vol_name(volume['id']) volume_name = self._get_3par_vol_name(volume['id'])
type_info = self.get_volume_settings_from_type(volume) type_info = self.get_volume_settings_from_type(volume)
cpg = type_info['cpg'] cpg = type_info['cpg']
optional = {'online': True, 'snapCPG': cpg} optional = {'online': True, 'snapCPG': cpg}
self.client.copyVolume(snap_name, volume_name, cpg, optional) self.client.copyVolume(snap_name, volume_name, cpg, optional)
self.client.addVolumeToVolumeSet(vvs_name, volume_name) self.client.addVolumeToVolumeSet(vvs_name, volume_name)
else:
msg = _("create_consistencygroup_from_src only supports a"
" cgsnapshot source, other sources cannot be used.")
raise exception.InvalidInput(reason=msg)
return None, None return None, None

View File

@ -0,0 +1,4 @@
---
features:
- Added support for creating a consistency group from a source consistency group
in the HPE 3PAR driver.