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)
|
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):
|
def quota_class_get_all_by_name(context, class_name):
|
||||||
"""Retrieve all quotas associated with a given quota class."""
|
"""Retrieve all quotas associated with a given quota class."""
|
||||||
return IMPL.quota_class_get_all_by_name(context, class_name)
|
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_'
|
_SHADOW_TABLE_PREFIX = 'shadow_'
|
||||||
|
_DEFAULT_QUOTA_NAME = 'default'
|
||||||
|
|
||||||
|
|
||||||
def get_backend():
|
def get_backend():
|
||||||
|
@ -2576,6 +2577,18 @@ def quota_class_get(context, class_name, resource):
|
||||||
return result
|
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
|
@require_context
|
||||||
def quota_class_get_all_by_name(context, class_name):
|
def quota_class_get_all_by_name(context, class_name):
|
||||||
nova.context.authorize_quota_class_context(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):
|
def get_defaults(self, context, resources):
|
||||||
"""Given a list of resources, retrieve the default quotas.
|
"""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 context: The request context, for access checks.
|
||||||
:param resources: A dictionary of the registered resources.
|
:param resources: A dictionary of the registered resources.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
quotas = {}
|
quotas = {}
|
||||||
|
default_quotas = db.quota_class_get_default(context)
|
||||||
for resource in resources.values():
|
for resource in resources.values():
|
||||||
quotas[resource.name] = resource.default
|
quotas[resource.name] = default_quotas.get(resource.name,
|
||||||
|
resource.default)
|
||||||
|
|
||||||
return quotas
|
return quotas
|
||||||
|
|
||||||
|
@ -180,6 +184,8 @@ class DbQuotaDriver(object):
|
||||||
else:
|
else:
|
||||||
class_quotas = {}
|
class_quotas = {}
|
||||||
|
|
||||||
|
default_quotas = self.get_defaults(context, resources)
|
||||||
|
|
||||||
for resource in resources.values():
|
for resource in resources.values():
|
||||||
# Omit default/quota class values
|
# Omit default/quota class values
|
||||||
if not defaults and resource.name not in project_quotas:
|
if not defaults and resource.name not in project_quotas:
|
||||||
|
@ -187,7 +193,7 @@ class DbQuotaDriver(object):
|
||||||
|
|
||||||
quotas[resource.name] = dict(
|
quotas[resource.name] = dict(
|
||||||
limit=project_quotas.get(resource.name, class_quotas.get(
|
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
|
# Include usages if desired. This is optional because one
|
||||||
|
|
|
@ -3930,6 +3930,28 @@ class KeyPairTestCase(test.TestCase, ModelsObjectComparatorMixin):
|
||||||
param['user_id'], param['name'])
|
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):
|
class ArchiveTestCase(test.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
@ -739,23 +739,36 @@ class DbQuotaDriverTestCase(test.TestCase):
|
||||||
|
|
||||||
def test_get_defaults(self):
|
def test_get_defaults(self):
|
||||||
# Use our pre-defined resources
|
# Use our pre-defined resources
|
||||||
|
self._stub_quota_class_get_default()
|
||||||
result = self.driver.get_defaults(None, quota.QUOTAS._resources)
|
result = self.driver.get_defaults(None, quota.QUOTAS._resources)
|
||||||
|
|
||||||
self.assertEqual(result, dict(
|
self.assertEqual(result, dict(
|
||||||
instances=10,
|
instances=5,
|
||||||
cores=20,
|
cores=20,
|
||||||
ram=50 * 1024,
|
ram=25 * 1024,
|
||||||
floating_ips=10,
|
floating_ips=10,
|
||||||
fixed_ips=10,
|
fixed_ips=10,
|
||||||
metadata_items=128,
|
metadata_items=64,
|
||||||
injected_files=5,
|
injected_files=5,
|
||||||
injected_file_content_bytes=10 * 1024,
|
injected_file_content_bytes=5 * 1024,
|
||||||
injected_file_path_bytes=255,
|
injected_file_path_bytes=255,
|
||||||
security_groups=10,
|
security_groups=10,
|
||||||
security_group_rules=20,
|
security_group_rules=20,
|
||||||
key_pairs=100,
|
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):
|
def _stub_quota_class_get_all_by_name(self):
|
||||||
# Stub out quota_class_get_all_by_name
|
# Stub out quota_class_get_all_by_name
|
||||||
def fake_qcgabn(context, quota_class):
|
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.stubs.Set(db, 'quota_usage_get_all_by_project', fake_qugabp)
|
||||||
|
|
||||||
self._stub_quota_class_get_all_by_name()
|
self._stub_quota_class_get_all_by_name()
|
||||||
|
self._stub_quota_class_get_default()
|
||||||
|
|
||||||
def test_get_project_quotas(self):
|
def test_get_project_quotas(self):
|
||||||
self.maxDiff = None
|
self.maxDiff = None
|
||||||
|
@ -843,6 +857,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
||||||
'quota_get_all_by_project',
|
'quota_get_all_by_project',
|
||||||
'quota_usage_get_all_by_project',
|
'quota_usage_get_all_by_project',
|
||||||
'quota_class_get_all_by_name',
|
'quota_class_get_all_by_name',
|
||||||
|
'quota_class_get_default',
|
||||||
])
|
])
|
||||||
self.assertEqual(result, dict(
|
self.assertEqual(result, dict(
|
||||||
instances=dict(
|
instances=dict(
|
||||||
|
@ -917,10 +932,11 @@ class DbQuotaDriverTestCase(test.TestCase):
|
||||||
self.assertEqual(self.calls, [
|
self.assertEqual(self.calls, [
|
||||||
'quota_get_all_by_project',
|
'quota_get_all_by_project',
|
||||||
'quota_usage_get_all_by_project',
|
'quota_usage_get_all_by_project',
|
||||||
|
'quota_class_get_default',
|
||||||
])
|
])
|
||||||
self.assertEqual(result, dict(
|
self.assertEqual(result, dict(
|
||||||
instances=dict(
|
instances=dict(
|
||||||
limit=10,
|
limit=5,
|
||||||
in_use=2,
|
in_use=2,
|
||||||
reserved=2,
|
reserved=2,
|
||||||
),
|
),
|
||||||
|
@ -930,7 +946,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
||||||
reserved=4,
|
reserved=4,
|
||||||
),
|
),
|
||||||
ram=dict(
|
ram=dict(
|
||||||
limit=50 * 1024,
|
limit=25 * 1024,
|
||||||
in_use=10 * 1024,
|
in_use=10 * 1024,
|
||||||
reserved=0,
|
reserved=0,
|
||||||
),
|
),
|
||||||
|
@ -945,7 +961,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
||||||
reserved=0,
|
reserved=0,
|
||||||
),
|
),
|
||||||
metadata_items=dict(
|
metadata_items=dict(
|
||||||
limit=128,
|
limit=64,
|
||||||
in_use=0,
|
in_use=0,
|
||||||
reserved=0,
|
reserved=0,
|
||||||
),
|
),
|
||||||
|
@ -955,7 +971,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
||||||
reserved=0,
|
reserved=0,
|
||||||
),
|
),
|
||||||
injected_file_content_bytes=dict(
|
injected_file_content_bytes=dict(
|
||||||
limit=10 * 1024,
|
limit=5 * 1024,
|
||||||
in_use=0,
|
in_use=0,
|
||||||
reserved=0,
|
reserved=0,
|
||||||
),
|
),
|
||||||
|
@ -992,6 +1008,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
||||||
'quota_get_all_by_project',
|
'quota_get_all_by_project',
|
||||||
'quota_usage_get_all_by_project',
|
'quota_usage_get_all_by_project',
|
||||||
'quota_class_get_all_by_name',
|
'quota_class_get_all_by_name',
|
||||||
|
'quota_class_get_default',
|
||||||
])
|
])
|
||||||
self.assertEqual(result, dict(
|
self.assertEqual(result, dict(
|
||||||
instances=dict(
|
instances=dict(
|
||||||
|
@ -1066,6 +1083,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
||||||
'quota_get_all_by_project',
|
'quota_get_all_by_project',
|
||||||
'quota_usage_get_all_by_project',
|
'quota_usage_get_all_by_project',
|
||||||
'quota_class_get_all_by_name',
|
'quota_class_get_all_by_name',
|
||||||
|
'quota_class_get_default',
|
||||||
])
|
])
|
||||||
self.assertEqual(result, dict(
|
self.assertEqual(result, dict(
|
||||||
cores=dict(
|
cores=dict(
|
||||||
|
@ -1094,6 +1112,7 @@ class DbQuotaDriverTestCase(test.TestCase):
|
||||||
self.assertEqual(self.calls, [
|
self.assertEqual(self.calls, [
|
||||||
'quota_get_all_by_project',
|
'quota_get_all_by_project',
|
||||||
'quota_class_get_all_by_name',
|
'quota_class_get_all_by_name',
|
||||||
|
'quota_class_get_default',
|
||||||
])
|
])
|
||||||
self.assertEqual(result, dict(
|
self.assertEqual(result, dict(
|
||||||
instances=dict(
|
instances=dict(
|
||||||
|
|
Loading…
Reference in New Issue