HPE 3PAR: Adds CG capability in generic volume groups(GVG).

This supports following functionality:
* Create consistent group using GVG APIs
* Delete consistent group using GVG APIs
* Create consistent group snapshot using GVG APIs
* Delete consistent group snapshot using GVG APIs
* Update (add/remove) volume from a group using GVG APIs
* Create group from a source using GVG APIs, where source can be a
  group or a snapshot of a group

Change-Id: I00cc28edec612f401002da5773d11917700db2ab
Implements: blueprint add-hpe3par-cg-capability-to-gvg
This commit is contained in:
swapnil-nilangekar 2017-04-07 08:17:20 -06:00
parent ff2cba6a4f
commit fadefc8206
5 changed files with 319 additions and 218 deletions

View File

@ -110,7 +110,7 @@ class HPE3PARBaseDriver(object):
VOLUME_3PAR_NAME = 'osv-0DM4qZEVSKON-DXN-NwVpw'
SNAPSHOT_3PAR_NAME = 'oss-L4I73ONuTci9Fd4ceij-MQ'
RCG_3PAR_NAME = 'rcg-0DM4qZEVSKON-DXN-N'
CONSIS_GROUP_ID = '6044fedf-c889-4752-900f-2039d247a5df'
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'
@ -613,20 +613,31 @@ class HPE3PARBaseDriver(object):
standard_logout = [
mock.call.logout()]
class fake_consistencygroup_object(object):
def __init__(self, cg_id='6044fedf-c889-4752-900f-2039d247a5df'):
self.id = cg_id
self.volume_type_id = '49fa96b5-828e-4653-b622-873a1b7e6f1c'
class fake_volume_object(object):
def __init__(self, vol_id='d03338a9-9115-48a3-8dfc-35cdfcdc15a7'):
self.id = vol_id
self.name = 'volume-d03338a9-9115-48a3-8dfc-35cdfcdc15a7'
self.display_name = 'Foo Volume'
self.size = 2
self.host = 'fakehost@foo#OpenStackCPG'
self.volume_type = None
self.volume_type_id = None
class fake_group_object(object):
def __init__(self, grp_id='6044fedf-c889-4752-900f-2039d247a5df'):
self.id = grp_id
self.volume_type_ids = ['d03338a9-9115-48a3-8dfc-33333333333']
self.volume_types = ['d03338a9-9115-48a3-8dfc-33333333333']
self.name = 'cg_name'
self.cgsnapshot_id = None
self.group_snapshot_id = None
self.host = 'fakehost@foo#OpenStackCPG'
self.description = 'consistency group'
class fake_cgsnapshot_object(object):
class fake_group_snapshot_object(object):
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.group_id = '6044fedf-c889-4752-900f-2039d247a5df'
self.description = 'group_snapshot'
self.readOnly = False
def setup_configuration(self):
@ -4112,22 +4123,26 @@ class HPE3PARBaseDriver(object):
safe_host = common._safe_hostname(long_hostname)
self.assertEqual(fixed_hostname, safe_host)
def test_create_consistency_group(self):
@mock.patch('cinder.volume.drivers.hpe.hpe_3par_common.HPE3PARCommon.'
'is_volume_group_snap_type')
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_group(self, cg_ss_enable, vol_ss_enable):
cg_ss_enable.return_value = True
vol_ss_enable.return_value = True
mock_client = self.setup_driver()
mock_client.getStorageSystemInfo.return_value = {'id': self.CLIENT_ID}
comment = Comment({
'consistency_group_id': self.CONSIS_GROUP_ID
'group_id': self.GROUP_ID
})
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}
# create a consistency group
group = self.fake_consistencygroup_object()
self.driver.create_consistencygroup(context.get_admin_context(),
group)
# create a group
group = self.fake_group_object()
self.driver.create_group(context.get_admin_context(), group)
expected = [
mock.call.getCPG(HPE3PAR_CPG),
@ -4143,23 +4158,38 @@ class HPE3PARBaseDriver(object):
expected +
self.standard_logout)
def test_create_consistency_group_from_src(self):
@mock.patch('cinder.volume.drivers.hpe.hpe_3par_common.HPE3PARCommon.'
'get_volume_settings_from_type')
@mock.patch('cinder.volume.drivers.hpe.hpe_3par_common.HPE3PARCommon.'
'is_volume_group_snap_type')
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_group_from_src(self, cg_ss_enable, vol_ss_enable,
typ_info):
cg_ss_enable.return_value = True
vol_ss_enable.return_value = True
mock_client = self.setup_driver()
mock_client.getStorageSystemInfo.return_value = {'id': self.CLIENT_ID}
volume = self.volume
volume = self.fake_volume_object()
type_info = {'cpg': 'OpenStackCPG',
'tpvv': True,
'tdvv': False,
'snap_cpg': 'OpenStackCPG',
'hpe3par_keys': {}}
cgsnap_comment = Comment({
"consistency_group_id": "6044fedf-c889-4752-900f-2039d247a5df",
"description": "cgsnapshot",
"cgsnapshot_id": "e91c5ed5-daee-4e84-8724-1c9e31e7a1f2",
typ_info.return_value = type_info
group_snap_comment = Comment({
"group_id": "6044fedf-c889-4752-900f-2039d247a5df",
"description": "group_snapshot",
"group_snapshot_id": "e91c5ed5-daee-4e84-8724-1c9e31e7a1f2",
})
cgsnap_optional = (
{'comment': cgsnap_comment,
group_snap_optional = (
{'comment': group_snap_comment,
'readOnly': False})
cg_comment = Comment({
'consistency_group_id': self.CONSIS_GROUP_ID
group_comment = Comment({
'group_id': self.GROUP_ID
})
with mock.patch.object(hpecommon.HPE3PARCommon,
@ -4168,16 +4198,15 @@ class HPE3PARBaseDriver(object):
mock_client.getCPG.return_value = {'domain': None}
# create a consistency group
group = self.fake_consistencygroup_object()
self.driver.create_consistencygroup(context.get_admin_context(),
group)
group = self.fake_group_object()
self.driver.create_group(context.get_admin_context(), group)
expected = [
mock.call.getCPG(HPE3PAR_CPG),
mock.call.createVolumeSet(
self.CONSIS_GROUP_NAME,
domain=None,
comment=cg_comment)]
comment=group_comment)]
mock_client.assert_has_calls(
self.get_id_login +
@ -4188,10 +4217,8 @@ class HPE3PARBaseDriver(object):
mock_client.reset_mock()
# add a volume to the consistency group
self.driver.update_consistencygroup(context.get_admin_context(),
group,
add_volumes=[volume],
remove_volumes=[])
self.driver.update_group(context.get_admin_context(), group,
add_volumes=[volume], remove_volumes=[])
expected = [
mock.call.addVolumeToVolumeSet(
@ -4207,20 +4234,20 @@ class HPE3PARBaseDriver(object):
mock_client.reset_mock()
# create a snapshot of the consistency group
cgsnapshot = self.fake_cgsnapshot_object()
self.driver.create_cgsnapshot(context.get_admin_context(),
cgsnapshot, [])
grp_snapshot = self.fake_group_snapshot_object()
self.driver.create_group_snapshot(context.get_admin_context(),
grp_snapshot, [])
expected = [
mock.call.createSnapshotOfVolumeSet(
self.CGSNAPSHOT_BASE_NAME + "-@count@",
self.CONSIS_GROUP_NAME,
optional=cgsnap_optional)]
optional=group_snap_optional)]
# create a consistency group from the cgsnapshot
self.driver.create_consistencygroup_from_src(
self.driver.create_group_from_src(
context.get_admin_context(), group,
[volume], cgsnapshot=cgsnapshot,
[volume], group_snapshot=grp_snapshot,
snapshots=[self.snapshot])
mock_client.assert_has_calls(
@ -4230,37 +4257,52 @@ class HPE3PARBaseDriver(object):
expected +
self.standard_logout)
def test_create_consistency_group_from_src_cg(self):
@mock.patch('cinder.volume.drivers.hpe.hpe_3par_common.HPE3PARCommon.'
'get_volume_settings_from_type')
@mock.patch('cinder.volume.drivers.hpe.hpe_3par_common.HPE3PARCommon.'
'is_volume_group_snap_type')
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_group_from_src_group(self, cg_ss_enable, vol_ss_enable,
typ_info):
cg_ss_enable.return_value = True
vol_ss_enable.return_value = True
mock_client = self.setup_driver()
mock_client.getStorageSystemInfo.return_value = {'id': self.CLIENT_ID}
volume = self.volume
volume = self.fake_volume_object()
type_info = {'cpg': 'OpenStackCPG',
'tpvv': True,
'tdvv': False,
'snap_cpg': 'OpenStackCPG',
'hpe3par_keys': {}}
typ_info.return_value = type_info
source_volume = self.volume_src_cg
cgsnap_optional = (
group_snap_optional = (
{'expirationHours': 1})
cg_comment = Comment({
'consistency_group_id': self.CONSIS_GROUP_ID
group_comment = Comment({
'group_id': self.GROUP_ID
})
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)
group = self.fake_group_object()
source_grp = self.fake_group_object(
grp_id=self.SRC_CONSIS_GROUP_ID)
expected = [
mock.call.getCPG(HPE3PAR_CPG),
mock.call.createVolumeSet(
self.CONSIS_GROUP_NAME,
domain=None,
comment=cg_comment),
comment=group_comment),
mock.call.createSnapshotOfVolumeSet(
mock.ANY,
self.SRC_CONSIS_GROUP_NAME,
optional=cgsnap_optional),
optional=group_snap_optional),
mock.call.copyVolume(
mock.ANY,
self.VOLUME_NAME_3PAR,
@ -4272,9 +4314,9 @@ class HPE3PARBaseDriver(object):
self.VOLUME_NAME_3PAR)]
# Create a consistency group from a source consistency group.
self.driver.create_consistencygroup_from_src(
self.driver.create_group_from_src(
context.get_admin_context(), group,
[volume], source_cg=source_group,
[volume], source_group=source_grp,
source_vols=[source_volume])
mock_client.assert_has_calls(
@ -4284,12 +4326,17 @@ class HPE3PARBaseDriver(object):
expected +
self.standard_logout)
def test_delete_consistency_group(self):
@mock.patch('cinder.volume.drivers.hpe.hpe_3par_common.HPE3PARCommon.'
'is_volume_group_snap_type')
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_delete_group(self, cg_ss_enable, vol_ss_enable):
cg_ss_enable.return_value = True
vol_ss_enable.return_value = True
mock_client = self.setup_driver()
mock_client.getStorageSystemInfo.return_value = {'id': self.CLIENT_ID}
comment = Comment({
'consistency_group_id': self.CONSIS_GROUP_ID
'group_id': self.GROUP_ID
})
with mock.patch.object(hpecommon.HPE3PARCommon,
@ -4298,9 +4345,8 @@ class HPE3PARBaseDriver(object):
mock_client.getCPG.return_value = {'domain': None}
# create a consistency group
group = self.fake_consistencygroup_object()
self.driver.create_consistencygroup(context.get_admin_context(),
group)
group = self.fake_group_object()
self.driver.create_group(context.get_admin_context(), group)
expected = [
mock.call.getCPG(HPE3PAR_CPG),
@ -4318,9 +4364,8 @@ class HPE3PARBaseDriver(object):
mock_client.reset_mock()
# remove the consistency group
group.status = fields.ConsistencyGroupStatus.DELETING
self.driver.delete_consistencygroup(context.get_admin_context(),
group, [])
group.status = fields.GroupStatus.DELETING
self.driver.delete_group(context.get_admin_context(), group, [])
expected = [
mock.call.deleteVolumeSet(
@ -4333,7 +4378,12 @@ class HPE3PARBaseDriver(object):
expected +
self.standard_logout)
def test_delete_consistency_group_exceptions(self):
@mock.patch('cinder.volume.drivers.hpe.hpe_3par_common.HPE3PARCommon.'
'is_volume_group_snap_type')
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_delete_group_exceptions(self, cg_ss_enable, vol_ss_enable):
cg_ss_enable.return_value = True
vol_ss_enable.return_value = True
mock_client = self.setup_driver()
mock_client.getStorageSystemInfo.return_value = {'id': self.CLIENT_ID}
@ -4343,42 +4393,44 @@ class HPE3PARBaseDriver(object):
mock_client.getCPG.return_value = {'domain': None}
# create a consistency group
group = self.fake_consistencygroup_object()
group = self.fake_group_object()
volume = fake_volume.fake_volume_obj(context.get_admin_context())
self.driver.create_consistencygroup(context.get_admin_context(),
group)
self.driver.create_group(context.get_admin_context(), group)
# remove the consistency group
group.status = fields.ConsistencyGroupStatus.DELETING
group.status = fields.GroupStatus.DELETING
# mock HTTPConflict in delete volume set
mock_client.deleteVolumeSet.side_effect = (
hpeexceptions.HTTPConflict())
# no exception should escape method
self.driver.delete_consistencygroup(context.get_admin_context(),
group, [])
self.driver.delete_group(context.get_admin_context(), group, [])
# mock HTTPNotFound in delete volume set
mock_client.deleteVolumeSet.side_effect = (
hpeexceptions.HTTPNotFound())
# no exception should escape method
self.driver.delete_consistencygroup(context.get_admin_context(),
group, [])
self.driver.delete_group(context.get_admin_context(), group, [])
# mock HTTPConflict in delete volume
mock_client.deleteVolume.side_effect = (
hpeexceptions.HTTPConflict())
# no exception should escape method
self.driver.delete_consistencygroup(context.get_admin_context(),
group, [volume])
self.driver.delete_group(context.get_admin_context(), group,
[volume])
def test_update_consistency_group_add_vol(self):
@mock.patch('cinder.volume.drivers.hpe.hpe_3par_common.HPE3PARCommon.'
'is_volume_group_snap_type')
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_update_group_add_vol(self, cg_ss_enable, vol_ss_enable):
cg_ss_enable.return_value = True
vol_ss_enable.return_value = True
mock_client = self.setup_driver()
mock_client.getStorageSystemInfo.return_value = {'id': self.CLIENT_ID}
volume = self.volume
volume = self.fake_volume_object()
comment = Comment({
'consistency_group_id': self.CONSIS_GROUP_ID
'group_id': self.GROUP_ID
})
with mock.patch.object(hpecommon.HPE3PARCommon,
@ -4387,9 +4439,8 @@ class HPE3PARBaseDriver(object):
mock_client.getCPG.return_value = {'domain': None}
# create a consistency group
group = self.fake_consistencygroup_object()
self.driver.create_consistencygroup(context.get_admin_context(),
group)
group = self.fake_group_object()
self.driver.create_group(context.get_admin_context(), group)
expected = [
mock.call.getCPG(HPE3PAR_CPG),
@ -4407,10 +4458,8 @@ class HPE3PARBaseDriver(object):
mock_client.reset_mock()
# add a volume to the consistency group
self.driver.update_consistencygroup(context.get_admin_context(),
group,
add_volumes=[volume],
remove_volumes=[])
self.driver.update_group(context.get_admin_context(), group,
add_volumes=[volume], remove_volumes=[])
expected = [
mock.call.addVolumeToVolumeSet(
@ -4424,13 +4473,18 @@ class HPE3PARBaseDriver(object):
expected +
self.standard_logout)
def test_update_consistency_group_remove_vol(self):
@mock.patch('cinder.volume.drivers.hpe.hpe_3par_common.HPE3PARCommon.'
'is_volume_group_snap_type')
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_update_group_remove_vol(self, cg_ss_enable, vol_ss_enable):
cg_ss_enable.return_value = True
vol_ss_enable.return_value = True
mock_client = self.setup_driver()
mock_client.getStorageSystemInfo.return_value = {'id': self.CLIENT_ID}
volume = self.volume
volume = self.fake_volume_object()
comment = Comment({
'consistency_group_id': self.CONSIS_GROUP_ID
'group_id': self.GROUP_ID
})
with mock.patch.object(hpecommon.HPE3PARCommon,
@ -4439,9 +4493,8 @@ class HPE3PARBaseDriver(object):
mock_client.getCPG.return_value = {'domain': None}
# create a consistency group
group = self.fake_consistencygroup_object()
self.driver.create_consistencygroup(context.get_admin_context(),
group)
group = self.fake_group_object()
self.driver.create_group(context.get_admin_context(), group)
expected = [
mock.call.getCPG(HPE3PAR_CPG),
@ -4459,10 +4512,8 @@ class HPE3PARBaseDriver(object):
mock_client.reset_mock()
# add a volume to the consistency group
self.driver.update_consistencygroup(context.get_admin_context(),
group,
add_volumes=[volume],
remove_volumes=[])
self.driver.update_group(context.get_admin_context(), group,
add_volumes=[volume], remove_volumes=[])
expected = [
mock.call.addVolumeToVolumeSet(
@ -4478,10 +4529,8 @@ class HPE3PARBaseDriver(object):
mock_client.reset_mock()
# remove the volume from the consistency group
self.driver.update_consistencygroup(context.get_admin_context(),
group,
add_volumes=[],
remove_volumes=[volume])
self.driver.update_group(context.get_admin_context(), group,
add_volumes=[], remove_volumes=[volume])
expected = [
mock.call.removeVolumeFromVolumeSet(
@ -4495,22 +4544,27 @@ class HPE3PARBaseDriver(object):
expected +
self.standard_logout)
def test_create_cgsnapshot(self):
@mock.patch('cinder.volume.drivers.hpe.hpe_3par_common.HPE3PARCommon.'
'is_volume_group_snap_type')
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_group_snapshot(self, cg_ss_enable, vol_ss_enable):
cg_ss_enable.return_value = True
vol_ss_enable.return_value = True
mock_client = self.setup_driver()
mock_client.getStorageSystemInfo.return_value = {'id': self.CLIENT_ID}
volume = self.volume
volume = self.fake_volume_object()
cg_comment = Comment({
'consistency_group_id': self.CONSIS_GROUP_ID
'group_id': self.GROUP_ID
})
cgsnap_comment = Comment({
"consistency_group_id": "6044fedf-c889-4752-900f-2039d247a5df",
"description": "cgsnapshot",
"cgsnapshot_id": "e91c5ed5-daee-4e84-8724-1c9e31e7a1f2"})
group_snap_comment = Comment({
"group_id": "6044fedf-c889-4752-900f-2039d247a5df",
"description": "group_snapshot",
"group_snapshot_id": "e91c5ed5-daee-4e84-8724-1c9e31e7a1f2"})
cgsnap_optional = (
{'comment': cgsnap_comment,
{'comment': group_snap_comment,
'readOnly': False})
with mock.patch.object(hpecommon.HPE3PARCommon,
@ -4519,9 +4573,8 @@ class HPE3PARBaseDriver(object):
mock_client.getCPG.return_value = {'domain': None}
# create a consistency group
group = self.fake_consistencygroup_object()
self.driver.create_consistencygroup(context.get_admin_context(),
group)
group = self.fake_group_object()
self.driver.create_group(context.get_admin_context(), group)
expected = [
mock.call.getCPG(HPE3PAR_CPG),
@ -4539,10 +4592,8 @@ class HPE3PARBaseDriver(object):
mock_client.reset_mock()
# add a volume to the consistency group
self.driver.update_consistencygroup(context.get_admin_context(),
group,
add_volumes=[volume],
remove_volumes=[])
self.driver.update_group(context.get_admin_context(), group,
add_volumes=[volume], remove_volumes=[])
expected = [
mock.call.addVolumeToVolumeSet(
@ -4558,9 +4609,9 @@ class HPE3PARBaseDriver(object):
mock_client.reset_mock()
# create a snapshot of the consistency group
cgsnapshot = self.fake_cgsnapshot_object()
self.driver.create_cgsnapshot(context.get_admin_context(),
cgsnapshot, [])
group_snapshot = self.fake_group_snapshot_object()
self.driver.create_group_snapshot(context.get_admin_context(),
group_snapshot, [])
expected = [
mock.call.createSnapshotOfVolumeSet(
@ -4575,22 +4626,27 @@ class HPE3PARBaseDriver(object):
expected +
self.standard_logout)
def test_delete_cgsnapshot(self):
@mock.patch('cinder.volume.drivers.hpe.hpe_3par_common.HPE3PARCommon.'
'is_volume_group_snap_type')
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_delete_group_snapshot(self, cg_ss_enable, vol_ss_enable):
cg_ss_enable.return_value = True
vol_ss_enable.return_value = True
mock_client = self.setup_driver()
mock_client.getStorageSystemInfo.return_value = {'id': self.CLIENT_ID}
volume = self.volume
cgsnapshot = self.fake_cgsnapshot_object()
volume = self.fake_volume_object()
group_snapshot = self.fake_group_snapshot_object()
cg_comment = Comment({
'consistency_group_id': self.CONSIS_GROUP_ID
'group_id': self.GROUP_ID
})
cgsnap_comment = Comment({
"consistency_group_id": "6044fedf-c889-4752-900f-2039d247a5df",
"description": "cgsnapshot",
"cgsnapshot_id": "e91c5ed5-daee-4e84-8724-1c9e31e7a1f2"})
group_snap_comment = Comment({
"group_id": "6044fedf-c889-4752-900f-2039d247a5df",
"description": "group_snapshot",
"group_snapshot_id": "e91c5ed5-daee-4e84-8724-1c9e31e7a1f2"})
cgsnap_optional = {'comment': cgsnap_comment,
group_snap_optional = {'comment': group_snap_comment,
'readOnly': False}
with mock.patch.object(hpecommon.HPE3PARCommon,
@ -4599,9 +4655,8 @@ class HPE3PARBaseDriver(object):
mock_client.getCPG.return_value = {'domain': None}
# create a consistency group
group = self.fake_consistencygroup_object()
self.driver.create_consistencygroup(context.get_admin_context(),
group)
group = self.fake_group_object()
self.driver.create_group(context.get_admin_context(), group)
expected = [
mock.call.getCPG(HPE3PAR_CPG),
@ -4619,11 +4674,8 @@ class HPE3PARBaseDriver(object):
mock_client.reset_mock()
# add a volume to the consistency group
self.driver.update_consistencygroup(context.get_admin_context(),
group,
add_volumes=[volume],
remove_volumes=[])
self.driver.update_group(context.get_admin_context(), group,
add_volumes=[volume], remove_volumes=[])
expected = [
mock.call.addVolumeToVolumeSet(
self.CONSIS_GROUP_NAME,
@ -4638,19 +4690,19 @@ class HPE3PARBaseDriver(object):
mock_client.reset_mock()
# create a snapshot of the consistency group
self.driver.create_cgsnapshot(context.get_admin_context(),
cgsnapshot, [])
self.driver.create_group_snapshot(context.get_admin_context(),
group_snapshot, [])
expected = [
mock.call.createSnapshotOfVolumeSet(
self.CGSNAPSHOT_BASE_NAME + "-@count@",
self.CONSIS_GROUP_NAME,
optional=cgsnap_optional)]
optional=group_snap_optional)]
# delete the snapshot of the consistency group
cgsnapshot.status = 'deleting'
self.driver.delete_cgsnapshot(context.get_admin_context(),
cgsnapshot, [])
group_snapshot.status = 'deleting'
self.driver.delete_group_snapshot(context.get_admin_context(),
group_snapshot, [])
mock_client.assert_has_calls(
self.get_id_login +

View File

@ -254,10 +254,12 @@ class HPE3PARCommon(object):
3.0.29 - Fix convert snapshot volume to base volume type. bug #1656186
3.0.30 - Handle manage and unmanage hosts present. bug #1648067
3.0.31 - Enable HPE-3PAR Compression Feature.
3.0.32 - Add consistency group capability to generic volume group
in HPE-3APR
"""
VERSION = "3.0.31"
VERSION = "3.0.32"
stats = {}
@ -525,34 +527,46 @@ class HPE3PARCommon(object):
growth_size_mib = growth_size * units.Ki
self._extend_volume(volume, volume_name, growth_size_mib)
def create_consistencygroup(self, context, group):
"""Creates a consistencygroup."""
def create_group(self, context, group):
"""Creates a group."""
if not volume_utils.is_group_a_cg_snapshot_type(group):
raise NotImplementedError()
if group.volume_type_ids is not None:
for volume_type in group.volume_types:
allow_type = self.is_volume_group_snap_type(
volume_type)
if not allow_type:
msg = _('For a volume type to be a part of consistent '
'group, volume type extra spec must have '
'consistent_group_snapshot_enabled="<is> True"')
LOG.error(msg)
raise exception.InvalidInput(reason=msg)
pool = volume_utils.extract_host(group.host, level='pool')
domain = self.get_domain(pool)
cg_name = self._get_3par_vvs_name(group.id)
extra = {'consistency_group_id': group.id}
if group.cgsnapshot_id:
extra['cgsnapshot_id'] = group.cgsnapshot_id
extra = {'group_id': group.id}
if group.group_snapshot_id is not None:
extra['group_snapshot_id'] = group.group_snapshot_id
self.client.createVolumeSet(cg_name, domain=domain,
comment=six.text_type(extra))
model_update = {'status': fields.ConsistencyGroupStatus.AVAILABLE}
model_update = {'status': fields.GroupStatus.AVAILABLE}
return model_update
def create_consistencygroup_from_src(self, context, group, volumes,
cgsnapshot=None, snapshots=None,
source_cg=None, source_vols=None):
def create_group_from_src(self, context, group, volumes,
group_snapshot=None, snapshots=None,
source_group=None, source_vols=None):
self.create_consistencygroup(context, group)
self.create_group(context, group)
vvs_name = self._get_3par_vvs_name(group.id)
if cgsnapshot and snapshots:
cgsnap_name = self._get_3par_snap_name(cgsnapshot.id)
if group_snapshot and snapshots:
cgsnap_name = self._get_3par_snap_name(group_snapshot.id)
snap_base = cgsnap_name
elif source_cg and source_vols:
cg_id = source_cg.id
elif source_group and source_vols:
cg_id = source_group.id
# Create a brand new uuid for the temp snap.
snap_uuid = uuid.uuid4().hex
@ -569,16 +583,17 @@ class HPE3PARCommon(object):
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)
cpg = type_info['cpg']
snapcpg = type_info['snap_cpg']
tpvv = type_info.get('tpvv', False)
tdvv = type_info.get('tdvv', False)
compression = self.get_compression_policy(
type_info['hpe3par_keys'])
optional = {'online': True, 'snapCPG': cpg,
optional = {'online': True, 'snapCPG': snapcpg,
'tpvv': tpvv, 'tdvv': tdvv}
if compression is not None:
@ -589,10 +604,12 @@ class HPE3PARCommon(object):
return None, None
def delete_consistencygroup(self, context, group, volumes):
"""Deletes a consistency group."""
def delete_group(self, context, group, volumes):
"""Deletes a group."""
try:
if not volume_utils.is_group_a_cg_snapshot_type(group):
raise NotImplementedError()
cg_name = self._get_3par_vvs_name(group.id)
self.client.deleteVolumeSet(cg_name)
except hpeexceptions.HTTPNotFound:
@ -617,20 +634,31 @@ class HPE3PARCommon(object):
'error': ex})
volume_update['status'] = 'error'
volume_model_updates.append(volume_update)
model_update = {'status': group.status}
return model_update, volume_model_updates
def update_consistencygroup(self, context, group,
add_volumes=None, remove_volumes=None):
def update_group(self, context, group, add_volumes=None,
remove_volumes=None):
grp_snap_enable = volume_utils.is_group_a_cg_snapshot_type(group)
if not grp_snap_enable:
raise NotImplementedError()
volume_set_name = self._get_3par_vvs_name(group.id)
for volume in add_volumes:
volume_name = self._get_3par_vol_name(volume['id'])
volume_name = self._get_3par_vol_name(volume.id)
vol_snap_enable = self.is_volume_group_snap_type(
volume.volume_type)
try:
self.client.addVolumeToVolumeSet(volume_set_name, volume_name)
if grp_snap_enable and vol_snap_enable:
self.client.addVolumeToVolumeSet(volume_set_name,
volume_name)
else:
msg = (_('Volume with volume id %s is not '
'supported as extra specs of this '
'volume does not have '
'consistent_group_snapshot_enabled="<is> True"'
) % volume['id'])
LOG.error(msg)
raise exception.InvalidInput(reason=msg)
except hpeexceptions.HTTPNotFound:
msg = (_('Virtual Volume Set %s does not exist.') %
volume_set_name)
@ -638,7 +666,7 @@ class HPE3PARCommon(object):
raise exception.InvalidInput(reason=msg)
for volume in remove_volumes:
volume_name = self._get_3par_vol_name(volume['id'])
volume_name = self._get_3par_vol_name(volume.id)
try:
self.client.removeVolumeFromVolumeSet(
volume_set_name, volume_name)
@ -650,17 +678,19 @@ class HPE3PARCommon(object):
return None, None, None
def create_cgsnapshot(self, context, cgsnapshot, snapshots):
"""Creates a cgsnapshot."""
def create_group_snapshot(self, context, group_snapshot, snapshots):
"""Creates a group snapshot."""
if not volume_utils.is_group_a_cg_snapshot_type(group_snapshot):
raise NotImplementedError()
cg_id = cgsnapshot.consistencygroup_id
snap_shot_name = self._get_3par_snap_name(cgsnapshot.id) + (
cg_id = group_snapshot.group_id
snap_shot_name = self._get_3par_snap_name(group_snapshot.id) + (
"-@count@")
copy_of_name = self._get_3par_vvs_name(cg_id)
extra = {'cgsnapshot_id': cgsnapshot.id}
extra['consistency_group_id'] = cg_id
extra['description'] = cgsnapshot.description
extra = {'group_snapshot_id': group_snapshot.id}
extra['group_id'] = cg_id
extra['description'] = group_snapshot.description
optional = {'comment': json.dumps(extra),
'readOnly': False}
@ -687,14 +717,15 @@ class HPE3PARCommon(object):
'status': fields.SnapshotStatus.AVAILABLE}
snapshot_model_updates.append(snapshot_update)
model_update = {'status': 'available'}
model_update = {'status': fields.GroupSnapshotStatus.AVAILABLE}
return model_update, snapshot_model_updates
def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
"""Deletes a cgsnapshot."""
cgsnap_name = self._get_3par_snap_name(cgsnapshot.id)
def delete_group_snapshot(self, context, group_snapshot, snapshots):
"""Deletes a group snapshot."""
if not volume_utils.is_group_a_cg_snapshot_type(group_snapshot):
raise NotImplementedError()
cgsnap_name = self._get_3par_snap_name(group_snapshot.id)
snapshot_model_updates = []
for i, snapshot in enumerate(snapshots):
@ -718,7 +749,7 @@ class HPE3PARCommon(object):
snapshot_update['status'] = fields.SnapshotStatus.ERROR
snapshot_model_updates.append(snapshot_update)
model_update = {'status': cgsnapshot.status}
model_update = {'status': fields.GroupSnapshotStatus.DELETED}
return model_update, snapshot_model_updates
@ -1378,7 +1409,7 @@ class HPE3PARCommon(object):
'filter_function': filter_function,
'goodness_function': goodness_function,
'multiattach': False,
'consistencygroup_support': True,
'consistent_group_snapshot_enabled': True,
'compression': compression_support,
}
@ -1908,7 +1939,7 @@ class HPE3PARCommon(object):
compression = self.get_compression_policy(
type_info['hpe3par_keys'])
cg_id = volume.get('consistencygroup_id', None)
cg_id = volume.get('group_id', None)
if cg_id:
vvs_name = self._get_3par_vvs_name(cg_id)
@ -3273,6 +3304,15 @@ class HPE3PARCommon(object):
rep_flag = False
return rep_flag
def is_volume_group_snap_type(self, volume_type):
consis_group_snap_type = False
if volume_type:
extra_specs = volume_type.extra_specs
if 'consistent_group_snapshot_enabled' in extra_specs:
gsnap_val = extra_specs['consistent_group_snapshot_enabled']
consis_group_snap_type = (gsnap_val == "<is> True")
return consis_group_snap_type
def _volume_of_replicated_type(self, volume):
replicated_type = False
volume_type_id = volume.get('volume_type_id')

View File

@ -110,10 +110,11 @@ class HPE3PARFCDriver(driver.ManageableVD,
by another host, while creating 3PAR FC Host. bug #1597454
3.0.10 - Added Entry point tracing
3.0.11 - Handle manage and unmanage hosts present. bug #1648067
3.0.12 - Adds consistency group capability in generic volume groups.
"""
VERSION = "3.0.11"
VERSION = "3.0.12"
# The name of the CI wiki page.
CI_WIKI_NAME = "HPE_Storage_CI"
@ -561,56 +562,58 @@ class HPE3PARFCDriver(driver.ManageableVD,
self._logout(common)
@utils.trace
def create_consistencygroup(self, context, group):
def create_group(self, context, group):
common = self._login()
try:
return common.create_consistencygroup(context, group)
return common.create_group(context, group)
finally:
self._logout(common)
@utils.trace
def create_consistencygroup_from_src(self, context, group, volumes,
cgsnapshot=None, snapshots=None,
source_cg=None, source_vols=None):
def create_group_from_src(self, context, group, volumes,
group_snapshot=None, snapshots=None,
source_group=None, source_vols=None):
common = self._login()
try:
return common.create_consistencygroup_from_src(
context, group, volumes, cgsnapshot, snapshots, source_cg,
source_vols)
return common.create_group_from_src(
context, group, volumes, group_snapshot, snapshots,
source_group, source_vols)
finally:
self._logout(common)
@utils.trace
def delete_consistencygroup(self, context, group, volumes):
def delete_group(self, context, group, volumes):
common = self._login()
try:
return common.delete_consistencygroup(context, group, volumes)
return common.delete_group(context, group, volumes)
finally:
self._logout(common)
@utils.trace
def update_consistencygroup(self, context, group,
add_volumes=None, remove_volumes=None):
def update_group(self, context, group, add_volumes=None,
remove_volumes=None):
common = self._login()
try:
return common.update_consistencygroup(context, group, add_volumes,
return common.update_group(context, group, add_volumes,
remove_volumes)
finally:
self._logout(common)
@utils.trace
def create_cgsnapshot(self, context, cgsnapshot, snapshots):
def create_group_snapshot(self, context, group_snapshot, snapshots):
common = self._login()
try:
return common.create_cgsnapshot(context, cgsnapshot, snapshots)
return common.create_group_snapshot(context, group_snapshot,
snapshots)
finally:
self._logout(common)
@utils.trace
def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
def delete_group_snapshot(self, context, group_snapshot, snapshots):
common = self._login()
try:
return common.delete_cgsnapshot(context, cgsnapshot, snapshots)
return common.delete_group_snapshot(context, group_snapshot,
snapshots)
finally:
self._logout(common)

View File

@ -122,10 +122,11 @@ class HPE3PARISCSIDriver(driver.ManageableVD,
3.0.13 - Handling HTTP conflict 409, host WWN/iSCSI name already used
by another host, while creating 3PAR iSCSI Host. bug #1642945
3.0.14 - Handle manage and unmanage hosts present. bug #1648067
3.0.15 - Adds consistency group capability in generic volume groups.
"""
VERSION = "3.0.14"
VERSION = "3.0.15"
# The name of the CI wiki page.
CI_WIKI_NAME = "HPE_Storage_CI"
@ -820,7 +821,6 @@ class HPE3PARISCSIDriver(driver.ManageableVD,
if count < current_smallest_count:
current_least_used_nsp = nsp
current_smallest_count = count
return current_least_used_nsp
@utils.trace
@ -832,56 +832,58 @@ class HPE3PARISCSIDriver(driver.ManageableVD,
self._logout(common)
@utils.trace
def create_consistencygroup(self, context, group):
def create_group(self, context, group):
common = self._login()
try:
common.create_consistencygroup(context, group)
common.create_group(context, group)
finally:
self._logout(common)
@utils.trace
def create_consistencygroup_from_src(self, context, group, volumes,
cgsnapshot=None, snapshots=None,
source_cg=None, source_vols=None):
def create_group_from_src(self, context, group, volumes,
group_snapshot=None, snapshots=None,
source_group=None, source_vols=None):
common = self._login()
try:
return common.create_consistencygroup_from_src(
context, group, volumes, cgsnapshot, snapshots, source_cg,
source_vols)
return common.create_group_from_src(
context, group, volumes, group_snapshot, snapshots,
source_group, source_vols)
finally:
self._logout(common)
@utils.trace
def delete_consistencygroup(self, context, group, volumes):
def delete_group(self, context, group, volumes):
common = self._login()
try:
return common.delete_consistencygroup(context, group, volumes)
return common.delete_group(context, group, volumes)
finally:
self._logout(common)
@utils.trace
def update_consistencygroup(self, context, group,
add_volumes=None, remove_volumes=None):
def update_group(self, context, group, add_volumes=None,
remove_volumes=None):
common = self._login()
try:
return common.update_consistencygroup(context, group, add_volumes,
return common.update_group(context, group, add_volumes,
remove_volumes)
finally:
self._logout(common)
@utils.trace
def create_cgsnapshot(self, context, cgsnapshot, snapshots):
def create_group_snapshot(self, context, group_snapshot, snapshots):
common = self._login()
try:
return common.create_cgsnapshot(context, cgsnapshot, snapshots)
return common.create_group_snapshot(context, group_snapshot,
snapshots)
finally:
self._logout(common)
@utils.trace
def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
def delete_group_snapshot(self, context, group_snapshot, snapshots):
common = self._login()
try:
return common.delete_cgsnapshot(context, cgsnapshot, snapshots)
return common.delete_group_snapshot(context, group_snapshot,
snapshots)
finally:
self._logout(common)

View File

@ -0,0 +1,4 @@
---
features:
- Added consistency group capability to generic volume groups in the
HPE 3PAR driver.