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
06d1f0dfd5
commit
1cf475d7a1
|
@ -224,10 +224,6 @@ def _db_error(caught_exception):
|
||||||
class ProjectCommands(object):
|
class ProjectCommands(object):
|
||||||
"""Class for managing projects."""
|
"""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):
|
def quota(self, project_id, key=None, value=None):
|
||||||
"""Set or display quotas for project"""
|
"""Set or display quotas for project"""
|
||||||
ctxt = context.get_admin_context()
|
ctxt = context.get_admin_context()
|
||||||
|
@ -260,52 +256,6 @@ class ProjectCommands(object):
|
||||||
AccountCommands = ProjectCommands
|
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 FixedIpCommands(object):
|
||||||
"""Class for managing fixed ip."""
|
"""Class for managing fixed ip."""
|
||||||
|
|
||||||
|
@ -1364,7 +1314,6 @@ CATEGORIES = [
|
||||||
('logs', GetLogCommands),
|
('logs', GetLogCommands),
|
||||||
('network', NetworkCommands),
|
('network', NetworkCommands),
|
||||||
('project', ProjectCommands),
|
('project', ProjectCommands),
|
||||||
('quota', QuotaCommands),
|
|
||||||
('service', ServiceCommands),
|
('service', ServiceCommands),
|
||||||
('shell', ShellCommands),
|
('shell', ShellCommands),
|
||||||
('sm', StorageManagerCommands),
|
('sm', StorageManagerCommands),
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{
|
{
|
||||||
"admin_or_owner": [["role:admin"], ["project_id:%(project_id)s"]],
|
"admin_or_owner": [["role:admin"], ["project_id:%(project_id)s"]],
|
||||||
"admin_or_projectadmin": [["role:projectadmin"], ["role:admin"]],
|
|
||||||
"default": [["rule:admin_or_owner"]],
|
"default": [["rule:admin_or_owner"]],
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,8 +48,7 @@
|
||||||
"compute_extension:networks": [["rule:admin_api"]],
|
"compute_extension:networks": [["rule:admin_api"]],
|
||||||
"compute_extension:networks:view": [],
|
"compute_extension:networks:view": [],
|
||||||
"compute_extension:quotas:show": [],
|
"compute_extension:quotas:show": [],
|
||||||
"compute_extension:quotas:update_for_project": [["rule:admin_api"]],
|
"compute_extension:quotas:update": [["rule:admin_api"]],
|
||||||
"compute_extension:quotas:update_for_user": [["rule:admin_or_projectadmin"]],
|
|
||||||
"compute_extension:quota_classes": [],
|
"compute_extension:quota_classes": [],
|
||||||
"compute_extension:rescue": [],
|
"compute_extension:rescue": [],
|
||||||
"compute_extension:security_groups": [],
|
"compute_extension:security_groups": [],
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import urlparse
|
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
from nova.api.openstack import extensions
|
from nova.api.openstack import extensions
|
||||||
|
@ -25,15 +24,13 @@ from nova import db
|
||||||
from nova.db.sqlalchemy import api as sqlalchemy_api
|
from nova.db.sqlalchemy import api as sqlalchemy_api
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import quota
|
from nova import quota
|
||||||
from nova import utils
|
|
||||||
|
|
||||||
|
|
||||||
QUOTAS = quota.QUOTAS
|
QUOTAS = quota.QUOTAS
|
||||||
|
|
||||||
|
|
||||||
def authorize_action(context, action_name):
|
authorize_update = extensions.extension_authorizer('compute', 'quotas:update')
|
||||||
action = 'quotas:%s' % action_name
|
authorize_show = extensions.extension_authorizer('compute', 'quotas:show')
|
||||||
extensions.extension_authorizer('compute', action)(context)
|
|
||||||
|
|
||||||
|
|
||||||
class QuotaTemplate(xmlutil.TemplateBuilder):
|
class QuotaTemplate(xmlutil.TemplateBuilder):
|
||||||
|
@ -60,102 +57,51 @@ class QuotaSetsController(object):
|
||||||
|
|
||||||
return dict(quota_set=result)
|
return dict(quota_set=result)
|
||||||
|
|
||||||
def _validate_quota_limit(self, limit, remain, quota):
|
def _validate_quota_limit(self, limit):
|
||||||
# NOTE: -1 is a flag value for unlimited
|
# NOTE: -1 is a flag value for unlimited
|
||||||
if limit < -1:
|
if limit < -1:
|
||||||
msg = _("Quota limit must be -1 or greater.")
|
msg = _("Quota limit must be -1 or greater.")
|
||||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
# Quota limit must be less than the remains of the project.
|
def _get_quotas(self, context, id, usages=False):
|
||||||
if remain != -1 and remain < limit - quota:
|
values = QUOTAS.get_project_quotas(context, id, usages=usages)
|
||||||
msg = _("Quota limit exceed the remains of the project.")
|
|
||||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
|
||||||
|
|
||||||
def _get_quotas(self, context, id, user_id=None, remaining=False,
|
|
||||||
usages=False):
|
|
||||||
# Get the remaining quotas for a project.
|
|
||||||
if remaining:
|
|
||||||
values = QUOTAS.get_remaining_quotas(context, id)
|
|
||||||
return values
|
|
||||||
|
|
||||||
if user_id:
|
|
||||||
# If user_id, return quotas for the given user.
|
|
||||||
values = QUOTAS.get_user_quotas(context, user_id, id,
|
|
||||||
usages=usages)
|
|
||||||
else:
|
|
||||||
values = QUOTAS.get_project_quotas(context, id, usages=usages)
|
|
||||||
|
|
||||||
if usages:
|
if usages:
|
||||||
return values
|
return values
|
||||||
else:
|
else:
|
||||||
return dict((k, v['limit']) for k, v in values.items())
|
return dict((k, v['limit']) for k, v in values.items())
|
||||||
|
|
||||||
def _request_params(self, req):
|
|
||||||
qs = req.environ.get('QUERY_STRING', '')
|
|
||||||
return urlparse.parse_qs(qs)
|
|
||||||
|
|
||||||
@wsgi.serializers(xml=QuotaTemplate)
|
@wsgi.serializers(xml=QuotaTemplate)
|
||||||
def show(self, req, id):
|
def show(self, req, id):
|
||||||
context = req.environ['nova.context']
|
context = req.environ['nova.context']
|
||||||
authorize_action(context, 'show')
|
authorize_show(context)
|
||||||
params = self._request_params(req)
|
|
||||||
remaining = False
|
|
||||||
if 'remaining' in params:
|
|
||||||
remaining = utils.bool_from_str(params["remaining"][0])
|
|
||||||
user_id = None
|
|
||||||
if 'user_id' in params:
|
|
||||||
user_id = params["user_id"][0]
|
|
||||||
try:
|
try:
|
||||||
sqlalchemy_api.authorize_project_context(context, id)
|
sqlalchemy_api.authorize_project_context(context, id)
|
||||||
return self._format_quota_set(id,
|
return self._format_quota_set(id, self._get_quotas(context, id))
|
||||||
self._get_quotas(context, id, user_id, remaining))
|
|
||||||
except exception.NotAuthorized:
|
except exception.NotAuthorized:
|
||||||
raise webob.exc.HTTPForbidden()
|
raise webob.exc.HTTPForbidden()
|
||||||
|
|
||||||
@wsgi.serializers(xml=QuotaTemplate)
|
@wsgi.serializers(xml=QuotaTemplate)
|
||||||
def update(self, req, id, body):
|
def update(self, req, id, body):
|
||||||
context = req.environ['nova.context']
|
context = req.environ['nova.context']
|
||||||
params = self._request_params(req)
|
authorize_update(context)
|
||||||
project_id = id
|
project_id = id
|
||||||
user_id = None
|
|
||||||
remains = {}
|
|
||||||
quotas = {}
|
|
||||||
if 'user_id' in params:
|
|
||||||
# Project admins are able to modify per-user quotas.
|
|
||||||
authorize_action(context, 'update_for_user')
|
|
||||||
user_id = params["user_id"][0]
|
|
||||||
remains = self._get_quotas(context, project_id, remaining=True)
|
|
||||||
quotas = db.quota_get_all_by_user(context, user_id, project_id)
|
|
||||||
else:
|
|
||||||
# Only admins are able to modify per-project quotas.
|
|
||||||
authorize_action(context, 'update_for_project')
|
|
||||||
|
|
||||||
for key in body['quota_set'].keys():
|
for key in body['quota_set'].keys():
|
||||||
if key in QUOTAS:
|
if key in QUOTAS:
|
||||||
value = int(body['quota_set'][key])
|
value = int(body['quota_set'][key])
|
||||||
|
self._validate_quota_limit(value)
|
||||||
try:
|
try:
|
||||||
if user_id:
|
db.quota_update(context, project_id, key, value)
|
||||||
self._validate_quota_limit(value, remains.get(key, 0),
|
|
||||||
quotas.get(key, 0))
|
|
||||||
db.quota_update_for_user(context, user_id,
|
|
||||||
project_id, key, value)
|
|
||||||
else:
|
|
||||||
self._validate_quota_limit(value, remains.get(key, -1),
|
|
||||||
quotas.get(key, 0))
|
|
||||||
db.quota_update(context, project_id, key, value)
|
|
||||||
except exception.ProjectQuotaNotFound:
|
except exception.ProjectQuotaNotFound:
|
||||||
db.quota_create(context, project_id, key, value)
|
db.quota_create(context, project_id, key, value)
|
||||||
except exception.UserQuotaNotFound:
|
|
||||||
db.quota_create_for_user(context, user_id,
|
|
||||||
project_id, key, value)
|
|
||||||
except exception.AdminRequired:
|
except exception.AdminRequired:
|
||||||
raise webob.exc.HTTPForbidden()
|
raise webob.exc.HTTPForbidden()
|
||||||
return {'quota_set': self._get_quotas(context, id, user_id)}
|
return {'quota_set': self._get_quotas(context, id)}
|
||||||
|
|
||||||
@wsgi.serializers(xml=QuotaTemplate)
|
@wsgi.serializers(xml=QuotaTemplate)
|
||||||
def defaults(self, req, id):
|
def defaults(self, req, id):
|
||||||
context = req.environ['nova.context']
|
context = req.environ['nova.context']
|
||||||
authorize_action(context, 'show')
|
authorize_show(context)
|
||||||
return self._format_quota_set(id, QUOTAS.get_defaults(context))
|
return self._format_quota_set(id, QUOTAS.get_defaults(context))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ import httplib
|
||||||
import math
|
import math
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
import urlparse
|
|
||||||
|
|
||||||
import webob.dec
|
import webob.dec
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
@ -86,18 +85,8 @@ class LimitsController(object):
|
||||||
Return all global and rate limit information.
|
Return all global and rate limit information.
|
||||||
"""
|
"""
|
||||||
context = req.environ['nova.context']
|
context = req.environ['nova.context']
|
||||||
qs = req.environ.get('QUERY_STRING', '')
|
quotas = QUOTAS.get_project_quotas(context, context.project_id,
|
||||||
params = urlparse.parse_qs(qs)
|
usages=False)
|
||||||
if 'user_id' in params:
|
|
||||||
user_id = params["user_id"][0]
|
|
||||||
quotas = QUOTAS.get_user_quotas(context, user_id,
|
|
||||||
context.project_id,
|
|
||||||
usages=False)
|
|
||||||
else:
|
|
||||||
quotas = QUOTAS.get_project_quotas(context,
|
|
||||||
context.project_id,
|
|
||||||
usages=False)
|
|
||||||
|
|
||||||
abs_limits = dict((k, v['limit']) for k, v in quotas.items())
|
abs_limits = dict((k, v['limit']) for k, v in quotas.items())
|
||||||
rate_limits = req.environ.get("nova.limits", [])
|
rate_limits = req.environ.get("nova.limits", [])
|
||||||
|
|
||||||
|
|
105
nova/db/api.py
105
nova/db/api.py
|
@ -568,12 +568,6 @@ def instance_create(context, values):
|
||||||
return IMPL.instance_create(context, values)
|
return IMPL.instance_create(context, values)
|
||||||
|
|
||||||
|
|
||||||
def instance_data_get_for_user(context, user_id, project_id, session=None):
|
|
||||||
"""Get (instance_count, total_cores, total_ram) for user."""
|
|
||||||
return IMPL.instance_data_get_for_user(context, user_id, project_id,
|
|
||||||
session=session)
|
|
||||||
|
|
||||||
|
|
||||||
def instance_data_get_for_project(context, project_id, session=None):
|
def instance_data_get_for_project(context, project_id, session=None):
|
||||||
"""Get (instance_count, total_cores, total_ram) for project."""
|
"""Get (instance_count, total_cores, total_ram) for project."""
|
||||||
return IMPL.instance_data_get_for_project(context, project_id,
|
return IMPL.instance_data_get_for_project(context, project_id,
|
||||||
|
@ -955,42 +949,6 @@ def quota_destroy(context, project_id, resource):
|
||||||
###################
|
###################
|
||||||
|
|
||||||
|
|
||||||
def quota_create_for_user(context, user_id, project_id, resource, limit):
|
|
||||||
"""Create a quota for the given user and project."""
|
|
||||||
return IMPL.quota_create_for_user(context, user_id,
|
|
||||||
project_id, resource, limit)
|
|
||||||
|
|
||||||
|
|
||||||
def quota_get_for_user(context, user_id, project_id, resource):
|
|
||||||
"""Retrieve a quota or raise if it does not exist."""
|
|
||||||
return IMPL.quota_get_for_user(context, user_id,
|
|
||||||
project_id, resource)
|
|
||||||
|
|
||||||
|
|
||||||
def quota_get_all_by_user(context, user_id, project_id):
|
|
||||||
"""Retrieve all quotas associated with a given user and project."""
|
|
||||||
return IMPL.quota_get_all_by_user(context, user_id, project_id)
|
|
||||||
|
|
||||||
|
|
||||||
def quota_get_remaining(context, project_id):
|
|
||||||
"""Retrieve the remaining quotas associated with a given project."""
|
|
||||||
return IMPL.quota_get_remaining(context, project_id)
|
|
||||||
|
|
||||||
|
|
||||||
def quota_update_for_user(context, user_id, project_id, resource, limit):
|
|
||||||
"""Update a quota or raise if it does not exist."""
|
|
||||||
return IMPL.quota_update_for_user(context, user_id,
|
|
||||||
project_id, resource, limit)
|
|
||||||
|
|
||||||
|
|
||||||
def quota_destroy_for_user(context, user_id, project_id, resource):
|
|
||||||
"""Destroy the quota or raise if it does not exist."""
|
|
||||||
return IMPL.quota_destroy_for_user(context, user_id, project_id, resource)
|
|
||||||
|
|
||||||
|
|
||||||
###################
|
|
||||||
|
|
||||||
|
|
||||||
def quota_class_create(context, class_name, resource, limit):
|
def quota_class_create(context, class_name, resource, limit):
|
||||||
"""Create a quota class for the given name and resource."""
|
"""Create a quota class for the given name and resource."""
|
||||||
return IMPL.quota_class_create(context, class_name, resource, limit)
|
return IMPL.quota_class_create(context, class_name, resource, limit)
|
||||||
|
@ -1024,21 +982,16 @@ def quota_class_destroy_all_by_name(context, class_name):
|
||||||
###################
|
###################
|
||||||
|
|
||||||
|
|
||||||
def quota_usage_create(context, user_id, project_id, resource, in_use,
|
def quota_usage_create(context, project_id, resource, in_use, reserved,
|
||||||
reserved, until_refresh):
|
until_refresh):
|
||||||
"""Create a quota usage for the given user and resource."""
|
"""Create a quota usage for the given project and resource."""
|
||||||
return IMPL.quota_usage_create(context, user_id, project_id, resource,
|
return IMPL.quota_usage_create(context, project_id, resource,
|
||||||
in_use, reserved, until_refresh)
|
in_use, reserved, until_refresh)
|
||||||
|
|
||||||
|
|
||||||
def quota_usage_get(context, user_id, project_id, resource):
|
def quota_usage_get(context, project_id, resource):
|
||||||
"""Retrieve a quota usage or raise if it does not exist."""
|
"""Retrieve a quota usage or raise if it does not exist."""
|
||||||
return IMPL.quota_usage_get(context, user_id, project_id, resource)
|
return IMPL.quota_usage_get(context, project_id, resource)
|
||||||
|
|
||||||
|
|
||||||
def quota_usage_get_all_by_user(context, user_id, project_id):
|
|
||||||
"""Retrieve all usage associated with a given user."""
|
|
||||||
return IMPL.quota_usage_get_all_by_user(context, user_id, project_id)
|
|
||||||
|
|
||||||
|
|
||||||
def quota_usage_get_all_by_project(context, project_id):
|
def quota_usage_get_all_by_project(context, project_id):
|
||||||
|
@ -1046,25 +999,25 @@ def quota_usage_get_all_by_project(context, project_id):
|
||||||
return IMPL.quota_usage_get_all_by_project(context, project_id)
|
return IMPL.quota_usage_get_all_by_project(context, project_id)
|
||||||
|
|
||||||
|
|
||||||
def quota_usage_update(context, user_id, project_id, resource, in_use,
|
def quota_usage_update(context, class_name, resource, in_use, reserved,
|
||||||
reserved, until_refresh):
|
until_refresh):
|
||||||
"""Update a quota usage or raise if it does not exist."""
|
"""Update a quota usage or raise if it does not exist."""
|
||||||
return IMPL.quota_usage_update(context, user_id, project_id, resource,
|
return IMPL.quota_usage_update(context, project_id, resource,
|
||||||
in_use, reserved, until_refresh)
|
in_use, reserved, until_refresh)
|
||||||
|
|
||||||
|
|
||||||
def quota_usage_destroy(context, user_id, project_id, resource):
|
def quota_usage_destroy(context, project_id, resource):
|
||||||
"""Destroy the quota usage or raise if it does not exist."""
|
"""Destroy the quota usage or raise if it does not exist."""
|
||||||
return IMPL.quota_usage_destroy(context, user_id, project_id, resource)
|
return IMPL.quota_usage_destroy(context, project_id, resource)
|
||||||
|
|
||||||
|
|
||||||
###################
|
###################
|
||||||
|
|
||||||
|
|
||||||
def reservation_create(context, uuid, usage, user_id, project_id, resource,
|
def reservation_create(context, uuid, usage, project_id, resource, delta,
|
||||||
delta, expire):
|
expire):
|
||||||
"""Create a reservation for the given user and resource."""
|
"""Create a reservation for the given project and resource."""
|
||||||
return IMPL.reservation_create(context, uuid, usage, user_id, project_id,
|
return IMPL.reservation_create(context, uuid, usage, project_id,
|
||||||
resource, delta, expire)
|
resource, delta, expire)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1073,9 +1026,9 @@ def reservation_get(context, uuid):
|
||||||
return IMPL.reservation_get(context, uuid)
|
return IMPL.reservation_get(context, uuid)
|
||||||
|
|
||||||
|
|
||||||
def reservation_get_all_by_user(context, user_id, project_id):
|
def reservation_get_all_by_project(context, project_id):
|
||||||
"""Retrieve all reservations associated with a given user."""
|
"""Retrieve all reservations associated with a given project."""
|
||||||
return IMPL.reservation_get_all_by_user(context, user_id, project_id)
|
return IMPL.reservation_get_all_by_project(context, project_id)
|
||||||
|
|
||||||
|
|
||||||
def reservation_destroy(context, uuid):
|
def reservation_destroy(context, uuid):
|
||||||
|
@ -1103,11 +1056,6 @@ def reservation_rollback(context, reservations):
|
||||||
return IMPL.reservation_rollback(context, reservations)
|
return IMPL.reservation_rollback(context, reservations)
|
||||||
|
|
||||||
|
|
||||||
def quota_destroy_all_by_user(context, user_id, project_id):
|
|
||||||
"""Destroy all quotas associated with a given user."""
|
|
||||||
return IMPL.quota_destroy_all_by_user(context, user_id, project_id)
|
|
||||||
|
|
||||||
|
|
||||||
def quota_destroy_all_by_project(context, project_id):
|
def quota_destroy_all_by_project(context, project_id):
|
||||||
"""Destroy all quotas associated with a given project."""
|
"""Destroy all quotas associated with a given project."""
|
||||||
return IMPL.quota_destroy_all_by_project(context, project_id)
|
return IMPL.quota_destroy_all_by_project(context, project_id)
|
||||||
|
@ -1136,12 +1084,6 @@ def volume_create(context, values):
|
||||||
return IMPL.volume_create(context, values)
|
return IMPL.volume_create(context, values)
|
||||||
|
|
||||||
|
|
||||||
def volume_data_get_for_user(context, user_id, project_id, session=None):
|
|
||||||
"""Get (volume_count, gigabytes) for user."""
|
|
||||||
return IMPL.volume_data_get_for_user(context, user_id, project_id,
|
|
||||||
session=session)
|
|
||||||
|
|
||||||
|
|
||||||
def volume_data_get_for_project(context, project_id, session=None):
|
def volume_data_get_for_project(context, project_id, session=None):
|
||||||
"""Get (volume_count, gigabytes) for project."""
|
"""Get (volume_count, gigabytes) for project."""
|
||||||
return IMPL.volume_data_get_for_project(context, project_id,
|
return IMPL.volume_data_get_for_project(context, project_id,
|
||||||
|
@ -1330,11 +1272,6 @@ def security_group_get_by_name(context, project_id, group_name):
|
||||||
return IMPL.security_group_get_by_name(context, project_id, group_name)
|
return IMPL.security_group_get_by_name(context, project_id, group_name)
|
||||||
|
|
||||||
|
|
||||||
def security_group_get_by_user(context, user_id, project_id):
|
|
||||||
"""Get all security groups belonging to a user."""
|
|
||||||
return IMPL.security_group_get_by_user(context, user_id, project_id)
|
|
||||||
|
|
||||||
|
|
||||||
def security_group_get_by_project(context, project_id):
|
def security_group_get_by_project(context, project_id):
|
||||||
"""Get all security groups belonging to a project."""
|
"""Get all security groups belonging to a project."""
|
||||||
return IMPL.security_group_get_by_project(context, project_id)
|
return IMPL.security_group_get_by_project(context, project_id)
|
||||||
|
@ -1370,12 +1307,6 @@ def security_group_destroy(context, security_group_id):
|
||||||
return IMPL.security_group_destroy(context, security_group_id)
|
return IMPL.security_group_destroy(context, security_group_id)
|
||||||
|
|
||||||
|
|
||||||
def security_group_count_by_user(context, user_id, project_id, session=None):
|
|
||||||
"""Count number of security groups for a user in specific project."""
|
|
||||||
return IMPL.security_group_count_by_user(context, user_id, project_id,
|
|
||||||
session=session)
|
|
||||||
|
|
||||||
|
|
||||||
def security_group_count_by_project(context, project_id, session=None):
|
def security_group_count_by_project(context, project_id, session=None):
|
||||||
"""Count number of security groups in a project."""
|
"""Count number of security groups in a project."""
|
||||||
return IMPL.security_group_count_by_project(context, project_id,
|
return IMPL.security_group_count_by_project(context, project_id,
|
||||||
|
|
|
@ -1442,33 +1442,20 @@ def instance_create(context, values):
|
||||||
return instance_ref
|
return instance_ref
|
||||||
|
|
||||||
|
|
||||||
def _get_instance_data(context, project_id, user_id=None, session=None):
|
@require_admin_context
|
||||||
|
def instance_data_get_for_project(context, project_id, session=None):
|
||||||
result = model_query(context,
|
result = model_query(context,
|
||||||
func.count(models.Instance.id),
|
func.count(models.Instance.id),
|
||||||
func.sum(models.Instance.vcpus),
|
func.sum(models.Instance.vcpus),
|
||||||
func.sum(models.Instance.memory_mb),
|
func.sum(models.Instance.memory_mb),
|
||||||
read_deleted="no",
|
read_deleted="no",
|
||||||
session=session).\
|
session=session).\
|
||||||
filter_by(project_id=project_id)
|
filter_by(project_id=project_id).\
|
||||||
if user_id:
|
first()
|
||||||
result = result.filter_by(user_id=user_id).first()
|
|
||||||
else:
|
|
||||||
result = result.first()
|
|
||||||
# NOTE(vish): convert None to 0
|
# NOTE(vish): convert None to 0
|
||||||
return (result[0] or 0, result[1] or 0, result[2] or 0)
|
return (result[0] or 0, result[1] or 0, result[2] or 0)
|
||||||
|
|
||||||
|
|
||||||
@require_admin_context
|
|
||||||
def instance_data_get_for_project(context, project_id, session=None):
|
|
||||||
return _get_instance_data(context, project_id, session=session)
|
|
||||||
|
|
||||||
|
|
||||||
@require_admin_context
|
|
||||||
def instance_data_get_for_user(context, user_id, project_id, session=None):
|
|
||||||
return _get_instance_data(context, project_id, user_id=user_id,
|
|
||||||
session=session)
|
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
@require_context
|
||||||
def instance_destroy(context, instance_uuid, constraint=None):
|
def instance_destroy(context, instance_uuid, constraint=None):
|
||||||
session = get_session()
|
session = get_session()
|
||||||
|
@ -2390,11 +2377,10 @@ def quota_get(context, project_id, resource, session=None):
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
@require_context
|
||||||
def quota_get_all_by_project(context, project_id, session=None):
|
def quota_get_all_by_project(context, project_id):
|
||||||
authorize_project_context(context, project_id)
|
authorize_project_context(context, project_id)
|
||||||
|
|
||||||
rows = model_query(context, models.Quota, session=session,
|
rows = model_query(context, models.Quota, read_deleted="no").\
|
||||||
read_deleted="no").\
|
|
||||||
filter_by(project_id=project_id).\
|
filter_by(project_id=project_id).\
|
||||||
all()
|
all()
|
||||||
|
|
||||||
|
@ -2435,97 +2421,6 @@ def quota_destroy(context, project_id, resource):
|
||||||
###################
|
###################
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
|
||||||
def quota_get_for_user(context, user_id, project_id, resource, session=None):
|
|
||||||
authorize_project_context(context, project_id)
|
|
||||||
result = model_query(context, models.UserQuota, session=session,
|
|
||||||
read_deleted="no").\
|
|
||||||
filter_by(user_id=user_id).\
|
|
||||||
filter_by(project_id=project_id).\
|
|
||||||
filter_by(resource=resource).\
|
|
||||||
first()
|
|
||||||
|
|
||||||
if not result:
|
|
||||||
raise exception.UserQuotaNotFound(project_id=project_id,
|
|
||||||
user_id=user_id)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
|
||||||
def quota_get_all_by_user(context, user_id, project_id):
|
|
||||||
authorize_project_context(context, project_id)
|
|
||||||
|
|
||||||
rows = model_query(context, models.UserQuota, read_deleted="no").\
|
|
||||||
filter_by(user_id=user_id).\
|
|
||||||
filter_by(project_id=project_id).\
|
|
||||||
all()
|
|
||||||
|
|
||||||
result = {'user_id': user_id, 'project_id': project_id}
|
|
||||||
for row in rows:
|
|
||||||
result[row.resource] = row.hard_limit
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
|
||||||
def quota_get_remaining(context, project_id):
|
|
||||||
authorize_project_context(context, project_id)
|
|
||||||
|
|
||||||
session = get_session()
|
|
||||||
with session.begin():
|
|
||||||
rows = model_query(context, models.UserQuota, session=session,
|
|
||||||
read_deleted="no").\
|
|
||||||
filter_by(project_id=project_id).\
|
|
||||||
all()
|
|
||||||
|
|
||||||
result = quota_get_all_by_project(context, project_id, session=session)
|
|
||||||
|
|
||||||
for row in rows:
|
|
||||||
if row.resource in result:
|
|
||||||
result[row.resource] -= row.hard_limit
|
|
||||||
|
|
||||||
result['project_id'] = project_id
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
|
||||||
def quota_create_for_user(context, user_id, project_id, resource, limit):
|
|
||||||
authorize_project_context(context, project_id)
|
|
||||||
quota_ref = models.UserQuota()
|
|
||||||
quota_ref.user_id = user_id
|
|
||||||
quota_ref.project_id = project_id
|
|
||||||
quota_ref.resource = resource
|
|
||||||
quota_ref.hard_limit = limit
|
|
||||||
quota_ref.save()
|
|
||||||
return quota_ref
|
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
|
||||||
def quota_update_for_user(context, user_id, project_id, resource, limit):
|
|
||||||
authorize_project_context(context, project_id)
|
|
||||||
session = get_session()
|
|
||||||
with session.begin():
|
|
||||||
quota_ref = quota_get_for_user(context, user_id, project_id, resource,
|
|
||||||
session=session)
|
|
||||||
quota_ref.hard_limit = limit
|
|
||||||
quota_ref.save(session=session)
|
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
|
||||||
def quota_destroy_for_user(context, user_id, project_id, resource):
|
|
||||||
authorize_project_context(context, project_id)
|
|
||||||
session = get_session()
|
|
||||||
with session.begin():
|
|
||||||
quota_ref = quota_get_for_user(context, user_id, project_id, resource,
|
|
||||||
session=session)
|
|
||||||
quota_ref.delete(session=session)
|
|
||||||
|
|
||||||
|
|
||||||
###################
|
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
@require_context
|
||||||
def quota_class_get(context, class_name, resource, session=None):
|
def quota_class_get(context, class_name, resource, session=None):
|
||||||
result = model_query(context, models.QuotaClass, session=session,
|
result = model_query(context, models.QuotaClass, session=session,
|
||||||
|
@ -2601,10 +2496,9 @@ def quota_class_destroy_all_by_name(context, class_name):
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
@require_context
|
||||||
def quota_usage_get(context, user_id, project_id, resource, session=None):
|
def quota_usage_get(context, project_id, resource, session=None):
|
||||||
result = model_query(context, models.QuotaUsage, session=session,
|
result = model_query(context, models.QuotaUsage, session=session,
|
||||||
read_deleted="no").\
|
read_deleted="no").\
|
||||||
filter_by(user_id=user_id).\
|
|
||||||
filter_by(project_id=project_id).\
|
filter_by(project_id=project_id).\
|
||||||
filter_by(resource=resource).\
|
filter_by(resource=resource).\
|
||||||
first()
|
first()
|
||||||
|
@ -2615,22 +2509,6 @@ def quota_usage_get(context, user_id, project_id, resource, session=None):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
|
||||||
def quota_usage_get_all_by_user(context, user_id, project_id):
|
|
||||||
authorize_project_context(context, project_id)
|
|
||||||
|
|
||||||
rows = model_query(context, models.QuotaUsage, read_deleted="no").\
|
|
||||||
filter_by(user_id=user_id).\
|
|
||||||
filter_by(project_id=project_id).\
|
|
||||||
all()
|
|
||||||
|
|
||||||
result = {'user_id': user_id, 'project_id': project_id}
|
|
||||||
for row in rows:
|
|
||||||
result[row.resource] = dict(in_use=row.in_use, reserved=row.reserved)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
@require_context
|
||||||
def quota_usage_get_all_by_project(context, project_id):
|
def quota_usage_get_all_by_project(context, project_id):
|
||||||
authorize_project_context(context, project_id)
|
authorize_project_context(context, project_id)
|
||||||
|
@ -2640,20 +2518,16 @@ def quota_usage_get_all_by_project(context, project_id):
|
||||||
all()
|
all()
|
||||||
|
|
||||||
result = {'project_id': project_id}
|
result = {'project_id': project_id}
|
||||||
in_use = 0
|
|
||||||
reserved = 0
|
|
||||||
for row in rows:
|
for row in rows:
|
||||||
result[row.resource] = dict(in_use=in_use + row.in_use,
|
result[row.resource] = dict(in_use=row.in_use, reserved=row.reserved)
|
||||||
reserved=reserved + row.reserved)
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@require_admin_context
|
@require_admin_context
|
||||||
def quota_usage_create(context, user_id, project_id, resource, in_use,
|
def quota_usage_create(context, project_id, resource, in_use, reserved,
|
||||||
reserved, until_refresh, session=None):
|
until_refresh, session=None):
|
||||||
quota_usage_ref = models.QuotaUsage()
|
quota_usage_ref = models.QuotaUsage()
|
||||||
quota_usage_ref.user_id = user_id
|
|
||||||
quota_usage_ref.project_id = project_id
|
quota_usage_ref.project_id = project_id
|
||||||
quota_usage_ref.resource = resource
|
quota_usage_ref.resource = resource
|
||||||
quota_usage_ref.in_use = in_use
|
quota_usage_ref.in_use = in_use
|
||||||
|
@ -2665,11 +2539,11 @@ def quota_usage_create(context, user_id, project_id, resource, in_use,
|
||||||
|
|
||||||
|
|
||||||
@require_admin_context
|
@require_admin_context
|
||||||
def quota_usage_update(context, user_id, project_id, resource, in_use,
|
def quota_usage_update(context, project_id, resource, in_use, reserved,
|
||||||
reserved, until_refresh, session=None):
|
until_refresh, session=None):
|
||||||
def do_update(session):
|
def do_update(session):
|
||||||
quota_usage_ref = quota_usage_get(context, user_id, project_id,
|
quota_usage_ref = quota_usage_get(context, project_id, resource,
|
||||||
resource, session=session)
|
session=session)
|
||||||
quota_usage_ref.in_use = in_use
|
quota_usage_ref.in_use = in_use
|
||||||
quota_usage_ref.reserved = reserved
|
quota_usage_ref.reserved = reserved
|
||||||
quota_usage_ref.until_refresh = until_refresh
|
quota_usage_ref.until_refresh = until_refresh
|
||||||
|
@ -2685,11 +2559,11 @@ def quota_usage_update(context, user_id, project_id, resource, in_use,
|
||||||
|
|
||||||
|
|
||||||
@require_admin_context
|
@require_admin_context
|
||||||
def quota_usage_destroy(context, user_id, project_id, resource):
|
def quota_usage_destroy(context, project_id, resource):
|
||||||
session = get_session()
|
session = get_session()
|
||||||
with session.begin():
|
with session.begin():
|
||||||
quota_usage_ref = quota_usage_get(context, user_id, project_id,
|
quota_usage_ref = quota_usage_get(context, project_id, resource,
|
||||||
resource, session=session)
|
session=session)
|
||||||
quota_usage_ref.delete(session=session)
|
quota_usage_ref.delete(session=session)
|
||||||
|
|
||||||
|
|
||||||
|
@ -2710,15 +2584,14 @@ def reservation_get(context, uuid, session=None):
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
@require_context
|
||||||
def reservation_get_all_by_user(context, user_id, project_id):
|
def reservation_get_all_by_project(context, project_id):
|
||||||
authorize_project_context(context, project_id)
|
authorize_project_context(context, project_id)
|
||||||
|
|
||||||
rows = model_query(context, models.QuotaUsage, read_deleted="no").\
|
rows = model_query(context, models.QuotaUsage, read_deleted="no").\
|
||||||
filter_by(user_id=user_id).\
|
|
||||||
filter_by(project_id=project_id).\
|
filter_by(project_id=project_id).\
|
||||||
all()
|
all()
|
||||||
|
|
||||||
result = {'user_id': user_id, 'project_id': project_id}
|
result = {'project_id': project_id}
|
||||||
for row in rows:
|
for row in rows:
|
||||||
result.setdefault(row.resource, {})
|
result.setdefault(row.resource, {})
|
||||||
result[row.resource][row.uuid] = row.delta
|
result[row.resource][row.uuid] = row.delta
|
||||||
|
@ -2727,12 +2600,11 @@ def reservation_get_all_by_user(context, user_id, project_id):
|
||||||
|
|
||||||
|
|
||||||
@require_admin_context
|
@require_admin_context
|
||||||
def reservation_create(context, uuid, usage, user_id, project_id, resource,
|
def reservation_create(context, uuid, usage, project_id, resource, delta,
|
||||||
delta, expire, session=None):
|
expire, session=None):
|
||||||
reservation_ref = models.Reservation()
|
reservation_ref = models.Reservation()
|
||||||
reservation_ref.uuid = uuid
|
reservation_ref.uuid = uuid
|
||||||
reservation_ref.usage_id = usage['id']
|
reservation_ref.usage_id = usage['id']
|
||||||
reservation_ref.user_id = user_id
|
|
||||||
reservation_ref.project_id = project_id
|
reservation_ref.project_id = project_id
|
||||||
reservation_ref.resource = resource
|
reservation_ref.resource = resource
|
||||||
reservation_ref.delta = delta
|
reservation_ref.delta = delta
|
||||||
|
@ -2762,7 +2634,6 @@ def _get_quota_usages(context, session):
|
||||||
rows = model_query(context, models.QuotaUsage,
|
rows = model_query(context, models.QuotaUsage,
|
||||||
read_deleted="no",
|
read_deleted="no",
|
||||||
session=session).\
|
session=session).\
|
||||||
filter_by(user_id=context.user_id).\
|
|
||||||
filter_by(project_id=context.project_id).\
|
filter_by(project_id=context.project_id).\
|
||||||
with_lockmode('update').\
|
with_lockmode('update').\
|
||||||
all()
|
all()
|
||||||
|
@ -2787,7 +2658,6 @@ def quota_reserve(context, resources, quotas, deltas, expire,
|
||||||
refresh = False
|
refresh = False
|
||||||
if resource not in usages:
|
if resource not in usages:
|
||||||
usages[resource] = quota_usage_create(elevated,
|
usages[resource] = quota_usage_create(elevated,
|
||||||
context.user_id,
|
|
||||||
context.project_id,
|
context.project_id,
|
||||||
resource,
|
resource,
|
||||||
0, 0,
|
0, 0,
|
||||||
|
@ -2811,13 +2681,11 @@ def quota_reserve(context, resources, quotas, deltas, expire,
|
||||||
# Grab the sync routine
|
# Grab the sync routine
|
||||||
sync = resources[resource].sync
|
sync = resources[resource].sync
|
||||||
|
|
||||||
updates = sync(elevated, context.user_id,
|
updates = sync(elevated, context.project_id, session)
|
||||||
context.project_id, session)
|
|
||||||
for res, in_use in updates.items():
|
for res, in_use in updates.items():
|
||||||
# Make sure we have a destination for the usage!
|
# Make sure we have a destination for the usage!
|
||||||
if res not in usages:
|
if res not in usages:
|
||||||
usages[res] = quota_usage_create(elevated,
|
usages[res] = quota_usage_create(elevated,
|
||||||
context.user_id,
|
|
||||||
context.project_id,
|
context.project_id,
|
||||||
res,
|
res,
|
||||||
0, 0,
|
0, 0,
|
||||||
|
@ -2868,7 +2736,6 @@ def quota_reserve(context, resources, quotas, deltas, expire,
|
||||||
reservation = reservation_create(elevated,
|
reservation = reservation_create(elevated,
|
||||||
str(utils.gen_uuid()),
|
str(utils.gen_uuid()),
|
||||||
usages[resource],
|
usages[resource],
|
||||||
context.user_id,
|
|
||||||
context.project_id,
|
context.project_id,
|
||||||
resource, delta, expire,
|
resource, delta, expire,
|
||||||
session=session)
|
session=session)
|
||||||
|
@ -2952,38 +2819,6 @@ def reservation_rollback(context, reservations):
|
||||||
usage.save(session=session)
|
usage.save(session=session)
|
||||||
|
|
||||||
|
|
||||||
@require_admin_context
|
|
||||||
def quota_destroy_all_by_user(context, user_id, project_id):
|
|
||||||
session = get_session()
|
|
||||||
with session.begin():
|
|
||||||
quotas = model_query(context, models.UserQuota, session=session,
|
|
||||||
read_deleted="no").\
|
|
||||||
filter_by(user_id=user_id).\
|
|
||||||
filter_by(project_id=project_id).\
|
|
||||||
all()
|
|
||||||
|
|
||||||
for quota_ref in quotas:
|
|
||||||
quota_ref.delete(session=session)
|
|
||||||
|
|
||||||
quota_usages = model_query(context, models.QuotaUsage,
|
|
||||||
session=session, read_deleted="no").\
|
|
||||||
filter_by(user_id=user_id).\
|
|
||||||
filter_by(project_id=project_id).\
|
|
||||||
all()
|
|
||||||
|
|
||||||
for quota_usage_ref in quota_usages:
|
|
||||||
quota_usage_ref.delete(session=session)
|
|
||||||
|
|
||||||
reservations = model_query(context, models.Reservation,
|
|
||||||
session=session, read_deleted="no").\
|
|
||||||
filter_by(user_id=user_id).\
|
|
||||||
filter_by(project_id=project_id).\
|
|
||||||
all()
|
|
||||||
|
|
||||||
for reservation_ref in reservations:
|
|
||||||
reservation_ref.delete(session=session)
|
|
||||||
|
|
||||||
|
|
||||||
@require_admin_context
|
@require_admin_context
|
||||||
def quota_destroy_all_by_project(context, project_id):
|
def quota_destroy_all_by_project(context, project_id):
|
||||||
session = get_session()
|
session = get_session()
|
||||||
|
@ -3089,33 +2924,20 @@ def volume_create(context, values):
|
||||||
return volume_ref
|
return volume_ref
|
||||||
|
|
||||||
|
|
||||||
def _get_volume_data(context, project_id, user_id=None, session=None):
|
@require_admin_context
|
||||||
|
def volume_data_get_for_project(context, project_id, session=None):
|
||||||
result = model_query(context,
|
result = model_query(context,
|
||||||
func.count(models.Volume.id),
|
func.count(models.Volume.id),
|
||||||
func.sum(models.Volume.size),
|
func.sum(models.Volume.size),
|
||||||
read_deleted="no",
|
read_deleted="no",
|
||||||
session=session).\
|
session=session).\
|
||||||
filter_by(project_id=project_id)
|
filter_by(project_id=project_id).\
|
||||||
|
first()
|
||||||
if user_id:
|
|
||||||
result = result.filter_by(user_id=user_id).first()
|
|
||||||
else:
|
|
||||||
result = result.first()
|
|
||||||
|
|
||||||
|
# NOTE(vish): convert None to 0
|
||||||
return (result[0] or 0, result[1] or 0)
|
return (result[0] or 0, result[1] or 0)
|
||||||
|
|
||||||
|
|
||||||
@require_admin_context
|
|
||||||
def volume_data_get_for_user(context, user_id, project_id, session=None):
|
|
||||||
return _get_volume_data(context, project_id, user_id=user_id,
|
|
||||||
session=session)
|
|
||||||
|
|
||||||
|
|
||||||
@require_admin_context
|
|
||||||
def volume_data_get_for_project(context, project_id, session=None):
|
|
||||||
return _get_volume_data(context, project_id, session=session)
|
|
||||||
|
|
||||||
|
|
||||||
@require_admin_context
|
@require_admin_context
|
||||||
def volume_destroy(context, volume_id):
|
def volume_destroy(context, volume_id):
|
||||||
session = get_session()
|
session = get_session()
|
||||||
|
@ -3636,14 +3458,6 @@ def security_group_get_by_name(context, project_id, group_name,
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
|
||||||
def security_group_get_by_user(context, user_id, project_id):
|
|
||||||
return _security_group_get_query(context, read_deleted="no").\
|
|
||||||
filter_by(user_id=user_id).\
|
|
||||||
filter_by(project_id=project_id).\
|
|
||||||
all()
|
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
@require_context
|
||||||
def security_group_get_by_project(context, project_id):
|
def security_group_get_by_project(context, project_id):
|
||||||
return _security_group_get_query(context, read_deleted="no").\
|
return _security_group_get_query(context, read_deleted="no").\
|
||||||
|
@ -3739,16 +3553,6 @@ def security_group_destroy(context, security_group_id):
|
||||||
'updated_at': literal_column('updated_at')})
|
'updated_at': literal_column('updated_at')})
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
|
||||||
def security_group_count_by_user(context, user_id, project_id, session=None):
|
|
||||||
authorize_project_context(context, project_id)
|
|
||||||
return model_query(context, models.SecurityGroup, read_deleted="no",
|
|
||||||
session=session).\
|
|
||||||
filter_by(user_id=user_id).\
|
|
||||||
filter_by(project_id=project_id).\
|
|
||||||
count()
|
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
@require_context
|
||||||
def security_group_count_by_project(context, project_id, session=None):
|
def security_group_count_by_project(context, project_id, session=None):
|
||||||
authorize_project_context(context, project_id)
|
authorize_project_context(context, project_id)
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2012 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from nova.openstack.common import log as logging
|
||||||
|
from sqlalchemy import Boolean, Column, DateTime, Integer
|
||||||
|
from sqlalchemy import MetaData, String, Table
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(migrate_engine):
|
||||||
|
# Reverse the previous migration
|
||||||
|
meta = MetaData()
|
||||||
|
meta.bind = migrate_engine
|
||||||
|
|
||||||
|
reservations = Table('reservations', meta, autoload=True)
|
||||||
|
d = reservations.delete(reservations.c.deleted == True)
|
||||||
|
d.execute()
|
||||||
|
reservations.drop_column('user_id')
|
||||||
|
|
||||||
|
quota_usages = Table('quota_usages', meta, autoload=True)
|
||||||
|
d = quota_usages.delete(quota_usages.c.user_id != None)
|
||||||
|
d.execute()
|
||||||
|
quota_usages.drop_column('user_id')
|
||||||
|
|
||||||
|
user_quotas = Table('user_quotas', meta, autoload=True)
|
||||||
|
try:
|
||||||
|
user_quotas.drop()
|
||||||
|
except Exception:
|
||||||
|
LOG.error(_("user_quotas table not dropped"))
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(migrate_engine):
|
||||||
|
# Undo the reversal of the previous migration
|
||||||
|
# (data is not preserved)
|
||||||
|
meta = MetaData()
|
||||||
|
meta.bind = migrate_engine
|
||||||
|
|
||||||
|
# Add 'user_id' column to quota_usages table.
|
||||||
|
quota_usages = Table('quota_usages', meta, autoload=True)
|
||||||
|
user_id = Column('user_id',
|
||||||
|
String(length=255, convert_unicode=False,
|
||||||
|
assert_unicode=None, unicode_error=None,
|
||||||
|
_warn_on_bytestring=False))
|
||||||
|
quota_usages.create_column(user_id)
|
||||||
|
|
||||||
|
# Add 'user_id' column to reservations table.
|
||||||
|
reservations = Table('reservations', meta, autoload=True)
|
||||||
|
user_id = Column('user_id',
|
||||||
|
String(length=255, convert_unicode=False,
|
||||||
|
assert_unicode=None, unicode_error=None,
|
||||||
|
_warn_on_bytestring=False))
|
||||||
|
reservations.create_column(user_id)
|
||||||
|
|
||||||
|
# New table.
|
||||||
|
user_quotas = Table('user_quotas', meta,
|
||||||
|
Column('id', Integer(), primary_key=True),
|
||||||
|
Column('created_at', DateTime(timezone=False)),
|
||||||
|
Column('updated_at', DateTime(timezone=False)),
|
||||||
|
Column('deleted_at', DateTime(timezone=False)),
|
||||||
|
Column('deleted', Boolean(), default=False),
|
||||||
|
Column('user_id',
|
||||||
|
String(length=255, convert_unicode=False,
|
||||||
|
assert_unicode=None, unicode_error=None,
|
||||||
|
_warn_on_bytestring=False)),
|
||||||
|
Column('project_id',
|
||||||
|
String(length=255, convert_unicode=False,
|
||||||
|
assert_unicode=None, unicode_error=None,
|
||||||
|
_warn_on_bytestring=False)),
|
||||||
|
Column('resource',
|
||||||
|
String(length=255, convert_unicode=False,
|
||||||
|
assert_unicode=None, unicode_error=None,
|
||||||
|
_warn_on_bytestring=False),
|
||||||
|
nullable=False),
|
||||||
|
Column('hard_limit', Integer(), nullable=True),
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
mysql_charset='utf8',
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
user_quotas.create()
|
||||||
|
except Exception:
|
||||||
|
LOG.error(_("Table |%s| not created!"), repr(user_quotas))
|
||||||
|
raise
|
|
@ -428,19 +428,6 @@ class Quota(BASE, NovaBase):
|
||||||
hard_limit = Column(Integer, nullable=True)
|
hard_limit = Column(Integer, nullable=True)
|
||||||
|
|
||||||
|
|
||||||
class UserQuota(BASE, NovaBase):
|
|
||||||
"""Represents a single quota override for a user."""
|
|
||||||
|
|
||||||
__tablename__ = 'user_quotas'
|
|
||||||
id = Column(Integer, primary_key=True)
|
|
||||||
|
|
||||||
user_id = Column(String(255), index=True)
|
|
||||||
project_id = Column(String(255), index=True)
|
|
||||||
|
|
||||||
resource = Column(String(255))
|
|
||||||
hard_limit = Column(Integer, nullable=True)
|
|
||||||
|
|
||||||
|
|
||||||
class QuotaClass(BASE, NovaBase):
|
class QuotaClass(BASE, NovaBase):
|
||||||
"""Represents a single quota override for a quota class.
|
"""Represents a single quota override for a quota class.
|
||||||
|
|
||||||
|
@ -464,7 +451,6 @@ class QuotaUsage(BASE, NovaBase):
|
||||||
__tablename__ = 'quota_usages'
|
__tablename__ = 'quota_usages'
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
|
|
||||||
user_id = Column(String(255), index=True)
|
|
||||||
project_id = Column(String(255), index=True)
|
project_id = Column(String(255), index=True)
|
||||||
resource = Column(String(255))
|
resource = Column(String(255))
|
||||||
|
|
||||||
|
@ -487,7 +473,6 @@ class Reservation(BASE, NovaBase):
|
||||||
|
|
||||||
usage_id = Column(Integer, ForeignKey('quota_usages.id'), nullable=False)
|
usage_id = Column(Integer, ForeignKey('quota_usages.id'), nullable=False)
|
||||||
|
|
||||||
user_id = Column(String(255), index=True)
|
|
||||||
project_id = Column(String(255), index=True)
|
project_id = Column(String(255), index=True)
|
||||||
resource = Column(String(255))
|
resource = Column(String(255))
|
||||||
|
|
||||||
|
|
|
@ -750,11 +750,6 @@ class QuotaResourceUnknown(QuotaNotFound):
|
||||||
message = _("Unknown quota resources %(unknown)s.")
|
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):
|
class ProjectQuotaNotFound(QuotaNotFound):
|
||||||
message = _("Quota for project %(project_id)s could not be found.")
|
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)
|
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):
|
def get_by_class(self, context, quota_class, resource):
|
||||||
"""Get a specific quota by quota class."""
|
"""Get a specific quota by quota class."""
|
||||||
|
|
||||||
|
@ -148,63 +143,6 @@ class DbQuotaDriver(object):
|
||||||
|
|
||||||
return quotas
|
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,
|
def get_project_quotas(self, context, resources, project_id,
|
||||||
quota_class=None, defaults=True,
|
quota_class=None, defaults=True,
|
||||||
usages=True):
|
usages=True):
|
||||||
|
@ -228,65 +166,44 @@ class DbQuotaDriver(object):
|
||||||
will also be returned.
|
will also be returned.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
quotas = {}
|
||||||
project_quotas = db.quota_get_all_by_project(context, project_id)
|
project_quotas = db.quota_get_all_by_project(context, project_id)
|
||||||
|
|
||||||
project_usages = None
|
|
||||||
if usages:
|
if usages:
|
||||||
project_usages = db.quota_usage_get_all_by_project(context,
|
project_usages = db.quota_usage_get_all_by_project(context,
|
||||||
project_id)
|
project_id)
|
||||||
|
|
||||||
return self._process_quotas(context, resources,
|
# Get the quotas for the appropriate class. If the project ID
|
||||||
project_id, project_quotas,
|
# matches the one in the context, we use the quota_class from
|
||||||
quota_class=quota_class,
|
# the context, otherwise, we use the provided quota_class (if
|
||||||
defaults=defaults,
|
# any)
|
||||||
usages=project_usages)
|
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,
|
for resource in resources.values():
|
||||||
quota_class=None, defaults=True,
|
# Omit default/quota class values
|
||||||
usages=True):
|
if not defaults and resource.name not in project_quotas:
|
||||||
"""
|
continue
|
||||||
Given a list of resources, retrieve the quotas for the given
|
|
||||||
user.
|
|
||||||
|
|
||||||
:param context: The request context, for access checks.
|
quotas[resource.name] = dict(
|
||||||
:param resources: A dictionary of the registered resources.
|
limit=project_quotas.get(resource.name, class_quotas.get(
|
||||||
:param project_id: The ID of the project to return quotas for.
|
resource.name, resource.default)),
|
||||||
: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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
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
|
return quotas
|
||||||
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
|
|
||||||
|
|
||||||
def _get_quotas(self, context, resources, keys, has_sync):
|
def _get_quotas(self, context, resources, keys, has_sync):
|
||||||
"""
|
"""
|
||||||
|
@ -318,10 +235,9 @@ class DbQuotaDriver(object):
|
||||||
raise exception.QuotaResourceUnknown(unknown=sorted(unknown))
|
raise exception.QuotaResourceUnknown(unknown=sorted(unknown))
|
||||||
|
|
||||||
# Grab and return the quotas (without usages)
|
# Grab and return the quotas (without usages)
|
||||||
quotas = self.get_user_quotas(context, sub_resources,
|
quotas = self.get_project_quotas(context, sub_resources,
|
||||||
context.user_id,
|
context.project_id,
|
||||||
context.project_id,
|
context.quota_class, usages=False)
|
||||||
context.quota_class, usages=False)
|
|
||||||
|
|
||||||
return dict((k, v['limit']) for k, v in quotas.items())
|
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)
|
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):
|
def expire(self, context):
|
||||||
"""Expire reservations.
|
"""Expire reservations.
|
||||||
|
|
||||||
|
@ -662,11 +566,6 @@ class QuotaEngine(object):
|
||||||
|
|
||||||
return self._driver.get_by_project(context, project_id, resource)
|
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):
|
def get_by_class(self, context, quota_class, resource):
|
||||||
"""Get a specific quota by quota class."""
|
"""Get a specific quota by quota class."""
|
||||||
|
|
||||||
|
@ -712,46 +611,10 @@ class QuotaEngine(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return self._driver.get_project_quotas(context, self._resources,
|
return self._driver.get_project_quotas(context, self._resources,
|
||||||
project_id,
|
project_id,
|
||||||
quota_class=quota_class,
|
quota_class=quota_class,
|
||||||
defaults=defaults,
|
defaults=defaults,
|
||||||
usages=usages)
|
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)
|
|
||||||
|
|
||||||
def count(self, context, resource, *args, **kwargs):
|
def count(self, context, resource, *args, **kwargs):
|
||||||
"""Count a resource.
|
"""Count a resource.
|
||||||
|
@ -882,18 +745,6 @@ class QuotaEngine(object):
|
||||||
|
|
||||||
self._driver.destroy_all_by_project(context, project_id)
|
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):
|
def expire(self, context):
|
||||||
"""Expire reservations.
|
"""Expire reservations.
|
||||||
|
|
||||||
|
@ -910,26 +761,26 @@ class QuotaEngine(object):
|
||||||
return sorted(self._resources.keys())
|
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'),
|
return dict(zip(('instances', 'cores', 'ram'),
|
||||||
db.instance_data_get_for_user(
|
db.instance_data_get_for_project(
|
||||||
context, user_id, project_id, session=session)))
|
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'),
|
return dict(zip(('volumes', 'gigabytes'),
|
||||||
db.volume_data_get_for_user(
|
db.volume_data_get_for_project(
|
||||||
context, user_id, project_id, session=session)))
|
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(
|
return dict(floating_ips=db.floating_ip_count_by_project(
|
||||||
context, project_id, session=session))
|
context, project_id, session=session))
|
||||||
|
|
||||||
|
|
||||||
def _sync_security_groups(context, user_id, project_id, session):
|
def _sync_security_groups(context, project_id, session):
|
||||||
return dict(security_groups=db.security_group_count_by_user(
|
return dict(security_groups=db.security_group_count_by_project(
|
||||||
context, user_id, project_id, session=session))
|
context, project_id, session=session))
|
||||||
|
|
||||||
|
|
||||||
QUOTAS = QuotaEngine()
|
QUOTAS = QuotaEngine()
|
||||||
|
|
|
@ -105,8 +105,7 @@
|
||||||
"compute_extension:networks": [],
|
"compute_extension:networks": [],
|
||||||
"compute_extension:networks:view": [],
|
"compute_extension:networks:view": [],
|
||||||
"compute_extension:quotas:show": [],
|
"compute_extension:quotas:show": [],
|
||||||
"compute_extension:quotas:update_for_project": [],
|
"compute_extension:quotas:update": [],
|
||||||
"compute_extension:quotas:update_for_user": [],
|
|
||||||
"compute_extension:quota_classes": [],
|
"compute_extension:quota_classes": [],
|
||||||
"compute_extension:rescue": [],
|
"compute_extension:rescue": [],
|
||||||
"compute_extension:security_groups": [],
|
"compute_extension:security_groups": [],
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue