summaryrefslogtreecommitdiff
path: root/nova/api/openstack/compute/legacy_v2/contrib/quotas.py
diff options
context:
space:
mode:
Diffstat (limited to 'nova/api/openstack/compute/legacy_v2/contrib/quotas.py')
-rw-r--r--nova/api/openstack/compute/legacy_v2/contrib/quotas.py272
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