class HPE3PARBaseDriver(object):
VOLUME_ID = 'd03338a9-9115-48a3-8dfc-35cdfcdc15a7'
+ SRC_CG_VOLUME_ID = 'bd21d11b-c765-4c68-896c-6b07f63cfcb6'
CLONE_ID = 'd03338a9-9115-48a3-8dfc-000000000000'
VOLUME_TYPE_ID_REPLICATED = 'be9181f1-4040-46f2-8298-e7532f2bf9db'
VOLUME_TYPE_ID_DEDUP = 'd03338a9-9115-48a3-8dfc-11111111111'
VOLUME_TYPE_ID_FLASH_CACHE = 'd03338a9-9115-48a3-8dfc-22222222222'
VOLUME_NAME = 'volume-' + VOLUME_ID
+ SRC_CG_VOLUME_NAME = 'volume-' + SRC_CG_VOLUME_ID
VOLUME_NAME_3PAR = 'osv-0DM4qZEVSKON-DXN-NwVpw'
SNAPSHOT_ID = '2f823bdc-e36e-4dc8-bd15-de1c7a28ff31'
SNAPSHOT_NAME = 'snapshot-2f823bdc-e36e-4dc8-bd15-de1c7a28ff31'
RCG_3PAR_NAME = 'rcg-0DM4qZEVSKON-DXN-N'
CONSIS_GROUP_ID = '6044fedf-c889-4752-900f-2039d247a5df'
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_BASE_NAME = 'oss-6Rxe1druToSHJByeMeeh8g'
CLIENT_ID = "12345"
'volume_type': 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,
'id': VOLUME_ID,
'display_name': 'Foo Volume',
mock.call.logout()]
class fake_consistencygroup_object(object):
- volume_type_id = '49fa96b5-828e-4653-b622-873a1b7e6f1c'
- name = 'cg_name'
- cgsnapshot_id = None
- host = 'fakehost@foo#OpenStackCPG'
- id = '6044fedf-c889-4752-900f-2039d247a5df'
- description = 'consistency group'
+ def __init__(self, cg_id='6044fedf-c889-4752-900f-2039d247a5df'):
+ self.id = cg_id
+ self.volume_type_id = '49fa96b5-828e-4653-b622-873a1b7e6f1c'
+ self.name = 'cg_name'
+ self.cgsnapshot_id = None
+ self.host = 'fakehost@foo#OpenStackCPG'
+ self.description = 'consistency group'
class fake_cgsnapshot_object(object):
- consistencygroup_id = '6044fedf-c889-4752-900f-2039d247a5df'
- description = 'cgsnapshot'
- id = 'e91c5ed5-daee-4e84-8724-1c9e31e7a1f2'
- readOnly = False
+ def __init__(self, cgsnap_id='e91c5ed5-daee-4e84-8724-1c9e31e7a1f2'):
+ self.id = cgsnap_id
+ self.consistencygroup_id = '6044fedf-c889-4752-900f-2039d247a5df'
+ self.description = 'cgsnapshot'
+ self.readOnly = False
def setup_configuration(self):
configuration = mock.MagicMock()
expected +
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):
mock_client = self.setup_driver()
mock_client.getStorageSystemInfo.return_value = {'id': self.CLIENT_ID}
3.0.10 - Added additional volumes checks to the manage snapshot API
3.0.11 - Fix the image cache capability bug #1491088
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 = {}
cgsnapshot=None, snapshots=None,
source_cg=None, source_vols=None):
+ self.create_consistencygroup(context, group)
+ vvs_name = self._get_3par_vvs_name(group.id)
if cgsnapshot and snapshots:
- self.create_consistencygroup(context, group)
- vvs_name = self._get_3par_vvs_name(group.id)
cgsnap_name = self._get_3par_snap_name(cgsnapshot.id)
- for i, (volume, snapshot) in enumerate(zip(volumes, snapshots)):
- snap_name = cgsnap_name + "-" + six.text_type(i)
- volume_name = self._get_3par_vol_name(volume['id'])
- type_info = self.get_volume_settings_from_type(volume)
- cpg = type_info['cpg']
- optional = {'online': True, 'snapCPG': cpg}
- self.client.copyVolume(snap_name, volume_name, cpg, optional)
- 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)
+ snap_base = cgsnap_name
+ 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'])
+ type_info = self.get_volume_settings_from_type(volume)
+ cpg = type_info['cpg']
+ optional = {'online': True, 'snapCPG': cpg}
+ self.client.copyVolume(snap_name, volume_name, cpg, optional)
+ self.client.addVolumeToVolumeSet(vvs_name, volume_name)
return None, None