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
This commit is contained in:
parent
180d012ca7
commit
24b06ef273
@ -125,6 +125,25 @@ class ClientManager(clientmanager.ClientManager):
|
||||
# use Network API by default
|
||||
return self.is_service_available('network') is not False
|
||||
|
||||
def is_compute_endpoint_enabled(self):
|
||||
"""Check if Compute endpoint is enabled"""
|
||||
|
||||
return self.is_service_available('compute') is not False
|
||||
|
||||
def is_volume_endpoint_enabled(self, volume_client):
|
||||
"""Check if volume endpoint is enabled"""
|
||||
# NOTE(jcross): Cinder did some interesting things with their service
|
||||
# name so we need to figure out which version to look
|
||||
# for when calling is_service_available()
|
||||
volume_version = volume_client.api_version.ver_major
|
||||
if self.is_service_available(
|
||||
"volumev%s" % volume_version) is not False:
|
||||
return True
|
||||
elif self.is_service_available('volume') is not False:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
# Plugin Support
|
||||
|
||||
|
@ -83,24 +83,34 @@ class ShowLimits(command.Lister):
|
||||
project_id = utils.find_resource(identity_client.projects,
|
||||
parsed_args.project).id
|
||||
|
||||
compute_limits = compute_client.limits.get(parsed_args.is_reserved,
|
||||
tenant_id=project_id)
|
||||
volume_limits = volume_client.limits.get()
|
||||
compute_limits = None
|
||||
volume_limits = None
|
||||
|
||||
if self.app.client_manager.is_compute_endpoint_enabled():
|
||||
compute_limits = compute_client.limits.get(parsed_args.is_reserved,
|
||||
tenant_id=project_id)
|
||||
|
||||
if self.app.client_manager.is_volume_endpoint_enabled(volume_client):
|
||||
volume_limits = volume_client.limits.get()
|
||||
|
||||
data = []
|
||||
if parsed_args.is_absolute:
|
||||
compute_limits = compute_limits.absolute
|
||||
volume_limits = volume_limits.absolute
|
||||
if compute_limits:
|
||||
data.append(compute_limits.absolute)
|
||||
if volume_limits:
|
||||
data.append(volume_limits.absolute)
|
||||
columns = ["Name", "Value"]
|
||||
return (columns, (utils.get_item_properties(s, columns)
|
||||
for s in itertools.chain(compute_limits, volume_limits)))
|
||||
for s in itertools.chain(*data)))
|
||||
|
||||
elif parsed_args.is_rate:
|
||||
compute_limits = compute_limits.rate
|
||||
volume_limits = volume_limits.rate
|
||||
if compute_limits:
|
||||
data.append(compute_limits.rate)
|
||||
if volume_limits:
|
||||
data.append(volume_limits.rate)
|
||||
columns = ["Verb", "URI", "Value", "Remain", "Unit",
|
||||
"Next Available"]
|
||||
return (columns, (utils.get_item_properties(s, columns)
|
||||
for s in itertools.chain(compute_limits, volume_limits)))
|
||||
|
||||
for s in itertools.chain(*data)))
|
||||
else:
|
||||
return ({}, {})
|
||||
return {}, {}
|
||||
|
125
openstackclient/tests/unit/common/test_limits.py
Normal file
125
openstackclient/tests/unit/common/test_limits.py
Normal file
@ -0,0 +1,125 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
from openstackclient.common import limits
|
||||
from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
|
||||
from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
|
||||
|
||||
|
||||
class TestComputeLimits(compute_fakes.TestComputev2):
|
||||
|
||||
absolute_columns = [
|
||||
'Name',
|
||||
'Value',
|
||||
]
|
||||
|
||||
rate_columns = [
|
||||
"Verb",
|
||||
"URI",
|
||||
"Value",
|
||||
"Remain",
|
||||
"Unit",
|
||||
"Next Available"
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(TestComputeLimits, self).setUp()
|
||||
self.app.client_manager.volume_endpoint_enabled = False
|
||||
self.compute = self.app.client_manager.compute
|
||||
|
||||
self.fake_limits = compute_fakes.FakeLimits()
|
||||
self.compute.limits.get.return_value = self.fake_limits
|
||||
|
||||
def test_compute_show_absolute(self):
|
||||
arglist = ['--absolute']
|
||||
verifylist = [('is_absolute', True)]
|
||||
cmd = limits.ShowLimits(self.app, None)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
|
||||
columns, data = cmd.take_action(parsed_args)
|
||||
|
||||
ret_limits = list(data)
|
||||
compute_reference_limits = self.fake_limits.absolute_limits()
|
||||
|
||||
self.assertEqual(self.absolute_columns, columns)
|
||||
self.assertEqual(compute_reference_limits, ret_limits)
|
||||
self.assertEqual(19, len(ret_limits))
|
||||
|
||||
def test_compute_show_rate(self):
|
||||
arglist = ['--rate']
|
||||
verifylist = [('is_rate', True)]
|
||||
cmd = limits.ShowLimits(self.app, None)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
|
||||
columns, data = cmd.take_action(parsed_args)
|
||||
|
||||
ret_limits = list(data)
|
||||
compute_reference_limits = self.fake_limits.rate_limits()
|
||||
|
||||
self.assertEqual(self.rate_columns, columns)
|
||||
self.assertEqual(compute_reference_limits, ret_limits)
|
||||
self.assertEqual(3, len(ret_limits))
|
||||
|
||||
|
||||
class TestVolumeLimits(volume_fakes.TestVolume):
|
||||
absolute_columns = [
|
||||
'Name',
|
||||
'Value',
|
||||
]
|
||||
|
||||
rate_columns = [
|
||||
"Verb",
|
||||
"URI",
|
||||
"Value",
|
||||
"Remain",
|
||||
"Unit",
|
||||
"Next Available"
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(TestVolumeLimits, self).setUp()
|
||||
self.app.client_manager.compute_endpoint_enabled = False
|
||||
self.volume = self.app.client_manager.volume
|
||||
|
||||
self.fake_limits = volume_fakes.FakeLimits()
|
||||
self.volume.limits.get.return_value = self.fake_limits
|
||||
|
||||
def test_volume_show_absolute(self):
|
||||
arglist = ['--absolute']
|
||||
verifylist = [('is_absolute', True)]
|
||||
cmd = limits.ShowLimits(self.app, None)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
|
||||
columns, data = cmd.take_action(parsed_args)
|
||||
|
||||
ret_limits = list(data)
|
||||
compute_reference_limits = self.fake_limits.absolute_limits()
|
||||
|
||||
self.assertEqual(self.absolute_columns, columns)
|
||||
self.assertEqual(compute_reference_limits, ret_limits)
|
||||
self.assertEqual(10, len(ret_limits))
|
||||
|
||||
def test_volume_show_rate(self):
|
||||
arglist = ['--rate']
|
||||
verifylist = [('is_rate', True)]
|
||||
cmd = limits.ShowLimits(self.app, None)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
|
||||
columns, data = cmd.take_action(parsed_args)
|
||||
|
||||
ret_limits = list(data)
|
||||
compute_reference_limits = self.fake_limits.rate_limits()
|
||||
|
||||
self.assertEqual(self.rate_columns, columns)
|
||||
self.assertEqual(compute_reference_limits, ret_limits)
|
||||
self.assertEqual(3, len(ret_limits))
|
@ -149,6 +149,9 @@ class FakeComputev2Client(object):
|
||||
self.images = mock.Mock()
|
||||
self.images.resource_class = fakes.FakeResource(None, {})
|
||||
|
||||
self.limits = mock.Mock()
|
||||
self.limits.resource_class = fakes.FakeResource(None, {})
|
||||
|
||||
self.servers = mock.Mock()
|
||||
self.servers.resource_class = fakes.FakeResource(None, {})
|
||||
|
||||
@ -1392,3 +1395,110 @@ class FakeQuota(object):
|
||||
quota.project_id = quota_attrs['id']
|
||||
|
||||
return quota
|
||||
|
||||
|
||||
class FakeLimits(object):
|
||||
"""Fake limits"""
|
||||
|
||||
def __init__(self, absolute_attrs=None, rate_attrs=None):
|
||||
self.absolute_limits_attrs = {
|
||||
'maxServerMeta': 128,
|
||||
'maxTotalInstances': 10,
|
||||
'maxPersonality': 5,
|
||||
'totalServerGroupsUsed': 0,
|
||||
'maxImageMeta': 128,
|
||||
'maxPersonalitySize': 10240,
|
||||
'maxTotalRAMSize': 51200,
|
||||
'maxServerGroups': 10,
|
||||
'maxSecurityGroupRules': 20,
|
||||
'maxTotalKeypairs': 100,
|
||||
'totalCoresUsed': 0,
|
||||
'totalRAMUsed': 0,
|
||||
'maxSecurityGroups': 10,
|
||||
'totalFloatingIpsUsed': 0,
|
||||
'totalInstancesUsed': 0,
|
||||
'maxServerGroupMembers': 10,
|
||||
'maxTotalFloatingIps': 10,
|
||||
'totalSecurityGroupsUsed': 0,
|
||||
'maxTotalCores': 20,
|
||||
}
|
||||
absolute_attrs = absolute_attrs or {}
|
||||
self.absolute_limits_attrs.update(absolute_attrs)
|
||||
|
||||
self.rate_limits_attrs = [{
|
||||
"uri": "*",
|
||||
"limit": [
|
||||
{
|
||||
"value": 10,
|
||||
"verb": "POST",
|
||||
"remaining": 2,
|
||||
"unit": "MINUTE",
|
||||
"next-available": "2011-12-15T22:42:45Z"
|
||||
},
|
||||
{
|
||||
"value": 10,
|
||||
"verb": "PUT",
|
||||
"remaining": 2,
|
||||
"unit": "MINUTE",
|
||||
"next-available": "2011-12-15T22:42:45Z"
|
||||
},
|
||||
{
|
||||
"value": 100,
|
||||
"verb": "DELETE",
|
||||
"remaining": 100,
|
||||
"unit": "MINUTE",
|
||||
"next-available": "2011-12-15T22:42:45Z"
|
||||
}
|
||||
]
|
||||
}]
|
||||
|
||||
@property
|
||||
def absolute(self):
|
||||
for (name, value) in self.absolute_limits_attrs.items():
|
||||
yield FakeAbsoluteLimit(name, value)
|
||||
|
||||
def absolute_limits(self):
|
||||
reference_data = []
|
||||
for (name, value) in self.absolute_limits_attrs.items():
|
||||
reference_data.append((name, value))
|
||||
return reference_data
|
||||
|
||||
@property
|
||||
def rate(self):
|
||||
for group in self.rate_limits_attrs:
|
||||
uri = group['uri']
|
||||
for rate in group['limit']:
|
||||
yield FakeRateLimit(rate['verb'], uri, rate['value'],
|
||||
rate['remaining'], rate['unit'],
|
||||
rate['next-available'])
|
||||
|
||||
def rate_limits(self):
|
||||
reference_data = []
|
||||
for group in self.rate_limits_attrs:
|
||||
uri = group['uri']
|
||||
for rate in group['limit']:
|
||||
reference_data.append((rate['verb'], uri, rate['value'],
|
||||
rate['remaining'], rate['unit'],
|
||||
rate['next-available']))
|
||||
return reference_data
|
||||
|
||||
|
||||
class FakeAbsoluteLimit(object):
|
||||
"""Data model that represents an absolute limit"""
|
||||
|
||||
def __init__(self, name, value):
|
||||
self.name = name
|
||||
self.value = value
|
||||
|
||||
|
||||
class FakeRateLimit(object):
|
||||
"""Data model that represents a flattened view of a single rate limit"""
|
||||
|
||||
def __init__(self, verb, uri, value, remain,
|
||||
unit, next_available):
|
||||
self.verb = verb
|
||||
self.uri = uri
|
||||
self.value = value
|
||||
self.remain = remain
|
||||
self.unit = unit
|
||||
self.next_available = next_available
|
||||
|
@ -140,6 +140,8 @@ class FakeClientManager(object):
|
||||
self.auth_ref = None
|
||||
self.auth_plugin_name = None
|
||||
self.network_endpoint_enabled = True
|
||||
self.compute_endpoint_enabled = True
|
||||
self.volume_endpoint_enabled = True
|
||||
|
||||
def get_configuration(self):
|
||||
return {
|
||||
@ -155,6 +157,12 @@ class FakeClientManager(object):
|
||||
def is_network_endpoint_enabled(self):
|
||||
return self.network_endpoint_enabled
|
||||
|
||||
def is_compute_endpoint_enabled(self):
|
||||
return self.compute_endpoint_enabled
|
||||
|
||||
def is_volume_endpoint_enabled(self, client):
|
||||
return self.volume_endpoint_enabled
|
||||
|
||||
|
||||
class FakeModule(object):
|
||||
|
||||
|
@ -200,6 +200,8 @@ class FakeVolumeClient(object):
|
||||
self.volumes.resource_class = fakes.FakeResource(None, {})
|
||||
self.extensions = mock.Mock()
|
||||
self.extensions.resource_class = fakes.FakeResource(None, {})
|
||||
self.limits = mock.Mock()
|
||||
self.limits.resource_class = fakes.FakeResource(None, {})
|
||||
self.volume_snapshots = mock.Mock()
|
||||
self.volume_snapshots.resource_class = fakes.FakeResource(None, {})
|
||||
self.backups = mock.Mock()
|
||||
@ -1004,3 +1006,101 @@ class FakeQuota(object):
|
||||
quota.project_id = quota_attrs['id']
|
||||
|
||||
return quota
|
||||
|
||||
|
||||
class FakeLimits(object):
|
||||
"""Fake limits"""
|
||||
|
||||
def __init__(self, absolute_attrs=None):
|
||||
self.absolute_limits_attrs = {
|
||||
'totalSnapshotsUsed': 1,
|
||||
'maxTotalBackups': 10,
|
||||
'maxTotalVolumeGigabytes': 1000,
|
||||
'maxTotalSnapshots': 10,
|
||||
'maxTotalBackupGigabytes': 1000,
|
||||
'totalBackupGigabytesUsed': 0,
|
||||
'maxTotalVolumes': 10,
|
||||
'totalVolumesUsed': 4,
|
||||
'totalBackupsUsed': 0,
|
||||
'totalGigabytesUsed': 35
|
||||
}
|
||||
absolute_attrs = absolute_attrs or {}
|
||||
self.absolute_limits_attrs.update(absolute_attrs)
|
||||
|
||||
self.rate_limits_attrs = [{
|
||||
"uri": "*",
|
||||
"limit": [
|
||||
{
|
||||
"value": 10,
|
||||
"verb": "POST",
|
||||
"remaining": 2,
|
||||
"unit": "MINUTE",
|
||||
"next-available": "2011-12-15T22:42:45Z"
|
||||
},
|
||||
{
|
||||
"value": 10,
|
||||
"verb": "PUT",
|
||||
"remaining": 2,
|
||||
"unit": "MINUTE",
|
||||
"next-available": "2011-12-15T22:42:45Z"
|
||||
},
|
||||
{
|
||||
"value": 100,
|
||||
"verb": "DELETE",
|
||||
"remaining": 100,
|
||||
"unit": "MINUTE",
|
||||
"next-available": "2011-12-15T22:42:45Z"
|
||||
}
|
||||
]
|
||||
}]
|
||||
|
||||
@property
|
||||
def absolute(self):
|
||||
for (name, value) in self.absolute_limits_attrs.items():
|
||||
yield FakeAbsoluteLimit(name, value)
|
||||
|
||||
def absolute_limits(self):
|
||||
reference_data = []
|
||||
for (name, value) in self.absolute_limits_attrs.items():
|
||||
reference_data.append((name, value))
|
||||
return reference_data
|
||||
|
||||
@property
|
||||
def rate(self):
|
||||
for group in self.rate_limits_attrs:
|
||||
uri = group['uri']
|
||||
for rate in group['limit']:
|
||||
yield FakeRateLimit(rate['verb'], uri, rate['value'],
|
||||
rate['remaining'], rate['unit'],
|
||||
rate['next-available'])
|
||||
|
||||
def rate_limits(self):
|
||||
reference_data = []
|
||||
for group in self.rate_limits_attrs:
|
||||
uri = group['uri']
|
||||
for rate in group['limit']:
|
||||
reference_data.append((rate['verb'], uri, rate['value'],
|
||||
rate['remaining'], rate['unit'],
|
||||
rate['next-available']))
|
||||
return reference_data
|
||||
|
||||
|
||||
class FakeAbsoluteLimit(object):
|
||||
"""Data model that represents an absolute limit."""
|
||||
|
||||
def __init__(self, name, value):
|
||||
self.name = name
|
||||
self.value = value
|
||||
|
||||
|
||||
class FakeRateLimit(object):
|
||||
"""Data model that represents a flattened view of a single rate limit."""
|
||||
|
||||
def __init__(self, verb, uri, value, remain,
|
||||
unit, next_available):
|
||||
self.verb = verb
|
||||
self.uri = uri
|
||||
self.value = value
|
||||
self.remain = remain
|
||||
self.unit = unit
|
||||
self.next_available = next_available
|
||||
|
Loading…
Reference in New Issue
Block a user