Revert "Remove quota-class logic from context and make unit tests pass"

This reverts commit e25316ecb9.

The quota_classes API was used to set default quota values
so it shouldn't have been removed, so reverting a series
of changes that removed the API and it's internal code.

Related mailing list thread on the topic:

http://lists.openstack.org/pipermail/openstack-dev/2014-May/035383.html

Partial-Bug: #1299517

Change-Id: If903863d28fbab74cfe571709a01cd2cdd46d174
This commit is contained in:
Matt Riedemann 2014-05-29 08:07:21 -07:00
parent c07626012e
commit d9cee6b2ee
4 changed files with 252 additions and 15 deletions

View File

@ -47,7 +47,7 @@ class RequestContext(object):
def __init__(self, user_id, project_id, is_admin=None, read_deleted="no",
roles=None, remote_address=None, timestamp=None,
request_id=None, auth_token=None, overwrite=True,
user_name=None, project_name=None,
quota_class=None, user_name=None, project_name=None,
service_catalog=None, instance_lock_checked=False, **kwargs):
""":param read_deleted: 'no' indicates deleted records are hidden,
'yes' indicates deleted records are visible,
@ -89,6 +89,10 @@ class RequestContext(object):
self.instance_lock_checked = instance_lock_checked
# NOTE(markmc): this attribute is currently only used by the
# rs_limits turnstile pre-processor.
# See https://lists.launchpad.net/openstack/msg12200.html
self.quota_class = quota_class
self.user_name = user_name
self.project_name = project_name
self.is_admin = is_admin
@ -125,6 +129,7 @@ class RequestContext(object):
'timestamp': timeutils.strtime(self.timestamp),
'request_id': self.request_id,
'auth_token': self.auth_token,
'quota_class': self.quota_class,
'user_name': self.user_name,
'service_catalog': self.service_catalog,
'project_name': self.project_name,
@ -214,3 +219,12 @@ def authorize_user_context(context, user_id):
raise exception.Forbidden()
elif context.user_id != user_id:
raise exception.Forbidden()
def authorize_quota_class_context(context, class_name):
"""Ensures a request has permission to access the given quota class."""
if is_user_context(context):
if not context.quota_class:
raise exception.Forbidden()
elif context.quota_class != class_name:
raise exception.Forbidden()

View File

@ -2894,6 +2894,8 @@ def quota_class_get_default(context):
@require_context
def quota_class_get_all_by_name(context, class_name):
nova.context.authorize_quota_class_context(context, class_name)
rows = model_query(context, models.QuotaClass, read_deleted="no").\
filter_by(class_name=class_name).\
all()

View File

@ -156,6 +156,16 @@ class DbQuotaDriver(object):
quota_class=None, defaults=True, usages=None,
remains=False):
modified_quotas = {}
# Get the quotas for the appropriate class. If the project ID
# matches the one in the context, we use the quota_class from
# the context, otherwise, we use the provided quota_class (if
# any)
if project_id == context.project_id:
quota_class = context.quota_class
if quota_class:
class_quotas = db.quota_class_get_all_by_name(context, quota_class)
else:
class_quotas = {}
default_quotas = self.get_defaults(context, resources)
@ -164,7 +174,8 @@ class DbQuotaDriver(object):
if not defaults and resource.name not in quotas:
continue
limit = quotas.get(resource.name, default_quotas[resource.name])
limit = quotas.get(resource.name, class_quotas.get(
resource.name, default_quotas[resource.name]))
modified_quotas[resource.name] = dict(limit=limit)
# Include usages if desired. This is optional because one
@ -370,13 +381,13 @@ class DbQuotaDriver(object):
# Grab and return the quotas (without usages)
quotas = self.get_user_quotas(context, sub_resources,
project_id, user_id,
None, usages=False,
context.quota_class, usages=False,
project_quotas=project_quotas)
else:
# Grab and return the quotas (without usages)
quotas = self.get_project_quotas(context, sub_resources,
project_id,
None,
context.quota_class,
usages=False,
project_quotas=project_quotas)
@ -955,7 +966,7 @@ class BaseResource(object):
project_id = kwargs.get('project_id', context.project_id)
# Ditto for the quota class
quota_class = kwargs.get('quota_class', None)
quota_class = kwargs.get('quota_class', context.quota_class)
# Look up the quota for the project
if project_id:

View File

@ -357,7 +357,7 @@ class BaseResourceTestCase(test.TestCase):
self.assertEqual(resource.flag, 'quota_instances')
self.assertEqual(resource.default, -1)
def test_quota_no_project(self):
def test_quota_no_project_no_class(self):
self.flags(quota_instances=10)
resource = quota.BaseResource('test_resource', 'quota_instances')
driver = FakeDriver()
@ -366,7 +366,7 @@ class BaseResourceTestCase(test.TestCase):
self.assertEqual(quota_value, 10)
def test_quota_with_project(self):
def test_quota_with_project_no_class(self):
self.flags(quota_instances=10)
resource = quota.BaseResource('test_resource', 'quota_instances')
driver = FakeDriver(by_project=dict(
@ -377,6 +377,57 @@ class BaseResourceTestCase(test.TestCase):
self.assertEqual(quota_value, 15)
def test_quota_no_project_with_class(self):
self.flags(quota_instances=10)
resource = quota.BaseResource('test_resource', 'quota_instances')
driver = FakeDriver(by_class=dict(
test_class=dict(test_resource=20),
))
context = FakeContext(None, 'test_class')
quota_value = resource.quota(driver, context)
self.assertEqual(quota_value, 20)
def test_quota_with_project_with_class(self):
self.flags(quota_instances=10)
resource = quota.BaseResource('test_resource', 'quota_instances')
driver = FakeDriver(by_project=dict(
test_project=dict(test_resource=15),
),
by_class=dict(
test_class=dict(test_resource=20),
))
context = FakeContext('test_project', 'test_class')
quota_value = resource.quota(driver, context)
self.assertEqual(quota_value, 15)
def test_quota_override_project_with_class(self):
self.flags(quota_instances=10)
resource = quota.BaseResource('test_resource', 'quota_instances')
driver = FakeDriver(by_project=dict(
test_project=dict(test_resource=15),
override_project=dict(test_resource=20),
))
context = FakeContext('test_project', 'test_class')
quota_value = resource.quota(driver, context,
project_id='override_project')
self.assertEqual(quota_value, 20)
def test_quota_with_project_override_class(self):
self.flags(quota_instances=10)
resource = quota.BaseResource('test_resource', 'quota_instances')
driver = FakeDriver(by_class=dict(
test_class=dict(test_resource=15),
override_class=dict(test_resource=20),
))
context = FakeContext('test_project', 'test_class')
quota_value = resource.quota(driver, context,
quota_class='override_class')
self.assertEqual(quota_value, 20)
class QuotaEngineTestCase(test.TestCase):
def test_init(self):
@ -861,10 +912,11 @@ class DbQuotaDriverTestCase(test.TestCase):
'quota_get_all_by_project_and_user',
'quota_get_all_by_project',
'quota_usage_get_all_by_project_and_user',
'quota_class_get_all_by_name',
])
self.assertEqual(result, dict(
instances=dict(
limit=10,
limit=5,
in_use=2,
reserved=2,
),
@ -874,7 +926,7 @@ class DbQuotaDriverTestCase(test.TestCase):
reserved=4,
),
ram=dict(
limit=50 * 1024,
limit=25 * 1024,
in_use=10 * 1024,
reserved=0,
),
@ -889,7 +941,7 @@ class DbQuotaDriverTestCase(test.TestCase):
reserved=0,
),
metadata_items=dict(
limit=128,
limit=64,
in_use=0,
reserved=0,
),
@ -899,7 +951,7 @@ class DbQuotaDriverTestCase(test.TestCase):
reserved=0,
),
injected_file_content_bytes=dict(
limit=10 * 1024,
limit=5 * 1024,
in_use=0,
reserved=0,
),
@ -987,6 +1039,7 @@ class DbQuotaDriverTestCase(test.TestCase):
self.assertEqual(self.calls, [
'quota_get_all_by_project',
'quota_usage_get_all_by_project',
'quota_class_get_all_by_name',
'quota_class_get_default',
])
self.assertEqual(result, dict(
@ -1202,6 +1255,159 @@ class DbQuotaDriverTestCase(test.TestCase):
),
))
def test_get_user_quotas_alt_context_with_class(self):
self.maxDiff = None
self._stub_get_by_project_and_user()
result = self.driver.get_user_quotas(
FakeContext('test_project', 'test_class'),
quota.QUOTAS._resources, 'test_project', 'fake_user',
quota_class='test_class')
self.assertEqual(self.calls, [
'quota_get_all_by_project_and_user',
'quota_get_all_by_project',
'quota_usage_get_all_by_project_and_user',
'quota_class_get_all_by_name',
])
self.assertEqual(result, dict(
instances=dict(
limit=5,
in_use=2,
reserved=2,
),
cores=dict(
limit=10,
in_use=4,
reserved=4,
),
ram=dict(
limit=25 * 1024,
in_use=10 * 1024,
reserved=0,
),
floating_ips=dict(
limit=10,
in_use=2,
reserved=0,
),
fixed_ips=dict(
limit=10,
in_use=0,
reserved=0,
),
metadata_items=dict(
limit=64,
in_use=0,
reserved=0,
),
injected_files=dict(
limit=2,
in_use=0,
reserved=0,
),
injected_file_content_bytes=dict(
limit=5 * 1024,
in_use=0,
reserved=0,
),
injected_file_path_bytes=dict(
limit=127,
in_use=0,
reserved=0,
),
security_groups=dict(
limit=10,
in_use=0,
reserved=0,
),
security_group_rules=dict(
limit=20,
in_use=0,
reserved=0,
),
key_pairs=dict(
limit=100,
in_use=0,
reserved=0,
),
))
def test_get_project_quotas_alt_context_with_class(self):
self.maxDiff = None
self._stub_get_by_project()
result = self.driver.get_project_quotas(
FakeContext('other_project', 'other_class'),
quota.QUOTAS._resources, 'test_project', quota_class='test_class')
self.assertEqual(self.calls, [
'quota_get_all_by_project',
'quota_usage_get_all_by_project',
'quota_class_get_all_by_name',
'quota_class_get_default',
])
self.assertEqual(result, dict(
instances=dict(
limit=5,
in_use=2,
reserved=2,
),
cores=dict(
limit=10,
in_use=4,
reserved=4,
),
ram=dict(
limit=25 * 1024,
in_use=10 * 1024,
reserved=0,
),
floating_ips=dict(
limit=10,
in_use=2,
reserved=0,
),
fixed_ips=dict(
limit=10,
in_use=0,
reserved=0,
),
metadata_items=dict(
limit=64,
in_use=0,
reserved=0,
),
injected_files=dict(
limit=2,
in_use=0,
reserved=0,
),
injected_file_content_bytes=dict(
limit=5 * 1024,
in_use=0,
reserved=0,
),
injected_file_path_bytes=dict(
limit=127,
in_use=0,
reserved=0,
),
security_groups=dict(
limit=10,
in_use=0,
reserved=0,
),
security_group_rules=dict(
limit=20,
in_use=0,
reserved=0,
),
key_pairs=dict(
limit=100,
in_use=0,
reserved=0,
),
))
def test_get_user_quotas_no_defaults(self):
self._stub_get_by_project_and_user()
result = self.driver.get_user_quotas(
@ -1213,6 +1419,7 @@ class DbQuotaDriverTestCase(test.TestCase):
'quota_get_all_by_project_and_user',
'quota_get_all_by_project',
'quota_usage_get_all_by_project_and_user',
'quota_class_get_all_by_name',
])
self.assertEqual(result, dict(
cores=dict(
@ -1241,6 +1448,7 @@ class DbQuotaDriverTestCase(test.TestCase):
self.assertEqual(self.calls, [
'quota_get_all_by_project',
'quota_usage_get_all_by_project',
'quota_class_get_all_by_name',
'quota_class_get_default',
])
self.assertEqual(result, dict(
@ -1270,16 +1478,17 @@ class DbQuotaDriverTestCase(test.TestCase):
self.assertEqual(self.calls, [
'quota_get_all_by_project_and_user',
'quota_get_all_by_project',
'quota_class_get_all_by_name',
])
self.assertEqual(result, dict(
instances=dict(
limit=10,
limit=5,
),
cores=dict(
limit=10,
),
ram=dict(
limit=50 * 1024,
limit=25 * 1024,
),
floating_ips=dict(
limit=10,
@ -1288,13 +1497,13 @@ class DbQuotaDriverTestCase(test.TestCase):
limit=10,
),
metadata_items=dict(
limit=128,
limit=64,
),
injected_files=dict(
limit=2,
),
injected_file_content_bytes=dict(
limit=10 * 1024,
limit=5 * 1024,
),
injected_file_path_bytes=dict(
limit=127,
@ -1318,6 +1527,7 @@ class DbQuotaDriverTestCase(test.TestCase):
self.assertEqual(self.calls, [
'quota_get_all_by_project',
'quota_class_get_all_by_name',
'quota_class_get_default',
])
self.assertEqual(result, dict(