summaryrefslogtreecommitdiff
path: root/nova/compute/api.py
diff options
context:
space:
mode:
authorJohn Garbutt <john@johngarbutt.com>2020-03-10 10:25:42 +0000
committermelanie witt <melwittt@gmail.com>2022-02-24 16:21:02 +0000
commit4207493829a1b1877f643c4a49cd2e079f23859d (patch)
tree548c2128e594b957caa62a295a0d770d371cc8a7 /nova/compute/api.py
parent3b69f959a848bad257f186f491111658b25f24c7 (diff)
downloadnova-4207493829a1b1877f643c4a49cd2e079f23859d.tar.gz
Enforce api and db limits
When using unified limits, we add enforcement of those limits on all related API calls. Note: we do not yet correctly report the configured limits to users via the quota APIs, that is in a future patch. Note the unified limits calls are made alongside the existing legacy quota calls. The old quota calls will be handed by the quota engine driver, that is basically a no-op. This is to make it easier to remove the legacy code paths in the future. Note, over quota exceptions raised with unified limits use the standard (improved) exception message as those raised by oslo.limit. They however do use the existing exception code to ease integration. The user of the API will see the same return codes, no matter which code is enabled to enforce the limits. Finally, this also adds test coverage where it was missing. Coverage for "quota recheck" behavior in KeypairAPI is added where all other KeypairAPI testing is located. Duplicate coverage is removed from nova/api/openstack/compute/test_keypairs.py at the same time. blueprint unified-limits-nova Change-Id: I36e82a17579158063396d7e55b495ccff4959ceb
Diffstat (limited to 'nova/compute/api.py')
-rw-r--r--nova/compute/api.py50
1 files changed, 50 insertions, 0 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py
index b25af9f3e1..173ac2f382 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -59,6 +59,7 @@ from nova import exception
from nova import exception_wrapper
from nova.i18n import _
from nova.image import glance
+from nova.limit import local as local_limit
from nova.network import constants
from nova.network import model as network_model
from nova.network import neutron
@@ -409,6 +410,10 @@ class API:
try:
objects.Quotas.limit_check(context,
injected_files=len(injected_files))
+ local_limit.enforce_api_limit(local_limit.INJECTED_FILES,
+ len(injected_files))
+ except exception.OnsetFileLimitExceeded:
+ raise
except exception.OverQuota:
raise exception.OnsetFileLimitExceeded()
@@ -424,6 +429,16 @@ class API:
objects.Quotas.limit_check(context,
injected_file_path_bytes=max_path,
injected_file_content_bytes=max_content)
+ # TODO(johngarbutt) we can simplify the except clause when
+ # the above legacy quota check is removed.
+ local_limit.enforce_api_limit(
+ local_limit.INJECTED_FILES_PATH, max_path)
+ local_limit.enforce_api_limit(
+ local_limit.INJECTED_FILES_CONTENT, max_content)
+ except exception.OnsetFilePathLimitExceeded:
+ raise
+ except exception.OnsetFileContentLimitExceeded:
+ raise
except exception.OverQuota as exc:
# Favor path limit over content limit for reporting
# purposes
@@ -444,6 +459,10 @@ class API:
num_metadata = len(metadata)
try:
objects.Quotas.limit_check(context, metadata_items=num_metadata)
+ local_limit.enforce_api_limit(
+ local_limit.SERVER_METADATA_ITEMS, num_metadata)
+ except exception.MetadataLimitExceeded:
+ raise
except exception.OverQuota as exc:
quota_metadata = exc.kwargs['quotas']['metadata_items']
raise exception.MetadataLimitExceeded(allowed=quota_metadata)
@@ -1451,6 +1470,11 @@ class API:
objects.Quotas.check_deltas(
context, {'server_group_members': 1},
instance_group, context.user_id)
+ local_limit.enforce_db_limit(
+ context, local_limit.SERVER_GROUP_MEMBERS,
+ entity_scope=instance_group.uuid, delta=1)
+ except exception.GroupMemberLimitExceeded:
+ raise
except exception.OverQuota:
msg = _("Quota exceeded, too many servers in "
"group")
@@ -1469,6 +1493,19 @@ class API:
objects.Quotas.check_deltas(
context, {'server_group_members': 0},
instance_group, context.user_id)
+ # TODO(johngarbutt): decide if we need this check
+ # The quota rechecking of limits is really just to
+ # protect against denial of service attacks that
+ # aim to fill up the database. Its usefulness could
+ # be debated.
+ local_limit.enforce_db_limit(
+ context, local_limit.SERVER_GROUP_MEMBERS,
+ entity_scope=instance_group.uuid, delta=0)
+ except exception.GroupMemberLimitExceeded:
+ with excutils.save_and_reraise_exception():
+ objects.InstanceGroup._remove_members_in_db(
+ context, instance_group.id,
+ [instance.uuid])
except exception.OverQuota:
objects.InstanceGroup._remove_members_in_db(
context, instance_group.id, [instance.uuid])
@@ -6551,6 +6588,10 @@ class KeypairAPI:
'1 and 255 characters long'))
try:
objects.Quotas.check_deltas(context, {'key_pairs': 1}, user_id)
+ local_limit.enforce_db_limit(context, local_limit.KEY_PAIRS,
+ entity_scope=user_id, delta=1)
+ except exception.KeypairLimitExceeded:
+ raise
except exception.OverQuota:
raise exception.KeypairLimitExceeded()
@@ -6623,6 +6664,15 @@ class KeypairAPI:
if CONF.quota.recheck_quota:
try:
objects.Quotas.check_deltas(context, {'key_pairs': 0}, user_id)
+ # TODO(johngarbutt) do we really need this recheck?
+ # The quota rechecking of limits is really just to protect
+ # against denial of service attacks that aim to fill up the
+ # database. Its usefulness could be debated.
+ local_limit.enforce_db_limit(context, local_limit.KEY_PAIRS,
+ entity_scope=user_id, delta=0)
+ except exception.KeypairLimitExceeded:
+ with excutils.save_and_reraise_exception():
+ keypair.destroy()
except exception.OverQuota:
keypair.destroy()
raise exception.KeypairLimitExceeded()