Merge "Storwize: add mirrored volume support"
This commit is contained in:
commit
31c2328c86
@ -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