From 6bcb6fea741267b72175e5936c6f6a656fb2fffc Mon Sep 17 00:00:00 2001 From: jarbassaidai Date: Mon, 1 Oct 2018 07:50:19 -0600 Subject: [PATCH] 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 12a7bf699df1558f081513b1686d9c389bd3b812) --- .../drivers/solidfire/test_solidfire.py | 84 ++++++++++++++++++- cinder/volume/drivers/solidfire.py | 15 ++-- .../notes/bug-1782588-7e058b379da95309.yaml | 5 ++ 3 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 releasenotes/notes/bug-1782588-7e058b379da95309.yaml diff --git a/cinder/tests/unit/volume/drivers/solidfire/test_solidfire.py b/cinder/tests/unit/volume/drivers/solidfire/test_solidfire.py index f534da5f10f..8e505d4c561 100644 --- a/cinder/tests/unit/volume/drivers/solidfire/test_solidfire.py +++ b/cinder/tests/unit/volume/drivers/solidfire/test_solidfire.py @@ -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', diff --git a/cinder/volume/drivers/solidfire.py b/cinder/volume/drivers/solidfire.py index fe2aba42dd8..3c520c3a939 100644 --- a/cinder/volume/drivers/solidfire.py +++ b/cinder/volume/drivers/solidfire.py @@ -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') diff --git a/releasenotes/notes/bug-1782588-7e058b379da95309.yaml b/releasenotes/notes/bug-1782588-7e058b379da95309.yaml new file mode 100644 index 00000000000..8c5a28dc0ac --- /dev/null +++ b/releasenotes/notes/bug-1782588-7e058b379da95309.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Solidfire fix extend volume with qos-Scaling to honor the increased size + with increased iops on the extended volume.