Revert per-user-quotas
See bug 1034384, bug 1037590. This reverts commit https://github.com/openstack/nova/commit/391f345d, but leaves the DB migration in place while adding a further migration to reverse it. The motivation for reversion is that the per-user quota logic would totally undermine the per-project quotas set for a pre-existing openstack install. The per-user quota logic could be re-introduced in a fixed state after Folsom-3. Change-Id: Idd4b55a2404a25f43f6737b661f828c28501066f
This commit is contained in:
parent
7819a052ff
commit
db27681b43
@ -224,10 +224,6 @@ def _db_error(caught_exception):
|
||||
class ProjectCommands(object):
|
||||
"""Class for managing projects."""
|
||||
|
||||
@args('--project', dest="project_id", metavar='<Project name>',
|
||||
help='Project name')
|
||||
@args('--key', dest="key", metavar='<key>', help='Key')
|
||||
@args('--value', dest="value", metavar='<value>', help='Value')
|
||||
def quota(self, project_id, key=None, value=None):
|
||||
"""Set or display quotas for project"""
|
||||
ctxt = context.get_admin_context()
|
||||
@ -260,52 +256,6 @@ class ProjectCommands(object):
|
||||
AccountCommands = ProjectCommands
|
||||
|
||||
|
||||
class QuotaCommands(object):
|
||||
"""Class for managing quotas."""
|
||||
|
||||
@args('--project', dest="project_id", metavar='<Project name>',
|
||||
help='Project name')
|
||||
@args('--key', dest="key", metavar='<key>', help='Key')
|
||||
@args('--value', dest="value", metavar='<value>', help='Value')
|
||||
def project(self, project_id, key=None, value=None):
|
||||
"""Set or display quotas for project"""
|
||||
ctxt = context.get_admin_context()
|
||||
if key:
|
||||
if value.lower() == 'unlimited':
|
||||
value = None
|
||||
try:
|
||||
db.quota_update(ctxt, project_id, key, value)
|
||||
except exception.ProjectQuotaNotFound:
|
||||
db.quota_create(ctxt, project_id, key, value)
|
||||
project_quota = QUOTAS.get_project_quotas(ctxt, project_id)
|
||||
for key, value in project_quota.iteritems():
|
||||
if value['limit'] < 0 or value['limit'] is None:
|
||||
value['limit'] = 'unlimited'
|
||||
print '%s: %s' % (key, value['limit'])
|
||||
|
||||
@args('--user', dest="user_id", metavar='<User name>',
|
||||
help='User name')
|
||||
@args('--project', dest="project_id", metavar='<Project name>',
|
||||
help='Project name')
|
||||
@args('--key', dest="key", metavar='<key>', help='Key')
|
||||
@args('--value', dest="value", metavar='<value>', help='Value')
|
||||
def user(self, user_id, project_id, key=None, value=None):
|
||||
"""Set or display quotas for user"""
|
||||
ctxt = context.get_admin_context()
|
||||
if key:
|
||||
if value.lower() == 'unlimited':
|
||||
value = None
|
||||
try:
|
||||
db.quota_update_for_user(ctxt, user_id, project_id, key, value)
|
||||
except exception.UserQuotaNotFound:
|
||||
db.quota_create_for_user(ctxt, user_id, project_id, key, value)
|
||||
user_quota = QUOTAS.get_user_quotas(ctxt, user_id, project_id)
|
||||
for key, value in user_quota.iteritems():
|
||||
if value['limit'] < 0 or value['limit'] is None:
|
||||
value['limit'] = 'unlimited'
|
||||
print '%s: %s' % (key, value['limit'])
|
||||
|
||||
|
||||
class FixedIpCommands(object):
|
||||
"""Class for managing fixed ip."""
|
||||
|
||||
@ -1364,7 +1314,6 @@ CATEGORIES = [
|
||||
('logs', GetLogCommands),
|
||||
('network', NetworkCommands),
|
||||
('project', ProjectCommands),
|
||||
('quota', QuotaCommands),
|
||||
('service', ServiceCommands),
|
||||
('shell', ShellCommands),
|
||||
('sm', StorageManagerCommands),
|
||||
|
@ -750,11 +750,6 @@ class QuotaResourceUnknown(QuotaNotFound):
|
||||
message = _("Unknown quota resources %(unknown)s.")
|
||||
|
||||
|
||||
class UserQuotaNotFound(QuotaNotFound):
|
||||
message = _("Quota for user %(user_id)s in project %(project_id)s "
|
||||
"could not be found.")
|
||||
|
||||
|
||||
class ProjectQuotaNotFound(QuotaNotFound):
|
||||
message = _("Quota for project %(project_id)s could not be found.")
|
||||
|
||||
|
241
nova/quota.py
241
nova/quota.py
@ -101,11 +101,6 @@ class DbQuotaDriver(object):
|
||||
|
||||
return db.quota_get(context, project_id, resource)
|
||||
|
||||
def get_by_user(self, context, user_id, project_id, resource):
|
||||
"""Get a specific quota by user."""
|
||||
|
||||
return db.quota_get_for_user(context, user_id, project_id, resource)
|
||||
|
||||
def get_by_class(self, context, quota_class, resource):
|
||||
"""Get a specific quota by quota class."""
|
||||
|
||||
@ -148,63 +143,6 @@ class DbQuotaDriver(object):
|
||||
|
||||
return quotas
|
||||
|
||||
def _process_quotas(self, context, resources, project_id, quotas,
|
||||
quota_class=None, defaults=True, usages=None):
|
||||
"""
|
||||
Given a list of resources, process the quotas for the given
|
||||
quotas and usages.
|
||||
|
||||
:param context: The request context, for access checks.
|
||||
:param resources: A dictionary of the registered resources.
|
||||
:param project_id: The ID of the project to return quotas for.
|
||||
:param quotas: The quotas dictionary need to be processed.
|
||||
:param quota_class: If project_id != context.project_id, the
|
||||
quota class cannot be determined. This
|
||||
parameter allows it to be specified. It
|
||||
will be ignored if project_id ==
|
||||
context.project_id.
|
||||
:param defaults: If True, the quota class value (or the
|
||||
default value, if there is no value from the
|
||||
quota class) will be reported if there is no
|
||||
specific value for the resource.
|
||||
:param usages: If not None, the current in_use and reserved counts
|
||||
will also be returned.
|
||||
"""
|
||||
|
||||
modified_quotas = {}
|
||||
# Get the quotas for the appropriate class. If the project ID
|
||||
# matches the one in the context, we use the quota_class from
|
||||
# the context, otherwise, we use the provided quota_class (if
|
||||
# any)
|
||||
if project_id == context.project_id:
|
||||
quota_class = context.quota_class
|
||||
if quota_class:
|
||||
class_quotas = db.quota_class_get_all_by_name(context, quota_class)
|
||||
else:
|
||||
class_quotas = {}
|
||||
|
||||
for resource in resources.values():
|
||||
# Omit default/quota class values
|
||||
if not defaults and resource.name not in quotas:
|
||||
continue
|
||||
|
||||
modified_quotas[resource.name] = dict(
|
||||
limit=quotas.get(resource.name, class_quotas.get(
|
||||
resource.name, resource.default)),
|
||||
)
|
||||
|
||||
# Include usages if desired. This is optional because one
|
||||
# internal consumer of this interface wants to access the
|
||||
# usages directly from inside a transaction.
|
||||
if usages:
|
||||
usage = usages.get(resource.name, {})
|
||||
modified_quotas[resource.name].update(
|
||||
in_use=usage.get('in_use', 0),
|
||||
reserved=usage.get('reserved', 0),
|
||||
)
|
||||
|
||||
return modified_quotas
|
||||
|
||||
def get_project_quotas(self, context, resources, project_id,
|
||||
quota_class=None, defaults=True,
|
||||
usages=True):
|
||||
@ -228,65 +166,44 @@ class DbQuotaDriver(object):
|
||||
will also be returned.
|
||||
"""
|
||||
|
||||
quotas = {}
|
||||
project_quotas = db.quota_get_all_by_project(context, project_id)
|
||||
|
||||
project_usages = None
|
||||
if usages:
|
||||
project_usages = db.quota_usage_get_all_by_project(context,
|
||||
project_id)
|
||||
|
||||
return self._process_quotas(context, resources,
|
||||
project_id, project_quotas,
|
||||
quota_class=quota_class,
|
||||
defaults=defaults,
|
||||
usages=project_usages)
|
||||
# Get the quotas for the appropriate class. If the project ID
|
||||
# matches the one in the context, we use the quota_class from
|
||||
# the context, otherwise, we use the provided quota_class (if
|
||||
# any)
|
||||
if project_id == context.project_id:
|
||||
quota_class = context.quota_class
|
||||
if quota_class:
|
||||
class_quotas = db.quota_class_get_all_by_name(context, quota_class)
|
||||
else:
|
||||
class_quotas = {}
|
||||
|
||||
def get_user_quotas(self, context, resources, user_id, project_id,
|
||||
quota_class=None, defaults=True,
|
||||
usages=True):
|
||||
"""
|
||||
Given a list of resources, retrieve the quotas for the given
|
||||
user.
|
||||
for resource in resources.values():
|
||||
# Omit default/quota class values
|
||||
if not defaults and resource.name not in project_quotas:
|
||||
continue
|
||||
|
||||
:param context: The request context, for access checks.
|
||||
:param resources: A dictionary of the registered resources.
|
||||
:param project_id: The ID of the project to return quotas for.
|
||||
:param user_id: The ID of the user to return quotas for.
|
||||
:param quota_class: If project_id != context.project_id, the
|
||||
quota class cannot be determined. This
|
||||
parameter allows it to be specified. It
|
||||
will be ignored if project_id ==
|
||||
context.project_id.
|
||||
:param defaults: If True, the quota class value (or the
|
||||
default value, if there is no value from the
|
||||
quota class) will be reported if there is no
|
||||
specific value for the resource.
|
||||
:param usages: If True, the current in_use and reserved counts
|
||||
will also be returned.
|
||||
"""
|
||||
quotas[resource.name] = dict(
|
||||
limit=project_quotas.get(resource.name, class_quotas.get(
|
||||
resource.name, resource.default)),
|
||||
)
|
||||
|
||||
user_quotas = db.quota_get_all_by_user(context, user_id, project_id)
|
||||
# Include usages if desired. This is optional because one
|
||||
# internal consumer of this interface wants to access the
|
||||
# usages directly from inside a transaction.
|
||||
if usages:
|
||||
usage = project_usages.get(resource.name, {})
|
||||
quotas[resource.name].update(
|
||||
in_use=usage.get('in_use', 0),
|
||||
reserved=usage.get('reserved', 0),
|
||||
)
|
||||
|
||||
user_usages = None
|
||||
if usages:
|
||||
user_usages = db.quota_usage_get_all_by_user(context,
|
||||
user_id,
|
||||
project_id)
|
||||
|
||||
return self._process_quotas(context, resources,
|
||||
project_id, user_quotas,
|
||||
quota_class=quota_class,
|
||||
defaults=defaults,
|
||||
usages=user_usages)
|
||||
|
||||
def get_remaining_quotas(self, context, project_id, resources):
|
||||
"""Get the remaining quotas for the given project."""
|
||||
defaults = self.get_defaults(context, resources)
|
||||
quotas = db.quota_get_remaining(context, project_id)
|
||||
for key in defaults.keys():
|
||||
if key in quotas:
|
||||
defaults[key] = quotas[key]
|
||||
return defaults
|
||||
return quotas
|
||||
|
||||
def _get_quotas(self, context, resources, keys, has_sync):
|
||||
"""
|
||||
@ -318,10 +235,9 @@ class DbQuotaDriver(object):
|
||||
raise exception.QuotaResourceUnknown(unknown=sorted(unknown))
|
||||
|
||||
# Grab and return the quotas (without usages)
|
||||
quotas = self.get_user_quotas(context, sub_resources,
|
||||
context.user_id,
|
||||
context.project_id,
|
||||
context.quota_class, usages=False)
|
||||
quotas = self.get_project_quotas(context, sub_resources,
|
||||
context.project_id,
|
||||
context.quota_class, usages=False)
|
||||
|
||||
return dict((k, v['limit']) for k, v in quotas.items())
|
||||
|
||||
@ -452,18 +368,6 @@ class DbQuotaDriver(object):
|
||||
|
||||
db.quota_destroy_all_by_project(context, project_id)
|
||||
|
||||
def destroy_all_by_user(self, context, user_id, project_id):
|
||||
"""
|
||||
Destroy all quotas, usages, and reservations associated with a
|
||||
user.
|
||||
|
||||
:param context: The request context, for access checks.
|
||||
:param user_id: The ID of the user being deleted.
|
||||
:param project_id: The ID of the project being deleted.
|
||||
"""
|
||||
|
||||
db.quota_destroy_all_by_user(context, user_id, project_id)
|
||||
|
||||
def expire(self, context):
|
||||
"""Expire reservations.
|
||||
|
||||
@ -662,11 +566,6 @@ class QuotaEngine(object):
|
||||
|
||||
return self._driver.get_by_project(context, project_id, resource)
|
||||
|
||||
def get_by_user(self, context, user_id, project_id, resource):
|
||||
"""Get a specific quota by user."""
|
||||
|
||||
return self._driver.get_by_user(context, user_id, project_id, resource)
|
||||
|
||||
def get_by_class(self, context, quota_class, resource):
|
||||
"""Get a specific quota by quota class."""
|
||||
|
||||
@ -712,46 +611,10 @@ class QuotaEngine(object):
|
||||
"""
|
||||
|
||||
return self._driver.get_project_quotas(context, self._resources,
|
||||
project_id,
|
||||
quota_class=quota_class,
|
||||
defaults=defaults,
|
||||
usages=usages)
|
||||
|
||||
def get_user_quotas(self, context, user_id, project_id,
|
||||
quota_class=None, defaults=True,
|
||||
usages=True):
|
||||
"""Retrieve the quotas for the given user.
|
||||
|
||||
:param context: The request context, for access checks.
|
||||
:param user_id: The ID of the user to return quotas for.
|
||||
:param project_id: The ID of the project to return quotas for.
|
||||
:param quota_class: If project_id != context.project_id, the
|
||||
quota class cannot be determined. This
|
||||
parameter allows it to be specified.
|
||||
:param defaults: If True, the quota class value (or the
|
||||
default value, if there is no value from the
|
||||
quota class) will be reported if there is no
|
||||
specific value for the resource.
|
||||
:param usages: If True, the current in_use and reserved counts
|
||||
will also be returned.
|
||||
"""
|
||||
|
||||
return self._driver.get_user_quotas(context, self._resources,
|
||||
user_id,
|
||||
project_id,
|
||||
quota_class=quota_class,
|
||||
defaults=defaults,
|
||||
usages=usages)
|
||||
|
||||
def get_remaining_quotas(self, context, project_id):
|
||||
"""Retrieve the remaining quotas for the given project.
|
||||
|
||||
:param context: The request context, for access checks.
|
||||
:param project_id: The ID of the project to return quotas for.
|
||||
"""
|
||||
|
||||
return self._driver.get_remaining_quotas(context, project_id,
|
||||
self._resources)
|
||||
project_id,
|
||||
quota_class=quota_class,
|
||||
defaults=defaults,
|
||||
usages=usages)
|
||||
|
||||
def count(self, context, resource, *args, **kwargs):
|
||||
"""Count a resource.
|
||||
@ -882,18 +745,6 @@ class QuotaEngine(object):
|
||||
|
||||
self._driver.destroy_all_by_project(context, project_id)
|
||||
|
||||
def destroy_all_by_user(self, context, user_id, project_id):
|
||||
"""
|
||||
Destroy all quotas, usages, and reservations associated with a
|
||||
user.
|
||||
|
||||
:param context: The request context, for access checks.
|
||||
:param user_id: The ID of the user being deleted.
|
||||
:param project_id: The ID of the project being deleted.
|
||||
"""
|
||||
|
||||
self._driver.destroy_all_by_user(context, user_id, project_id)
|
||||
|
||||
def expire(self, context):
|
||||
"""Expire reservations.
|
||||
|
||||
@ -910,26 +761,26 @@ class QuotaEngine(object):
|
||||
return sorted(self._resources.keys())
|
||||
|
||||
|
||||
def _sync_instances(context, user_id, project_id, session):
|
||||
def _sync_instances(context, project_id, session):
|
||||
return dict(zip(('instances', 'cores', 'ram'),
|
||||
db.instance_data_get_for_user(
|
||||
context, user_id, project_id, session=session)))
|
||||
db.instance_data_get_for_project(
|
||||
context, project_id, session=session)))
|
||||
|
||||
|
||||
def _sync_volumes(context, user_id, project_id, session):
|
||||
def _sync_volumes(context, project_id, session):
|
||||
return dict(zip(('volumes', 'gigabytes'),
|
||||
db.volume_data_get_for_user(
|
||||
context, user_id, project_id, session=session)))
|
||||
db.volume_data_get_for_project(
|
||||
context, project_id, session=session)))
|
||||
|
||||
|
||||
def _sync_floating_ips(context, user_id, project_id, session):
|
||||
def _sync_floating_ips(context, project_id, session):
|
||||
return dict(floating_ips=db.floating_ip_count_by_project(
|
||||
context, project_id, session=session))
|
||||
|
||||
|
||||
def _sync_security_groups(context, user_id, project_id, session):
|
||||
return dict(security_groups=db.security_group_count_by_user(
|
||||
context, user_id, project_id, session=session))
|
||||
def _sync_security_groups(context, project_id, session):
|
||||
return dict(security_groups=db.security_group_count_by_project(
|
||||
context, project_id, session=session))
|
||||
|
||||
|
||||
QUOTAS = QuotaEngine()
|
||||
|
@ -105,8 +105,7 @@
|
||||
"compute_extension:networks": [],
|
||||
"compute_extension:networks:view": [],
|
||||
"compute_extension:quotas:show": [],
|
||||
"compute_extension:quotas:update_for_project": [],
|
||||
"compute_extension:quotas:update_for_user": [],
|
||||
"compute_extension:quotas:update": [],
|
||||
"compute_extension:quota_classes": [],
|
||||
"compute_extension:rescue": [],
|
||||
"compute_extension:security_groups": [],
|
||||
|
Loading…
Reference in New Issue
Block a user