diff options
Diffstat (limited to 'nova/api/openstack/compute/legacy_v2/contrib/quotas.py')
-rw-r--r-- | nova/api/openstack/compute/legacy_v2/contrib/quotas.py | 272 |
1 files changed, 0 insertions, 272 deletions
diff --git a/nova/api/openstack/compute/legacy_v2/contrib/quotas.py b/nova/api/openstack/compute/legacy_v2/contrib/quotas.py deleted file mode 100644 index 5672258854..0000000000 --- a/nova/api/openstack/compute/legacy_v2/contrib/quotas.py +++ /dev/null @@ -1,272 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_utils import strutils -import six.moves.urllib.parse as urlparse -import webob - -from nova.api.openstack import extensions -from nova.api.openstack import wsgi -import nova.context -from nova import db -from nova import exception -from nova.i18n import _ -from nova import objects -from nova import quota -from nova import utils - - -QUOTAS = quota.QUOTAS -NON_QUOTA_KEYS = ['tenant_id', 'id', 'force'] - -# Quotas that are only enabled by specific extensions -EXTENDED_QUOTAS = {'server_groups': 'os-server-group-quotas', - 'server_group_members': 'os-server-group-quotas'} - -authorize_update = extensions.extension_authorizer('compute', 'quotas:update') -authorize_show = extensions.extension_authorizer('compute', 'quotas:show') -authorize_delete = extensions.extension_authorizer('compute', 'quotas:delete') - - -class QuotaSetsController(wsgi.Controller): - - supported_quotas = [] - - def __init__(self, ext_mgr): - self.ext_mgr = ext_mgr - self.supported_quotas = QUOTAS.resources - for resource, extension in EXTENDED_QUOTAS.items(): - if not self.ext_mgr.is_loaded(extension): - self.supported_quotas.remove(resource) - - def _format_quota_set(self, project_id, quota_set): - """Convert the quota object to a result dict.""" - - if project_id: - result = dict(id=str(project_id)) - else: - result = {} - - for resource in self.supported_quotas: - if resource in quota_set: - result[resource] = quota_set[resource] - - return dict(quota_set=result) - - def _validate_quota_limit(self, resource, limit, minimum, maximum): - # NOTE: -1 is a flag value for unlimited, maximum value is limited - # by SQL standard integer type `INT` which is `0x7FFFFFFF`, it's a - # general value for SQL, using a hardcoded value here is not a - # `nice` way, but it seems like the only way for now: - # http://dev.mysql.com/doc/refman/5.0/en/integer-types.html - # http://www.postgresql.org/docs/9.1/static/datatype-numeric.html - if limit < -1 or limit > db.MAX_INT: - msg = (_("Quota limit %(limit)s for %(resource)s " - "must be in the range of -1 and %(max)s.") % - {'limit': limit, 'resource': resource, 'max': db.MAX_INT}) - raise webob.exc.HTTPBadRequest(explanation=msg) - - def conv_inf(value): - return float("inf") if value == -1 else value - - if conv_inf(limit) < conv_inf(minimum): - msg = (_("Quota limit %(limit)s for %(resource)s must " - "be greater than or equal to already used and " - "reserved %(minimum)s.") % - {'limit': limit, 'resource': resource, 'minimum': minimum}) - raise webob.exc.HTTPBadRequest(explanation=msg) - if conv_inf(limit) > conv_inf(maximum): - msg = (_("Quota limit %(limit)s for %(resource)s must be " - "less than or equal to %(maximum)s.") % - {'limit': limit, 'resource': resource, 'maximum': maximum}) - raise webob.exc.HTTPBadRequest(explanation=msg) - - def _get_quotas(self, context, id, user_id=None, usages=False): - if user_id: - values = QUOTAS.get_user_quotas(context, id, user_id, - usages=usages) - else: - values = QUOTAS.get_project_quotas(context, id, usages=usages) - - if usages: - return values - else: - return {k: v['limit'] for k, v in values.items()} - - def show(self, req, id): - context = req.environ['nova.context'] - authorize_show(context) - params = urlparse.parse_qs(req.environ.get('QUERY_STRING', '')) - user_id = None - if self.ext_mgr.is_loaded('os-user-quotas'): - user_id = params.get('user_id', [None])[0] - try: - nova.context.authorize_project_context(context, id) - return self._format_quota_set(id, - self._get_quotas(context, id, user_id=user_id)) - except exception.Forbidden: - raise webob.exc.HTTPForbidden() - - def update(self, req, id, body): - context = req.environ['nova.context'] - authorize_update(context) - try: - # NOTE(alex_xu): back-compatible with db layer hard-code admin - # permission checks. This has to be left only for API v2.0 because - # this version has to be stable even if it means that only admins - # can call this method while the policy could be changed. - nova.context.require_admin_context(context) - except exception.AdminRequired: - raise webob.exc.HTTPForbidden() - - project_id = id - - bad_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 - - user_id = None - if self.ext_mgr.is_loaded('os-user-quotas'): - # Update user quotas only if the extended is loaded - params = urlparse.parse_qs(req.environ.get('QUERY_STRING', '')) - user_id = params.get('user_id', [None])[0] - - try: - # NOTE(alex_xu): back-compatible with db layer hard-code admin - # permission checks. - nova.context.authorize_project_context(context, id) - settable_quotas = QUOTAS.get_settable_quotas(context, project_id, - user_id=user_id) - except exception.Forbidden: - raise webob.exc.HTTPForbidden() - - if not self.is_valid_body(body, 'quota_set'): - msg = _("quota_set not specified") - raise webob.exc.HTTPBadRequest(explanation=msg) - quota_set = body['quota_set'] - - # NOTE(dims): Pass #1 - In this loop for quota_set.items(), we figure - # out if we have bad keys or if we need to forcibly set quotas or - # if some of the values for the quotas can be converted to integers. - for key, value in quota_set.items(): - if (key not in self.supported_quotas - and 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: - utils.validate_integer(value, key) - except exception.InvalidInput as e: - raise webob.exc.HTTPBadRequest( - explanation=e.format_message()) - - if bad_keys: - msg = _("Bad key(s) %s in quota_set") % ",".join(bad_keys) - raise webob.exc.HTTPBadRequest(explanation=msg) - - # NOTE(dims): Pass #2 - In this loop for quota_set.items(), based on - # force_update flag we validate the quota limit. A loop just for - # the validation of min/max values ensure that we can bail out if - # any of the items in the set is bad. - valid_quotas = {} - for key, value in quota_set.items(): - if key in NON_QUOTA_KEYS or (not value and value != 0): - continue - # 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 not force_update: - minimum = settable_quotas[key]['minimum'] - maximum = settable_quotas[key]['maximum'] - self._validate_quota_limit(key, value, minimum, maximum) - valid_quotas[key] = value - - # NOTE(dims): Pass #3 - At this point we know that all the keys and - # values are valid and we can iterate and update them all in one - # shot without having to worry about rolling back etc as we have done - # the validation up front in the 2 loops above. - for key, value in valid_quotas.items(): - try: - objects.Quotas.create_limit(context, project_id, - key, value, user_id=user_id) - except exception.QuotaExists: - objects.Quotas.update_limit(context, project_id, - key, value, user_id=user_id) - values = self._get_quotas(context, id, user_id=user_id) - return self._format_quota_set(None, values) - - def defaults(self, req, id): - context = req.environ['nova.context'] - authorize_show(context) - values = QUOTAS.get_defaults(context) - return self._format_quota_set(id, values) - - def delete(self, req, id): - if self.ext_mgr.is_loaded('os-extended-quotas'): - context = req.environ['nova.context'] - authorize_delete(context) - params = urlparse.parse_qs(req.environ.get('QUERY_STRING', '')) - user_id = params.get('user_id', [None])[0] - if user_id and not self.ext_mgr.is_loaded('os-user-quotas'): - raise webob.exc.HTTPNotFound() - try: - nova.context.authorize_project_context(context, id) - # NOTE(alex_xu): back-compatible with db layer hard-code admin - # permission checks. This has to be left only for API v2.0 - # because this version has to be stable even if it means that - # only admins can call this method while the policy could be - # changed. - nova.context.require_admin_context(context) - if user_id: - QUOTAS.destroy_all_by_project_and_user(context, - id, user_id) - else: - QUOTAS.destroy_all_by_project(context, id) - return webob.Response(status_int=202) - except exception.Forbidden: - raise webob.exc.HTTPForbidden() - raise webob.exc.HTTPNotFound() - - -class Quotas(extensions.ExtensionDescriptor): - """Quotas management support.""" - - name = "Quotas" - alias = "os-quota-sets" - namespace = "http://docs.openstack.org/compute/ext/quotas-sets/api/v1.1" - updated = "2011-08-08T00:00:00Z" - - def get_resources(self): - resources = [] - - res = extensions.ResourceExtension('os-quota-sets', - QuotaSetsController(self.ext_mgr), - member_actions={'defaults': 'GET'}) - resources.append(res) - - return resources |