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:
		@@ -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})
 | 
			
		||||
 
 | 
			
		||||
@@ -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'])
 | 
			
		||||
 
 | 
			
		||||
@@ -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))
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user