User quota update should not exceed project quota

Move the default user quota setting code from db to quota.py,
because it is necessary to check if user quota is set in db
to get the settable quota for the user under a project.

Fixes bug 1208400

Change-Id: I83a4a7fcd8bf80b20e4e700bad7dd31294f8ed0b
This commit is contained in:
liyingjun 2013-08-05 17:57:15 +08:00
parent 8fb450fb3a
commit b4905b40fd
4 changed files with 192 additions and 32 deletions

View File

@ -2640,16 +2640,7 @@ def quota_get_all_by_project_and_user(context, project_id, user_id):
filter_by(user_id=user_id).\
all()
proj_quotas = model_query(context, models.Quota.resource,
models.Quota.hard_limit,
base_model=models.Quota).\
filter_by(project_id=project_id).\
all()
result = {'project_id': project_id, 'user_id': user_id}
# Use the project quota for default user quota.
for quota in proj_quotas:
result[quota.resource] = quota.hard_limit
for quota in user_quotas:
result[quota.resource] = quota.hard_limit

View File

@ -222,6 +222,11 @@ class DbQuotaDriver(object):
"""
user_quotas = db.quota_get_all_by_project_and_user(context,
project_id, user_id)
# Use the project quota for default user quota.
proj_quotas = db.quota_get_all_by_project(context, project_id)
for key, value in proj_quotas.iteritems():
if key not in user_quotas.keys():
user_quotas[key] = value
user_usages = None
if usages:
user_usages = db.quota_usage_get_all_by_project_and_user(context,

View File

@ -4764,18 +4764,6 @@ class QuotaTestCase(test.TestCase, ModelsObjectComparatorMixin):
'resource2': 2})
def test_quota_get_all_by_project_and_user(self):
for i in range(3):
for j in range(3):
db.quota_create(self.ctxt, 'proj%d' % i, 'resource%d' % j, j)
for i in range(3):
quotas_db = db.quota_get_all_by_project_and_user(self.ctxt,
'proj%d' % i,
'user%d' % i)
self.assertEqual(quotas_db, {'project_id': 'proj%d' % i,
'user_id': 'user%d' % i,
'resource0': 0,
'resource1': 1,
'resource2': 2})
for i in range(3):
for j in range(3):
db.quota_create(self.ctxt, 'proj%d' % i, 'resource%d' % j,
@ -4876,10 +4864,7 @@ class QuotaTestCase(test.TestCase, ModelsObjectComparatorMixin):
self.assertEqual(db.quota_get_all_by_project_and_user(self.ctxt,
'project1', 'user1'),
{'project_id': 'project1',
'user_id': 'user1',
'resource0': 0,
'resource1': 1,
'resource2': 2})
'user_id': 'user1'})
self.assertEqual(db.quota_usage_get_all_by_project_and_user(
self.ctxt, 'project1', 'user1'),
{'project_id': 'project1',

View File

@ -864,7 +864,7 @@ class DbQuotaDriverTestCase(test.TestCase):
))
def _stub_get_by_project_and_user(self):
def fake_qgabp(context, project_id, user_id):
def fake_qgabpau(context, project_id, user_id):
self.calls.append('quota_get_all_by_project_and_user')
self.assertEqual(project_id, 'test_project')
self.assertEqual(user_id, 'fake_user')
@ -874,7 +874,16 @@ class DbQuotaDriverTestCase(test.TestCase):
injected_file_path_bytes=127,
)
def fake_qugabp(context, project_id, user_id):
def fake_qgabp(context, project_id):
self.calls.append('quota_get_all_by_project')
self.assertEqual(project_id, 'test_project')
return {
'cores': 10,
'injected_files': 2,
'injected_file_path_bytes': 127,
}
def fake_qugabpau(context, project_id, user_id):
self.calls.append('quota_usage_get_all_by_project_and_user')
self.assertEqual(project_id, 'test_project')
self.assertEqual(user_id, 'fake_user')
@ -889,9 +898,10 @@ class DbQuotaDriverTestCase(test.TestCase):
injected_file_path_bytes=dict(in_use=0, reserved=0),
)
self.stubs.Set(db, 'quota_get_all_by_project_and_user', fake_qgabp)
self.stubs.Set(db, 'quota_get_all_by_project_and_user', fake_qgabpau)
self.stubs.Set(db, 'quota_get_all_by_project', fake_qgabp)
self.stubs.Set(db, 'quota_usage_get_all_by_project_and_user',
fake_qugabp)
fake_qugabpau)
self._stub_quota_class_get_all_by_name()
@ -904,6 +914,7 @@ class DbQuotaDriverTestCase(test.TestCase):
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',
])
@ -1080,11 +1091,12 @@ class DbQuotaDriverTestCase(test.TestCase):
self.maxDiff = None
self._stub_get_by_project_and_user()
result = self.driver.get_user_quotas(
FakeContext('other_project', 'other_class'),
FakeContext('test_project', None),
quota.QUOTAS._resources, 'test_project', 'fake_user')
self.assertEqual(self.calls, [
'quota_get_all_by_project_and_user',
'quota_get_all_by_project',
'quota_usage_get_all_by_project_and_user',
])
self.assertEqual(result, dict(
@ -1103,7 +1115,7 @@ class DbQuotaDriverTestCase(test.TestCase):
in_use=10 * 1024,
reserved=0,
),
floating_ips=dict(
floating_ips=dict(
limit=10,
in_use=2,
reserved=0,
@ -1229,12 +1241,13 @@ class DbQuotaDriverTestCase(test.TestCase):
self.maxDiff = None
self._stub_get_by_project_and_user()
result = self.driver.get_user_quotas(
FakeContext('other_project', 'other_class'),
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',
])
@ -1386,6 +1399,7 @@ class DbQuotaDriverTestCase(test.TestCase):
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',
])
@ -1445,6 +1459,7 @@ 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(
@ -1536,6 +1551,170 @@ class DbQuotaDriverTestCase(test.TestCase):
),
))
def _stub_get_settable_quotas(self):
def fake_get_project_quotas(context, resources, project_id,
quota_class=None, defaults=True,
usages=True, remains=False):
self.calls.append('get_project_quotas')
result = {}
for k, v in resources.items():
if k == 'instances':
remains = v.default - 5
in_use = 1
else:
remains = v.default
in_use = 0
result[k] = {'limit': v.default, 'in_use': in_use,
'reserved': 0, 'remains': remains}
return result
def fake_get_user_quotas(context, resources, project_id, user_id,
quota_class=None, defaults=True,
usages=True):
self.calls.append('get_user_quotas')
result = {}
for k, v in resources.items():
if k == 'instances':
in_use = 1
else:
in_use = 0
result[k] = {'limit': v.default,
'in_use': in_use, 'reserved': 0}
return result
def fake_qgabpau(context, project_id, user_id):
self.calls.append('quota_get_all_by_project_and_user')
return {'instances': 2}
self.stubs.Set(self.driver, 'get_project_quotas',
fake_get_project_quotas)
self.stubs.Set(self.driver, 'get_user_quotas',
fake_get_user_quotas)
self.stubs.Set(db, 'quota_get_all_by_project_and_user',
fake_qgabpau)
def test_get_settable_quotas_with_user(self):
self._stub_get_settable_quotas()
result = self.driver.get_settable_quotas(
FakeContext('test_project', 'test_class'),
quota.QUOTAS._resources, 'test_project', user_id='test_user')
self.assertEqual(self.calls, [
'get_project_quotas',
'get_user_quotas',
'quota_get_all_by_project_and_user',
])
self.assertEqual(result, {
'instances': {
'minimum': 1,
'maximum': 7,
},
'cores': {
'minimum': 0,
'maximum': 20,
},
'ram': {
'minimum': 0,
'maximum': 50 * 1024,
},
'floating_ips': {
'minimum': 0,
'maximum': 10,
},
'fixed_ips': {
'minimum': 0,
'maximum': 10,
},
'metadata_items': {
'minimum': 0,
'maximum': 128,
},
'injected_files': {
'minimum': 0,
'maximum': 5,
},
'injected_file_content_bytes': {
'minimum': 0,
'maximum': 10 * 1024,
},
'injected_file_path_bytes': {
'minimum': 0,
'maximum': 255,
},
'security_groups': {
'minimum': 0,
'maximum': 10,
},
'security_group_rules': {
'minimum': 0,
'maximum': 20,
},
'key_pairs': {
'minimum': 0,
'maximum': 100,
},
})
def test_get_settable_quotas_without_user(self):
self._stub_get_settable_quotas()
result = self.driver.get_settable_quotas(
FakeContext('test_project', 'test_class'),
quota.QUOTAS._resources, 'test_project')
self.assertEqual(self.calls, [
'get_project_quotas',
])
self.assertEqual(result, {
'instances': {
'minimum': 5,
'maximum': -1,
},
'cores': {
'minimum': 0,
'maximum': -1,
},
'ram': {
'minimum': 0,
'maximum': -1,
},
'floating_ips': {
'minimum': 0,
'maximum': -1,
},
'fixed_ips': {
'minimum': 0,
'maximum': -1,
},
'metadata_items': {
'minimum': 0,
'maximum': -1,
},
'injected_files': {
'minimum': 0,
'maximum': -1,
},
'injected_file_content_bytes': {
'minimum': 0,
'maximum': -1,
},
'injected_file_path_bytes': {
'minimum': 0,
'maximum': -1,
},
'security_groups': {
'minimum': 0,
'maximum': -1,
},
'security_group_rules': {
'minimum': 0,
'maximum': -1,
},
'key_pairs': {
'minimum': 0,
'maximum': -1,
},
})
def _stub_get_project_quotas(self):
def fake_get_project_quotas(context, resources, project_id,
quota_class=None, defaults=True,