Add the ability to check tenant quota detail
For other component such like cinder, the administrator could check the quota usage of tenant. Currently Manila retrieves the quota set information only with 'limit' property. This patch intends to enhance the API by return more properties ('in_use', 'limit', 'reserved') with new option '--detail'. Change-Id: Ibc0f9f65891b8e2a308358420d2c4dc3ea4697ce Implements: blueprint admin-check-tenant-quota-usage
This commit is contained in:
parent
c91deb8498
commit
64f38da1ff
@ -79,3 +79,8 @@ class ManilaClientTestQuotasReadOnly(base.BaseTestCase):
|
||||
@utils.skip_if_microversion_not_supported("2.7")
|
||||
def test_quota_show_api_2_7(self, role):
|
||||
self._get_quotas(role, "show", "2.7")
|
||||
|
||||
@ddt.data('admin', 'user')
|
||||
@utils.skip_if_microversion_not_supported("2.25")
|
||||
def test_quota_show_api_2_25(self, role):
|
||||
self._get_quotas(role, "show --detail", "2.25")
|
||||
|
@ -285,6 +285,42 @@ class FakeHTTPClient(fakes.FakeHTTPClient):
|
||||
}
|
||||
return (200, {}, instances)
|
||||
|
||||
def get_quota_sets_1234(self, *args, **kwargs):
|
||||
quota_set = {
|
||||
'quota_set': {
|
||||
'id': '1234',
|
||||
'shares': 50,
|
||||
'gigabytes': 1000,
|
||||
'snapshots': 50,
|
||||
'snapshot_gigabytes': 1000,
|
||||
'share_networks': 10,
|
||||
}
|
||||
}
|
||||
return (200, {}, quota_set)
|
||||
|
||||
def get_quota_sets_1234_detail(self, *args, **kwargs):
|
||||
quota_set = {
|
||||
'quota_set': {
|
||||
'id': '1234',
|
||||
'shares': {'in_use': 0,
|
||||
'limit': 50,
|
||||
'reserved': 0},
|
||||
'gigabytes': {'in_use': 0,
|
||||
'limit': 10000,
|
||||
'reserved': 0},
|
||||
'snapshots': {'in_use': 0,
|
||||
'limit': 50,
|
||||
'reserved': 0},
|
||||
'snapshot_gigabytes': {'in_use': 0,
|
||||
'limit': 1000,
|
||||
'reserved': 0},
|
||||
'share_networks': {'in_use': 0,
|
||||
'limit': 10,
|
||||
'reserved': 0},
|
||||
}
|
||||
}
|
||||
return (200, {}, quota_set)
|
||||
|
||||
def get_share_instances(self, **kw):
|
||||
return self._share_instances()
|
||||
|
||||
@ -921,3 +957,12 @@ def fake_create(url, body, response_key):
|
||||
|
||||
def fake_update(url, body, response_key):
|
||||
return {'url': url, 'body': body, 'resp_key': response_key}
|
||||
|
||||
|
||||
class FakeQuotaSet(object):
|
||||
|
||||
def __init__(self, dictionary):
|
||||
self.dictionary = dictionary
|
||||
|
||||
def to_dict(self):
|
||||
return self.dictionary
|
||||
|
@ -35,28 +35,41 @@ class QuotaSetsTest(utils.TestCase):
|
||||
return quotas.RESOURCE_PATH
|
||||
return quotas.RESOURCE_PATH_LEGACY
|
||||
|
||||
@ddt.data("2.6", "2.7")
|
||||
@ddt.data("2.6", "2.7", "2.25")
|
||||
def test_tenant_quotas_get(self, microversion):
|
||||
tenant_id = 'test'
|
||||
manager = self._get_manager(microversion)
|
||||
resource_path = self._get_resource_path(microversion)
|
||||
expected_url = "%s/test" % resource_path
|
||||
version = api_versions.APIVersion(microversion)
|
||||
if version >= api_versions.APIVersion('2.25'):
|
||||
expected_url = "%s/test/detail" % resource_path
|
||||
else:
|
||||
expected_url = ("%s/test"
|
||||
% resource_path)
|
||||
|
||||
with mock.patch.object(manager, '_get',
|
||||
mock.Mock(return_value='fake_get')):
|
||||
manager.get(tenant_id)
|
||||
manager.get(tenant_id, detail=True)
|
||||
|
||||
manager._get.assert_called_once_with(expected_url, "quota_set")
|
||||
|
||||
@ddt.data("2.6", "2.7")
|
||||
@ddt.data("2.6", "2.7", "2.25")
|
||||
def test_user_quotas_get(self, microversion):
|
||||
tenant_id = 'test'
|
||||
user_id = 'fake_user'
|
||||
manager = self._get_manager(microversion)
|
||||
resource_path = self._get_resource_path(microversion)
|
||||
expected_url = "%s/test?user_id=fake_user" % resource_path
|
||||
version = api_versions.APIVersion(microversion)
|
||||
if version >= api_versions.APIVersion('2.25'):
|
||||
expected_url = ("%s/test/detail?user_id=fake_user"
|
||||
% resource_path)
|
||||
else:
|
||||
expected_url = ("%s/test?user_id=fake_user"
|
||||
% resource_path)
|
||||
|
||||
with mock.patch.object(manager, '_get',
|
||||
mock.Mock(return_value='fake_get')):
|
||||
manager.get(tenant_id, user_id=user_id)
|
||||
manager.get(tenant_id, user_id=user_id, detail=True)
|
||||
|
||||
manager._get.assert_called_once_with(expected_url, "quota_set")
|
||||
|
||||
|
@ -1619,6 +1619,33 @@ class ShellTest(test_utils.TestCase):
|
||||
mock.ANY,
|
||||
fields=["Name", "Host", "Backend", "Pool"])
|
||||
|
||||
@mock.patch.object(cliutils, 'print_dict', mock.Mock())
|
||||
def test_quota_show(self):
|
||||
self.run_command('quota-show --tenant 1234')
|
||||
self.assert_called(
|
||||
'GET',
|
||||
'/quota-sets/1234',
|
||||
)
|
||||
cliutils.print_dict.assert_called_once_with(mock.ANY)
|
||||
|
||||
@mock.patch.object(cliutils, 'print_dict', mock.Mock())
|
||||
def test_quota_show_with_detail(self):
|
||||
self.run_command('quota-show --tenant 1234 --detail')
|
||||
self.assert_called(
|
||||
'GET',
|
||||
'/quota-sets/1234/detail',
|
||||
)
|
||||
cliutils.print_dict.assert_called_once_with(mock.ANY)
|
||||
|
||||
@mock.patch.object(cliutils, 'print_dict', mock.Mock())
|
||||
def test_quota_show_with_user_id(self):
|
||||
self.run_command('quota-show --tenant 1234 --user 1111')
|
||||
self.assert_called(
|
||||
'GET',
|
||||
'/quota-sets/1234?user_id=1111',
|
||||
)
|
||||
cliutils.print_dict.assert_called_once_with(mock.ANY)
|
||||
|
||||
@mock.patch.object(cliutils, 'print_list', mock.Mock())
|
||||
def test_pool_list_with_detail(self):
|
||||
self.run_command('pool-list --detail')
|
||||
@ -1641,6 +1668,23 @@ class ShellTest(test_utils.TestCase):
|
||||
mock.ANY,
|
||||
fields=["Name", "Host"])
|
||||
|
||||
@ddt.data(({"key1": "value1",
|
||||
"key2": "value2"},
|
||||
{"key1": "value1",
|
||||
"key2": "value2"}),
|
||||
({"key1": {"key11": "value11", "key12": "value12"},
|
||||
"key2": {"key21": "value21"}},
|
||||
{"key1": "key11 = value11\nkey12 = value12",
|
||||
"key2": "key21 = value21"}),
|
||||
({}, {}))
|
||||
@ddt.unpack
|
||||
@mock.patch.object(cliutils, 'print_dict', mock.Mock())
|
||||
def test_quota_set_pretty_show(self, value, expected):
|
||||
fake_quota_set = fakes.FakeQuotaSet(value)
|
||||
|
||||
shell_v2._quota_set_pretty_show(fake_quota_set)
|
||||
cliutils.print_dict.assert_called_with(expected)
|
||||
|
||||
@ddt.data('--share-type test_type', '--share_type test_type',
|
||||
'--share-type-id 0123456789', '--share_type_id 0123456789')
|
||||
@mock.patch.object(cliutils, 'print_list', mock.Mock())
|
||||
|
@ -35,27 +35,40 @@ class QuotaSet(common_base.Resource):
|
||||
class QuotaSetManager(base.ManagerWithFind):
|
||||
resource_class = QuotaSet
|
||||
|
||||
def _do_get(self, tenant_id, user_id=None, resource_path=RESOURCE_PATH):
|
||||
def _do_get(self, tenant_id, user_id=None, detail=False,
|
||||
resource_path=RESOURCE_PATH):
|
||||
if hasattr(tenant_id, 'tenant_id'):
|
||||
tenant_id = tenant_id.tenant_id
|
||||
|
||||
if detail:
|
||||
query = '/detail'
|
||||
else:
|
||||
query = ''
|
||||
|
||||
if user_id:
|
||||
query = '%s?user_id=%s' % (query, user_id)
|
||||
data = {
|
||||
"resource_path": resource_path,
|
||||
"tenant_id": tenant_id,
|
||||
"user_id": user_id,
|
||||
}
|
||||
if user_id:
|
||||
url = "%(resource_path)s/%(tenant_id)s?user_id=%(user_id)s" % data
|
||||
else:
|
||||
url = "%(resource_path)s/%(tenant_id)s" % data
|
||||
|
||||
url = ("%(resource_path)s/%(tenant_id)s" + query) % data
|
||||
return self._get(url, "quota_set")
|
||||
|
||||
@api_versions.wraps("1.0", "2.6")
|
||||
def get(self, tenant_id, user_id=None):
|
||||
return self._do_get(tenant_id, user_id, RESOURCE_PATH_LEGACY)
|
||||
def get(self, tenant_id, user_id=None, detail=False):
|
||||
return self._do_get(tenant_id, user_id,
|
||||
resource_path=RESOURCE_PATH_LEGACY)
|
||||
|
||||
@api_versions.wraps("2.7") # noqa
|
||||
def get(self, tenant_id, user_id=None):
|
||||
return self._do_get(tenant_id, user_id, RESOURCE_PATH)
|
||||
@api_versions.wraps("2.7", "2.24") # noqa
|
||||
def get(self, tenant_id, user_id=None, detail=False):
|
||||
return self._do_get(tenant_id, user_id,
|
||||
resource_path=RESOURCE_PATH)
|
||||
|
||||
@api_versions.wraps("2.25") # noqa
|
||||
def get(self, tenant_id, user_id=None, detail=False):
|
||||
return self._do_get(tenant_id, user_id, detail,
|
||||
resource_path=RESOURCE_PATH)
|
||||
|
||||
def _do_update(self, tenant_id, shares=None, snapshots=None,
|
||||
gigabytes=None, snapshot_gigabytes=None,
|
||||
|
@ -219,6 +219,19 @@ def _print_share_snapshot(cs, snapshot):
|
||||
cliutils.print_dict(info)
|
||||
|
||||
|
||||
def _quota_set_pretty_show(quotas):
|
||||
"""convert quotas object to dict and display"""
|
||||
|
||||
new_quotas = {}
|
||||
for quota_k, quota_v in sorted(quotas.to_dict().items()):
|
||||
if isinstance(quota_v, dict):
|
||||
quota_v = '\n'.join(
|
||||
['%s = %s' % (k, v) for k, v in sorted(quota_v.items())])
|
||||
new_quotas[quota_k] = quota_v
|
||||
|
||||
cliutils.print_dict(new_quotas)
|
||||
|
||||
|
||||
def _find_share_snapshot_instance(cs, snapshot_instance):
|
||||
"""Get a share snapshot instance by ID."""
|
||||
return apiclient_utils.find_resource(
|
||||
@ -361,13 +374,16 @@ def _quota_update(manager, identifier, args):
|
||||
metavar='<user-id>',
|
||||
default=None,
|
||||
help='ID of user to list the quotas for.')
|
||||
@cliutils.arg(
|
||||
'--detail',
|
||||
action='store_true',
|
||||
help='Optional flag to indicate whether to show quota in detail. '
|
||||
'Default false, available only for microversion >= 2.25.')
|
||||
def do_quota_show(cs, args):
|
||||
"""List the quotas for a tenant/user."""
|
||||
project_id = cs.keystone_client.project_id
|
||||
if not args.tenant:
|
||||
_quota_show(cs.quotas.get(project_id, user_id=args.user))
|
||||
else:
|
||||
_quota_show(cs.quotas.get(args.tenant, user_id=args.user))
|
||||
project = args.tenant or cs.keystone_client.project_id
|
||||
qts = cs.quotas.get(project, user_id=args.user, detail=args.detail)
|
||||
_quota_set_pretty_show(qts)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
|
@ -0,0 +1,3 @@
|
||||
---
|
||||
features:
|
||||
- Add support to check quota usage by '--detail' in quota-show
|
Loading…
x
Reference in New Issue
Block a user