Handling unlimited values when updating quota
Changes: - Adding a general approach to handle unlimited values when performing calculations with quota values. - New test that fails without the fix. - Updated test cases to support the fix. Change-Id: I762a8e67261c0e0286307832cd13ad12e6d96504 Closes-Bug: #1292494
This commit is contained in:
+37
-9
@@ -92,6 +92,8 @@ class DbQuotaDriver(object):
|
||||
quota information. The default driver utilizes the local
|
||||
database.
|
||||
"""
|
||||
UNLIMITED_VALUE = -1
|
||||
|
||||
def get_by_project_and_user(self, context, project_id, user_id, resource):
|
||||
"""Get a specific quota by project and user."""
|
||||
|
||||
@@ -273,6 +275,30 @@ class DbQuotaDriver(object):
|
||||
defaults=defaults, usages=project_usages,
|
||||
remains=remains)
|
||||
|
||||
def _is_unlimited_value(self, v):
|
||||
"""A helper method to check for unlimited value.
|
||||
"""
|
||||
|
||||
return v <= self.UNLIMITED_VALUE
|
||||
|
||||
def _sum_quota_values(self, v1, v2):
|
||||
"""A helper method that handles unlimited values when performing
|
||||
sum operation.
|
||||
"""
|
||||
|
||||
if self._is_unlimited_value(v1) or self._is_unlimited_value(v2):
|
||||
return self.UNLIMITED_VALUE
|
||||
return v1 + v2
|
||||
|
||||
def _sub_quota_values(self, v1, v2):
|
||||
"""A helper method that handles unlimited values when performing
|
||||
subtraction operation.
|
||||
"""
|
||||
|
||||
if self._is_unlimited_value(v1) or self._is_unlimited_value(v2):
|
||||
return self.UNLIMITED_VALUE
|
||||
return v1 - v2
|
||||
|
||||
def get_settable_quotas(self, context, resources, project_id,
|
||||
user_id=None):
|
||||
"""Given a list of resources, retrieve the range of settable quotas for
|
||||
@@ -283,6 +309,7 @@ class DbQuotaDriver(object):
|
||||
:param project_id: The ID of the project to return quotas for.
|
||||
:param user_id: The ID of the user to return quotas for.
|
||||
"""
|
||||
|
||||
settable_quotas = {}
|
||||
db_proj_quotas = db.quota_get_all_by_project(context, project_id)
|
||||
project_quotas = self.get_project_quotas(context, resources,
|
||||
@@ -297,17 +324,18 @@ class DbQuotaDriver(object):
|
||||
project_quotas=db_proj_quotas,
|
||||
user_quotas=setted_quotas)
|
||||
for key, value in user_quotas.items():
|
||||
maximum = project_quotas[key]['remains'] +\
|
||||
setted_quotas.get(key, 0)
|
||||
settable_quotas[key] = dict(
|
||||
minimum=value['in_use'] + value['reserved'],
|
||||
maximum=maximum
|
||||
)
|
||||
maximum = \
|
||||
self._sum_quota_values(project_quotas[key]['remains'],
|
||||
setted_quotas.get(key, 0))
|
||||
minimum = value['in_use'] + value['reserved']
|
||||
settable_quotas[key] = {'minimum': minimum, 'maximum': maximum}
|
||||
else:
|
||||
for key, value in project_quotas.items():
|
||||
minimum = max(int(value['limit'] - value['remains']),
|
||||
int(value['in_use'] + value['reserved']))
|
||||
settable_quotas[key] = dict(minimum=minimum, maximum=-1)
|
||||
minimum = \
|
||||
max(int(self._sub_quota_values(value['limit'],
|
||||
value['remains'])),
|
||||
int(value['in_use'] + value['reserved']))
|
||||
settable_quotas[key] = {'minimum': minimum, 'maximum': -1}
|
||||
return settable_quotas
|
||||
|
||||
def _get_quotas(self, context, resources, keys, has_sync, project_id=None,
|
||||
|
||||
@@ -1590,14 +1590,20 @@ class DbQuotaDriverTestCase(test.TestCase):
|
||||
self.calls.append('get_project_quotas')
|
||||
result = {}
|
||||
for k, v in resources.items():
|
||||
limit = v.default
|
||||
reserved = 0
|
||||
if k == 'instances':
|
||||
remains = v.default - 5
|
||||
in_use = 1
|
||||
elif k == 'cores':
|
||||
remains = -1
|
||||
in_use = 5
|
||||
limit = -1
|
||||
else:
|
||||
remains = v.default
|
||||
in_use = 0
|
||||
result[k] = {'limit': v.default, 'in_use': in_use,
|
||||
'reserved': 0, 'remains': remains}
|
||||
result[k] = {'limit': limit, 'in_use': in_use,
|
||||
'reserved': reserved, 'remains': remains}
|
||||
return result
|
||||
|
||||
def fake_get_user_quotas(context, resources, project_id, user_id,
|
||||
@@ -1607,17 +1613,21 @@ class DbQuotaDriverTestCase(test.TestCase):
|
||||
self.calls.append('get_user_quotas')
|
||||
result = {}
|
||||
for k, v in resources.items():
|
||||
reserved = 0
|
||||
if k == 'instances':
|
||||
in_use = 1
|
||||
elif k == 'cores':
|
||||
in_use = 5
|
||||
reserved = 10
|
||||
else:
|
||||
in_use = 0
|
||||
result[k] = {'limit': v.default,
|
||||
'in_use': in_use, 'reserved': 0}
|
||||
'in_use': in_use, 'reserved': reserved}
|
||||
return result
|
||||
|
||||
def fake_qgabpau(context, project_id, user_id):
|
||||
self.calls.append('quota_get_all_by_project_and_user')
|
||||
return {'instances': 2}
|
||||
return {'instances': 2, 'cores': -1}
|
||||
|
||||
self.stubs.Set(self.driver, 'get_project_quotas',
|
||||
fake_get_project_quotas)
|
||||
@@ -1643,8 +1653,8 @@ class DbQuotaDriverTestCase(test.TestCase):
|
||||
'maximum': 7,
|
||||
},
|
||||
'cores': {
|
||||
'minimum': 0,
|
||||
'maximum': 20,
|
||||
'minimum': 15,
|
||||
'maximum': -1,
|
||||
},
|
||||
'ram': {
|
||||
'minimum': 0,
|
||||
@@ -1703,7 +1713,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
||||
'maximum': -1,
|
||||
},
|
||||
'cores': {
|
||||
'minimum': 0,
|
||||
'minimum': 5,
|
||||
'maximum': -1,
|
||||
},
|
||||
'ram': {
|
||||
@@ -1748,6 +1758,68 @@ class DbQuotaDriverTestCase(test.TestCase):
|
||||
},
|
||||
})
|
||||
|
||||
def test_get_settable_quotas_by_user_with_unlimited_value(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',
|
||||
'quota_get_all_by_project_and_user',
|
||||
'get_user_quotas',
|
||||
])
|
||||
self.assertEqual(result, {
|
||||
'instances': {
|
||||
'minimum': 1,
|
||||
'maximum': 7,
|
||||
},
|
||||
'cores': {
|
||||
'minimum': 15,
|
||||
'maximum': -1,
|
||||
},
|
||||
'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 _stub_get_project_quotas(self):
|
||||
def fake_get_project_quotas(context, resources, project_id,
|
||||
quota_class=None, defaults=True,
|
||||
|
||||
Reference in New Issue
Block a user