compute: Fix 'usage * -f yaml' output
Make use of 'FormattableColumn'-derived formatters, which provide better output than what we were using before, particularly for the YAML output format. Change-Id: Ic770f27cb1f74222636f05350f97400808adffbf Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
This commit is contained in:
parent
03776d82e5
commit
af5e9d16e8
@ -17,7 +17,9 @@
|
||||
|
||||
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
|
||||
@ -25,6 +27,57 @@ from osc_lib import utils
|
||||
from openstackclient.i18n import _
|
||||
|
||||
|
||||
# TODO(stephenfin): This exists in a couple of places and should be moved to a
|
||||
# common module
|
||||
class ProjectColumn(cliff_columns.FormattableColumn):
|
||||
"""Formattable column for project column.
|
||||
|
||||
Unlike the parent FormattableColumn class, the initializer of the class
|
||||
takes project_cache as the second argument.
|
||||
``osc_lib.utils.get_item_properties`` instantiates ``FormattableColumn``
|
||||
objects with a single parameter, the column value, so you need to pass a
|
||||
partially initialized class like ``functools.partial(ProjectColumn,
|
||||
project_cache)`` to use this.
|
||||
"""
|
||||
|
||||
def __init__(self, value, project_cache=None):
|
||||
super().__init__(value)
|
||||
self.project_cache = project_cache or {}
|
||||
|
||||
def human_readable(self):
|
||||
project = self._value
|
||||
if not project:
|
||||
return ''
|
||||
|
||||
if project in self.project_cache.keys():
|
||||
return self.project_cache[project].name
|
||||
|
||||
return project
|
||||
|
||||
|
||||
class CountColumn(cliff_columns.FormattableColumn):
|
||||
|
||||
def human_readable(self):
|
||||
return len(self._value)
|
||||
|
||||
|
||||
class FloatColumn(cliff_columns.FormattableColumn):
|
||||
|
||||
def human_readable(self):
|
||||
return float("%.2f" % self._value)
|
||||
|
||||
|
||||
def _formatters(project_cache):
|
||||
return {
|
||||
'tenant_id': functools.partial(
|
||||
ProjectColumn, project_cache=project_cache),
|
||||
'server_usages': CountColumn,
|
||||
'total_memory_mb_usage': FloatColumn,
|
||||
'total_vcpus_usage': FloatColumn,
|
||||
'total_local_gb_usage': FloatColumn,
|
||||
}
|
||||
|
||||
|
||||
def _get_usage_marker(usage):
|
||||
marker = None
|
||||
if hasattr(usage, 'server_usages') and usage.server_usages:
|
||||
@ -147,17 +200,15 @@ class ListUsage(command.Lister):
|
||||
"end": end.strftime(dateformat),
|
||||
})
|
||||
|
||||
return (column_headers,
|
||||
(utils.get_item_properties(
|
||||
return (
|
||||
column_headers,
|
||||
(
|
||||
utils.get_item_properties(
|
||||
s, columns,
|
||||
formatters={
|
||||
'tenant_id': _format_project,
|
||||
'server_usages': lambda x: len(x),
|
||||
'total_memory_mb_usage': lambda x: float("%.2f" % x),
|
||||
'total_vcpus_usage': lambda x: float("%.2f" % x),
|
||||
'total_local_gb_usage': lambda x: float("%.2f" % x),
|
||||
},
|
||||
) for s in usage_list))
|
||||
formatters=_formatters(project_cache),
|
||||
) for s in usage_list
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class ShowUsage(command.ShowOne):
|
||||
@ -222,17 +273,21 @@ class ShowUsage(command.ShowOne):
|
||||
"project": project,
|
||||
})
|
||||
|
||||
info = {}
|
||||
info['Servers'] = (
|
||||
len(usage.server_usages)
|
||||
if hasattr(usage, "server_usages") else None)
|
||||
info['RAM MB-Hours'] = (
|
||||
float("%.2f" % usage.total_memory_mb_usage)
|
||||
if hasattr(usage, "total_memory_mb_usage") else None)
|
||||
info['CPU Hours'] = (
|
||||
float("%.2f" % usage.total_vcpus_usage)
|
||||
if hasattr(usage, "total_vcpus_usage") else None)
|
||||
info['Disk GB-Hours'] = (
|
||||
float("%.2f" % usage.total_local_gb_usage)
|
||||
if hasattr(usage, "total_local_gb_usage") else None)
|
||||
return zip(*sorted(info.items()))
|
||||
columns = (
|
||||
"tenant_id",
|
||||
"server_usages",
|
||||
"total_memory_mb_usage",
|
||||
"total_vcpus_usage",
|
||||
"total_local_gb_usage"
|
||||
)
|
||||
column_headers = (
|
||||
"Project",
|
||||
"Servers",
|
||||
"RAM MB-Hours",
|
||||
"CPU Hours",
|
||||
"Disk GB-Hours"
|
||||
)
|
||||
|
||||
data = utils.get_item_properties(
|
||||
usage, columns, formatters=_formatters(None))
|
||||
return column_headers, data
|
||||
|
@ -16,7 +16,7 @@ from unittest import mock
|
||||
|
||||
from novaclient import api_versions
|
||||
|
||||
from openstackclient.compute.v2 import usage
|
||||
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
|
||||
|
||||
@ -49,11 +49,11 @@ class TestUsageList(TestUsage):
|
||||
)
|
||||
|
||||
data = [(
|
||||
usages[0].tenant_id,
|
||||
len(usages[0].server_usages),
|
||||
float("%.2f" % usages[0].total_memory_mb_usage),
|
||||
float("%.2f" % usages[0].total_vcpus_usage),
|
||||
float("%.2f" % usages[0].total_local_gb_usage),
|
||||
usage_cmds.ProjectColumn(usages[0].tenant_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),
|
||||
usage_cmds.FloatColumn(usages[0].total_local_gb_usage),
|
||||
)]
|
||||
|
||||
def setUp(self):
|
||||
@ -63,7 +63,7 @@ class TestUsageList(TestUsage):
|
||||
|
||||
self.projects_mock.list.return_value = [self.project]
|
||||
# Get the command object to test
|
||||
self.cmd = usage.ListUsage(self.app, None)
|
||||
self.cmd = usage_cmds.ListUsage(self.app, None)
|
||||
|
||||
def test_usage_list_no_options(self):
|
||||
|
||||
@ -79,8 +79,8 @@ class TestUsageList(TestUsage):
|
||||
|
||||
self.projects_mock.list.assert_called_with()
|
||||
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertEqual(tuple(self.data), tuple(data))
|
||||
self.assertCountEqual(self.columns, columns)
|
||||
self.assertCountEqual(tuple(self.data), tuple(data))
|
||||
|
||||
def test_usage_list_with_options(self):
|
||||
arglist = [
|
||||
@ -102,8 +102,8 @@ class TestUsageList(TestUsage):
|
||||
datetime.datetime(2016, 12, 20, 0, 0),
|
||||
detailed=True)
|
||||
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertEqual(tuple(self.data), tuple(data))
|
||||
self.assertCountEqual(self.columns, columns)
|
||||
self.assertCountEqual(tuple(self.data), tuple(data))
|
||||
|
||||
def test_usage_list_with_pagination(self):
|
||||
arglist = []
|
||||
@ -127,8 +127,8 @@ class TestUsageList(TestUsage):
|
||||
mock.call(mock.ANY, mock.ANY, detailed=True,
|
||||
marker=self.usages[0]['server_usages'][0]['instance_id'])
|
||||
])
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertEqual(tuple(self.data), tuple(data))
|
||||
self.assertCountEqual(self.columns, columns)
|
||||
self.assertCountEqual(tuple(self.data), tuple(data))
|
||||
|
||||
|
||||
class TestUsageShow(TestUsage):
|
||||
@ -139,17 +139,19 @@ class TestUsageShow(TestUsage):
|
||||
attrs={'tenant_id': project.name})
|
||||
|
||||
columns = (
|
||||
'Project',
|
||||
'Servers',
|
||||
'RAM MB-Hours',
|
||||
'CPU Hours',
|
||||
'Disk GB-Hours',
|
||||
'RAM MB-Hours',
|
||||
'Servers',
|
||||
)
|
||||
|
||||
data = (
|
||||
float("%.2f" % usage.total_vcpus_usage),
|
||||
float("%.2f" % usage.total_local_gb_usage),
|
||||
float("%.2f" % usage.total_memory_mb_usage),
|
||||
len(usage.server_usages),
|
||||
usage_cmds.ProjectColumn(usage.tenant_id),
|
||||
usage_cmds.CountColumn(usage.server_usages),
|
||||
usage_cmds.FloatColumn(usage.total_memory_mb_usage),
|
||||
usage_cmds.FloatColumn(usage.total_vcpus_usage),
|
||||
usage_cmds.FloatColumn(usage.total_local_gb_usage),
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
@ -159,7 +161,7 @@ class TestUsageShow(TestUsage):
|
||||
|
||||
self.projects_mock.get.return_value = self.project
|
||||
# Get the command object to test
|
||||
self.cmd = usage.ShowUsage(self.app, None)
|
||||
self.cmd = usage_cmds.ShowUsage(self.app, None)
|
||||
|
||||
def test_usage_show_no_options(self):
|
||||
|
||||
|
@ -8,3 +8,9 @@ fixes:
|
||||
will now be rendered as objects. In addition, the ``power_state`` field
|
||||
will now be humanized and rendered as a string value when using the table
|
||||
formatter.
|
||||
- |
|
||||
The ``usage list`` and ``usage show`` commands will now display the name
|
||||
of the project being queried rather than the ID when using the table
|
||||
formatter. In addition, the ``server_usages``, ``total_memory_mb_usage``,
|
||||
``total_vcpus_usage`` and ``total_local_gb_usage`` values will only be
|
||||
humanized when using the table formatter.
|
||||
|
Loading…
Reference in New Issue
Block a user