From 87104a28d75bd77df8b7ceb44600cd2b3971b4ae Mon Sep 17 00:00:00 2001 From: Dean Troyer Date: Wed, 3 Jul 2013 16:46:00 -0500 Subject: [PATCH] Add quota commands * Add quota set and quota show commands; these work on both the compute and volume APIs * Add the --class variation on the above commands Note: this replaces the existing volume-only quota commands and eliminates quota list Blueprint: cinder-client Bug: 1172064 Change-Id: I766d40e410e48f05e36e17e567a4f01a9411b40e --- openstackclient/common/quota.py | 192 +++++++++++++++++++++++++++++ openstackclient/volume/v1/quota.py | 114 ----------------- setup.cfg | 6 +- 3 files changed, 194 insertions(+), 118 deletions(-) create mode 100644 openstackclient/common/quota.py delete mode 100644 openstackclient/volume/v1/quota.py diff --git a/openstackclient/common/quota.py b/openstackclient/common/quota.py new file mode 100644 index 0000000000..fd482da9e6 --- /dev/null +++ b/openstackclient/common/quota.py @@ -0,0 +1,192 @@ +# Copyright 2012 OpenStack Foundation +# +# 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. +# + +"""Quota action implementations""" + +import itertools +import logging +import six +import sys + +from cliff import command +from cliff import show + + +# List the quota items, map the internal argument name to the option +# name that the user sees. + +COMPUTE_QUOTAS = { + 'cores': 'cores', + 'fixed_ips': 'fixed-ips', + 'floating_ips': 'floating-ips', + 'injected_file_content_bytes': 'injected-file-size', + 'injected_file_path_bytes': 'injected-path-size', + 'injected_files': 'injected-files', + 'instances': 'instances', + 'key_pairs': 'key-pairs', + 'metadata_items': 'properties', + 'ram': 'ram', + 'security_group_rules': 'secgroup-rules', + 'security_groups': 'secgroups', +} + +VOLUME_QUOTAS = { + 'gigabytes': 'gigabytes', + 'snapshots': 'snapshots', + 'volumes': 'volumes', +} + + +class SetQuota(command.Command): + """Set quotas for project or class""" + + log = logging.getLogger(__name__ + '.SetQuota') + + def get_parser(self, prog_name): + parser = super(SetQuota, self).get_parser(prog_name) + parser.add_argument( + 'project', + metavar='', + help='Set quotas for this project or class (name/ID)', + ) + parser.add_argument( + '--class', + dest='quota_class', + action='store_true', + default=False, + help='Set quotas for ', + ) + for k, v in itertools.chain( + COMPUTE_QUOTAS.items(), VOLUME_QUOTAS.items()): + parser.add_argument( + '--%s' % v, + metavar='' % v, + type=int, + help='New value for the %s quota' % v, + ) + return parser + + def take_action(self, parsed_args): + self.log.debug('take_action(%s)' % parsed_args) + + compute_client = self.app.client_manager.compute + volume_client = self.app.client_manager.volume + + compute_kwargs = {} + for k, v in COMPUTE_QUOTAS.items(): + if v in parsed_args: + compute_kwargs[k] = getattr(parsed_args, v, None) + + volume_kwargs = {} + for k, v in VOLUME_QUOTAS.items(): + if v in parsed_args: + volume_kwargs[k] = getattr(parsed_args, v, None) + + if compute_kwargs == {} and volume_kwargs == {}: + sys.stderr.write("No quotas updated") + return + + if parsed_args.quota_class: + if compute_kwargs: + compute_client.quota_classes.update( + parsed_args.project, + **compute_kwargs) + if volume_kwargs: + volume_client.quota_classes.update( + parsed_args.project, + **volume_kwargs) + else: + if compute_kwargs: + compute_client.quotas.update( + parsed_args.project, + **compute_kwargs) + if volume_kwargs: + volume_client.quotas.update( + parsed_args.project, + **volume_kwargs) + + +class ShowQuota(show.ShowOne): + """Show quotas for project or class""" + + log = logging.getLogger(__name__ + '.ShowQuota') + + def get_parser(self, prog_name): + parser = super(ShowQuota, self).get_parser(prog_name) + parser.add_argument( + 'project', + metavar='', + help='Show this project or class (name/ID)', + ) + type_group = parser.add_mutually_exclusive_group() + type_group.add_argument( + '--class', + dest='quota_class', + action='store_true', + default=False, + help='Show quotas for ', + ) + type_group.add_argument( + '--default', + dest='default', + action='store_true', + default=False, + help='Show default quotas for ' + ) + return parser + + def take_action(self, parsed_args): + self.log.debug('take_action(%s)' % parsed_args) + + compute_client = self.app.client_manager.compute + volume_client = self.app.client_manager.volume + + # NOTE(dtroyer): These quota API calls do not validate the project + # or class arguments and return what appears to be + # the default quota values if the project or class + # does not exist. If this is determined to be the + # intended behaviour of the API we will validate + # the argument with Identity ourselves later. + if parsed_args.quota_class: + compute_quota = compute_client.quota_classes.get( + parsed_args.project) + volume_quota = volume_client.quota_classes.get( + parsed_args.project) + elif parsed_args.default: + compute_quota = compute_client.quotas.defaults( + parsed_args.project) + volume_quota = volume_client.quotas.defaults( + parsed_args.project) + else: + compute_quota = compute_client.quotas.get(parsed_args.project) + volume_quota = volume_client.quotas.get(parsed_args.project) + + info = {} + info.update(compute_quota._info) + info.update(volume_quota._info) + + # Map the internal quota names to the external ones + for k, v in itertools.chain( + COMPUTE_QUOTAS.items(), VOLUME_QUOTAS.items()): + if not k == v and info[k]: + info[v] = info[k] + info.pop(k) + + # Handle project ID special as it only appears in output + if info['id']: + info['project'] = info['id'] + info.pop('id') + + return zip(*sorted(six.iteritems(info))) diff --git a/openstackclient/volume/v1/quota.py b/openstackclient/volume/v1/quota.py deleted file mode 100644 index 4f4e97e8f5..0000000000 --- a/openstackclient/volume/v1/quota.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2012-2013 OpenStack, LLC. -# -# 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. -# - -"""Volume v1 Quota action implementations""" - -import logging -import sys - -from cliff import command -from cliff import show - -from openstackclient.common import utils - - -class ListQuota(show.ShowOne): - """List quota command""" - - api = 'volume' - log = logging.getLogger(__name__ + '.ListQuota') - - def get_parser(self, prog_name): - parser = super(ListQuota, self).get_parser(prog_name) - parser.add_argument( - 'tenant', - metavar='', - help='ID of tenant to list the default quotas for') - return parser - - def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) - volume_client = self.app.client_manager.volume - defaults = volume_client.quotas.defaults(parsed_args.tenant) - - return zip(*sorted(defaults._info.iteritems())) - - -class SetQuota(command.Command): - """Set quota command""" - - api = 'volume' - log = logging.getLogger(__name__ + '.SetQuota') - - def get_parser(self, prog_name): - parser = super(SetQuota, self).get_parser(prog_name) - parser.add_argument( - 'tenant', - metavar='', - help='ID of tenant to set the quotas for') - parser.add_argument( - '--volumes', - metavar='', - type=int, - help='New value for the volumes quota') - parser.add_argument( - '--gigabytes', - metavar='', - type=int, - help='New value for the gigabytes quota') - return parser - - def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) - - kwargs = {} - if parsed_args.volumes: - kwargs['volumes'] = parsed_args.volumes - if parsed_args.gigabytes: - kwargs['gigabytes'] = parsed_args.gigabytes - - if kwargs == {}: - sys.stdout.write("Quota not updated, no arguments present") - return - - volume_client = self.app.client_manager.volume - volume_client.quotas.update(parsed_args.tenant, - parsed_args.volumes, - parsed_args.gigabytes) - - return - - -class ShowQuota(show.ShowOne): - """Show quota command""" - - api = 'volume' - log = logging.getLogger(__name__ + '.ShowQuota') - - def get_parser(self, prog_name): - parser = super(ShowQuota, self).get_parser(prog_name) - parser.add_argument( - 'tenant', - metavar='', - help='ID of tenant to list the quotas for') - return parser - - def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) - volume_client = self.app.client_manager.volume - quota = utils.find_resource(volume_client.quotas, - parsed_args.tenant) - - return zip(*sorted(quota._info.iteritems())) diff --git a/setup.cfg b/setup.cfg index bbda913db1..475e2077bb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -33,6 +33,8 @@ openstack.cli = openstack.common = limits_show = openstackclient.common.limits:ShowLimits + quota_set = openstackclient.common.quota:SetQuota + quota_show = openstackclient.common.quota:ShowQuota openstack.identity.v2_0 = ec2_credentials_create = openstackclient.identity.v2_0.ec2creds:CreateEC2Creds @@ -203,10 +205,6 @@ openstack.compute.v2 = server_unpause = openstackclient.compute.v2.server:UnpauseServer openstack.volume.v1 = - quota_list = openstackclient.volume.v1.quota:ListQuota - quota_set = openstackclient.volume.v1.quota:SetQuota - quota_show = openstackclient.volume.v1.quota:ShowQuota - snapshot_create = openstackclient.volume.v1.snapshot:CreateSnapshot snapshot_delete = openstackclient.volume.v1.snapshot:DeleteSnapshot snapshot_list = openstackclient.volume.v1.snapshot:ListSnapshot