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:
parent
4b96310411
commit
822fb701de
@ -538,7 +538,8 @@ class StorwizeSVCManagementSimulator(object):
|
|||||||
'vdisk_count', 'capacity', 'extent_size',
|
'vdisk_count', 'capacity', 'extent_size',
|
||||||
'free_capacity', 'virtual_capacity', 'used_capacity',
|
'free_capacity', 'virtual_capacity', 'used_capacity',
|
||||||
'real_capacity', 'overallocation', 'warning',
|
'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):
|
for i in range(pool_num):
|
||||||
row_data = [str(i + 1),
|
row_data = [str(i + 1),
|
||||||
self._flags['storwize_svc_volpool_name'][i], 'online',
|
self._flags['storwize_svc_volpool_name'][i], 'online',
|
||||||
@ -546,24 +547,32 @@ class StorwizeSVCManagementSimulator(object):
|
|||||||
'3573412790272', '256', '3529926246400',
|
'3573412790272', '256', '3529926246400',
|
||||||
'1693247906775',
|
'1693247906775',
|
||||||
'26843545600', '38203734097', '47', '80', 'auto',
|
'26843545600', '38203734097', '47', '80', 'auto',
|
||||||
'inactive', '']
|
'inactive', '', 'no']
|
||||||
rows.append(row_data)
|
rows.append(row_data)
|
||||||
rows.append([str(pool_num + 1), 'openstack2', 'online',
|
rows.append([str(pool_num + 1), 'openstack2', 'online',
|
||||||
'1', '0', '3573412790272', '256',
|
'1', '0', '3573412790272', '256',
|
||||||
'3529432325160', '1693247906775', '26843545600',
|
'3529432325160', '1693247906775', '26843545600',
|
||||||
'38203734097', '47', '80', 'auto', 'inactive', ''])
|
'38203734097', '47', '80', 'auto', 'inactive', '', 'no'])
|
||||||
rows.append([str(pool_num + 2), 'openstack3', 'offline',
|
rows.append([str(pool_num + 2), 'openstack3', 'offline',
|
||||||
'1', '0', '3573412790272', '128',
|
'1', '0', '3573412790272', '128',
|
||||||
'3529432325160', '1693247906775', '26843545600',
|
'3529432325160', '1693247906775', '26843545600',
|
||||||
'38203734097', '47', '80', 'auto', 'inactive', ''])
|
'38203734097', '47', '80', 'auto', 'inactive', '', 'yes'])
|
||||||
rows.append([str(pool_num + 3), 'hyperswap1', 'online',
|
rows.append([str(pool_num + 3), 'hyperswap1', 'online',
|
||||||
'1', '0', '3573412790272', '256',
|
'1', '0', '3573412790272', '256',
|
||||||
'3529432325160', '1693247906775', '26843545600',
|
'3529432325160', '1693247906775', '26843545600',
|
||||||
'38203734097', '47', '80', 'auto', 'inactive', '1'])
|
'38203734097', '47', '80', 'auto', 'inactive', '1', 'no'])
|
||||||
rows.append([str(pool_num + 4), 'hyperswap2', 'online',
|
rows.append([str(pool_num + 4), 'hyperswap2', 'online',
|
||||||
'1', '0', '3573412790272', '128',
|
'1', '0', '3573412790272', '128',
|
||||||
'3529432325160', '1693247906775', '26843545600',
|
'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:
|
if 'obj' not in kwargs:
|
||||||
return self._print_info_cmd(rows=rows, **kwargs)
|
return self._print_info_cmd(rows=rows, **kwargs)
|
||||||
else:
|
else:
|
||||||
@ -577,12 +586,16 @@ class StorwizeSVCManagementSimulator(object):
|
|||||||
row = each_row
|
row = each_row
|
||||||
break
|
break
|
||||||
elif pool_name == 'openstack2':
|
elif pool_name == 'openstack2':
|
||||||
row = rows[-4]
|
row = rows[-6]
|
||||||
elif pool_name == 'openstack3':
|
elif pool_name == 'openstack3':
|
||||||
row = rows[-3]
|
row = rows[-5]
|
||||||
elif pool_name == 'hyperswap1':
|
elif pool_name == 'hyperswap1':
|
||||||
row = rows[-2]
|
row = rows[-4]
|
||||||
elif pool_name == 'hyperswap2':
|
elif pool_name == 'hyperswap2':
|
||||||
|
row = rows[-3]
|
||||||
|
elif pool_name == 'dr_pool1':
|
||||||
|
row = rows[-2]
|
||||||
|
elif pool_name == 'dr_pool2':
|
||||||
row = rows[-1]
|
row = rows[-1]
|
||||||
else:
|
else:
|
||||||
return self._errors['CMMVC5754E']
|
return self._errors['CMMVC5754E']
|
||||||
@ -961,7 +974,8 @@ port_speed!N/A
|
|||||||
'primary': 'yes',
|
'primary': 'yes',
|
||||||
'mdisk_grp_id': str(mdiskgrp_id),
|
'mdisk_grp_id': str(mdiskgrp_id),
|
||||||
'mdisk_grp_name': mdiskgrp,
|
'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']}
|
'compressed_copy': volume_info['compressed_copy']}
|
||||||
volume_info['copies'] = {'0': vol_cp}
|
volume_info['copies'] = {'0': vol_cp}
|
||||||
if is_mirror_vol:
|
if is_mirror_vol:
|
||||||
@ -971,7 +985,8 @@ port_speed!N/A
|
|||||||
'primary': 'no',
|
'primary': 'no',
|
||||||
'mdisk_grp_id': str(sec_pool_id),
|
'mdisk_grp_id': str(sec_pool_id),
|
||||||
'mdisk_grp_name': sec_pool,
|
'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']}
|
'compressed_copy': volume_info['compressed_copy']}
|
||||||
volume_info['copies']['1'] = vol_cp1
|
volume_info['copies']['1'] = vol_cp1
|
||||||
|
|
||||||
@ -2716,7 +2731,7 @@ port_speed!N/A
|
|||||||
site_volume_info['RC_name'] = ''
|
site_volume_info['RC_name'] = ''
|
||||||
site_volume_info['RC_id'] = ''
|
site_volume_info['RC_id'] = ''
|
||||||
|
|
||||||
if 'buffersize' in kwargs:
|
if 'thin' in kwargs or 'compressed' in kwargs:
|
||||||
site_volume_info['formatted'] = 'no'
|
site_volume_info['formatted'] = 'no'
|
||||||
# Fake numbers
|
# Fake numbers
|
||||||
site_volume_info['used_capacity'] = '786432'
|
site_volume_info['used_capacity'] = '786432'
|
||||||
@ -4816,6 +4831,15 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
vol = testutils.create_volume(self.ctxt, **prop)
|
vol = testutils.create_volume(self.ctxt, **prop)
|
||||||
return vol
|
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):
|
def _generate_snap_info(self, vol_id, size=10):
|
||||||
prop = {'volume_id': vol_id,
|
prop = {'volume_id': vol_id,
|
||||||
'volume_size': size}
|
'volume_size': size}
|
||||||
@ -5853,6 +5877,24 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
'failed')
|
'failed')
|
||||||
self.driver.delete_volume(volume)
|
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,
|
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
|
||||||
'disable_vdisk_qos')
|
'disable_vdisk_qos')
|
||||||
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
|
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
|
||||||
@ -7164,7 +7206,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
easytier_type = self._create_volume_type(spec,
|
easytier_type = self._create_volume_type(spec,
|
||||||
'easytier_type')
|
'easytier_type')
|
||||||
vol = self._generate_vol_info(easytier_type)
|
vol = self._generate_vol_info(easytier_type)
|
||||||
self.assertRaises(exception.InvalidInput,
|
self.assertRaises(exception.VolumeDriverException,
|
||||||
self.driver.create_volume, vol)
|
self.driver.create_volume, vol)
|
||||||
|
|
||||||
# create hyperswap volume without peer_pool
|
# create hyperswap volume without peer_pool
|
||||||
@ -7553,6 +7595,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
# retype from hyperswap volume to replication volume
|
# retype from hyperswap volume to replication volume
|
||||||
spec3 = {'replication_enabled': '<is> True',
|
spec3 = {'replication_enabled': '<is> True',
|
||||||
'replication_type': '<in> metro'}
|
'replication_type': '<in> metro'}
|
||||||
|
self.driver._replica_target['pool_name'] = 'openstack2'
|
||||||
replication_type = self._create_volume_type(spec3,
|
replication_type = self._create_volume_type(spec3,
|
||||||
'test_replication_type')
|
'test_replication_type')
|
||||||
diff, _equal = volume_types.volume_types_diff(
|
diff, _equal = volume_types.volume_types_diff(
|
||||||
@ -7740,6 +7783,239 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
add_volumes_update)
|
add_volumes_update)
|
||||||
self.assertEqual([], remove_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):
|
class CLIResponseTestCase(test.TestCase):
|
||||||
def test_empty(self):
|
def test_empty(self):
|
||||||
@ -8283,6 +8559,83 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
|
|||||||
self._create_test_volume,
|
self._create_test_volume,
|
||||||
self.gmcv_with_cps86401_type)
|
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):
|
def _validate_replic_vol_creation(self, volume, isGMCV=False):
|
||||||
self._assert_vol_exists(volume['name'], True)
|
self._assert_vol_exists(volume['name'], True)
|
||||||
self._assert_vol_exists(
|
self._assert_vol_exists(
|
||||||
|
@ -195,7 +195,7 @@ class StorwizeSVCReplicationGMCV(StorwizeSVCReplicationGlobalMirror):
|
|||||||
self.driver._helpers.create_vdisk(source_change_vol_name,
|
self.driver._helpers.create_vdisk(source_change_vol_name,
|
||||||
six.text_type(vref['size']),
|
six.text_type(vref['size']),
|
||||||
'gb',
|
'gb',
|
||||||
src_attr['mdisk_grp_id'],
|
src_attr['mdisk_grp_name'],
|
||||||
src_change_opts)
|
src_change_opts)
|
||||||
# Create target volume if it doesn't exist
|
# Create target volume if it doesn't exist
|
||||||
target_attr = self.target_helpers.get_vdisk_attributes(
|
target_attr = self.target_helpers.get_vdisk_attributes(
|
||||||
|
@ -78,7 +78,7 @@ storwize_svc_opts = [
|
|||||||
cfg.IntOpt('storwize_svc_vol_grainsize',
|
cfg.IntOpt('storwize_svc_vol_grainsize',
|
||||||
default=256,
|
default=256,
|
||||||
help='Storage system grain size parameter for volumes '
|
help='Storage system grain size parameter for volumes '
|
||||||
'(32/64/128/256)'),
|
'(8/32/64/128/256)'),
|
||||||
cfg.BoolOpt('storwize_svc_vol_compression',
|
cfg.BoolOpt('storwize_svc_vol_compression',
|
||||||
default=False,
|
default=False,
|
||||||
help='Storage system compression option for volumes'),
|
help='Storage system compression option for volumes'),
|
||||||
@ -802,6 +802,14 @@ class StorwizeHelpers(object):
|
|||||||
attrs = self.get_pool_attrs(pool_name)
|
attrs = self.get_pool_attrs(pool_name)
|
||||||
return attrs is not None
|
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):
|
def get_available_io_groups(self):
|
||||||
"""Return list of available IO groups."""
|
"""Return list of available IO groups."""
|
||||||
iogrps = []
|
iogrps = []
|
||||||
@ -1286,7 +1294,7 @@ class StorwizeHelpers(object):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def check_vdisk_opts(state, opts):
|
def check_vdisk_opts(state, opts):
|
||||||
# Check that grainsize is 32/64/128/256
|
# 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(
|
raise exception.InvalidInput(
|
||||||
reason=_('Illegal value specified for '
|
reason=_('Illegal value specified for '
|
||||||
'storwize_svc_vol_grainsize: set to either '
|
'storwize_svc_vol_grainsize: set to either '
|
||||||
@ -1481,29 +1489,110 @@ class StorwizeHelpers(object):
|
|||||||
self.check_vdisk_opts(state, opts)
|
self.check_vdisk_opts(state, opts)
|
||||||
return 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
|
@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'
|
easytier = 'on' if opts['easytier'] else 'off'
|
||||||
if opts['rsize'] == -1:
|
if opts['rsize'] == -1:
|
||||||
params = []
|
params = []
|
||||||
if opts['nofmtdisk']:
|
if opts['nofmtdisk']:
|
||||||
params.append('-nofmtdisk')
|
params.append('-nofmtdisk')
|
||||||
else:
|
else:
|
||||||
params = ['-rsize', '%s%%' % str(opts['rsize']),
|
if is_dr_pool:
|
||||||
'-autoexpand', '-warning',
|
params = ['-rsize', '%s%%' % str(opts['rsize']), '-autoexpand']
|
||||||
'%s%%' % str(opts['warning'])]
|
if opts['compression']:
|
||||||
if not opts['autoexpand']:
|
params.append('-compressed')
|
||||||
params.remove('-autoexpand')
|
|
||||||
|
|
||||||
if opts['compression']:
|
|
||||||
params.append('-compressed')
|
|
||||||
else:
|
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']:
|
if add_copies and opts['mirror_pool']:
|
||||||
params.extend(['-copies', '2'])
|
params.extend(['-copies', '2'])
|
||||||
|
|
||||||
params.extend(['-easytier', easytier])
|
if not is_dr_pool:
|
||||||
|
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):
|
||||||
@ -1517,19 +1606,31 @@ class StorwizeHelpers(object):
|
|||||||
# The syntax of pool SVC expects is pool:mirror_pool in
|
# The syntax of pool SVC expects is pool:mirror_pool in
|
||||||
# mdiskgrp for mirror volume
|
# mdiskgrp for mirror volume
|
||||||
mdiskgrp = '%s:%s' % (pool, opts['mirror_pool'])
|
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(
|
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)
|
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_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.
|
# Storwize/svc use cli command mkvolume to create hyperswap volume.
|
||||||
# You must specify -thin with grainsize.
|
# You must specify -thin with grainsize.
|
||||||
# You must specify either -thin or -compressed with warning.
|
# You must specify either -thin or -compressed with warning.
|
||||||
params = []
|
params = []
|
||||||
LOG.debug('The I/O groups of a hyperswap volume will be selected by '
|
LOG.debug('The I/O groups of a hyperswap volume will be selected by '
|
||||||
'storage.')
|
'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']),
|
params.extend(['-buffersize', '%s%%' % str(opts['rsize']),
|
||||||
'-warning',
|
'-warning',
|
||||||
'%s%%' % six.text_type(opts['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):
|
def create_hyperswap_volume(self, vol_name, size, units, pool, opts):
|
||||||
vol_name = '"%s"' % vol_name
|
vol_name = '"%s"' % vol_name
|
||||||
params = self._get_hyperswap_volume_create_params(opts)
|
params = []
|
||||||
self.ssh.mkvolume(vol_name, six.text_type(size), units, pool, 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):
|
def convert_volume_to_hyperswap(self, vol_name, opts, state):
|
||||||
vol_name = '%s' % vol_name
|
vol_name = '%s' % vol_name
|
||||||
if not self.is_system_topology_hyperswap(state):
|
if not self.is_system_topology_hyperswap(state):
|
||||||
reason = _('Convert volume to hyperswap failed, the system is '
|
msg = _('Convert volume to hyperswap failed, the system is '
|
||||||
'below release 7.6.0.0 or it is not hyperswap '
|
'below release 7.6.0.0 or it is not hyperswap '
|
||||||
'topology.')
|
'topology.')
|
||||||
raise exception.VolumeDriverException(reason=reason)
|
raise exception.VolumeDriverException(message=msg)
|
||||||
else:
|
else:
|
||||||
attr = self.get_vdisk_attributes(vol_name)
|
attr = self.get_vdisk_attributes(vol_name)
|
||||||
if attr is None:
|
if attr is None:
|
||||||
@ -1564,7 +1672,10 @@ class StorwizeHelpers(object):
|
|||||||
pool = attr['mdisk_grp_name']
|
pool = attr['mdisk_grp_name']
|
||||||
self.check_hyperswap_pool(pool, opts['peer_pool'])
|
self.check_hyperswap_pool(pool, opts['peer_pool'])
|
||||||
hyper_pool = '%s' % 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)
|
self.ssh.addvolumecopy(vol_name, hyper_pool, params)
|
||||||
|
|
||||||
def convert_hyperswap_volume_to_normal(self, vol_name, peer_pool):
|
def convert_hyperswap_volume_to_normal(self, vol_name, peer_pool):
|
||||||
@ -2213,7 +2324,10 @@ class StorwizeHelpers(object):
|
|||||||
else:
|
else:
|
||||||
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)
|
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:
|
try:
|
||||||
new_copy_id = self.ssh.addvdiskcopy(vdisk, dest_pool, params,
|
new_copy_id = self.ssh.addvdiskcopy(vdisk, dest_pool, params,
|
||||||
auto_delete)
|
auto_delete)
|
||||||
@ -2904,14 +3018,12 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
'replication enabled is not supported.')
|
'replication enabled is not supported.')
|
||||||
raise exception.InvalidInput(reason=reason)
|
raise exception.InvalidInput(reason=reason)
|
||||||
if not opts['easytier']:
|
if not opts['easytier']:
|
||||||
raise exception.InvalidInput(
|
msg = _('The default easytier of hyperswap volume is '
|
||||||
reason=_('The default easytier of hyperswap volume is '
|
'on, it does not support easytier off.')
|
||||||
'on, it does not support easytier off.'))
|
raise exception.VolumeDriverException(message=msg)
|
||||||
self._helpers.check_hyperswap_pool(pool, opts['peer_pool'])
|
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,
|
||||||
self._helpers.create_hyperswap_volume(volume.name,
|
'gb', pool, opts)
|
||||||
volume.size, 'gb',
|
|
||||||
hyperpool, opts)
|
|
||||||
else:
|
else:
|
||||||
if opts['mirror_pool'] and rep_type:
|
if opts['mirror_pool'] and rep_type:
|
||||||
reason = _('Create mirror volume with replication enabled is '
|
reason = _('Create mirror volume with replication enabled is '
|
||||||
@ -4293,6 +4405,21 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
resp = self._helpers.lsvdiskcopy(volume.name)
|
resp = self._helpers.lsvdiskcopy(volume.name)
|
||||||
if len(resp) > 1:
|
if len(resp) > 1:
|
||||||
copies = self._helpers.get_vdisk_copies(volume.name)
|
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,
|
self._helpers.migratevdisk(volume.name, dest_pool,
|
||||||
copies['primary']['copy_id'])
|
copies['primary']['copy_id'])
|
||||||
else:
|
else:
|
||||||
@ -4309,8 +4436,17 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
{'id': volume.id, 'host': host['host']})
|
{'id': volume.id, 'host': host['host']})
|
||||||
return (True, None)
|
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,
|
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
|
# Some volume parameters can not be changed or changed at the same
|
||||||
# time during volume retype operation. This function checks the
|
# time during volume retype operation. This function checks the
|
||||||
# retype parameters.
|
# retype parameters.
|
||||||
@ -4320,6 +4456,16 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
'has only one copy in storage.') % volume.name)
|
'has only one copy in storage.') % volume.name)
|
||||||
raise exception.VolumeDriverException(message=msg)
|
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:
|
if need_copy:
|
||||||
# mirror volume can not add volume-copy again.
|
# mirror volume can not add volume-copy again.
|
||||||
if len(resp) > 1:
|
if len(resp) > 1:
|
||||||
@ -4332,6 +4478,7 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
'it is not allowed for mirror volume '
|
'it is not allowed for mirror volume '
|
||||||
'%s.') % volume.name)
|
'%s.') % volume.name)
|
||||||
raise exception.VolumeDriverException(message=msg)
|
raise exception.VolumeDriverException(message=msg)
|
||||||
|
need_check_dr_pool_param = True
|
||||||
|
|
||||||
if change_mirror:
|
if change_mirror:
|
||||||
if (new_opts['mirror_pool'] and
|
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 '
|
msg = (_('Unable to retype: The pool %s in which mirror copy '
|
||||||
'is stored is not valid') % new_opts['mirror_pool'])
|
'is stored is not valid') % new_opts['mirror_pool'])
|
||||||
raise exception.VolumeDriverException(message=msg)
|
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
|
# There are four options for rep_type: None, metro, global, gmcv
|
||||||
if new_rep_type or old_rep_type:
|
if new_rep_type or old_rep_type:
|
||||||
@ -4367,6 +4524,15 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
'new_rep_type': new_rep_type})
|
'new_rep_type': new_rep_type})
|
||||||
LOG.error(msg)
|
LOG.error(msg)
|
||||||
raise exception.VolumeDriverException(message=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:
|
elif storwize_const.GMCV == new_rep_type:
|
||||||
# To gmcv, we may change cycle_period_seconds if needed
|
# To gmcv, we may change cycle_period_seconds if needed
|
||||||
previous_cps = old_opts.get('cycle_period_seconds')
|
previous_cps = old_opts.get('cycle_period_seconds')
|
||||||
@ -4375,6 +4541,22 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
self._helpers.change_relationship_cycleperiod(volume.name,
|
self._helpers.change_relationship_cycleperiod(volume.name,
|
||||||
new_cps)
|
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,
|
def _check_hyperswap_retype_params(self, volume, new_opts, old_opts,
|
||||||
change_mirror, new_rep_type,
|
change_mirror, new_rep_type,
|
||||||
old_rep_type, old_pool,
|
old_rep_type, old_pool,
|
||||||
@ -4413,13 +4595,23 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
raise exception.InvalidInput(
|
raise exception.InvalidInput(
|
||||||
reason=_('The default easytier of hyperswap volume is '
|
reason=_('The default easytier of hyperswap volume is '
|
||||||
'on, it does not support easytier off.'))
|
'on, it does not support easytier off.'))
|
||||||
if (old_opts['volume_topology'] != 'hyperswap' and
|
if old_opts['volume_topology'] != 'hyperswap':
|
||||||
self._helpers._get_vdisk_fc_mappings(volume.name)):
|
is_new_type_dr_pool = self._helpers.is_volume_type_dr_pools(
|
||||||
msg = _('Unable to retype: it is not allowed to change a '
|
new_pool, new_opts)
|
||||||
'normal volume with snapshot to a hyperswap '
|
if is_new_type_dr_pool and new_opts['rsize'] != -1:
|
||||||
'volume.')
|
try:
|
||||||
LOG.error(msg)
|
self._helpers.check_data_reduction_pool_params(
|
||||||
raise exception.InvalidInput(message=msg)
|
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
|
if (old_opts['volume_topology'] == 'hyperswap' and
|
||||||
old_opts['peer_pool'] != new_opts['peer_pool']):
|
old_opts['peer_pool'] != new_opts['peer_pool']):
|
||||||
msg = _('Unable to retype: it is not allowed to change a '
|
msg = _('Unable to retype: it is not allowed to change a '
|
||||||
@ -4529,7 +4721,8 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
new_opts, new_pool)
|
new_opts, new_pool)
|
||||||
|
|
||||||
self._verify_retype_params(volume, new_opts, old_opts, need_copy,
|
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']:
|
if old_opts['volume_topology'] or new_opts['volume_topology']:
|
||||||
self._check_hyperswap_retype_params(volume, new_opts, old_opts,
|
self._check_hyperswap_retype_params(volume, new_opts, old_opts,
|
||||||
@ -4540,6 +4733,11 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
old_pool, new_pool, vdisk_changes,
|
old_pool, new_pool, vdisk_changes,
|
||||||
need_copy, new_type)
|
need_copy, new_type)
|
||||||
else:
|
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:
|
if need_copy:
|
||||||
self._check_volume_copy_ops()
|
self._check_volume_copy_ops()
|
||||||
dest_pool = self._helpers.can_migrate_to_host(host,
|
dest_pool = self._helpers.can_migrate_to_host(host,
|
||||||
@ -4732,6 +4930,17 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
'type_cps': rep_cps})
|
'type_cps': rep_cps})
|
||||||
raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
|
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']:
|
if volume['volume_type_id']:
|
||||||
opts = self._get_vdisk_params(volume['volume_type_id'],
|
opts = self._get_vdisk_params(volume['volume_type_id'],
|
||||||
volume_metadata=
|
volume_metadata=
|
||||||
@ -4822,17 +5031,17 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
{'vdisk_iogrp': vdisk['IO_group_name'],
|
{'vdisk_iogrp': vdisk['IO_group_name'],
|
||||||
'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')
|
|
||||||
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':
|
model_update = {'replication_status':
|
||||||
fields.ReplicationStatus.NOT_CAPABLE}
|
fields.ReplicationStatus.NOT_CAPABLE}
|
||||||
self._helpers.rename_vdisk(vdisk['name'], volume['name'])
|
self._helpers.rename_vdisk(vdisk['name'], volume['name'])
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Added data reduction pool support for thin-provisoned and compressed
|
||||||
|
volume in Storwize cinder driver.
|
Loading…
Reference in New Issue
Block a user