Fix Qos for clone for Nimble Storage Driver

Currently the Qos is set only for the create volume.
The attribute needs to be overriden by the clone.
By default the clone inherits the attributes of the parent,
but if user needs to modify the Qos and Folder name of the child
(clone) they should be able to do it with this fix.

Change-Id: Ic30c1f386ee902333260fe23d57954ea021c24a4
Closes-Bug: #1659165
This commit is contained in:
Raunak Kumar 2017-01-24 18:04:52 -08:00
parent f7683734f9
commit 1c98d1604b
2 changed files with 80 additions and 12 deletions

View File

@ -696,7 +696,8 @@ class NimbleDriverVolumeTestCase(NimbleDriverBaseTestCase):
return_value=
{'nimble:perfpol-name': 'default',
'nimble:encryption': 'yes',
'nimble:multi-initiator': 'false'}))
'nimble:multi-initiator': 'false',
'nimble:iops-limit': '1024'}))
@NimbleDriverBaseTestCase.client_mock_decorator(create_configuration(
'nimble', 'nimble_pass', '10.18.108.55', 'default', '*', False))
@mock.patch.object(obj_volume.VolumeList, 'get_all_by_host')
@ -744,7 +745,7 @@ class NimbleDriverVolumeTestCase(NimbleDriverBaseTestCase):
'volume_size': src_volume['size'],
'display_name': volume['display_name'],
'display_description': ''},
True, False, 'iSCSI')]
True, False, 'iSCSI', 'default')]
self.mock_client_service.assert_has_calls(expected_calls)
@ -1033,7 +1034,8 @@ class NimbleDriverSnapshotTestCase(NimbleDriverBaseTestCase):
'volume_size': 1},
False,
False,
'iSCSI'),
'iSCSI',
'default'),
mock.call.edit_vol('clone-testvolume',
{'data': {'size': 2048,
'snap_limit': sys.maxsize,

View File

@ -68,6 +68,7 @@ SM_SUBNET_MGMT_PLUS_DATA = 'mgmt-data'
SM_STATE_MSG = "is already in requested state"
SM_OBJ_EXIST_MSG = "Object exists"
SM_OBJ_ENOENT_MSG = "No such object"
IOPS_ERR_MSG = "Please set valid IOPS limit in the range"
LUN_ID = '0'
WARN_LEVEL = 80
DEFAULT_SLEEP = 5
@ -242,9 +243,11 @@ class NimbleBaseVolumeDriver(san.SanDriver):
Extend the volume if the size of the volume is more than the snapshot.
"""
reserve = not self.configuration.san_thin_provision
pool_name = self.configuration.nimble_pool_name
self.APIExecutor.clone_vol(volume, snapshot, reserve,
self._group_target_enabled,
self._storage_protocol)
self._storage_protocol,
pool_name)
if(volume['size'] > snapshot['volume_size']):
vol_size = volume['size'] * units.Ki
reserve_size = 100 if reserve else 0
@ -1181,10 +1184,11 @@ class NimbleRestAPIExecutor(object):
if iops_limit is not None:
if not iops_limit.isdigit() or (
int(iops_limit) < MIN_IOPS) or (int(iops_limit) > MAX_IOPS):
raise NimbleAPIException(_("Please set valid IOPS limit"
" in the range [%(min)s, %(max)s]") %
{'min': MIN_IOPS,
raise NimbleAPIException(_("%(err)s [%(min)s, %(max)s]") %
{'err': IOPS_ERR_MSG,
'min': MIN_IOPS,
'max': MAX_IOPS})
data['data']['limit_iops'] = iops_limit
LOG.debug("Volume metadata :%s", volume.metadata)
@ -1194,10 +1198,9 @@ class NimbleRestAPIExecutor(object):
if key == EXTRA_SPEC_IOPS_LIMIT and value.isdigit():
if type(value) == int or int(value) < MIN_IOPS or (
int(value) > MAX_IOPS):
raise NimbleAPIException(_("Please enter valid IOPS "
"limit in the range ["
"%(min)s, %(max)s]") %
{'min': MIN_IOPS,
raise NimbleAPIException(_("%(err)s [%(min)s, %(max)s]") %
{'err': IOPS_ERR_MSG,
'min': MIN_IOPS,
'max': MAX_IOPS})
LOG.debug("IOPS Limit %s", value)
data['data']['limit_iops'] = value
@ -1478,7 +1481,7 @@ class NimbleRestAPIExecutor(object):
return r['data']
def clone_vol(self, volume, snapshot, reserve, is_gst_enabled,
protocol):
protocol, pool_name):
api = "volumes"
volume_name = snapshot['volume_name']
snap_name = snapshot['name']
@ -1493,6 +1496,9 @@ class NimbleRestAPIExecutor(object):
perf_policy_id = self.get_performance_policy_id(perf_policy_name)
encrypt = extra_specs_map.get(EXTRA_SPEC_ENCRYPTION)
multi_initiator = extra_specs_map.get(EXTRA_SPEC_MULTI_INITIATOR)
iops_limit = extra_specs_map[EXTRA_SPEC_IOPS_LIMIT]
folder_name = extra_specs_map[EXTRA_SPEC_FOLDER]
pool_id = self.get_pool_id(pool_name)
# default value of cipher for encryption
cipher = DEFAULT_CIPHER
if encrypt.lower() == 'yes':
@ -1535,6 +1541,66 @@ class NimbleRestAPIExecutor(object):
if protocol == "iSCSI":
data['data']['multi_initiator'] = multi_initiator
folder_id = None
if folder_name is not None:
# validate if folder exists in pool_name
pool_info = self.get_pool_info(pool_id)
if 'folder_list' in pool_info and (pool_info['folder_list'] is
not None):
for folder_list in pool_info['folder_list']:
LOG.debug("folder_list : %s", folder_list)
if folder_list['fqn'] == "/" + folder_name:
LOG.debug("Folder %(folder)s present in pool "
"%(pool)s",
{'folder': folder_name,
'pool': pool_name})
folder_id = self.get_folder_id(folder_name)
if folder_id is not None:
data['data']["folder_id"] = folder_id
if folder_id is None:
raise NimbleAPIException(_("Folder '%(folder)s' not "
"present in pool '%(pool)s'") %
{'folder': folder_name,
'pool': pool_name})
else:
raise NimbleAPIException(_("Folder '%(folder)s' not present in"
" pool '%(pool)s'") %
{'folder': folder_name,
'pool': pool_name})
if iops_limit is not None:
if not iops_limit.isdigit() or (
int(iops_limit) < MIN_IOPS) or (int(iops_limit) > MAX_IOPS):
raise NimbleAPIException(_("%(err)s [%(min)s, %(max)s]") %
{'err': IOPS_ERR_MSG,
'min': MIN_IOPS,
'max': MAX_IOPS})
data['data']['limit_iops'] = iops_limit
if iops_limit is not None:
if not iops_limit.isdigit() or (
int(iops_limit) < MIN_IOPS) or (int(iops_limit) > MAX_IOPS):
raise NimbleAPIException(_("Please set valid IOPS limit"
" in the range [%(min)s, %(max)s]") %
{'min': MIN_IOPS,
'max': MAX_IOPS})
data['data']['limit_iops'] = iops_limit
LOG.debug("Volume metadata :%s", volume.metadata)
for key, value in volume.metadata.items():
LOG.debug("Key %(key)s Value %(value)s",
{'key': key, 'value': value})
if key == EXTRA_SPEC_IOPS_LIMIT and value.isdigit():
if type(value) == int or int(value) < MIN_IOPS or (
int(value) > MAX_IOPS):
raise NimbleAPIException(_("Please enter valid IOPS "
"limit in the range ["
"%(min)s, %(max)s]") %
{'min': MIN_IOPS,
'max': MAX_IOPS})
LOG.debug("IOPS Limit %s", value)
data['data']['limit_iops'] = value
r = self.post(api, data)
return r['data']