diff --git a/cinder/quota.py b/cinder/quota.py index eb29a8aeb27..05438a6693f 100644 --- a/cinder/quota.py +++ b/cinder/quota.py @@ -188,6 +188,7 @@ class DbQuotaDriver(object): quotas = {} project_quotas = db.quota_get_all_by_project(context, project_id) allocated_quotas = None + default_quotas = None if usages: project_usages = db.quota_usage_get_all_by_project(context, project_id) @@ -206,20 +207,22 @@ class DbQuotaDriver(object): else: class_quotas = {} - # TODO(mc_nair): change this to be lazy loaded - default_quotas = self.get_defaults(context, resources, project_id) - 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, - default_quotas[resource.name])), - ) + quota_val = project_quotas.get(resource.name) + if quota_val is None: + quota_val = class_quotas.get(resource.name) + if quota_val is None: + # Lazy load the default quotas + if default_quotas is None: + default_quotas = self.get_defaults( + context, resources, project_id) + quota_val = default_quotas[resource.name] + + quotas[resource.name] = {'limit': quota_val} # Include usages if desired. This is optional because one # internal consumer of this interface wants to access the diff --git a/cinder/tests/unit/test_quota.py b/cinder/tests/unit/test_quota.py index 826af9468cb..23618ad62b1 100644 --- a/cinder/tests/unit/test_quota.py +++ b/cinder/tests/unit/test_quota.py @@ -1063,6 +1063,24 @@ class DbQuotaDriverTestCase(DbQuotaDriverBaseTestCase): reserved= 0) ), result) + @mock.patch('cinder.quota.db.quota_get_all_by_project') + @mock.patch('cinder.quota.db.quota_class_get_default') + def test_get_project_quotas_lazy_load_defaults( + self, mock_defaults, mock_quotas): + mock_quotas.return_value = self._default_quotas_non_child + self.driver.get_project_quotas( + FakeContext('test_project', None), + quota.QUOTAS.resources, 'test_project', usages=False) + # Shouldn't load a project's defaults if all the quotas are already + # defined in the DB + self.assertFalse(mock_defaults.called) + + mock_quotas.return_value = {} + self.driver.get_project_quotas( + FakeContext('test_project', None), + quota.QUOTAS.resources, 'test_project', usages=False) + self.assertTrue(mock_defaults.called) + def test_get_root_project_with_subprojects_quotas(self): self._stub_get_by_project() self._stub_volume_type_get_all() @@ -1171,8 +1189,7 @@ class DbQuotaDriverTestCase(DbQuotaDriverBaseTestCase): self.assertEqual(['quota_get_all_by_project', 'quota_usage_get_all_by_project', - 'quota_class_get_all_by_name', - 'quota_class_get_default', ], self.calls) + 'quota_class_get_all_by_name'], self.calls) self.assertEqual(dict(backups=dict(limit=10, in_use=2, reserved=0, ),