From 5345f8cb9c8ec416aa5d764ea5ea47e3ff4d8d1d Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Thu, 28 Sep 2017 03:23:22 -0400 Subject: [PATCH] VNX: Fix issue when creating without type When creating a volume without type, a error will be thrown: AttributeError: 'NoneType' object has no attribute 'qos_specs' This issue was introduced in qos patch: https://review.openstack.org/#/c/441786/ Change-Id: I861d61dd11f982a8a54b57b6a6c895e6ebe399c0 Closes-bug: #1720063 --- .../volume/drivers/dell_emc/vnx/test_utils.py | 36 ++++++++++--------- cinder/volume/drivers/dell_emc/vnx/utils.py | 11 ++++-- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/cinder/tests/unit/volume/drivers/dell_emc/vnx/test_utils.py b/cinder/tests/unit/volume/drivers/dell_emc/vnx/test_utils.py index 3ffd40bf88c..a6cf09756e2 100644 --- a/cinder/tests/unit/volume/drivers/dell_emc/vnx/test_utils.py +++ b/cinder/tests/unit/volume/drivers/dell_emc/vnx/test_utils.py @@ -25,6 +25,7 @@ from cinder.tests.unit.volume.drivers.dell_emc.vnx import res_mock from cinder.tests.unit.volume.drivers.dell_emc.vnx import utils as ut_utils from cinder.volume.drivers.dell_emc.vnx import common from cinder.volume.drivers.dell_emc.vnx import utils as vnx_utils +from cinder.volume import volume_types class FakeDriver(object): @@ -215,25 +216,26 @@ class TestUtils(test.TestCase): @ut_utils.patch_extra_specs({}) @res_mock.mock_driver_input def test_get_backend_qos_specs(self, cinder_input): - volume = mock.Mock() - volume.volume_type.qos_specs = mock.Mock() - volume.volume_type.qos_specs.__getitem__ = mock.Mock(return_value=None) - r = vnx_utils.get_backend_qos_specs(volume) - self.assertIsNone(r) + volume = cinder_input['volume'] + with mock.patch.object(volume_types, 'get_volume_type_qos_specs', + return_value={'qos_specs': None}): + r = vnx_utils.get_backend_qos_specs(volume) + self.assertIsNone(r) - volume.volume_type.qos_specs.__getitem__ = mock.Mock( - return_value={'consumer': 'frontend'}) - r = vnx_utils.get_backend_qos_specs(volume) - self.assertIsNone(r) + with mock.patch.object(volume_types, 'get_volume_type_qos_specs', + return_value={ + 'qos_specs': {'consumer': 'frontend'}}): + r = vnx_utils.get_backend_qos_specs(volume) + self.assertIsNone(r) - volume.volume_type.qos_specs.__getitem__ = mock.Mock( - return_value={'id': 'test', 'consumer': 'back-end', - 'specs': {common.QOS_MAX_BWS: 100, - common.QOS_MAX_IOPS: 10}}) - r = vnx_utils.get_backend_qos_specs(volume) - self.assertIsNotNone(r) - self.assertEqual(100, r[common.QOS_MAX_BWS]) - self.assertEqual(10, r[common.QOS_MAX_IOPS]) + with mock.patch.object(volume_types, 'get_volume_type_qos_specs', + return_value={ + 'qos_specs': {'id': 'test', 'consumer': 'back-end', 'specs': { + common.QOS_MAX_BWS: 100, common.QOS_MAX_IOPS: 10}}}): + r = vnx_utils.get_backend_qos_specs(volume) + self.assertIsNotNone(r) + self.assertEqual(100, r[common.QOS_MAX_BWS]) + self.assertEqual(10, r[common.QOS_MAX_IOPS]) @ut_utils.patch_group_specs({ 'consistent_group_replication_enabled': ' True'}) diff --git a/cinder/volume/drivers/dell_emc/vnx/utils.py b/cinder/volume/drivers/dell_emc/vnx/utils.py index 6d7a2b952ca..3d10f2c38db 100644 --- a/cinder/volume/drivers/dell_emc/vnx/utils.py +++ b/cinder/volume/drivers/dell_emc/vnx/utils.py @@ -28,6 +28,7 @@ from cinder.objects import fields from cinder.volume.drivers.dell_emc.vnx import common from cinder.volume.drivers.san.san import san_opts from cinder.volume import utils as vol_utils +from cinder.volume import volume_types storops = importutils.try_import('storops') @@ -454,7 +455,12 @@ def calc_migrate_and_provision(volume): def get_backend_qos_specs(volume): - qos_specs = volume.volume_type.qos_specs + type_id = volume.volume_type_id + if type_id is None: + return None + + # Use the provided interface to avoid permission issue + qos_specs = volume_types.get_volume_type_qos_specs(type_id) if qos_specs is None: return None @@ -463,13 +469,12 @@ def get_backend_qos_specs(volume): return None consumer = qos_specs['consumer'] - # Front end QoS specs are handled by nova. Just ignore them here. + # Front end QoS specs are handled by nova. We ignore them here. if consumer not in common.BACKEND_QOS_CONSUMERS: return None max_iops = qos_specs['specs'].get(common.QOS_MAX_IOPS) max_bws = qos_specs['specs'].get(common.QOS_MAX_BWS) - if max_iops is None and max_bws is None: return None