return db.quota_class_get(context, quota_class, resource_name)
- def get_default(self, context, resource):
- """Get a specific default quota for a resource."""
+ def get_default(self, context, resource, parent_project_id=None):
+ """Get a specific default quota for a resource.
+
+ :param parent_project_id: The id of the current project's parent,
+ if any.
+ """
default_quotas = db.quota_class_get_default(context)
- return default_quotas.get(resource.name, resource.default)
+ default_quota_value = 0 if parent_project_id else resource.default
+ return default_quotas.get(resource.name, default_quota_value)
- def get_defaults(self, context, resources):
+ def get_defaults(self, context, resources, parent_project_id=None):
"""Given a list of resources, retrieve the default quotas.
Use the class quotas named `_DEFAULT_QUOTA_NAME` as default quotas,
:param context: The request context, for access checks.
:param resources: A dictionary of the registered resources.
+ :param parent_project_id: The id of the current project's parent,
+ if any.
"""
quotas = {}
"default quota class for default "
"quota.") % {'res': resource.name})
quotas[resource.name] = default_quotas.get(resource.name,
- resource.default)
-
+ (0 if parent_project_id
+ else resource.default))
return quotas
def get_class_quotas(self, context, resources, quota_class,
def get_project_quotas(self, context, resources, project_id,
quota_class=None, defaults=True,
- usages=True):
+ usages=True, parent_project_id=None):
"""Given a list of resources, retrieve the quotas for the given
project.
specific value for the resource.
:param usages: If True, the current in_use and reserved counts
will also be returned.
+ :param parent_project_id: The id of the current project's parent,
+ if any.
"""
quotas = {}
else:
class_quotas = {}
- default_quotas = self.get_defaults(context, resources)
+ default_quotas = self.get_defaults(context, resources,
+ parent_project_id=parent_project_id)
for resource in resources.values():
# Omit default/quota class values
return quotas
- def _get_quotas(self, context, resources, keys, has_sync, project_id=None):
+ def _get_quotas(self, context, resources, keys, has_sync, project_id=None,
+ parent_project_id=None):
"""A helper method which retrieves the quotas for specific resources.
This specific resource is identified by keys, and which apply to the
:param project_id: Specify the project_id if current context
is admin and admin wants to impact on
common user's tenant.
+ :param parent_project_id: The id of the current project's parent,
+ if any.
"""
# Filter resources
# Grab and return the quotas (without usages)
quotas = self.get_project_quotas(context, sub_resources,
project_id,
- context.quota_class, usages=False)
+ context.quota_class, usages=False,
+ parent_project_id=parent_project_id)
return {k: v['limit'] for k, v in quotas.items()}
class BaseResource(object):
"""Describe a single resource for quota checking."""
- def __init__(self, name, flag=None):
+ def __init__(self, name, flag=None, parent_project_id=None):
"""Initializes a Resource.
:param name: The name of the resource, i.e., "volumes".
:param flag: The name of the flag or configuration option
which specifies the default value of the quota
for this resource.
+ :param parent_project_id: The id of the current project's parent,
+ if any.
"""
self.name = name
self.flag = flag
+ self.parent_project_id = parent_project_id
def quota(self, driver, context, **kwargs):
"""Given a driver and context, obtain the quota for this resource.
pass
# OK, return the default
- return driver.get_default(context, self)
+ return driver.get_default(context, self,
+ parent_project_id=self.parent_project_id)
@property
def default(self):
"""Return the default value of the quota."""
+ if self.parent_project_id:
+ return 0
+
return CONF[self.flag] if self.flag else -1
return self._driver.get_by_class(context, quota_class, resource_name)
- def get_default(self, context, resource):
- """Get a specific default quota for a resource."""
+ def get_default(self, context, resource, parent_project_id=None):
+ """Get a specific default quota for a resource.
+
+ :param parent_project_id: The id of the current project's parent,
+ if any.
+ """
- return self._driver.get_default(context, resource)
+ return self._driver.get_default(context, resource,
+ parent_project_id=parent_project_id)
- def get_defaults(self, context):
+ def get_defaults(self, context, parent_project_id=None):
"""Retrieve the default quotas.
:param context: The request context, for access checks.
+ :param parent_project_id: The id of the current project's parent,
+ if any.
"""
- return self._driver.get_defaults(context, self.resources)
+ return self._driver.get_defaults(context, self.resources,
+ parent_project_id)
def get_class_quotas(self, context, quota_class, defaults=True):
"""Retrieve the quotas for the given quota class.
quota_class, defaults=defaults)
def get_project_quotas(self, context, project_id, quota_class=None,
- defaults=True, usages=True):
+ defaults=True, usages=True, parent_project_id=None):
"""Retrieve the quotas for the given project.
:param context: The request context, for access checks.
specific value for the resource.
:param usages: If True, the current in_use and reserved counts
will also be returned.
+ :param parent_project_id: The id of the current project's parent,
+ if any.
"""
return self._driver.get_project_quotas(context, self.resources,
project_id,
quota_class=quota_class,
defaults=defaults,
- usages=usages)
+ usages=usages,
+ parent_project_id=
+ parent_project_id)
def count(self, context, resource, *args, **kwargs):
"""Count a resource.
except KeyError:
raise exception.QuotaClassNotFound(class_name=quota_class)
- def get_default(self, context, resource):
- self.called.append(('get_default', context, resource))
+ def get_default(self, context, resource, parent_project_id=None):
+ self.called.append(('get_default', context, resource,
+ parent_project_id))
return resource.default
- def get_defaults(self, context, resources):
- self.called.append(('get_defaults', context, resources))
+ def get_defaults(self, context, resources, parent_project_id=None):
+ self.called.append(('get_defaults', context, resources,
+ parent_project_id))
return resources
def get_class_quotas(self, context, resources, quota_class,
return resources
def get_project_quotas(self, context, resources, project_id,
- quota_class=None, defaults=True, usages=True):
+ quota_class=None, defaults=True, usages=True,
+ parent_project_id=None):
self.called.append(('get_project_quotas', context, resources,
- project_id, quota_class, defaults, usages))
+ project_id, quota_class, defaults, usages,
+ parent_project_id))
return resources
def limit_check(self, context, resources, values, project_id=None):
self.assertEqual(quota_value, 20)
+ def test_quota_override_subproject_no_class(self):
+ self.flags(quota_volumes=10)
+ resource = quota.BaseResource('test_resource', 'quota_volumes',
+ parent_project_id='test_parent_project')
+ driver = FakeDriver()
+ context = FakeContext('test_project', None)
+ quota_value = resource.quota(driver, context)
+
+ self.assertEqual(quota_value, 0)
+
def test_quota_with_project_override_class(self):
self.flags(quota_volumes=10)
resource = quota.BaseResource('test_resource', 'quota_volumes')
def test_get_defaults(self):
context = FakeContext(None, None)
+ parent_project_id = None
driver = FakeDriver()
quota_obj = self._make_quota_obj(driver)
result = quota_obj.get_defaults(context)
self.assertEqual(driver.called, [('get_defaults',
context,
- quota_obj.resources), ])
+ quota_obj.resources,
+ parent_project_id), ])
self.assertEqual(result, quota_obj.resources)
def test_get_class_quotas(self):
def test_get_project_quotas(self):
context = FakeContext(None, None)
driver = FakeDriver()
+ parent_project_id = None
quota_obj = self._make_quota_obj(driver)
result1 = quota_obj.get_project_quotas(context, 'test_project')
result2 = quota_obj.get_project_quotas(context, 'test_project',
'test_project',
None,
True,
- True),
+ True,
+ parent_project_id),
('get_project_quotas',
context,
quota_obj.resources,
'test_project',
'test_class',
False,
- False), ])
+ False,
+ parent_project_id), ])
+ self.assertEqual(result1, quota_obj.resources)
+ self.assertEqual(result2, quota_obj.resources)
+
+ def test_get_subproject_quotas(self):
+ context = FakeContext(None, None)
+ driver = FakeDriver()
+ parent_project_id = 'test_parent_project_id'
+ quota_obj = self._make_quota_obj(driver)
+ result1 = quota_obj.get_project_quotas(context, 'test_project',
+ parent_project_id=
+ parent_project_id)
+ result2 = quota_obj.get_project_quotas(context, 'test_project',
+ quota_class='test_class',
+ defaults=False,
+ usages=False,
+ parent_project_id=
+ parent_project_id)
+
+ self.assertEqual(driver.called, [
+ ('get_project_quotas',
+ context,
+ quota_obj.resources,
+ 'test_project',
+ None,
+ True,
+ True,
+ parent_project_id),
+ ('get_project_quotas',
+ context,
+ quota_obj.resources,
+ 'test_project',
+ 'test_class',
+ False,
+ False,
+ parent_project_id), ])
self.assertEqual(result1, quota_obj.resources)
self.assertEqual(result2, quota_obj.resources)
backup_gigabytes=1000,
per_volume_gigabytes=-1))
+ def test_subproject_get_defaults(self):
+ # Test subproject default values.
+ self._stub_quota_class_get_default_subproject()
+ self._stub_volume_type_get_all()
+ parent_project_id = 'test_parent_project_id'
+ result = self.driver.get_defaults(None,
+ quota.QUOTAS.resources,
+ parent_project_id)
+
+ self.assertEqual(
+ result,
+ dict(
+ volumes=0,
+ snapshots=0,
+ gigabytes=0,
+ backups=0,
+ backup_gigabytes=0,
+ per_volume_gigabytes=0))
+
def _stub_quota_class_get_default(self):
# Stub out quota_class_get_default
def fake_qcgd(context):
)
self.stubs.Set(db, 'quota_class_get_default', fake_qcgd)
+ def _stub_quota_class_get_default_subproject(self):
+ # Stub out quota_class_get_default for subprojects
+ def fake_qcgd(context):
+ self.calls.append('quota_class_get_default')
+ return {}
+ self.stubs.Set(db, 'quota_class_get_default', fake_qcgd)
+
def _stub_volume_type_get_all(self):
def fake_vtga(context, inactive=False, filters=None):
return {}
self._stub_quota_class_get_all_by_name()
self._stub_quota_class_get_default()
+ def _stub_get_by_subproject(self):
+ def fake_qgabp(context, project_id):
+ self.calls.append('quota_get_all_by_project')
+ self.assertEqual(project_id, 'test_project')
+ return dict(volumes=10, gigabytes=50, reserved=0)
+
+ def fake_qugabp(context, project_id):
+ self.calls.append('quota_usage_get_all_by_project')
+ self.assertEqual(project_id, 'test_project')
+ return dict(volumes=dict(in_use=2, reserved=0),
+ gigabytes=dict(in_use=10, reserved=0))
+
+ self.stubs.Set(db, 'quota_get_all_by_project', fake_qgabp)
+ 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_subproject()
+
def test_get_project_quotas(self):
self._stub_get_by_project()
self._stub_volume_type_get_all()
reserved= 0)
))
+ def test_get_subproject_quotas(self):
+ self._stub_get_by_subproject()
+ self._stub_volume_type_get_all()
+ parent_project_id = 'test_parent_project_id'
+ result = self.driver.get_project_quotas(
+ FakeContext('test_project', None),
+ quota.QUOTAS.resources, 'test_project',
+ parent_project_id=parent_project_id)
+
+ self.assertEqual(self.calls, ['quota_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, ),
+ snapshots=dict(limit=0,
+ in_use=0,
+ reserved=0, ),
+ gigabytes=dict(limit=50,
+ in_use=10,
+ reserved=0, ),
+ backups=dict(limit=0,
+ in_use=0,
+ reserved=0, ),
+ backup_gigabytes=dict(limit=0,
+ in_use=0,
+ reserved=0, ),
+ per_volume_gigabytes=dict(in_use=0,
+ limit=0,
+ reserved= 0)
+ ))
+
def test_get_project_quotas_alt_context_no_class(self):
self._stub_get_by_project()
self._stub_volume_type_get_all()
def _stub_get_project_quotas(self):
def fake_get_project_quotas(context, resources, project_id,
quota_class=None, defaults=True,
- usages=True):
+ usages=True, parent_project_id=None):
self.calls.append('get_project_quotas')
return {k: dict(limit=v.default) for k, v in resources.items()}