summaryrefslogtreecommitdiffstats
path: root/nova/quota.py
diff options
context:
space:
mode:
authorKylin CG <kylin7.sg@gmail.com>2012-06-04 22:21:41 +0800
committerKylin CG <kylin7.sg@gmail.com>2012-08-06 23:55:22 +0800
commit391f345dfff174108e330de1ed4c7ed18f8ff923 (patch)
treef80dd112f40d94cdbb76b578a4b3b84c8915edef /nova/quota.py
parent51002f0d0f85f077bbbfed1d151df59240775ff8 (diff)
downloadnova-391f345dfff174108e330de1ed4c7ed18f8ff923.tar.gz
nova-391f345dfff174108e330de1ed4c7ed18f8ff923.tar.xz
nova-391f345dfff174108e330de1ed4c7ed18f8ff923.zip
Adds per-user-quotas support for more detailed quotas management
Implements blueprint per-user-quotas. Based on the original quotas structure. NOTE: quota_instances, quota_cores, quota_ram, quota_volumes, quota_gigabytes, quota_key_pairs and quota_security_groups are supported per user. Allow 'projectadmin' role to access the user quota setting methods. Add commands 'nova-manage quota project/user' for quotas management. Change-Id: I07a39499432571fedd819c53ae414240cefc3354
Diffstat (limited to 'nova/quota.py')
-rw-r--r--nova/quota.py219
1 files changed, 184 insertions, 35 deletions
diff --git a/nova/quota.py b/nova/quota.py
index d3ba0aa02..44e3c593d 100644
--- a/nova/quota.py
+++ b/nova/quota.py
@@ -101,6 +101,11 @@ class DbQuotaDriver(object):
return db.quota_get(context, project_id, resource)
+ def get_by_user(self, context, user_id, project_id, resource):
+ """Get a specific quota by user."""
+
+ return db.quota_get_for_user(context, user_id, project_id, resource)
+
def get_by_class(self, context, quota_class, resource):
"""Get a specific quota by quota class."""
@@ -143,16 +148,16 @@ class DbQuotaDriver(object):
return quotas
- def get_project_quotas(self, context, resources, project_id,
- quota_class=None, defaults=True,
- usages=True):
+ def _process_quotas(self, context, resources, project_id, quotas,
+ quota_class=None, defaults=True, usages=None):
"""
- Given a list of resources, retrieve the quotas for the given
- project.
+ Given a list of resources, process the quotas for the given
+ quotas and usages.
:param context: The request context, for access checks.
:param resources: A dictionary of the registered resources.
:param project_id: The ID of the project to return quotas for.
+ :param quotas: The quotas dictionary need to be processed.
:param quota_class: If project_id != context.project_id, the
quota class cannot be determined. This
parameter allows it to be specified. It
@@ -162,16 +167,11 @@ class DbQuotaDriver(object):
default value, if there is no value from the
quota class) will be reported if there is no
specific value for the resource.
- :param usages: If True, the current in_use and reserved counts
+ :param usages: If not None, the current in_use and reserved counts
will also be returned.
"""
- quotas = {}
- project_quotas = db.quota_get_all_by_project(context, project_id)
- if usages:
- project_usages = db.quota_usage_get_all_by_project(context,
- project_id)
-
+ modified_quotas = {}
# Get the quotas for the appropriate class. If the project ID
# matches the one in the context, we use the quota_class from
# the context, otherwise, we use the provided quota_class (if
@@ -185,11 +185,11 @@ class DbQuotaDriver(object):
for resource in resources.values():
# Omit default/quota class values
- if not defaults and resource.name not in project_quotas:
+ if not defaults and resource.name not in quotas:
continue
- quotas[resource.name] = dict(
- limit=project_quotas.get(resource.name, class_quotas.get(
+ modified_quotas[resource.name] = dict(
+ limit=quotas.get(resource.name, class_quotas.get(
resource.name, resource.default)),
)
@@ -197,13 +197,96 @@ class DbQuotaDriver(object):
# internal consumer of this interface wants to access the
# usages directly from inside a transaction.
if usages:
- usage = project_usages.get(resource.name, {})
- quotas[resource.name].update(
+ usage = usages.get(resource.name, {})
+ modified_quotas[resource.name].update(
in_use=usage.get('in_use', 0),
reserved=usage.get('reserved', 0),
)
- return quotas
+ return modified_quotas
+
+ def get_project_quotas(self, context, resources, project_id,
+ quota_class=None, defaults=True,
+ usages=True):
+ """
+ Given a list of resources, retrieve the quotas for the given
+ project.
+
+ :param context: The request context, for access checks.
+ :param resources: A dictionary of the registered resources.
+ :param project_id: The ID of the project to return quotas for.
+ :param quota_class: If project_id != context.project_id, the
+ quota class cannot be determined. This
+ parameter allows it to be specified. It
+ will be ignored if project_id ==
+ context.project_id.
+ :param defaults: If True, the quota class value (or the
+ default value, if there is no value from the
+ quota class) will be reported if there is no
+ specific value for the resource.
+ :param usages: If True, the current in_use and reserved counts
+ will also be returned.
+ """
+
+ project_quotas = db.quota_get_all_by_project(context, project_id)
+
+ project_usages = None
+ if usages:
+ project_usages = db.quota_usage_get_all_by_project(context,
+ project_id)
+
+ return self._process_quotas(context, resources,
+ project_id, project_quotas,
+ quota_class=quota_class,
+ defaults=defaults,
+ usages=project_usages)
+
+ def get_user_quotas(self, context, resources, user_id, project_id,
+ quota_class=None, defaults=True,
+ usages=True):
+ """
+ Given a list of resources, retrieve the quotas for the given
+ user.
+
+ :param context: The request context, for access checks.
+ :param resources: A dictionary of the registered resources.
+ :param project_id: The ID of the project to return quotas for.
+ :param user_id: The ID of the user to return quotas for.
+ :param quota_class: If project_id != context.project_id, the
+ quota class cannot be determined. This
+ parameter allows it to be specified. It
+ will be ignored if project_id ==
+ context.project_id.
+ :param defaults: If True, the quota class value (or the
+ default value, if there is no value from the
+ quota class) will be reported if there is no
+ specific value for the resource.
+ :param usages: If True, the current in_use and reserved counts
+ will also be returned.
+ """
+
+ user_quotas = db.quota_get_all_by_user(context, user_id, project_id)
+
+ user_usages = None
+ if usages:
+ user_usages = db.quota_usage_get_all_by_user(context,
+ user_id,
+ project_id)
+
+ return self._process_quotas(context, resources,
+ project_id, user_quotas,
+ quota_class=quota_class,
+ defaults=defaults,
+ usages=user_usages)
+
+ def get_remaining_quotas(self, context, project_id, resources):
+ """Get the remaining quotas for the given project."""
+ defaults = self.get_defaults(context, resources)
+ quotas = db.quota_get_remaining(context, project_id)
+ for key in defaults.keys():
+ if key in quotas:
+ defaults[key] = quotas[key]
+ return defaults
def _get_quotas(self, context, resources, keys, has_sync):
"""
@@ -235,9 +318,10 @@ class DbQuotaDriver(object):
raise exception.QuotaResourceUnknown(unknown=sorted(unknown))
# Grab and return the quotas (without usages)
- quotas = self.get_project_quotas(context, sub_resources,
- context.project_id,
- context.quota_class, usages=False)
+ quotas = self.get_user_quotas(context, sub_resources,
+ context.user_id,
+ context.project_id,
+ context.quota_class, usages=False)
return dict((k, v['limit']) for k, v in quotas.items())
@@ -368,6 +452,18 @@ class DbQuotaDriver(object):
db.quota_destroy_all_by_project(context, project_id)
+ def destroy_all_by_user(self, context, user_id, project_id):
+ """
+ Destroy all quotas, usages, and reservations associated with a
+ user.
+
+ :param context: The request context, for access checks.
+ :param user_id: The ID of the user being deleted.
+ :param project_id: The ID of the project being deleted.
+ """
+
+ db.quota_destroy_all_by_user(context, user_id, project_id)
+
def expire(self, context):
"""Expire reservations.
@@ -566,6 +662,11 @@ class QuotaEngine(object):
return self._driver.get_by_project(context, project_id, resource)
+ def get_by_user(self, context, user_id, project_id, resource):
+ """Get a specific quota by user."""
+
+ return self._driver.get_by_user(context, user_id, project_id, resource)
+
def get_by_class(self, context, quota_class, resource):
"""Get a specific quota by quota class."""
@@ -611,10 +712,46 @@ class QuotaEngine(object):
"""
return self._driver.get_project_quotas(context, self._resources,
- project_id,
- quota_class=quota_class,
- defaults=defaults,
- usages=usages)
+ project_id,
+ quota_class=quota_class,
+ defaults=defaults,
+ usages=usages)
+
+ def get_user_quotas(self, context, user_id, project_id,
+ quota_class=None, defaults=True,
+ usages=True):
+ """Retrieve the quotas for the given user.
+
+ :param context: The request context, for access checks.
+ :param user_id: The ID of the user to return quotas for.
+ :param project_id: The ID of the project to return quotas for.
+ :param quota_class: If project_id != context.project_id, the
+ quota class cannot be determined. This
+ parameter allows it to be specified.
+ :param defaults: If True, the quota class value (or the
+ default value, if there is no value from the
+ quota class) will be reported if there is no
+ specific value for the resource.
+ :param usages: If True, the current in_use and reserved counts
+ will also be returned.
+ """
+
+ return self._driver.get_user_quotas(context, self._resources,
+ user_id,
+ project_id,
+ quota_class=quota_class,
+ defaults=defaults,
+ usages=usages)
+
+ def get_remaining_quotas(self, context, project_id):
+ """Retrieve the remaining quotas for the given project.
+
+ :param context: The request context, for access checks.
+ :param project_id: The ID of the project to return quotas for.
+ """
+
+ return self._driver.get_remaining_quotas(context, project_id,
+ self._resources)
def count(self, context, resource, *args, **kwargs):
"""Count a resource.
@@ -745,6 +882,18 @@ class QuotaEngine(object):
self._driver.destroy_all_by_project(context, project_id)
+ def destroy_all_by_user(self, context, user_id, project_id):
+ """
+ Destroy all quotas, usages, and reservations associated with a
+ user.
+
+ :param context: The request context, for access checks.
+ :param user_id: The ID of the user being deleted.
+ :param project_id: The ID of the project being deleted.
+ """
+
+ self._driver.destroy_all_by_user(context, user_id, project_id)
+
def expire(self, context):
"""Expire reservations.
@@ -761,26 +910,26 @@ class QuotaEngine(object):
return sorted(self._resources.keys())
-def _sync_instances(context, project_id, session):
+def _sync_instances(context, user_id, project_id, session):
return dict(zip(('instances', 'cores', 'ram'),
- db.instance_data_get_for_project(
- context, project_id, session=session)))
+ db.instance_data_get_for_user(
+ context, user_id, project_id, session=session)))
-def _sync_volumes(context, project_id, session):
+def _sync_volumes(context, user_id, project_id, session):
return dict(zip(('volumes', 'gigabytes'),
- db.volume_data_get_for_project(
- context, project_id, session=session)))
+ db.volume_data_get_for_user(
+ context, user_id, project_id, session=session)))
-def _sync_floating_ips(context, project_id, session):
+def _sync_floating_ips(context, user_id, project_id, session):
return dict(floating_ips=db.floating_ip_count_by_project(
context, project_id, session=session))
-def _sync_security_groups(context, project_id, session):
- return dict(security_groups=db.security_group_count_by_project(
- context, project_id, session=session))
+def _sync_security_groups(context, user_id, project_id, session):
+ return dict(security_groups=db.security_group_count_by_user(
+ context, user_id, project_id, session=session))
QUOTAS = QuotaEngine()