Merge "Storwize: add CG capability to generic groups"

This commit is contained in:
Jenkins 2017-04-07 15:35:12 +00:00 committed by Gerrit Code Review
commit a5f3addc8b
5 changed files with 387 additions and 266 deletions

View File

@ -48,6 +48,7 @@ from cinder.volume.drivers.ibm.storwize_svc import storwize_const
from cinder.volume.drivers.ibm.storwize_svc import storwize_svc_common
from cinder.volume.drivers.ibm.storwize_svc import storwize_svc_fc
from cinder.volume.drivers.ibm.storwize_svc import storwize_svc_iscsi
from cinder.volume import group_types
from cinder.volume import qos_specs
from cinder.volume import utils as volume_utils
from cinder.volume import volume_types
@ -3685,54 +3686,55 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
self.driver.delete_volume(volume)
self.db.volume_destroy(self.ctxt, volume['id'])
def _create_consistencygroup_in_db(self, **kwargs):
cg = testutils.create_consistencygroup(self.ctxt, **kwargs)
def _create_group_in_db(self, **kwargs):
cg = testutils.create_group(self.ctxt, **kwargs)
return cg
def _create_consistencegroup(self, **kwargs):
cg = self._create_consistencygroup_in_db(**kwargs)
def _create_group(self, **kwargs):
grp = self._create_group_in_db(**kwargs)
model_update = self.driver.create_consistencygroup(self.ctxt, cg)
self.assertEqual(fields.ConsistencyGroupStatus.AVAILABLE,
model_update = self.driver.create_group(self.ctxt, grp)
self.assertEqual(fields.GroupStatus.AVAILABLE,
model_update['status'],
"CG created failed")
return cg
return grp
def _create_cgsnapshot_in_db(self, cg_id, **kwargs):
cg_snapshot = testutils.create_cgsnapshot(self.ctxt,
consistencygroup_id= cg_id,
**kwargs)
def _create_group_snapshot_in_db(self, group_id, **kwargs):
group_snapshot = testutils.create_group_snapshot(self.ctxt,
group_id=group_id,
**kwargs)
snapshots = []
cg_id = cg_snapshot['consistencygroup_id']
volumes = self.db.volume_get_all_by_group(self.ctxt.elevated(), cg_id)
volumes = self.db.volume_get_all_by_generic_group(
self.ctxt.elevated(), group_id)
if not volumes:
msg = _("Consistency group is empty. No cgsnapshot "
"will be created.")
raise exception.InvalidConsistencyGroup(reason=msg)
msg = _("Group is empty. No cgsnapshot will be created.")
raise exception.InvalidGroup(reason=msg)
for volume in volumes:
snapshots.append(testutils.create_snapshot(
self.ctxt, volume['id'],
cg_snapshot.id,
cg_snapshot.name,
cg_snapshot.id,
group_snapshot.id,
group_snapshot.name,
group_snapshot.id,
fields.SnapshotStatus.CREATING))
return cg_snapshot, snapshots
return group_snapshot, snapshots
def _create_cgsnapshot(self, cg_id, **kwargs):
cg_snapshot, snapshots = self._create_cgsnapshot_in_db(cg_id, **kwargs)
def _create_group_snapshot(self, cg_id, **kwargs):
group_snapshot, snapshots = self._create_group_snapshot_in_db(
cg_id, **kwargs)
model_update, snapshots_model = (
self.driver.create_cgsnapshot(self.ctxt, cg_snapshot, snapshots))
self.assertEqual('available',
self.driver.create_group_snapshot(self.ctxt, group_snapshot,
snapshots))
self.assertEqual(fields.GroupSnapshotStatus.AVAILABLE,
model_update['status'],
"CGSnapshot created failed")
for snapshot in snapshots_model:
self.assertEqual(fields.SnapshotStatus.AVAILABLE,
snapshot['status'])
return cg_snapshot, snapshots
return group_snapshot, snapshots
def _create_test_vol(self, opts):
ctxt = testutils.get_test_admin_context()
@ -4065,8 +4067,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
volume)
# Try to delete a volume that doesn't exist (should not fail)
vol_no_exist = {'name': 'i_dont_exist',
'id': '111111'}
vol_no_exist = self._generate_vol_info(None, None)
self.driver.delete_volume(vol_no_exist)
# Ensure export for volume that doesn't exist (should not fail)
self.driver.ensure_export(None, vol_no_exist)
@ -4075,15 +4076,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
self.driver.delete_volume(volume)
def test_storwize_svc_volume_name(self):
# Create a volume with space in name
pool = _get_test_pool()
rand_id = six.text_type(random.randint(10000, 99999))
volume = {'name': 'volume_ space',
'size': 10,
'id': '%s' % rand_id,
'volume_type_id': None,
'mdisk_grp_name': pool,
'host': 'openstack@svc#%s' % pool}
volume = self._generate_vol_info(None, None)
self.driver.create_volume(volume)
self.driver.ensure_export(None, volume)
@ -4295,6 +4288,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
each_pool['thin_provisioning_support'])
self.assertEqual(not is_thin_provisioning_enabled,
each_pool['thick_provisioning_support'])
self.assertTrue(each_pool['consistent_group_snapshot_enabled'])
if self.USESIM:
expected = 'storwize-svc-sim'
self.assertEqual(expected, stats['volume_backend_name'])
@ -4951,232 +4945,300 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
attrs = self.driver._helpers.get_vdisk_attributes(vol2['name'])
self.assertIn('openstack2', attrs['mdisk_grp_name'])
# Test groups operation ####
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_storwize_group_create_with_replication(
self, is_grp_a_cg_snapshot_type):
"""Test group create."""
is_grp_a_cg_snapshot_type.side_effect = True
spec = {'replication_enabled': '<is> True',
'replication_type': '<in> metro'}
rep_type_ref = volume_types.create(self.ctxt, 'rep_type', spec)
rep_group = testutils.create_group(
self.ctxt, group_type_id=fake.GROUP_TYPE_ID,
volume_type_ids=[rep_type_ref['id']])
model_update = self.driver.create_group(self.ctxt, rep_group)
self.assertEqual(fields.GroupStatus.ERROR,
model_update['status'])
self.assertFalse(is_grp_a_cg_snapshot_type.called)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_storwize_group_create(self, is_grp_a_cg_snapshot_type):
"""Test group create."""
is_grp_a_cg_snapshot_type.side_effect = [False, True]
group = mock.MagicMock()
self.assertRaises(NotImplementedError,
self.driver.create_group, self.ctxt, group)
model_update = self.driver.create_group(self.ctxt, group)
self.assertEqual(fields.GroupStatus.AVAILABLE,
model_update['status'])
@mock.patch('oslo_service.loopingcall.FixedIntervalLoopingCall',
new=testutils.ZeroIntervalLoopingCall)
def test_storwize_consistency_group_snapshot(self):
cg_type = self._create_consistency_group_volume_type()
self.ctxt.user_id = fake.USER_ID
self.ctxt.project_id = fake.PROJECT_ID
cg = self._create_consistencygroup_in_db(volume_type_id=cg_type['id'])
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_storwize_delete_group(self, is_grp_a_cg_snapshot_type):
is_grp_a_cg_snapshot_type.side_effect = [False, True]
type_ref = volume_types.create(self.ctxt, 'testtype', None)
group = testutils.create_group(self.ctxt,
group_type_id=fake.GROUP_TYPE_ID,
volume_type_id=type_ref['id'])
model_update = self.driver.create_consistencygroup(self.ctxt, cg)
self._create_volume(volume_type_id=type_ref['id'], group_id=group.id)
self._create_volume(volume_type_id=type_ref['id'], group_id=group.id)
volumes = self.db.volume_get_all_by_generic_group(
self.ctxt.elevated(), group.id)
self.assertRaises(NotImplementedError,
self.driver.delete_group,
self.ctxt, group, volumes)
self.assertEqual(fields.ConsistencyGroupStatus.AVAILABLE,
model_update['status'],
"CG created failed")
volumes = [
self._create_volume(volume_type_id=cg_type['id'],
consistencygroup_id=cg['id']),
self._create_volume(volume_type_id=cg_type['id'],
consistencygroup_id=cg['id']),
self._create_volume(volume_type_id=cg_type['id'],
consistencygroup_id=cg['id'])
]
cg_snapshot, snapshots = self._create_cgsnapshot_in_db(cg['id'])
snapshots = objects.SnapshotList.get_all_for_cgsnapshot(
self.ctxt, cg_snapshot.id)
model_update = self.driver.create_cgsnapshot(self.ctxt, cg_snapshot,
snapshots)
self.assertEqual('available',
model_update[0]['status'],
"CGSnapshot created failed")
for snapshot in model_update[1]:
self.assertEqual(fields.SnapshotStatus.AVAILABLE,
snapshot['status'])
model_update = self.driver.delete_consistencygroup(self.ctxt,
cg, volumes)
self.assertEqual(fields.ConsistencyGroupStatus.DELETED,
model_update = self.driver.delete_group(self.ctxt, group, volumes)
self.assertEqual(fields.GroupStatus.DELETED,
model_update[0]['status'])
for volume in model_update[1]:
self.assertEqual('deleted', volume['status'])
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_storwize_group_update(self, is_grp_a_cg_snapshot_type):
"""Test group update."""
is_grp_a_cg_snapshot_type.side_effect = [False, True]
group = mock.MagicMock()
self.assertRaises(NotImplementedError, self.driver.update_group,
self.ctxt, group, None, None)
(model_update, add_volumes_update,
remove_volumes_update) = self.driver.update_group(self.ctxt, group)
self.assertIsNone(model_update)
self.assertIsNone(add_volumes_update)
self.assertIsNone(remove_volumes_update)
@mock.patch('oslo_service.loopingcall.FixedIntervalLoopingCall',
new=testutils.ZeroIntervalLoopingCall)
def test_storwize_consistency_group_from_src_invalid(self):
# Invalid input case for create cg from src
cg_type = self._create_consistency_group_volume_type()
self.ctxt.user_id = fake.USER_ID
self.ctxt.project_id = fake.PROJECT_ID
# create cg in db
cg = self._create_consistencygroup_in_db(volume_type_id=cg_type['id'])
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_storwize_create_group_snapshot(self, is_grp_a_cg_snapshot_type):
is_grp_a_cg_snapshot_type.side_effect = [False, True]
type_ref = volume_types.create(self.ctxt, 'testtype', None)
group = testutils.create_group(self.ctxt,
group_type_id=fake.GROUP_TYPE_ID,
volume_type_id=type_ref['id'])
self._create_volume(volume_type_id=type_ref['id'], group_id=group.id)
self._create_volume(volume_type_id=type_ref['id'], group_id=group.id)
group_snapshot, snapshots = self._create_group_snapshot_in_db(
group.id)
self.assertRaises(NotImplementedError,
self.driver.create_group_snapshot,
self.ctxt, group_snapshot, snapshots)
(model_update,
snapshots_model_update) = self.driver.create_group_snapshot(
self.ctxt, group_snapshot, snapshots)
self.assertEqual(fields.GroupSnapshotStatus.AVAILABLE,
model_update['status'],
"CGSnapshot created failed")
for snapshot in snapshots_model_update:
self.assertEqual(fields.SnapshotStatus.AVAILABLE,
snapshot['status'])
@mock.patch('oslo_service.loopingcall.FixedIntervalLoopingCall',
new=testutils.ZeroIntervalLoopingCall)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_storwize_delete_group_snapshot(self, is_grp_a_cg_snapshot_type):
is_grp_a_cg_snapshot_type.side_effect = [True, False, True]
type_ref = volume_types.create(self.ctxt, 'testtype', None)
group = testutils.create_group(self.ctxt,
group_type_id=fake.GROUP_TYPE_ID,
volume_type_id=type_ref['id'])
self._create_volume(volume_type_id=type_ref['id'], group_id=group.id)
self._create_volume(volume_type_id=type_ref['id'], group_id=group.id)
group_snapshot, snapshots = self._create_group_snapshot(group.id)
self.assertRaises(NotImplementedError,
self.driver.delete_group_snapshot,
self.ctxt, group_snapshot, snapshots)
model_update = self.driver.delete_group_snapshot(self.ctxt,
group_snapshot,
snapshots)
self.assertEqual(fields.GroupSnapshotStatus.DELETED,
model_update[0]['status'])
for volume in model_update[1]:
self.assertEqual(fields.SnapshotStatus.DELETED, volume['status'])
@mock.patch('oslo_service.loopingcall.FixedIntervalLoopingCall',
new=testutils.ZeroIntervalLoopingCall)
def test_storwize_create_group_from_src_invalid(self):
# Invalid input case for create group from src
type_ref = volume_types.create(self.ctxt, 'testtype', None)
spec = {'consistent_group_snapshot_enabled': '<is> True'}
cg_type_ref = group_types.create(self.ctxt, 'cg_type', spec)
vg_type_ref = group_types.create(self.ctxt, 'vg_type', None)
# create group in db
group = self._create_group_in_db(volume_type_id=type_ref.id,
group_type_id=vg_type_ref.id)
self.assertRaises(NotImplementedError,
self.driver.create_group_from_src,
self.ctxt, group, None, None, None,
None, None)
group = self._create_group_in_db(volume_type_id=type_ref.id,
group_type_id=cg_type_ref.id)
# create volumes in db
vol1 = testutils.create_volume(self.ctxt, volume_type_id=cg_type['id'],
consistencygroup_id=cg['id'])
vol2 = testutils.create_volume(self.ctxt, volume_type_id=cg_type['id'],
consistencygroup_id=cg['id'])
vol1 = testutils.create_volume(self.ctxt, volume_type_id=type_ref.id,
group_id=group.id)
vol2 = testutils.create_volume(self.ctxt, volume_type_id=type_ref.id,
group_id=group.id)
volumes = [vol1, vol2]
source_cg = self._create_consistencegroup(volume_type_id=cg_type['id'])
source_cg = self._create_group_in_db(volume_type_id=type_ref.id,
group_type_id=cg_type_ref.id)
# Add volumes to source CG
src_vol1 = self._create_volume(volume_type_id=cg_type['id'],
consistencygroup_id=source_cg['id'])
src_vol2 = self._create_volume(volume_type_id=cg_type['id'],
consistencygroup_id=source_cg['id'])
src_vol1 = self._create_volume(volume_type_id=type_ref.id,
group_id=source_cg['id'])
src_vol2 = self._create_volume(volume_type_id=type_ref.id,
group_id=source_cg['id'])
source_vols = [src_vol1, src_vol2]
cgsnapshot, snapshots = self._create_cgsnapshot(source_cg['id'])
group_snapshot, snapshots = self._create_group_snapshot(
source_cg['id'], group_type_id=cg_type_ref.id)
# Create cg from src with null input
# Create group from src with null input
self.assertRaises(exception.InvalidInput,
self.driver.create_consistencygroup_from_src,
self.ctxt, cg, volumes, None, None,
self.driver.create_group_from_src,
self.ctxt, group, volumes, None, None,
None, None)
# Create cg from src with source_cg and empty source_vols
self.assertRaises(exception.InvalidInput,
self.driver.create_consistencygroup_from_src,
self.ctxt, cg, volumes, None, None,
self.driver.create_group_from_src,
self.ctxt, group, volumes, None, None,
source_cg, None)
# Create cg from src with source_vols and empty source_cg
self.assertRaises(exception.InvalidInput,
self.driver.create_consistencygroup_from_src,
self.ctxt, cg, volumes, None, None,
self.driver.create_group_from_src,
self.ctxt, group, volumes, None, None,
None, source_vols)
# Create cg from src with cgsnapshot and empty snapshots
self.assertRaises(exception.InvalidInput,
self.driver.create_consistencygroup_from_src,
self.ctxt, cg, volumes, cgsnapshot, None,
self.driver.create_group_from_src,
self.ctxt, group, volumes, group_snapshot, None,
None, None)
# Create cg from src with snapshots and empty cgsnapshot
self.assertRaises(exception.InvalidInput,
self.driver.create_consistencygroup_from_src,
self.ctxt, cg, volumes, None, snapshots,
self.driver.create_group_from_src,
self.ctxt, group, volumes, None, snapshots,
None, None)
model_update = self.driver.delete_consistencygroup(self.ctxt,
cg, volumes)
model_update = self.driver.delete_group(self.ctxt, group, volumes)
self.assertEqual(fields.ConsistencyGroupStatus.DELETED,
self.assertEqual(fields.GroupStatus.DELETED,
model_update[0]['status'])
for volume in model_update[1]:
self.assertEqual('deleted', volume['status'])
model_update = (
self.driver.delete_consistencygroup(self.ctxt,
source_cg, source_vols))
model_update = self.driver.delete_group(self.ctxt,
source_cg, source_vols)
self.assertEqual(fields.ConsistencyGroupStatus.DELETED,
self.assertEqual(fields.GroupStatus.DELETED,
model_update[0]['status'])
for volume in model_update[1]:
self.assertEqual('deleted', volume['status'])
model_update = (
self.driver.delete_consistencygroup(self.ctxt,
cgsnapshot, snapshots))
model_update = self.driver.delete_group(self.ctxt,
group_snapshot, snapshots)
self.assertEqual(fields.ConsistencyGroupStatus.DELETED,
self.assertEqual(fields.GroupStatus.DELETED,
model_update[0]['status'])
for volume in model_update[1]:
self.assertEqual('deleted', volume['status'])
@mock.patch('oslo_service.loopingcall.FixedIntervalLoopingCall',
new=testutils.ZeroIntervalLoopingCall)
def test_storwize_consistency_group_from_src(self):
def test_storwize_group_from_src(self):
# Valid case for create cg from src
cg_type = self._create_consistency_group_volume_type()
self.ctxt.user_id = fake.USER_ID
self.ctxt.project_id = fake.PROJECT_ID
type_ref = volume_types.create(self.ctxt, 'testtype', None)
spec = {'consistent_group_snapshot_enabled': '<is> True'}
cg_type_ref = group_types.create(self.ctxt, 'cg_type', spec)
pool = _get_test_pool()
# Create cg in db
cg = self._create_consistencygroup_in_db(volume_type_id=cg_type['id'])
group = self._create_group_in_db(volume_type_id=type_ref.id,
group_type_id=cg_type_ref.id)
# Create volumes in db
testutils.create_volume(self.ctxt, volume_type_id=cg_type['id'],
consistencygroup_id=cg['id'],
testutils.create_volume(self.ctxt, volume_type_id=type_ref.id,
group_id=group.id,
host='openstack@svc#%s' % pool)
testutils.create_volume(self.ctxt, volume_type_id=cg_type['id'],
consistencygroup_id=cg['id'],
testutils.create_volume(self.ctxt, volume_type_id=type_ref.id,
consistencygroup_id=group.id,
host='openstack@svc#%s' % pool)
volumes = (
self.db.volume_get_all_by_group(self.ctxt.elevated(), cg['id']))
volumes = self.db.volume_get_all_by_generic_group(
self.ctxt.elevated(), group.id)
# Create source CG
source_cg = self._create_consistencegroup(volume_type_id=cg_type['id'])
source_cg = self._create_group_in_db(volume_type_id=type_ref.id,
group_type_id=cg_type_ref.id)
# Add volumes to source CG
self._create_volume(volume_type_id=cg_type['id'],
consistencygroup_id=source_cg['id'])
self._create_volume(volume_type_id=cg_type['id'],
consistencygroup_id=source_cg['id'])
source_vols = self.db.volume_get_all_by_group(
self._create_volume(volume_type_id=type_ref.id,
group_id=source_cg['id'])
self._create_volume(volume_type_id=type_ref.id,
group_id=source_cg['id'])
source_vols = self.db.volume_get_all_by_generic_group(
self.ctxt.elevated(), source_cg['id'])
# Create cgsnapshot
cgsnapshot, snapshots = self._create_cgsnapshot(source_cg['id'])
group_snapshot, snapshots = self._create_group_snapshot(
source_cg['id'], group_type_id=cg_type_ref.id)
# Create cg from source cg
model_update, volumes_model_update = (
self.driver.create_consistencygroup_from_src(self.ctxt,
cg,
volumes,
None, None,
source_cg,
source_vols))
self.assertEqual(fields.ConsistencyGroupStatus.AVAILABLE,
self.driver.create_group_from_src(self.ctxt, group, volumes, None,
None, source_cg, source_vols))
self.assertEqual(fields.GroupStatus.AVAILABLE,
model_update['status'],
"CG create from src created failed")
for each_vol in volumes_model_update:
self.assertEqual('available', each_vol['status'])
model_update = self.driver.delete_consistencygroup(self.ctxt,
cg,
volumes)
self.assertEqual(fields.ConsistencyGroupStatus.DELETED,
model_update = self.driver.delete_group(self.ctxt, group, volumes)
self.assertEqual(fields.GroupStatus.DELETED,
model_update[0]['status'])
for each_vol in model_update[1]:
self.assertEqual('deleted', each_vol['status'])
# Create cg from cg snapshot
model_update, volumes_model_update = (
self.driver.create_consistencygroup_from_src(self.ctxt,
cg,
volumes,
cgsnapshot,
snapshots,
None, None))
self.assertEqual(fields.ConsistencyGroupStatus.AVAILABLE,
self.driver.create_group_from_src(self.ctxt, group, volumes,
group_snapshot, snapshots,
None, None))
self.assertEqual(fields.GroupStatus.AVAILABLE,
model_update['status'],
"CG create from src created failed")
for each_vol in volumes_model_update:
self.assertEqual('available', each_vol['status'])
model_update = self.driver.delete_consistencygroup(self.ctxt,
cg, volumes)
self.assertEqual(fields.ConsistencyGroupStatus.DELETED,
model_update = self.driver.delete_group(self.ctxt, group, volumes)
self.assertEqual(fields.GroupStatus.DELETED,
model_update[0]['status'])
for each_vol in model_update[1]:
self.assertEqual('deleted', each_vol['status'])
model_update = self.driver.delete_consistencygroup(self.ctxt,
cgsnapshot,
snapshots)
self.assertEqual(fields.ConsistencyGroupStatus.DELETED,
model_update = self.driver.delete_group_snapshot(self.ctxt,
group_snapshot,
snapshots)
self.assertEqual(fields.GroupStatus.DELETED,
model_update[0]['status'])
for volume in model_update[1]:
self.assertEqual('deleted', volume['status'])
model_update = self.driver.delete_consistencygroup(self.ctxt,
source_cg,
source_vols)
self.assertEqual(fields.ConsistencyGroupStatus.DELETED,
model_update[0]['status'])
for each_vol in model_update[1]:
self.assertEqual('deleted', each_vol['status'])
def _create_volume_type_qos(self, extra_specs, fake_qos):
# Generate a QoS volume type for volume.
if extra_specs:
@ -5871,27 +5933,20 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
is_vol_defined = self.driver._helpers.is_vdisk_defined(name)
self.assertEqual(exists, is_vol_defined)
def _generate_vol_info(self, vol_name, vol_id, vol_type=None):
def _generate_vol_info(self, vol_type=None, size=1):
pool = _get_test_pool()
rand_id = six.text_type(random.randint(10000, 99999))
volume_type = self.non_replica_type
if vol_type:
volume_type = vol_type
if vol_name:
return {'name': 'snap_volume%s' % rand_id,
'volume_name': vol_name,
'id': rand_id,
'volume_id': vol_id,
'volume_size': 10,
'mdisk_grp_name': pool}
else:
return {'name': 'test_volume%s' % rand_id,
'size': 10,
'id': '%s' % rand_id,
'mdisk_grp_name': pool,
'host': 'openstack@svc#%s' % pool,
'volume_type_id': volume_type['id'],
'volume_type': volume_type}
volume_type = vol_type if vol_type else self.non_replica_type
prop = {'size': size,
'volume_type_id': volume_type.id,
'host': 'openstack@svc#%s' % pool
}
vol = testutils.create_volume(self.ctxt, **prop)
return vol
def _generate_snap_info(self, vol_id):
prop = {'volume_id': vol_id}
snap = testutils.create_snapshot(self.ctxt, **prop)
return snap
def _create_replica_volume_type(self, enable,
rep_type=storwize_const.METRO):
@ -5910,8 +5965,7 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
type_name = "non_rep"
type_ref = volume_types.create(self.ctxt, type_name, spec)
replication_type = volume_types.get_volume_type(self.ctxt,
replication_type = objects.VolumeType.get_by_id(self.ctxt,
type_ref['id'])
return replication_type
@ -5923,14 +5977,7 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
self.non_replica_type = self._create_replica_volume_type(False)
def _create_test_volume(self, rep_type):
volume = self._generate_vol_info(None, None, rep_type)
opts = {}
for p in volume.keys():
if p not in volume:
opts[p] = volume[p]
vol = testutils.create_volume(self.ctxt, **opts)
volume['id'] = vol['id']
volume['name'] = vol['name']
volume = self._generate_vol_info(rep_type)
model_update = self.driver.create_volume(volume)
volume['status'] = 'available'
return volume, model_update
@ -6054,10 +6101,10 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
vol1, model_update = self._create_test_volume(self.mm_type)
self.assertEqual('enabled', model_update['replication_status'])
snap = self._generate_vol_info(vol1['name'], vol1['id'])
snap = testutils.create_snapshot(self.ctxt, vol1.id)
self.driver.create_snapshot(snap)
vol2 = self._generate_vol_info(None, None, self.mm_type)
vol2 = self._generate_vol_info(self.mm_type)
model_update = self.driver.create_volume_from_snapshot(vol2, snap)
self.assertEqual('enabled', model_update['replication_status'])
self._validate_replic_vol_creation(vol2)
@ -6076,7 +6123,7 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
src_volume, model_update = self._create_test_volume(self.mm_type)
self.assertEqual('enabled', model_update['replication_status'])
volume = self._generate_vol_info(None, None, self.mm_type)
volume = self._generate_vol_info(self.mm_type)
# Create a cloned volume from source volume.
model_update = self.driver.create_cloned_volume(volume, src_volume)
@ -6177,7 +6224,7 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
non_rep_volume, model_update = self._create_test_volume(
self.non_replica_type)
new_volume = self._generate_vol_info(None, None)
new_volume = self._generate_vol_info()
ref = {'source-name': rep_volume['name']}
new_volume['volume_type_id'] = self.non_replica_type['id']
@ -6213,7 +6260,7 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
uid_of_aux = self._get_vdisk_uid(
storwize_const.REPLICA_AUX_VOL_PREFIX + rep_volume['name'])
new_volume = self._generate_vol_info(None, None)
new_volume = self._generate_vol_info()
ref = {'source-name': rep_volume['name']}
new_volume['volume_type_id'] = self.mm_type['id']
new_volume['volume_type'] = self.mm_type
@ -6692,7 +6739,7 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
'start_relationship')
def test_sync_replica_volumes_with_aux(self, start_relationship):
# Create metro mirror replication.
mm_vol = self._generate_vol_info(None, None, self.mm_type)
mm_vol = self._generate_vol_info(self.mm_type)
tgt_volume = storwize_const.REPLICA_AUX_VOL_PREFIX + mm_vol['name']
volumes = [mm_vol]
@ -6741,7 +6788,7 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
new=testutils.ZeroIntervalLoopingCall)
def test_wait_replica_vol_ready(self, get_relationship_info):
# Create metro mirror replication.
mm_vol = self._generate_vol_info(None, None, self.mm_type)
mm_vol = self._generate_vol_info(self.mm_type)
fake_info = {'volume': 'fake',
'master_vdisk_name': 'fake',
'aux_vdisk_name': 'fake',

View File

@ -1343,7 +1343,7 @@ class StorwizeHelpers(object):
def run_consistgrp_snapshots(self, fc_consistgrp, snapshots, state,
config, timeout):
model_update = {'status': fields.ConsistencyGroupStatus.AVAILABLE}
model_update = {'status': fields.GroupSnapshotStatus.AVAILABLE}
snapshots_model_update = []
try:
for snapshot in snapshots:
@ -1362,7 +1362,7 @@ class StorwizeHelpers(object):
# Cinder general will maintain the CG and snapshots relationship.
self.delete_fc_consistgrp(fc_consistgrp)
except exception.VolumeBackendAPIException as err:
model_update['status'] = fields.ConsistencyGroupStatus.ERROR
model_update['status'] = fields.GroupSnapshotStatus.ERROR
# Release cg
self.delete_fc_consistgrp(fc_consistgrp)
LOG.error("Failed to create CGSnapshot. "
@ -1377,7 +1377,7 @@ class StorwizeHelpers(object):
def delete_consistgrp_snapshots(self, fc_consistgrp, snapshots):
"""Delete flashcopy maps and consistent group."""
model_update = {'status': fields.ConsistencyGroupStatus.DELETED}
model_update = {'status': fields.GroupSnapshotStatus.DELETED}
snapshots_model_update = []
try:
@ -1385,7 +1385,7 @@ class StorwizeHelpers(object):
self.ssh.rmvdisk(snapshot['name'], True)
except exception.VolumeBackendAPIException as err:
model_update['status'] = (
fields.ConsistencyGroupStatus.ERROR_DELETING)
fields.GroupSnapshotStatus.ERROR_DELETING)
LOG.error("Failed to delete the snapshot %(snap)s of "
"CGSnapshot. Exception: %(exception)s.",
{'snap': snapshot['name'], 'exception': err})
@ -1429,7 +1429,7 @@ class StorwizeHelpers(object):
LOG.debug('Enter: create_cg_from_source: cg %(cg)s'
' source %(source)s, target %(target)s',
{'cg': fc_consistgrp, 'source': sources, 'target': targets})
model_update = {'status': fields.ConsistencyGroupStatus.AVAILABLE}
model_update = {'status': fields.GroupStatus.AVAILABLE}
ctxt = context.get_admin_context()
try:
for source, target in zip(sources, targets):
@ -1447,7 +1447,7 @@ class StorwizeHelpers(object):
volumes_model_update = self._get_volume_model_updates(
ctxt, targets, group['id'], model_update['status'])
except exception.VolumeBackendAPIException as err:
model_update['status'] = fields.ConsistencyGroupStatus.ERROR
model_update['status'] = fields.GroupStatus.ERROR
volumes_model_update = self._get_volume_model_updates(
ctxt, targets, group['id'], model_update['status'])
with excutils.save_and_reraise_exception():
@ -3065,13 +3065,13 @@ class StorwizeSVCCommonDriver(san.SanDriver,
raise exception.InvalidInput(reason=msg)
return replication_type
def _get_volume_replicated_type(self, ctxt, volume):
def _get_volume_replicated_type(self, ctxt, volume, vol_type_id=None):
replication_type = None
if volume.get("volume_type_id"):
volume_type = volume_types.get_volume_type(
ctxt, volume["volume_type_id"])
volume_type = (volume.volume_type if volume else
objects.VolumeType.get_by_name_or_id(ctxt,
vol_type_id))
if volume_type:
replication_type = self._get_specs_replicated_type(volume_type)
return replication_type
def _get_storwize_config(self):
@ -3479,23 +3479,49 @@ class StorwizeSVCCommonDriver(san.SanDriver,
return self._stats
def create_consistencygroup(self, context, group):
"""Create a consistency group.
# Add CG capability to generic volume groups
def create_group(self, context, group):
"""Creates a group.
IBM Storwize will create CG until cg-snapshot creation,
db will maintain the volumes and CG relationship.
:param context: the context of the caller.
:param group: the group object.
:returns: model_update
"""
LOG.debug("Creating consistency group.")
model_update = {'status': fields.ConsistencyGroupStatus.AVAILABLE}
return model_update
def delete_consistencygroup(self, context, group, volumes):
"""Deletes a consistency group.
LOG.debug("Creating group.")
model_update = {'status': fields.GroupStatus.AVAILABLE}
IBM Storwize will delete the volumes of the CG.
for vol_type_id in group.volume_type_ids:
replication_type = self._get_volume_replicated_type(
context, None, vol_type_id)
if replication_type:
# An unsupported configuration
LOG.error('Unable to create group: create group with '
'replication volume type is not supported.')
model_update = {'status': fields.GroupStatus.ERROR}
return model_update
if utils.is_group_a_cg_snapshot_type(group):
return {'status': fields.GroupStatus.AVAILABLE}
# we'll rely on the generic group implementation if it is not a
# consistency group request.
raise NotImplementedError()
def delete_group(self, context, group, volumes):
"""Deletes a group.
:param context: the context of the caller.
:param group: the group object.
:param volumes: a list of volume objects in the group.
:returns: model_update, volumes_model_update
"""
LOG.debug("Deleting consistency group.")
model_update = {'status': fields.ConsistencyGroupStatus.DELETED}
LOG.debug("Deleting group.")
if not utils.is_group_a_cg_snapshot_type(group):
# we'll rely on the generic group implementation if it is
# not a consistency group request.
raise NotImplementedError()
model_update = {'status': fields.GroupStatus.DELETED}
volumes_model_update = []
for volume in volumes:
@ -3505,51 +3531,69 @@ class StorwizeSVCCommonDriver(san.SanDriver,
{'id': volume['id'], 'status': 'deleted'})
except exception.VolumeBackendAPIException as err:
model_update['status'] = (
fields.ConsistencyGroupStatus.ERROR_DELETING)
fields.GroupStatus.ERROR_DELETING)
LOG.error("Failed to delete the volume %(vol)s of CG. "
"Exception: %(exception)s.",
{'vol': volume['name'], 'exception': err})
volumes_model_update.append(
{'id': volume['id'], 'status': 'error_deleting'})
{'id': volume['id'],
'status': fields.GroupStatus.ERROR_DELETING})
return model_update, volumes_model_update
def update_consistencygroup(self, ctxt, group, add_volumes,
remove_volumes):
"""Adds or removes volume(s) to/from an existing consistency group."""
LOG.debug("Updating consistency group.")
return None, None, None
def create_consistencygroup_from_src(self, context, group, volumes,
cgsnapshot=None, snapshots=None,
source_cg=None, source_vols=None):
"""Creates a consistencygroup from source.
def update_group(self, context, group, add_volumes=None,
remove_volumes=None):
"""Updates a group.
:param context: the context of the caller.
:param group: the dictionary of the consistency group to be created.
:param volumes: a list of volume dictionaries in the group.
:param cgsnapshot: the dictionary of the cgsnapshot as source.
:param snapshots: a list of snapshot dictionaries in the cgsnapshot.
:param source_cg: the dictionary of a consistency group as source.
:param source_vols: a list of volume dictionaries in the source_cg.
:param group: the group object.
:param add_volumes: a list of volume objects to be added.
:param remove_volumes: a list of volume objects to be removed.
:returns: model_update, add_volumes_update, remove_volumes_update
"""
LOG.debug("Updating group.")
if utils.is_group_a_cg_snapshot_type(group):
return None, None, None
# we'll rely on the generic group implementation if it is not a
# consistency group request.
raise NotImplementedError()
def create_group_from_src(self, context, group, volumes,
group_snapshot=None, snapshots=None,
source_group=None, source_vols=None):
"""Creates a group from source.
:param context: the context of the caller.
:param group: the Group object to be created.
:param volumes: a list of Volume objects in the group.
:param group_snapshot: the GroupSnapshot object as source.
:param snapshots: a list of snapshot objects in group_snapshot.
:param source_group: the Group object as source.
:param source_vols: a list of volume objects in the source_group.
:returns: model_update, volumes_model_update
"""
LOG.debug('Enter: create_consistencygroup_from_src.')
if cgsnapshot and snapshots:
cg_name = 'cg-' + cgsnapshot.id
LOG.debug('Enter: create_group_from_src.')
if not utils.is_group_a_cg_snapshot_type(group):
# we'll rely on the generic volume groups implementation if it is
# not a consistency group request.
raise NotImplementedError()
if group_snapshot and snapshots:
cg_name = 'cg-' + group_snapshot.id
sources = snapshots
elif source_cg and source_vols:
cg_name = 'cg-' + source_cg.id
elif source_group and source_vols:
cg_name = 'cg-' + source_group.id
sources = source_vols
else:
error_msg = _("create_consistencygroup_from_src must be "
"creating from a CG snapshot, or a source CG.")
error_msg = _("create_group_from_src must be creating from a "
"group snapshot, or a source group.")
raise exception.InvalidInput(reason=error_msg)
LOG.debug('create_consistencygroup_from_src: cg_name %(cg_name)s'
LOG.debug('create_group_from_src: cg_name %(cg_name)s'
' %(sources)s', {'cg_name': cg_name, 'sources': sources})
self._helpers.create_fc_consistgrp(cg_name)
timeout = self.configuration.storwize_svc_flashcopy_timeout
@ -3561,13 +3605,24 @@ class StorwizeSVCCommonDriver(san.SanDriver,
self._state,
self.configuration,
timeout))
LOG.debug("Leave: create_consistencygroup_from_src.")
LOG.debug("Leave: create_group_from_src.")
return model_update, snapshots_model
def create_cgsnapshot(self, ctxt, cgsnapshot, snapshots):
"""Creates a cgsnapshot."""
# Use cgsnapshot id as cg name
cg_name = 'cg_snap-' + cgsnapshot.id
def create_group_snapshot(self, context, group_snapshot, snapshots):
"""Creates a group_snapshot.
:param context: the context of the caller.
:param group_snapshot: the GroupSnapshot object to be created.
:param snapshots: a list of Snapshot objects in the group_snapshot.
:returns: model_update, snapshots_model_update
"""
if not utils.is_group_a_cg_snapshot_type(group_snapshot):
# we'll rely on the generic group implementation if it is not a
# consistency group request.
raise NotImplementedError()
# Use group_snapshot id as cg name
cg_name = 'cg_snap-' + group_snapshot.id
# Create new cg as cg_snapshot
self._helpers.create_fc_consistgrp(cg_name)
@ -3582,9 +3637,21 @@ class StorwizeSVCCommonDriver(san.SanDriver,
return model_update, snapshots_model
def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
"""Deletes a cgsnapshot."""
cgsnapshot_id = cgsnapshot['id']
def delete_group_snapshot(self, context, group_snapshot, snapshots):
"""Deletes a group_snapshot.
:param context: the context of the caller.
:param group_snapshot: the GroupSnapshot object to be deleted.
:param snapshots: a list of snapshot objects in the group_snapshot.
:returns: model_update, snapshots_model_update
"""
if not utils.is_group_a_cg_snapshot_type(group_snapshot):
# we'll rely on the generic group implementation if it is not a
# consistency group request.
raise NotImplementedError()
cgsnapshot_id = group_snapshot.id
cg_name = 'cg_snap-' + cgsnapshot_id
model_update, snapshots_model = (
@ -3671,6 +3738,7 @@ class StorwizeSVCCommonDriver(san.SanDriver,
'thin_provisioning_support': not use_thick_provisioning,
'thick_provisioning_support': use_thick_provisioning,
'max_over_subscription_ratio': over_sub_ratio,
'consistent_group_snapshot_enabled': True,
}
if self._replica_enabled:
pool_stats.update({

View File

@ -88,9 +88,10 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
2.1 - Added replication V2 support to the global/metro mirror
mode
2.1.1 - Update replication to version 2.1
2.2 - Add CG capability to generic volume groups
"""
VERSION = "2.1.1"
VERSION = "2.2"
# ThirdPartySystems wiki page
CI_WIKI_NAME = "IBM_STORAGE_CI"

View File

@ -88,9 +88,10 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
2.1 - Added replication V2 support to the global/metro mirror
mode
2.1.1 - Update replication to version 2.1
2.2 - Add CG capability to generic volume groups
"""
VERSION = "2.1.1"
VERSION = "2.2"
# ThirdPartySystems wiki page
CI_WIKI_NAME = "IBM_STORAGE_CI"

View File

@ -0,0 +1,4 @@
---
features:
- Add consistency group capability to generic volume groups in Storwize
drivers.