Add json and yaml formatting to manila-manage
Add the possibility to specify how the data will be displayed while issuing the manila-manage command. This can be helpful to automations, Change-Id: I0af426254be886e31553275feb23b9ec90ec2cc8
This commit is contained in:
parent
4bf505404a
commit
861a67193b
@ -55,9 +55,11 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
import yaml
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from manila.common import config # Need to register global_opts # noqa
|
||||
from manila import context
|
||||
@ -69,6 +71,7 @@ from manila import version
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
ALLOWED_OUTPUT_FORMATS = ['table', 'json', 'yaml']
|
||||
HOST_UPDATE_HELP_MSG = ("A fully qualified host string is of the format "
|
||||
"'HostA@BackendB#PoolC'. Provide only the host name "
|
||||
"(ex: 'HostA') to update the hostname part of "
|
||||
@ -78,6 +81,8 @@ HOST_UPDATE_HELP_MSG = ("A fully qualified host string is of the format "
|
||||
HOST_UPDATE_CURRENT_HOST_HELP = ("Current share host name. %s" %
|
||||
HOST_UPDATE_HELP_MSG)
|
||||
HOST_UPDATE_NEW_HOST_HELP = "New share host name. %s" % HOST_UPDATE_HELP_MSG
|
||||
LIST_OUTPUT_FORMAT_HELP = ("Format to be used to print the output (table, "
|
||||
"json, yaml). Defaults to 'table'")
|
||||
SHARE_SERVERS_UPDATE_HELP = ("List of share servers to be updated, separated "
|
||||
"by commas.")
|
||||
SHARE_SERVERS_UPDATE_CAPABILITIES_HELP = (
|
||||
@ -93,6 +98,37 @@ def args(*args, **kwargs):
|
||||
return _decorator
|
||||
|
||||
|
||||
class ListCommand(object):
|
||||
|
||||
def list_json(self, resource_name, resource_list):
|
||||
resource_list = {resource_name: resource_list}
|
||||
object_list = jsonutils.dumps(resource_list, indent=4)
|
||||
print(object_list)
|
||||
|
||||
def list_yaml(self, resource_name, resource_list):
|
||||
resource_list = {resource_name: resource_list}
|
||||
data_yaml = yaml.dump(resource_list)
|
||||
print(data_yaml)
|
||||
|
||||
def list_table(self, resource_name, resource_list):
|
||||
print_format = "{0:<16} {1:<36} {2:<16} {3:<10} {4:<5} {5:<10}"
|
||||
print(print_format.format(
|
||||
*[k.capitalize().replace(
|
||||
'_', ' ') for k in resource_list[0].keys()]))
|
||||
for resource in resource_list:
|
||||
# Print is not transforming into a string, so let's ensure it
|
||||
# happens
|
||||
resource['updated_at'] = str(resource['updated_at'])
|
||||
print(print_format.format(*resource.values()))
|
||||
|
||||
def _check_format_output(self, format_output):
|
||||
if format_output not in ALLOWED_OUTPUT_FORMATS:
|
||||
print('Invalid output format specified. Defaulting to table.')
|
||||
return 'table'
|
||||
else:
|
||||
return format_output
|
||||
|
||||
|
||||
class ShellCommands(object):
|
||||
def bpython(self):
|
||||
"""Runs a bpython shell.
|
||||
@ -319,35 +355,35 @@ class GetLogCommands(object):
|
||||
print("No manila entries in syslog!")
|
||||
|
||||
|
||||
class ServiceCommands(object):
|
||||
class ServiceCommands(ListCommand):
|
||||
"""Methods for managing services."""
|
||||
def list(self):
|
||||
|
||||
@args('--format_output', required=False, default='table',
|
||||
help=LIST_OUTPUT_FORMAT_HELP)
|
||||
def list(self, format_output):
|
||||
"""Show a list of all manila services."""
|
||||
ctxt = context.get_admin_context()
|
||||
services = db.service_get_all(ctxt)
|
||||
print_format = "%-16s %-36s %-16s %-10s %-5s %-10s"
|
||||
print(print_format % (
|
||||
_('Binary'),
|
||||
_('Host'),
|
||||
_('Zone'),
|
||||
_('Status'),
|
||||
_('State'),
|
||||
_('Updated At'))
|
||||
)
|
||||
for svc in services:
|
||||
alive = utils.service_is_up(svc)
|
||||
art = ":-)" if alive else "XXX"
|
||||
format_output = self._check_format_output(format_output)
|
||||
|
||||
services_list = []
|
||||
for service in services:
|
||||
alive = utils.service_is_up(service)
|
||||
state = ":-)" if alive else "XXX"
|
||||
status = 'enabled'
|
||||
if svc['disabled']:
|
||||
if service['disabled']:
|
||||
status = 'disabled'
|
||||
print(print_format % (
|
||||
svc['binary'],
|
||||
svc['host'].partition('.')[0],
|
||||
svc['availability_zone']['name'],
|
||||
status,
|
||||
art,
|
||||
svc['updated_at'],
|
||||
))
|
||||
services_list.append({
|
||||
'binary': service['binary'],
|
||||
'host': service['host'].partition('.')[0],
|
||||
'zone': service['availability_zone']['name'],
|
||||
'status': status,
|
||||
'state': state,
|
||||
'updated_at': str(service['updated_at']),
|
||||
})
|
||||
|
||||
method_list_name = f'list_{format_output}'
|
||||
getattr(self, method_list_name)('services', services_list)
|
||||
|
||||
def cleanup(self):
|
||||
"""Remove manila services reporting as 'down'."""
|
||||
|
@ -18,9 +18,11 @@ import io
|
||||
import readline
|
||||
import sys
|
||||
from unittest import mock
|
||||
import yaml
|
||||
|
||||
import ddt
|
||||
from oslo_config import cfg
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from manila.cmd import manage as manila_manage
|
||||
from manila import context
|
||||
@ -48,6 +50,7 @@ class ManilaCmdManageTestCase(test.TestCase):
|
||||
self.service_cmds = manila_manage.ServiceCommands()
|
||||
self.share_cmds = manila_manage.ShareCommands()
|
||||
self.server_cmds = manila_manage.ShareServerCommands()
|
||||
self.list_commands = manila_manage.ListCommand()
|
||||
|
||||
@mock.patch.object(manila_manage.ShellCommands, 'run', mock.Mock())
|
||||
def test_shell_commands_bpython(self):
|
||||
@ -291,7 +294,7 @@ class ManilaCmdManageTestCase(test.TestCase):
|
||||
'Zone',
|
||||
'Status',
|
||||
'State',
|
||||
'Updated At')
|
||||
'Updated at')
|
||||
service_format = format % (service['binary'],
|
||||
service['host'].partition('.')[0],
|
||||
service['availability_zone']['name'],
|
||||
@ -299,12 +302,47 @@ class ManilaCmdManageTestCase(test.TestCase):
|
||||
':-)',
|
||||
service['updated_at'])
|
||||
expected_out = print_format + '\n' + service_format + '\n'
|
||||
self.service_cmds.list()
|
||||
self.service_cmds.list(format_output='table')
|
||||
self.assertEqual(expected_out, fake_out.getvalue())
|
||||
get_admin_context.assert_called_with()
|
||||
service_get_all.assert_called_with(ctxt)
|
||||
service_is_up.assert_called_with(service)
|
||||
|
||||
@ddt.data('json', 'yaml')
|
||||
def test_service_commands_list_format(self, format_output):
|
||||
ctxt = context.RequestContext('fake-user', 'fake-project')
|
||||
format_method_name = f'list_{format_output}'
|
||||
mock_list_method = self.mock_object(
|
||||
self.service_cmds, format_method_name)
|
||||
get_admin_context = self.mock_object(context, 'get_admin_context')
|
||||
service_get_all = self.mock_object(db, 'service_get_all')
|
||||
service_is_up = self.mock_object(utils, 'service_is_up')
|
||||
get_admin_context.return_value = ctxt
|
||||
service = {'binary': 'manila-binary',
|
||||
'host': 'fake-host.fake-domain',
|
||||
'availability_zone': {'name': 'fake-zone'},
|
||||
'updated_at': '2014-06-30 11:22:33',
|
||||
'disabled': False}
|
||||
services = [service]
|
||||
service_get_all.return_value = services
|
||||
service_is_up.return_value = True
|
||||
|
||||
with mock.patch('sys.stdout', new=io.StringIO()):
|
||||
self.service_cmds.list(format_output=format_output)
|
||||
get_admin_context.assert_called_with()
|
||||
service_get_all.assert_called_with(ctxt)
|
||||
service_is_up.assert_called_with(service)
|
||||
service_format = {
|
||||
'binary': service['binary'],
|
||||
'host': service['host'].partition('.')[0],
|
||||
'zone': service['availability_zone']['name'],
|
||||
'status': 'enabled',
|
||||
'state': ':-)',
|
||||
'updated_at': service['updated_at'],
|
||||
}
|
||||
mock_list_method.assert_called_once_with(
|
||||
'services', [service_format])
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_service_commands_cleanup(self, service_is_up):
|
||||
ctxt = context.RequestContext('fake-user', 'fake-project')
|
||||
@ -508,3 +546,47 @@ class ManilaCmdManageTestCase(test.TestCase):
|
||||
True)
|
||||
|
||||
self.assertEqual(1, exit.code)
|
||||
|
||||
@mock.patch('builtins.print')
|
||||
def test_list_commands_json(self, mock_print):
|
||||
resource_name = 'service'
|
||||
service_format = [{
|
||||
'binary': 'manila-binary',
|
||||
'host': 'fake-host',
|
||||
'availability_zone': 'fakeaz',
|
||||
'status': 'enabled',
|
||||
'state': ':-)',
|
||||
'updated_at': '13 04:57:49 PM -03 2023'
|
||||
}]
|
||||
|
||||
mock_json_dumps = self.mock_object(
|
||||
jsonutils, 'dumps', mock.Mock(return_value=service_format[0]))
|
||||
services = {resource_name: service_format}
|
||||
|
||||
self.list_commands.list_json('service', service_format)
|
||||
|
||||
mock_json_dumps.assert_called_once_with(
|
||||
services, indent=4)
|
||||
mock_print.assert_called_once_with(service_format[0])
|
||||
|
||||
@mock.patch('builtins.print')
|
||||
def test_list_commands_yaml(self, mock_print):
|
||||
resource_name = 'service'
|
||||
service_format = [{
|
||||
'binary': 'manila-binary',
|
||||
'host': 'fake-host',
|
||||
'availability_zone': 'fakeaz',
|
||||
'status': 'enabled',
|
||||
'state': ':-)',
|
||||
'updated_at': '13 04:57:49 PM -03 2023'
|
||||
}]
|
||||
|
||||
mock_yaml_dump = self.mock_object(
|
||||
yaml, 'dump', mock.Mock(return_value=service_format[0]))
|
||||
services = {resource_name: service_format}
|
||||
|
||||
self.list_commands.list_yaml('service', service_format)
|
||||
|
||||
mock_yaml_dump.assert_called_once_with(
|
||||
services)
|
||||
mock_print.assert_called_once_with(service_format[0])
|
||||
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
The possibility to specify the desired output format while issuing the
|
||||
`manila-manage service list` command was added. It is now possible to
|
||||
display the output also in yaml and json formats.
|
Loading…
Reference in New Issue
Block a user