Several changes designed to bring the openstack api 1.1 closer to spec
- add ram limits to the nova compute quotas - enable injected file limits and injected file size limits to be overridden in the quota database table - expose quota limits as absolute limits in the openstack api 1.1 limits resource - add support for controlling 'unlimited' quotas to nova-manage
This commit is contained in:
@@ -417,12 +417,16 @@ class ProjectCommands(object):
|
|||||||
arguments: project_id [key] [value]"""
|
arguments: project_id [key] [value]"""
|
||||||
ctxt = context.get_admin_context()
|
ctxt = context.get_admin_context()
|
||||||
if key:
|
if key:
|
||||||
|
if value.lower() == 'unlimited':
|
||||||
|
value = None
|
||||||
try:
|
try:
|
||||||
db.quota_update(ctxt, project_id, key, value)
|
db.quota_update(ctxt, project_id, key, value)
|
||||||
except exception.ProjectQuotaNotFound:
|
except exception.ProjectQuotaNotFound:
|
||||||
db.quota_create(ctxt, project_id, key, value)
|
db.quota_create(ctxt, project_id, key, value)
|
||||||
project_quota = quota.get_quota(ctxt, project_id)
|
project_quota = quota.get_project_quotas(ctxt, project_id)
|
||||||
for key, value in project_quota.iteritems():
|
for key, value in project_quota.iteritems():
|
||||||
|
if value is None:
|
||||||
|
value = 'unlimited'
|
||||||
print '%s: %s' % (key, value)
|
print '%s: %s' % (key, value)
|
||||||
|
|
||||||
def remove(self, project_id, user_id):
|
def remove(self, project_id, user_id):
|
||||||
|
108
nova/quota.py
108
nova/quota.py
@@ -28,6 +28,8 @@ flags.DEFINE_integer('quota_instances', 10,
|
|||||||
'number of instances allowed per project')
|
'number of instances allowed per project')
|
||||||
flags.DEFINE_integer('quota_cores', 20,
|
flags.DEFINE_integer('quota_cores', 20,
|
||||||
'number of instance cores allowed per project')
|
'number of instance cores allowed per project')
|
||||||
|
flags.DEFINE_integer('quota_ram', 50 * 1024,
|
||||||
|
'megabytes of instance ram allowed per project')
|
||||||
flags.DEFINE_integer('quota_volumes', 10,
|
flags.DEFINE_integer('quota_volumes', 10,
|
||||||
'number of volumes allowed per project')
|
'number of volumes allowed per project')
|
||||||
flags.DEFINE_integer('quota_gigabytes', 1000,
|
flags.DEFINE_integer('quota_gigabytes', 1000,
|
||||||
@@ -44,14 +46,28 @@ flags.DEFINE_integer('quota_max_injected_file_path_bytes', 255,
|
|||||||
'number of bytes allowed per injected file path')
|
'number of bytes allowed per injected file path')
|
||||||
|
|
||||||
|
|
||||||
def get_quota(context, project_id):
|
def _get_default_quotas():
|
||||||
rval = {'instances': FLAGS.quota_instances,
|
defaults = {
|
||||||
'cores': FLAGS.quota_cores,
|
'instances': FLAGS.quota_instances,
|
||||||
'volumes': FLAGS.quota_volumes,
|
'cores': FLAGS.quota_cores,
|
||||||
'gigabytes': FLAGS.quota_gigabytes,
|
'ram': FLAGS.quota_ram,
|
||||||
'floating_ips': FLAGS.quota_floating_ips,
|
'volumes': FLAGS.quota_volumes,
|
||||||
'metadata_items': FLAGS.quota_metadata_items}
|
'gigabytes': FLAGS.quota_gigabytes,
|
||||||
|
'floating_ips': FLAGS.quota_floating_ips,
|
||||||
|
'metadata_items': FLAGS.quota_metadata_items,
|
||||||
|
'injected_files': FLAGS.quota_max_injected_files,
|
||||||
|
'injected_file_content_bytes':
|
||||||
|
FLAGS.quota_max_injected_file_content_bytes,
|
||||||
|
}
|
||||||
|
# -1 in the quota flags means unlimited
|
||||||
|
for key in defaults.keys():
|
||||||
|
if defaults[key] == -1:
|
||||||
|
defaults[key] = None
|
||||||
|
return defaults
|
||||||
|
|
||||||
|
|
||||||
|
def get_project_quotas(context, project_id):
|
||||||
|
rval = _get_default_quotas()
|
||||||
quota = db.quota_get_all_by_project(context, project_id)
|
quota = db.quota_get_all_by_project(context, project_id)
|
||||||
for key in rval.keys():
|
for key in rval.keys():
|
||||||
if key in quota:
|
if key in quota:
|
||||||
@@ -65,71 +81,81 @@ def _get_request_allotment(requested, used, quota):
|
|||||||
return quota - used
|
return quota - used
|
||||||
|
|
||||||
|
|
||||||
def allowed_instances(context, num_instances, instance_type):
|
def allowed_instances(context, requested_instances, instance_type):
|
||||||
"""Check quota and return min(num_instances, allowed_instances)."""
|
"""Check quota and return min(requested_instances, allowed_instances)."""
|
||||||
project_id = context.project_id
|
project_id = context.project_id
|
||||||
context = context.elevated()
|
context = context.elevated()
|
||||||
num_cores = num_instances * instance_type['vcpus']
|
requested_cores = requested_instances * instance_type['vcpus']
|
||||||
used_instances, used_cores = db.instance_data_get_for_project(context,
|
requested_ram = requested_instances * instance_type['memory_mb']
|
||||||
project_id)
|
usage = db.instance_data_get_for_project(context, project_id)
|
||||||
quota = get_quota(context, project_id)
|
used_instances, used_cores, used_ram = usage
|
||||||
allowed_instances = _get_request_allotment(num_instances, used_instances,
|
quota = get_project_quotas(context, project_id)
|
||||||
|
allowed_instances = _get_request_allotment(requested_instances,
|
||||||
|
used_instances,
|
||||||
quota['instances'])
|
quota['instances'])
|
||||||
allowed_cores = _get_request_allotment(num_cores, used_cores,
|
allowed_cores = _get_request_allotment(requested_cores, used_cores,
|
||||||
quota['cores'])
|
quota['cores'])
|
||||||
|
allowed_ram = _get_request_allotment(requested_ram, used_ram, quota['ram'])
|
||||||
allowed_instances = min(allowed_instances,
|
allowed_instances = min(allowed_instances,
|
||||||
int(allowed_cores // instance_type['vcpus']))
|
allowed_cores // instance_type['vcpus'],
|
||||||
return min(num_instances, allowed_instances)
|
allowed_ram // instance_type['memory_mb'])
|
||||||
|
return min(requested_instances, allowed_instances)
|
||||||
|
|
||||||
|
|
||||||
def allowed_volumes(context, num_volumes, size):
|
def allowed_volumes(context, requested_volumes, size):
|
||||||
"""Check quota and return min(num_volumes, allowed_volumes)."""
|
"""Check quota and return min(requested_volumes, allowed_volumes)."""
|
||||||
project_id = context.project_id
|
project_id = context.project_id
|
||||||
context = context.elevated()
|
context = context.elevated()
|
||||||
size = int(size)
|
size = int(size)
|
||||||
num_gigabytes = num_volumes * size
|
requested_gigabytes = requested_volumes * size
|
||||||
used_volumes, used_gigabytes = db.volume_data_get_for_project(context,
|
used_volumes, used_gigabytes = db.volume_data_get_for_project(context,
|
||||||
project_id)
|
project_id)
|
||||||
quota = get_quota(context, project_id)
|
quota = get_project_quotas(context, project_id)
|
||||||
allowed_volumes = _get_request_allotment(num_volumes, used_volumes,
|
allowed_volumes = _get_request_allotment(requested_volumes, used_volumes,
|
||||||
quota['volumes'])
|
quota['volumes'])
|
||||||
allowed_gigabytes = _get_request_allotment(num_gigabytes, used_gigabytes,
|
allowed_gigabytes = _get_request_allotment(requested_gigabytes,
|
||||||
|
used_gigabytes,
|
||||||
quota['gigabytes'])
|
quota['gigabytes'])
|
||||||
allowed_volumes = min(allowed_volumes,
|
allowed_volumes = min(allowed_volumes,
|
||||||
int(allowed_gigabytes // size))
|
int(allowed_gigabytes // size))
|
||||||
return min(num_volumes, allowed_volumes)
|
return min(requested_volumes, allowed_volumes)
|
||||||
|
|
||||||
|
|
||||||
def allowed_floating_ips(context, num_floating_ips):
|
def allowed_floating_ips(context, requested_floating_ips):
|
||||||
"""Check quota and return min(num_floating_ips, allowed_floating_ips)."""
|
"""Check quota and return min(requested, allowed) floating ips."""
|
||||||
project_id = context.project_id
|
project_id = context.project_id
|
||||||
context = context.elevated()
|
context = context.elevated()
|
||||||
used_floating_ips = db.floating_ip_count_by_project(context, project_id)
|
used_floating_ips = db.floating_ip_count_by_project(context, project_id)
|
||||||
quota = get_quota(context, project_id)
|
quota = get_project_quotas(context, project_id)
|
||||||
allowed_floating_ips = _get_request_allotment(num_floating_ips,
|
allowed_floating_ips = _get_request_allotment(requested_floating_ips,
|
||||||
used_floating_ips,
|
used_floating_ips,
|
||||||
quota['floating_ips'])
|
quota['floating_ips'])
|
||||||
return min(num_floating_ips, allowed_floating_ips)
|
return min(requested_floating_ips, allowed_floating_ips)
|
||||||
|
|
||||||
|
|
||||||
def allowed_metadata_items(context, num_metadata_items):
|
def _calculate_simple_quota(context, resource, requested):
|
||||||
"""Check quota; return min(num_metadata_items,allowed_metadata_items)."""
|
"""Check quota for resource; return min(requested, allowed)."""
|
||||||
project_id = context.project_id
|
quota = get_project_quotas(context, context.project_id)
|
||||||
context = context.elevated()
|
allowed = _get_request_allotment(requested, 0, quota[resource])
|
||||||
quota = get_quota(context, project_id)
|
return min(requested, allowed)
|
||||||
allowed_metadata_items = _get_request_allotment(num_metadata_items, 0,
|
|
||||||
quota['metadata_items'])
|
|
||||||
return min(num_metadata_items, allowed_metadata_items)
|
|
||||||
|
|
||||||
|
|
||||||
def allowed_injected_files(context):
|
def allowed_metadata_items(context, requested_metadata_items):
|
||||||
|
"""Return the number of metadata items allowed."""
|
||||||
|
return _calculate_simple_quota(context, 'metadata_items',
|
||||||
|
requested_metadata_items)
|
||||||
|
|
||||||
|
|
||||||
|
def allowed_injected_files(context, requested_injected_files):
|
||||||
"""Return the number of injected files allowed."""
|
"""Return the number of injected files allowed."""
|
||||||
return FLAGS.quota_max_injected_files
|
return _calculate_simple_quota(context, 'injected_files',
|
||||||
|
requested_injected_files)
|
||||||
|
|
||||||
|
|
||||||
def allowed_injected_file_content_bytes(context):
|
def allowed_injected_file_content_bytes(context, requested_bytes):
|
||||||
"""Return the number of bytes allowed per injected file content."""
|
"""Return the number of bytes allowed per injected file content."""
|
||||||
return FLAGS.quota_max_injected_file_content_bytes
|
resource = 'injected_file_content_bytes'
|
||||||
|
return _calculate_simple_quota(context, resource, requested_bytes)
|
||||||
|
|
||||||
|
|
||||||
def allowed_injected_file_path_bytes(context):
|
def allowed_injected_file_path_bytes(context):
|
||||||
|
Reference in New Issue
Block a user