summaryrefslogtreecommitdiffstats
path: root/nova/api
diff options
context:
space:
mode:
authorKevin L. Mitchell <kevin.mitchell@rackspace.com>2012-05-11 15:30:14 -0500
committerKevin L. Mitchell <kevin.mitchell@rackspace.com>2012-05-23 10:17:41 -0500
commitb7f0946bbd071bc76809eca440ab7d21a03eb1a3 (patch)
tree4f46ad3896cb89c8747bdf09e3f33a476eccbf16 /nova/api
parent7e15d4e28f98e13f0ea7399787c50839139d8492 (diff)
downloadnova-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.py49
-rw-r--r--nova/api/openstack/common.py8
-rw-r--r--nova/api/openstack/compute/contrib/quota_classes.py15
-rw-r--r--nova/api/openstack/compute/contrib/quotas.py27
-rw-r--r--nova/api/openstack/compute/contrib/security_groups.py60
-rw-r--r--nova/api/openstack/compute/limits.py7
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)