From d45442b3d46b26d928a5634874530168f961bb2b Mon Sep 17 00:00:00 2001 From: Abhishek Raut Date: Tue, 3 May 2016 05:17:12 -0700 Subject: [PATCH] Add support to expose default quotas for tenants Neutron client should be able to show the default quotas set for tenants. This patch adds support for the same and introduces a new CLI to retrieve default quotas. Sample usage: neutron quota-default-show +-----------------------+-------+ | Field | Value | +-----------------------+-------+ | floatingip | 50 | | l2-gateway-connection | -1 | | network | 10 | | port | 50 | | rbac_policy | 10 | | router | 10 | | security_group | 10 | | security_group_rule | 100 | | subnet | 10 | | subnetpool | -1 | +-----------------------+-------+ Change-Id: Ie92c22862d2b8ace32a2cf4cb642a6d0bac7932d Closes-Bug: #1204956 --- neutronclient/neutron/v2_0/quota.py | 49 ++++++++++--------- neutronclient/shell.py | 1 + neutronclient/tests/unit/test_quota.py | 33 +++++++++++++ neutronclient/v2_0/client.py | 7 +++ ...d-quota-default-show-c2ab35b791dcdcbc.yaml | 7 +++ 5 files changed, 73 insertions(+), 24 deletions(-) create mode 100644 releasenotes/notes/add-quota-default-show-c2ab35b791dcdcbc.yaml diff --git a/neutronclient/neutron/v2_0/quota.py b/neutronclient/neutron/v2_0/quota.py index e7e74b106..061f87371 100644 --- a/neutronclient/neutron/v2_0/quota.py +++ b/neutronclient/neutron/v2_0/quota.py @@ -16,6 +16,7 @@ from __future__ import print_function +import abc import argparse from cliff import lister @@ -90,14 +91,17 @@ class ListQuota(neutronV20.NeutronCommand, lister.Lister): for s in info)) -class ShowQuota(neutronV20.NeutronCommand, show.ShowOne): - """Show quotas of a given tenant. +class ShowQuotaBase(neutronV20.NeutronCommand, show.ShowOne): + """Base class to show quotas of a given tenant.""" - """ resource = "quota" + @abc.abstractmethod + def retrieve_data(self, tenant_id, neutron_client): + """Retrieve data using neutron client for the given tenant.""" + def get_parser(self, prog_name): - parser = super(ShowQuota, self).get_parser(prog_name) + parser = super(ShowQuotaBase, self).get_parser(prog_name) parser.add_argument( '--tenant-id', metavar='tenant-id', help=_('The owner tenant ID.')) @@ -115,27 +119,24 @@ class ShowQuota(neutronV20.NeutronCommand, show.ShowOne): def take_action(self, parsed_args): neutron_client = self.get_client() tenant_id = get_tenant_id(parsed_args, neutron_client) - params = {} - obj_shower = getattr(neutron_client, - "show_%s" % self.resource) - data = obj_shower(tenant_id, **params) + data = self.retrieve_data(tenant_id, neutron_client) if self.resource in data: - for k, v in six.iteritems(data[self.resource]): - if isinstance(v, list): - value = "" - for _item in v: - if value: - value += "\n" - if isinstance(_item, dict): - value += jsonutils.dumps(_item) - else: - value += str(_item) - data[self.resource][k] = value - elif v is None: - data[self.resource][k] = '' return zip(*sorted(six.iteritems(data[self.resource]))) - else: - return None + return + + +class ShowQuota(ShowQuotaBase): + """Show quotas for a given tenant.""" + + def retrieve_data(self, tenant_id, neutron_client): + return neutron_client.show_quota(tenant_id) + + +class ShowQuotaDefault(ShowQuotaBase): + """Show default quotas for a given tenant.""" + + def retrieve_data(self, tenant_id, neutron_client): + return neutron_client.show_quota_default(tenant_id) class UpdateQuota(neutronV20.NeutronCommand, show.ShowOne): @@ -240,4 +241,4 @@ class UpdateQuota(neutronV20.NeutronCommand, show.ShowOne): data[self.resource][k] = '' return zip(*sorted(six.iteritems(data[self.resource]))) else: - return None + return diff --git a/neutronclient/shell.py b/neutronclient/shell.py index 0870599c3..5ddae52b2 100644 --- a/neutronclient/shell.py +++ b/neutronclient/shell.py @@ -181,6 +181,7 @@ COMMAND_V2 = { 'purge': purge.Purge, 'quota-list': quota.ListQuota, 'quota-show': quota.ShowQuota, + 'quota-default-show': quota.ShowQuotaDefault, 'quota-delete': quota.DeleteQuota, 'quota-update': quota.UpdateQuota, 'ext-list': extension.ListExt, diff --git a/neutronclient/tests/unit/test_quota.py b/neutronclient/tests/unit/test_quota.py index 5be7ba3b7..b9d7b4448 100644 --- a/neutronclient/tests/unit/test_quota.py +++ b/neutronclient/tests/unit/test_quota.py @@ -16,6 +16,8 @@ import sys +from mox3 import mox + from neutronclient.common import exceptions from neutronclient.neutron.v2_0 import quota as test_quota from neutronclient.tests.unit import test_cli20 @@ -59,3 +61,34 @@ class CLITestV20Quota(test_cli20.CLITestV20Base): exceptions.NeutronClientException, self._test_update_resource, resource, cmd, self.test_id, args=args, extrafields={'network': 'new'}) + + def test_show_quota_default(self): + resource = 'quota' + cmd = test_quota.ShowQuotaDefault( + test_cli20.MyApp(sys.stdout), None) + args = ['--tenant-id', self.test_id] + self.mox.StubOutWithMock(cmd, "get_client") + self.mox.StubOutWithMock(self.client.httpclient, "request") + cmd.get_client().MultipleTimes().AndReturn(self.client) + expected_res = {'quota': {'port': 50, 'network': 10, 'subnet': 10}} + resstr = self.client.serialize(expected_res) + path = getattr(self.client, "quota_default_path") + return_tup = (test_cli20.MyResp(200), resstr) + self.client.httpclient.request( + test_cli20.end_url(path % self.test_id), 'GET', + body=None, + headers=mox.ContainsKeyValue( + 'X-Auth-Token', test_cli20.TOKEN)).AndReturn(return_tup) + self.mox.ReplayAll() + + cmd_parser = cmd.get_parser("test_" + resource) + parsed_args = cmd_parser.parse_args(args) + cmd.run(parsed_args) + + self.mox.VerifyAll() + self.mox.UnsetStubs() + _str = self.fake_stdout.make_string() + self.assertIn('network', _str) + self.assertIn('subnet', _str) + self.assertIn('port', _str) + self.assertNotIn('subnetpool', _str) diff --git a/neutronclient/v2_0/client.py b/neutronclient/v2_0/client.py index 5504fd1dd..ccea20ba0 100644 --- a/neutronclient/v2_0/client.py +++ b/neutronclient/v2_0/client.py @@ -411,6 +411,7 @@ class Client(ClientBase): address_scope_path = "/address-scopes/%s" quotas_path = "/quotas" quota_path = "/quotas/%s" + quota_default_path = "/quotas/%s/default" extensions_path = "/extensions" extension_path = "/extensions/%s" routers_path = "/routers" @@ -602,6 +603,12 @@ class Client(ClientBase): """Fetch information of a certain project's quotas.""" return self.get(self.quota_path % (project_id), params=_params) + @debtcollector.renames.renamed_kwarg( + 'tenant_id', 'project_id', replace=True) + def show_quota_default(self, project_id, **_params): + """Fetch information of a certain project's default quotas.""" + return self.get(self.quota_default_path % (project_id), params=_params) + @debtcollector.renames.renamed_kwarg( 'tenant_id', 'project_id', replace=True) def update_quota(self, project_id, body=None): diff --git a/releasenotes/notes/add-quota-default-show-c2ab35b791dcdcbc.yaml b/releasenotes/notes/add-quota-default-show-c2ab35b791dcdcbc.yaml new file mode 100644 index 000000000..3aececa35 --- /dev/null +++ b/releasenotes/notes/add-quota-default-show-c2ab35b791dcdcbc.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + CLI support to display the default quota reserved for a tenant. + + * The ``quota-default-show`` command outputs the default quota + of resources for a given tenant.