Storwize: add data reduction pool support

Data reduction pool is a new style pool on Storwize/SVC storage.
Thin provisioned/compressed vdisk copies created in a data_reduction
pool are quite different from regular pool.

This patch adds thin-provision and compressed volumes support on
data reduction pool.

Change-Id: Icb09cbacc3cfe63017d17847799c0904e06cf8a7
Implements: blueprint svc-drpool-support
This commit is contained in:
yixuan.zhang 2018-05-21 14:27:39 +08:00 committed by yixuan zhang
parent 4b96310411
commit 822fb701de
4 changed files with 631 additions and 64 deletions

View File

@ -538,7 +538,8 @@ class StorwizeSVCManagementSimulator(object):
'vdisk_count', 'capacity', 'extent_size',
'free_capacity', 'virtual_capacity', 'used_capacity',
'real_capacity', 'overallocation', 'warning',
'easy_tier', 'easy_tier_status', 'site_id'])
'easy_tier', 'easy_tier_status', 'site_id',
'data_reduction'])
for i in range(pool_num):
row_data = [str(i + 1),
self._flags['storwize_svc_volpool_name'][i], 'online',
@ -546,24 +547,32 @@ class StorwizeSVCManagementSimulator(object):
'3573412790272', '256', '3529926246400',
'1693247906775',
'26843545600', '38203734097', '47', '80', 'auto',
'inactive', '']
'inactive', '', 'no']
rows.append(row_data)
rows.append([str(pool_num + 1), 'openstack2', 'online',
'1', '0', '3573412790272', '256',
'3529432325160', '1693247906775', '26843545600',
'38203734097', '47', '80', 'auto', 'inactive', ''])
'38203734097', '47', '80', 'auto', 'inactive', '', 'no'])
rows.append([str(pool_num + 2), 'openstack3', 'offline',
'1', '0', '3573412790272', '128',
'3529432325160', '1693247906775', '26843545600',
'38203734097', '47', '80', 'auto', 'inactive', ''])
'38203734097', '47', '80', 'auto', 'inactive', '', 'yes'])
rows.append([str(pool_num + 3), 'hyperswap1', 'online',
'1', '0', '3573412790272', '256',
'3529432325160', '1693247906775', '26843545600',
'38203734097', '47', '80', 'auto', 'inactive', '1'])
'38203734097', '47', '80', 'auto', 'inactive', '1', 'no'])
rows.append([str(pool_num + 4), 'hyperswap2', 'online',
'1', '0', '3573412790272', '128',
'3529432325160', '1693247906775', '26843545600',
'38203734097', '47', '80', 'auto', 'inactive', '2'])
'38203734097', '47', '80', 'auto', 'inactive', '2', 'no'])
rows.append([str(pool_num + 5), 'dr_pool1', 'online',
'1', '0', '3573412790272', '128', '3529432325160',
'1693247906775', '26843545600', '38203734097', '47', '80',
'auto', 'inactive', '1', 'yes'])
rows.append([str(pool_num + 6), 'dr_pool2', 'online',
'1', '0', '3573412790272', '128', '3529432325160',
'1693247906775', '26843545600', '38203734097', '47', '80',
'auto', 'inactive', '2', 'yes'])
if 'obj' not in kwargs:
return self._print_info_cmd(rows=rows, **kwargs)
else:
@ -577,12 +586,16 @@ class StorwizeSVCManagementSimulator(object):
row = each_row
break
elif pool_name == 'openstack2':
row = rows[-4]
row = rows[-6]
elif pool_name == 'openstack3':
row = rows[-3]
row = rows[-5]
elif pool_name == 'hyperswap1':
row = rows[-2]
row = rows[-4]
elif pool_name == 'hyperswap2':
row = rows[-3]
elif pool_name == 'dr_pool1':
row = rows[-2]
elif pool_name == 'dr_pool2':
row = rows[-1]
else:
return self._errors['CMMVC5754E']
@ -961,7 +974,8 @@ port_speed!N/A
'primary': 'yes',
'mdisk_grp_id': str(mdiskgrp_id),
'mdisk_grp_name': mdiskgrp,
'easy_tier': volume_info['easy_tier'],
'easy_tier': (volume_info[
'easy_tier'] if 'easy_tier' in volume_info else 'on'),
'compressed_copy': volume_info['compressed_copy']}
volume_info['copies'] = {'0': vol_cp}
if is_mirror_vol:
@ -971,7 +985,8 @@ port_speed!N/A
'primary': 'no',
'mdisk_grp_id': str(sec_pool_id),
'mdisk_grp_name': sec_pool,
'easy_tier': volume_info['easy_tier'],
'easy_tier': (volume_info['easy_tier']
if 'easy_tier' in volume_info else 'on'),
'compressed_copy': volume_info['compressed_copy']}
volume_info['copies']['1'] = vol_cp1
@ -2716,7 +2731,7 @@ port_speed!N/A
site_volume_info['RC_name'] = ''
site_volume_info['RC_id'] = ''
if 'buffersize' in kwargs:
if 'thin' in kwargs or 'compressed' in kwargs:
site_volume_info['formatted'] = 'no'
# Fake numbers
site_volume_info['used_capacity'] = '786432'
@ -4816,6 +4831,15 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
vol = testutils.create_volume(self.ctxt, **prop)
return vol
def _generate_vol_info_on_dr_pool(self, vol_type=None, size=10):
pool = 'dr_pool1'
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}
@ -5853,6 +5877,24 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
'failed')
self.driver.delete_volume(volume)
# retype a volume in dr_pool
loc = ('StorwizeSVCDriver:' + self.driver._state['system_id'] +
':openstack3')
cap = {'location_info': loc, 'extent_size': '128'}
self.driver._stats = {'location_info': loc}
host = {'host': 'openstack@svc#openstack3', 'capabilities': cap}
volume = testutils.create_volume(
self.ctxt, volume_type_id=old_type.id,
host='openstack@svc#hyperswap3')
volume['host'] = host['host']
new_type = objects.VolumeType.get_by_id(ctxt,
new_type_ref['id'])
self.driver.create_volume(volume)
self.assertRaises(exception.VolumeDriverException,
self.driver.retype, ctxt, volume,
new_type, diff, host)
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'disable_vdisk_qos')
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
@ -7164,7 +7206,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
easytier_type = self._create_volume_type(spec,
'easytier_type')
vol = self._generate_vol_info(easytier_type)
self.assertRaises(exception.InvalidInput,
self.assertRaises(exception.VolumeDriverException,
self.driver.create_volume, vol)
# create hyperswap volume without peer_pool
@ -7553,6 +7595,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
# retype from hyperswap volume to replication volume
spec3 = {'replication_enabled': '<is> True',
'replication_type': '<in> metro'}
self.driver._replica_target['pool_name'] = 'openstack2'
replication_type = self._create_volume_type(spec3,
'test_replication_type')
diff, _equal = volume_types.volume_types_diff(
@ -7740,6 +7783,239 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
add_volumes_update)
self.assertEqual([], remove_volumes_update)
@ddt.data({'spec': {'rsize': -1}},
{'spec': {'mirror_pool': 'dr_pool2'}},
{'spec': {'drivers:volume_topology': 'hyperswap',
'peer_pool': 'dr_pool2'}})
@ddt.unpack
def test_storwize_volumes_on_dr_pool_success_case(self, spec):
with mock.patch.object(storwize_svc_common.StorwizeHelpers,
'get_system_info') as get_system_info:
fake_system_info = {'code_level': (7, 7, 0, 0),
'topology': 'hyperswap',
'system_name': 'storwize-svc-sim',
'system_id': '0123456789ABCDEF'}
get_system_info.return_value = fake_system_info
self.driver.do_setup(None)
dr_type = self._create_volume_type(spec, 'type_dr')
vol = testutils.create_volume(self.ctxt, volume_type_id=dr_type.id,
host='openstack@svc#hyperswap1')
self.driver.create_volume(vol)
vol2 = testutils.create_volume(self.ctxt, volume_type_id=dr_type.id,
host='openstack@svc#hyperswap1')
ref = {'source-name': vol.name}
self.driver.manage_existing(vol2, ref)
@ddt.data({'spec': {'warning': 30}},
{'spec': {'rsize': 5}},
{'spec': {'easytier': False}},
{'spec': {'autoexpand': False}},
{'spec': {'grainsize': 128}})
@ddt.unpack
def test_storwize_create_thin_volume_on_dr_pool_failure_case(self, spec):
# create basic thin volume on dr_pool
with mock.patch.object(storwize_svc_common.StorwizeHelpers,
'get_system_info') as get_system_info:
fake_system_info = {'code_level': (7, 7, 0, 0),
'topology': 'hyperswap',
'system_name': 'storwize-svc-sim',
'system_id': '0123456789ABCDEF'}
get_system_info.return_value = fake_system_info
self.driver.do_setup(None)
thin_dr_type = self._create_volume_type(spec, 'type_thin')
vol = self._generate_vol_info_on_dr_pool(thin_dr_type)
self.assertRaises(exception.VolumeDriverException,
self.driver.create_volume, vol)
# create mirror volume on dr_pool
self._set_flag('storwize_svc_mirror_pool', 'dr_pool1')
mirror_dr_type = self._create_volume_type(spec, 'type_mirror')
vol = self._generate_vol_info(mirror_dr_type)
self.assertRaises(exception.VolumeDriverException,
self.driver.create_volume, vol)
self._reset_flags()
# create hyperswap volume on dr_pool
spec.update({'drivers:volume_topology': 'hyperswap',
'peer_pool': 'dr_pool2'})
hyper_dr_type = self._create_volume_type(spec, 'hyper_dr_type')
self.assertRaises(exception.VolumeDriverException,
self._create_hyperswap_volume, hyper_dr_type)
@ddt.data({'spec': {'warning': 30}},
{'spec': {'rsize': 5}},
{'spec': {'easytier': False}},
{'spec': {'autoexpand': False}},
{'spec': {'grainsize': 128}})
@ddt.unpack
def test_storwize_manage_volume_on_dr_pool_failure_case(self, spec):
with mock.patch.object(storwize_svc_common.StorwizeHelpers,
'get_system_info') as get_system_info:
fake_system_info = {'code_level': (7, 7, 0, 0),
'topology': 'hyperswap',
'system_name': 'storwize-svc-sim',
'system_id': '0123456789ABCDEF'}
get_system_info.return_value = fake_system_info
self.driver.do_setup(None)
extra_spec = {}
thin_type = self._create_volume_type(extra_spec, 'thin_type')
vol_type1 = self._create_volume_type(spec, 'vol_type1')
thin_volume = self._generate_vol_info_on_dr_pool(thin_type)
self.driver.create_volume(thin_volume)
vol1 = self._generate_vol_info_on_dr_pool(vol_type1)
ref1 = {'source-name': thin_volume.name}
self.assertRaises(exception.ManageExistingVolumeTypeMismatch,
self.driver.manage_existing, vol1, ref1)
extra_spec = {'mirror_pool': 'dr_pool1'}
mirror_type = self._create_volume_type(extra_spec, 'type_mirror')
mirror_volume = self._generate_vol_info(mirror_type)
self.driver.create_volume(mirror_volume)
spec.update({'mirror_pool': 'dr_pool1'})
vol_type2 = self._create_volume_type(spec, 'vol_type2')
vol2 = self._generate_vol_info(vol_type2)
ref2 = {'source-name': mirror_volume.name}
self.assertRaises(exception.ManageExistingVolumeTypeMismatch,
self.driver.manage_existing, vol2, ref2)
spec.pop('mirror_pool')
extra_spec = {'drivers:volume_topology': 'hyperswap',
'peer_pool': 'dr_pool2'}
hyper_type = self._create_volume_type(extra_spec, 'type_hyper')
hyper_volume = testutils.create_volume(
self.ctxt, volume_type_id=hyper_type.id,
host='openstack@svc#hyperswap1')
self.driver.create_volume(hyper_volume)
spec.update(extra_spec)
vol_type3 = self._create_volume_type(spec, 'vol_type3')
vol3 = testutils.create_volume(
self.ctxt, volume_type_id=vol_type3.id,
host='openstack@svc#hyperswap1')
ref3 = {'source-name': hyper_volume.name}
self.assertRaises(exception.ManageExistingVolumeTypeMismatch,
self.driver.manage_existing, vol3, ref3)
def test_storwize_migrate_volume_between_regular_dr_pool(self):
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)
loc = ('StorwizeSVCDriver:' + self.driver._state['system_id'] +
':dr_pool2')
cap = {'location_info': loc, 'extent_size': '256'}
host = {'host': 'openstack@svc#dr_pool2', 'capabilities': cap}
ctxt = context.get_admin_context()
self.assertRaises(exception.VolumeDriverException,
self.driver.migrate_volume, ctxt, vol, host)
vol2 = self._generate_vol_info_on_dr_pool(mirror_vol_type)
self.driver.create_volume(vol2)
self.assertRaises(exception.VolumeDriverException,
self.driver.migrate_volume, ctxt, vol2, host)
spec = {'mirror_pool': 'dr_pool1'}
mirror_vol_type1 = self._create_volume_type(spec, 'test_mirror_type1')
vol3 = self._generate_vol_info(mirror_vol_type1)
self.driver.create_volume(vol3)
self.assertRaises(exception.VolumeDriverException,
self.driver.migrate_volume, ctxt, vol3, host)
spec.update({'rsize': -1})
thick_vol_type = self._create_volume_type(spec, 'thick_mirror_type')
vol3 = self._generate_vol_info_on_dr_pool(thick_vol_type)
self.driver.create_volume(vol3)
self.driver.migrate_volume(ctxt, vol3, host)
vol4 = self._create_volume()
self.driver.migrate_volume(ctxt, vol4, host)
spec = {'rsize': '10'}
rsize_type = self._create_volume_type(spec, 'rsize_type')
vol5 = self._generate_vol_info(rsize_type)
self.driver.create_volume(vol5)
self.assertRaises(exception.VolumeDriverException,
self.driver.migrate_volume, ctxt, vol5, host)
@ddt.data(({}, {'easytier': True, 'warning': 5, 'autoexpand': False}),
({}, {'grainsize': 128}),
({'mirror_pool': 'dr_pool2'}, {'mirror_pool': 'hyperswap1'}))
@ddt.unpack
def test_storwize_svc_retype_old_type_dr_pool(self, key_specs_old,
key_specs_new):
self.driver.do_setup(None)
loc = ('StorwizeSVCDriver:' + self.driver._state['system_id'] +
':dr_pool1')
cap = {'location_info': loc, 'extent_size': '128'}
self.driver._stats = {'location_info': loc}
host = {'host': 'openstack@svc#dr_pool1', 'capabilities': cap}
ctxt = context.get_admin_context()
old_type_ref = volume_types.create(ctxt, 'old', key_specs_old)
new_type_ref = volume_types.create(ctxt, 'new', key_specs_new)
diff, _equal = volume_types.volume_types_diff(ctxt, old_type_ref['id'],
new_type_ref['id'])
old_type = objects.VolumeType.get_by_id(ctxt,
old_type_ref['id'])
volume = self._generate_vol_info_on_dr_pool(old_type)
volume['host'] = host['host']
new_type = objects.VolumeType.get_by_id(ctxt,
new_type_ref['id'])
self.driver.create_volume(volume)
self.assertRaises(exception.VolumeDriverException,
self.driver.retype, ctxt, volume,
new_type, diff, host)
@ddt.data(({}, {'mirror_pool': 'dr_pool2', 'warning': 5}),
({'mirror_pool': 'openstack2'}, {'mirror_pool': 'dr_pool2'}),
({'mirror_pool': 'dr_pool2'}, {'mirror_pool': 'hyperswap1'}),
({'autoexpand': False}, {'drivers:volume_topology': 'hyperswap',
'peer_pool': 'dr_pool2',
'autoexpand': False}))
@ddt.unpack
def test_storwize_svc_retype_new_type_dr_pool(self, key_specs_old,
key_specs_new):
with mock.patch.object(storwize_svc_common.StorwizeHelpers,
'get_system_info') as get_system_info:
fake_system_info = {'code_level': (7, 7, 0, 0),
'topology': 'hyperswap',
'system_name': 'storwize-svc-sim',
'system_id': '0123456789ABCDEF'}
get_system_info.return_value = fake_system_info
self.driver.do_setup(None)
loc = ('StorwizeSVCDriver:' + self.driver._state['system_id'] +
':openstack')
cap = {'location_info': loc, 'extent_size': '128'}
self.driver._stats = {'location_info': loc}
host = {'host': 'openstack@svc#openstack', 'capabilities': cap}
ctxt = context.get_admin_context()
old_type_ref = volume_types.create(ctxt, 'old', key_specs_old)
new_type_ref = volume_types.create(ctxt, 'new', key_specs_new)
diff, _equal = volume_types.volume_types_diff(ctxt, old_type_ref['id'],
new_type_ref['id'])
old_type = objects.VolumeType.get_by_id(ctxt,
old_type_ref['id'])
volume = self._generate_vol_info(old_type)
volume['host'] = host['host']
new_type = objects.VolumeType.get_by_id(ctxt,
new_type_ref['id'])
self.driver.create_volume(volume)
self.assertRaises(exception.VolumeDriverException,
self.driver.retype, ctxt, volume,
new_type, diff, host)
class CLIResponseTestCase(test.TestCase):
def test_empty(self):
@ -8283,6 +8559,83 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
self._create_test_volume,
self.gmcv_with_cps86401_type)
@ddt.data(({"backend_id": "svc_aux_target_1",
"san_ip": "192.168.10.22",
"san_login": "admin",
"san_password": "admin",
"pool_name": "openstack"}, 'openstack@svc#dr_pool1'),
({"backend_id": "svc_aux_target_1",
"san_ip": "192.168.10.22",
"san_login": "admin",
"san_password": "admin",
"pool_name": "dr_pool1"}, 'openstack@svc#openstack'))
@ddt.unpack
def test_storwize_replication_volume_with_dr_pools(self, target, vol_host):
# Set replication target
self.driver.configuration.set_override('replication_device',
[target])
self.driver.do_setup(self.ctxt)
# Create metro mirror replication volume on dr_pool.
volume = testutils.create_volume(
self.ctxt, volume_type_id=self.mm_type.id,
host=vol_host)
model_update = self.driver.create_volume(volume)
self.assertEqual(fields.ReplicationStatus.ENABLED,
model_update['replication_status'])
volume1 = testutils.create_volume(
self.ctxt, volume_type_id=self.mm_type.id,
host=vol_host)
ref = {'source-name': volume.name}
self.driver.manage_existing(volume1, ref)
spec = {'replication_enabled': '<is> True',
'replication_type': '<in> metro',
'easytier': 'False'}
type_ref = volume_types.create(self.ctxt, 'type_dr', spec)
dr_type = objects.VolumeType.get_by_id(self.ctxt, type_ref['id'])
volume2 = testutils.create_volume(
self.ctxt, volume_type_id=dr_type.id,
host=vol_host)
self.assertRaises(exception.VolumeDriverException,
self.driver.create_volume, volume2)
volume3 = testutils.create_volume(
self.ctxt, volume_type_id=self.mm_type.id,
host=vol_host)
model_update = self.driver.create_volume(volume3)
ref2 = {'source-name': volume3.name}
self.assertRaises(exception.ManageExistingVolumeTypeMismatch,
self.driver.manage_existing, volume2, ref2)
volume4 = testutils.create_volume(
self.ctxt, volume_type_id=self.non_replica_type.id,
host=vol_host)
self.driver.create_volume(volume4)
# Retype to mm replica
host = {'host': vol_host}
diff, _equal = volume_types.volume_types_diff(
self.ctxt, self.non_replica_type['id'], self.mm_type['id'])
retyped, model_update = self.driver.retype(
self.ctxt, volume4, self.mm_type, diff, host)
volume4['volume_type_id'] = self.mm_type['id']
volume4['volume_type'] = self.mm_type
self.assertEqual(fields.ReplicationStatus.ENABLED,
model_update['replication_status'])
self._validate_replic_vol_creation(volume4)
volume5 = testutils.create_volume(
self.ctxt, volume_type_id=self.non_replica_type.id,
host=vol_host)
self.driver.create_volume(volume5)
# retype with check dr_pool params failure
diff, _equal = volume_types.volume_types_diff(
self.ctxt, self.non_replica_type['id'], dr_type['id'])
self.assertRaises(exception.VolumeDriverException,
self.driver.retype, self.ctxt, volume5,
dr_type, diff, host)
def _validate_replic_vol_creation(self, volume, isGMCV=False):
self._assert_vol_exists(volume['name'], True)
self._assert_vol_exists(

View File

@ -195,7 +195,7 @@ class StorwizeSVCReplicationGMCV(StorwizeSVCReplicationGlobalMirror):
self.driver._helpers.create_vdisk(source_change_vol_name,
six.text_type(vref['size']),
'gb',
src_attr['mdisk_grp_id'],
src_attr['mdisk_grp_name'],
src_change_opts)
# Create target volume if it doesn't exist
target_attr = self.target_helpers.get_vdisk_attributes(

View File

@ -78,7 +78,7 @@ storwize_svc_opts = [
cfg.IntOpt('storwize_svc_vol_grainsize',
default=256,
help='Storage system grain size parameter for volumes '
'(32/64/128/256)'),
'(8/32/64/128/256)'),
cfg.BoolOpt('storwize_svc_vol_compression',
default=False,
help='Storage system compression option for volumes'),
@ -802,6 +802,14 @@ class StorwizeHelpers(object):
attrs = self.get_pool_attrs(pool_name)
return attrs is not None
def is_data_reduction_pool(self, pool_name):
"""Check if pool is data reduction pool."""
pool_data = self.get_pool_attrs(pool_name)
if (pool_data and 'data_reduction' in pool_data and
pool_data['data_reduction'] == 'yes'):
return True
return False
def get_available_io_groups(self):
"""Return list of available IO groups."""
iogrps = []
@ -1286,7 +1294,7 @@ class StorwizeHelpers(object):
@staticmethod
def check_vdisk_opts(state, opts):
# Check that grainsize is 32/64/128/256
if opts['grainsize'] not in [32, 64, 128, 256]:
if opts['grainsize'] not in [8, 32, 64, 128, 256]:
raise exception.InvalidInput(
reason=_('Illegal value specified for '
'storwize_svc_vol_grainsize: set to either '
@ -1481,29 +1489,110 @@ class StorwizeHelpers(object):
self.check_vdisk_opts(state, opts)
return opts
def check_data_reduction_pool_params(self, opts):
"""Check the configured parameters if vol in data reduction pool."""
if opts['warning'] != 0:
msg = (_('You cannot specify -warning for thin-provisioned or '
'compressed volumes that are in data reduction '
'pools. The configured warning is '
'%s.') % opts['warning'])
raise exception.VolumeDriverException(message=msg)
if not opts['easytier']:
msg = (_('You cannot specify -easytier for thin-provisioned '
'or compressed volumes that are in data reduction '
'pools. The configured easytier is '
'%s') % opts['easytier'])
raise exception.VolumeDriverException(message=msg)
if opts['grainsize'] != 256 and opts['grainsize'] != 8:
msg = (_('You cannot specify -grainsize for thin-provisioned '
'or compressed volumes that are in data reduction '
'pools. This type of volume will be created with a '
'grainsize of 8 KB. The configured grainsize is '
'%s.') % opts['grainsize'])
raise exception.VolumeDriverException(message=msg)
if opts['rsize'] != 2:
if opts['volume_topology'] == 'hyperswap':
msg = (_('You cannot specify -buffersize for Hyperswap volumes'
' that are in data reduction pools, The configured '
'buffersize is %s.') % opts['rsize'])
raise exception.VolumeDriverException(message=msg)
else:
msg = (_('You cannot specify -rsize for thin-provisioned '
'or compressed volumes that are in data reduction '
'pools. The -rsize parameter will be ignored in '
'mkvdisk. Only its presence or absence is used to '
'determine if the disk is a data reduction volume '
'copy or a thick volume copy. The '
'configured rsize is %s.') % opts['rsize'])
raise exception.VolumeDriverException(message=msg)
if not opts['autoexpand']:
msg = (_('You cannot set the autoexpand to disable for '
'thin-provisioned or compressed volumes that are in data '
'reduction pool. The configured'
' autoexpand is %s.') % opts['autoexpand'])
raise exception.VolumeDriverException(message=msg)
else:
LOG.info('You cannot specify warning, grainsize and '
'easytier for thin-provisioned or compressed'
' volumes that are in data reduction pools. '
'The rsize parameter will be ignored, the '
'autoexpand must be enabled.')
def is_volume_type_dr_pools(self, pool, opts, rep_type=None,
rep_target_pool=None):
"""Check every configured pools is data reduction pool."""
if self.is_data_reduction_pool(pool):
LOG.debug('The configured pool %s is a data reduction pool.', pool)
return True
if opts['mirror_pool'] and self.is_data_reduction_pool(
opts['mirror_pool']):
LOG.debug('The mirror_pool %s is a data reduction pool.',
opts['mirror_pool'])
return True
if (opts['volume_topology'] == 'hyperswap' and
self.is_data_reduction_pool(opts['peer_pool'])):
LOG.debug('The peer_pool %s is a data reduction pool.',
opts['peer_pool'])
return True
if rep_type and self.is_data_reduction_pool(rep_target_pool):
LOG.debug('The replica target pool %s is a data reduction pool.',
rep_target_pool)
return True
return False
@staticmethod
def _get_vdisk_create_params(opts, add_copies=False):
def _get_vdisk_create_params(opts, is_dr_pool, add_copies=False):
easytier = 'on' if opts['easytier'] else 'off'
if opts['rsize'] == -1:
params = []
if opts['nofmtdisk']:
params.append('-nofmtdisk')
else:
params = ['-rsize', '%s%%' % str(opts['rsize']),
'-autoexpand', '-warning',
'%s%%' % str(opts['warning'])]
if not opts['autoexpand']:
params.remove('-autoexpand')
if opts['compression']:
params.append('-compressed')
if is_dr_pool:
params = ['-rsize', '%s%%' % str(opts['rsize']), '-autoexpand']
if opts['compression']:
params.append('-compressed')
else:
params.extend(['-grainsize', str(opts['grainsize'])])
params = ['-rsize', '%s%%' % str(opts['rsize']),
'-autoexpand', '-warning',
'%s%%' % str(opts['warning'])]
if not opts['autoexpand']:
params.remove('-autoexpand')
if opts['compression']:
params.append('-compressed')
else:
params.extend(['-grainsize', str(opts['grainsize'])])
if add_copies and opts['mirror_pool']:
params.extend(['-copies', '2'])
params.extend(['-easytier', easytier])
if not is_dr_pool:
params.extend(['-easytier', easytier])
return params
def create_vdisk(self, name, size, units, pool, opts):
@ -1517,19 +1606,31 @@ class StorwizeHelpers(object):
# The syntax of pool SVC expects is pool:mirror_pool in
# mdiskgrp for mirror volume
mdiskgrp = '%s:%s' % (pool, opts['mirror_pool'])
is_dr_pool = False
if opts['rsize'] != -1:
is_dr_pool = self.is_volume_type_dr_pools(pool, opts)
if is_dr_pool:
self.check_data_reduction_pool_params(opts)
params = self._get_vdisk_create_params(
opts, add_copies=True if opts['mirror_pool'] else False)
opts, is_dr_pool,
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_hyperswap_volume_create_params(self, opts):
def _get_hyperswap_volume_create_params(self, opts, is_dr_pool):
# Storwize/svc use cli command mkvolume to create hyperswap volume.
# You must specify -thin with grainsize.
# You must specify either -thin or -compressed with warning.
params = []
LOG.debug('The I/O groups of a hyperswap volume will be selected by '
'storage.')
if opts['rsize'] != -1:
if is_dr_pool:
if opts['compression']:
params.append('-compressed')
else:
params.append('-thin')
else:
params.extend(['-buffersize', '%s%%' % str(opts['rsize']),
'-warning',
'%s%%' % six.text_type(opts['warning'])])
@ -1544,16 +1645,23 @@ class StorwizeHelpers(object):
def create_hyperswap_volume(self, vol_name, size, units, pool, opts):
vol_name = '"%s"' % vol_name
params = self._get_hyperswap_volume_create_params(opts)
self.ssh.mkvolume(vol_name, six.text_type(size), units, pool, params)
params = []
if opts['rsize'] != -1:
is_dr_pool = self.is_volume_type_dr_pools(pool, opts)
if is_dr_pool:
self.check_data_reduction_pool_params(opts)
params = self._get_hyperswap_volume_create_params(opts, is_dr_pool)
hyperpool = '%s:%s' % (pool, opts['peer_pool'])
self.ssh.mkvolume(vol_name, six.text_type(size), units,
hyperpool, params)
def convert_volume_to_hyperswap(self, vol_name, opts, state):
vol_name = '%s' % vol_name
if not self.is_system_topology_hyperswap(state):
reason = _('Convert volume to hyperswap failed, the system is '
'below release 7.6.0.0 or it is not hyperswap '
'topology.')
raise exception.VolumeDriverException(reason=reason)
msg = _('Convert volume to hyperswap failed, the system is '
'below release 7.6.0.0 or it is not hyperswap '
'topology.')
raise exception.VolumeDriverException(message=msg)
else:
attr = self.get_vdisk_attributes(vol_name)
if attr is None:
@ -1564,7 +1672,10 @@ class StorwizeHelpers(object):
pool = attr['mdisk_grp_name']
self.check_hyperswap_pool(pool, opts['peer_pool'])
hyper_pool = '%s' % opts['peer_pool']
params = self._get_hyperswap_volume_create_params(opts)
is_dr_pool = self.is_volume_type_dr_pools(pool, opts)
if is_dr_pool and opts['rsize'] != -1:
self.check_data_reduction_pool_params(opts)
params = self._get_hyperswap_volume_create_params(opts, is_dr_pool)
self.ssh.addvolumecopy(vol_name, hyper_pool, params)
def convert_hyperswap_volume_to_normal(self, vol_name, peer_pool):
@ -2213,7 +2324,10 @@ class StorwizeHelpers(object):
else:
opts = self.get_vdisk_params(config, state, volume_type['id'],
volume_type=volume_type)
params = self._get_vdisk_create_params(opts)
is_dr_pool = self.is_data_reduction_pool(dest_pool)
if is_dr_pool and opts['rsize'] != -1:
self.check_data_reduction_pool_params(opts)
params = self._get_vdisk_create_params(opts, is_dr_pool)
try:
new_copy_id = self.ssh.addvdiskcopy(vdisk, dest_pool, params,
auto_delete)
@ -2904,14 +3018,12 @@ class StorwizeSVCCommonDriver(san.SanDriver,
'replication enabled is not supported.')
raise exception.InvalidInput(reason=reason)
if not opts['easytier']:
raise exception.InvalidInput(
reason=_('The default easytier of hyperswap volume is '
'on, it does not support easytier off.'))
msg = _('The default easytier of hyperswap volume is '
'on, it does not support easytier off.')
raise exception.VolumeDriverException(message=msg)
self._helpers.check_hyperswap_pool(pool, opts['peer_pool'])
hyperpool = '%s:%s' % (pool, opts['peer_pool'])
self._helpers.create_hyperswap_volume(volume.name,
volume.size, 'gb',
hyperpool, opts)
self._helpers.create_hyperswap_volume(volume.name, volume.size,
'gb', pool, opts)
else:
if opts['mirror_pool'] and rep_type:
reason = _('Create mirror volume with replication enabled is '
@ -4293,6 +4405,21 @@ class StorwizeSVCCommonDriver(san.SanDriver,
resp = self._helpers.lsvdiskcopy(volume.name)
if len(resp) > 1:
copies = self._helpers.get_vdisk_copies(volume.name)
src_pool = copies['primary']['mdisk_grp_name']
mirror_pool = copies['secondary']['mdisk_grp_name']
opts = self._get_vdisk_params(volume.volume_type_id)
if opts['rsize'] != -1:
if (self._helpers.is_data_reduction_pool(src_pool) or
self._helpers.is_data_reduction_pool(mirror_pool)):
msg = _('Unable to migrate: the thin-provisioned or '
'compressed volume can not be migrated from a data'
' reduction pool. ')
raise exception.VolumeDriverException(message=msg)
elif self._helpers.is_data_reduction_pool(dest_pool):
msg = _('Unable to migrate: the thin-provisioned or '
'compressed volume can not be migrated to a data '
'reduction pool.')
raise exception.VolumeDriverException(message=msg)
self._helpers.migratevdisk(volume.name, dest_pool,
copies['primary']['copy_id'])
else:
@ -4309,8 +4436,17 @@ class StorwizeSVCCommonDriver(san.SanDriver,
{'id': volume.id, 'host': host['host']})
return (True, None)
def _verify_iogrp(self, rsize, pool, opts, rep_type, status):
if rsize != -1 and self._helpers.is_volume_type_dr_pools(
pool, opts, rep_type, rep_target_pool=self._replica_target[
'pool_name'] if rep_type else None):
msg = _('Unable to retype: the thin-provisioned or compressed '
'vol in data reduction pool can not modify iogrp.')
raise exception.VolumeDriverException(message=msg)
def _verify_retype_params(self, volume, new_opts, old_opts, need_copy,
change_mirror, new_rep_type, old_rep_type):
change_mirror, new_rep_type, old_rep_type,
vdisk_changes, old_pool, new_pool):
# Some volume parameters can not be changed or changed at the same
# time during volume retype operation. This function checks the
# retype parameters.
@ -4320,6 +4456,16 @@ class StorwizeSVCCommonDriver(san.SanDriver,
'has only one copy in storage.') % volume.name)
raise exception.VolumeDriverException(message=msg)
is_old_type_dr_pool = self._helpers.is_volume_type_dr_pools(
old_pool, old_opts, old_rep_type,
rep_target_pool=self._replica_target[
'pool_name'] if old_rep_type else None)
is_new_type_dr_pool = self._helpers.is_volume_type_dr_pools(
new_pool, new_opts, new_rep_type,
rep_target_pool=self._replica_target[
'pool_name'] if new_rep_type else None)
need_check_dr_pool_param = False
if need_copy:
# mirror volume can not add volume-copy again.
if len(resp) > 1:
@ -4332,6 +4478,7 @@ class StorwizeSVCCommonDriver(san.SanDriver,
'it is not allowed for mirror volume '
'%s.') % volume.name)
raise exception.VolumeDriverException(message=msg)
need_check_dr_pool_param = True
if change_mirror:
if (new_opts['mirror_pool'] and
@ -4340,6 +4487,16 @@ class StorwizeSVCCommonDriver(san.SanDriver,
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)
# migrate second copy to a dr pool or from a dr pool is not allowed
if (old_opts['mirror_pool'] and new_opts[
'mirror_pool'] and old_opts['rsize'] != -1):
if is_old_type_dr_pool or is_new_type_dr_pool:
msg = _('Unable to retype: the thin-provisioned or '
'compressed vol can not be migrated from a dr pool'
' or to a dr pool.')
raise exception.VolumeDriverException(message=msg)
if not old_opts['mirror_pool'] and new_opts['mirror_pool']:
need_check_dr_pool_param = True
# There are four options for rep_type: None, metro, global, gmcv
if new_rep_type or old_rep_type:
@ -4367,6 +4524,15 @@ class StorwizeSVCCommonDriver(san.SanDriver,
'new_rep_type': new_rep_type})
LOG.error(msg)
raise exception.VolumeDriverException(message=msg)
if not old_rep_type and new_rep_type:
if new_opts['rsize'] != -1 and is_new_type_dr_pool:
try:
self._helpers.check_data_reduction_pool_params(
new_opts)
except Exception as err:
msg = (_("Failed to retype volume, the error is "
"%s") % err)
raise exception.VolumeDriverException(message=msg)
elif storwize_const.GMCV == new_rep_type:
# To gmcv, we may change cycle_period_seconds if needed
previous_cps = old_opts.get('cycle_period_seconds')
@ -4375,6 +4541,22 @@ class StorwizeSVCCommonDriver(san.SanDriver,
self._helpers.change_relationship_cycleperiod(volume.name,
new_cps)
if (is_new_type_dr_pool and new_opts[
'rsize'] != -1 and need_check_dr_pool_param == 1):
try:
self._helpers.check_data_reduction_pool_params(new_opts)
except Exception as err:
msg = (_("Failed to retype volume, the error is "
"%s") % err)
raise exception.VolumeDriverException(message=msg)
if vdisk_changes and not need_copy:
if is_old_type_dr_pool or is_new_type_dr_pool:
msg = _('The volume specified is a thin or compressed volume '
'in a data reduction pool. The autoexpand and warning'
' and easytier can not be changed.')
raise exception.VolumeDriverException(message=msg)
def _check_hyperswap_retype_params(self, volume, new_opts, old_opts,
change_mirror, new_rep_type,
old_rep_type, old_pool,
@ -4413,13 +4595,23 @@ class StorwizeSVCCommonDriver(san.SanDriver,
raise exception.InvalidInput(
reason=_('The default easytier of hyperswap volume is '
'on, it does not support easytier off.'))
if (old_opts['volume_topology'] != 'hyperswap' and
self._helpers._get_vdisk_fc_mappings(volume.name)):
msg = _('Unable to retype: it is not allowed to change a '
'normal volume with snapshot to a hyperswap '
'volume.')
LOG.error(msg)
raise exception.InvalidInput(message=msg)
if old_opts['volume_topology'] != 'hyperswap':
is_new_type_dr_pool = self._helpers.is_volume_type_dr_pools(
new_pool, new_opts)
if is_new_type_dr_pool and new_opts['rsize'] != -1:
try:
self._helpers.check_data_reduction_pool_params(
new_opts)
except Exception as err:
msg = (_("Failed to retype volume, the error is "
"%s") % err)
raise exception.VolumeDriverException(reason=msg)
if self._helpers._get_vdisk_fc_mappings(volume.name):
msg = _('Unable to retype: it is not allowed to change a '
'normal volume with snapshot to a hyperswap '
'volume.')
LOG.error(msg)
raise exception.InvalidInput(message=msg)
if (old_opts['volume_topology'] == 'hyperswap' and
old_opts['peer_pool'] != new_opts['peer_pool']):
msg = _('Unable to retype: it is not allowed to change a '
@ -4529,7 +4721,8 @@ class StorwizeSVCCommonDriver(san.SanDriver,
new_opts, new_pool)
self._verify_retype_params(volume, new_opts, old_opts, need_copy,
change_mirror, new_rep_type, old_rep_type)
change_mirror, new_rep_type, old_rep_type,
vdisk_changes, old_pool, new_pool)
if old_opts['volume_topology'] or new_opts['volume_topology']:
self._check_hyperswap_retype_params(volume, new_opts, old_opts,
@ -4540,6 +4733,11 @@ class StorwizeSVCCommonDriver(san.SanDriver,
old_pool, new_pool, vdisk_changes,
need_copy, new_type)
else:
# hyperswap volume will select iogrp by storage. ignore iogrp here.
if old_io_grp != new_io_grp:
self._verify_iogrp(old_opts['rsize'], old_pool, old_opts,
old_rep_type,
volume.previous_status)
if need_copy:
self._check_volume_copy_ops()
dest_pool = self._helpers.can_migrate_to_host(host,
@ -4732,6 +4930,17 @@ class StorwizeSVCCommonDriver(san.SanDriver,
'type_cps': rep_cps})
raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
pool = utils.extract_host(volume['host'], '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': copies['primary']['mdisk_grp_name'],
'backend_pool': pool})
raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
if volume['volume_type_id']:
opts = self._get_vdisk_params(volume['volume_type_id'],
volume_metadata=
@ -4822,17 +5031,17 @@ class StorwizeSVCCommonDriver(san.SanDriver,
{'vdisk_iogrp': vdisk['IO_group_name'],
'opt_iogrp': opts['iogrp']})
raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
pool = utils.extract_host(volume['host'], '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': copies['primary']['mdisk_grp_name'],
'backend_pool': pool})
raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
if opts['rsize'] != -1 and self._helpers.is_volume_type_dr_pools(
pool, opts, rep_type, rep_target_pool=self._replica_target[
'pool_name'] if rep_type else None):
try:
self._helpers.check_data_reduction_pool_params(opts)
except Exception as err:
msg = (_("Failed to manage existing volume, the error is "
"%s") % err)
raise exception.ManageExistingVolumeTypeMismatch(
reason=msg)
model_update = {'replication_status':
fields.ReplicationStatus.NOT_CAPABLE}
self._helpers.rename_vdisk(vdisk['name'], volume['name'])

View File

@ -0,0 +1,5 @@
---
features:
- |
Added data reduction pool support for thin-provisoned and compressed
volume in Storwize cinder driver.