diff --git a/openstackclient/common/quota.py b/openstackclient/common/quota.py index 4eb44b393e..d412e05cfd 100644 --- a/openstackclient/common/quota.py +++ b/openstackclient/common/quota.py @@ -11,7 +11,6 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -# """Quota action implementations""" @@ -130,18 +129,12 @@ def get_compute_quotas( app, project_id, *, - quota_class=False, detail=False, default=False, ): try: client = app.client_manager.compute - if quota_class: - # NOTE(stephenfin): The 'project' argument here could be anything - # as the nova API doesn't care what you pass in. We only pass the - # project in to avoid weirding people out :) - quota = client.quota_classes.get(project_id) - elif default: + if default: quota = client.quotas.defaults(project_id) else: quota = client.quotas.get(project_id, detail=detail) @@ -156,15 +149,12 @@ def get_volume_quotas( app, project_id, *, - quota_class=False, detail=False, default=False, ): try: client = app.client_manager.volume - if quota_class: - quota = client.quota_classes.get(project_id) - elif default: + if default: quota = client.quotas.defaults(project_id) else: quota = client.quotas.get(project_id, usage=detail) @@ -180,7 +170,6 @@ def get_network_quotas( app, project_id, *, - quota_class=False, detail=False, default=False, ): @@ -207,11 +196,6 @@ def get_network_quotas( return result - # neutron doesn't have the concept of quota classes and if we're using - # nova-network we already fetched this - if quota_class: - return {} - # we have nothing to return if we are not using neutron if not app.client_manager.is_network_endpoint_enabled(): return {} @@ -227,34 +211,14 @@ def get_network_quotas( class ListQuota(command.Lister): - _description = _( - "List quotas for all projects with non-default quota values or " - "list detailed quota information for requested project" - ) + """List quotas for all projects with non-default quota values. + + Empty output means all projects are using default quotas, which can be + inspected with 'openstack quota show --default'. + """ def get_parser(self, prog_name): parser = super().get_parser(prog_name) - # TODO(stephenfin): Remove in OSC 8.0 - parser.add_argument( - '--project', - metavar='', - help=_( - "**Deprecated** List quotas for this project " - "(name or ID). " - "Use 'quota show' instead." - ), - ) - # TODO(stephenfin): Remove in OSC 8.0 - parser.add_argument( - '--detail', - dest='detail', - action='store_true', - default=False, - help=_( - "**Deprecated** Show details about quotas usage. " - "Use 'quota show --usage' instead." - ), - ) option = parser.add_mutually_exclusive_group(required=True) option.add_argument( '--compute', @@ -276,102 +240,13 @@ class ListQuota(command.Lister): ) return parser - def _get_detailed_quotas(self, parsed_args): - project_info = get_project(self.app, parsed_args.project) - project = project_info['id'] - - quotas = {} - - if parsed_args.compute: - quotas.update( - get_compute_quotas( - self.app, - project, - detail=parsed_args.detail, - ) - ) - - if parsed_args.network: - quotas.update( - get_network_quotas( - self.app, - project, - detail=parsed_args.detail, - ) - ) - - if parsed_args.volume: - quotas.update( - get_volume_quotas( - self.app, - parsed_args, - detail=parsed_args.detail, - ), - ) - - result = [] - for resource, values in quotas.items(): - # NOTE(slaweq): there is no detailed quotas info for some resources - # and it shouldn't be displayed here - if isinstance(values, dict): - result.append( - { - 'resource': resource, - 'in_use': values.get('in_use'), - 'reserved': values.get('reserved'), - 'limit': values.get('limit'), - } - ) - - columns = ( - 'resource', - 'in_use', - 'reserved', - 'limit', - ) - column_headers = ( - 'Resource', - 'In Use', - 'Reserved', - 'Limit', - ) - - return ( - column_headers, - (utils.get_dict_properties(s, columns) for s in result), - ) - def take_action(self, parsed_args): - if parsed_args.detail: - msg = _( - "The --detail option has been deprecated. " - "Use 'openstack quota show --usage' instead." - ) - self.log.warning(msg) - elif parsed_args.project: # elif to avoid being too noisy - msg = _( - "The --project option has been deprecated. " - "Use 'openstack quota show' instead." - ) - self.log.warning(msg) - result = [] - project_ids = [] - if parsed_args.project is None: - for p in self.app.client_manager.identity.projects.list(): - project_ids.append(getattr(p, 'id', '')) - else: - identity_client = self.app.client_manager.identity - project = utils.find_resource( - identity_client.projects, - parsed_args.project, - ) - project_ids.append(getattr(project, 'id', '')) + project_ids = [ + p.id for p in self.app.client_manager.identity.projects.list() + ] if parsed_args.compute: - if parsed_args.detail: - return self._get_detailed_quotas(parsed_args) - compute_client = self.app.client_manager.compute for p in project_ids: try: @@ -434,9 +309,6 @@ class ListQuota(command.Lister): ) if parsed_args.volume: - if parsed_args.detail: - return self._get_detailed_quotas(parsed_args) - volume_client = self.app.client_manager.volume for p in project_ids: try: @@ -488,9 +360,6 @@ class ListQuota(command.Lister): ) if parsed_args.network: - if parsed_args.detail: - return self._get_detailed_quotas(parsed_args) - client = self.app.client_manager.network for p in project_ids: try: @@ -728,22 +597,24 @@ class SetQuota(common.NetDetectionMixin, command.Command): "Network quotas are ignored since quota classes are not " "supported." ) - else: - project = utils.find_resource( - identity_client.projects, - parsed_args.project, - ).id - if compute_kwargs: - compute_client.quotas.update(project, **compute_kwargs) - if volume_kwargs: - volume_client.quotas.update(project, **volume_kwargs) - if ( - network_kwargs - and self.app.client_manager.is_network_endpoint_enabled() - ): - network_client = self.app.client_manager.network - network_client.update_quota(project, **network_kwargs) + return + + project = utils.find_resource( + identity_client.projects, + parsed_args.project, + ).id + + if compute_kwargs: + compute_client.quotas.update(project, **compute_kwargs) + if volume_kwargs: + volume_client.quotas.update(project, **volume_kwargs) + if ( + network_kwargs + and self.app.client_manager.is_network_endpoint_enabled() + ): + network_client = self.app.client_manager.network + network_client.update_quota(project, **network_kwargs) class ShowQuota(command.Lister): @@ -758,29 +629,14 @@ and ``server-group-members`` output for a given quota class.""" parser = super().get_parser(prog_name) parser.add_argument( 'project', - metavar='', + metavar='', nargs='?', help=_( - 'Show quotas for this project or class (name or ID) ' + 'Show quotas for this project (name or ID) ' '(defaults to current project)' ), ) type_group = parser.add_mutually_exclusive_group() - # TODO(stephenfin): Remove in OSC 8.0 - type_group.add_argument( - '--class', - dest='quota_class', - action='store_true', - default=False, - help=_( - '**Deprecated** Show quotas for . ' - 'Deprecated as quota classes were never fully implemented ' - 'and only the default class is supported. ' - 'Use --default instead which is also supported by the network ' - 'service. ' - '(compute and volume only)' - ), - ) type_group.add_argument( '--default', dest='default', @@ -832,20 +688,8 @@ and ``server-group-members`` output for a given quota class.""" return parser def take_action(self, parsed_args): - project = parsed_args.project - - if parsed_args.quota_class: - msg = _( - "The '--class' option has been deprecated. Quota classes were " - "never fully implemented and the compute and volume services " - "only support a single 'default' quota class while the " - "network service does not support quota classes at all. " - "Please use 'openstack quota show --default' instead." - ) - self.log.warning(msg) - else: - project_info = get_project(self.app, parsed_args.project) - project = project_info['id'] + project_info = get_project(self.app, parsed_args.project) + project = project_info['id'] compute_quota_info = {} volume_quota_info = {} @@ -861,7 +705,6 @@ and ``server-group-members`` output for a given quota class.""" self.app, project, detail=parsed_args.usage, - quota_class=parsed_args.quota_class, default=parsed_args.default, ) if parsed_args.service in {'all', 'volume'}: @@ -869,7 +712,6 @@ and ``server-group-members`` output for a given quota class.""" self.app, project, detail=parsed_args.usage, - quota_class=parsed_args.quota_class, default=parsed_args.default, ) if parsed_args.service in {'all', 'network'}: @@ -877,7 +719,6 @@ and ``server-group-members`` output for a given quota class.""" self.app, project, detail=parsed_args.usage, - quota_class=parsed_args.quota_class, default=parsed_args.default, ) diff --git a/openstackclient/tests/functional/common/test_quota.py b/openstackclient/tests/functional/common/test_quota.py index 0ee27c84e8..e46d237dbe 100644 --- a/openstackclient/tests/functional/common/test_quota.py +++ b/openstackclient/tests/functional/common/test_quota.py @@ -39,40 +39,6 @@ class QuotaTests(base.TestCase): cls.openstack(f'project delete {cls.PROJECT_NAME}') super().tearDownClass() - def test_quota_list_details_compute(self): - expected_headers = ["Resource", "In Use", "Reserved", "Limit"] - cmd_output = self.openstack( - 'quota list --detail --compute', - parse_output=True, - ) - self.assertIsNotNone(cmd_output) - resources = [] - for row in cmd_output: - row_headers = [str(r) for r in row.keys()] - self.assertEqual(sorted(expected_headers), sorted(row_headers)) - resources.append(row['Resource']) - # Ensure that returned quota is compute quota - self.assertIn("instances", resources) - # and that there is no network quota here - self.assertNotIn("networks", resources) - - def test_quota_list_details_network(self): - expected_headers = ["Resource", "In Use", "Reserved", "Limit"] - cmd_output = self.openstack( - 'quota list --detail --network', - parse_output=True, - ) - self.assertIsNotNone(cmd_output) - resources = [] - for row in cmd_output: - row_headers = [str(r) for r in row.keys()] - self.assertEqual(sorted(expected_headers), sorted(row_headers)) - resources.append(row['Resource']) - # Ensure that returned quota is network quota - self.assertIn("networks", resources) - # and that there is no compute quota here - self.assertNotIn("instances", resources) - def test_quota_list_network_option(self): if not self.haz_network: self.skipTest("No Network service present") @@ -155,41 +121,23 @@ class QuotaTests(base.TestCase): if self.haz_network: self.assertTrue(cmd_output["routers"] >= 0) - def test_quota_set_class(self): + def test_quota_set_default(self): self.openstack( - 'quota set --key-pairs 33 --snapshots 43 ' + '--class default' + 'quota set --key-pairs 33 --snapshots 43 --class default' ) cmd_output = self.openstack( - 'quota show --class default', + 'quota show --default', parse_output=True, ) self.assertIsNotNone(cmd_output) cmd_output = {x['Resource']: x['Limit'] for x in cmd_output} - self.assertEqual( - 33, - cmd_output["key-pairs"], - ) - self.assertEqual( - 43, - cmd_output["snapshots"], - ) - - # Check default quota class - cmd_output = self.openstack( - 'quota show --class', - parse_output=True, - ) - self.assertIsNotNone(cmd_output) - # We don't necessarily know the default quotas, we're checking the - # returned attributes - cmd_output = {x['Resource']: x['Limit'] for x in cmd_output} - self.assertTrue(cmd_output["key-pairs"] >= 0) - self.assertTrue(cmd_output["snapshots"] >= 0) + self.assertEqual(33, cmd_output["key-pairs"]) + self.assertEqual(43, cmd_output["snapshots"]) def _restore_quota_limit(self, resource, limit, project): self.openstack(f'quota set --{resource} {limit} {project}') - def test_quota_network_set_with_no_force(self): + def test_quota_set_network_with_no_force(self): if not self.haz_network: self.skipTest('No Network service present') if not self.is_extension_enabled('quota-check-limit'): @@ -227,7 +175,7 @@ class QuotaTests(base.TestCase): 'quota set --networks 1 --no-force ' + self.PROJECT_NAME, ) - def test_quota_network_set_with_force(self): + def test_quota_set_network_with_force(self): self.skipTest('story 2010110') if not self.haz_network: self.skipTest('No Network service present') @@ -274,3 +222,37 @@ class QuotaTests(base.TestCase): ) self.assertIsNotNone(cmd_output) self.assertEqual(1, cmd_output[0]['Networks']) + + def test_quota_show(self): + expected_headers = ["Resource", "Limit"] + cmd_output = self.openstack( + 'quota show', + parse_output=True, + ) + self.assertIsNotNone(cmd_output) + resources = [] + for row in cmd_output: + row_headers = [str(r) for r in row.keys()] + self.assertEqual(sorted(expected_headers), sorted(row_headers)) + resources.append(row['Resource']) + # Ensure that returned quota has network quota... + self.assertIn("networks", resources) + # ...and compute quota + self.assertIn("instances", resources) + + def test_quota_show_usage_option(self): + expected_headers = ["Resource", "Limit", "In Use", "Reserved"] + cmd_output = self.openstack( + 'quota show --usage', + parse_output=True, + ) + self.assertIsNotNone(cmd_output) + resources = [] + for row in cmd_output: + row_headers = [str(r) for r in row.keys()] + self.assertEqual(sorted(expected_headers), sorted(row_headers)) + resources.append(row['Resource']) + # Ensure that returned quota has network quota... + self.assertIn("networks", resources) + # ...and compute quota + self.assertIn("instances", resources) diff --git a/openstackclient/tests/unit/common/test_quota.py b/openstackclient/tests/unit/common/test_quota.py index b07d6e015c..f18e917b2b 100644 --- a/openstackclient/tests/unit/common/test_quota.py +++ b/openstackclient/tests/unit/common/test_quota.py @@ -189,115 +189,6 @@ class TestQuotaList(TestQuota): self.cmd = quota.ListQuota(self.app, None) - @staticmethod - def _get_detailed_reference_data(quota): - reference_data = [] - for name, values in quota.to_dict().items(): - if type(values) is dict: - if 'used' in values: - # For network quota it's "used" key instead of "in_use" - in_use = values['used'] - else: - in_use = values['in_use'] - resource_values = [in_use, values['reserved'], values['limit']] - reference_data.append(tuple([name] + resource_values)) - return reference_data - - def test_quota_list_details_compute(self): - detailed_quota = compute_fakes.create_one_comp_detailed_quota() - - detailed_column_header = ( - 'Resource', - 'In Use', - 'Reserved', - 'Limit', - ) - detailed_reference_data = self._get_detailed_reference_data( - detailed_quota - ) - - self.compute_client.quotas.get = mock.Mock(return_value=detailed_quota) - - arglist = [ - '--detail', - '--compute', - ] - verifylist = [ - ('detail', True), - ('compute', 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_details_network(self): - detailed_quota = ( - network_fakes.FakeQuota.create_one_net_detailed_quota() - ) - - detailed_column_header = ( - 'Resource', - 'In Use', - 'Reserved', - 'Limit', - ) - detailed_reference_data = self._get_detailed_reference_data( - detailed_quota - ) - - self.network_client.get_quota = mock.Mock(return_value=detailed_quota) - - arglist = [ - '--detail', - '--network', - ] - verifylist = [ - ('detail', True), - ('network', 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_details_volume(self): - detailed_quota = volume_fakes.create_one_detailed_quota() - - detailed_column_header = ( - 'Resource', - 'In Use', - 'Reserved', - 'Limit', - ) - detailed_reference_data = self._get_detailed_reference_data( - detailed_quota - ) - - self.volume_client.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_client.quotas.get = mock.Mock( @@ -414,30 +305,6 @@ class TestQuotaList(TestQuota): parsed_args, ) - def test_quota_list_compute_by_project(self): - # Two projects with non-default quotas - self.compute_client.quotas.get = mock.Mock( - side_effect=self.compute_quotas, - ) - - arglist = [ - '--compute', - '--project', - self.projects[0].name, - ] - verifylist = [ - ('compute', True), - ('project', self.projects[0].name), - ] - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - columns, data = self.cmd.take_action(parsed_args) - ret_quotas = list(data) - - self.assertEqual(self.compute_column_header, columns) - self.assertEqual(self.compute_reference_data, ret_quotas[0]) - self.assertEqual(1, len(ret_quotas)) - def test_quota_list_network(self): # Two projects with non-default quotas self.network_client.get_quota = mock.Mock( @@ -507,30 +374,6 @@ class TestQuotaList(TestQuota): self.assertEqual(self.network_reference_data, ret_quotas[0]) self.assertEqual(1, len(ret_quotas)) - def test_quota_list_network_by_project(self): - # Two projects with non-default quotas - self.network_client.get_quota = mock.Mock( - side_effect=self.network_quotas, - ) - - arglist = [ - '--network', - '--project', - self.projects[0].name, - ] - verifylist = [ - ('network', True), - ('project', self.projects[0].name), - ] - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - columns, data = self.cmd.take_action(parsed_args) - ret_quotas = list(data) - - self.assertEqual(self.network_column_header, columns) - self.assertEqual(self.network_reference_data, ret_quotas[0]) - self.assertEqual(1, len(ret_quotas)) - def test_quota_list_volume(self): # Two projects with non-default quotas self.volume_client.quotas.get = mock.Mock( @@ -600,30 +443,6 @@ class TestQuotaList(TestQuota): self.assertEqual(self.volume_reference_data, ret_quotas[0]) self.assertEqual(1, len(ret_quotas)) - def test_quota_list_volume_by_project(self): - # Two projects with non-default quotas - self.volume_client.quotas.get = mock.Mock( - side_effect=self.volume_quotas, - ) - - arglist = [ - '--volume', - '--project', - self.projects[0].name, - ] - verifylist = [ - ('volume', True), - ('project', self.projects[0].name), - ] - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - columns, data = self.cmd.take_action(parsed_args) - ret_quotas = list(data) - - self.assertEqual(self.volume_column_header, columns) - self.assertEqual(self.volume_reference_data, ret_quotas[0]) - self.assertEqual(1, len(ret_quotas)) - class TestQuotaSet(TestQuota): def setUp(self): @@ -1227,25 +1046,6 @@ class TestQuotaShow(TestQuota): ) self.assertNotCalled(self.network_client.get_quota) - def test_quota_show__with_class(self): - arglist = [ - '--class', - 'default', - ] - verifylist = [ - ('quota_class', True), - ('project', 'default'), # project is actually a class here - ] - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - - self.compute_quotas_class_mock.get.assert_called_once_with('default') - self.volume_quotas_class_mock.get.assert_called_once_with('default') - # neutron doesn't have the concept of quota classes - self.assertNotCalled(self.network_client.get_quota) - self.assertNotCalled(self.network_client.get_quota_default) - def test_quota_show__with_usage(self): # update mocks to return detailed quota instead self.compute_quota = compute_fakes.create_one_comp_detailed_quota() diff --git a/releasenotes/notes/remove-deprecated-quota-show-class-option-2109a6ff7ac18e80.yaml b/releasenotes/notes/remove-deprecated-quota-show-class-option-2109a6ff7ac18e80.yaml new file mode 100644 index 0000000000..ab1ce58639 --- /dev/null +++ b/releasenotes/notes/remove-deprecated-quota-show-class-option-2109a6ff7ac18e80.yaml @@ -0,0 +1,8 @@ +--- +upgrade: + - | + The ``--class`` options of the ``quota show`` command, which was deprecated + in 6.1.0 (Antelope), has now been removed in favour of the ``--default`` + option. Quota classes were never fully implemented and the compute and + volume services only support a single ``default`` quota class while the + network service does not support quota classes at all.