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
'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}
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):
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
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
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 = {}
self.config = config
self.client = None
self.uuid = uuid.uuid4()
+ self.db = importutils.import_module('cinder.db')
def get_version(self):
return self.VERSION
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.
'multiattach': True,
}
+ if hp3parclient.version >= MIN_CG_CLIENT_VERSION:
+ pool['consistencygroup_support'] = True
+
pools.append(pool)
self.stats = {'driver_version': '1.0',
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.
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')
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.
"""
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'],
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: