Storwize: add mirrored volume support
Add mirrored volume support for IBM Storwize. Stretch cluster volume support is also added for IBM SVC. One new property is added in volume type config. User can specify the pool in which mirrored copy is stored by mirror_pool. Implements: blueprint stretch-cluster-svc Change-Id: I4870bfc1789a57b9083dc8551949943334a20a05
This commit is contained in:
parent
6ce8d6f32f
commit
76fc4edc64
@ -325,7 +325,8 @@ class StorwizeSVCManagementSimulator(object):
|
||||
'aux',
|
||||
'cluster',
|
||||
'linkbandwidthmbits',
|
||||
'backgroundcopyrate'
|
||||
'backgroundcopyrate',
|
||||
'copies'
|
||||
]
|
||||
no_or_one_param_args = [
|
||||
'autoexpand',
|
||||
@ -732,10 +733,25 @@ port_speed!N/A
|
||||
volume_info['uid'] = ('ABCDEF' * 3) + ('0' * 14) + volume_info['id']
|
||||
|
||||
mdiskgrp = kwargs['mdiskgrp'].strip('\'\"')
|
||||
sec_pool = None
|
||||
is_mirror_vol = False
|
||||
if 'copies' in kwargs:
|
||||
# it is a mirror volume
|
||||
pool_split = mdiskgrp.split(':')
|
||||
if len(pool_split) != 2:
|
||||
raise exception.InvalidInput(
|
||||
reason=_('mdiskgrp %s is invalid for mirror '
|
||||
'volume') % kwargs['mdiskgrp'])
|
||||
else:
|
||||
is_mirror_vol = True
|
||||
mdiskgrp = pool_split[0]
|
||||
sec_pool = pool_split[1]
|
||||
|
||||
if mdiskgrp == kwargs['mdiskgrp']:
|
||||
raise exception.InvalidInput(
|
||||
reason=_('mdiskgrp missing quotes %s') % kwargs['mdiskgrp'])
|
||||
mdiskgrp_id = self._get_mdiskgrp_id(mdiskgrp)
|
||||
sec_pool_id = self._get_mdiskgrp_id(sec_pool)
|
||||
volume_info['mdisk_grp_name'] = mdiskgrp
|
||||
volume_info['mdisk_grp_id'] = str(mdiskgrp_id)
|
||||
|
||||
@ -803,6 +819,16 @@ port_speed!N/A
|
||||
'easy_tier': volume_info['easy_tier'],
|
||||
'compressed_copy': volume_info['compressed_copy']}
|
||||
volume_info['copies'] = {'0': vol_cp}
|
||||
if is_mirror_vol:
|
||||
vol_cp1 = {'id': '1',
|
||||
'status': 'online',
|
||||
'sync': 'yes',
|
||||
'primary': 'no',
|
||||
'mdisk_grp_id': str(sec_pool_id),
|
||||
'mdisk_grp_name': sec_pool,
|
||||
'easy_tier': volume_info['easy_tier'],
|
||||
'compressed_copy': volume_info['compressed_copy']}
|
||||
volume_info['copies']['1'] = vol_cp1
|
||||
|
||||
if volume_info['name'] in self._volumes_list:
|
||||
return self._errors['CMMVC6035E']
|
||||
@ -1588,32 +1614,17 @@ port_speed!N/A
|
||||
return self._errors['CMMVC5707E']
|
||||
mdiskgrp = kwargs['mdiskgrp'].strip('\'\"')
|
||||
vdisk = kwargs['vdisk'].strip('\'\"')
|
||||
copy_id = kwargs['copy']
|
||||
if vdisk not in self._volumes_list:
|
||||
return self._errors['CMMVC5753E']
|
||||
mdiskgrp_id = str(self._get_mdiskgrp_id(mdiskgrp))
|
||||
|
||||
if vdisk in self._volumes_list:
|
||||
curr_mdiskgrp = self._volumes_list
|
||||
else:
|
||||
for pool in self._other_pools:
|
||||
if vdisk in pool:
|
||||
curr_mdiskgrp = pool
|
||||
break
|
||||
else:
|
||||
return self._errors['CMMVC5754E']
|
||||
self._volumes_list[vdisk]['mdisk_grp_name'] = mdiskgrp
|
||||
self._volumes_list[vdisk]['mdisk_grp_id'] = mdiskgrp_id
|
||||
|
||||
if mdiskgrp == self._flags['storwize_svc_volpool_name']:
|
||||
tgt_mdiskgrp = self._volumes_list
|
||||
elif mdiskgrp == 'openstack2':
|
||||
tgt_mdiskgrp = self._other_pools['openstack2']
|
||||
elif mdiskgrp == 'openstack3':
|
||||
tgt_mdiskgrp = self._other_pools['openstack3']
|
||||
else:
|
||||
return self._errors['CMMVC5754E']
|
||||
|
||||
if curr_mdiskgrp == tgt_mdiskgrp:
|
||||
return self._errors['CMMVC6430E']
|
||||
|
||||
vol = curr_mdiskgrp[vdisk]
|
||||
tgt_mdiskgrp[vdisk] = vol
|
||||
del curr_mdiskgrp[vdisk]
|
||||
vol = self._volumes_list[vdisk]
|
||||
vol['copies'][copy_id]['mdisk_grp_name'] = mdiskgrp
|
||||
vol['copies'][copy_id]['mdisk_grp_id'] = mdiskgrp_id
|
||||
return ('', '')
|
||||
|
||||
def _cmd_addvdiskcopy(self, **kwargs):
|
||||
@ -1629,6 +1640,7 @@ port_speed!N/A
|
||||
if mdiskgrp == kwargs['mdiskgrp']:
|
||||
raise exception.InvalidInput(
|
||||
reason=_('mdiskgrp missing quotes %s') % kwargs['mdiskgrp'])
|
||||
auto_del = True if 'autodelete' in kwargs else False
|
||||
|
||||
copy_info = {}
|
||||
copy_info['id'] = self._find_unused_id(vol['copies'])
|
||||
@ -1649,6 +1661,14 @@ port_speed!N/A
|
||||
else:
|
||||
copy_info['compressed_copy'] = 'no'
|
||||
vol['copies'][copy_info['id']] = copy_info
|
||||
if auto_del:
|
||||
del_copy_id = None
|
||||
for v in vol['copies'].values():
|
||||
if v['id'] != copy_info['id']:
|
||||
del_copy_id = v['id']
|
||||
break
|
||||
if del_copy_id:
|
||||
del vol['copies'][del_copy_id]
|
||||
return ('Vdisk [%(vid)s] copy [%(cid)s] successfully created' %
|
||||
{'vid': vol['id'], 'cid': copy_info['id']}, '')
|
||||
|
||||
@ -1725,6 +1745,8 @@ port_speed!N/A
|
||||
for key, value in kwargs.items():
|
||||
if key == 'easytier':
|
||||
vol['easy_tier'] = value
|
||||
for copy in vol['copies'].values():
|
||||
vol['copies'][copy['id']]['easy_tier'] = value
|
||||
continue
|
||||
if key == 'warning':
|
||||
vol['warning'] = value.rstrip('%')
|
||||
@ -1749,6 +1771,9 @@ port_speed!N/A
|
||||
return ('', err)
|
||||
if key in params:
|
||||
vol[key] = value
|
||||
if key == 'autoexpand':
|
||||
for copy in vol['copies'].values():
|
||||
vol['copies'][copy['id']]['autoexpand'] = value
|
||||
else:
|
||||
err = self._errors['CMMVC5709E'][1] % {'VALUE': key}
|
||||
return ('', err)
|
||||
@ -3447,6 +3472,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
self.driver._helpers.check_fcmapping_interval = 0
|
||||
self.mock_object(storwize_svc_iscsi.StorwizeSVCISCSIDriver,
|
||||
'DEFAULT_GR_SLEEP', 0)
|
||||
self._create_test_volume_types()
|
||||
|
||||
def _set_flag(self, flag, value, configuration=None):
|
||||
if not configuration:
|
||||
@ -3465,6 +3491,11 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
is_vol_defined = self.driver._helpers.is_vdisk_defined(name)
|
||||
self.assertEqual(exists, is_vol_defined)
|
||||
|
||||
def _create_test_volume_types(self):
|
||||
spec = {'mirror_pool': 'openstack1'}
|
||||
self.mirror_vol_type = self._create_volume_type(spec, 'mirror_type')
|
||||
self.default_vol_type = self._create_volume_type(None, 'default_type')
|
||||
|
||||
def test_storwize_svc_connectivity(self):
|
||||
# Make sure we detect if the pool doesn't exist
|
||||
no_exist_pool = 'i-dont-exist-%s' % random.randint(10000, 99999)
|
||||
@ -3656,21 +3687,26 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
self.assertEqual(self._driver.configuration.storwize_san_secondary_ip,
|
||||
self._driver.active_ip)
|
||||
|
||||
def _generate_vol_info(self, vol_name, vol_id):
|
||||
def _create_volume_type(self, opts, type_name):
|
||||
type_ref = volume_types.create(self.ctxt, type_name, opts)
|
||||
vol_type = objects.VolumeType.get_by_id(self.ctxt, type_ref['id'])
|
||||
return vol_type
|
||||
|
||||
def _generate_vol_info(self, vol_type=None, size=10):
|
||||
pool = _get_test_pool()
|
||||
prop = {'mdisk_grp_name': pool}
|
||||
if vol_name:
|
||||
prop.update(volume_name=vol_name,
|
||||
volume_id=vol_id,
|
||||
volume_size=10)
|
||||
else:
|
||||
prop.update(size=10,
|
||||
volume_type_id=None,
|
||||
mdisk_grp_name=pool,
|
||||
host='openstack@svc#%s' % pool)
|
||||
prop = {'size': size,
|
||||
'host': 'openstack@svc#%s' % pool}
|
||||
if vol_type:
|
||||
prop['volume_type_id'] = vol_type.id
|
||||
vol = testutils.create_volume(self.ctxt, **prop)
|
||||
return vol
|
||||
|
||||
def _generate_snap_info(self, vol_id, size=10):
|
||||
prop = {'volume_id': vol_id,
|
||||
'volume_size': size}
|
||||
snap = testutils.create_snapshot(self.ctxt, **prop)
|
||||
return snap
|
||||
|
||||
def _create_volume(self, **kwargs):
|
||||
pool = _get_test_pool()
|
||||
prop = {'host': 'openstack@svc#%s' % pool,
|
||||
@ -3739,7 +3775,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
def _create_test_vol(self, opts):
|
||||
ctxt = testutils.get_test_admin_context()
|
||||
type_ref = volume_types.create(ctxt, 'testtype', opts)
|
||||
volume = self._generate_vol_info(None, None)
|
||||
volume = self._generate_vol_info()
|
||||
volume.volume_type_id = type_ref['id']
|
||||
volume.volume_typ = objects.VolumeType.get_by_id(ctxt,
|
||||
type_ref['id'])
|
||||
@ -3761,7 +3797,8 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
'qos': None,
|
||||
'replication': False,
|
||||
'stretched_cluster': None,
|
||||
'nofmtdisk': False}
|
||||
'nofmtdisk': False,
|
||||
'mirror_pool': None}
|
||||
return opt
|
||||
|
||||
@mock.patch.object(storwize_svc_common.StorwizeHelpers, 'add_vdisk_qos')
|
||||
@ -3792,7 +3829,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
|
||||
def test_storwize_svc_snapshots(self):
|
||||
vol1 = self._create_volume()
|
||||
snap1 = self._generate_vol_info(vol1['name'], vol1['id'])
|
||||
snap1 = self._generate_snap_info(vol1.id)
|
||||
|
||||
# Test timeout and volume cleanup
|
||||
self._set_flag('storwize_svc_flashcopy_timeout', 1)
|
||||
@ -3824,7 +3861,8 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
self._assert_vol_exists(snap1['name'], True)
|
||||
|
||||
# Try to create a snapshot from an non-existing volume - should fail
|
||||
snap_novol = self._generate_vol_info('undefined-vol', '12345')
|
||||
vol2 = self._generate_vol_info()
|
||||
snap_novol = self._generate_snap_info(vol2.id)
|
||||
self.assertRaises(exception.VolumeDriverException,
|
||||
self.driver.create_snapshot,
|
||||
snap_novol)
|
||||
@ -3880,14 +3918,14 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
|
||||
def test_storwize_svc_create_volume_from_snapshot(self):
|
||||
vol1 = self._create_volume()
|
||||
snap1 = self._generate_vol_info(vol1['name'], vol1['id'])
|
||||
snap1 = self._generate_snap_info(vol1.id)
|
||||
self.driver.create_snapshot(snap1)
|
||||
vol2 = self._generate_vol_info(None, None)
|
||||
vol3 = self._generate_vol_info(None, None)
|
||||
vol2 = self._generate_vol_info()
|
||||
vol3 = self._generate_vol_info()
|
||||
|
||||
# Try to create a volume from a non-existing snapshot
|
||||
snap_novol = self._generate_vol_info('undefined-vol', '12345')
|
||||
vol_novol = self._generate_vol_info(None, None)
|
||||
vol_novol = self._generate_vol_info()
|
||||
snap_novol = self._generate_snap_info(vol_novol.id)
|
||||
self.assertRaises(exception.VolumeDriverException,
|
||||
self.driver.create_volume_from_snapshot,
|
||||
vol_novol,
|
||||
@ -3938,10 +3976,10 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
def test_storwize_svc_create_volfromsnap_clone_with_qos(self,
|
||||
add_vdisk_qos):
|
||||
vol1 = self._create_volume()
|
||||
snap1 = self._generate_vol_info(vol1['name'], vol1['id'])
|
||||
snap1 = self._generate_snap_info(vol1.id)
|
||||
self.driver.create_snapshot(snap1)
|
||||
vol2 = self._generate_vol_info(None, None)
|
||||
vol3 = self._generate_vol_info(None, None)
|
||||
vol2 = self._generate_vol_info()
|
||||
vol3 = self._generate_vol_info()
|
||||
fake_opts = self._get_default_opts()
|
||||
|
||||
# Succeed
|
||||
@ -4002,12 +4040,12 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
def test_storwize_svc_delete_vol_with_fcmap(self):
|
||||
vol1 = self._create_volume()
|
||||
# create two snapshots
|
||||
snap1 = self._generate_vol_info(vol1['name'], vol1['id'])
|
||||
snap2 = self._generate_vol_info(vol1['name'], vol1['id'])
|
||||
snap1 = self._generate_snap_info(vol1.id)
|
||||
snap2 = self._generate_snap_info(vol1.id)
|
||||
self.driver.create_snapshot(snap1)
|
||||
self.driver.create_snapshot(snap2)
|
||||
vol2 = self._generate_vol_info(None, None)
|
||||
vol3 = self._generate_vol_info(None, None)
|
||||
vol2 = self._generate_vol_info()
|
||||
vol3 = self._generate_vol_info()
|
||||
|
||||
# Create vol from the second snapshot
|
||||
if self.USESIM:
|
||||
@ -4045,7 +4083,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
|
||||
def test_storwize_svc_volumes(self):
|
||||
# Create a first volume
|
||||
volume = self._generate_vol_info(None, None)
|
||||
volume = self._generate_vol_info()
|
||||
self.driver.create_volume(volume)
|
||||
|
||||
self.driver.ensure_export(None, volume)
|
||||
@ -4067,7 +4105,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
volume)
|
||||
|
||||
# Try to delete a volume that doesn't exist (should not fail)
|
||||
vol_no_exist = self._generate_vol_info(None, None)
|
||||
vol_no_exist = self._generate_vol_info()
|
||||
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)
|
||||
@ -4076,7 +4114,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
self.driver.delete_volume(volume)
|
||||
|
||||
def test_storwize_svc_volume_name(self):
|
||||
volume = self._generate_vol_info(None, None)
|
||||
volume = self._generate_vol_info()
|
||||
self.driver.create_volume(volume)
|
||||
self.driver.ensure_export(None, volume)
|
||||
|
||||
@ -4154,7 +4192,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
self.driver.do_setup(None)
|
||||
|
||||
rand_id = random.randint(10000, 99999)
|
||||
volume1 = self._generate_vol_info(None, None)
|
||||
volume1 = self._generate_vol_info()
|
||||
self.driver.create_volume(volume1)
|
||||
self._assert_vol_exists(volume1['name'], True)
|
||||
|
||||
@ -4199,21 +4237,21 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
|
||||
# Fail creating a snapshot - will force delete the snapshot
|
||||
if self.USESIM and False:
|
||||
snap = self._generate_vol_info(master['name'], master['id'])
|
||||
snap = self._generate_snap_info(master.id)
|
||||
self.sim.error_injection('startfcmap', 'bad_id')
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.create_snapshot, snap)
|
||||
self._assert_vol_exists(snap['name'], False)
|
||||
|
||||
# Delete a snapshot
|
||||
snap = self._generate_vol_info(master['name'], master['id'])
|
||||
snap = self._generate_snap_info(master.id)
|
||||
self.driver.create_snapshot(snap)
|
||||
self._assert_vol_exists(snap['name'], True)
|
||||
self.driver.delete_snapshot(snap)
|
||||
self._assert_vol_exists(snap['name'], False)
|
||||
|
||||
# Delete a volume with snapshots (regular)
|
||||
snap = self._generate_vol_info(master['name'], master['id'])
|
||||
snap = self._generate_snap_info(master.id)
|
||||
self.driver.create_snapshot(snap)
|
||||
self._assert_vol_exists(snap['name'], True)
|
||||
self.driver.delete_volume(master)
|
||||
@ -4221,7 +4259,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
|
||||
# Fail create volume from snapshot - will force delete the volume
|
||||
if self.USESIM:
|
||||
volfs = self._generate_vol_info(None, None)
|
||||
volfs = self._generate_vol_info()
|
||||
self.sim.error_injection('startfcmap', 'bad_id')
|
||||
self.sim.error_injection('lsfcmap', 'speed_up')
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
@ -4230,7 +4268,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
self._assert_vol_exists(volfs['name'], False)
|
||||
|
||||
# Create volume from snapshot and delete it
|
||||
volfs = self._generate_vol_info(None, None)
|
||||
volfs = self._generate_vol_info()
|
||||
if self.USESIM:
|
||||
self.sim.error_injection('lsfcmap', 'speed_up')
|
||||
self.driver.create_volume_from_snapshot(volfs, snap)
|
||||
@ -4239,7 +4277,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
self._assert_vol_exists(volfs['name'], False)
|
||||
|
||||
# Create volume from snapshot and delete the snapshot
|
||||
volfs = self._generate_vol_info(None, None)
|
||||
volfs = self._generate_vol_info()
|
||||
if self.USESIM:
|
||||
self.sim.error_injection('lsfcmap', 'speed_up')
|
||||
self.driver.create_volume_from_snapshot(volfs, snap)
|
||||
@ -4248,7 +4286,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
|
||||
# Fail create clone - will force delete the target volume
|
||||
if self.USESIM:
|
||||
clone = self._generate_vol_info(None, None)
|
||||
clone = self._generate_vol_info()
|
||||
self.sim.error_injection('startfcmap', 'bad_id')
|
||||
self.sim.error_injection('lsfcmap', 'speed_up')
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
@ -4257,7 +4295,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
self._assert_vol_exists(clone['name'], False)
|
||||
|
||||
# Create the clone, delete the source and target
|
||||
clone = self._generate_vol_info(None, None)
|
||||
clone = self._generate_vol_info()
|
||||
if self.USESIM:
|
||||
self.sim.error_injection('lsfcmap', 'speed_up')
|
||||
self.driver.create_cloned_volume(clone, volfs)
|
||||
@ -4306,12 +4344,13 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
def test_get_pool(self):
|
||||
ctxt = testutils.get_test_admin_context()
|
||||
type_ref = volume_types.create(ctxt, 'testtype', None)
|
||||
volume = self._generate_vol_info(None, None)
|
||||
volume = self._generate_vol_info()
|
||||
volume.volume_type_id = type_ref['id']
|
||||
volume.volume_type = objects.VolumeType.get_by_id(ctxt,
|
||||
type_ref['id'])
|
||||
self.driver.create_volume(volume)
|
||||
self.assertEqual(volume['mdisk_grp_name'],
|
||||
vol = self.driver._helpers.get_vdisk_attributes(volume.name)
|
||||
self.assertEqual(vol['mdisk_grp_name'],
|
||||
self.driver.get_pool(volume))
|
||||
|
||||
self.driver.delete_volume(volume)
|
||||
@ -4325,7 +4364,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
|
||||
self.assertAlmostEqual(vol_size, 13)
|
||||
|
||||
snap = self._generate_vol_info(volume['name'], volume['id'])
|
||||
snap = self._generate_snap_info(volume.id)
|
||||
self.driver.create_snapshot(snap)
|
||||
self._assert_vol_exists(snap['name'], True)
|
||||
self.assertRaises(exception.VolumeDriverException,
|
||||
@ -4537,10 +4576,9 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
diff, _equal = volume_types.volume_types_diff(ctxt, old_type_ref['id'],
|
||||
new_type_ref['id'])
|
||||
|
||||
volume = self._generate_vol_info(None, None)
|
||||
old_type = objects.VolumeType.get_by_id(ctxt,
|
||||
old_type_ref['id'])
|
||||
volume['volume_type'] = old_type
|
||||
volume = self._generate_vol_info(old_type)
|
||||
volume['host'] = host['host']
|
||||
new_type = objects.VolumeType.get_by_id(ctxt,
|
||||
new_type_ref['id'])
|
||||
@ -4629,10 +4667,9 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
diff, _equal = volume_types.volume_types_diff(ctxt, old_type_ref['id'],
|
||||
new_type_ref['id'])
|
||||
|
||||
volume = self._generate_vol_info(None, None)
|
||||
old_type = objects.VolumeType.get_by_id(ctxt,
|
||||
old_type_ref['id'])
|
||||
volume['volume_type'] = old_type
|
||||
volume = self._generate_vol_info(old_type)
|
||||
volume['host'] = host['host']
|
||||
new_type = objects.VolumeType.get_by_id(ctxt,
|
||||
new_type_ref['id'])
|
||||
@ -4666,10 +4703,9 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
diff, _equal = volume_types.volume_types_diff(ctxt, old_type_ref['id'],
|
||||
new_type_ref['id'])
|
||||
|
||||
volume = self._generate_vol_info(None, None)
|
||||
old_type = objects.VolumeType.get_by_id(ctxt,
|
||||
old_type_ref['id'])
|
||||
volume['volume_type'] = old_type
|
||||
volume = self._generate_vol_info(old_type)
|
||||
volume['host'] = host['host']
|
||||
new_type = objects.VolumeType.get_by_id(ctxt,
|
||||
new_type_ref['id'])
|
||||
@ -4801,7 +4837,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
self.assertNotIn(volume['id'], self.driver._vdiskcopyops)
|
||||
|
||||
def test_storwize_create_volume_with_replication_disable(self):
|
||||
volume = self._generate_vol_info(None, None)
|
||||
volume = self._generate_vol_info()
|
||||
|
||||
model_update = self.driver.create_volume(volume)
|
||||
self.assertIsNone(model_update)
|
||||
@ -4814,7 +4850,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
self._set_flag('storwize_svc_stretched_cluster_partner', 'openstack2')
|
||||
|
||||
# Create a type for repliation.
|
||||
volume = self._generate_vol_info(None, None)
|
||||
volume = self._generate_vol_info()
|
||||
volume_type = self._create_replication_volume_type(True)
|
||||
volume['volume_type_id'] = volume_type['id']
|
||||
|
||||
@ -4907,11 +4943,11 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
self.driver.do_setup(self.ctxt)
|
||||
|
||||
# Create a source volume.
|
||||
src_volume = self._generate_vol_info(None, None)
|
||||
src_volume = self._generate_vol_info()
|
||||
self.driver.create_volume(src_volume)
|
||||
|
||||
# Create a type for repliation.
|
||||
volume = self._generate_vol_info(None, None)
|
||||
volume = self._generate_vol_info()
|
||||
volume_type = self._create_replication_volume_type(True)
|
||||
volume['volume_type_id'] = volume_type['id']
|
||||
|
||||
@ -4929,12 +4965,12 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
self.driver.do_setup(self.ctxt)
|
||||
|
||||
vol1 = self._create_volume()
|
||||
snap = self._generate_vol_info(vol1['name'], vol1['id'])
|
||||
snap = self._generate_snap_info(vol1.id)
|
||||
self.driver.create_snapshot(snap)
|
||||
vol2 = self._generate_vol_info(None, None)
|
||||
vol2 = self._generate_vol_info()
|
||||
|
||||
# Create a type for repliation.
|
||||
vol2 = self._generate_vol_info(None, None)
|
||||
vol2 = self._generate_vol_info()
|
||||
volume_type = self._create_replication_volume_type(True)
|
||||
vol2['volume_type_id'] = volume_type['id']
|
||||
|
||||
@ -5239,6 +5275,231 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
for volume in model_update[1]:
|
||||
self.assertEqual('deleted', volume['status'])
|
||||
|
||||
# mirror/strtch cluster volume test cases
|
||||
def test_storwize_svc_create_mirror_volume(self):
|
||||
# create mirror volume in invalid pool
|
||||
spec = {'mirror_pool': 'invalid_pool'}
|
||||
mirror_vol_type = self._create_volume_type(spec, 'invalid_mirror_type')
|
||||
vol = self._generate_vol_info(mirror_vol_type)
|
||||
self.assertRaises(exception.InvalidInput,
|
||||
self.driver.create_volume, vol)
|
||||
|
||||
spec = {'mirror_pool': 'openstack1'}
|
||||
mirror_vol_type = self._create_volume_type(spec, 'test_mirror_type')
|
||||
vol = self._generate_vol_info(mirror_vol_type)
|
||||
self.driver.create_volume(vol)
|
||||
self._assert_vol_exists(vol.name, True)
|
||||
|
||||
copies = self.driver._helpers.get_vdisk_copies(vol.name)
|
||||
self.assertEqual(copies['primary']['mdisk_grp_name'], 'openstack')
|
||||
self.assertEqual(copies['secondary']['mdisk_grp_name'], 'openstack1')
|
||||
self.driver.delete_volume(vol)
|
||||
self._assert_vol_exists(vol['name'], False)
|
||||
|
||||
def test_storwize_svc_snapshots_mirror_volume(self):
|
||||
vol1 = self._generate_vol_info(self.mirror_vol_type)
|
||||
self.driver.create_volume(vol1)
|
||||
|
||||
snap1 = self._generate_snap_info(vol1.id)
|
||||
self._assert_vol_exists(snap1.name, False)
|
||||
|
||||
self.driver.create_snapshot(snap1)
|
||||
if self.USESIM:
|
||||
self.sim.error_injection('lsfcmap', 'speed_up')
|
||||
self._assert_vol_exists(snap1.name, True)
|
||||
copies = self.driver._helpers.get_vdisk_copies(snap1.name)
|
||||
self.assertEqual(copies['primary']['mdisk_grp_name'], 'openstack')
|
||||
self.assertEqual(copies['secondary']['mdisk_grp_name'], 'openstack1')
|
||||
|
||||
self.driver.delete_snapshot(snap1)
|
||||
self.driver.delete_volume(vol1)
|
||||
|
||||
def test_storwize_svc_create_cloned_mirror_volume(self):
|
||||
vol1 = self._generate_vol_info(self.mirror_vol_type)
|
||||
self.driver.create_volume(vol1)
|
||||
vol2 = self._generate_vol_info(self.mirror_vol_type)
|
||||
|
||||
if self.USESIM:
|
||||
self.sim.error_injection('lsfcmap', 'speed_up')
|
||||
self.driver.create_cloned_volume(vol2, vol1)
|
||||
self._assert_vol_exists(vol2.name, True)
|
||||
copies = self.driver._helpers.get_vdisk_copies(vol2.name)
|
||||
self.assertEqual(copies['primary']['mdisk_grp_name'], 'openstack')
|
||||
self.assertEqual(copies['secondary']['mdisk_grp_name'], 'openstack1')
|
||||
|
||||
self.driver.delete_volume(vol2)
|
||||
self._assert_vol_exists(vol2.name, False)
|
||||
self.driver.delete_volume(vol1)
|
||||
self._assert_vol_exists(vol1.name, False)
|
||||
|
||||
def test_storwize_svc_create_mirror_volume_from_snapshot(self):
|
||||
vol1 = self._generate_vol_info(self.mirror_vol_type)
|
||||
self.driver.create_volume(vol1)
|
||||
snap1 = self._generate_snap_info(vol1.id)
|
||||
self.driver.create_snapshot(snap1)
|
||||
|
||||
if self.USESIM:
|
||||
self.sim.error_injection('lsfcmap', 'speed_up')
|
||||
|
||||
vol2 = self._generate_vol_info(self.mirror_vol_type)
|
||||
self.driver.create_volume_from_snapshot(vol2, snap1)
|
||||
self._assert_vol_exists(vol2.name, True)
|
||||
copies = self.driver._helpers.get_vdisk_copies(vol2.name)
|
||||
self.assertEqual(copies['primary']['mdisk_grp_name'], 'openstack')
|
||||
self.assertEqual(copies['secondary']['mdisk_grp_name'], 'openstack1')
|
||||
|
||||
self.driver.delete_volume(vol2)
|
||||
self._assert_vol_exists(vol2['name'], False)
|
||||
self.driver.delete_snapshot(snap1)
|
||||
self._assert_vol_exists(snap1['name'], False)
|
||||
self.driver.delete_volume(vol1)
|
||||
self._assert_vol_exists(vol1['name'], False)
|
||||
|
||||
@mock.patch.object(storwize_svc_common.StorwizeHelpers, 'add_vdisk_copy')
|
||||
def test_storwize_svc_mirror_volume_migrate(self, add_vdisk_copy):
|
||||
# use migratevdisk for mirror volume migration, rather than
|
||||
# addvdiskcopy
|
||||
self.driver.do_setup(None)
|
||||
loc = ('StorwizeSVCDriver:' + self.driver._state['system_id'] +
|
||||
':openstack2')
|
||||
host = {'host': 'openstack@svc#openstack2',
|
||||
'capabilities': {'location_info': loc}}
|
||||
ctxt = context.get_admin_context()
|
||||
vol1 = self._generate_vol_info(self.mirror_vol_type)
|
||||
self.driver.create_volume(vol1)
|
||||
copies = self.driver._helpers.get_vdisk_copies(vol1.name)
|
||||
self.assertEqual(copies['primary']['mdisk_grp_name'], 'openstack')
|
||||
self.assertEqual(copies['secondary']['mdisk_grp_name'], 'openstack1')
|
||||
|
||||
self.driver.migrate_volume(ctxt, vol1, host)
|
||||
copies = self.driver._helpers.get_vdisk_copies(vol1.name)
|
||||
self.assertEqual(copies['primary']['mdisk_grp_name'], 'openstack2')
|
||||
self.assertEqual(copies['secondary']['mdisk_grp_name'], 'openstack1')
|
||||
self.assertFalse(add_vdisk_copy.called)
|
||||
self._delete_volume(vol1)
|
||||
|
||||
@ddt.data(({'mirror_pool': 'openstack1'},
|
||||
{'mirror_pool': 'openstack1', 'compression': True}),
|
||||
({'compression': False},
|
||||
{'mirror_pool': 'openstack1', 'compression': True}),
|
||||
({}, {'mirror_pool': 'invalidpool'}))
|
||||
@ddt.unpack
|
||||
def test_storwize_svc_retype_mirror_volume_invalid(self, old_opts,
|
||||
new_opts):
|
||||
self.driver.do_setup(self.ctxt)
|
||||
host = {'host': 'openstack@svc#openstack'}
|
||||
ctxt = context.get_admin_context()
|
||||
|
||||
vol_type1 = self._create_volume_type(old_opts, 'old')
|
||||
vol_type2 = self._create_volume_type(new_opts, 'new')
|
||||
diff, _equal = volume_types.volume_types_diff(ctxt, vol_type1.id,
|
||||
vol_type2.id)
|
||||
vol1 = self._generate_vol_info(vol_type1)
|
||||
self.driver.create_volume(vol1)
|
||||
|
||||
self.assertRaises(exception.VolumeDriverException,
|
||||
self.driver.retype, self.ctxt, vol1,
|
||||
vol_type2, diff, host)
|
||||
self.driver.delete_volume(vol1)
|
||||
|
||||
@ddt.data(({'mirror_pool': 'openstack1'}, {}),
|
||||
({'mirror_pool': 'openstack1'}, {'mirror_pool': ''}))
|
||||
@ddt.unpack
|
||||
def test_storwize_retype_from_mirror_to_none_mirror(self,
|
||||
old_opts, new_opts):
|
||||
self.driver.do_setup(self.ctxt)
|
||||
host = {'host': 'openstack@svc#openstack'}
|
||||
ctxt = context.get_admin_context()
|
||||
|
||||
vol_type1 = self._create_volume_type(old_opts, 'old')
|
||||
vol_type2 = self._create_volume_type(new_opts, 'new')
|
||||
diff, _equal = volume_types.volume_types_diff(ctxt, vol_type1.id,
|
||||
vol_type2.id)
|
||||
vol1 = self._generate_vol_info(vol_type1)
|
||||
self.driver.create_volume(vol1)
|
||||
|
||||
self._assert_vol_exists(vol1.name, True)
|
||||
copies = self.driver._helpers.lsvdiskcopy(vol1.name)
|
||||
self.assertEqual(len(copies), 2)
|
||||
|
||||
self.driver.retype(self.ctxt, vol1, vol_type2, diff, host)
|
||||
copies = self.driver._helpers.lsvdiskcopy(vol1.name)
|
||||
self.assertEqual(len(copies), 1)
|
||||
copies = self.driver._helpers.get_vdisk_copies(vol1.name)
|
||||
self.assertEqual(copies['primary']['mdisk_grp_name'], 'openstack')
|
||||
|
||||
self.driver.delete_volume(vol1)
|
||||
|
||||
@ddt.data(({}, {'mirror_pool': 'openstack1'}),
|
||||
({'mirror_pool': ''}, {'mirror_pool': 'openstack1'}))
|
||||
@ddt.unpack
|
||||
def test_storwize_retype_from_none_to_mirror_volume(self,
|
||||
old_opts, new_opts):
|
||||
self.driver.do_setup(self.ctxt)
|
||||
host = {'host': 'openstack@svc#openstack'}
|
||||
ctxt = context.get_admin_context()
|
||||
|
||||
old_opts = {}
|
||||
new_opts = {'mirror_pool': 'openstack1'}
|
||||
vol_type1 = self._create_volume_type(old_opts, 'old')
|
||||
vol_type2 = self._create_volume_type(new_opts, 'new')
|
||||
diff, _equal = volume_types.volume_types_diff(ctxt, vol_type1.id,
|
||||
vol_type2.id)
|
||||
vol1 = self._generate_vol_info(vol_type1)
|
||||
self.driver.create_volume(vol1)
|
||||
|
||||
self._assert_vol_exists(vol1.name, True)
|
||||
copies = self.driver._helpers.lsvdiskcopy(vol1.name)
|
||||
self.assertEqual(len(copies), 1)
|
||||
|
||||
self.driver.retype(self.ctxt, vol1, vol_type2, diff, host)
|
||||
copies = self.driver._helpers.lsvdiskcopy(vol1.name)
|
||||
self.assertEqual(len(copies), 2)
|
||||
copies = self.driver._helpers.get_vdisk_copies(vol1.name)
|
||||
self.assertEqual(copies['primary']['mdisk_grp_name'], 'openstack')
|
||||
self.assertEqual(copies['secondary']['mdisk_grp_name'], 'openstack1')
|
||||
|
||||
self.driver.delete_volume(vol1)
|
||||
|
||||
@ddt.data(({}, {'mirror_pool': 'openstack1'}),
|
||||
({'mirror_pool': ''}, {'mirror_pool': 'openstack1'}),
|
||||
({'mirror_pool': 'openstack1'}, {}),
|
||||
({'mirror_pool': 'openstack1'}, {'mirror_pool': ''}),
|
||||
({'mirror_pool': 'openstack1'}, {'mirror_pool': 'invalidpool'}))
|
||||
@ddt.unpack
|
||||
def test_storwize_manage_existing_mismatch_with_mirror_volume(
|
||||
self, opts1, opts2):
|
||||
self.driver.do_setup(self.ctxt)
|
||||
vol_type1 = self._create_volume_type(opts1, 'vol_type1')
|
||||
vol_type2 = self._create_volume_type(opts2, 'vol_type2')
|
||||
vol1 = self._generate_vol_info(vol_type1)
|
||||
self.driver.create_volume(vol1)
|
||||
vol2 = self._generate_vol_info(vol_type2)
|
||||
|
||||
ref = {'source-name': vol1.name}
|
||||
self.assertRaises(exception.ManageExistingVolumeTypeMismatch,
|
||||
self.driver.manage_existing, vol2, ref)
|
||||
|
||||
self.driver.delete_volume(vol1)
|
||||
|
||||
def test_storwize_manage_existing_with_mirror_volume(self):
|
||||
self.driver.do_setup(self.ctxt)
|
||||
vol1 = self._generate_vol_info(self.mirror_vol_type)
|
||||
self.driver.create_volume(vol1)
|
||||
uid_of_vol1 = self._get_vdisk_uid(vol1.name)
|
||||
|
||||
opts1 = {'mirror_pool': 'openstack1'}
|
||||
new_volume_type = self._create_volume_type(opts1, 'new_mirror_type')
|
||||
new_volume = self._generate_vol_info(new_volume_type)
|
||||
ref = {'source-name': vol1.name}
|
||||
self.driver.manage_existing(new_volume, ref)
|
||||
|
||||
# Check the uid of the volume which has been renamed.
|
||||
uid_of_new_vol = self._get_vdisk_uid(new_volume.name)
|
||||
self.assertEqual(uid_of_vol1, uid_of_new_vol)
|
||||
|
||||
self.driver.delete_volume(new_volume)
|
||||
|
||||
def _create_volume_type_qos(self, extra_specs, fake_qos):
|
||||
# Generate a QoS volume type for volume.
|
||||
if extra_specs:
|
||||
@ -5309,7 +5570,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
create_volume and then calling into the simulator to perform an
|
||||
lsvdisk directly.
|
||||
"""
|
||||
volume = self._generate_vol_info(None, None)
|
||||
volume = self._generate_vol_info()
|
||||
self.driver.create_volume(volume)
|
||||
|
||||
return (volume, self._get_vdisk_uid(volume['name']))
|
||||
@ -5321,14 +5582,14 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
a bad reference that the Storwize driver doesn't understand. We
|
||||
expect an exception to be raised.
|
||||
"""
|
||||
volume = self._generate_vol_info(None, None)
|
||||
volume = self._generate_vol_info()
|
||||
ref = {}
|
||||
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||
self.driver.manage_existing_get_size, volume, ref)
|
||||
|
||||
def test_manage_existing_get_size_bad_uid(self):
|
||||
"""Error when the specified UUID does not exist."""
|
||||
volume = self._generate_vol_info(None, None)
|
||||
volume = self._generate_vol_info()
|
||||
ref = {'source-id': 'bad_uid'}
|
||||
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||
self.driver.manage_existing_get_size, volume, ref)
|
||||
@ -5336,7 +5597,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
|
||||
def test_manage_existing_get_size_bad_name(self):
|
||||
"""Error when the specified name does not exist."""
|
||||
volume = self._generate_vol_info(None, None)
|
||||
volume = self._generate_vol_info()
|
||||
ref = {'source-name': 'bad_name'}
|
||||
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||
self.driver.manage_existing_get_size, volume, ref)
|
||||
@ -5350,19 +5611,19 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
"""
|
||||
|
||||
# Error when neither UUID nor name are specified.
|
||||
volume = self._generate_vol_info(None, None)
|
||||
volume = self._generate_vol_info()
|
||||
ref = {}
|
||||
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||
self.driver.manage_existing, volume, ref)
|
||||
|
||||
# Error when the specified UUID does not exist.
|
||||
volume = self._generate_vol_info(None, None)
|
||||
volume = self._generate_vol_info()
|
||||
ref = {'source-id': 'bad_uid'}
|
||||
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||
self.driver.manage_existing, volume, ref)
|
||||
|
||||
# Error when the specified name does not exist.
|
||||
volume = self._generate_vol_info(None, None)
|
||||
volume = self._generate_vol_info()
|
||||
ref = {'source-name': 'bad_name'}
|
||||
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||
self.driver.manage_existing, volume, ref)
|
||||
@ -5386,7 +5647,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
opts = {'rsize': -1, 'iogrp': 1}
|
||||
type_iogrp_ref = volume_types.create(ctxt, 'testtype4', opts)
|
||||
|
||||
new_volume = self._generate_vol_info(None, None)
|
||||
new_volume = self._generate_vol_info()
|
||||
ref = {'source-name': _volume['name']}
|
||||
|
||||
fake_copy_thin = self._get_default_opts()
|
||||
@ -5462,7 +5723,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
|
||||
# Descriptor of the Cinder volume that we want to own the vdisk
|
||||
# referenced by uid.
|
||||
new_volume = self._generate_vol_info(None, None)
|
||||
new_volume = self._generate_vol_info()
|
||||
|
||||
# Submit the request to manage it.
|
||||
ref = {'source-id': uid}
|
||||
@ -5490,7 +5751,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
|
||||
# Descriptor of the Cinder volume that we want to own the vdisk
|
||||
# referenced by uid.
|
||||
new_volume = self._generate_vol_info(None, None)
|
||||
new_volume = self._generate_vol_info()
|
||||
|
||||
# Submit the request to manage it.
|
||||
ref = {'source-name': _volume['name']}
|
||||
@ -5523,7 +5784,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
|
||||
# Descriptor of the Cinder volume that we want to own the vdisk
|
||||
# referenced by uid.
|
||||
volume = self._generate_vol_info(None, None)
|
||||
volume = self._generate_vol_info()
|
||||
ref = {'source-id': uid}
|
||||
|
||||
# Attempt to manage this disk, and except an exception beause the
|
||||
@ -5555,7 +5816,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
|
||||
# Descriptor of the Cinder volume that we want to own the vdisk
|
||||
# referenced by uid.
|
||||
new_volume = self._generate_vol_info(None, None)
|
||||
new_volume = self._generate_vol_info()
|
||||
|
||||
# Submit the request to manage it, specifying that it is OK to
|
||||
# manage a volume that is already attached.
|
||||
@ -5589,7 +5850,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
||||
|
||||
# Descriptor of the Cinder volume that we want to own the vdisk
|
||||
# referenced by uid.
|
||||
new_volume = self._generate_vol_info(None, None)
|
||||
new_volume = self._generate_vol_info()
|
||||
|
||||
# Submit the request to manage it, specifying that it is OK to
|
||||
# manage a volume that is already attached.
|
||||
@ -5856,6 +6117,7 @@ class StorwizeSSHTestCase(test.TestCase):
|
||||
'fakevol', '1', 'gb', 'fakepool', opt, [])
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class StorwizeSVCReplicationTestCase(test.TestCase):
|
||||
@mock.patch.object(time, 'sleep')
|
||||
def setUp(self, mock_sleep):
|
||||
@ -5949,7 +6211,8 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
|
||||
return snap
|
||||
|
||||
def _create_replica_volume_type(self, enable,
|
||||
rep_type=storwize_const.METRO):
|
||||
rep_type=storwize_const.METRO,
|
||||
opts=None, vol_type_name=None):
|
||||
# Generate a volume type for volume repliation.
|
||||
if enable:
|
||||
if rep_type == storwize_const.METRO:
|
||||
@ -5960,6 +6223,9 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
|
||||
spec = {'replication_enabled': '<is> True',
|
||||
'replication_type': '<in> global'}
|
||||
type_name = 'rep_global'
|
||||
elif opts:
|
||||
spec = opts
|
||||
type_name = vol_type_name
|
||||
else:
|
||||
spec = {'replication_enabled': '<is> False'}
|
||||
type_name = "non_rep"
|
||||
@ -6042,6 +6308,21 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
|
||||
self.driver._active_backend_id = None
|
||||
self.driver._get_storwize_config()
|
||||
|
||||
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
|
||||
'create_vdisk')
|
||||
def test_storwize_svc_create_stretch_volume_with_replication(self,
|
||||
create_vdisk):
|
||||
spec = {'mirror_pool': 'openstack1',
|
||||
'replication_enabled': '<is> True',
|
||||
'replication_type': '<in> global'
|
||||
}
|
||||
vol_type = self._create_replica_volume_type(
|
||||
False, opts=spec, vol_type_name='test_type')
|
||||
vol = self._generate_vol_info(vol_type)
|
||||
self.assertRaises(exception.InvalidInput,
|
||||
self.driver.create_volume, vol)
|
||||
self.assertFalse(create_vdisk.called)
|
||||
|
||||
def test_storwize_create_volume_with_mirror_replication(self):
|
||||
# Set replication target.
|
||||
self.driver.configuration.set_override('replication_device',
|
||||
@ -6133,6 +6414,43 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
|
||||
self.driver.delete_volume(src_volume)
|
||||
self.driver.delete_volume(volume)
|
||||
|
||||
@ddt.data(({'replication_enabled': '<is> True',
|
||||
'replication_type': '<in> global'},
|
||||
{'replication_enabled': '<is> True',
|
||||
'replication_type': '<in> metro'}),
|
||||
({'replication_enabled': '<is> True',
|
||||
'replication_type': '<in> metro'},
|
||||
{'replication_enabled': '<is> True',
|
||||
'replication_type': '<in> global'}),
|
||||
({'replication_enabled': '<is> True',
|
||||
'replication_type': '<in> metro'},
|
||||
{'mirror_pool': 'openstack1'}),
|
||||
({'mirror_pool': 'openstack1'},
|
||||
{'mirror_pool': 'openstack1',
|
||||
'replication_enabled': '<is> True',
|
||||
'replication_type': '<in> metro'}),
|
||||
({'replication_enabled': '<is> False'},
|
||||
{'mirror_pool': 'openstack1',
|
||||
'replication_enabled': '<is> True',
|
||||
'replication_type': '<in> metro'}))
|
||||
@ddt.unpack
|
||||
def test_storwize_retype_invalid_replication(self, old_opts, new_opts):
|
||||
# Set replication target
|
||||
self.driver.configuration.set_override('replication_device',
|
||||
[self.rep_target])
|
||||
self.driver.do_setup(self.ctxt)
|
||||
host = {'host': 'openstack@svc#openstack'}
|
||||
old_type = self._create_replica_volume_type(
|
||||
False, opts=old_opts, vol_type_name='test_old_type')
|
||||
|
||||
volume, model_update = self._create_test_volume(old_type)
|
||||
new_type = self._create_replica_volume_type(
|
||||
False, opts=new_opts, vol_type_name='test_new_type')
|
||||
diff, _equal = volume_types.volume_types_diff(
|
||||
self.ctxt, new_type['id'], old_type['id'])
|
||||
self.assertRaises(exception.VolumeDriverException, self.driver.retype,
|
||||
self.ctxt, volume, new_type, diff, host)
|
||||
|
||||
def test_storwize_retype_from_mirror_to_none_replication(self):
|
||||
# Set replication target
|
||||
self.driver.configuration.set_override('replication_device',
|
||||
@ -6143,13 +6461,6 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
|
||||
volume, model_update = self._create_test_volume(self.mm_type)
|
||||
self.assertEqual('enabled', model_update['replication_status'])
|
||||
|
||||
diff, _equal = volume_types.volume_types_diff(
|
||||
self.ctxt, self.mm_type['id'], self.gm_type['id'])
|
||||
# Change the mirror type
|
||||
self.assertRaises(exception.VolumeDriverException,
|
||||
self.driver.retype, self.ctxt,
|
||||
volume, self.gm_type, diff, host)
|
||||
|
||||
diff, _equal = volume_types.volume_types_diff(
|
||||
self.ctxt, self.non_replica_type['id'], self.mm_type['id'])
|
||||
# Disable replica
|
||||
@ -6275,6 +6586,33 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
|
||||
|
||||
self.driver.delete_volume(rep_volume)
|
||||
|
||||
@mock.patch.object(storwize_svc_common.StorwizeHelpers, 'rename_vdisk')
|
||||
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
|
||||
'get_relationship_info')
|
||||
def test_storwize_update_migrated_replication_volume(
|
||||
self, get_rp_info, rename_vdisk):
|
||||
self.driver.configuration.set_override('replication_device',
|
||||
[self.rep_target])
|
||||
self.driver.do_setup(self.ctxt)
|
||||
|
||||
# Create replication volume.
|
||||
backend_volume, model_update = self._create_test_volume(self.mm_type)
|
||||
volume, model_update = self._create_test_volume(self.mm_type)
|
||||
get_rp_info.side_effect = [{'aux_vdisk_name': 'aux_test'}]
|
||||
model_update = self.driver.update_migrated_volume(self.ctxt, volume,
|
||||
backend_volume,
|
||||
'available')
|
||||
aux_vol = (storwize_const.REPLICA_AUX_VOL_PREFIX + volume.name)
|
||||
rename_vdisk.assert_called_with('aux_test', aux_vol)
|
||||
self.assertEqual({'_name_id': None}, model_update)
|
||||
|
||||
rename_vdisk.reset_mock()
|
||||
rename_vdisk.side_effect = exception.VolumeBackendAPIException
|
||||
model_update = self.driver.update_migrated_volume(self.ctxt, volume,
|
||||
backend_volume,
|
||||
'available')
|
||||
self.assertEqual({'_name_id': backend_volume.id}, model_update)
|
||||
|
||||
def test_storwize_delete_volume_with_mirror_replication(self):
|
||||
# Set replication target.
|
||||
self.driver.configuration.set_override('replication_device',
|
||||
|
@ -120,6 +120,10 @@ storwize_svc_opts = [
|
||||
help='Specifies the Storwize FlashCopy copy rate to be used '
|
||||
'when creating a full volume copy. The default is rate '
|
||||
'is 50, and the valid rates are 1-100.'),
|
||||
cfg.StrOpt('storwize_svc_mirror_pool',
|
||||
default=None,
|
||||
help='Specifies the name of the pool in which mirrored copy '
|
||||
'is stored. Example: "pool2"'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -196,7 +200,13 @@ class StorwizeSSH(object):
|
||||
def lsmdiskgrp(self, pool):
|
||||
ssh_cmd = ['svcinfo', 'lsmdiskgrp', '-bytes', '-delim', '!',
|
||||
'"%s"' % pool]
|
||||
return self.run_ssh_info(ssh_cmd)[0]
|
||||
try:
|
||||
return self.run_ssh_info(ssh_cmd)[0]
|
||||
except exception.VolumeBackendAPIException as ex:
|
||||
LOG.warning("Failed to get pool %(pool)s info. "
|
||||
"Exception: %(ex)s.", {'pool': pool,
|
||||
'ex': ex})
|
||||
return None
|
||||
|
||||
def lsiogrp(self):
|
||||
ssh_cmd = ['svcinfo', 'lsiogrp', '-delim', '!']
|
||||
@ -542,9 +552,12 @@ class StorwizeSSH(object):
|
||||
ssh_cmd = ['svctask', 'rmfcconsistgrp', '-force', fc_consist_group]
|
||||
return self.run_ssh_assert_no_output(ssh_cmd)
|
||||
|
||||
def addvdiskcopy(self, vdisk, dest_pool, params):
|
||||
def addvdiskcopy(self, vdisk, dest_pool, params, auto_delete):
|
||||
ssh_cmd = (['svctask', 'addvdiskcopy'] + params + ['-mdiskgrp',
|
||||
'"%s"' % dest_pool, '"%s"' % vdisk])
|
||||
'"%s"' % dest_pool])
|
||||
if auto_delete:
|
||||
ssh_cmd += ['-autodelete']
|
||||
ssh_cmd += ['"%s"' % vdisk]
|
||||
return self.run_ssh_check_created(ssh_cmd)
|
||||
|
||||
def lsvdiskcopy(self, vdisk, copy_id=None):
|
||||
@ -579,6 +592,11 @@ class StorwizeSSH(object):
|
||||
'-filtervalue', 'node_id=%s' % node_id]
|
||||
return self.run_ssh_info(ssh_cmd, with_header=True)
|
||||
|
||||
def migratevdisk(self, vdisk, dest_pool, copy_id='0'):
|
||||
ssh_cmd = ['svctask', 'migratevdisk', '-mdiskgrp', dest_pool, '-copy',
|
||||
copy_id, '-vdisk', vdisk]
|
||||
self.run_ssh_assert_no_output(ssh_cmd)
|
||||
|
||||
|
||||
class StorwizeHelpers(object):
|
||||
|
||||
@ -653,6 +671,11 @@ class StorwizeHelpers(object):
|
||||
"""Return attributes for the specified pool."""
|
||||
return self.ssh.lsmdiskgrp(pool)
|
||||
|
||||
def is_pool_defined(self, pool_name):
|
||||
"""Check if vdisk is defined."""
|
||||
attrs = self.get_pool_attrs(pool_name)
|
||||
return attrs is not None
|
||||
|
||||
def get_available_io_groups(self):
|
||||
"""Return list of available IO groups."""
|
||||
iogrps = []
|
||||
@ -1030,7 +1053,8 @@ class StorwizeHelpers(object):
|
||||
'qos': None,
|
||||
'stretched_cluster': cluster_partner,
|
||||
'replication': False,
|
||||
'nofmtdisk': config.storwize_svc_vol_nofmtdisk}
|
||||
'nofmtdisk': config.storwize_svc_vol_nofmtdisk,
|
||||
'mirror_pool': config.storwize_svc_mirror_pool}
|
||||
return opt
|
||||
|
||||
@staticmethod
|
||||
@ -1225,7 +1249,7 @@ class StorwizeHelpers(object):
|
||||
return opts
|
||||
|
||||
@staticmethod
|
||||
def _get_vdisk_create_params(opts):
|
||||
def _get_vdisk_create_params(opts, add_copies=False):
|
||||
easytier = 'on' if opts['easytier'] else 'off'
|
||||
if opts['rsize'] == -1:
|
||||
params = []
|
||||
@ -1243,14 +1267,27 @@ class StorwizeHelpers(object):
|
||||
else:
|
||||
params.extend(['-grainsize', str(opts['grainsize'])])
|
||||
|
||||
if add_copies and opts['mirror_pool']:
|
||||
params.extend(['-copies', '2'])
|
||||
|
||||
params.extend(['-easytier', easytier])
|
||||
return params
|
||||
|
||||
def create_vdisk(self, name, size, units, pool, opts):
|
||||
name = '"%s"' % name
|
||||
LOG.debug('Enter: create_vdisk: vdisk %s.', name)
|
||||
params = self._get_vdisk_create_params(opts)
|
||||
self.ssh.mkvdisk(name, size, units, pool, opts, params)
|
||||
mdiskgrp = pool
|
||||
if opts['mirror_pool']:
|
||||
if not self.is_pool_defined(opts['mirror_pool']):
|
||||
raise exception.InvalidInput(
|
||||
reason=_('The pool %s in which mirrored copy is stored '
|
||||
'is invalid') % opts['mirror_pool'])
|
||||
# The syntax of pool SVC expects is pool:mirror_pool in
|
||||
# mdiskgrp for mirror volume
|
||||
mdiskgrp = '%s:%s' % (pool, opts['mirror_pool'])
|
||||
params = self._get_vdisk_create_params(
|
||||
opts, add_copies=True if opts['mirror_pool'] else False)
|
||||
self.ssh.mkvdisk(name, size, units, mdiskgrp, opts, params)
|
||||
LOG.debug('Leave: _create_vdisk: volume %s.', name)
|
||||
|
||||
def get_vdisk_attributes(self, vdisk):
|
||||
@ -1349,11 +1386,18 @@ class StorwizeHelpers(object):
|
||||
for snapshot in snapshots:
|
||||
opts = self.get_vdisk_params(config, state,
|
||||
snapshot['volume_type_id'])
|
||||
|
||||
volume = snapshot.volume
|
||||
if not volume:
|
||||
msg = (_("Can't get volume from snapshot: %(id)s")
|
||||
% {"id": snapshot.id})
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeBackendAPIException(data=msg)
|
||||
pool = utils.extract_host(volume.host, 'pool')
|
||||
self.create_flashcopy_to_consistgrp(snapshot['volume_name'],
|
||||
snapshot['name'],
|
||||
fc_consistgrp,
|
||||
config, opts)
|
||||
config, opts, False,
|
||||
pool=pool)
|
||||
|
||||
self.prepare_fc_consistgrp(fc_consistgrp, timeout)
|
||||
self.start_fc_consistgrp(fc_consistgrp)
|
||||
@ -1382,7 +1426,7 @@ class StorwizeHelpers(object):
|
||||
|
||||
try:
|
||||
for snapshot in snapshots:
|
||||
self.ssh.rmvdisk(snapshot['name'], True)
|
||||
self.delete_vdisk(snapshot['name'], True)
|
||||
except exception.VolumeBackendAPIException as err:
|
||||
model_update['status'] = (
|
||||
fields.GroupSnapshotStatus.ERROR_DELETING)
|
||||
@ -1744,7 +1788,8 @@ class StorwizeHelpers(object):
|
||||
def extend_vdisk(self, vdisk, amount):
|
||||
self.ssh.expandvdisksize(vdisk, amount)
|
||||
|
||||
def add_vdisk_copy(self, vdisk, dest_pool, volume_type, state, config):
|
||||
def add_vdisk_copy(self, vdisk, dest_pool, volume_type, state, config,
|
||||
auto_delete=False):
|
||||
"""Add a vdisk copy in the given pool."""
|
||||
resp = self.ssh.lsvdiskcopy(vdisk)
|
||||
if len(resp) > 1:
|
||||
@ -1766,7 +1811,15 @@ class StorwizeHelpers(object):
|
||||
opts = self.get_vdisk_params(config, state, volume_type['id'],
|
||||
volume_type=volume_type)
|
||||
params = self._get_vdisk_create_params(opts)
|
||||
new_copy_id = self.ssh.addvdiskcopy(vdisk, dest_pool, params)
|
||||
try:
|
||||
new_copy_id = self.ssh.addvdiskcopy(vdisk, dest_pool, params,
|
||||
auto_delete)
|
||||
except exception.VolumeBackendAPIException as e:
|
||||
msg = (_('Unable to add vdiskcopy for volume %(vol)s. '
|
||||
'Exception: %(err)s.'),
|
||||
{'vol': vdisk, 'err': e})
|
||||
LOG.exception(msg)
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
return (orig_copy_id, new_copy_id)
|
||||
|
||||
def is_vdisk_copy_synced(self, vdisk, copy_id):
|
||||
@ -1778,6 +1831,9 @@ class StorwizeHelpers(object):
|
||||
def rm_vdisk_copy(self, vdisk, copy_id):
|
||||
self.ssh.rmvdiskcopy(vdisk, copy_id)
|
||||
|
||||
def lsvdiskcopy(self, vdisk, copy_id=None):
|
||||
return self.ssh.lsvdiskcopy(vdisk, copy_id)
|
||||
|
||||
@staticmethod
|
||||
def can_migrate_to_host(host, state):
|
||||
if 'location_info' not in host['capabilities']:
|
||||
@ -1880,6 +1936,9 @@ class StorwizeHelpers(object):
|
||||
def change_vdisk_primary_copy(self, vdisk, copy_id):
|
||||
self.ssh.chvdisk(vdisk, ['-primary', copy_id])
|
||||
|
||||
def migratevdisk(self, vdisk, dest_pool, copy_id='0'):
|
||||
self.ssh.migratevdisk(vdisk, dest_pool, copy_id)
|
||||
|
||||
|
||||
class CLIResponse(object):
|
||||
"""Parse SVC CLI output and generate iterable."""
|
||||
@ -2148,11 +2207,9 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
# Validate that the pool exists
|
||||
pools = self._get_backend_pools()
|
||||
for pool in pools:
|
||||
try:
|
||||
self._helpers.get_pool_attrs(pool)
|
||||
except exception.VolumeBackendAPIException:
|
||||
msg = _('Failed getting details for pool %s.') % pool
|
||||
raise exception.InvalidInput(reason=msg)
|
||||
if not self._helpers.is_pool_defined(pool):
|
||||
reason = (_('Failed getting details for pool %s.') % pool)
|
||||
raise exception.InvalidInput(reason=reason)
|
||||
|
||||
def check_for_setup_error(self):
|
||||
"""Ensure that the flags are set properly."""
|
||||
@ -2337,8 +2394,14 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
opts = self._get_vdisk_params(volume['volume_type_id'],
|
||||
volume_metadata=
|
||||
volume.get('volume_metadata'))
|
||||
pool = utils.extract_host(volume['host'], 'pool')
|
||||
ctxt = context.get_admin_context()
|
||||
rep_type = self._get_volume_replicated_type(ctxt, volume)
|
||||
|
||||
pool = utils.extract_host(volume['host'], 'pool')
|
||||
if opts['mirror_pool'] and rep_type:
|
||||
reason = _('Create mirror volume with replication enabled is '
|
||||
'not supported.')
|
||||
raise exception.InvalidInput(reason=reason)
|
||||
opts['iogrp'] = self._helpers.select_io_group(self._state, opts)
|
||||
self._helpers.create_vdisk(volume['name'], str(volume['size']),
|
||||
'gb', pool, opts)
|
||||
@ -2346,8 +2409,6 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
self._helpers.add_vdisk_qos(volume['name'], opts['qos'])
|
||||
|
||||
model_update = None
|
||||
ctxt = context.get_admin_context()
|
||||
rep_type = self._get_volume_replicated_type(ctxt, volume)
|
||||
|
||||
# The replication V2 has a higher priority than the replication V1.
|
||||
# Check if V2 is available first, then check if V1 is available.
|
||||
@ -2370,8 +2431,9 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
|
||||
rep_type = self._get_volume_replicated_type(ctxt, volume)
|
||||
if rep_type:
|
||||
self._aux_backend_helpers.delete_rc_volume(volume['name'],
|
||||
target_vol=True)
|
||||
if self._aux_backend_helpers:
|
||||
self._aux_backend_helpers.delete_rc_volume(volume['name'],
|
||||
target_vol=True)
|
||||
if not self._active_backend_id:
|
||||
self._master_backend_helpers.delete_rc_volume(volume['name'])
|
||||
else:
|
||||
@ -2565,10 +2627,11 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
self._helpers.extend_vdisk(volume_name, extend_amt)
|
||||
LOG.debug('leave: _extend_volume_op: volume %s', volume['id'])
|
||||
|
||||
def add_vdisk_copy(self, volume, dest_pool, vol_type):
|
||||
def add_vdisk_copy(self, volume, dest_pool, vol_type, auto_delete=False):
|
||||
return self._helpers.add_vdisk_copy(volume, dest_pool,
|
||||
vol_type, self._state,
|
||||
self.configuration)
|
||||
self.configuration,
|
||||
auto_delete=auto_delete)
|
||||
|
||||
def _add_vdisk_copy_op(self, ctxt, volume, new_op):
|
||||
metadata = self.db.volume_admin_metadata_get(ctxt.elevated(),
|
||||
@ -3164,13 +3227,78 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
else:
|
||||
vol_type = None
|
||||
|
||||
self._check_volume_copy_ops()
|
||||
new_op = self.add_vdisk_copy(volume['name'], dest_pool, vol_type)
|
||||
self._add_vdisk_copy_op(ctxt, volume, new_op)
|
||||
resp = self._helpers.lsvdiskcopy(volume.name)
|
||||
if len(resp) > 1:
|
||||
copies = self._helpers.get_vdisk_copies(volume.name)
|
||||
self._helpers.migratevdisk(volume.name, dest_pool,
|
||||
copies['primary']['copy_id'])
|
||||
else:
|
||||
self.add_vdisk_copy(volume.name, dest_pool, vol_type,
|
||||
auto_delete=True)
|
||||
|
||||
LOG.debug('leave: migrate_volume: id=%(id)s, host=%(host)s',
|
||||
{'id': volume['id'], 'host': host['host']})
|
||||
{'id': volume.id, 'host': host['host']})
|
||||
return (True, None)
|
||||
|
||||
def _verify_retype_params(self, volume, new_opts, old_opts, need_copy,
|
||||
change_mirror, new_rep_type, old_rep_type):
|
||||
# Some volume parameters can not be changed or changed at the same
|
||||
# time during volume retype operation. This function checks the
|
||||
# retype parameters.
|
||||
resp = self._helpers.lsvdiskcopy(volume.name)
|
||||
if old_opts['mirror_pool'] and len(resp) == 1:
|
||||
msg = (_('Unable to retype: volume %s is a mirrorred vol. But it '
|
||||
'has only one copy in storage.') % volume.name)
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
|
||||
if need_copy:
|
||||
# mirror volume can not add volume-copy again.
|
||||
if len(resp) > 1:
|
||||
msg = (_('Unable to retype: current action needs volume-copy. '
|
||||
'A copy of volume %s exists. Adding another copy '
|
||||
'would exceed the limit of 2 copies.') % volume.name)
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
if old_opts['mirror_pool'] or new_opts['mirror_pool']:
|
||||
msg = (_('Unable to retype: current action needs volume-copy, '
|
||||
'it is not allowed for mirror volume '
|
||||
'%s.') % volume.name)
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
|
||||
if change_mirror:
|
||||
if (new_opts['mirror_pool'] and
|
||||
not self._helpers.is_pool_defined(
|
||||
new_opts['mirror_pool'])):
|
||||
msg = (_('Unable to retype: The pool %s in which mirror copy '
|
||||
'is stored is not valid') % new_opts['mirror_pool'])
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
|
||||
# There are three options for rep_type: None, metro, global
|
||||
if new_rep_type or old_rep_type:
|
||||
# If volume is replicated, can't copy
|
||||
if need_copy or new_opts['mirror_pool'] or old_opts['mirror_pool']:
|
||||
msg = (_('Unable to retype: current action needs volume-copy, '
|
||||
'it is not allowed for replication type. '
|
||||
'Volume = %s') % volume.id)
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
|
||||
if new_rep_type != old_rep_type:
|
||||
old_io_grp = self._helpers.get_volume_io_group(volume.name)
|
||||
if (old_io_grp not in
|
||||
StorwizeHelpers._get_valid_requested_io_groups(
|
||||
self._state, new_opts)):
|
||||
msg = (_('Unable to retype: it is not allowed to change '
|
||||
'replication type and io group at the same time.'))
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
if new_rep_type and old_rep_type:
|
||||
msg = (_('Unable to retype: it is not allowed to change '
|
||||
'%(old_rep_type)s volume to %(new_rep_type)s '
|
||||
'volume.') %
|
||||
{'old_rep_type': old_rep_type,
|
||||
'new_rep_type': new_rep_type})
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
|
||||
def retype(self, ctxt, volume, new_type, diff, host):
|
||||
"""Convert the volume to be of the new type.
|
||||
|
||||
@ -3206,6 +3334,8 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
|
||||
vdisk_changes = []
|
||||
need_copy = False
|
||||
change_mirror = False
|
||||
|
||||
for key in all_keys:
|
||||
if old_opts[key] != new_opts[key]:
|
||||
if key in copy_keys:
|
||||
@ -3218,38 +3348,18 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
utils.extract_host(host['host'], 'pool')):
|
||||
need_copy = True
|
||||
|
||||
if old_opts['mirror_pool'] != new_opts['mirror_pool']:
|
||||
change_mirror = True
|
||||
|
||||
# Check if retype affects volume replication
|
||||
model_update = None
|
||||
new_rep_type = self._get_specs_replicated_type(new_type)
|
||||
old_rep_type = self._get_volume_replicated_type(ctxt, volume)
|
||||
old_io_grp = self._helpers.get_volume_io_group(volume['name'])
|
||||
|
||||
# There are three options for rep_type: None, metro, global
|
||||
if new_rep_type != old_rep_type:
|
||||
if (old_io_grp not in
|
||||
StorwizeHelpers._get_valid_requested_io_groups(
|
||||
self._state, new_opts)):
|
||||
msg = (_('Unable to retype: it is not allowed to change '
|
||||
'replication type and io group at the same time.'))
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
if new_rep_type and old_rep_type:
|
||||
msg = (_('Unable to retype: it is not allowed to change '
|
||||
'%(old_rep_type)s volume to %(new_rep_type)s '
|
||||
'volume.') %
|
||||
{'old_rep_type': old_rep_type,
|
||||
'new_rep_type': new_rep_type})
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
# If volume is replicated, can't copy
|
||||
if need_copy:
|
||||
msg = (_('Unable to retype: Current action needs volume-copy,'
|
||||
' it is not allowed when new type is replication.'
|
||||
' Volume = %s') % volume['id'])
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
|
||||
new_io_grp = self._helpers.select_io_group(self._state, new_opts)
|
||||
|
||||
self._verify_retype_params(volume, new_opts, old_opts, need_copy,
|
||||
change_mirror, new_rep_type, old_rep_type)
|
||||
if need_copy:
|
||||
self._check_volume_copy_ops()
|
||||
dest_pool = self._helpers.can_migrate_to_host(host, self._state)
|
||||
@ -3259,10 +3369,8 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
retype_iogrp_property(volume,
|
||||
new_io_grp, old_io_grp)
|
||||
try:
|
||||
new_op = self.add_vdisk_copy(volume['name'],
|
||||
dest_pool,
|
||||
new_type)
|
||||
self._add_vdisk_copy_op(ctxt, volume, new_op)
|
||||
self.add_vdisk_copy(volume['name'], dest_pool, new_type,
|
||||
auto_delete=True)
|
||||
except exception.VolumeDriverException:
|
||||
# roll back changing iogrp property
|
||||
retype_iogrp_property(volume, old_io_grp, new_io_grp)
|
||||
@ -3275,7 +3383,23 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
|
||||
self._helpers.change_vdisk_options(volume['name'], vdisk_changes,
|
||||
new_opts, self._state)
|
||||
|
||||
if change_mirror:
|
||||
copies = self._helpers.get_vdisk_copies(volume.name)
|
||||
if not old_opts['mirror_pool'] and new_opts['mirror_pool']:
|
||||
# retype from non mirror vol to mirror vol
|
||||
self.add_vdisk_copy(volume['name'],
|
||||
new_opts['mirror_pool'], new_type)
|
||||
elif old_opts['mirror_pool'] and not new_opts['mirror_pool']:
|
||||
# retype from mirror vol to non mirror vol
|
||||
secondary = copies['secondary']
|
||||
if secondary:
|
||||
self._helpers.rm_vdisk_copy(
|
||||
volume.name, secondary['copy_id'])
|
||||
else:
|
||||
# migrate the second copy to another pool.
|
||||
self._helpers.migratevdisk(
|
||||
volume.name, new_opts['mirror_pool'],
|
||||
copies['secondary']['copy_id'])
|
||||
if new_opts['qos']:
|
||||
# Add the new QoS setting to the volume. If the volume has an
|
||||
# old QoS setting, it will be overwritten.
|
||||
@ -3322,6 +3446,13 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
original_volume_name = CONF.volume_name_template % volume['id']
|
||||
try:
|
||||
self._helpers.rename_vdisk(current_name, original_volume_name)
|
||||
rep_type = self._get_volume_replicated_type(ctxt, new_volume)
|
||||
if rep_type:
|
||||
rel_info = self._helpers.get_relationship_info(current_name)
|
||||
aux_vol = (storwize_const.REPLICA_AUX_VOL_PREFIX +
|
||||
original_volume_name)
|
||||
self._aux_backend_helpers.rename_vdisk(
|
||||
rel_info['aux_vdisk_name'], aux_vol)
|
||||
except exception.VolumeBackendAPIException:
|
||||
LOG.error('Unable to rename the logical volume '
|
||||
'for volume: %s', volume['id'])
|
||||
@ -3357,6 +3488,7 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
rep_type = self._get_volume_replicated_type(ctxt, volume)
|
||||
vol_rep_type = None
|
||||
rel_info = self._helpers.get_relationship_info(vdisk['name'])
|
||||
copies = self._helpers.get_vdisk_copies(vdisk['name'])
|
||||
if rel_info:
|
||||
vol_rep_type = rel_info['copy_type']
|
||||
aux_info = self._aux_backend_helpers.get_system_info()
|
||||
@ -3379,8 +3511,28 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
opts = self._get_vdisk_params(volume['volume_type_id'],
|
||||
volume_metadata=
|
||||
volume.get('volume_metadata'))
|
||||
vdisk_copy = self._helpers.get_vdisk_copy_attrs(vdisk['name'], '0')
|
||||
resp = self._helpers.lsvdiskcopy(vdisk['name'])
|
||||
expected_copy_num = 2 if opts['mirror_pool'] else 1
|
||||
if len(resp) != expected_copy_num:
|
||||
msg = (_("Failed to manage existing volume due to mirror type "
|
||||
"mismatch. Volume to be managed has %(resp_len)s "
|
||||
"copies. mirror_pool of the chosen type is "
|
||||
"%(mirror_pool)s.") %
|
||||
{'resp_len': len(resp),
|
||||
'mirror_pool': opts['mirror_pool']})
|
||||
raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
|
||||
if (opts['mirror_pool']and opts['mirror_pool'] !=
|
||||
copies['secondary']['mdisk_grp_name']):
|
||||
msg = (_("Failed to manage existing volume due to mirror pool "
|
||||
"mismatch. The secondary pool of the volume to be "
|
||||
"managed is %(sec_copy_pool)s. mirror_pool of the "
|
||||
"chosen type is %(mirror_pool)s.") %
|
||||
{'sec_copy_pool': copies['secondary']['mdisk_grp_name'],
|
||||
'mirror_pool': opts['mirror_pool']})
|
||||
raise exception.ManageExistingVolumeTypeMismatch(
|
||||
reason=msg)
|
||||
|
||||
vdisk_copy = self._helpers.get_vdisk_copy_attrs(vdisk['name'], '0')
|
||||
if vdisk_copy['autoexpand'] == 'on' and opts['rsize'] == -1:
|
||||
msg = (_("Failed to manage existing volume due to "
|
||||
"the volume to be managed is thin, but "
|
||||
@ -3418,15 +3570,14 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
'opt_iogrp': opts['iogrp']})
|
||||
raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
|
||||
pool = utils.extract_host(volume['host'], 'pool')
|
||||
if vdisk['mdisk_grp_name'] != pool:
|
||||
if copies['primary']['mdisk_grp_name'] != pool:
|
||||
msg = (_("Failed to manage existing volume due to the "
|
||||
"pool of the volume to be managed does not "
|
||||
"match the backend pool. Pool of the "
|
||||
"volume to be managed is %(vdisk_pool)s. Pool "
|
||||
"of the backend is %(backend_pool)s.") %
|
||||
{'vdisk_pool': vdisk['mdisk_grp_name'],
|
||||
'backend_pool':
|
||||
self._get_backend_pools()})
|
||||
{'vdisk_pool': copies['primary']['mdisk_grp_name'],
|
||||
'backend_pool': pool})
|
||||
raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
|
||||
|
||||
model_update = {}
|
||||
|
@ -89,9 +89,10 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
mode
|
||||
2.1.1 - Update replication to version 2.1
|
||||
2.2 - Add CG capability to generic volume groups
|
||||
2.2.1 - Add vdisk mirror/stretch cluster support
|
||||
"""
|
||||
|
||||
VERSION = "2.2"
|
||||
VERSION = "2.2.1"
|
||||
|
||||
# ThirdPartySystems wiki page
|
||||
CI_WIKI_NAME = "IBM_STORAGE_CI"
|
||||
|
@ -89,9 +89,10 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
mode
|
||||
2.1.1 - Update replication to version 2.1
|
||||
2.2 - Add CG capability to generic volume groups
|
||||
2.2.1 - Add vdisk mirror/stretch cluster support
|
||||
"""
|
||||
|
||||
VERSION = "2.2"
|
||||
VERSION = "2.2.1"
|
||||
|
||||
# ThirdPartySystems wiki page
|
||||
CI_WIKI_NAME = "IBM_STORAGE_CI"
|
||||
|
@ -0,0 +1,3 @@
|
||||
---
|
||||
features:
|
||||
- Add mirrored volume support in IBM SVC/Storwize driver.
|
Loading…
Reference in New Issue
Block a user