Skip to content

Commit 87104a2

Browse files
author
Dean Troyer
committed
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
1 parent aa81b8b commit 87104a2

3 files changed

Lines changed: 194 additions & 118 deletions

File tree

openstackclient/common/quota.py

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
# Copyright 2012 OpenStack Foundation
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
#
15+
16+
"""Quota action implementations"""
17+
18+
import itertools
19+
import logging
20+
import six
21+
import sys
22+
23+
from cliff import command
24+
from cliff import show
25+
26+
27+
# List the quota items, map the internal argument name to the option
28+
# name that the user sees.
29+
30+
COMPUTE_QUOTAS = {
31+
'cores': 'cores',
32+
'fixed_ips': 'fixed-ips',
33+
'floating_ips': 'floating-ips',
34+
'injected_file_content_bytes': 'injected-file-size',
35+
'injected_file_path_bytes': 'injected-path-size',
36+
'injected_files': 'injected-files',
37+
'instances': 'instances',
38+
'key_pairs': 'key-pairs',
39+
'metadata_items': 'properties',
40+
'ram': 'ram',
41+
'security_group_rules': 'secgroup-rules',
42+
'security_groups': 'secgroups',
43+
}
44+
45+
VOLUME_QUOTAS = {
46+
'gigabytes': 'gigabytes',
47+
'snapshots': 'snapshots',
48+
'volumes': 'volumes',
49+
}
50+
51+
52+
class SetQuota(command.Command):
53+
"""Set quotas for project or class"""
54+
55+
log = logging.getLogger(__name__ + '.SetQuota')
56+
57+
def get_parser(self, prog_name):
58+
parser = super(SetQuota, self).get_parser(prog_name)
59+
parser.add_argument(
60+
'project',
61+
metavar='<project/class>',
62+
help='Set quotas for this project or class (name/ID)',
63+
)
64+
parser.add_argument(
65+
'--class',
66+
dest='quota_class',
67+
action='store_true',
68+
default=False,
69+
help='Set quotas for <class>',
70+
)
71+
for k, v in itertools.chain(
72+
COMPUTE_QUOTAS.items(), VOLUME_QUOTAS.items()):
73+
parser.add_argument(
74+
'--%s' % v,
75+
metavar='<new-%s>' % v,
76+
type=int,
77+
help='New value for the %s quota' % v,
78+
)
79+
return parser
80+
81+
def take_action(self, parsed_args):
82+
self.log.debug('take_action(%s)' % parsed_args)
83+
84+
compute_client = self.app.client_manager.compute
85+
volume_client = self.app.client_manager.volume
86+
87+
compute_kwargs = {}
88+
for k, v in COMPUTE_QUOTAS.items():
89+
if v in parsed_args:
90+
compute_kwargs[k] = getattr(parsed_args, v, None)
91+
92+
volume_kwargs = {}
93+
for k, v in VOLUME_QUOTAS.items():
94+
if v in parsed_args:
95+
volume_kwargs[k] = getattr(parsed_args, v, None)
96+
97+
if compute_kwargs == {} and volume_kwargs == {}:
98+
sys.stderr.write("No quotas updated")
99+
return
100+
101+
if parsed_args.quota_class:
102+
if compute_kwargs:
103+
compute_client.quota_classes.update(
104+
parsed_args.project,
105+
**compute_kwargs)
106+
if volume_kwargs:
107+
volume_client.quota_classes.update(
108+
parsed_args.project,
109+
**volume_kwargs)
110+
else:
111+
if compute_kwargs:
112+
compute_client.quotas.update(
113+
parsed_args.project,
114+
**compute_kwargs)
115+
if volume_kwargs:
116+
volume_client.quotas.update(
117+
parsed_args.project,
118+
**volume_kwargs)
119+
120+
121+
class ShowQuota(show.ShowOne):
122+
"""Show quotas for project or class"""
123+
124+
log = logging.getLogger(__name__ + '.ShowQuota')
125+
126+
def get_parser(self, prog_name):
127+
parser = super(ShowQuota, self).get_parser(prog_name)
128+
parser.add_argument(
129+
'project',
130+
metavar='<project/class>',
131+
help='Show this project or class (name/ID)',
132+
)
133+
type_group = parser.add_mutually_exclusive_group()
134+
type_group.add_argument(
135+
'--class',
136+
dest='quota_class',
137+
action='store_true',
138+
default=False,
139+
help='Show quotas for <class>',
140+
)
141+
type_group.add_argument(
142+
'--default',
143+
dest='default',
144+
action='store_true',
145+
default=False,
146+
help='Show default quotas for <project>'
147+
)
148+
return parser
149+
150+
def take_action(self, parsed_args):
151+
self.log.debug('take_action(%s)' % parsed_args)
152+
153+
compute_client = self.app.client_manager.compute
154+
volume_client = self.app.client_manager.volume
155+
156+
# NOTE(dtroyer): These quota API calls do not validate the project
157+
# or class arguments and return what appears to be
158+
# the default quota values if the project or class
159+
# does not exist. If this is determined to be the
160+
# intended behaviour of the API we will validate
161+
# the argument with Identity ourselves later.
162+
if parsed_args.quota_class:
163+
compute_quota = compute_client.quota_classes.get(
164+
parsed_args.project)
165+
volume_quota = volume_client.quota_classes.get(
166+
parsed_args.project)
167+
elif parsed_args.default:
168+
compute_quota = compute_client.quotas.defaults(
169+
parsed_args.project)
170+
volume_quota = volume_client.quotas.defaults(
171+
parsed_args.project)
172+
else:
173+
compute_quota = compute_client.quotas.get(parsed_args.project)
174+
volume_quota = volume_client.quotas.get(parsed_args.project)
175+
176+
info = {}
177+
info.update(compute_quota._info)
178+
info.update(volume_quota._info)
179+
180+
# Map the internal quota names to the external ones
181+
for k, v in itertools.chain(
182+
COMPUTE_QUOTAS.items(), VOLUME_QUOTAS.items()):
183+
if not k == v and info[k]:
184+
info[v] = info[k]
185+
info.pop(k)
186+
187+
# Handle project ID special as it only appears in output
188+
if info['id']:
189+
info['project'] = info['id']
190+
info.pop('id')
191+
192+
return zip(*sorted(six.iteritems(info)))

openstackclient/volume/v1/quota.py

Lines changed: 0 additions & 114 deletions
This file was deleted.

setup.cfg

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ openstack.cli =
3333

3434
openstack.common =
3535
limits_show = openstackclient.common.limits:ShowLimits
36+
quota_set = openstackclient.common.quota:SetQuota
37+
quota_show = openstackclient.common.quota:ShowQuota
3638

3739
openstack.identity.v2_0 =
3840
ec2_credentials_create = openstackclient.identity.v2_0.ec2creds:CreateEC2Creds
@@ -203,10 +205,6 @@ openstack.compute.v2 =
203205
server_unpause = openstackclient.compute.v2.server:UnpauseServer
204206

205207
openstack.volume.v1 =
206-
quota_list = openstackclient.volume.v1.quota:ListQuota
207-
quota_set = openstackclient.volume.v1.quota:SetQuota
208-
quota_show = openstackclient.volume.v1.quota:ShowQuota
209-
210208
snapshot_create = openstackclient.volume.v1.snapshot:CreateSnapshot
211209
snapshot_delete = openstackclient.volume.v1.snapshot:DeleteSnapshot
212210
snapshot_list = openstackclient.volume.v1.snapshot:ListSnapshot

0 commit comments

Comments
 (0)