SF: Handle qos values on extend volume

For the Solidfire cinder driver when volume extend is called on a volume
that has a qos with scaledIOPs=True, the values scaleMin, scaleMax,
scaleBurst are ignored, thus when a volume grows the iops values stay
the same when they should either grow or shrink.

To correct the bug _retrieve_qos_setting has a new argument size with a
default value of zero. This allows all previous calls to function
properly, and saved duplicating code.

Extend volume now calls _retrive_qos_settings with the new size argument
and then includes that qos with the call to solidfire api  ModifyVolume.

Closes-Bug: #1783588
Change-Id: I8cb7b1eccbc63ef4077e86324afdd1a11409343d
(cherry picked from commit 12a7bf699d)
This commit is contained in:
jarbassaidai 2018-10-01 07:50:19 -06:00 committed by Fernando Ferraz
parent 7a33e5fa79
commit 6bcb6fea74
3 changed files with 95 additions and 9 deletions

View File

@ -1,4 +1,4 @@
#
# Copyright 2012 OpenStack Foundation
# All Rights Reserved.
#
@ -63,6 +63,8 @@ f_uuid = ['262b9ce2-a71a-4fbe-830c-c20c5596caea',
@ddt.ddt
class SolidFireVolumeTestCase(test.TestCase):
EXPECTED_QOS = {'minIOPS': 110, 'burstIOPS': 1530, 'maxIOPS': 1020}
def setUp(self):
self.ctxt = context.get_admin_context()
self.configuration = conf.Configuration(None)
@ -939,6 +941,58 @@ class SolidFireVolumeTestCase(test.TestCase):
return_value=fake_no_volumes):
sfv.delete_snapshot(testsnap)
def fake_ext_qos_issue_api_request(obj, method, params, version='1.0',
endpoint=None):
EXPECTED_SIZE = 2 << 30 # 2147483648 size + increase
if method == 'ModifyVolume':
response = {'error': {'code': 0,
'name': 'Extend Volume',
'message': 'extend fail, size/scale-iops'},
'id': 1}
if params.get('totalSize', None) != EXPECTED_SIZE:
msg = ('Error (%s) encountered during '
'SolidFire API call.' % response['error']['name'])
raise exception.SolidFireAPIException(message=msg)
if params.get('qos', None) != SolidFireVolumeTestCase.EXPECTED_QOS:
msg = ('Error (%s) encountered during '
'SolidFire API call.' % response['error']['name'])
raise exception.SolidFireAPIException(message=msg)
return {'result': {}, 'id': 1}
elif method == 'GetAccountByName' and version == '1.0':
results = {'result': {'account':
{'accountID': 25,
'username': params['username'],
'status': 'active',
'initiatorSecret': '123456789012',
'targetSecret': '123456789012',
'attributes': {},
'volumes': [6, 7, 20]}},
"id": 1}
return results
elif method == 'ListVolumesForAccount' and version == '1.0':
test_name = 'OS-VOLID-a720b3c0-d1f0-11e1-9b23-0800200c9a66'
result = {'result': {
'volumes': [{'volumeID': 5,
'name': test_name,
'accountID': 25,
'sliceCount': 1,
'totalSize': 1 * units.Gi,
'enable512e': True,
'access': "readWrite",
'status': "active",
'attributes': {},
'qos': None,
'iqn': test_name}]}}
return result
else:
return None
def test_extend_volume(self):
self.mock_object(solidfire.SolidFireDriver,
'_issue_api_request',
@ -952,6 +1006,30 @@ class SolidFireVolumeTestCase(test.TestCase):
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
sfv.extend_volume(testvol, 2)
def test_extend_volume_with_scaled_qos(self):
size = 1
self.mock_object(solidfire.SolidFireDriver,
'_issue_api_request',
self.fake_issue_api_request)
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
qos_ref = qos_specs.create(self.ctxt,
'qos-specs-1', {'minIOPS': '100',
'maxIOPS': '1000',
'burstIOPS': '1500',
'scaledIOPS': 'True',
'scaleMin': '10',
'scaleMax': '20',
'scaleBurst': '30'})
type_ref = volume_types.create(self.ctxt, "type1",
{'qos:minIOPS': '1000',
'qos:maxIOPS': '10000',
'qos:burstIOPS': '20000'})
qos_specs.associate_qos_with_type(self.ctxt,
qos_ref['id'],
type_ref['id'])
qos = sfv._set_qos_by_volume_type(self.ctxt, type_ref['id'], size + 1)
self.assertEqual(SolidFireVolumeTestCase.EXPECTED_QOS, qos)
def test_extend_volume_fails_no_volume(self):
self.mock_object(solidfire.SolidFireDriver,
'_issue_api_request',
@ -1502,8 +1580,8 @@ class SolidFireVolumeTestCase(test.TestCase):
if 'ListSnapshots'in method:
return {'result': {'snapshots': sf_snaps}}
with mock.patch.object(
sfv, '_issue_api_request', side_effect=_fake_issue_api_req):
with mock.patch.object(sfv, '_issue_api_request',
side_effect=_fake_issue_api_req):
volume_updates, snapshot_updates = sfv.update_provider_info(
vrefs, snaprefs)
self.assertEqual('99 100 53c8be1e-89e2-4f7f-a2e3-7cb84c47e0ec',

View File

@ -206,10 +206,10 @@ class SolidFireDriver(san.SanISCSIDriver):
2.0.10 - Add response to debug on retryable errors
2.0.11 - Add ability to failback replicating volumes
2.0.12 - Fix bug #1744005
2.0.14 - Fix bug #1782588 qos settings on extend
"""
VERSION = '2.0.12'
VERSION = '2.0.14'
# ThirdPartySystems wiki page
CI_WIKI_NAME = "NetApp_SolidFire_CI"
@ -1351,7 +1351,8 @@ class SolidFireDriver(san.SanISCSIDriver):
volume)
return model, True
def _retrieve_qos_setting(self, volume):
# extended_size > 0 when we are extending a volume
def _retrieve_qos_setting(self, volume, extended_size=0):
qos = {}
if (self.configuration.sf_allow_tenant_qos and
volume.get('volume_metadata')is not None):
@ -1361,7 +1362,8 @@ class SolidFireDriver(san.SanISCSIDriver):
type_id = volume.get('volume_type_id', None)
if type_id is not None:
qos = self._set_qos_by_volume_type(ctxt, type_id,
volume.get('size'))
extended_size if extended_size
> 0 else volume.get('size'))
return qos
def create_volume(self, volume):
@ -1904,10 +1906,11 @@ class SolidFireDriver(san.SanISCSIDriver):
"the SolidFire Cluster while attempting "
"extend_volume operation!", volume['id'])
raise exception.VolumeNotFound(volume_id=volume['id'])
qos = self._retrieve_qos_setting(volume, new_size)
params = {
'volumeID': sf_vol['volumeID'],
'totalSize': int(new_size * units.Gi)
'totalSize': int(new_size * units.Gi),
'qos': qos
}
self._issue_api_request('ModifyVolume',
params, version='5.0')

View File

@ -0,0 +1,5 @@
---
fixes:
- |
Solidfire fix extend volume with qos-Scaling to honor the increased size
with increased iops on the extended volume.