Allow setting quota of other tenants

Currently, the quota API/CLI allows users to set
quotas for current tenant only. However, admin
users needs the ability to set quota for other
tenants. For example:

   $ source /opt/stack/devstack/openrc admin admin
   $ openstack appcontainer quota update --containers 100 <DEMO_TENANT_UUID>

Depends-On: https://review.openstack.org/627075
Change-Id: Ia147575d3e8d2c6d54bddd98846f0c9e3e518ec3
Related-Bug: #1807620
This commit is contained in:
Kien Nguyen 2018-12-23 16:47:00 +07:00
parent 77046229b8
commit eedf5c7fdd
4 changed files with 72 additions and 25 deletions

View File

@ -52,6 +52,10 @@ class UpdateQuota(command.ShowOne):
metavar='<disk>',
help='The number of gigabytes of container Disk '
'allowed per project')
parser.add_argument(
'project_id',
metavar='<project_id>',
help='The UUID of project in a multi-project cloud')
return parser
def take_action(self, parsed_args):
@ -61,7 +65,7 @@ class UpdateQuota(command.ShowOne):
opts['memory'] = parsed_args.memory
opts['cpu'] = parsed_args.cpu
opts['disk'] = parsed_args.disk
quota = client.quotas.update(**opts)
quota = client.quotas.update(parsed_args.project_id, **opts)
columns = _quota_columns(quota)
return columns, utils.get_item_properties(quota, columns)
@ -77,11 +81,17 @@ class GetQuota(command.ShowOne):
'--usages',
action='store_true',
help='Whether show quota usage statistic or not')
parser.add_argument(
'project_id',
metavar='<project_id>',
help='The UUID of project in a multi-project cloud')
return parser
def take_action(self, parsed_args):
client = _get_client(self, parsed_args)
quota = client.quotas.get(usages=parsed_args.usages)
quota = client.quotas.get(
parsed_args.project_id,
usages=parsed_args.usages)
columns = _quota_columns(quota)
return columns, utils.get_item_properties(quota, columns)
@ -91,9 +101,17 @@ class GetDefaultQuota(command.ShowOne):
log = logging.getLogger(__name__ + '.GetDefeaultQuota')
def get_parser(self, prog_name):
parser = super(GetDefaultQuota, self).get_parser(prog_name)
parser.add_argument(
'project_id',
metavar='<project_id>',
help='The UUID of project in a multi-project cloud')
return parser
def take_action(self, parsed_args):
client = _get_client(self, parsed_args)
default_quota = client.quotas.defaults()
default_quota = client.quotas.defaults(parsed_args.project_id)
columns = _quota_columns(default_quota)
return columns, utils.get_item_properties(
default_quota, columns)
@ -104,10 +122,18 @@ class DeleteQuota(command.Command):
log = logging.getLogger(__name__ + '.DeleteQuota')
def get_parser(self, prog_name):
parser = super(DeleteQuota, self).get_parser(prog_name)
parser.add_argument(
'project_id',
metavar='<project_id>',
help='The UUID of project in a multi-project cloud')
return parser
def take_action(self, parsed_args):
client = _get_client(self, parsed_args)
try:
client.quotas.delete()
client.quotas.delete(parsed_args.project_id)
print(_('Request to delete quotas has been accepted.'))
except Exception as e:
print("Delete for quotas failed: %(e)s" % {'e': e})

View File

@ -40,7 +40,7 @@ MODIFIED_USAGE_QUOTAS = {
}
fake_responses = {
'/v1/quotas':
'/v1/quotas/test_project_id':
{
'GET': (
{},
@ -55,14 +55,14 @@ fake_responses = {
None
)
},
'/v1/quotas/defaults':
'/v1/quotas/test_project_id/defaults':
{
'GET': (
{},
DEFAULT_QUOTAS
)
},
'/v1/quotas?usages=True':
'/v1/quotas/test_project_id?usages=True':
{
'GET': (
{},
@ -80,9 +80,9 @@ class QuotaManagerTest(testtools.TestCase):
self.mgr = quotas.QuotaManager(self.api)
def test_quotas_get_defaults(self):
quotas = self.mgr.defaults()
quotas = self.mgr.defaults('test_project_id')
expect = [
('GET', '/v1/quotas/defaults', {}, None)
('GET', '/v1/quotas/test_project_id/defaults', {}, None)
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(quotas.containers, DEFAULT_QUOTAS['containers'])

View File

@ -22,16 +22,18 @@ class QuotaManager(base.Manager):
resource_class = Quota
@staticmethod
def _path():
def _path(project_id):
if project_id is not None:
return '/v1/quotas/{}'.format(project_id)
return '/v1/quotas'
def get(self, **kwargs):
def get(self, project_id, **kwargs):
if not kwargs.get('usages'):
kwargs = {}
return self._list(self._path(), qparams=kwargs)[0]
return self._list(self._path(project_id), qparams=kwargs)[0]
def update(self, containers=None, memory=None,
cpu=None, disk=None):
def update(self, project_id, containers=None,
memory=None, cpu=None, disk=None):
resources = {}
if cpu is not None:
resources['cpu'] = cpu
@ -41,10 +43,10 @@ class QuotaManager(base.Manager):
resources['containers'] = containers
if disk is not None:
resources['disk'] = disk
return self._update(self._path(), resources, method='PUT')
return self._update(self._path(project_id), resources, method='PUT')
def defaults(self):
return self._list(self._path() + '/defaults')[0]
def defaults(self, project_id):
return self._list(self._path(project_id) + '/defaults')[0]
def delete(self):
return self._delete(self._path())
def delete(self, project_id):
return self._delete(self._path(project_id))

View File

@ -33,9 +33,14 @@ from zunclient.common import cliutils as utils
metavar='<disk>',
type=int,
help='The number of gigabytes of container Disk allowed per project')
@utils.arg(
'project_id',
metavar='<project_id>',
help='The UUID of project in a multi-project cloud')
def do_quota_update(cs, args):
"""Print an updated quotas for a project"""
utils.print_dict(cs.quotas.update(containers=args.containers,
utils.print_dict(cs.quotas.update(args.project_id,
containers=args.containers,
memory=args.memory,
cpu=args.cpu,
disk=args.disk)._info)
@ -46,20 +51,34 @@ def do_quota_update(cs, args):
default=False,
action='store_true',
help='Whether show quota usage statistic or not')
@utils.arg(
'project_id',
metavar='<project_id>',
help='The UUID of project in a multi-project cloud')
def do_quota_get(cs, args):
"""Print a quotas for a project with usages (optional)"""
if args.usages:
utils.print_dict(cs.quotas.get(usages=args.usages)._info,
value_fields=('limit', 'in_use'))
utils.print_dict(
cs.quotas.get(args.project_id, usages=args.usages)._info,
value_fields=('limit', 'in_use'))
else:
utils.print_dict(cs.quotas.get(usages=args.usages)._info)
utils.print_dict(
cs.quotas.get(args.project_id, usages=args.usages)._info)
@utils.arg(
'project_id',
metavar='<project_id>',
help='The UUID of project in a multi-project cloud')
def do_quota_defaults(cs, args):
"""Print a default quotas for a project"""
utils.print_dict(cs.quotas.defaults()._info)
utils.print_dict(cs.quotas.defaults(args.project_id)._info)
@utils.arg(
'project_id',
metavar='<project_id>',
help='The UUID of project in a multi-project cloud')
def do_quota_delete(cs, args):
"""Delete quotas for a project"""
cs.quotas.delete()
cs.quotas.delete(args.project_id)