Merge "Storwize: add mirrored volume support"
This commit is contained in:
commit
31c2328c86
cinder
tests/unit/volume/drivers/ibm
volume/drivers/ibm/storwize_svc
releasenotes/notes
@ -325,7 +325,8 @@ class StorwizeSVCManagementSimulator(object):
|
|||||||
'aux',
|
'aux',
|
||||||
'cluster',
|
'cluster',
|
||||||
'linkbandwidthmbits',
|
'linkbandwidthmbits',
|
||||||
'backgroundcopyrate'
|
'backgroundcopyrate',
|
||||||
|
'copies'
|
||||||
]
|
]
|
||||||
no_or_one_param_args = [
|
no_or_one_param_args = [
|
||||||
'autoexpand',
|
'autoexpand',
|
||||||
@ -732,10 +733,25 @@ port_speed!N/A
|
|||||||
volume_info['uid'] = ('ABCDEF' * 3) + ('0' * 14) + volume_info['id']
|
volume_info['uid'] = ('ABCDEF' * 3) + ('0' * 14) + volume_info['id']
|
||||||
|
|
||||||
mdiskgrp = kwargs['mdiskgrp'].strip('\'\"')
|
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']:
|
if mdiskgrp == kwargs['mdiskgrp']:
|
||||||
raise exception.InvalidInput(
|
raise exception.InvalidInput(
|
||||||
reason=_('mdiskgrp missing quotes %s') % kwargs['mdiskgrp'])
|
reason=_('mdiskgrp missing quotes %s') % kwargs['mdiskgrp'])
|
||||||
mdiskgrp_id = self._get_mdiskgrp_id(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_name'] = mdiskgrp
|
||||||
volume_info['mdisk_grp_id'] = str(mdiskgrp_id)
|
volume_info['mdisk_grp_id'] = str(mdiskgrp_id)
|
||||||
|
|
||||||
@ -803,6 +819,16 @@ port_speed!N/A
|
|||||||
'easy_tier': volume_info['easy_tier'],
|
'easy_tier': volume_info['easy_tier'],
|
||||||
'compressed_copy': volume_info['compressed_copy']}
|
'compressed_copy': volume_info['compressed_copy']}
|
||||||
volume_info['copies'] = {'0': vol_cp}
|
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:
|
if volume_info['name'] in self._volumes_list:
|
||||||
return self._errors['CMMVC6035E']
|
return self._errors['CMMVC6035E']
|
||||||
@ -1588,32 +1614,17 @@ port_speed!N/A
|
|||||||
return self._errors['CMMVC5707E']
|
return self._errors['CMMVC5707E']
|
||||||
mdiskgrp = kwargs['mdiskgrp'].strip('\'\"')
|
mdiskgrp = kwargs['mdiskgrp'].strip('\'\"')
|
||||||
vdisk = kwargs['vdisk'].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:
|
self._volumes_list[vdisk]['mdisk_grp_name'] = mdiskgrp
|
||||||
curr_mdiskgrp = self._volumes_list
|
self._volumes_list[vdisk]['mdisk_grp_id'] = mdiskgrp_id
|
||||||
else:
|
|
||||||
for pool in self._other_pools:
|
|
||||||
if vdisk in pool:
|
|
||||||
curr_mdiskgrp = pool
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
return self._errors['CMMVC5754E']
|
|
||||||
|
|
||||||
if mdiskgrp == self._flags['storwize_svc_volpool_name']:
|
vol = self._volumes_list[vdisk]
|
||||||
tgt_mdiskgrp = self._volumes_list
|
vol['copies'][copy_id]['mdisk_grp_name'] = mdiskgrp
|
||||||
elif mdiskgrp == 'openstack2':
|
vol['copies'][copy_id]['mdisk_grp_id'] = mdiskgrp_id
|
||||||
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]
|
|
||||||
return ('', '')
|
return ('', '')
|
||||||
|
|
||||||
def _cmd_addvdiskcopy(self, **kwargs):
|
def _cmd_addvdiskcopy(self, **kwargs):
|
||||||
@ -1629,6 +1640,7 @@ port_speed!N/A
|
|||||||
if mdiskgrp == kwargs['mdiskgrp']:
|
if mdiskgrp == kwargs['mdiskgrp']:
|
||||||
raise exception.InvalidInput(
|
raise exception.InvalidInput(
|
||||||
reason=_('mdiskgrp missing quotes %s') % kwargs['mdiskgrp'])
|
reason=_('mdiskgrp missing quotes %s') % kwargs['mdiskgrp'])
|
||||||
|
auto_del = True if 'autodelete' in kwargs else False
|
||||||
|
|
||||||
copy_info = {}
|
copy_info = {}
|
||||||
copy_info['id'] = self._find_unused_id(vol['copies'])
|
copy_info['id'] = self._find_unused_id(vol['copies'])
|
||||||
@ -1649,6 +1661,14 @@ port_speed!N/A
|
|||||||
else:
|
else:
|
||||||
copy_info['compressed_copy'] = 'no'
|
copy_info['compressed_copy'] = 'no'
|
||||||
vol['copies'][copy_info['id']] = copy_info
|
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' %
|
return ('Vdisk [%(vid)s] copy [%(cid)s] successfully created' %
|
||||||
{'vid': vol['id'], 'cid': copy_info['id']}, '')
|
{'vid': vol['id'], 'cid': copy_info['id']}, '')
|
||||||
|
|
||||||
@ -1725,6 +1745,8 @@ port_speed!N/A
|
|||||||
for key, value in kwargs.items():
|
for key, value in kwargs.items():
|
||||||
if key == 'easytier':
|
if key == 'easytier':
|
||||||
vol['easy_tier'] = value
|
vol['easy_tier'] = value
|
||||||
|
for copy in vol['copies'].values():
|
||||||
|
vol['copies'][copy['id']]['easy_tier'] = value
|
||||||
continue
|
continue
|
||||||
if key == 'warning':
|
if key == 'warning':
|
||||||
vol['warning'] = value.rstrip('%')
|
vol['warning'] = value.rstrip('%')
|
||||||
@ -1749,6 +1771,9 @@ port_speed!N/A
|
|||||||
return ('', err)
|
return ('', err)
|
||||||
if key in params:
|
if key in params:
|
||||||
vol[key] = value
|
vol[key] = value
|
||||||
|
if key == 'autoexpand':
|
||||||
|
for copy in vol['copies'].values():
|
||||||
|
vol['copies'][copy['id']]['autoexpand'] = value
|
||||||
else:
|
else:
|
||||||
err = self._errors['CMMVC5709E'][1] % {'VALUE': key}
|
err = self._errors['CMMVC5709E'][1] % {'VALUE': key}
|
||||||
return ('', err)
|
return ('', err)
|
||||||
@ -3447,6 +3472,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
self.driver._helpers.check_fcmapping_interval = 0
|
self.driver._helpers.check_fcmapping_interval = 0
|
||||||
self.mock_object(storwize_svc_iscsi.StorwizeSVCISCSIDriver,
|
self.mock_object(storwize_svc_iscsi.StorwizeSVCISCSIDriver,
|
||||||
'DEFAULT_GR_SLEEP', 0)
|
'DEFAULT_GR_SLEEP', 0)
|
||||||
|
self._create_test_volume_types()
|
||||||
|
|
||||||
def _set_flag(self, flag, value, configuration=None):
|
def _set_flag(self, flag, value, configuration=None):
|
||||||
if not configuration:
|
if not configuration:
|
||||||
@ -3465,6 +3491,11 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
is_vol_defined = self.driver._helpers.is_vdisk_defined(name)
|
is_vol_defined = self.driver._helpers.is_vdisk_defined(name)
|
||||||
self.assertEqual(exists, is_vol_defined)
|
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):
|
def test_storwize_svc_connectivity(self):
|
||||||
# Make sure we detect if the pool doesn't exist
|
# Make sure we detect if the pool doesn't exist
|
||||||
no_exist_pool = 'i-dont-exist-%s' % random.randint(10000, 99999)
|
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.assertEqual(self._driver.configuration.storwize_san_secondary_ip,
|
||||||
self._driver.active_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()
|
pool = _get_test_pool()
|
||||||
prop = {'mdisk_grp_name': pool}
|
prop = {'size': size,
|
||||||
if vol_name:
|
'host': 'openstack@svc#%s' % pool}
|
||||||
prop.update(volume_name=vol_name,
|
if vol_type:
|
||||||
volume_id=vol_id,
|
prop['volume_type_id'] = vol_type.id
|
||||||
volume_size=10)
|
|
||||||
else:
|
|
||||||
prop.update(size=10,
|
|
||||||
volume_type_id=None,
|
|
||||||
mdisk_grp_name=pool,
|
|
||||||
host='openstack@svc#%s' % pool)
|
|
||||||
vol = testutils.create_volume(self.ctxt, **prop)
|
vol = testutils.create_volume(self.ctxt, **prop)
|
||||||
return vol
|
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):
|
def _create_volume(self, **kwargs):
|
||||||
pool = _get_test_pool()
|
pool = _get_test_pool()
|
||||||
prop = {'host': 'openstack@svc#%s' % pool,
|
prop = {'host': 'openstack@svc#%s' % pool,
|
||||||
@ -3739,7 +3775,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
def _create_test_vol(self, opts):
|
def _create_test_vol(self, opts):
|
||||||
ctxt = testutils.get_test_admin_context()
|
ctxt = testutils.get_test_admin_context()
|
||||||
type_ref = volume_types.create(ctxt, 'testtype', opts)
|
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_type_id = type_ref['id']
|
||||||
volume.volume_typ = objects.VolumeType.get_by_id(ctxt,
|
volume.volume_typ = objects.VolumeType.get_by_id(ctxt,
|
||||||
type_ref['id'])
|
type_ref['id'])
|
||||||
@ -3761,7 +3797,8 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
'qos': None,
|
'qos': None,
|
||||||
'replication': False,
|
'replication': False,
|
||||||
'stretched_cluster': None,
|
'stretched_cluster': None,
|
||||||
'nofmtdisk': False}
|
'nofmtdisk': False,
|
||||||
|
'mirror_pool': None}
|
||||||
return opt
|
return opt
|
||||||
|
|
||||||
@mock.patch.object(storwize_svc_common.StorwizeHelpers, 'add_vdisk_qos')
|
@mock.patch.object(storwize_svc_common.StorwizeHelpers, 'add_vdisk_qos')
|
||||||
@ -3792,7 +3829,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
|
|
||||||
def test_storwize_svc_snapshots(self):
|
def test_storwize_svc_snapshots(self):
|
||||||
vol1 = self._create_volume()
|
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
|
# Test timeout and volume cleanup
|
||||||
self._set_flag('storwize_svc_flashcopy_timeout', 1)
|
self._set_flag('storwize_svc_flashcopy_timeout', 1)
|
||||||
@ -3824,7 +3861,8 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
self._assert_vol_exists(snap1['name'], True)
|
self._assert_vol_exists(snap1['name'], True)
|
||||||
|
|
||||||
# Try to create a snapshot from an non-existing volume - should fail
|
# 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.assertRaises(exception.VolumeDriverException,
|
||||||
self.driver.create_snapshot,
|
self.driver.create_snapshot,
|
||||||
snap_novol)
|
snap_novol)
|
||||||
@ -3880,14 +3918,14 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
|
|
||||||
def test_storwize_svc_create_volume_from_snapshot(self):
|
def test_storwize_svc_create_volume_from_snapshot(self):
|
||||||
vol1 = self._create_volume()
|
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)
|
self.driver.create_snapshot(snap1)
|
||||||
vol2 = self._generate_vol_info(None, None)
|
vol2 = self._generate_vol_info()
|
||||||
vol3 = self._generate_vol_info(None, None)
|
vol3 = self._generate_vol_info()
|
||||||
|
|
||||||
# Try to create a volume from a non-existing snapshot
|
# 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()
|
||||||
vol_novol = self._generate_vol_info(None, None)
|
snap_novol = self._generate_snap_info(vol_novol.id)
|
||||||
self.assertRaises(exception.VolumeDriverException,
|
self.assertRaises(exception.VolumeDriverException,
|
||||||
self.driver.create_volume_from_snapshot,
|
self.driver.create_volume_from_snapshot,
|
||||||
vol_novol,
|
vol_novol,
|
||||||
@ -3938,10 +3976,10 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
def test_storwize_svc_create_volfromsnap_clone_with_qos(self,
|
def test_storwize_svc_create_volfromsnap_clone_with_qos(self,
|
||||||
add_vdisk_qos):
|
add_vdisk_qos):
|
||||||
vol1 = self._create_volume()
|
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)
|
self.driver.create_snapshot(snap1)
|
||||||
vol2 = self._generate_vol_info(None, None)
|
vol2 = self._generate_vol_info()
|
||||||
vol3 = self._generate_vol_info(None, None)
|
vol3 = self._generate_vol_info()
|
||||||
fake_opts = self._get_default_opts()
|
fake_opts = self._get_default_opts()
|
||||||
|
|
||||||
# Succeed
|
# Succeed
|
||||||
@ -4002,12 +4040,12 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
def test_storwize_svc_delete_vol_with_fcmap(self):
|
def test_storwize_svc_delete_vol_with_fcmap(self):
|
||||||
vol1 = self._create_volume()
|
vol1 = self._create_volume()
|
||||||
# create two snapshots
|
# create two snapshots
|
||||||
snap1 = self._generate_vol_info(vol1['name'], vol1['id'])
|
snap1 = self._generate_snap_info(vol1.id)
|
||||||
snap2 = self._generate_vol_info(vol1['name'], vol1['id'])
|
snap2 = self._generate_snap_info(vol1.id)
|
||||||
self.driver.create_snapshot(snap1)
|
self.driver.create_snapshot(snap1)
|
||||||
self.driver.create_snapshot(snap2)
|
self.driver.create_snapshot(snap2)
|
||||||
vol2 = self._generate_vol_info(None, None)
|
vol2 = self._generate_vol_info()
|
||||||
vol3 = self._generate_vol_info(None, None)
|
vol3 = self._generate_vol_info()
|
||||||
|
|
||||||
# Create vol from the second snapshot
|
# Create vol from the second snapshot
|
||||||
if self.USESIM:
|
if self.USESIM:
|
||||||
@ -4045,7 +4083,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
|
|
||||||
def test_storwize_svc_volumes(self):
|
def test_storwize_svc_volumes(self):
|
||||||
# Create a first volume
|
# Create a first volume
|
||||||
volume = self._generate_vol_info(None, None)
|
volume = self._generate_vol_info()
|
||||||
self.driver.create_volume(volume)
|
self.driver.create_volume(volume)
|
||||||
|
|
||||||
self.driver.ensure_export(None, volume)
|
self.driver.ensure_export(None, volume)
|
||||||
@ -4067,7 +4105,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
volume)
|
volume)
|
||||||
|
|
||||||
# Try to delete a volume that doesn't exist (should not fail)
|
# 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)
|
self.driver.delete_volume(vol_no_exist)
|
||||||
# Ensure export for volume that doesn't exist (should not fail)
|
# Ensure export for volume that doesn't exist (should not fail)
|
||||||
self.driver.ensure_export(None, vol_no_exist)
|
self.driver.ensure_export(None, vol_no_exist)
|
||||||
@ -4076,7 +4114,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
self.driver.delete_volume(volume)
|
self.driver.delete_volume(volume)
|
||||||
|
|
||||||
def test_storwize_svc_volume_name(self):
|
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.create_volume(volume)
|
||||||
self.driver.ensure_export(None, volume)
|
self.driver.ensure_export(None, volume)
|
||||||
|
|
||||||
@ -4154,7 +4192,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
self.driver.do_setup(None)
|
self.driver.do_setup(None)
|
||||||
|
|
||||||
rand_id = random.randint(10000, 99999)
|
rand_id = random.randint(10000, 99999)
|
||||||
volume1 = self._generate_vol_info(None, None)
|
volume1 = self._generate_vol_info()
|
||||||
self.driver.create_volume(volume1)
|
self.driver.create_volume(volume1)
|
||||||
self._assert_vol_exists(volume1['name'], True)
|
self._assert_vol_exists(volume1['name'], True)
|
||||||
|
|
||||||
@ -4199,21 +4237,21 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
|
|
||||||
# Fail creating a snapshot - will force delete the snapshot
|
# Fail creating a snapshot - will force delete the snapshot
|
||||||
if self.USESIM and False:
|
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.sim.error_injection('startfcmap', 'bad_id')
|
||||||
self.assertRaises(exception.VolumeBackendAPIException,
|
self.assertRaises(exception.VolumeBackendAPIException,
|
||||||
self.driver.create_snapshot, snap)
|
self.driver.create_snapshot, snap)
|
||||||
self._assert_vol_exists(snap['name'], False)
|
self._assert_vol_exists(snap['name'], False)
|
||||||
|
|
||||||
# Delete a snapshot
|
# 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.driver.create_snapshot(snap)
|
||||||
self._assert_vol_exists(snap['name'], True)
|
self._assert_vol_exists(snap['name'], True)
|
||||||
self.driver.delete_snapshot(snap)
|
self.driver.delete_snapshot(snap)
|
||||||
self._assert_vol_exists(snap['name'], False)
|
self._assert_vol_exists(snap['name'], False)
|
||||||
|
|
||||||
# Delete a volume with snapshots (regular)
|
# 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.driver.create_snapshot(snap)
|
||||||
self._assert_vol_exists(snap['name'], True)
|
self._assert_vol_exists(snap['name'], True)
|
||||||
self.driver.delete_volume(master)
|
self.driver.delete_volume(master)
|
||||||
@ -4221,7 +4259,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
|
|
||||||
# Fail create volume from snapshot - will force delete the volume
|
# Fail create volume from snapshot - will force delete the volume
|
||||||
if self.USESIM:
|
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('startfcmap', 'bad_id')
|
||||||
self.sim.error_injection('lsfcmap', 'speed_up')
|
self.sim.error_injection('lsfcmap', 'speed_up')
|
||||||
self.assertRaises(exception.VolumeBackendAPIException,
|
self.assertRaises(exception.VolumeBackendAPIException,
|
||||||
@ -4230,7 +4268,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
self._assert_vol_exists(volfs['name'], False)
|
self._assert_vol_exists(volfs['name'], False)
|
||||||
|
|
||||||
# Create volume from snapshot and delete it
|
# Create volume from snapshot and delete it
|
||||||
volfs = self._generate_vol_info(None, None)
|
volfs = self._generate_vol_info()
|
||||||
if self.USESIM:
|
if self.USESIM:
|
||||||
self.sim.error_injection('lsfcmap', 'speed_up')
|
self.sim.error_injection('lsfcmap', 'speed_up')
|
||||||
self.driver.create_volume_from_snapshot(volfs, snap)
|
self.driver.create_volume_from_snapshot(volfs, snap)
|
||||||
@ -4239,7 +4277,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
self._assert_vol_exists(volfs['name'], False)
|
self._assert_vol_exists(volfs['name'], False)
|
||||||
|
|
||||||
# Create volume from snapshot and delete the snapshot
|
# Create volume from snapshot and delete the snapshot
|
||||||
volfs = self._generate_vol_info(None, None)
|
volfs = self._generate_vol_info()
|
||||||
if self.USESIM:
|
if self.USESIM:
|
||||||
self.sim.error_injection('lsfcmap', 'speed_up')
|
self.sim.error_injection('lsfcmap', 'speed_up')
|
||||||
self.driver.create_volume_from_snapshot(volfs, snap)
|
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
|
# Fail create clone - will force delete the target volume
|
||||||
if self.USESIM:
|
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('startfcmap', 'bad_id')
|
||||||
self.sim.error_injection('lsfcmap', 'speed_up')
|
self.sim.error_injection('lsfcmap', 'speed_up')
|
||||||
self.assertRaises(exception.VolumeBackendAPIException,
|
self.assertRaises(exception.VolumeBackendAPIException,
|
||||||
@ -4257,7 +4295,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
self._assert_vol_exists(clone['name'], False)
|
self._assert_vol_exists(clone['name'], False)
|
||||||
|
|
||||||
# Create the clone, delete the source and target
|
# Create the clone, delete the source and target
|
||||||
clone = self._generate_vol_info(None, None)
|
clone = self._generate_vol_info()
|
||||||
if self.USESIM:
|
if self.USESIM:
|
||||||
self.sim.error_injection('lsfcmap', 'speed_up')
|
self.sim.error_injection('lsfcmap', 'speed_up')
|
||||||
self.driver.create_cloned_volume(clone, volfs)
|
self.driver.create_cloned_volume(clone, volfs)
|
||||||
@ -4306,12 +4344,13 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
def test_get_pool(self):
|
def test_get_pool(self):
|
||||||
ctxt = testutils.get_test_admin_context()
|
ctxt = testutils.get_test_admin_context()
|
||||||
type_ref = volume_types.create(ctxt, 'testtype', None)
|
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_id = type_ref['id']
|
||||||
volume.volume_type = objects.VolumeType.get_by_id(ctxt,
|
volume.volume_type = objects.VolumeType.get_by_id(ctxt,
|
||||||
type_ref['id'])
|
type_ref['id'])
|
||||||
self.driver.create_volume(volume)
|
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.get_pool(volume))
|
||||||
|
|
||||||
self.driver.delete_volume(volume)
|
self.driver.delete_volume(volume)
|
||||||
@ -4325,7 +4364,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
|
|
||||||
self.assertAlmostEqual(vol_size, 13)
|
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.driver.create_snapshot(snap)
|
||||||
self._assert_vol_exists(snap['name'], True)
|
self._assert_vol_exists(snap['name'], True)
|
||||||
self.assertRaises(exception.VolumeDriverException,
|
self.assertRaises(exception.VolumeDriverException,
|
||||||
@ -4537,10 +4576,9 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
diff, _equal = volume_types.volume_types_diff(ctxt, old_type_ref['id'],
|
diff, _equal = volume_types.volume_types_diff(ctxt, old_type_ref['id'],
|
||||||
new_type_ref['id'])
|
new_type_ref['id'])
|
||||||
|
|
||||||
volume = self._generate_vol_info(None, None)
|
|
||||||
old_type = objects.VolumeType.get_by_id(ctxt,
|
old_type = objects.VolumeType.get_by_id(ctxt,
|
||||||
old_type_ref['id'])
|
old_type_ref['id'])
|
||||||
volume['volume_type'] = old_type
|
volume = self._generate_vol_info(old_type)
|
||||||
volume['host'] = host['host']
|
volume['host'] = host['host']
|
||||||
new_type = objects.VolumeType.get_by_id(ctxt,
|
new_type = objects.VolumeType.get_by_id(ctxt,
|
||||||
new_type_ref['id'])
|
new_type_ref['id'])
|
||||||
@ -4629,10 +4667,9 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
diff, _equal = volume_types.volume_types_diff(ctxt, old_type_ref['id'],
|
diff, _equal = volume_types.volume_types_diff(ctxt, old_type_ref['id'],
|
||||||
new_type_ref['id'])
|
new_type_ref['id'])
|
||||||
|
|
||||||
volume = self._generate_vol_info(None, None)
|
|
||||||
old_type = objects.VolumeType.get_by_id(ctxt,
|
old_type = objects.VolumeType.get_by_id(ctxt,
|
||||||
old_type_ref['id'])
|
old_type_ref['id'])
|
||||||
volume['volume_type'] = old_type
|
volume = self._generate_vol_info(old_type)
|
||||||
volume['host'] = host['host']
|
volume['host'] = host['host']
|
||||||
new_type = objects.VolumeType.get_by_id(ctxt,
|
new_type = objects.VolumeType.get_by_id(ctxt,
|
||||||
new_type_ref['id'])
|
new_type_ref['id'])
|
||||||
@ -4666,10 +4703,9 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
diff, _equal = volume_types.volume_types_diff(ctxt, old_type_ref['id'],
|
diff, _equal = volume_types.volume_types_diff(ctxt, old_type_ref['id'],
|
||||||
new_type_ref['id'])
|
new_type_ref['id'])
|
||||||
|
|
||||||
volume = self._generate_vol_info(None, None)
|
|
||||||
old_type = objects.VolumeType.get_by_id(ctxt,
|
old_type = objects.VolumeType.get_by_id(ctxt,
|
||||||
old_type_ref['id'])
|
old_type_ref['id'])
|
||||||
volume['volume_type'] = old_type
|
volume = self._generate_vol_info(old_type)
|
||||||
volume['host'] = host['host']
|
volume['host'] = host['host']
|
||||||
new_type = objects.VolumeType.get_by_id(ctxt,
|
new_type = objects.VolumeType.get_by_id(ctxt,
|
||||||
new_type_ref['id'])
|
new_type_ref['id'])
|
||||||
@ -4801,7 +4837,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
self.assertNotIn(volume['id'], self.driver._vdiskcopyops)
|
self.assertNotIn(volume['id'], self.driver._vdiskcopyops)
|
||||||
|
|
||||||
def test_storwize_create_volume_with_replication_disable(self):
|
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)
|
model_update = self.driver.create_volume(volume)
|
||||||
self.assertIsNone(model_update)
|
self.assertIsNone(model_update)
|
||||||
@ -4814,7 +4850,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
self._set_flag('storwize_svc_stretched_cluster_partner', 'openstack2')
|
self._set_flag('storwize_svc_stretched_cluster_partner', 'openstack2')
|
||||||
|
|
||||||
# Create a type for repliation.
|
# 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_type = self._create_replication_volume_type(True)
|
||||||
volume['volume_type_id'] = volume_type['id']
|
volume['volume_type_id'] = volume_type['id']
|
||||||
|
|
||||||
@ -4907,11 +4943,11 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
self.driver.do_setup(self.ctxt)
|
self.driver.do_setup(self.ctxt)
|
||||||
|
|
||||||
# Create a source volume.
|
# Create a source volume.
|
||||||
src_volume = self._generate_vol_info(None, None)
|
src_volume = self._generate_vol_info()
|
||||||
self.driver.create_volume(src_volume)
|
self.driver.create_volume(src_volume)
|
||||||
|
|
||||||
# Create a type for repliation.
|
# 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_type = self._create_replication_volume_type(True)
|
||||||
volume['volume_type_id'] = volume_type['id']
|
volume['volume_type_id'] = volume_type['id']
|
||||||
|
|
||||||
@ -4929,12 +4965,12 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
self.driver.do_setup(self.ctxt)
|
self.driver.do_setup(self.ctxt)
|
||||||
|
|
||||||
vol1 = self._create_volume()
|
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)
|
self.driver.create_snapshot(snap)
|
||||||
vol2 = self._generate_vol_info(None, None)
|
vol2 = self._generate_vol_info()
|
||||||
|
|
||||||
# Create a type for repliation.
|
# 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)
|
volume_type = self._create_replication_volume_type(True)
|
||||||
vol2['volume_type_id'] = volume_type['id']
|
vol2['volume_type_id'] = volume_type['id']
|
||||||
|
|
||||||
@ -5239,6 +5275,231 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
for volume in model_update[1]:
|
for volume in model_update[1]:
|
||||||
self.assertEqual('deleted', volume['status'])
|
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):
|
def _create_volume_type_qos(self, extra_specs, fake_qos):
|
||||||
# Generate a QoS volume type for volume.
|
# Generate a QoS volume type for volume.
|
||||||
if extra_specs:
|
if extra_specs:
|
||||||
@ -5309,7 +5570,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
create_volume and then calling into the simulator to perform an
|
create_volume and then calling into the simulator to perform an
|
||||||
lsvdisk directly.
|
lsvdisk directly.
|
||||||
"""
|
"""
|
||||||
volume = self._generate_vol_info(None, None)
|
volume = self._generate_vol_info()
|
||||||
self.driver.create_volume(volume)
|
self.driver.create_volume(volume)
|
||||||
|
|
||||||
return (volume, self._get_vdisk_uid(volume['name']))
|
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
|
a bad reference that the Storwize driver doesn't understand. We
|
||||||
expect an exception to be raised.
|
expect an exception to be raised.
|
||||||
"""
|
"""
|
||||||
volume = self._generate_vol_info(None, None)
|
volume = self._generate_vol_info()
|
||||||
ref = {}
|
ref = {}
|
||||||
self.assertRaises(exception.ManageExistingInvalidReference,
|
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||||
self.driver.manage_existing_get_size, volume, ref)
|
self.driver.manage_existing_get_size, volume, ref)
|
||||||
|
|
||||||
def test_manage_existing_get_size_bad_uid(self):
|
def test_manage_existing_get_size_bad_uid(self):
|
||||||
"""Error when the specified UUID does not exist."""
|
"""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'}
|
ref = {'source-id': 'bad_uid'}
|
||||||
self.assertRaises(exception.ManageExistingInvalidReference,
|
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||||
self.driver.manage_existing_get_size, volume, ref)
|
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):
|
def test_manage_existing_get_size_bad_name(self):
|
||||||
"""Error when the specified name does not exist."""
|
"""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'}
|
ref = {'source-name': 'bad_name'}
|
||||||
self.assertRaises(exception.ManageExistingInvalidReference,
|
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||||
self.driver.manage_existing_get_size, volume, ref)
|
self.driver.manage_existing_get_size, volume, ref)
|
||||||
@ -5350,19 +5611,19 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Error when neither UUID nor name are specified.
|
# Error when neither UUID nor name are specified.
|
||||||
volume = self._generate_vol_info(None, None)
|
volume = self._generate_vol_info()
|
||||||
ref = {}
|
ref = {}
|
||||||
self.assertRaises(exception.ManageExistingInvalidReference,
|
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||||
self.driver.manage_existing, volume, ref)
|
self.driver.manage_existing, volume, ref)
|
||||||
|
|
||||||
# Error when the specified UUID does not exist.
|
# 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'}
|
ref = {'source-id': 'bad_uid'}
|
||||||
self.assertRaises(exception.ManageExistingInvalidReference,
|
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||||
self.driver.manage_existing, volume, ref)
|
self.driver.manage_existing, volume, ref)
|
||||||
|
|
||||||
# Error when the specified name does not exist.
|
# 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'}
|
ref = {'source-name': 'bad_name'}
|
||||||
self.assertRaises(exception.ManageExistingInvalidReference,
|
self.assertRaises(exception.ManageExistingInvalidReference,
|
||||||
self.driver.manage_existing, volume, ref)
|
self.driver.manage_existing, volume, ref)
|
||||||
@ -5386,7 +5647,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
opts = {'rsize': -1, 'iogrp': 1}
|
opts = {'rsize': -1, 'iogrp': 1}
|
||||||
type_iogrp_ref = volume_types.create(ctxt, 'testtype4', opts)
|
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']}
|
ref = {'source-name': _volume['name']}
|
||||||
|
|
||||||
fake_copy_thin = self._get_default_opts()
|
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
|
# Descriptor of the Cinder volume that we want to own the vdisk
|
||||||
# referenced by uid.
|
# referenced by uid.
|
||||||
new_volume = self._generate_vol_info(None, None)
|
new_volume = self._generate_vol_info()
|
||||||
|
|
||||||
# Submit the request to manage it.
|
# Submit the request to manage it.
|
||||||
ref = {'source-id': uid}
|
ref = {'source-id': uid}
|
||||||
@ -5490,7 +5751,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
|
|
||||||
# Descriptor of the Cinder volume that we want to own the vdisk
|
# Descriptor of the Cinder volume that we want to own the vdisk
|
||||||
# referenced by uid.
|
# referenced by uid.
|
||||||
new_volume = self._generate_vol_info(None, None)
|
new_volume = self._generate_vol_info()
|
||||||
|
|
||||||
# Submit the request to manage it.
|
# Submit the request to manage it.
|
||||||
ref = {'source-name': _volume['name']}
|
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
|
# Descriptor of the Cinder volume that we want to own the vdisk
|
||||||
# referenced by uid.
|
# referenced by uid.
|
||||||
volume = self._generate_vol_info(None, None)
|
volume = self._generate_vol_info()
|
||||||
ref = {'source-id': uid}
|
ref = {'source-id': uid}
|
||||||
|
|
||||||
# Attempt to manage this disk, and except an exception beause the
|
# 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
|
# Descriptor of the Cinder volume that we want to own the vdisk
|
||||||
# referenced by uid.
|
# 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
|
# Submit the request to manage it, specifying that it is OK to
|
||||||
# manage a volume that is already attached.
|
# 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
|
# Descriptor of the Cinder volume that we want to own the vdisk
|
||||||
# referenced by uid.
|
# 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
|
# Submit the request to manage it, specifying that it is OK to
|
||||||
# manage a volume that is already attached.
|
# manage a volume that is already attached.
|
||||||
@ -5856,6 +6117,7 @@ class StorwizeSSHTestCase(test.TestCase):
|
|||||||
'fakevol', '1', 'gb', 'fakepool', opt, [])
|
'fakevol', '1', 'gb', 'fakepool', opt, [])
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
class StorwizeSVCReplicationTestCase(test.TestCase):
|
class StorwizeSVCReplicationTestCase(test.TestCase):
|
||||||
@mock.patch.object(time, 'sleep')
|
@mock.patch.object(time, 'sleep')
|
||||||
def setUp(self, mock_sleep):
|
def setUp(self, mock_sleep):
|
||||||
@ -5949,7 +6211,8 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
|
|||||||
return snap
|
return snap
|
||||||
|
|
||||||
def _create_replica_volume_type(self, enable,
|
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.
|
# Generate a volume type for volume repliation.
|
||||||
if enable:
|
if enable:
|
||||||
if rep_type == storwize_const.METRO:
|
if rep_type == storwize_const.METRO:
|
||||||
@ -5960,6 +6223,9 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
|
|||||||
spec = {'replication_enabled': '<is> True',
|
spec = {'replication_enabled': '<is> True',
|
||||||
'replication_type': '<in> global'}
|
'replication_type': '<in> global'}
|
||||||
type_name = 'rep_global'
|
type_name = 'rep_global'
|
||||||
|
elif opts:
|
||||||
|
spec = opts
|
||||||
|
type_name = vol_type_name
|
||||||
else:
|
else:
|
||||||
spec = {'replication_enabled': '<is> False'}
|
spec = {'replication_enabled': '<is> False'}
|
||||||
type_name = "non_rep"
|
type_name = "non_rep"
|
||||||
@ -6042,6 +6308,21 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
|
|||||||
self.driver._active_backend_id = None
|
self.driver._active_backend_id = None
|
||||||
self.driver._get_storwize_config()
|
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):
|
def test_storwize_create_volume_with_mirror_replication(self):
|
||||||
# Set replication target.
|
# Set replication target.
|
||||||
self.driver.configuration.set_override('replication_device',
|
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(src_volume)
|
||||||
self.driver.delete_volume(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):
|
def test_storwize_retype_from_mirror_to_none_replication(self):
|
||||||
# Set replication target
|
# Set replication target
|
||||||
self.driver.configuration.set_override('replication_device',
|
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)
|
volume, model_update = self._create_test_volume(self.mm_type)
|
||||||
self.assertEqual('enabled', model_update['replication_status'])
|
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(
|
diff, _equal = volume_types.volume_types_diff(
|
||||||
self.ctxt, self.non_replica_type['id'], self.mm_type['id'])
|
self.ctxt, self.non_replica_type['id'], self.mm_type['id'])
|
||||||
# Disable replica
|
# Disable replica
|
||||||
@ -6275,6 +6586,33 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
|
|||||||
|
|
||||||
self.driver.delete_volume(rep_volume)
|
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):
|
def test_storwize_delete_volume_with_mirror_replication(self):
|
||||||
# Set replication target.
|
# Set replication target.
|
||||||
self.driver.configuration.set_override('replication_device',
|
self.driver.configuration.set_override('replication_device',
|
||||||
|
@ -120,6 +120,10 @@ storwize_svc_opts = [
|
|||||||
help='Specifies the Storwize FlashCopy copy rate to be used '
|
help='Specifies the Storwize FlashCopy copy rate to be used '
|
||||||
'when creating a full volume copy. The default is rate '
|
'when creating a full volume copy. The default is rate '
|
||||||
'is 50, and the valid rates are 1-100.'),
|
'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
|
CONF = cfg.CONF
|
||||||
@ -196,7 +200,13 @@ class StorwizeSSH(object):
|
|||||||
def lsmdiskgrp(self, pool):
|
def lsmdiskgrp(self, pool):
|
||||||
ssh_cmd = ['svcinfo', 'lsmdiskgrp', '-bytes', '-delim', '!',
|
ssh_cmd = ['svcinfo', 'lsmdiskgrp', '-bytes', '-delim', '!',
|
||||||
'"%s"' % pool]
|
'"%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):
|
def lsiogrp(self):
|
||||||
ssh_cmd = ['svcinfo', 'lsiogrp', '-delim', '!']
|
ssh_cmd = ['svcinfo', 'lsiogrp', '-delim', '!']
|
||||||
@ -542,9 +552,12 @@ class StorwizeSSH(object):
|
|||||||
ssh_cmd = ['svctask', 'rmfcconsistgrp', '-force', fc_consist_group]
|
ssh_cmd = ['svctask', 'rmfcconsistgrp', '-force', fc_consist_group]
|
||||||
return self.run_ssh_assert_no_output(ssh_cmd)
|
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',
|
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)
|
return self.run_ssh_check_created(ssh_cmd)
|
||||||
|
|
||||||
def lsvdiskcopy(self, vdisk, copy_id=None):
|
def lsvdiskcopy(self, vdisk, copy_id=None):
|
||||||
@ -579,6 +592,11 @@ class StorwizeSSH(object):
|
|||||||
'-filtervalue', 'node_id=%s' % node_id]
|
'-filtervalue', 'node_id=%s' % node_id]
|
||||||
return self.run_ssh_info(ssh_cmd, with_header=True)
|
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):
|
class StorwizeHelpers(object):
|
||||||
|
|
||||||
@ -653,6 +671,11 @@ class StorwizeHelpers(object):
|
|||||||
"""Return attributes for the specified pool."""
|
"""Return attributes for the specified pool."""
|
||||||
return self.ssh.lsmdiskgrp(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):
|
def get_available_io_groups(self):
|
||||||
"""Return list of available IO groups."""
|
"""Return list of available IO groups."""
|
||||||
iogrps = []
|
iogrps = []
|
||||||
@ -1030,7 +1053,8 @@ class StorwizeHelpers(object):
|
|||||||
'qos': None,
|
'qos': None,
|
||||||
'stretched_cluster': cluster_partner,
|
'stretched_cluster': cluster_partner,
|
||||||
'replication': False,
|
'replication': False,
|
||||||
'nofmtdisk': config.storwize_svc_vol_nofmtdisk}
|
'nofmtdisk': config.storwize_svc_vol_nofmtdisk,
|
||||||
|
'mirror_pool': config.storwize_svc_mirror_pool}
|
||||||
return opt
|
return opt
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -1225,7 +1249,7 @@ class StorwizeHelpers(object):
|
|||||||
return opts
|
return opts
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_vdisk_create_params(opts):
|
def _get_vdisk_create_params(opts, add_copies=False):
|
||||||
easytier = 'on' if opts['easytier'] else 'off'
|
easytier = 'on' if opts['easytier'] else 'off'
|
||||||
if opts['rsize'] == -1:
|
if opts['rsize'] == -1:
|
||||||
params = []
|
params = []
|
||||||
@ -1243,14 +1267,27 @@ class StorwizeHelpers(object):
|
|||||||
else:
|
else:
|
||||||
params.extend(['-grainsize', str(opts['grainsize'])])
|
params.extend(['-grainsize', str(opts['grainsize'])])
|
||||||
|
|
||||||
|
if add_copies and opts['mirror_pool']:
|
||||||
|
params.extend(['-copies', '2'])
|
||||||
|
|
||||||
params.extend(['-easytier', easytier])
|
params.extend(['-easytier', easytier])
|
||||||
return params
|
return params
|
||||||
|
|
||||||
def create_vdisk(self, name, size, units, pool, opts):
|
def create_vdisk(self, name, size, units, pool, opts):
|
||||||
name = '"%s"' % name
|
name = '"%s"' % name
|
||||||
LOG.debug('Enter: create_vdisk: vdisk %s.', name)
|
LOG.debug('Enter: create_vdisk: vdisk %s.', name)
|
||||||
params = self._get_vdisk_create_params(opts)
|
mdiskgrp = pool
|
||||||
self.ssh.mkvdisk(name, size, units, pool, opts, params)
|
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)
|
LOG.debug('Leave: _create_vdisk: volume %s.', name)
|
||||||
|
|
||||||
def get_vdisk_attributes(self, vdisk):
|
def get_vdisk_attributes(self, vdisk):
|
||||||
@ -1349,11 +1386,18 @@ class StorwizeHelpers(object):
|
|||||||
for snapshot in snapshots:
|
for snapshot in snapshots:
|
||||||
opts = self.get_vdisk_params(config, state,
|
opts = self.get_vdisk_params(config, state,
|
||||||
snapshot['volume_type_id'])
|
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'],
|
self.create_flashcopy_to_consistgrp(snapshot['volume_name'],
|
||||||
snapshot['name'],
|
snapshot['name'],
|
||||||
fc_consistgrp,
|
fc_consistgrp,
|
||||||
config, opts)
|
config, opts, False,
|
||||||
|
pool=pool)
|
||||||
|
|
||||||
self.prepare_fc_consistgrp(fc_consistgrp, timeout)
|
self.prepare_fc_consistgrp(fc_consistgrp, timeout)
|
||||||
self.start_fc_consistgrp(fc_consistgrp)
|
self.start_fc_consistgrp(fc_consistgrp)
|
||||||
@ -1382,7 +1426,7 @@ class StorwizeHelpers(object):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
for snapshot in snapshots:
|
for snapshot in snapshots:
|
||||||
self.ssh.rmvdisk(snapshot['name'], True)
|
self.delete_vdisk(snapshot['name'], True)
|
||||||
except exception.VolumeBackendAPIException as err:
|
except exception.VolumeBackendAPIException as err:
|
||||||
model_update['status'] = (
|
model_update['status'] = (
|
||||||
fields.GroupSnapshotStatus.ERROR_DELETING)
|
fields.GroupSnapshotStatus.ERROR_DELETING)
|
||||||
@ -1744,7 +1788,8 @@ class StorwizeHelpers(object):
|
|||||||
def extend_vdisk(self, vdisk, amount):
|
def extend_vdisk(self, vdisk, amount):
|
||||||
self.ssh.expandvdisksize(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."""
|
"""Add a vdisk copy in the given pool."""
|
||||||
resp = self.ssh.lsvdiskcopy(vdisk)
|
resp = self.ssh.lsvdiskcopy(vdisk)
|
||||||
if len(resp) > 1:
|
if len(resp) > 1:
|
||||||
@ -1766,7 +1811,15 @@ class StorwizeHelpers(object):
|
|||||||
opts = self.get_vdisk_params(config, state, volume_type['id'],
|
opts = self.get_vdisk_params(config, state, volume_type['id'],
|
||||||
volume_type=volume_type)
|
volume_type=volume_type)
|
||||||
params = self._get_vdisk_create_params(opts)
|
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)
|
return (orig_copy_id, new_copy_id)
|
||||||
|
|
||||||
def is_vdisk_copy_synced(self, vdisk, 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):
|
def rm_vdisk_copy(self, vdisk, copy_id):
|
||||||
self.ssh.rmvdiskcopy(vdisk, copy_id)
|
self.ssh.rmvdiskcopy(vdisk, copy_id)
|
||||||
|
|
||||||
|
def lsvdiskcopy(self, vdisk, copy_id=None):
|
||||||
|
return self.ssh.lsvdiskcopy(vdisk, copy_id)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def can_migrate_to_host(host, state):
|
def can_migrate_to_host(host, state):
|
||||||
if 'location_info' not in host['capabilities']:
|
if 'location_info' not in host['capabilities']:
|
||||||
@ -1880,6 +1936,9 @@ class StorwizeHelpers(object):
|
|||||||
def change_vdisk_primary_copy(self, vdisk, copy_id):
|
def change_vdisk_primary_copy(self, vdisk, copy_id):
|
||||||
self.ssh.chvdisk(vdisk, ['-primary', 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):
|
class CLIResponse(object):
|
||||||
"""Parse SVC CLI output and generate iterable."""
|
"""Parse SVC CLI output and generate iterable."""
|
||||||
@ -2148,11 +2207,9 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
# Validate that the pool exists
|
# Validate that the pool exists
|
||||||
pools = self._get_backend_pools()
|
pools = self._get_backend_pools()
|
||||||
for pool in pools:
|
for pool in pools:
|
||||||
try:
|
if not self._helpers.is_pool_defined(pool):
|
||||||
self._helpers.get_pool_attrs(pool)
|
reason = (_('Failed getting details for pool %s.') % pool)
|
||||||
except exception.VolumeBackendAPIException:
|
raise exception.InvalidInput(reason=reason)
|
||||||
msg = _('Failed getting details for pool %s.') % pool
|
|
||||||
raise exception.InvalidInput(reason=msg)
|
|
||||||
|
|
||||||
def check_for_setup_error(self):
|
def check_for_setup_error(self):
|
||||||
"""Ensure that the flags are set properly."""
|
"""Ensure that the flags are set properly."""
|
||||||
@ -2337,8 +2394,14 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
opts = self._get_vdisk_params(volume['volume_type_id'],
|
opts = self._get_vdisk_params(volume['volume_type_id'],
|
||||||
volume_metadata=
|
volume_metadata=
|
||||||
volume.get('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)
|
opts['iogrp'] = self._helpers.select_io_group(self._state, opts)
|
||||||
self._helpers.create_vdisk(volume['name'], str(volume['size']),
|
self._helpers.create_vdisk(volume['name'], str(volume['size']),
|
||||||
'gb', pool, opts)
|
'gb', pool, opts)
|
||||||
@ -2346,8 +2409,6 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
self._helpers.add_vdisk_qos(volume['name'], opts['qos'])
|
self._helpers.add_vdisk_qos(volume['name'], opts['qos'])
|
||||||
|
|
||||||
model_update = None
|
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.
|
# The replication V2 has a higher priority than the replication V1.
|
||||||
# Check if V2 is available first, then check if V1 is available.
|
# 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)
|
rep_type = self._get_volume_replicated_type(ctxt, volume)
|
||||||
if rep_type:
|
if rep_type:
|
||||||
self._aux_backend_helpers.delete_rc_volume(volume['name'],
|
if self._aux_backend_helpers:
|
||||||
target_vol=True)
|
self._aux_backend_helpers.delete_rc_volume(volume['name'],
|
||||||
|
target_vol=True)
|
||||||
if not self._active_backend_id:
|
if not self._active_backend_id:
|
||||||
self._master_backend_helpers.delete_rc_volume(volume['name'])
|
self._master_backend_helpers.delete_rc_volume(volume['name'])
|
||||||
else:
|
else:
|
||||||
@ -2565,10 +2627,11 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
self._helpers.extend_vdisk(volume_name, extend_amt)
|
self._helpers.extend_vdisk(volume_name, extend_amt)
|
||||||
LOG.debug('leave: _extend_volume_op: volume %s', volume['id'])
|
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,
|
return self._helpers.add_vdisk_copy(volume, dest_pool,
|
||||||
vol_type, self._state,
|
vol_type, self._state,
|
||||||
self.configuration)
|
self.configuration,
|
||||||
|
auto_delete=auto_delete)
|
||||||
|
|
||||||
def _add_vdisk_copy_op(self, ctxt, volume, new_op):
|
def _add_vdisk_copy_op(self, ctxt, volume, new_op):
|
||||||
metadata = self.db.volume_admin_metadata_get(ctxt.elevated(),
|
metadata = self.db.volume_admin_metadata_get(ctxt.elevated(),
|
||||||
@ -3164,13 +3227,78 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
else:
|
else:
|
||||||
vol_type = None
|
vol_type = None
|
||||||
|
|
||||||
self._check_volume_copy_ops()
|
resp = self._helpers.lsvdiskcopy(volume.name)
|
||||||
new_op = self.add_vdisk_copy(volume['name'], dest_pool, vol_type)
|
if len(resp) > 1:
|
||||||
self._add_vdisk_copy_op(ctxt, volume, new_op)
|
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',
|
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)
|
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):
|
def retype(self, ctxt, volume, new_type, diff, host):
|
||||||
"""Convert the volume to be of the new type.
|
"""Convert the volume to be of the new type.
|
||||||
|
|
||||||
@ -3206,6 +3334,8 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
|
|
||||||
vdisk_changes = []
|
vdisk_changes = []
|
||||||
need_copy = False
|
need_copy = False
|
||||||
|
change_mirror = False
|
||||||
|
|
||||||
for key in all_keys:
|
for key in all_keys:
|
||||||
if old_opts[key] != new_opts[key]:
|
if old_opts[key] != new_opts[key]:
|
||||||
if key in copy_keys:
|
if key in copy_keys:
|
||||||
@ -3218,38 +3348,18 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
utils.extract_host(host['host'], 'pool')):
|
utils.extract_host(host['host'], 'pool')):
|
||||||
need_copy = True
|
need_copy = True
|
||||||
|
|
||||||
|
if old_opts['mirror_pool'] != new_opts['mirror_pool']:
|
||||||
|
change_mirror = True
|
||||||
|
|
||||||
# Check if retype affects volume replication
|
# Check if retype affects volume replication
|
||||||
model_update = None
|
model_update = None
|
||||||
new_rep_type = self._get_specs_replicated_type(new_type)
|
new_rep_type = self._get_specs_replicated_type(new_type)
|
||||||
old_rep_type = self._get_volume_replicated_type(ctxt, volume)
|
old_rep_type = self._get_volume_replicated_type(ctxt, volume)
|
||||||
old_io_grp = self._helpers.get_volume_io_group(volume['name'])
|
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)
|
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:
|
if need_copy:
|
||||||
self._check_volume_copy_ops()
|
self._check_volume_copy_ops()
|
||||||
dest_pool = self._helpers.can_migrate_to_host(host, self._state)
|
dest_pool = self._helpers.can_migrate_to_host(host, self._state)
|
||||||
@ -3259,10 +3369,8 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
retype_iogrp_property(volume,
|
retype_iogrp_property(volume,
|
||||||
new_io_grp, old_io_grp)
|
new_io_grp, old_io_grp)
|
||||||
try:
|
try:
|
||||||
new_op = self.add_vdisk_copy(volume['name'],
|
self.add_vdisk_copy(volume['name'], dest_pool, new_type,
|
||||||
dest_pool,
|
auto_delete=True)
|
||||||
new_type)
|
|
||||||
self._add_vdisk_copy_op(ctxt, volume, new_op)
|
|
||||||
except exception.VolumeDriverException:
|
except exception.VolumeDriverException:
|
||||||
# roll back changing iogrp property
|
# roll back changing iogrp property
|
||||||
retype_iogrp_property(volume, old_io_grp, new_io_grp)
|
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,
|
self._helpers.change_vdisk_options(volume['name'], vdisk_changes,
|
||||||
new_opts, self._state)
|
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']:
|
if new_opts['qos']:
|
||||||
# Add the new QoS setting to the volume. If the volume has an
|
# Add the new QoS setting to the volume. If the volume has an
|
||||||
# old QoS setting, it will be overwritten.
|
# old QoS setting, it will be overwritten.
|
||||||
@ -3322,6 +3446,13 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
original_volume_name = CONF.volume_name_template % volume['id']
|
original_volume_name = CONF.volume_name_template % volume['id']
|
||||||
try:
|
try:
|
||||||
self._helpers.rename_vdisk(current_name, original_volume_name)
|
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:
|
except exception.VolumeBackendAPIException:
|
||||||
LOG.error('Unable to rename the logical volume '
|
LOG.error('Unable to rename the logical volume '
|
||||||
'for volume: %s', volume['id'])
|
'for volume: %s', volume['id'])
|
||||||
@ -3357,6 +3488,7 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
rep_type = self._get_volume_replicated_type(ctxt, volume)
|
rep_type = self._get_volume_replicated_type(ctxt, volume)
|
||||||
vol_rep_type = None
|
vol_rep_type = None
|
||||||
rel_info = self._helpers.get_relationship_info(vdisk['name'])
|
rel_info = self._helpers.get_relationship_info(vdisk['name'])
|
||||||
|
copies = self._helpers.get_vdisk_copies(vdisk['name'])
|
||||||
if rel_info:
|
if rel_info:
|
||||||
vol_rep_type = rel_info['copy_type']
|
vol_rep_type = rel_info['copy_type']
|
||||||
aux_info = self._aux_backend_helpers.get_system_info()
|
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'],
|
opts = self._get_vdisk_params(volume['volume_type_id'],
|
||||||
volume_metadata=
|
volume_metadata=
|
||||||
volume.get('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:
|
if vdisk_copy['autoexpand'] == 'on' and opts['rsize'] == -1:
|
||||||
msg = (_("Failed to manage existing volume due to "
|
msg = (_("Failed to manage existing volume due to "
|
||||||
"the volume to be managed is thin, but "
|
"the volume to be managed is thin, but "
|
||||||
@ -3418,15 +3570,14 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
'opt_iogrp': opts['iogrp']})
|
'opt_iogrp': opts['iogrp']})
|
||||||
raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
|
raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
|
||||||
pool = utils.extract_host(volume['host'], 'pool')
|
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 "
|
msg = (_("Failed to manage existing volume due to the "
|
||||||
"pool of the volume to be managed does not "
|
"pool of the volume to be managed does not "
|
||||||
"match the backend pool. Pool of the "
|
"match the backend pool. Pool of the "
|
||||||
"volume to be managed is %(vdisk_pool)s. Pool "
|
"volume to be managed is %(vdisk_pool)s. Pool "
|
||||||
"of the backend is %(backend_pool)s.") %
|
"of the backend is %(backend_pool)s.") %
|
||||||
{'vdisk_pool': vdisk['mdisk_grp_name'],
|
{'vdisk_pool': copies['primary']['mdisk_grp_name'],
|
||||||
'backend_pool':
|
'backend_pool': pool})
|
||||||
self._get_backend_pools()})
|
|
||||||
raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
|
raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
|
||||||
|
|
||||||
model_update = {}
|
model_update = {}
|
||||||
|
@ -89,9 +89,10 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
|
|||||||
mode
|
mode
|
||||||
2.1.1 - Update replication to version 2.1
|
2.1.1 - Update replication to version 2.1
|
||||||
2.2 - Add CG capability to generic volume groups
|
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
|
# ThirdPartySystems wiki page
|
||||||
CI_WIKI_NAME = "IBM_STORAGE_CI"
|
CI_WIKI_NAME = "IBM_STORAGE_CI"
|
||||||
|
@ -89,9 +89,10 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
|
|||||||
mode
|
mode
|
||||||
2.1.1 - Update replication to version 2.1
|
2.1.1 - Update replication to version 2.1
|
||||||
2.2 - Add CG capability to generic volume groups
|
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
|
# ThirdPartySystems wiki page
|
||||||
CI_WIKI_NAME = "IBM_STORAGE_CI"
|
CI_WIKI_NAME = "IBM_STORAGE_CI"
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Add mirrored volume support in IBM SVC/Storwize driver.
|
Loading…
x
Reference in New Issue
Block a user