]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Add qos_specs support to solidfire driver
authorJohn Griffith <john.griffith@solidfire.com>
Sat, 21 Dec 2013 00:33:23 +0000 (17:33 -0700)
committerjohn-griffith <john.griffith@solidfire.com>
Sun, 22 Dec 2013 17:17:37 +0000 (10:17 -0700)
We've added a new qos_specs object to Cinder that allows creation
and management of qos settings separate from volume-types.
Now instead of embedding the qos info in the extra-specs of the
volume-type we associate the desired qos-spec to a volume-type.

This change implements the capability of the SolidFire driver to
take advantage of that feature.

Change-Id: I215bd0cff0c0a91c106de27eea9ec2b91689a46e
Implements: blueprint add-qosspecs-support-to-solidfire-driver

cinder/tests/test_solidfire.py
cinder/volume/drivers/solidfire.py

index b228509889fe63159812114174e6c1dc39c141c3..48f8ef241179e6812853d920eadcdc2c69d71b6c 100644 (file)
@@ -17,6 +17,7 @@
 
 import mox
 
+from cinder import context
 from cinder import exception
 from cinder.openstack.common import log as logging
 from cinder.openstack.common import timeutils
@@ -24,6 +25,8 @@ from cinder import test
 from cinder import units
 from cinder.volume import configuration as conf
 from cinder.volume.drivers.solidfire import SolidFireDriver
+from cinder.volume import qos_specs
+from cinder.volume import volume_types
 
 LOG = logging.getLogger(__name__)
 
@@ -37,6 +40,7 @@ def create_configuration():
 
 class SolidFireVolumeTestCase(test.TestCase):
     def setUp(self):
+        self.ctxt = context.get_admin_context()
         self._mox = mox.Mox()
         self.configuration = mox.MockObject(conf.Configuration)
         self.configuration.sf_allow_tenant_qos = True
@@ -48,6 +52,10 @@ class SolidFireVolumeTestCase(test.TestCase):
         self.stubs.Set(SolidFireDriver, '_issue_api_request',
                        self.fake_issue_api_request)
 
+        self.expected_qos_results = {'minIOPS': 1000,
+                                     'maxIOPS': 10000,
+                                     'burstIOPS': 20000}
+
     def fake_issue_api_request(obj, method, params, version='1.0'):
         if method is 'GetClusterCapacity' and version == '1.0':
             LOG.info('Called Fake GetClusterCapacity...')
@@ -429,3 +437,46 @@ class SolidFireVolumeTestCase(test.TestCase):
         self.assertRaises(exception.SolidFireAccountNotFound,
                           sfv.extend_volume,
                           testvol, 2)
+
+    def test_set_by_qos_spec_with_scoping(self):
+        sfv = SolidFireDriver(configuration=self.configuration)
+        qos_ref = qos_specs.create(self.ctxt,
+                                   'qos-specs-1', {'qos:minIOPS': '1000',
+                                                   'qos:maxIOPS': '10000',
+                                                   'qos:burstIOPS': '20000'})
+        type_ref = volume_types.create(self.ctxt,
+                                       "type1", {"qos:minIOPS": "100",
+                                                 "qos:burstIOPS": "300",
+                                                 "qos:maxIOPS": "200"})
+        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'])
+        self.assertEqual(qos, self.expected_qos_results)
+
+    def test_set_by_qos_spec(self):
+        sfv = SolidFireDriver(configuration=self.configuration)
+        qos_ref = qos_specs.create(self.ctxt,
+                                   'qos-specs-1', {'minIOPS': '1000',
+                                                   'maxIOPS': '10000',
+                                                   'burstIOPS': '20000'})
+        type_ref = volume_types.create(self.ctxt,
+                                       "type1", {"qos:minIOPS": "100",
+                                                 "qos:burstIOPS": "300",
+                                                 "qos:maxIOPS": "200"})
+        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'])
+        self.assertEqual(qos, self.expected_qos_results)
+
+    def test_set_by_qos_by_type_only(self):
+        sfv = SolidFireDriver(configuration=self.configuration)
+        type_ref = volume_types.create(self.ctxt,
+                                       "type1", {"qos:minIOPS": "100",
+                                                 "qos:burstIOPS": "300",
+                                                 "qos:maxIOPS": "200"})
+        qos = sfv._set_qos_by_volume_type(self.ctxt, type_ref['id'])
+        self.assertEqual(qos, {'minIOPS': 100,
+                               'maxIOPS': 200,
+                               'burstIOPS': 300})
index d862048625002387062eee7c6f9fa7a7c871cb3d..71fb48be20cbdcc77ca9b54789a3e3cb5fdbebdf 100644 (file)
@@ -32,6 +32,7 @@ from cinder import exception
 from cinder.openstack.common import log as logging
 from cinder.openstack.common import timeutils
 from cinder.volume.drivers.san.san import SanISCSIDriver
+from cinder.volume import qos_specs
 from cinder.volume import volume_types
 
 LOG = logging.getLogger(__name__)
@@ -432,8 +433,18 @@ class SolidFireDriver(SanISCSIDriver):
     def _set_qos_by_volume_type(self, ctxt, type_id):
         qos = {}
         volume_type = volume_types.get_volume_type(ctxt, type_id)
+        qos_specs_id = volume_type.get('qos_specs_id')
         specs = volume_type.get('extra_specs')
-        for key, value in specs.iteritems():
+
+        # NOTE(jdg): We prefer the qos_specs association
+        # and over-ride any existing
+        # extra-specs settings if present
+        if qos_specs_id is not None:
+            kvs = qos_specs.get_qos_specs(ctxt, qos_specs_id)['specs']
+        else:
+            kvs = specs
+
+        for key, value in kvs.iteritems():
             if ':' in key:
                 fields = key.split(':')
                 key = fields[1]