Skip to content

Commit 24b06ef

Browse files
committed
Fix limits show command without Nova and Cinder
This patch implements an endpoint lookup when showing limits. This addresses the issue when showing limits without both Nova and Cinder and will display limits if one is missing. Change-Id: I2214b281e0206f8fe117aae52de2bf4c4e2c6525 Closes-bug: #1707960
1 parent 180d012 commit 24b06ef

6 files changed

Lines changed: 383 additions & 11 deletions

File tree

openstackclient/common/clientmanager.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,25 @@ def is_network_endpoint_enabled(self):
125125
# use Network API by default
126126
return self.is_service_available('network') is not False
127127

128+
def is_compute_endpoint_enabled(self):
129+
"""Check if Compute endpoint is enabled"""
130+
131+
return self.is_service_available('compute') is not False
132+
133+
def is_volume_endpoint_enabled(self, volume_client):
134+
"""Check if volume endpoint is enabled"""
135+
# NOTE(jcross): Cinder did some interesting things with their service
136+
# name so we need to figure out which version to look
137+
# for when calling is_service_available()
138+
volume_version = volume_client.api_version.ver_major
139+
if self.is_service_available(
140+
"volumev%s" % volume_version) is not False:
141+
return True
142+
elif self.is_service_available('volume') is not False:
143+
return True
144+
else:
145+
return False
146+
128147

129148
# Plugin Support
130149

openstackclient/common/limits.py

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,24 +83,34 @@ def take_action(self, parsed_args):
8383
project_id = utils.find_resource(identity_client.projects,
8484
parsed_args.project).id
8585

86-
compute_limits = compute_client.limits.get(parsed_args.is_reserved,
87-
tenant_id=project_id)
88-
volume_limits = volume_client.limits.get()
86+
compute_limits = None
87+
volume_limits = None
8988

89+
if self.app.client_manager.is_compute_endpoint_enabled():
90+
compute_limits = compute_client.limits.get(parsed_args.is_reserved,
91+
tenant_id=project_id)
92+
93+
if self.app.client_manager.is_volume_endpoint_enabled(volume_client):
94+
volume_limits = volume_client.limits.get()
95+
96+
data = []
9097
if parsed_args.is_absolute:
91-
compute_limits = compute_limits.absolute
92-
volume_limits = volume_limits.absolute
98+
if compute_limits:
99+
data.append(compute_limits.absolute)
100+
if volume_limits:
101+
data.append(volume_limits.absolute)
93102
columns = ["Name", "Value"]
94103
return (columns, (utils.get_item_properties(s, columns)
95-
for s in itertools.chain(compute_limits, volume_limits)))
104+
for s in itertools.chain(*data)))
96105

97106
elif parsed_args.is_rate:
98-
compute_limits = compute_limits.rate
99-
volume_limits = volume_limits.rate
107+
if compute_limits:
108+
data.append(compute_limits.rate)
109+
if volume_limits:
110+
data.append(volume_limits.rate)
100111
columns = ["Verb", "URI", "Value", "Remain", "Unit",
101112
"Next Available"]
102113
return (columns, (utils.get_item_properties(s, columns)
103-
for s in itertools.chain(compute_limits, volume_limits)))
104-
114+
for s in itertools.chain(*data)))
105115
else:
106-
return ({}, {})
116+
return {}, {}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
#
13+
14+
from openstackclient.common import limits
15+
from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
16+
from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
17+
18+
19+
class TestComputeLimits(compute_fakes.TestComputev2):
20+
21+
absolute_columns = [
22+
'Name',
23+
'Value',
24+
]
25+
26+
rate_columns = [
27+
"Verb",
28+
"URI",
29+
"Value",
30+
"Remain",
31+
"Unit",
32+
"Next Available"
33+
]
34+
35+
def setUp(self):
36+
super(TestComputeLimits, self).setUp()
37+
self.app.client_manager.volume_endpoint_enabled = False
38+
self.compute = self.app.client_manager.compute
39+
40+
self.fake_limits = compute_fakes.FakeLimits()
41+
self.compute.limits.get.return_value = self.fake_limits
42+
43+
def test_compute_show_absolute(self):
44+
arglist = ['--absolute']
45+
verifylist = [('is_absolute', True)]
46+
cmd = limits.ShowLimits(self.app, None)
47+
parsed_args = self.check_parser(cmd, arglist, verifylist)
48+
49+
columns, data = cmd.take_action(parsed_args)
50+
51+
ret_limits = list(data)
52+
compute_reference_limits = self.fake_limits.absolute_limits()
53+
54+
self.assertEqual(self.absolute_columns, columns)
55+
self.assertEqual(compute_reference_limits, ret_limits)
56+
self.assertEqual(19, len(ret_limits))
57+
58+
def test_compute_show_rate(self):
59+
arglist = ['--rate']
60+
verifylist = [('is_rate', True)]
61+
cmd = limits.ShowLimits(self.app, None)
62+
parsed_args = self.check_parser(cmd, arglist, verifylist)
63+
64+
columns, data = cmd.take_action(parsed_args)
65+
66+
ret_limits = list(data)
67+
compute_reference_limits = self.fake_limits.rate_limits()
68+
69+
self.assertEqual(self.rate_columns, columns)
70+
self.assertEqual(compute_reference_limits, ret_limits)
71+
self.assertEqual(3, len(ret_limits))
72+
73+
74+
class TestVolumeLimits(volume_fakes.TestVolume):
75+
absolute_columns = [
76+
'Name',
77+
'Value',
78+
]
79+
80+
rate_columns = [
81+
"Verb",
82+
"URI",
83+
"Value",
84+
"Remain",
85+
"Unit",
86+
"Next Available"
87+
]
88+
89+
def setUp(self):
90+
super(TestVolumeLimits, self).setUp()
91+
self.app.client_manager.compute_endpoint_enabled = False
92+
self.volume = self.app.client_manager.volume
93+
94+
self.fake_limits = volume_fakes.FakeLimits()
95+
self.volume.limits.get.return_value = self.fake_limits
96+
97+
def test_volume_show_absolute(self):
98+
arglist = ['--absolute']
99+
verifylist = [('is_absolute', True)]
100+
cmd = limits.ShowLimits(self.app, None)
101+
parsed_args = self.check_parser(cmd, arglist, verifylist)
102+
103+
columns, data = cmd.take_action(parsed_args)
104+
105+
ret_limits = list(data)
106+
compute_reference_limits = self.fake_limits.absolute_limits()
107+
108+
self.assertEqual(self.absolute_columns, columns)
109+
self.assertEqual(compute_reference_limits, ret_limits)
110+
self.assertEqual(10, len(ret_limits))
111+
112+
def test_volume_show_rate(self):
113+
arglist = ['--rate']
114+
verifylist = [('is_rate', True)]
115+
cmd = limits.ShowLimits(self.app, None)
116+
parsed_args = self.check_parser(cmd, arglist, verifylist)
117+
118+
columns, data = cmd.take_action(parsed_args)
119+
120+
ret_limits = list(data)
121+
compute_reference_limits = self.fake_limits.rate_limits()
122+
123+
self.assertEqual(self.rate_columns, columns)
124+
self.assertEqual(compute_reference_limits, ret_limits)
125+
self.assertEqual(3, len(ret_limits))

openstackclient/tests/unit/compute/v2/fakes.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ def __init__(self, **kwargs):
149149
self.images = mock.Mock()
150150
self.images.resource_class = fakes.FakeResource(None, {})
151151

152+
self.limits = mock.Mock()
153+
self.limits.resource_class = fakes.FakeResource(None, {})
154+
152155
self.servers = mock.Mock()
153156
self.servers.resource_class = fakes.FakeResource(None, {})
154157

@@ -1392,3 +1395,110 @@ def create_one_default_comp_quota(attrs=None):
13921395
quota.project_id = quota_attrs['id']
13931396

13941397
return quota
1398+
1399+
1400+
class FakeLimits(object):
1401+
"""Fake limits"""
1402+
1403+
def __init__(self, absolute_attrs=None, rate_attrs=None):
1404+
self.absolute_limits_attrs = {
1405+
'maxServerMeta': 128,
1406+
'maxTotalInstances': 10,
1407+
'maxPersonality': 5,
1408+
'totalServerGroupsUsed': 0,
1409+
'maxImageMeta': 128,
1410+
'maxPersonalitySize': 10240,
1411+
'maxTotalRAMSize': 51200,
1412+
'maxServerGroups': 10,
1413+
'maxSecurityGroupRules': 20,
1414+
'maxTotalKeypairs': 100,
1415+
'totalCoresUsed': 0,
1416+
'totalRAMUsed': 0,
1417+
'maxSecurityGroups': 10,
1418+
'totalFloatingIpsUsed': 0,
1419+
'totalInstancesUsed': 0,
1420+
'maxServerGroupMembers': 10,
1421+
'maxTotalFloatingIps': 10,
1422+
'totalSecurityGroupsUsed': 0,
1423+
'maxTotalCores': 20,
1424+
}
1425+
absolute_attrs = absolute_attrs or {}
1426+
self.absolute_limits_attrs.update(absolute_attrs)
1427+
1428+
self.rate_limits_attrs = [{
1429+
"uri": "*",
1430+
"limit": [
1431+
{
1432+
"value": 10,
1433+
"verb": "POST",
1434+
"remaining": 2,
1435+
"unit": "MINUTE",
1436+
"next-available": "2011-12-15T22:42:45Z"
1437+
},
1438+
{
1439+
"value": 10,
1440+
"verb": "PUT",
1441+
"remaining": 2,
1442+
"unit": "MINUTE",
1443+
"next-available": "2011-12-15T22:42:45Z"
1444+
},
1445+
{
1446+
"value": 100,
1447+
"verb": "DELETE",
1448+
"remaining": 100,
1449+
"unit": "MINUTE",
1450+
"next-available": "2011-12-15T22:42:45Z"
1451+
}
1452+
]
1453+
}]
1454+
1455+
@property
1456+
def absolute(self):
1457+
for (name, value) in self.absolute_limits_attrs.items():
1458+
yield FakeAbsoluteLimit(name, value)
1459+
1460+
def absolute_limits(self):
1461+
reference_data = []
1462+
for (name, value) in self.absolute_limits_attrs.items():
1463+
reference_data.append((name, value))
1464+
return reference_data
1465+
1466+
@property
1467+
def rate(self):
1468+
for group in self.rate_limits_attrs:
1469+
uri = group['uri']
1470+
for rate in group['limit']:
1471+
yield FakeRateLimit(rate['verb'], uri, rate['value'],
1472+
rate['remaining'], rate['unit'],
1473+
rate['next-available'])
1474+
1475+
def rate_limits(self):
1476+
reference_data = []
1477+
for group in self.rate_limits_attrs:
1478+
uri = group['uri']
1479+
for rate in group['limit']:
1480+
reference_data.append((rate['verb'], uri, rate['value'],
1481+
rate['remaining'], rate['unit'],
1482+
rate['next-available']))
1483+
return reference_data
1484+
1485+
1486+
class FakeAbsoluteLimit(object):
1487+
"""Data model that represents an absolute limit"""
1488+
1489+
def __init__(self, name, value):
1490+
self.name = name
1491+
self.value = value
1492+
1493+
1494+
class FakeRateLimit(object):
1495+
"""Data model that represents a flattened view of a single rate limit"""
1496+
1497+
def __init__(self, verb, uri, value, remain,
1498+
unit, next_available):
1499+
self.verb = verb
1500+
self.uri = uri
1501+
self.value = value
1502+
self.remain = remain
1503+
self.unit = unit
1504+
self.next_available = next_available

openstackclient/tests/unit/fakes.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ def __init__(self):
140140
self.auth_ref = None
141141
self.auth_plugin_name = None
142142
self.network_endpoint_enabled = True
143+
self.compute_endpoint_enabled = True
144+
self.volume_endpoint_enabled = True
143145

144146
def get_configuration(self):
145147
return {
@@ -155,6 +157,12 @@ def get_configuration(self):
155157
def is_network_endpoint_enabled(self):
156158
return self.network_endpoint_enabled
157159

160+
def is_compute_endpoint_enabled(self):
161+
return self.compute_endpoint_enabled
162+
163+
def is_volume_endpoint_enabled(self, client):
164+
return self.volume_endpoint_enabled
165+
158166

159167
class FakeModule(object):
160168

0 commit comments

Comments
 (0)