diff options
author | gengjh <gengjh@cn.ibm.com> | 2013-04-01 22:11:50 +0800 |
---|---|---|
committer | gengjh <gengjh@cn.ibm.com> | 2013-06-13 15:36:08 +0800 |
commit | d5bbfad3d06e8801d70f4efce84c9504519efbc3 (patch) | |
tree | f06bbf29dea8206525bd388f0d05c36fb7916d3d /nova/api | |
parent | e0142d0f63bf64a07db3bd3b840fc2072d2e6ca3 (diff) | |
download | nova-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.py | 9 | ||||
-rw-r--r-- | nova/api/openstack/compute/contrib/quotas.py | 71 |
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: |