3PAR: Adding Consistency Group Support

Adds support for Consistency Groups to the HP 3PAR driver

Implements: blueprint hp-3par-add-consistency-groups
Change-Id: I31e74b55db0f9b813a9295378271715df4b839f4
This commit is contained in:
Alex O'Rourke 2015-07-20 10:05:40 -07:00
parent 442aea54c9
commit 1899d7f80b
4 changed files with 788 additions and 7 deletions

View File

@ -94,6 +94,10 @@ class HP3PARBaseDriver(object):
SNAPSHOT_NAME = 'snapshot-2f823bdc-e36e-4dc8-bd15-de1c7a28ff31'
VOLUME_3PAR_NAME = 'osv-0DM4qZEVSKON-DXN-NwVpw'
SNAPSHOT_3PAR_NAME = 'oss-L4I73ONuTci9Fd4ceij-MQ'
CONSIS_GROUP_ID = '6044fedf-c889-4752-900f-2039d247a5df'
CONSIS_GROUP_NAME = 'vvs-YET.38iJR1KQDyA50kel3w'
CGSNAPSHOT_ID = 'e91c5ed5-daee-4e84-8724-1c9e31e7a1f2'
CGSNAPSHOT_BASE_NAME = 'oss-6Rxe1druToSHJByeMeeh8g'
# fake host on the 3par
FAKE_HOST = 'fakehost'
FAKE_CINDER_HOST = 'fakehost@foo#' + HP3PAR_CPG
@ -264,6 +268,11 @@ class HP3PARBaseDriver(object):
'state': 1,
'uuid': '29c214aa-62b9-41c8-b198-543f6cf24edf'}]
cgsnapshot = {'consistencygroup_id': CONSIS_GROUP_ID,
'description': 'cgsnapshot',
'id': CGSNAPSHOT_ID,
'readOnly': False}
TASK_DONE = 1
TASK_ACTIVE = 2
STATUS_DONE = {'status': 1}
@ -2947,6 +2956,505 @@ class HP3PARBaseDriver(object):
safe_host = common._safe_hostname(long_hostname)
self.assertEqual(fixed_hostname, safe_host)
@mock.patch('hp3parclient.version', "3.2.2")
def test_create_consistency_group(self):
class fake_consitencygroup_object(object):
volume_type_id = '49fa96b5-828e-4653-b622-873a1b7e6f1c'
name = 'cg_name'
cgsnapshot_id = None
host = self.FAKE_CINDER_HOST
id = self.CONSIS_GROUP_ID
description = 'consistency group'
mock_client = self.setup_driver()
comment = (
"{'display_name': 'cg_name',"
" 'consistency_group_id':"
" '" + self.CONSIS_GROUP_ID + "',"
" 'description': 'consistency group'}")
with mock.patch.object(hpcommon.HP3PARCommon,
'_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 = fake_consitencygroup_object()
self.driver.create_consistencygroup(context.get_admin_context(),
group)
expected = [
mock.call.getCPG(HP3PAR_CPG),
mock.call.createVolumeSet(
self.CONSIS_GROUP_NAME,
domain=None,
comment=comment)]
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
@mock.patch('hp3parclient.version', "3.2.2")
def test_create_consistency_group_from_src(self):
class fake_consitencygroup_object(object):
volume_type_id = '49fa96b5-828e-4653-b622-873a1b7e6f1c'
name = 'cg_name'
cgsnapshot_id = None
host = self.FAKE_CINDER_HOST
id = self.CONSIS_GROUP_ID
description = 'consistency group'
mock_client = self.setup_driver()
volume = self.volume
cgsnap_optional = (
{'comment': '{"consistency_group_id":'
' "6044fedf-c889-4752-900f-2039d247a5df",'
' "description": "cgsnapshot",'
' "cgsnapshot_id": "e91c5ed5-daee-4e84-8724-1c9e31e7a1f2"}',
'readOnly': False})
cg_comment = (
"{'display_name': 'cg_name',"
" 'consistency_group_id':"
" '" + self.CONSIS_GROUP_ID + "',"
" 'description': 'consistency group'}")
with mock.patch.object(hpcommon.HP3PARCommon,
'_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 = fake_consitencygroup_object()
self.driver.create_consistencygroup(context.get_admin_context(),
group)
expected = [
mock.call.getCPG(HP3PAR_CPG),
mock.call.createVolumeSet(
self.CONSIS_GROUP_NAME,
domain=None,
comment=cg_comment)]
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
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=[])
expected = [
mock.call.addVolumeToVolumeSet(
self.CONSIS_GROUP_NAME,
self.VOLUME_NAME_3PAR)]
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
mock_client.reset_mock()
# create a snapshot of the consistency group
self.driver.create_cgsnapshot(context.get_admin_context(),
self.cgsnapshot)
expected = [
mock.call.createSnapshotOfVolumeSet(
self.CGSNAPSHOT_BASE_NAME + "-@count@",
self.CONSIS_GROUP_NAME,
optional=cgsnap_optional)]
# create a consistency group from the cgsnapshot
self.driver.create_consistencygroup_from_src(
context.get_admin_context(), group,
[volume], cgsnapshot=self.cgsnapshot,
snapshots=[self.snapshot])
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
@mock.patch('hp3parclient.version', "3.2.2")
def test_delete_consistency_group(self):
class fake_consitencygroup_object(object):
volume_type_id = '49fa96b5-828e-4653-b622-873a1b7e6f1c'
name = 'cg_name'
cgsnapshot_id = None
host = self.FAKE_CINDER_HOST
id = self.CONSIS_GROUP_ID
description = 'consistency group'
mock_client = self.setup_driver()
comment = (
"{'display_name': 'cg_name',"
" 'consistency_group_id':"
" '" + self.CONSIS_GROUP_ID + "',"
" 'description': 'consistency group'}")
with mock.patch.object(hpcommon.HP3PARCommon,
'_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 = fake_consitencygroup_object()
self.driver.create_consistencygroup(context.get_admin_context(),
group)
expected = [
mock.call.getCPG(HP3PAR_CPG),
mock.call.createVolumeSet(
self.CONSIS_GROUP_NAME,
domain=None,
comment=comment)]
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
mock_client.reset_mock()
# remove the consistency group
group.status = 'deleting'
self.driver.delete_consistencygroup(context.get_admin_context(),
group)
expected = [
mock.call.deleteVolumeSet(
self.CONSIS_GROUP_NAME)]
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
@mock.patch('hp3parclient.version', "3.2.2")
def test_update_consistency_group_add_vol(self):
class fake_consitencygroup_object(object):
volume_type_id = '49fa96b5-828e-4653-b622-873a1b7e6f1c'
name = 'cg_name'
cgsnapshot_id = None
host = self.FAKE_CINDER_HOST
id = self.CONSIS_GROUP_ID
description = 'consistency group'
mock_client = self.setup_driver()
volume = self.volume
comment = (
"{'display_name': 'cg_name',"
" 'consistency_group_id':"
" '" + self.CONSIS_GROUP_ID + "',"
" 'description': 'consistency group'}")
with mock.patch.object(hpcommon.HP3PARCommon,
'_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 = fake_consitencygroup_object()
self.driver.create_consistencygroup(context.get_admin_context(),
group)
expected = [
mock.call.getCPG(HP3PAR_CPG),
mock.call.createVolumeSet(
self.CONSIS_GROUP_NAME,
domain=None,
comment=comment)]
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
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=[])
expected = [
mock.call.addVolumeToVolumeSet(
self.CONSIS_GROUP_NAME,
self.VOLUME_NAME_3PAR)]
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
@mock.patch('hp3parclient.version', "3.2.2")
def test_update_consistency_group_remove_vol(self):
class fake_consitencygroup_object(object):
volume_type_id = '49fa96b5-828e-4653-b622-873a1b7e6f1c'
name = 'cg_name'
cgsnapshot_id = None
host = self.FAKE_CINDER_HOST
id = self.CONSIS_GROUP_ID
description = 'consistency group'
mock_client = self.setup_driver()
volume = self.volume
comment = (
"{'display_name': 'cg_name',"
" 'consistency_group_id':"
" '" + self.CONSIS_GROUP_ID + "',"
" 'description': 'consistency group'}")
with mock.patch.object(hpcommon.HP3PARCommon,
'_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 = fake_consitencygroup_object()
self.driver.create_consistencygroup(context.get_admin_context(),
group)
expected = [
mock.call.getCPG(HP3PAR_CPG),
mock.call.createVolumeSet(
self.CONSIS_GROUP_NAME,
domain=None,
comment=comment)]
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
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=[])
expected = [
mock.call.addVolumeToVolumeSet(
self.CONSIS_GROUP_NAME,
self.VOLUME_NAME_3PAR)]
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
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])
expected = [
mock.call.removeVolumeFromVolumeSet(
self.CONSIS_GROUP_NAME,
self.VOLUME_NAME_3PAR)]
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
@mock.patch('hp3parclient.version', "3.2.2")
def test_create_cgsnapshot(self):
class fake_consitencygroup_object(object):
volume_type_id = '49fa96b5-828e-4653-b622-873a1b7e6f1c'
name = 'cg_name'
cgsnapshot_id = None
host = self.FAKE_CINDER_HOST
id = self.CONSIS_GROUP_ID
description = 'consistency group'
mock_client = self.setup_driver()
volume = self.volume
cg_comment = (
"{'display_name': 'cg_name',"
" 'consistency_group_id':"
" '" + self.CONSIS_GROUP_ID + "',"
" 'description': 'consistency group'}")
cgsnap_optional = (
{'comment': '{"consistency_group_id":'
' "6044fedf-c889-4752-900f-2039d247a5df",'
' "description": "cgsnapshot",'
' "cgsnapshot_id": "e91c5ed5-daee-4e84-8724-1c9e31e7a1f2"}',
'readOnly': False})
with mock.patch.object(hpcommon.HP3PARCommon,
'_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 = fake_consitencygroup_object()
self.driver.create_consistencygroup(context.get_admin_context(),
group)
expected = [
mock.call.getCPG(HP3PAR_CPG),
mock.call.createVolumeSet(
self.CONSIS_GROUP_NAME,
domain=None,
comment=cg_comment)]
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
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=[])
expected = [
mock.call.addVolumeToVolumeSet(
self.CONSIS_GROUP_NAME,
self.VOLUME_NAME_3PAR)]
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
mock_client.reset_mock()
# create a snapshot of the consistency group
self.driver.create_cgsnapshot(context.get_admin_context(),
self.cgsnapshot)
expected = [
mock.call.createSnapshotOfVolumeSet(
self.CGSNAPSHOT_BASE_NAME + "-@count@",
self.CONSIS_GROUP_NAME,
optional=cgsnap_optional)]
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
@mock.patch('hp3parclient.version', "3.2.2")
def test_delete_cgsnapshot(self):
class fake_consitencygroup_object(object):
volume_type_id = '49fa96b5-828e-4653-b622-873a1b7e6f1c'
name = 'cg_name'
cgsnapshot_id = None
host = self.FAKE_CINDER_HOST
id = self.CONSIS_GROUP_ID
description = 'consistency group'
mock_client = self.setup_driver()
volume = self.volume
cgsnapshot = self.cgsnapshot
cg_comment = (
"{'display_name': 'cg_name',"
" 'consistency_group_id':"
" '" + self.CONSIS_GROUP_ID + "',"
" 'description': 'consistency group'}")
cgsnap_optional = (
{'comment': '{"consistency_group_id":'
' "6044fedf-c889-4752-900f-2039d247a5df",'
' "description": "cgsnapshot",'
' "cgsnapshot_id": "e91c5ed5-daee-4e84-8724-1c9e31e7a1f2"}',
'readOnly': False})
with mock.patch.object(hpcommon.HP3PARCommon,
'_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 = fake_consitencygroup_object()
self.driver.create_consistencygroup(context.get_admin_context(),
group)
expected = [
mock.call.getCPG(HP3PAR_CPG),
mock.call.createVolumeSet(
self.CONSIS_GROUP_NAME,
domain=None,
comment=cg_comment)]
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
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=[])
expected = [
mock.call.addVolumeToVolumeSet(
self.CONSIS_GROUP_NAME,
self.VOLUME_NAME_3PAR)]
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
mock_client.reset_mock()
# create a snapshot of the consistency group
self.driver.create_cgsnapshot(context.get_admin_context(),
cgsnapshot)
expected = [
mock.call.createSnapshotOfVolumeSet(
self.CGSNAPSHOT_BASE_NAME + "-@count@",
self.CONSIS_GROUP_NAME,
optional=cgsnap_optional)]
# delete the snapshot of the consistency group
cgsnapshot['status'] = 'deleting'
self.driver.delete_cgsnapshot(context.get_admin_context(),
cgsnapshot)
mock_client.assert_has_calls(
[mock.call.getWsApiVersion()] +
self.standard_login +
expected +
self.standard_logout)
class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):

View File

@ -61,6 +61,7 @@ from cinder import context
from cinder import exception
from cinder import flow_utils
from cinder.i18n import _, _LE, _LI, _LW
from cinder import objects
from cinder.volume import qos_specs
from cinder.volume import utils as volume_utils
from cinder.volume import volume_types
@ -72,6 +73,7 @@ LOG = logging.getLogger(__name__)
MIN_CLIENT_VERSION = '3.1.2'
GETCPGSTATDATA_VERSION = '3.2.2'
MIN_CG_CLIENT_VERSION = '3.2.2'
DEDUP_API_VERSION = 30201120
FLASH_CACHE_API_VERSION = 30201200
SRSTATLD_API_VERSION = 30201200
@ -198,10 +200,11 @@ class HP3PARCommon(object):
2.0.48 - Adding changes to support 3PAR iSCSI multipath.
2.0.49 - Added client CPG stats to driver volume stats. bug #1482741
2.0.50 - Add over subscription support
2.0.51 - Adds consistency group support
"""
VERSION = "2.0.50"
VERSION = "2.0.51"
stats = {}
@ -242,6 +245,7 @@ class HP3PARCommon(object):
self.config = config
self.client = None
self.uuid = uuid.uuid4()
self.db = importutils.import_module('cinder.db')
def get_version(self):
return self.VERSION
@ -373,6 +377,167 @@ class HP3PARCommon(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."""
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}
extra['description'] = group.description
extra['display_name'] = group.name
if group.cgsnapshot_id:
extra['cgsnapshot_id'] = group.cgsnapshot_id
self.client.createVolumeSet(cg_name, domain=domain,
comment=six.text_type(extra))
model_update = {'status': 'available'}
return model_update
def create_consistencygroup_from_src(self, context, group, volumes,
cgsnapshot=None, snapshots=None,
source_cg=None, source_vols=None):
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)
return None, None
def delete_consistencygroup(self, context, group):
"""Deletes a consistency group."""
try:
cg_name = self._get_3par_vvs_name(group.id)
self.client.deleteVolumeSet(cg_name)
except hpexceptions.HTTPNotFound:
err = (_LW("Virtual Volume Set '%s' doesn't exist on array.") %
cg_name)
LOG.warning(err)
except hpexceptions.HTTPConflict as e:
err = (_LE("Conflict detected in Virtual Volume Set"
" %(volume_set): %(error)"),
{"volume_set": cg_name,
"error": e})
LOG.error(err)
volumes = self.db.volume_get_all_by_group(context, group.id)
for volume in volumes:
self.delete_volume(volume)
volume.status = 'deleted'
model_update = {'status': group.status}
return model_update, volumes
def update_consistencygroup(self, context, group,
add_volumes=None, remove_volumes=None):
volume_set_name = self._get_3par_vvs_name(group.id)
for volume in add_volumes:
volume_name = self._get_3par_vol_name(volume['id'])
try:
self.client.addVolumeToVolumeSet(volume_set_name, volume_name)
except hpexceptions.HTTPNotFound:
msg = (_LE('Virtual Volume Set %s does not exist.') %
volume_set_name)
LOG.error(msg)
raise exception.InvalidInput(reason=msg)
for volume in remove_volumes:
volume_name = self._get_3par_vol_name(volume['id'])
try:
self.client.removeVolumeFromVolumeSet(
volume_set_name, volume_name)
except hpexceptions.HTTPNotFound:
msg = (_LE('Virtual Volume Set %s does not exist.') %
volume_set_name)
LOG.error(msg)
raise exception.InvalidInput(reason=msg)
return None, None, None
def create_cgsnapshot(self, context, cgsnapshot):
"""Creates a cgsnapshot."""
cg_id = cgsnapshot['consistencygroup_id']
snap_shot_name = self._get_3par_snap_name(cgsnapshot['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']
optional = {'comment': json.dumps(extra),
'readOnly': False}
if self.config.hp3par_snapshot_expiration:
optional['expirationHours'] = (
int(self.config.hp3par_snapshot_expiration))
if self.config.hp3par_snapshot_retention:
optional['retentionHours'] = (
int(self.config.hp3par_snapshot_retention))
self.client.createSnapshotOfVolumeSet(snap_shot_name, copy_of_name,
optional=optional)
snapshots = objects.SnapshotList().get_all_for_cgsnapshot(
context, cgsnapshot['id'])
for snapshot in snapshots:
snapshot.status = 'available'
model_update = {'status': 'available'}
return model_update, snapshots
def delete_cgsnapshot(self, context, cgsnapshot):
"""Deletes a cgsnapshot."""
cgsnap_name = self._get_3par_snap_name(cgsnapshot['id'])
snapshots = objects.SnapshotList().get_all_for_cgsnapshot(
context, cgsnapshot['id'])
for i, snapshot in enumerate(snapshots):
try:
snap_name = cgsnap_name + "-" + six.text_type(i)
self.client.deleteVolume(snap_name)
except hpexceptions.HTTPForbidden as ex:
LOG.error(_LE("Exception: %s."), ex)
raise exception.NotAuthorized()
except hpexceptions.HTTPNotFound as ex:
# We'll let this act as if it worked
# it helps clean up the cinder entries.
LOG.warning(_LW("Delete Snapshot id not found. Removing from "
"cinder: %(id)s Ex: %(msg)s"),
{'id': snapshot['id'], 'msg': ex})
except hpexceptions.HTTPConflict as ex:
LOG.error(_LE("Exception: %s."), ex)
raise exception.SnapshotIsBusy(snapshot_name=snapshot['id'])
snapshot['status'] = 'deleted'
model_update = {'status': cgsnapshot['status']}
return model_update, snapshots
def manage_existing(self, volume, existing_ref):
"""Manage an existing 3PAR volume.
@ -817,6 +982,9 @@ class HP3PARCommon(object):
'multiattach': True,
}
if hp3parclient.version >= MIN_CG_CLIENT_VERSION:
pool['consistencygroup_support'] = True
pools.append(pool)
self.stats = {'driver_version': '1.0',
@ -1191,7 +1359,6 @@ class HP3PARCommon(object):
cpg = pool
self.validate_cpg(cpg)
# Look to see if the snap_cpg was specified in volume type
# extra spec, if not use hp3par_cpg_snap from config as the
# default.
@ -1292,6 +1459,10 @@ class HP3PARCommon(object):
tdvv = type_info['tdvv']
flash_cache = self.get_flash_cache_policy(type_info['hp3par_keys'])
cg_id = volume.get('consistencygroup_id', None)
if cg_id:
vvs_name = self._get_3par_vvs_name(cg_id)
type_id = volume.get('volume_type_id', None)
if type_id is not None:
comments['volume_type_name'] = volume_type.get('name')
@ -1494,7 +1665,8 @@ class HP3PARCommon(object):
LOG.error(_LE("Exception: %s"), ex)
raise exception.CinderException(ex)
def create_volume_from_snapshot(self, volume, snapshot):
def create_volume_from_snapshot(self, volume, snapshot, snap_name=None,
vvs_name=None):
"""Creates a volume from a snapshot.
"""
@ -1510,7 +1682,8 @@ class HP3PARCommon(object):
raise exception.InvalidInput(reason=err)
try:
snap_name = self._get_3par_snap_name(snapshot['id'])
if not snap_name:
snap_name = self._get_3par_snap_name(snapshot['id'])
volume_name = self._get_3par_vol_name(volume['id'])
extra = {'volume_id': volume['id'],
@ -1518,8 +1691,10 @@ class HP3PARCommon(object):
type_id = volume.get('volume_type_id', None)
hp3par_keys, qos, _volume_type, vvs_name = self.get_type_info(
hp3par_keys, qos, _volume_type, vvs = self.get_type_info(
type_id)
if vvs:
vvs_name = vvs
name = volume.get('display_name', None)
if name:

View File

@ -80,10 +80,11 @@ class HP3PARFCDriver(cinder.volume.driver.FibreChannelDriver):
2.0.16 - Added encrypted property to initialize_connection #1439917
2.0.17 - Improved VLUN creation and deletion logic. #1469816
2.0.18 - Changed initialize_connection to use getHostVLUNs. #1475064
2.0.19 - Adds consistency group support
"""
VERSION = "2.0.18"
VERSION = "2.0.19"
def __init__(self, *args, **kwargs):
super(HP3PARFCDriver, self).__init__(*args, **kwargs)
@ -427,6 +428,54 @@ class HP3PARFCDriver(cinder.volume.driver.FibreChannelDriver):
finally:
self._logout(common)
def create_consistencygroup(self, context, group):
common = self._login()
try:
return common.create_consistencygroup(context, group)
finally:
self._logout(common)
def create_consistencygroup_from_src(self, context, group, volumes,
cgsnapshot=None, snapshots=None,
source_cg=None, source_vols=None):
common = self._login()
try:
return common.create_consistencygroup_from_src(
context, group, volumes, cgsnapshot, snapshots, source_cg,
source_vols)
finally:
self._logout(common)
def delete_consistencygroup(self, context, group):
common = self._login()
try:
return common.delete_consistencygroup(context, group)
finally:
self._logout(common)
def update_consistencygroup(self, context, group,
add_volumes=None, remove_volumes=None):
common = self._login()
try:
return common.update_consistencygroup(context, group, add_volumes,
remove_volumes)
finally:
self._logout(common)
def create_cgsnapshot(self, context, cgsnapshot):
common = self._login()
try:
return common.create_cgsnapshot(context, cgsnapshot)
finally:
self._logout(common)
def delete_cgsnapshot(self, context, cgsnapshot):
common = self._login()
try:
return common.delete_cgsnapshot(context, cgsnapshot)
finally:
self._logout(common)
def manage_existing(self, volume, existing_ref):
common = self._login()
try:

View File

@ -90,10 +90,11 @@ class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver):
2.0.18 - Improved VLUN creation and deletion logic. #1469816
2.0.19 - Changed initialize_connection to use getHostVLUNs. #1475064
2.0.20 - Adding changes to support 3PAR iSCSI multipath.
2.0.21 - Adds consistency group support
"""
VERSION = "2.0.20"
VERSION = "2.0.21"
def __init__(self, *args, **kwargs):
super(HP3PARISCSIDriver, self).__init__(*args, **kwargs)
@ -724,6 +725,54 @@ class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver):
finally:
self._logout(common)
def create_consistencygroup(self, context, group):
common = self._login()
try:
common.create_consistencygroup(context, group)
finally:
self._logout(common)
def create_consistencygroup_from_src(self, context, group, volumes,
cgsnapshot=None, snapshots=None,
source_cg=None, source_vols=None):
common = self._login()
try:
return common.create_consistencygroup_from_src(
context, group, volumes, cgsnapshot, snapshots, source_cg,
source_vols)
finally:
self._logout(common)
def delete_consistencygroup(self, context, group):
common = self._login()
try:
return common.delete_consistencygroup(context, group)
finally:
self._logout(common)
def update_consistencygroup(self, context, group,
add_volumes=None, remove_volumes=None):
common = self._login()
try:
return common.update_consistencygroup(context, group, add_volumes,
remove_volumes)
finally:
self._logout(common)
def create_cgsnapshot(self, context, cgsnapshot):
common = self._login()
try:
return common.create_cgsnapshot(context, cgsnapshot)
finally:
self._logout(common)
def delete_cgsnapshot(self, context, cgsnapshot):
common = self._login()
try:
return common.delete_cgsnapshot(context, cgsnapshot)
finally:
self._logout(common)
def manage_existing(self, volume, existing_ref):
common = self._login()
try: