Merge "Add Generic Volume Group Into Quota Management"

This commit is contained in:
Jenkins 2017-06-07 09:06:15 +00:00 committed by Gerrit Code Review
commit cbddc11560
6 changed files with 55 additions and 17 deletions

View File

@ -25,6 +25,7 @@ from cinder import utils
QUOTAS = quota.QUOTAS
GROUP_QUOTAS = quota.GROUP_QUOTAS
authorize = extensions.extension_authorizer('volume', 'quota_classes')
@ -46,9 +47,11 @@ class QuotaClassSetsController(wsgi.Controller):
db.sqlalchemy.api.authorize_quota_class_context(context, id)
except exception.NotAuthorized:
raise webob.exc.HTTPForbidden()
quota_set = QUOTAS.get_class_quotas(context, id)
group_quota_set = GROUP_QUOTAS.get_class_quotas(context, id)
quota_set.update(group_quota_set)
return self._format_quota_set(id,
QUOTAS.get_class_quotas(context, id))
return self._format_quota_set(id, quota_set)
def update(self, req, id, body):
context = req.environ['cinder.context']
@ -63,7 +66,7 @@ class QuotaClassSetsController(wsgi.Controller):
raise webob.exc.HTTPBadRequest(explanation=msg)
for key, value in body['quota_class_set'].items():
if key in QUOTAS:
if key in QUOTAS or key in GROUP_QUOTAS:
try:
value = utils.validate_integer(value, key, min_value=-1,
max_value=db.MAX_INT)
@ -72,8 +75,12 @@ class QuotaClassSetsController(wsgi.Controller):
db.quota_class_create(context, quota_class, key, value)
except exception.AdminRequired:
raise webob.exc.HTTPForbidden()
return {'quota_class_set': QUOTAS.get_class_quotas(context,
quota_class)}
quota_set = QUOTAS.get_class_quotas(context, quota_class)
group_quota_set = GROUP_QUOTAS.get_class_quotas(context, quota_class)
quota_set.update(group_quota_set)
return {'quota_class_set': quota_set}
class Quota_classes(extensions.ExtensionDescriptor):

View File

@ -28,6 +28,7 @@ from cinder import quota_utils
from cinder import utils
QUOTAS = quota.QUOTAS
GROUP_QUOTAS = quota.GROUP_QUOTAS
NON_QUOTA_KEYS = ['tenant_id', 'id']
authorize_update = extensions.extension_authorizer('volume', 'quotas:update')
@ -63,6 +64,9 @@ class QuotaSetsController(wsgi.Controller):
def _get_quotas(self, context, id, usages=False):
values = QUOTAS.get_project_quotas(context, id, usages=usages)
group_values = GROUP_QUOTAS.get_project_quotas(context, id,
usages=usages)
values.update(group_values)
if usages:
return values
@ -225,7 +229,8 @@ class QuotaSetsController(wsgi.Controller):
# NOTE(ankit): Pass #1 - In this loop for body['quota_set'].items(),
# we figure out if we have any bad keys.
for key, value in body['quota_set'].items():
if (key not in QUOTAS and key not in NON_QUOTA_KEYS):
if (key not in QUOTAS and key not in GROUP_QUOTAS and key not in
NON_QUOTA_KEYS):
bad_keys.append(key)
continue
@ -259,6 +264,10 @@ class QuotaSetsController(wsgi.Controller):
# resources.
quota_values = QUOTAS.get_project_quotas(context, target_project_id,
defaults=False)
group_quota_values = GROUP_QUOTAS.get_project_quotas(context,
target_project_id,
defaults=False)
quota_values.update(group_quota_values)
valid_quotas = {}
reservations = []
for key in body['quota_set'].keys():
@ -326,17 +335,20 @@ class QuotaSetsController(wsgi.Controller):
res_change = new_quota_from_target_proj - orig_quota_from_target_proj
if res_change != 0:
deltas = {res: res_change}
resources = QUOTAS.resources
resources.update(GROUP_QUOTAS.resources)
reservations += quota_utils.update_alloc_to_next_hard_limit(
ctxt, QUOTAS.resources, deltas, res, None, target_project.id)
ctxt, resources, deltas, res, None, target_project.id)
return reservations
def defaults(self, req, id):
context = req.environ['cinder.context']
authorize_show(context)
return self._format_quota_set(id, QUOTAS.get_defaults(
context, project_id=id))
defaults = QUOTAS.get_defaults(context, project_id=id)
group_defaults = GROUP_QUOTAS.get_defaults(context, project_id=id)
defaults.update(group_defaults)
return self._format_quota_set(id, defaults)
def delete(self, req, id):
"""Delete Quota for a particular tenant.
@ -366,6 +378,9 @@ class QuotaSetsController(wsgi.Controller):
try:
project_quotas = QUOTAS.get_project_quotas(
ctxt, proj_id, usages=True, defaults=False)
project_group_quotas = GROUP_QUOTAS.get_project_quotas(
ctxt, proj_id, usages=True, defaults=False)
project_quotas.update(project_group_quotas)
except exception.NotAuthorized:
raise webob.exc.HTTPForbidden()
@ -382,6 +397,7 @@ class QuotaSetsController(wsgi.Controller):
parent_id)
defaults = QUOTAS.get_defaults(ctxt, proj_id)
defaults.update(GROUP_QUOTAS.get_defaults(ctxt, proj_id))
# If the project which is being deleted has allocated part of its
# quota to its subprojects, then subprojects' quotas should be
# deleted first.
@ -416,8 +432,11 @@ class QuotaSetsController(wsgi.Controller):
ctxt = req.environ['cinder.context']
params = req.params
try:
resources = QUOTAS.resources
resources.update(GROUP_QUOTAS.resources)
quota_utils.validate_setup_for_nested_quota_use(
ctxt, QUOTAS.resources, quota.NestedDbQuotaDriver(),
ctxt, resources, quota.NestedDbQuotaDriver(),
fix_allocated_quotas=params.get('fix_allocated_quotas'))
except exception.InvalidNestedQuotaSetup as e:
raise webob.exc.HTTPBadRequest(explanation=e.msg)

View File

@ -147,6 +147,7 @@ def update_alloc_to_next_hard_limit(context, resources, deltas, res,
expire, project_id):
from cinder import quota
QUOTAS = quota.QUOTAS
GROUP_QUOTAS = quota.GROUP_QUOTAS
reservations = []
projects = get_project_hierarchy(context, project_id,
parents_as_ids=True).parents
@ -156,8 +157,12 @@ def update_alloc_to_next_hard_limit(context, resources, deltas, res,
while projects and not hard_limit_found:
cur_proj_id = list(projects)[0]
projects = projects[cur_proj_id]
cur_quota_lim = QUOTAS.get_by_project_or_default(
context, cur_proj_id, res)
if res == 'groups':
cur_quota_lim = GROUP_QUOTAS.get_by_project_or_default(
context, cur_proj_id, res)
else:
cur_quota_lim = QUOTAS.get_by_project_or_default(
context, cur_proj_id, res)
hard_limit_found = (cur_quota_lim != -1)
cur_quota = {res: cur_quota_lim}
cur_delta = {res: deltas[res]}

View File

@ -43,13 +43,14 @@ CONF = cfg.CONF
def make_body(root=True, gigabytes=1000, snapshots=10,
volumes=10, backups=10, backup_gigabytes=1000,
tenant_id=fake.PROJECT_ID, per_volume_gigabytes=-1):
tenant_id=fake.PROJECT_ID, per_volume_gigabytes=-1, groups=10):
resources = {'gigabytes': gigabytes,
'snapshots': snapshots,
'volumes': volumes,
'backups': backups,
'backup_gigabytes': backup_gigabytes,
'per_volume_gigabytes': per_volume_gigabytes, }
'per_volume_gigabytes': per_volume_gigabytes,
'groups': groups}
# need to consider preexisting volume types as well
volume_types = db.volume_type_get_all(context.get_admin_context())

View File

@ -33,19 +33,21 @@ from cinder.volume import volume_types
QUOTAS = quota.QUOTAS
GROUP_QUOTAS = quota.GROUP_QUOTAS
def make_body(root=True, gigabytes=1000, snapshots=10,
volumes=10, backups=10,
backup_gigabytes=1000, per_volume_gigabytes=-1,
volume_types_faked=None,
tenant_id=fake.PROJECT_ID):
tenant_id=fake.PROJECT_ID, groups=10):
resources = {'gigabytes': gigabytes,
'snapshots': snapshots,
'volumes': volumes,
'backups': backups,
'per_volume_gigabytes': per_volume_gigabytes,
'backup_gigabytes': backup_gigabytes}
'backup_gigabytes': backup_gigabytes,
'groups': groups}
if not volume_types_faked:
volume_types_faked = {'fake_type': None}
for volume_type in volume_types_faked:
@ -68,6 +70,7 @@ def make_response_body(root=True, ctxt=None, quota_class='foo',
if not ctxt:
ctxt = context.get_admin_context()
resources.update(QUOTAS.get_class_quotas(ctxt, quota_class))
resources.update(GROUP_QUOTAS.get_class_quotas(ctxt, quota_class))
if not request_body and not request_body['quota_class_set']:
resources.update(request_body['quota_class_set'])

View File

@ -0,0 +1,3 @@
---
features:
- Generic group is added into quota management.