summaryrefslogtreecommitdiffstats
path: root/nova/api
diff options
context:
space:
mode:
authorgengjh <gengjh@cn.ibm.com>2013-04-01 22:11:50 +0800
committergengjh <gengjh@cn.ibm.com>2013-06-13 15:36:08 +0800
commitd5bbfad3d06e8801d70f4efce84c9504519efbc3 (patch)
treef06bbf29dea8206525bd388f0d05c36fb7916d3d /nova/api
parente0142d0f63bf64a07db3bd3b840fc2072d2e6ca3 (diff)
downloadnova-d5bbfad3d06e8801d70f4efce84c9504519efbc3.tar.gz
nova-d5bbfad3d06e8801d70f4efce84c9504519efbc3.tar.xz
nova-d5bbfad3d06e8801d70f4efce84c9504519efbc3.zip
Enhance the validation of the quotas update
Need check whether the already used and reserved exceeds the new quota before update it. DocImpact Implements a validation to validate whether already used and reserved quota exceeds the new quota when run 'nova quota-update', it will throw error if the quota exceeds. This check will be ignored if admin want to force update when run 'nova quota-update' with additional option '--force'. This validation help admin to be aware of whether the quotas are oversold when they try to update quota and also provide an option '--force' to allow admin force update the quotas. Fix bug 1160749 Change-Id: Iba3cee0f0d92cf2e6d64bc83830b0091992d1ee9
Diffstat (limited to 'nova/api')
-rw-r--r--nova/api/openstack/compute/contrib/extended_quotas.py9
-rw-r--r--nova/api/openstack/compute/contrib/quotas.py71
2 files changed, 65 insertions, 15 deletions
diff --git a/nova/api/openstack/compute/contrib/extended_quotas.py b/nova/api/openstack/compute/contrib/extended_quotas.py
index 431b95e9b..a21888c4a 100644
--- a/nova/api/openstack/compute/contrib/extended_quotas.py
+++ b/nova/api/openstack/compute/contrib/extended_quotas.py
@@ -17,9 +17,12 @@ from nova.api.openstack import extensions
class Extended_quotas(extensions.ExtensionDescriptor):
- """Adds ability for admins to delete quota."""
+ """Adds ability for admins to delete quota
+ and optionally force the update Quota command.
+ """
name = "ExtendedQuotas"
alias = "os-extended-quotas"
- namespace = "http://docs.openstack.org/compute/ext/quota-delete/api/v1.1"
- updated = "2013-05-23T00:00:00+00:00"
+ namespace = ("http://docs.openstack.org/compute/ext/extended_quotas"
+ "/api/v1.1")
+ updated = "2013-06-09T00:00:00+00:00"
diff --git a/nova/api/openstack/compute/contrib/quotas.py b/nova/api/openstack/compute/contrib/quotas.py
index 0a2453038..a0740ebe5 100644
--- a/nova/api/openstack/compute/contrib/quotas.py
+++ b/nova/api/openstack/compute/contrib/quotas.py
@@ -24,11 +24,13 @@ import nova.context
from nova import db
from nova import exception
from nova.openstack.common import log as logging
+from nova.openstack.common import strutils
from nova import quota
QUOTAS = quota.QUOTAS
LOG = logging.getLogger(__name__)
+NON_QUOTA_KEYS = ['tenant_id', 'id', 'force']
authorize_update = extensions.extension_authorizer('compute', 'quotas:update')
@@ -94,26 +96,71 @@ class QuotaSetsController(object):
project_id = id
bad_keys = []
- for key in body['quota_set'].keys():
+
+ # By default, we can force update the quota if the extended
+ # is not loaded
+ force_update = True
+ extended_loaded = False
+ if self.ext_mgr.is_loaded('os-extended-quotas'):
+ # force optional has been enabled, the default value of
+ # force_update need to be changed to False
+ extended_loaded = True
+ force_update = False
+
+ for key, value in body['quota_set'].items():
if (key not in QUOTAS and
- key != 'tenant_id' and
- key != 'id'):
+ key not in NON_QUOTA_KEYS):
bad_keys.append(key)
+ continue
+ if key == 'force' and extended_loaded:
+ # only check the force optional when the extended has
+ # been loaded
+ force_update = strutils.bool_from_string(value)
+ elif key not in NON_QUOTA_KEYS and value:
+ try:
+ value = int(value)
+ except (ValueError, TypeError):
+ msg = _("Quota '%(value)s' for %(key)s should be "
+ "integer.") % locals()
+ LOG.warn(msg)
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+ self._validate_quota_limit(value)
+
+ LOG.debug(_("force update quotas: %s") % force_update)
if len(bad_keys) > 0:
msg = _("Bad key(s) %s in quota_set") % ",".join(bad_keys)
raise webob.exc.HTTPBadRequest(explanation=msg)
- for key in body['quota_set'].keys():
- try:
- value = int(body['quota_set'][key])
- except (ValueError, TypeError):
- LOG.warn(_("Quota for %s should be integer.") % key)
- # NOTE(hzzhoushaoyu): Do not prevent valid value to be
- # updated. If raise BadRequest, some may be updated and
- # others may be not.
+ try:
+ project_quota = self._get_quotas(context, id, True)
+ except exception.NotAuthorized:
+ raise webob.exc.HTTPForbidden()
+
+ for key, value in body['quota_set'].items():
+ if key in NON_QUOTA_KEYS or not value:
continue
- self._validate_quota_limit(value)
+ # validate whether already used and reserved exceeds the new
+ # quota, this check will be ignored if admin want to force
+ # update
+ value = int(value)
+ if force_update is not True and value >= 0:
+ quota_value = project_quota.get(key)
+ if quota_value and quota_value['limit'] >= 0:
+ quota_used = (quota_value['in_use'] +
+ quota_value['reserved'])
+ LOG.debug(_("Quota %(key)s used: %(quota_used)s, "
+ "value: %(value)s."),
+ {'key': key, 'quota_used': quota_used,
+ 'value': value})
+ if quota_used > value:
+ msg = (_("Quota value %(value)s for %(key)s are "
+ "greater than already used and reserved "
+ "%(quota_used)s") %
+ {'value': value, 'key': key,
+ 'quota_used': quota_used})
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
try:
db.quota_update(context, project_id, key, value)
except exception.ProjectQuotaNotFound: