Skip to content

Commit 9d39437

Browse files
rajatherestephenfin
andcommitted
common: Migrate 'limits show' to SDK
This is done for both the compute and block storage services even though the compute service hasn't supported rate limits since API v2.1 was introduced [1]. [1] openstack/nova@ca4ec762804 Change-Id: Idd9f4a1c23952a6087f08c03ac8b5bebd5a0c86d Co-authored-by: Stephen Finucane <stephenfin@redhat.com> Depends-on: https://review.opendev.org/c/openstack/openstacksdk/+/918519
1 parent 55cbb84 commit 9d39437

7 files changed

Lines changed: 220 additions & 253 deletions

File tree

openstackclient/common/clientmanager.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,17 @@ def is_volume_endpoint_enabled(self, volume_client):
133133
# NOTE(jcross): Cinder did some interesting things with their service
134134
# name so we need to figure out which version to look
135135
# for when calling is_service_available()
136-
volume_version = volume_client.api_version.ver_major
136+
endpoint_data = volume_client.get_endpoint_data()
137+
# Not sure how endpoint data stores the api version for v2 API,
138+
# for v3 it is a tuple (3, 0)
139+
if endpoint_data.api_version and isinstance(
140+
endpoint_data.api_version, tuple
141+
):
142+
volume_version = endpoint_data.api_version[0]
143+
else:
144+
# Setting volume_version as 2 here if it doesn't satisfy the
145+
# conditions for version 3
146+
volume_version = 2
137147
if (
138148
self.is_service_available("volumev%s" % volume_version)
139149
is not False

openstackclient/common/limits.py

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,31 @@
2424
from openstackclient.identity import common as identity_common
2525

2626

27+
def _format_absolute_limit(absolute_limits):
28+
info = {}
29+
30+
for key in set(absolute_limits):
31+
if key in ('id', 'name', 'location'):
32+
continue
33+
34+
info[key] = absolute_limits[key]
35+
36+
return info
37+
38+
39+
def _format_rate_limit(rate_limits):
40+
# flatten this:
41+
#
42+
# {'uri': '<uri>', 'limit': [{'value': '<value>', ...], ...}
43+
#
44+
# to this:
45+
#
46+
# {'uri': '<uri>', 'value': '<value>', ...}, ...}
47+
return itertools.chain(
48+
*[[{'uri': x['uri'], **y} for y in x['limit']] for x in rate_limits]
49+
)
50+
51+
2752
class ShowLimits(command.Lister):
2853
_description = _("Show compute and block storage limits")
2954

@@ -42,36 +67,42 @@ def get_parser(self, prog_name):
4267
dest="is_rate",
4368
action="store_true",
4469
default=False,
45-
help=_("Show rate limits"),
70+
help=_(
71+
'Show rate limits. This is not supported by the compute '
72+
'service since the 12.0.0 (Liberty) release and is only '
73+
'supported by the block storage service when the '
74+
'rate-limiting middleware is enabled. It is therefore a no-op '
75+
'in most deployments.'
76+
),
4677
)
4778
parser.add_argument(
4879
"--reserved",
4980
dest="is_reserved",
5081
action="store_true",
5182
default=False,
52-
help=_("Include reservations count [only valid with --absolute]"),
83+
help=_("Include reservations count (only valid with --absolute)"),
5384
)
5485
parser.add_argument(
5586
'--project',
5687
metavar='<project>',
5788
help=_(
58-
'Show limits for a specific project (name or ID)'
59-
' [only valid with --absolute]'
89+
'Show limits for a specific project (name or ID) '
90+
'(only valid with --absolute)'
6091
),
6192
)
6293
parser.add_argument(
6394
'--domain',
6495
metavar='<domain>',
6596
help=_(
66-
'Domain the project belongs to (name or ID)'
67-
' [only valid with --absolute]'
97+
'Domain the project belongs to (name or ID) '
98+
'(only valid with --absolute)'
6899
),
69100
)
70101
return parser
71102

72103
def take_action(self, parsed_args):
73-
compute_client = self.app.client_manager.compute
74-
volume_client = self.app.client_manager.volume
104+
compute_client = self.app.client_manager.sdk_connection.compute
105+
volume_client = self.app.client_manager.sdk_connection.volume
75106

76107
project_id = None
77108
if parsed_args.project is not None:
@@ -94,33 +125,30 @@ def take_action(self, parsed_args):
94125
volume_limits = None
95126

96127
if self.app.client_manager.is_compute_endpoint_enabled():
97-
compute_limits = compute_client.limits.get(
98-
parsed_args.is_reserved, tenant_id=project_id
128+
compute_limits = compute_client.get_limits(
129+
reserved=parsed_args.is_reserved, tenant_id=project_id
99130
)
100131

101132
if self.app.client_manager.is_volume_endpoint_enabled(volume_client):
102-
volume_limits = volume_client.limits.get()
133+
volume_limits = volume_client.get_limits(
134+
project_id=project_id,
135+
)
103136

104-
data = []
105137
if parsed_args.is_absolute:
138+
columns = ["Name", "Value"]
139+
info = {}
106140
if compute_limits:
107-
data.append(compute_limits.absolute)
141+
info.update(_format_absolute_limit(compute_limits.absolute))
108142
if volume_limits:
109-
data.append(volume_limits.absolute)
110-
columns = ["Name", "Value"]
111-
return (
112-
columns,
113-
(
114-
utils.get_item_properties(s, columns)
115-
for s in itertools.chain(*data)
116-
),
117-
)
143+
info.update(_format_absolute_limit(volume_limits.absolute))
118144

119-
elif parsed_args.is_rate:
145+
return (columns, sorted(info.items(), key=lambda x: x[0]))
146+
else: # parsed_args.is_rate
147+
data = []
120148
if compute_limits:
121-
data.append(compute_limits.rate)
149+
data.extend(_format_rate_limit(compute_limits.rate))
122150
if volume_limits:
123-
data.append(volume_limits.rate)
151+
data.extend(_format_rate_limit(volume_limits.rate))
124152
columns = [
125153
"Verb",
126154
"URI",
@@ -129,12 +157,18 @@ def take_action(self, parsed_args):
129157
"Unit",
130158
"Next Available",
131159
]
160+
132161
return (
133162
columns,
134-
(
135-
utils.get_item_properties(s, columns)
136-
for s in itertools.chain(*data)
137-
),
163+
[
164+
(
165+
s['verb'],
166+
s['uri'],
167+
s['value'],
168+
s['remaining'],
169+
s['unit'],
170+
s.get('next-available') or s['next_available'],
171+
)
172+
for s in data
173+
],
138174
)
139-
else:
140-
return {}, {}

openstackclient/tests/unit/common/test_limits.py

Lines changed: 73 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,62 @@
1313

1414
from openstackclient.common import limits
1515
from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
16-
from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
16+
from openstackclient.tests.unit.volume.v3 import fakes as volume_fakes
1717

1818

1919
class TestComputeLimits(compute_fakes.TestComputev2):
20-
absolute_columns = [
21-
'Name',
22-
'Value',
23-
]
24-
20+
absolute_columns = ['Name', 'Value']
2521
rate_columns = ["Verb", "URI", "Value", "Remain", "Unit", "Next Available"]
2622

2723
def setUp(self):
2824
super().setUp()
2925
self.app.client_manager.volume_endpoint_enabled = False
3026

31-
self.fake_limits = compute_fakes.FakeLimits()
32-
self.compute_client.limits.get.return_value = self.fake_limits
27+
self.fake_limits = compute_fakes.create_limits()
28+
29+
self.absolute_data = [
30+
('floating_ips', 10),
31+
('floating_ips_used', 0),
32+
('image_meta', 128),
33+
('instances', 10),
34+
('instances_used', 0),
35+
('keypairs', 100),
36+
('max_image_meta', 128),
37+
('max_security_group_rules', 20),
38+
('max_security_groups', 10),
39+
('max_server_group_members', 10),
40+
('max_server_groups', 10),
41+
('max_server_meta', 128),
42+
('max_total_cores', 20),
43+
('max_total_floating_ips', 10),
44+
('max_total_instances', 10),
45+
('max_total_keypairs', 100),
46+
('max_total_ram_size', 51200),
47+
('personality', 5),
48+
('personality_size', 10240),
49+
('security_group_rules', 20),
50+
('security_groups', 10),
51+
('security_groups_used', 0),
52+
('server_group_members', 10),
53+
('server_groups', 10),
54+
('server_groups_used', 0),
55+
('server_meta', 128),
56+
('total_cores', 20),
57+
('total_cores_used', 0),
58+
('total_floating_ips_used', 0),
59+
('total_instances_used', 0),
60+
('total_ram', 51200),
61+
('total_ram_used', 0),
62+
('total_security_groups_used', 0),
63+
('total_server_groups_used', 0),
64+
]
65+
self.rate_data = [
66+
('POST', '*', 10, 2, 'MINUTE', '2011-12-15T22:42:45Z'),
67+
('PUT', '*', 10, 2, 'MINUTE', '2011-12-15T22:42:45Z'),
68+
('DELETE', '*', 100, 100, 'MINUTE', '2011-12-15T22:42:45Z'),
69+
]
70+
71+
self.compute_sdk_client.get_limits.return_value = self.fake_limits
3372

3473
def test_compute_show_absolute(self):
3574
arglist = ['--absolute']
@@ -39,12 +78,8 @@ def test_compute_show_absolute(self):
3978

4079
columns, data = cmd.take_action(parsed_args)
4180

42-
ret_limits = list(data)
43-
compute_reference_limits = self.fake_limits.absolute_limits()
44-
4581
self.assertEqual(self.absolute_columns, columns)
46-
self.assertEqual(compute_reference_limits, ret_limits)
47-
self.assertEqual(19, len(ret_limits))
82+
self.assertEqual(self.absolute_data, data)
4883

4984
def test_compute_show_rate(self):
5085
arglist = ['--rate']
@@ -54,28 +89,39 @@ def test_compute_show_rate(self):
5489

5590
columns, data = cmd.take_action(parsed_args)
5691

57-
ret_limits = list(data)
58-
compute_reference_limits = self.fake_limits.rate_limits()
59-
6092
self.assertEqual(self.rate_columns, columns)
61-
self.assertEqual(compute_reference_limits, ret_limits)
62-
self.assertEqual(3, len(ret_limits))
93+
self.assertEqual(self.rate_data, data)
6394

6495

6596
class TestVolumeLimits(volume_fakes.TestVolume):
66-
absolute_columns = [
67-
'Name',
68-
'Value',
69-
]
70-
97+
absolute_columns = ['Name', 'Value']
7198
rate_columns = ["Verb", "URI", "Value", "Remain", "Unit", "Next Available"]
7299

73100
def setUp(self):
74101
super().setUp()
75102
self.app.client_manager.compute_endpoint_enabled = False
76103

77-
self.fake_limits = volume_fakes.FakeLimits()
78-
self.volume_client.limits.get.return_value = self.fake_limits
104+
self.fake_limits = volume_fakes.create_limits()
105+
106+
self.absolute_data = [
107+
('max_total_backup_gigabytes', 1000),
108+
('max_total_backups', 10),
109+
('max_total_snapshots', 10),
110+
('max_total_volume_gigabytes', 1000),
111+
('max_total_volumes', 10),
112+
('total_backup_gigabytes_used', 0),
113+
('total_backups_used', 0),
114+
('total_gigabytes_used', 35),
115+
('total_snapshots_used', 1),
116+
('total_volumes_used', 4),
117+
]
118+
self.rate_data = [
119+
('POST', '*', 10, 2, 'MINUTE', '2011-12-15T22:42:45Z'),
120+
('PUT', '*', 10, 2, 'MINUTE', '2011-12-15T22:42:45Z'),
121+
('DELETE', '*', 100, 100, 'MINUTE', '2011-12-15T22:42:45Z'),
122+
]
123+
124+
self.volume_sdk_client.get_limits.return_value = self.fake_limits
79125

80126
def test_volume_show_absolute(self):
81127
arglist = ['--absolute']
@@ -85,12 +131,8 @@ def test_volume_show_absolute(self):
85131

86132
columns, data = cmd.take_action(parsed_args)
87133

88-
ret_limits = list(data)
89-
compute_reference_limits = self.fake_limits.absolute_limits()
90-
91134
self.assertEqual(self.absolute_columns, columns)
92-
self.assertEqual(compute_reference_limits, ret_limits)
93-
self.assertEqual(10, len(ret_limits))
135+
self.assertEqual(self.absolute_data, data)
94136

95137
def test_volume_show_rate(self):
96138
arglist = ['--rate']
@@ -100,9 +142,5 @@ def test_volume_show_rate(self):
100142

101143
columns, data = cmd.take_action(parsed_args)
102144

103-
ret_limits = list(data)
104-
compute_reference_limits = self.fake_limits.rate_limits()
105-
106145
self.assertEqual(self.rate_columns, columns)
107-
self.assertEqual(compute_reference_limits, ret_limits)
108-
self.assertEqual(3, len(ret_limits))
146+
self.assertEqual(self.rate_data, data)

0 commit comments

Comments
 (0)