From ce4cbeab67f6dbf87b0f15dabcff43488eca0050 Mon Sep 17 00:00:00 2001 From: Daniel Wilson Date: Tue, 18 Oct 2022 00:30:55 -0400 Subject: [PATCH] Use the compute SDK in usage commands Update usage list and usage show to use the compute component of the OpenStack SDK instead of directly using the nova interface. Change-Id: I1c4d2247c9c1a577ed9efad7e8332e7c9b974ad5 --- openstackclient/compute/v2/usage.py | 69 ++++++++----------- .../tests/unit/compute/v2/test_usage.py | 45 +++++------- 2 files changed, 48 insertions(+), 66 deletions(-) diff --git a/openstackclient/compute/v2/usage.py b/openstackclient/compute/v2/usage.py index 69fa04e8ba..86f538a7d9 100644 --- a/openstackclient/compute/v2/usage.py +++ b/openstackclient/compute/v2/usage.py @@ -15,12 +15,10 @@ """Usage action implementations""" -import collections import datetime import functools from cliff import columns as cliff_columns -from novaclient import api_versions from osc_lib.command import command from osc_lib import utils @@ -58,7 +56,7 @@ class ProjectColumn(cliff_columns.FormattableColumn): class CountColumn(cliff_columns.FormattableColumn): def human_readable(self): - return len(self._value) + return len(self._value) if self._value is not None else None class FloatColumn(cliff_columns.FormattableColumn): @@ -69,7 +67,7 @@ class FloatColumn(cliff_columns.FormattableColumn): def _formatters(project_cache): return { - 'tenant_id': functools.partial( + 'project_id': functools.partial( ProjectColumn, project_cache=project_cache), 'server_usages': CountColumn, 'total_memory_mb_usage': FloatColumn, @@ -102,10 +100,10 @@ def _merge_usage(usage, next_usage): def _merge_usage_list(usages, next_usage_list): for next_usage in next_usage_list: - if next_usage.tenant_id in usages: - _merge_usage(usages[next_usage.tenant_id], next_usage) + if next_usage.project_id in usages: + _merge_usage(usages[next_usage.project_id], next_usage) else: - usages[next_usage.tenant_id] = next_usage + usages[next_usage.project_id] = next_usage class ListUsage(command.Lister): @@ -138,9 +136,9 @@ class ListUsage(command.Lister): else: return project - compute_client = self.app.client_manager.compute + compute_client = self.app.client_manager.sdk_connection.compute columns = ( - "tenant_id", + "project_id", "server_usages", "total_memory_mb_usage", "total_vcpus_usage", @@ -154,36 +152,25 @@ class ListUsage(command.Lister): "Disk GB-Hours" ) - dateformat = "%Y-%m-%d" + date_cli_format = "%Y-%m-%d" + date_api_format = "%Y-%m-%dT%H:%M:%S" now = datetime.datetime.utcnow() if parsed_args.start: - start = datetime.datetime.strptime(parsed_args.start, dateformat) + start = datetime.datetime.strptime( + parsed_args.start, date_cli_format) else: start = now - datetime.timedelta(weeks=4) if parsed_args.end: - end = datetime.datetime.strptime(parsed_args.end, dateformat) + end = datetime.datetime.strptime(parsed_args.end, date_cli_format) else: end = now + datetime.timedelta(days=1) - if compute_client.api_version < api_versions.APIVersion("2.40"): - usage_list = compute_client.usage.list(start, end, detailed=True) - else: - # If the number of instances used to calculate the usage is greater - # than CONF.api.max_limit, the usage will be split across multiple - # requests and the responses will need to be merged back together. - usages = collections.OrderedDict() - usage_list = compute_client.usage.list(start, end, detailed=True) - _merge_usage_list(usages, usage_list) - marker = _get_usage_list_marker(usage_list) - while marker: - next_usage_list = compute_client.usage.list( - start, end, detailed=True, marker=marker) - marker = _get_usage_list_marker(next_usage_list) - if marker: - _merge_usage_list(usages, next_usage_list) - usage_list = list(usages.values()) + usage_list = list(compute_client.usages( + start=start.strftime(date_api_format), + end=end.strftime(date_api_format), + detailed=True)) # Cache the project list project_cache = {} @@ -196,8 +183,8 @@ class ListUsage(command.Lister): if parsed_args.formatter == 'table' and len(usage_list) > 0: self.app.stdout.write(_("Usage from %(start)s to %(end)s: \n") % { - "start": start.strftime(dateformat), - "end": end.strftime(dateformat), + "start": start.strftime(date_cli_format), + "end": end.strftime(date_cli_format), }) return ( @@ -239,17 +226,19 @@ class ShowUsage(command.ShowOne): def take_action(self, parsed_args): identity_client = self.app.client_manager.identity - compute_client = self.app.client_manager.compute - dateformat = "%Y-%m-%d" + compute_client = self.app.client_manager.sdk_connection.compute + date_cli_format = "%Y-%m-%d" + date_api_format = "%Y-%m-%dT%H:%M:%S" now = datetime.datetime.utcnow() if parsed_args.start: - start = datetime.datetime.strptime(parsed_args.start, dateformat) + start = datetime.datetime.strptime( + parsed_args.start, date_cli_format) else: start = now - datetime.timedelta(weeks=4) if parsed_args.end: - end = datetime.datetime.strptime(parsed_args.end, dateformat) + end = datetime.datetime.strptime(parsed_args.end, date_cli_format) else: end = now + datetime.timedelta(days=1) @@ -262,19 +251,21 @@ class ShowUsage(command.ShowOne): # Get the project from the current auth project = self.app.client_manager.auth_ref.project_id - usage = compute_client.usage.get(project, start, end) + usage = compute_client.get_usage( + project=project, start=start.strftime(date_api_format), + end=end.strftime(date_api_format)) if parsed_args.formatter == 'table': self.app.stdout.write(_( "Usage from %(start)s to %(end)s on project %(project)s: \n" ) % { - "start": start.strftime(dateformat), - "end": end.strftime(dateformat), + "start": start.strftime(date_cli_format), + "end": end.strftime(date_cli_format), "project": project, }) columns = ( - "tenant_id", + "project_id", "server_usages", "total_memory_mb_usage", "total_vcpus_usage", diff --git a/openstackclient/tests/unit/compute/v2/test_usage.py b/openstackclient/tests/unit/compute/v2/test_usage.py index bbccb9bdc7..85b45e1b28 100644 --- a/openstackclient/tests/unit/compute/v2/test_usage.py +++ b/openstackclient/tests/unit/compute/v2/test_usage.py @@ -11,11 +11,8 @@ # under the License. # -import datetime from unittest import mock -from novaclient import api_versions - from openstackclient.compute.v2 import usage as usage_cmds from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes @@ -26,8 +23,9 @@ class TestUsage(compute_fakes.TestComputev2): def setUp(self): super(TestUsage, self).setUp() - self.usage_mock = self.app.client_manager.compute.usage - self.usage_mock.reset_mock() + self.app.client_manager.sdk_connection = mock.Mock() + self.app.client_manager.sdk_connection.compute = mock.Mock() + self.sdk_client = self.app.client_manager.sdk_connection.compute self.projects_mock = self.app.client_manager.identity.projects self.projects_mock.reset_mock() @@ -38,7 +36,7 @@ class TestUsageList(TestUsage): project = identity_fakes.FakeProject.create_one_project() # Return value of self.usage_mock.list(). usages = compute_fakes.FakeUsage.create_usages( - attrs={'tenant_id': project.name}, count=1) + attrs={'project_id': project.name}, count=1) columns = ( "Project", @@ -49,7 +47,7 @@ class TestUsageList(TestUsage): ) data = [( - usage_cmds.ProjectColumn(usages[0].tenant_id), + usage_cmds.ProjectColumn(usages[0].project_id), usage_cmds.CountColumn(usages[0].server_usages), usage_cmds.FloatColumn(usages[0].total_memory_mb_usage), usage_cmds.FloatColumn(usages[0].total_vcpus_usage), @@ -59,7 +57,7 @@ class TestUsageList(TestUsage): def setUp(self): super(TestUsageList, self).setUp() - self.usage_mock.list.return_value = self.usages + self.sdk_client.usages.return_value = self.usages self.projects_mock.list.return_value = [self.project] # Get the command object to test @@ -97,9 +95,9 @@ class TestUsageList(TestUsage): columns, data = self.cmd.take_action(parsed_args) self.projects_mock.list.assert_called_with() - self.usage_mock.list.assert_called_with( - datetime.datetime(2016, 11, 11, 0, 0), - datetime.datetime(2016, 12, 20, 0, 0), + self.sdk_client.usages.assert_called_with( + start='2016-11-11T00:00:00', + end='2016-12-20T00:00:00', detailed=True) self.assertCountEqual(self.columns, columns) @@ -112,20 +110,13 @@ class TestUsageList(TestUsage): ('end', None), ] - self.app.client_manager.compute.api_version = api_versions.APIVersion( - '2.40') - self.usage_mock.list.reset_mock() - self.usage_mock.list.side_effect = [self.usages, []] - parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) self.projects_mock.list.assert_called_with() - self.usage_mock.list.assert_has_calls([ - mock.call(mock.ANY, mock.ANY, detailed=True), - mock.call(mock.ANY, mock.ANY, detailed=True, - marker=self.usages[0]['server_usages'][0]['instance_id']) + self.sdk_client.usages.assert_has_calls([ + mock.call(start=mock.ANY, end=mock.ANY, detailed=True) ]) self.assertCountEqual(self.columns, columns) self.assertCountEqual(tuple(self.data), tuple(data)) @@ -136,7 +127,7 @@ class TestUsageShow(TestUsage): project = identity_fakes.FakeProject.create_one_project() # Return value of self.usage_mock.list(). usage = compute_fakes.FakeUsage.create_one_usage( - attrs={'tenant_id': project.name}) + attrs={'project_id': project.name}) columns = ( 'Project', @@ -147,7 +138,7 @@ class TestUsageShow(TestUsage): ) data = ( - usage_cmds.ProjectColumn(usage.tenant_id), + usage_cmds.ProjectColumn(usage.project_id), usage_cmds.CountColumn(usage.server_usages), usage_cmds.FloatColumn(usage.total_memory_mb_usage), usage_cmds.FloatColumn(usage.total_vcpus_usage), @@ -157,7 +148,7 @@ class TestUsageShow(TestUsage): def setUp(self): super(TestUsageShow, self).setUp() - self.usage_mock.get.return_value = self.usage + self.sdk_client.get_usage.return_value = self.usage self.projects_mock.get.return_value = self.project # Get the command object to test @@ -199,10 +190,10 @@ class TestUsageShow(TestUsage): columns, data = self.cmd.take_action(parsed_args) - self.usage_mock.get.assert_called_with( - self.project.id, - datetime.datetime(2016, 11, 11, 0, 0), - datetime.datetime(2016, 12, 20, 0, 0)) + self.sdk_client.get_usage.assert_called_with( + project=self.project.id, + start='2016-11-11T00:00:00', + end='2016-12-20T00:00:00') self.assertEqual(self.columns, columns) self.assertEqual(self.data, data)