summaryrefslogtreecommitdiffstats
path: root/nova/api
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/api
parent51002f0d0f85f077bbbfed1d151df59240775ff8 (diff)
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/api')
-rw-r--r--nova/api/openstack/compute/contrib/quotas.py78
-rw-r--r--nova/api/openstack/compute/limits.py15
2 files changed, 79 insertions, 14 deletions
diff --git a/nova/api/openstack/compute/contrib/quotas.py b/nova/api/openstack/compute/contrib/quotas.py
index 33584badc..56583ff79 100644
--- a/nova/api/openstack/compute/contrib/quotas.py
+++ b/nova/api/openstack/compute/contrib/quotas.py
@@ -15,6 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import urlparse
import webob
from nova.api.openstack import extensions
@@ -24,13 +25,15 @@ from nova import db
from nova.db.sqlalchemy import api as sqlalchemy_api
from nova import exception
from nova import quota
+from nova import utils
QUOTAS = quota.QUOTAS
-authorize_update = extensions.extension_authorizer('compute', 'quotas:update')
-authorize_show = extensions.extension_authorizer('compute', 'quotas:show')
+def authorize_action(context, action_name):
+ action = 'quotas:%s' % action_name
+ extensions.extension_authorizer('compute', action)(context)
class QuotaTemplate(xmlutil.TemplateBuilder):
@@ -57,51 +60,102 @@ class QuotaSetsController(object):
return dict(quota_set=result)
- def _validate_quota_limit(self, limit):
+ def _validate_quota_limit(self, limit, remain, quota):
# NOTE: -1 is a flag value for unlimited
if limit < -1:
msg = _("Quota limit must be -1 or greater.")
raise webob.exc.HTTPBadRequest(explanation=msg)
- def _get_quotas(self, context, id, usages=False):
- values = QUOTAS.get_project_quotas(context, id, usages=usages)
+ # Quota limit must be less than the remains of the project.
+ if remain != -1 and remain < limit - quota:
+ msg = _("Quota limit exceed the remains of the project.")
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
+ def _get_quotas(self, context, id, user_id=None, remaining=False,
+ usages=False):
+ # Get the remaining quotas for a project.
+ if remaining:
+ values = QUOTAS.get_remaining_quotas(context, id)
+ return values
+
+ if user_id:
+ # If user_id, return quotas for the given user.
+ values = QUOTAS.get_user_quotas(context, user_id, id,
+ usages=usages)
+ else:
+ values = QUOTAS.get_project_quotas(context, id, usages=usages)
if usages:
return values
else:
return dict((k, v['limit']) for k, v in values.items())
+ def _request_params(self, req):
+ qs = req.environ.get('QUERY_STRING', '')
+ return urlparse.parse_qs(qs)
+
@wsgi.serializers(xml=QuotaTemplate)
def show(self, req, id):
context = req.environ['nova.context']
- authorize_show(context)
+ authorize_action(context, 'show')
+ params = self._request_params(req)
+ remaining = False
+ if 'remaining' in params:
+ remaining = utils.bool_from_str(params["remaining"][0])
+ user_id = None
+ if 'user_id' in params:
+ user_id = params["user_id"][0]
try:
sqlalchemy_api.authorize_project_context(context, id)
- return self._format_quota_set(id, self._get_quotas(context, id))
+ return self._format_quota_set(id,
+ self._get_quotas(context, id, user_id, remaining))
except exception.NotAuthorized:
raise webob.exc.HTTPForbidden()
@wsgi.serializers(xml=QuotaTemplate)
def update(self, req, id, body):
context = req.environ['nova.context']
- authorize_update(context)
+ params = self._request_params(req)
project_id = id
+ user_id = None
+ remains = {}
+ quotas = {}
+ if 'user_id' in params:
+ # Project admins are able to modify per-user quotas.
+ authorize_action(context, 'update_for_user')
+ user_id = params["user_id"][0]
+ remains = self._get_quotas(context, project_id, remaining=True)
+ quotas = db.quota_get_all_by_user(context, user_id, project_id)
+ else:
+ # Only admins are able to modify per-project quotas.
+ authorize_action(context, 'update_for_project')
+
for key in body['quota_set'].keys():
if key in QUOTAS:
value = int(body['quota_set'][key])
- self._validate_quota_limit(value)
try:
- db.quota_update(context, project_id, key, value)
+ if user_id:
+ self._validate_quota_limit(value, remains.get(key, 0),
+ quotas.get(key, 0))
+ db.quota_update_for_user(context, user_id,
+ project_id, key, value)
+ else:
+ self._validate_quota_limit(value, remains.get(key, -1),
+ quotas.get(key, 0))
+ db.quota_update(context, project_id, key, value)
except exception.ProjectQuotaNotFound:
db.quota_create(context, project_id, key, value)
+ except exception.UserQuotaNotFound:
+ db.quota_create_for_user(context, user_id,
+ project_id, key, value)
except exception.AdminRequired:
raise webob.exc.HTTPForbidden()
- return {'quota_set': self._get_quotas(context, id)}
+ return {'quota_set': self._get_quotas(context, id, user_id)}
@wsgi.serializers(xml=QuotaTemplate)
def defaults(self, req, id):
context = req.environ['nova.context']
- authorize_show(context)
+ authorize_action(context, 'show')
return self._format_quota_set(id, QUOTAS.get_defaults(context))
diff --git a/nova/api/openstack/compute/limits.py b/nova/api/openstack/compute/limits.py
index c0ef65670..990c08a10 100644
--- a/nova/api/openstack/compute/limits.py
+++ b/nova/api/openstack/compute/limits.py
@@ -23,6 +23,7 @@ import httplib
import math
import re
import time
+import urlparse
import webob.dec
import webob.exc
@@ -85,8 +86,18 @@ class LimitsController(object):
Return all global and rate limit information.
"""
context = req.environ['nova.context']
- quotas = QUOTAS.get_project_quotas(context, context.project_id,
- usages=False)
+ qs = req.environ.get('QUERY_STRING', '')
+ params = urlparse.parse_qs(qs)
+ if 'user_id' in params:
+ user_id = params["user_id"][0]
+ quotas = QUOTAS.get_user_quotas(context, user_id,
+ context.project_id,
+ usages=False)
+ else:
+ quotas = QUOTAS.get_project_quotas(context,
+ context.project_id,
+ usages=False)
+
abs_limits = dict((k, v['limit']) for k, v in quotas.items())
rate_limits = req.environ.get("nova.limits", [])