Skip to content

Commit ce4cbea

Browse files
committed
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
1 parent ccd9356 commit ce4cbea

2 files changed

Lines changed: 48 additions & 66 deletions

File tree

openstackclient/compute/v2/usage.py

Lines changed: 30 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,10 @@
1515

1616
"""Usage action implementations"""
1717

18-
import collections
1918
import datetime
2019
import functools
2120

2221
from cliff import columns as cliff_columns
23-
from novaclient import api_versions
2422
from osc_lib.command import command
2523
from osc_lib import utils
2624

@@ -58,7 +56,7 @@ def human_readable(self):
5856
class CountColumn(cliff_columns.FormattableColumn):
5957

6058
def human_readable(self):
61-
return len(self._value)
59+
return len(self._value) if self._value is not None else None
6260

6361

6462
class FloatColumn(cliff_columns.FormattableColumn):
@@ -69,7 +67,7 @@ def human_readable(self):
6967

7068
def _formatters(project_cache):
7169
return {
72-
'tenant_id': functools.partial(
70+
'project_id': functools.partial(
7371
ProjectColumn, project_cache=project_cache),
7472
'server_usages': CountColumn,
7573
'total_memory_mb_usage': FloatColumn,
@@ -102,10 +100,10 @@ def _merge_usage(usage, next_usage):
102100

103101
def _merge_usage_list(usages, next_usage_list):
104102
for next_usage in next_usage_list:
105-
if next_usage.tenant_id in usages:
106-
_merge_usage(usages[next_usage.tenant_id], next_usage)
103+
if next_usage.project_id in usages:
104+
_merge_usage(usages[next_usage.project_id], next_usage)
107105
else:
108-
usages[next_usage.tenant_id] = next_usage
106+
usages[next_usage.project_id] = next_usage
109107

110108

111109
class ListUsage(command.Lister):
@@ -138,9 +136,9 @@ def _format_project(project):
138136
else:
139137
return project
140138

141-
compute_client = self.app.client_manager.compute
139+
compute_client = self.app.client_manager.sdk_connection.compute
142140
columns = (
143-
"tenant_id",
141+
"project_id",
144142
"server_usages",
145143
"total_memory_mb_usage",
146144
"total_vcpus_usage",
@@ -154,36 +152,25 @@ def _format_project(project):
154152
"Disk GB-Hours"
155153
)
156154

157-
dateformat = "%Y-%m-%d"
155+
date_cli_format = "%Y-%m-%d"
156+
date_api_format = "%Y-%m-%dT%H:%M:%S"
158157
now = datetime.datetime.utcnow()
159158

160159
if parsed_args.start:
161-
start = datetime.datetime.strptime(parsed_args.start, dateformat)
160+
start = datetime.datetime.strptime(
161+
parsed_args.start, date_cli_format)
162162
else:
163163
start = now - datetime.timedelta(weeks=4)
164164

165165
if parsed_args.end:
166-
end = datetime.datetime.strptime(parsed_args.end, dateformat)
166+
end = datetime.datetime.strptime(parsed_args.end, date_cli_format)
167167
else:
168168
end = now + datetime.timedelta(days=1)
169169

170-
if compute_client.api_version < api_versions.APIVersion("2.40"):
171-
usage_list = compute_client.usage.list(start, end, detailed=True)
172-
else:
173-
# If the number of instances used to calculate the usage is greater
174-
# than CONF.api.max_limit, the usage will be split across multiple
175-
# requests and the responses will need to be merged back together.
176-
usages = collections.OrderedDict()
177-
usage_list = compute_client.usage.list(start, end, detailed=True)
178-
_merge_usage_list(usages, usage_list)
179-
marker = _get_usage_list_marker(usage_list)
180-
while marker:
181-
next_usage_list = compute_client.usage.list(
182-
start, end, detailed=True, marker=marker)
183-
marker = _get_usage_list_marker(next_usage_list)
184-
if marker:
185-
_merge_usage_list(usages, next_usage_list)
186-
usage_list = list(usages.values())
170+
usage_list = list(compute_client.usages(
171+
start=start.strftime(date_api_format),
172+
end=end.strftime(date_api_format),
173+
detailed=True))
187174

188175
# Cache the project list
189176
project_cache = {}
@@ -196,8 +183,8 @@ def _format_project(project):
196183

197184
if parsed_args.formatter == 'table' and len(usage_list) > 0:
198185
self.app.stdout.write(_("Usage from %(start)s to %(end)s: \n") % {
199-
"start": start.strftime(dateformat),
200-
"end": end.strftime(dateformat),
186+
"start": start.strftime(date_cli_format),
187+
"end": end.strftime(date_cli_format),
201188
})
202189

203190
return (
@@ -239,17 +226,19 @@ def get_parser(self, prog_name):
239226

240227
def take_action(self, parsed_args):
241228
identity_client = self.app.client_manager.identity
242-
compute_client = self.app.client_manager.compute
243-
dateformat = "%Y-%m-%d"
229+
compute_client = self.app.client_manager.sdk_connection.compute
230+
date_cli_format = "%Y-%m-%d"
231+
date_api_format = "%Y-%m-%dT%H:%M:%S"
244232
now = datetime.datetime.utcnow()
245233

246234
if parsed_args.start:
247-
start = datetime.datetime.strptime(parsed_args.start, dateformat)
235+
start = datetime.datetime.strptime(
236+
parsed_args.start, date_cli_format)
248237
else:
249238
start = now - datetime.timedelta(weeks=4)
250239

251240
if parsed_args.end:
252-
end = datetime.datetime.strptime(parsed_args.end, dateformat)
241+
end = datetime.datetime.strptime(parsed_args.end, date_cli_format)
253242
else:
254243
end = now + datetime.timedelta(days=1)
255244

@@ -262,19 +251,21 @@ def take_action(self, parsed_args):
262251
# Get the project from the current auth
263252
project = self.app.client_manager.auth_ref.project_id
264253

265-
usage = compute_client.usage.get(project, start, end)
254+
usage = compute_client.get_usage(
255+
project=project, start=start.strftime(date_api_format),
256+
end=end.strftime(date_api_format))
266257

267258
if parsed_args.formatter == 'table':
268259
self.app.stdout.write(_(
269260
"Usage from %(start)s to %(end)s on project %(project)s: \n"
270261
) % {
271-
"start": start.strftime(dateformat),
272-
"end": end.strftime(dateformat),
262+
"start": start.strftime(date_cli_format),
263+
"end": end.strftime(date_cli_format),
273264
"project": project,
274265
})
275266

276267
columns = (
277-
"tenant_id",
268+
"project_id",
278269
"server_usages",
279270
"total_memory_mb_usage",
280271
"total_vcpus_usage",

openstackclient/tests/unit/compute/v2/test_usage.py

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,8 @@
1111
# under the License.
1212
#
1313

14-
import datetime
1514
from unittest import mock
1615

17-
from novaclient import api_versions
18-
1916
from openstackclient.compute.v2 import usage as usage_cmds
2017
from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
2118
from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
@@ -26,8 +23,9 @@ class TestUsage(compute_fakes.TestComputev2):
2623
def setUp(self):
2724
super(TestUsage, self).setUp()
2825

29-
self.usage_mock = self.app.client_manager.compute.usage
30-
self.usage_mock.reset_mock()
26+
self.app.client_manager.sdk_connection = mock.Mock()
27+
self.app.client_manager.sdk_connection.compute = mock.Mock()
28+
self.sdk_client = self.app.client_manager.sdk_connection.compute
3129

3230
self.projects_mock = self.app.client_manager.identity.projects
3331
self.projects_mock.reset_mock()
@@ -38,7 +36,7 @@ class TestUsageList(TestUsage):
3836
project = identity_fakes.FakeProject.create_one_project()
3937
# Return value of self.usage_mock.list().
4038
usages = compute_fakes.FakeUsage.create_usages(
41-
attrs={'tenant_id': project.name}, count=1)
39+
attrs={'project_id': project.name}, count=1)
4240

4341
columns = (
4442
"Project",
@@ -49,7 +47,7 @@ class TestUsageList(TestUsage):
4947
)
5048

5149
data = [(
52-
usage_cmds.ProjectColumn(usages[0].tenant_id),
50+
usage_cmds.ProjectColumn(usages[0].project_id),
5351
usage_cmds.CountColumn(usages[0].server_usages),
5452
usage_cmds.FloatColumn(usages[0].total_memory_mb_usage),
5553
usage_cmds.FloatColumn(usages[0].total_vcpus_usage),
@@ -59,7 +57,7 @@ class TestUsageList(TestUsage):
5957
def setUp(self):
6058
super(TestUsageList, self).setUp()
6159

62-
self.usage_mock.list.return_value = self.usages
60+
self.sdk_client.usages.return_value = self.usages
6361

6462
self.projects_mock.list.return_value = [self.project]
6563
# Get the command object to test
@@ -97,9 +95,9 @@ def test_usage_list_with_options(self):
9795
columns, data = self.cmd.take_action(parsed_args)
9896

9997
self.projects_mock.list.assert_called_with()
100-
self.usage_mock.list.assert_called_with(
101-
datetime.datetime(2016, 11, 11, 0, 0),
102-
datetime.datetime(2016, 12, 20, 0, 0),
98+
self.sdk_client.usages.assert_called_with(
99+
start='2016-11-11T00:00:00',
100+
end='2016-12-20T00:00:00',
103101
detailed=True)
104102

105103
self.assertCountEqual(self.columns, columns)
@@ -112,20 +110,13 @@ def test_usage_list_with_pagination(self):
112110
('end', None),
113111
]
114112

115-
self.app.client_manager.compute.api_version = api_versions.APIVersion(
116-
'2.40')
117-
self.usage_mock.list.reset_mock()
118-
self.usage_mock.list.side_effect = [self.usages, []]
119-
120113
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
121114

122115
columns, data = self.cmd.take_action(parsed_args)
123116

124117
self.projects_mock.list.assert_called_with()
125-
self.usage_mock.list.assert_has_calls([
126-
mock.call(mock.ANY, mock.ANY, detailed=True),
127-
mock.call(mock.ANY, mock.ANY, detailed=True,
128-
marker=self.usages[0]['server_usages'][0]['instance_id'])
118+
self.sdk_client.usages.assert_has_calls([
119+
mock.call(start=mock.ANY, end=mock.ANY, detailed=True)
129120
])
130121
self.assertCountEqual(self.columns, columns)
131122
self.assertCountEqual(tuple(self.data), tuple(data))
@@ -136,7 +127,7 @@ class TestUsageShow(TestUsage):
136127
project = identity_fakes.FakeProject.create_one_project()
137128
# Return value of self.usage_mock.list().
138129
usage = compute_fakes.FakeUsage.create_one_usage(
139-
attrs={'tenant_id': project.name})
130+
attrs={'project_id': project.name})
140131

141132
columns = (
142133
'Project',
@@ -147,7 +138,7 @@ class TestUsageShow(TestUsage):
147138
)
148139

149140
data = (
150-
usage_cmds.ProjectColumn(usage.tenant_id),
141+
usage_cmds.ProjectColumn(usage.project_id),
151142
usage_cmds.CountColumn(usage.server_usages),
152143
usage_cmds.FloatColumn(usage.total_memory_mb_usage),
153144
usage_cmds.FloatColumn(usage.total_vcpus_usage),
@@ -157,7 +148,7 @@ class TestUsageShow(TestUsage):
157148
def setUp(self):
158149
super(TestUsageShow, self).setUp()
159150

160-
self.usage_mock.get.return_value = self.usage
151+
self.sdk_client.get_usage.return_value = self.usage
161152

162153
self.projects_mock.get.return_value = self.project
163154
# Get the command object to test
@@ -199,10 +190,10 @@ def test_usage_show_with_options(self):
199190

200191
columns, data = self.cmd.take_action(parsed_args)
201192

202-
self.usage_mock.get.assert_called_with(
203-
self.project.id,
204-
datetime.datetime(2016, 11, 11, 0, 0),
205-
datetime.datetime(2016, 12, 20, 0, 0))
193+
self.sdk_client.get_usage.assert_called_with(
194+
project=self.project.id,
195+
start='2016-11-11T00:00:00',
196+
end='2016-12-20T00:00:00')
206197

207198
self.assertEqual(self.columns, columns)
208199
self.assertEqual(self.data, data)

0 commit comments

Comments
 (0)