Merge "quota: Add support for detailed volume quotas"
This commit is contained in:
commit
8be0c641e1
@ -94,7 +94,7 @@ quota-defaults,quota show --default,Lists default quotas for a tenant.
|
||||
quota-delete,quota delete --volume,Delete the quotas for a tenant.
|
||||
quota-show,quota show,Lists quotas for a tenant.
|
||||
quota-update,quota set,Updates quotas for a tenant.
|
||||
quota-usage,,Lists quota usage for a tenant.
|
||||
quota-usage,quota list --detail,Lists quota usage for a tenant.
|
||||
rate-limits,limits show --rate,Lists rate limits for a user.
|
||||
readonly-mode-update,volume set --read-only-mode | --read-write-mode,Updates volume read-only access-mode flag.
|
||||
rename,volume set --name,Renames a volume.
|
||||
|
|
@ -143,6 +143,7 @@ class BaseQuota(object):
|
||||
def get_volume_quota(self, client, parsed_args):
|
||||
quota_class = (
|
||||
parsed_args.quota_class if 'quota_class' in parsed_args else False)
|
||||
detail = parsed_args.detail if 'detail' in parsed_args else False
|
||||
default = parsed_args.default if 'default' in parsed_args else False
|
||||
try:
|
||||
if quota_class:
|
||||
@ -153,7 +154,7 @@ class BaseQuota(object):
|
||||
if default:
|
||||
quota = client.quotas.defaults(project)
|
||||
else:
|
||||
quota = client.quotas.get(project)
|
||||
quota = client.quotas.get(project, usage=detail)
|
||||
except Exception as e:
|
||||
if type(e).__name__ == 'EndpointNotFound':
|
||||
return {}
|
||||
@ -195,7 +196,7 @@ class BaseQuota(object):
|
||||
# more consistent
|
||||
for key, values in network_quota.items():
|
||||
if type(values) is dict and "used" in values:
|
||||
values[u'in_use'] = values.pop("used")
|
||||
values['in_use'] = values.pop("used")
|
||||
network_quota[key] = values
|
||||
return network_quota
|
||||
else:
|
||||
@ -205,7 +206,8 @@ class BaseQuota(object):
|
||||
class ListQuota(command.Lister, BaseQuota):
|
||||
_description = _(
|
||||
"List quotas for all projects with non-default quota values or "
|
||||
"list detailed quota information for requested project")
|
||||
"list detailed quota information for requested project"
|
||||
)
|
||||
|
||||
def _get_detailed_quotas(self, parsed_args):
|
||||
columns = (
|
||||
@ -222,10 +224,21 @@ class ListQuota(command.Lister, BaseQuota):
|
||||
)
|
||||
quotas = {}
|
||||
if parsed_args.compute:
|
||||
quotas.update(self.get_compute_quota(
|
||||
self.app.client_manager.compute, parsed_args))
|
||||
quotas.update(
|
||||
self.get_compute_quota(
|
||||
self.app.client_manager.compute,
|
||||
parsed_args,
|
||||
)
|
||||
)
|
||||
if parsed_args.network:
|
||||
quotas.update(self.get_network_quota(parsed_args))
|
||||
if parsed_args.volume:
|
||||
quotas.update(
|
||||
self.get_volume_quota(
|
||||
self.app.client_manager.volume,
|
||||
parsed_args,
|
||||
),
|
||||
)
|
||||
|
||||
result = []
|
||||
for resource, values in quotas.items():
|
||||
@ -359,8 +372,7 @@ class ListQuota(command.Lister, BaseQuota):
|
||||
|
||||
if parsed_args.volume:
|
||||
if parsed_args.detail:
|
||||
LOG.warning("Volume service doesn't provide detailed quota"
|
||||
" information")
|
||||
return self._get_detailed_quotas(parsed_args)
|
||||
volume_client = self.app.client_manager.volume
|
||||
for p in project_ids:
|
||||
try:
|
||||
|
@ -279,6 +279,37 @@ class TestQuotaList(TestQuota):
|
||||
self.assertEqual(
|
||||
sorted(detailed_reference_data), sorted(ret_quotas))
|
||||
|
||||
def test_quota_list_details_volume(self):
|
||||
detailed_quota = (
|
||||
volume_fakes.FakeQuota.create_one_detailed_quota())
|
||||
|
||||
detailed_column_header = (
|
||||
'Resource',
|
||||
'In Use',
|
||||
'Reserved',
|
||||
'Limit',
|
||||
)
|
||||
detailed_reference_data = (
|
||||
self._get_detailed_reference_data(detailed_quota))
|
||||
|
||||
self.volume.quotas.get = mock.Mock(return_value=detailed_quota)
|
||||
|
||||
arglist = [
|
||||
'--detail',
|
||||
'--volume',
|
||||
]
|
||||
verifylist = [
|
||||
('detail', True),
|
||||
('volume', True),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
ret_quotas = list(data)
|
||||
|
||||
self.assertEqual(detailed_column_header, columns)
|
||||
self.assertEqual(sorted(detailed_reference_data), sorted(ret_quotas))
|
||||
|
||||
def test_quota_list_compute(self):
|
||||
# Two projects with non-default quotas
|
||||
self.compute.quotas.get = mock.Mock(
|
||||
@ -1001,7 +1032,7 @@ class TestQuotaSet(TestQuota):
|
||||
class TestQuotaShow(TestQuota):
|
||||
|
||||
def setUp(self):
|
||||
super(TestQuotaShow, self).setUp()
|
||||
super().setUp()
|
||||
|
||||
self.compute_quota = compute_fakes.FakeQuota.create_one_comp_quota()
|
||||
self.compute_quotas_mock.get.return_value = self.compute_quota
|
||||
@ -1066,7 +1097,7 @@ class TestQuotaShow(TestQuota):
|
||||
self.projects[0].id, detail=False
|
||||
)
|
||||
self.volume_quotas_mock.get.assert_called_once_with(
|
||||
self.projects[0].id,
|
||||
self.projects[0].id, usage=False
|
||||
)
|
||||
self.network.get_quota.assert_called_once_with(
|
||||
self.projects[0].id, details=False
|
||||
@ -1128,7 +1159,7 @@ class TestQuotaShow(TestQuota):
|
||||
identity_fakes.project_id, detail=False
|
||||
)
|
||||
self.volume_quotas_mock.get.assert_called_once_with(
|
||||
identity_fakes.project_id,
|
||||
identity_fakes.project_id, usage=False
|
||||
)
|
||||
self.network.get_quota.assert_called_once_with(
|
||||
identity_fakes.project_id, details=False
|
||||
|
@ -1193,6 +1193,35 @@ class FakeQuota(object):
|
||||
|
||||
return quota
|
||||
|
||||
@staticmethod
|
||||
def create_one_detailed_quota(attrs=None):
|
||||
"""Create one quota"""
|
||||
attrs = attrs or {}
|
||||
|
||||
quota_attrs = {
|
||||
'volumes': {'limit': 3, 'in_use': 1, 'reserved': 0},
|
||||
'per_volume_gigabytes': {'limit': -1, 'in_use': 0, 'reserved': 0},
|
||||
'snapshots': {'limit': 10, 'in_use': 0, 'reserved': 0},
|
||||
'gigabytes': {'limit': 1000, 'in_use': 5, 'reserved': 0},
|
||||
'backups': {'limit': 10, 'in_use': 0, 'reserved': 0},
|
||||
'backup_gigabytes': {'limit': 1000, 'in_use': 0, 'reserved': 0},
|
||||
'volumes_lvmdriver-1': {'limit': -1, 'in_use': 1, 'reserved': 0},
|
||||
'gigabytes_lvmdriver-1': {'limit': -1, 'in_use': 5, 'reserved': 0},
|
||||
'snapshots_lvmdriver-1': {'limit': -1, 'in_use': 0, 'reserved': 0},
|
||||
'volumes___DEFAULT__': {'limit': -1, 'in_use': 0, 'reserved': 0},
|
||||
'gigabytes___DEFAULT__': {'limit': -1, 'in_use': 0, 'reserved': 0},
|
||||
'snapshots___DEFAULT__': {'limit': -1, 'in_use': 0, 'reserved': 0},
|
||||
'groups': {'limit': 10, 'in_use': 0, 'reserved': 0},
|
||||
'id': uuid.uuid4().hex,
|
||||
}
|
||||
quota_attrs.update(attrs)
|
||||
|
||||
quota = fakes.FakeResource(
|
||||
info=copy.deepcopy(quota_attrs),
|
||||
loaded=True)
|
||||
|
||||
return quota
|
||||
|
||||
|
||||
class FakeLimits(object):
|
||||
"""Fake limits"""
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
The ``quota list`` command can now provide detailed quotas for the volume
|
||||
service, e.g.::
|
||||
|
||||
$ openstack quota list --detail --volume
|
Loading…
Reference in New Issue
Block a user