Editable default quota support
Implement blueprint edit-default-quota DocImpact Using the class quotas named `default` as the default editable quotas. We can use the following novaclient command to update default quota: nova quota-class-update default <key> <value> Change-Id: I5a5001fadcbd61d550ebd5bdc33613b0ffdf29b2
This commit is contained in:
parent
505af894f3
commit
682fb1de14
|
@ -911,6 +911,11 @@ def quota_class_get(context, class_name, resource):
|
|||
return IMPL.quota_class_get(context, class_name, resource)
|
||||
|
||||
|
||||
def quota_class_get_default(context):
|
||||
"""Retrieve all default quotas."""
|
||||
return IMPL.quota_class_get_default(context)
|
||||
|
||||
|
||||
def quota_class_get_all_by_name(context, class_name):
|
||||
"""Retrieve all quotas associated with a given quota class."""
|
||||
return IMPL.quota_class_get_all_by_name(context, class_name)
|
||||
|
|
|
@ -81,6 +81,7 @@ get_session = db_session.get_session
|
|||
|
||||
|
||||
_SHADOW_TABLE_PREFIX = 'shadow_'
|
||||
_DEFAULT_QUOTA_NAME = 'default'
|
||||
|
||||
|
||||
def get_backend():
|
||||
|
@ -2576,6 +2577,18 @@ def quota_class_get(context, class_name, resource):
|
|||
return result
|
||||
|
||||
|
||||
def quota_class_get_default(context):
|
||||
rows = model_query(context, models.QuotaClass, read_deleted="no").\
|
||||
filter_by(class_name=_DEFAULT_QUOTA_NAME).\
|
||||
all()
|
||||
|
||||
result = {'class_name': _DEFAULT_QUOTA_NAME}
|
||||
for row in rows:
|
||||
result[row.resource] = row.hard_limit
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@require_context
|
||||
def quota_class_get_all_by_name(context, class_name):
|
||||
nova.context.authorize_quota_class_context(context, class_name)
|
||||
|
|
|
@ -105,14 +105,18 @@ class DbQuotaDriver(object):
|
|||
|
||||
def get_defaults(self, context, resources):
|
||||
"""Given a list of resources, retrieve the default quotas.
|
||||
Use the class quotas named `_DEFAULT_QUOTA_NAME` as default quotas,
|
||||
if it exists.
|
||||
|
||||
:param context: The request context, for access checks.
|
||||
:param resources: A dictionary of the registered resources.
|
||||
"""
|
||||
|
||||
quotas = {}
|
||||
default_quotas = db.quota_class_get_default(context)
|
||||
for resource in resources.values():
|
||||
quotas[resource.name] = resource.default
|
||||
quotas[resource.name] = default_quotas.get(resource.name,
|
||||
resource.default)
|
||||
|
||||
return quotas
|
||||
|
||||
|
@ -180,6 +184,8 @@ class DbQuotaDriver(object):
|
|||
else:
|
||||
class_quotas = {}
|
||||
|
||||
default_quotas = self.get_defaults(context, resources)
|
||||
|
||||
for resource in resources.values():
|
||||
# Omit default/quota class values
|
||||
if not defaults and resource.name not in project_quotas:
|
||||
|
@ -187,7 +193,7 @@ class DbQuotaDriver(object):
|
|||
|
||||
quotas[resource.name] = dict(
|
||||
limit=project_quotas.get(resource.name, class_quotas.get(
|
||||
resource.name, resource.default)),
|
||||
resource.name, default_quotas[resource.name])),
|
||||
)
|
||||
|
||||
# Include usages if desired. This is optional because one
|
||||
|
|
|
@ -3930,6 +3930,28 @@ class KeyPairTestCase(test.TestCase, ModelsObjectComparatorMixin):
|
|||
param['user_id'], param['name'])
|
||||
|
||||
|
||||
class QuotaClassTestCase(test.TestCase, ModelsObjectComparatorMixin):
|
||||
|
||||
def setUp(self):
|
||||
super(QuotaClassTestCase, self).setUp()
|
||||
self.ctxt = context.get_admin_context()
|
||||
|
||||
def test_quota_class_get_default(self):
|
||||
params = {
|
||||
'test_resource1': '10',
|
||||
'test_resource2': '20',
|
||||
'test_resource3': '30',
|
||||
}
|
||||
for res, limit in params.items():
|
||||
db.quota_class_create(self.ctxt, 'default', res, limit)
|
||||
|
||||
defaults = db.quota_class_get_default(self.ctxt)
|
||||
self.assertEqual(defaults, dict(class_name='default',
|
||||
test_resource1=10,
|
||||
test_resource2=20,
|
||||
test_resource3=30))
|
||||
|
||||
|
||||
class ArchiveTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
|
|
@ -739,23 +739,36 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||
|
||||
def test_get_defaults(self):
|
||||
# Use our pre-defined resources
|
||||
self._stub_quota_class_get_default()
|
||||
result = self.driver.get_defaults(None, quota.QUOTAS._resources)
|
||||
|
||||
self.assertEqual(result, dict(
|
||||
instances=10,
|
||||
instances=5,
|
||||
cores=20,
|
||||
ram=50 * 1024,
|
||||
ram=25 * 1024,
|
||||
floating_ips=10,
|
||||
fixed_ips=10,
|
||||
metadata_items=128,
|
||||
metadata_items=64,
|
||||
injected_files=5,
|
||||
injected_file_content_bytes=10 * 1024,
|
||||
injected_file_content_bytes=5 * 1024,
|
||||
injected_file_path_bytes=255,
|
||||
security_groups=10,
|
||||
security_group_rules=20,
|
||||
key_pairs=100,
|
||||
))
|
||||
|
||||
def _stub_quota_class_get_default(self):
|
||||
# Stub out quota_class_get_default
|
||||
def fake_qcgd(context):
|
||||
self.calls.append('quota_class_get_default')
|
||||
return dict(
|
||||
instances=5,
|
||||
ram=25 * 1024,
|
||||
metadata_items=64,
|
||||
injected_file_content_bytes=5 * 1024,
|
||||
)
|
||||
self.stubs.Set(db, 'quota_class_get_default', fake_qcgd)
|
||||
|
||||
def _stub_quota_class_get_all_by_name(self):
|
||||
# Stub out quota_class_get_all_by_name
|
||||
def fake_qcgabn(context, quota_class):
|
||||
|
@ -831,6 +844,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||
self.stubs.Set(db, 'quota_usage_get_all_by_project', fake_qugabp)
|
||||
|
||||
self._stub_quota_class_get_all_by_name()
|
||||
self._stub_quota_class_get_default()
|
||||
|
||||
def test_get_project_quotas(self):
|
||||
self.maxDiff = None
|
||||
|
@ -843,6 +857,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||
'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(
|
||||
|
@ -917,10 +932,11 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||
self.assertEqual(self.calls, [
|
||||
'quota_get_all_by_project',
|
||||
'quota_usage_get_all_by_project',
|
||||
'quota_class_get_default',
|
||||
])
|
||||
self.assertEqual(result, dict(
|
||||
instances=dict(
|
||||
limit=10,
|
||||
limit=5,
|
||||
in_use=2,
|
||||
reserved=2,
|
||||
),
|
||||
|
@ -930,7 +946,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||
reserved=4,
|
||||
),
|
||||
ram=dict(
|
||||
limit=50 * 1024,
|
||||
limit=25 * 1024,
|
||||
in_use=10 * 1024,
|
||||
reserved=0,
|
||||
),
|
||||
|
@ -945,7 +961,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||
reserved=0,
|
||||
),
|
||||
metadata_items=dict(
|
||||
limit=128,
|
||||
limit=64,
|
||||
in_use=0,
|
||||
reserved=0,
|
||||
),
|
||||
|
@ -955,7 +971,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||
reserved=0,
|
||||
),
|
||||
injected_file_content_bytes=dict(
|
||||
limit=10 * 1024,
|
||||
limit=5 * 1024,
|
||||
in_use=0,
|
||||
reserved=0,
|
||||
),
|
||||
|
@ -992,6 +1008,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||
'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(
|
||||
|
@ -1066,6 +1083,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
|||
'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(
|
||||
cores=dict(
|
||||
|
@ -1094,6 +1112,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(
|
||||
instances=dict(
|
||||
|
|
Loading…
Reference in New Issue