]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Editable default quota support for cinder
authorliyingjun <liyingjun1988@gmail.com>
Thu, 23 May 2013 08:24:26 +0000 (16:24 +0800)
committerliyingjun <liyingjun1988@gmail.com>
Mon, 17 Jun 2013 13:26:38 +0000 (21:26 +0800)
Implement blueprint edit-default-quota

DocImpact

Using the class quotas named `default` as the default editable quotas.

We can use the following cinderclient command to update default quota:

cinder quota-class-update default <key> <value>

Change-Id: I9f97506b41157066026dd43163ec4b1827d5b9cf

cinder/db/api.py
cinder/db/sqlalchemy/api.py
cinder/quota.py
cinder/tests/test_quota.py
etc/cinder/cinder.conf.sample

index 099856642d3706fd434f1975b77bb8b446f3ebdd..15e4a3f78bfefe1c8c7d6d4699f24a8f8f05d708 100644 (file)
@@ -617,6 +617,11 @@ def quota_class_get(context, class_name, resource):
     return IMPL.quota_class_get(context, class_name, resource)
 
 
+def quota_class_get_default(context):
+    """Retrieve all default quotas."""
+    return IMPL.quota_class_get_default(context)
+
+
 def quota_class_get_all_by_name(context, class_name):
     """Retrieve all quotas associated with a given quota class."""
     return IMPL.quota_class_get_all_by_name(context, class_name)
index c4a18b393daec36f8d90b88eee3c5572f1b0b635..c5735fc85de43f09dda6d6905c2d0a2a652bccc8 100644 (file)
@@ -52,6 +52,8 @@ db_session.set_defaults(sql_connection='sqlite:///$state_path/$sqlite_db',
 get_engine = db_session.get_engine
 get_session = db_session.get_session
 
+_DEFAULT_QUOTA_NAME = 'default'
+
 
 def get_backend():
     """The backend is this module itself."""
@@ -499,6 +501,18 @@ def quota_class_get(context, class_name, resource, session=None):
     return result
 
 
+def quota_class_get_default(context):
+    rows = model_query(context, models.QuotaClass,
+                       read_deleted="no").\
+        filter_by(class_name=_DEFAULT_QUOTA_NAME).all()
+
+    result = {'class_name': _DEFAULT_QUOTA_NAME}
+    for row in rows:
+        result[row.resource] = row.hard_limit
+
+    return result
+
+
 @require_context
 def quota_class_get_all_by_name(context, class_name):
     authorize_quota_class_context(context, class_name)
index 3f9b174ecd3851a2cdb0656cd173a4b1d1fc661d..9a27df190640ec006a2206d7e2f09962cb754f22 100644 (file)
@@ -54,7 +54,10 @@ quota_opts = [
                help='number of seconds between subsequent usage refreshes'),
     cfg.StrOpt('quota_driver',
                default='cinder.quota.DbQuotaDriver',
-               help='default driver to use for quota checks'), ]
+               help='default driver to use for quota checks'),
+    cfg.BoolOpt('use_default_quota_class',
+                default='True',
+                help='whether to use default quota class for default quota'), ]
 
 CONF = cfg.CONF
 CONF.register_opts(quota_opts)
@@ -79,14 +82,26 @@ class DbQuotaDriver(object):
 
     def get_defaults(self, context, resources):
         """Given a list of resources, retrieve the default quotas.
+        Use the class quotas named `_DEFAULT_QUOTA_NAME` as default quotas,
+        if it exists.
 
         :param context: The request context, for access checks.
         :param resources: A dictionary of the registered resources.
         """
 
         quotas = {}
+        default_quotas = {}
+        if CONF.use_default_quota_class:
+            default_quotas = db.quota_class_get_default(context)
         for resource in resources.values():
-            quotas[resource.name] = resource.default
+            if resource.name not in default_quotas:
+                LOG.deprecated(_("Default quota for resource: %(res)s is set "
+                                 "by the default quota flag: quota_%(res)s, "
+                                 "it is now deprecated. Please use the "
+                                 "the default quota class for default "
+                                 "quota.") % {'res': resource.name})
+            quotas[resource.name] = default_quotas.get(resource.name,
+                                                       resource.default)
 
         return quotas
 
@@ -154,15 +169,19 @@ class DbQuotaDriver(object):
         else:
             class_quotas = {}
 
+        default_quotas = self.get_defaults(context, resources)
+
         for resource in resources.values():
             # Omit default/quota class values
             if not defaults and resource.name not in project_quotas:
                 continue
 
             quotas[resource.name] = dict(
-                limit=project_quotas.get(resource.name,
-                                         class_quotas.get(resource.name,
-                                                          resource.default)), )
+                limit=project_quotas.get(
+                    resource.name,
+                    class_quotas.get(resource.name,
+                                     default_quotas[resource.name])),
+            )
 
             # Include usages if desired.  This is optional because one
             # internal consumer of this interface wants to access the
index 6639cd37838f6a022c1c938a0329821f669a1c4c..6a5e1653c9a493380c8936435158061a24b90863 100644 (file)
@@ -666,6 +666,7 @@ class DbQuotaDriverTestCase(test.TestCase):
 
     def test_get_defaults(self):
         # Use our pre-defined resources
+        self._stub_quota_class_get_default()
         result = self.driver.get_defaults(None, quota.QUOTAS._resources)
 
         self.assertEqual(
@@ -675,6 +676,15 @@ class DbQuotaDriverTestCase(test.TestCase):
                 snapshots=10,
                 gigabytes=1000, ))
 
+    def _stub_quota_class_get_default(self):
+        # Stub out quota_class_get_default
+        def fake_qcgd(context):
+            self.calls.append('quota_class_get_default')
+            return dict(volumes=10,
+                        snapshots=10,
+                        gigabytes=1000,)
+        self.stubs.Set(db, 'quota_class_get_default', fake_qcgd)
+
     def _stub_quota_class_get_all_by_name(self):
         # Stub out quota_class_get_all_by_name
         def fake_qcgabn(context, quota_class):
@@ -720,6 +730,7 @@ class DbQuotaDriverTestCase(test.TestCase):
         self.stubs.Set(db, 'quota_usage_get_all_by_project', fake_qugabp)
 
         self._stub_quota_class_get_all_by_name()
+        self._stub_quota_class_get_default()
 
     def test_get_project_quotas(self):
         self._stub_get_by_project()
@@ -729,7 +740,8 @@ class DbQuotaDriverTestCase(test.TestCase):
 
         self.assertEqual(self.calls, ['quota_get_all_by_project',
                                       'quota_usage_get_all_by_project',
-                                      'quota_class_get_all_by_name', ])
+                                      'quota_class_get_all_by_name',
+                                      'quota_class_get_default', ])
         self.assertEqual(result, dict(volumes=dict(limit=10,
                                                    in_use=2,
                                                    reserved=0, ),
@@ -747,7 +759,8 @@ class DbQuotaDriverTestCase(test.TestCase):
             quota.QUOTAS._resources, 'test_project')
 
         self.assertEqual(self.calls, ['quota_get_all_by_project',
-                                      'quota_usage_get_all_by_project', ])
+                                      'quota_usage_get_all_by_project',
+                                      'quota_class_get_default', ])
         self.assertEqual(result, dict(volumes=dict(limit=10,
                                                    in_use=2,
                                                    reserved=0, ),
@@ -766,7 +779,8 @@ class DbQuotaDriverTestCase(test.TestCase):
 
         self.assertEqual(self.calls, ['quota_get_all_by_project',
                                       'quota_usage_get_all_by_project',
-                                      'quota_class_get_all_by_name', ])
+                                      'quota_class_get_all_by_name',
+                                      'quota_class_get_default', ])
         self.assertEqual(result, dict(volumes=dict(limit=10,
                                                    in_use=2,
                                                    reserved=0, ),
@@ -785,7 +799,8 @@ class DbQuotaDriverTestCase(test.TestCase):
 
         self.assertEqual(self.calls, ['quota_get_all_by_project',
                                       'quota_usage_get_all_by_project',
-                                      'quota_class_get_all_by_name', ])
+                                      'quota_class_get_all_by_name',
+                                      'quota_class_get_default', ])
         self.assertEqual(result,
                          dict(gigabytes=dict(limit=50,
                                              in_use=10,
@@ -804,7 +819,8 @@ class DbQuotaDriverTestCase(test.TestCase):
             quota.QUOTAS._resources, 'test_project', usages=False)
 
         self.assertEqual(self.calls, ['quota_get_all_by_project',
-                                      'quota_class_get_all_by_name', ])
+                                      'quota_class_get_all_by_name',
+                                      'quota_class_get_default', ])
         self.assertEqual(result, dict(volumes=dict(limit=10, ),
                                       snapshots=dict(limit=10, ),
                                       gigabytes=dict(limit=50, ), ))
index 871818ca383b9484eb9b0cf9cffb76f3a4cbade0..ba5bbeea7fb55366a231712c996d4acda9b47163 100644 (file)
 # Options defined in cinder.quota
 #
 
+# If True, uses the default quota class for default quota, the
+# quota_* option will be deprecated if the default quota for
+# the related resource is set by default quota class (boolean value)
+#use_default_quota_class=true
+
 # number of volumes allowed per project (integer value)
 #quota_volumes=10