diff options
| author | Kevin L. Mitchell <kevin.mitchell@rackspace.com> | 2012-05-11 15:30:14 -0500 |
|---|---|---|
| committer | Kevin L. Mitchell <kevin.mitchell@rackspace.com> | 2012-05-23 10:17:41 -0500 |
| commit | b7f0946bbd071bc76809eca440ab7d21a03eb1a3 (patch) | |
| tree | 4f46ad3896cb89c8747bdf09e3f33a476eccbf16 /nova/api | |
| parent | 7e15d4e28f98e13f0ea7399787c50839139d8492 (diff) | |
| download | nova-b7f0946bbd071bc76809eca440ab7d21a03eb1a3.tar.gz nova-b7f0946bbd071bc76809eca440ab7d21a03eb1a3.tar.xz nova-b7f0946bbd071bc76809eca440ab7d21a03eb1a3.zip | |
Finish quota refactor.
Finishes quota refactoring by making use of the new quota infrastructure.
Partially implements blueprint quota-refactor (the final piece is to
remove the old quota architecture).
This change is fairly substantial. To make it easier to review, it has been
broken up into 3 parts. This is the second part.
Change-Id: I1c8b43198f0d44e9e13a45575361aa043fd0639e
Diffstat (limited to 'nova/api')
| -rw-r--r-- | nova/api/ec2/cloud.py | 49 | ||||
| -rw-r--r-- | nova/api/openstack/common.py | 8 | ||||
| -rw-r--r-- | nova/api/openstack/compute/contrib/quota_classes.py | 15 | ||||
| -rw-r--r-- | nova/api/openstack/compute/contrib/quotas.py | 27 | ||||
| -rw-r--r-- | nova/api/openstack/compute/contrib/security_groups.py | 60 | ||||
| -rw-r--r-- | nova/api/openstack/compute/limits.py | 7 |
6 files changed, 120 insertions, 46 deletions
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index b077d55aa..13c91cf19 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -40,6 +40,7 @@ from nova import flags from nova.image import s3 from nova import log as logging from nova import network +from nova.openstack.common import excutils from nova.openstack.common import importutils from nova import quota from nova import utils @@ -50,6 +51,8 @@ FLAGS = flags.FLAGS LOG = logging.getLogger(__name__) +QUOTAS = quota.QUOTAS + def validate_ec2_id(val): if not validator.validate_str()(val): @@ -713,10 +716,11 @@ class CloudController(object): raise exception.EC2APIError(err % values_for_rule) postvalues.append(values_for_rule) - allowed = quota.allowed_security_group_rules(context, - security_group['id'], - 1) - if allowed < 1: + count = QUOTAS.count(context, 'security_group_rules', + security_group['id']) + try: + QUOTAS.limit_check(context, security_group_rules=count + 1) + except exception.OverQuota: msg = _("Quota exceeded, too many security group rules.") raise exception.EC2APIError(msg) @@ -777,17 +781,26 @@ class CloudController(object): msg = _('group %s already exists') raise exception.EC2APIError(msg % group_name) - if quota.allowed_security_groups(context, 1) < 1: + try: + reservations = QUOTAS.reserve(context, security_groups=1) + except exception.OverQuota: msg = _("Quota exceeded, too many security groups.") raise exception.EC2APIError(msg) - group = {'user_id': context.user_id, - 'project_id': context.project_id, - 'name': group_name, - 'description': group_description} - group_ref = db.security_group_create(context, group) + try: + group = {'user_id': context.user_id, + 'project_id': context.project_id, + 'name': group_name, + 'description': group_description} + group_ref = db.security_group_create(context, group) + + self.sgh.trigger_security_group_create_refresh(context, group) - self.sgh.trigger_security_group_create_refresh(context, group) + # Commit the reservation + QUOTAS.commit(context, reservations) + except Exception: + with excutils.save_and_reraise_exception(): + QUOTAS.rollback(context, reservations) return {'securityGroupSet': [self._format_security_group(context, group_ref)]} @@ -810,11 +823,25 @@ class CloudController(object): raise notfound(security_group_id=group_id) if db.security_group_in_use(context, security_group.id): raise exception.InvalidGroup(reason="In Use") + + # Get reservations + try: + reservations = QUOTAS.reserve(context, security_groups=-1) + except Exception: + reservations = None + LOG.exception(_("Failed to update usages deallocating " + "security group")) + LOG.audit(_("Delete security group %s"), group_name, context=context) db.security_group_destroy(context, security_group.id) self.sgh.trigger_security_group_destroy_refresh(context, security_group.id) + + # Commit the reservations + if reservations: + QUOTAS.commit(context, reservations) + return True def get_console_output(self, context, instance_id, **kwargs): diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 1eae7002b..3756f91a8 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -27,6 +27,7 @@ from nova.api.openstack import wsgi from nova.api.openstack import xmlutil from nova.compute import task_states from nova.compute import vm_states +from nova import exception from nova import flags from nova import log as logging from nova.network import model as network_model @@ -35,6 +36,7 @@ from nova import quota LOG = logging.getLogger(__name__) FLAGS = flags.FLAGS +QUOTAS = quota.QUOTAS XML_NS_V11 = 'http://docs.openstack.org/compute/api/v1.1' @@ -272,9 +274,9 @@ def get_version_from_href(href): def check_img_metadata_properties_quota(context, metadata): if metadata is None: return - num_metadata = len(metadata) - quota_metadata = quota.allowed_metadata_items(context, num_metadata) - if quota_metadata < num_metadata: + try: + QUOTAS.limit_check(context, metadata_items=len(metadata)) + except exception.OverQuota: expl = _("Image metadata limit exceeded") raise webob.exc.HTTPRequestEntityTooLarge(explanation=expl, headers={'Retry-After': 0}) diff --git a/nova/api/openstack/compute/contrib/quota_classes.py b/nova/api/openstack/compute/contrib/quota_classes.py index 04d0841ef..437b58005 100644 --- a/nova/api/openstack/compute/contrib/quota_classes.py +++ b/nova/api/openstack/compute/contrib/quota_classes.py @@ -23,6 +23,9 @@ from nova import exception from nova import quota +QUOTAS = quota.QUOTAS + + authorize = extensions.extension_authorizer('compute', 'quota_classes') @@ -32,7 +35,7 @@ class QuotaClassTemplate(xmlutil.TemplateBuilder): selector='quota_class_set') root.set('id') - for resource in quota.quota_resources: + for resource in QUOTAS.resources: elem = xmlutil.SubTemplateElement(root, resource) elem.text = resource @@ -46,7 +49,7 @@ class QuotaClassSetsController(object): result = dict(id=str(quota_class)) - for resource in quota.quota_resources: + for resource in QUOTAS.resources: result[resource] = quota_set[resource] return dict(quota_class_set=result) @@ -58,7 +61,7 @@ class QuotaClassSetsController(object): try: db.sqlalchemy.api.authorize_quota_class_context(context, id) return self._format_quota_set(id, - quota.get_class_quotas(context, id)) + QUOTAS.get_class_quotas(context, id)) except exception.NotAuthorized: raise webob.exc.HTTPForbidden() @@ -68,7 +71,7 @@ class QuotaClassSetsController(object): authorize(context) quota_class = id for key in body['quota_class_set'].keys(): - if key in quota.quota_resources: + if key in QUOTAS: value = int(body['quota_class_set'][key]) try: db.quota_class_update(context, quota_class, key, value) @@ -76,8 +79,8 @@ class QuotaClassSetsController(object): db.quota_class_create(context, quota_class, key, value) except exception.AdminRequired: raise webob.exc.HTTPForbidden() - return {'quota_class_set': quota.get_class_quotas(context, - quota_class)} + return {'quota_class_set': QUOTAS.get_class_quotas(context, + quota_class)} class Quota_classes(extensions.ExtensionDescriptor): diff --git a/nova/api/openstack/compute/contrib/quotas.py b/nova/api/openstack/compute/contrib/quotas.py index 382649f4c..361335927 100644 --- a/nova/api/openstack/compute/contrib/quotas.py +++ b/nova/api/openstack/compute/contrib/quotas.py @@ -26,6 +26,9 @@ from nova import exception from nova import quota +QUOTAS = quota.QUOTAS + + authorize = extensions.extension_authorizer('compute', 'quotas') @@ -34,7 +37,7 @@ class QuotaTemplate(xmlutil.TemplateBuilder): root = xmlutil.TemplateElement('quota_set', selector='quota_set') root.set('id') - for resource in quota.quota_resources: + for resource in QUOTAS.resources: elem = xmlutil.SubTemplateElement(root, resource) elem.text = resource @@ -48,7 +51,7 @@ class QuotaSetsController(object): result = dict(id=str(project_id)) - for resource in quota.quota_resources: + for resource in QUOTAS.resources: result[resource] = quota_set[resource] return dict(quota_set=result) @@ -59,14 +62,21 @@ class QuotaSetsController(object): 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) + + if usages: + return values + else: + return dict((k, v['limit']) for k, v in values.items()) + @wsgi.serializers(xml=QuotaTemplate) def show(self, req, id): context = req.environ['nova.context'] authorize(context) try: sqlalchemy_api.authorize_project_context(context, id) - return self._format_quota_set(id, - quota.get_project_quotas(context, id)) + return self._format_quota_set(id, self._get_quotas(context, id)) except exception.NotAuthorized: raise webob.exc.HTTPForbidden() @@ -76,7 +86,7 @@ class QuotaSetsController(object): authorize(context) project_id = id for key in body['quota_set'].keys(): - if key in quota.quota_resources: + if key in QUOTAS: value = int(body['quota_set'][key]) self._validate_quota_limit(value) try: @@ -85,12 +95,13 @@ class QuotaSetsController(object): db.quota_create(context, project_id, key, value) except exception.AdminRequired: raise webob.exc.HTTPForbidden() - return {'quota_set': quota.get_project_quotas(context, project_id)} + return {'quota_set': self._get_quotas(context, id)} @wsgi.serializers(xml=QuotaTemplate) def defaults(self, req, id): - authorize(req.environ['nova.context']) - return self._format_quota_set(id, quota._get_default_quotas()) + context = req.environ['nova.context'] + authorize(context) + return self._format_quota_set(id, QUOTAS.get_defaults(context)) class Quotas(extensions.ExtensionDescriptor): diff --git a/nova/api/openstack/compute/contrib/security_groups.py b/nova/api/openstack/compute/contrib/security_groups.py index 2a4886988..7e3f93752 100644 --- a/nova/api/openstack/compute/contrib/security_groups.py +++ b/nova/api/openstack/compute/contrib/security_groups.py @@ -31,6 +31,7 @@ from nova import db from nova import exception from nova import flags from nova import log as logging +from nova.openstack.common import excutils from nova.openstack.common import importutils from nova import quota from nova import utils @@ -38,6 +39,7 @@ from nova import utils LOG = logging.getLogger(__name__) FLAGS = flags.FLAGS +QUOTAS = quota.QUOTAS authorize = extensions.extension_authorizer('compute', 'security_groups') @@ -244,11 +246,24 @@ class SecurityGroupController(SecurityGroupControllerBase): if db.security_group_in_use(context, security_group.id): msg = _("Security group is still in use") raise exc.HTTPBadRequest(explanation=msg) + + # Get reservations + try: + reservations = QUOTAS.reserve(context, security_groups=-1) + except Exception: + reservations = None + LOG.exception(_("Failed to update usages deallocating " + "security group")) + LOG.audit(_("Delete security group %s"), id, context=context) db.security_group_destroy(context, security_group.id) self.sgh.trigger_security_group_destroy_refresh( context, security_group.id) + # Commit the reservations + if reservations: + QUOTAS.commit(context, reservations) + return webob.Response(status_int=202) @wsgi.serializers(xml=SecurityGroupsTemplate) @@ -291,22 +306,33 @@ class SecurityGroupController(SecurityGroupControllerBase): group_name = group_name.strip() group_description = group_description.strip() - if quota.allowed_security_groups(context, 1) < 1: + try: + reservations = QUOTAS.reserve(context, security_groups=1) + except exception.OverQuota: msg = _("Quota exceeded, too many security groups.") raise exc.HTTPBadRequest(explanation=msg) - LOG.audit(_("Create Security Group %s"), group_name, context=context) - self.compute_api.ensure_default_security_group(context) - if db.security_group_exists(context, context.project_id, group_name): - msg = _('Security group %s already exists') % group_name - raise exc.HTTPBadRequest(explanation=msg) - - group = {'user_id': context.user_id, - 'project_id': context.project_id, - 'name': group_name, - 'description': group_description} - group_ref = db.security_group_create(context, group) - self.sgh.trigger_security_group_create_refresh(context, group) + try: + LOG.audit(_("Create Security Group %s"), group_name, + context=context) + self.compute_api.ensure_default_security_group(context) + if db.security_group_exists(context, context.project_id, + group_name): + msg = _('Security group %s already exists') % group_name + raise exc.HTTPBadRequest(explanation=msg) + + group = {'user_id': context.user_id, + 'project_id': context.project_id, + 'name': group_name, + 'description': group_description} + group_ref = db.security_group_create(context, group) + self.sgh.trigger_security_group_create_refresh(context, group) + + # Commit the reservation + QUOTAS.commit(context, reservations) + except Exception: + with excutils.save_and_reraise_exception(): + QUOTAS.rollback(context, reservations) return {'security_group': self._format_security_group(context, group_ref)} @@ -382,10 +408,10 @@ class SecurityGroupRulesController(SecurityGroupControllerBase): msg = _('This rule already exists in group %s') % parent_group_id raise exc.HTTPBadRequest(explanation=msg) - allowed = quota.allowed_security_group_rules(context, - parent_group_id, - 1) - if allowed < 1: + count = QUOTAS.count(context, 'security_group_rules', parent_group_id) + try: + QUOTAS.limit_check(context, security_group_rules=count + 1) + except exception.OverQuota: msg = _("Quota exceeded, too many security group rules.") raise exc.HTTPBadRequest(explanation=msg) diff --git a/nova/api/openstack/compute/limits.py b/nova/api/openstack/compute/limits.py index 60c7e4b93..09dba0744 100644 --- a/nova/api/openstack/compute/limits.py +++ b/nova/api/openstack/compute/limits.py @@ -36,6 +36,9 @@ from nova import quota from nova import wsgi as base_wsgi +QUOTAS = quota.QUOTAS + + # Convenience constants for the limits dictionary passed to Limiter(). PER_SECOND = 1 PER_MINUTE = 60 @@ -82,7 +85,9 @@ class LimitsController(object): Return all global and rate limit information. """ context = req.environ['nova.context'] - abs_limits = quota.get_project_quotas(context, context.project_id) + 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", []) builder = self._get_view_builder(req) |
