compute: Add 'server show --topology' option

Add support for compute microversion 2.78 by adding a '--topology'
option to 'openstack server show' command that retrieves server NUMA
information.

Change-Id: Ie22979df2ea9082ca64a4d43b571bd4025684825
This commit is contained in:
Yongli He 2019-09-09 13:56:30 +08:00 committed by Stephen Finucane
parent a5c6470f2d
commit f200799848
4 changed files with 92 additions and 9 deletions
doc/source/cli/data
openstackclient
compute/v2
tests/unit/compute/v2
releasenotes/notes

@ -121,6 +121,7 @@ start,server start,Start the server(s).
stop,server stop,Stop the server(s). stop,server stop,Stop the server(s).
suspend,server suspend,Suspend a server. suspend,server suspend,Suspend a server.
trigger-crash-dump,server dump create,Trigger crash dump in an instance. trigger-crash-dump,server dump create,Trigger crash dump in an instance.
topology,openstack server show --topology,Retrieve server NUMA topology.
unlock,server unlock,Unlock a server. unlock,server unlock,Unlock a server.
unpause,server unpause,Unpause a server. unpause,server unpause,Unpause a server.
unrescue,server unrescue,Restart the server from normal boot disk again. unrescue,server unrescue,Restart the server from normal boot disk again.

1 add-fixed-ip server add fixed ip Add new IP address on a network to server.
121 stop server stop Stop the server(s).
122 suspend server suspend Suspend a server.
123 trigger-crash-dump server dump create Trigger crash dump in an instance.
124 topology openstack server show --topology Retrieve server NUMA topology.
125 unlock server unlock Unlock a server.
126 unpause server unpause Unpause a server.
127 unrescue server unrescue Restart the server from normal boot disk again.

@ -3383,7 +3383,8 @@ class ShelveServer(command.Command):
class ShowServer(command.ShowOne): class ShowServer(command.ShowOne):
_description = _( _description = _(
"Show server details. Specify ``--os-compute-api-version 2.47`` " "Show server details. Specify ``--os-compute-api-version 2.47`` "
"or higher to see the embedded flavor information for the server.") "or higher to see the embedded flavor information for the server."
)
def get_parser(self, prog_name): def get_parser(self, prog_name):
parser = super(ShowServer, self).get_parser(prog_name) parser = super(ShowServer, self).get_parser(prog_name)
@ -3392,18 +3393,29 @@ class ShowServer(command.ShowOne):
metavar='<server>', metavar='<server>',
help=_('Server (name or ID)'), help=_('Server (name or ID)'),
) )
parser.add_argument( # TODO(stephenfin): This should be a separate command, not a flag
diagnostics_group = parser.add_mutually_exclusive_group()
diagnostics_group.add_argument(
'--diagnostics', '--diagnostics',
action='store_true', action='store_true',
default=False, default=False,
help=_('Display server diagnostics information'), help=_('Display server diagnostics information'),
) )
diagnostics_group.add_argument(
'--topology',
action='store_true',
default=False,
help=_(
'Include topology information in the output '
'(supported by --os-compute-api-version 2.78 or above)'
),
)
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
compute_client = self.app.client_manager.compute compute_client = self.app.client_manager.compute
server = utils.find_resource(compute_client.servers, server = utils.find_resource(
parsed_args.server) compute_client.servers, parsed_args.server)
if parsed_args.diagnostics: if parsed_args.diagnostics:
(resp, data) = server.diagnostics() (resp, data) = server.diagnostics()
@ -3412,10 +3424,26 @@ class ShowServer(command.ShowOne):
"Error retrieving diagnostics data\n" "Error retrieving diagnostics data\n"
)) ))
return ({}, {}) return ({}, {})
else: return zip(*sorted(data.items()))
data = _prep_server_detail(compute_client,
self.app.client_manager.image, server, topology = None
refresh=False) if parsed_args.topology:
if compute_client.api_version < api_versions.APIVersion('2.78'):
msg = _(
'--os-compute-api-version 2.78 or greater is required to '
'support the --topology option'
)
raise exceptions.CommandError(msg)
topology = server.topology()
data = _prep_server_detail(
compute_client, self.app.client_manager.image, server,
refresh=False)
if topology:
data['topology'] = format_columns.DictColumn(topology)
return zip(*sorted(data.items())) return zip(*sorted(data.items()))
@ -3731,7 +3759,7 @@ class UnsetServer(command.Command):
help=_( help=_(
'Tag to remove from the server. ' 'Tag to remove from the server. '
'Specify multiple times to remove multiple tags. ' 'Specify multiple times to remove multiple tags. '
'(supported by --os-compute-api-version 2.26 or later' '(supported by --os-compute-api-version 2.26 or above)'
), ),
) )
return parser return parser

@ -6285,6 +6285,10 @@ class TestServerShow(TestServer):
self.image = image_fakes.FakeImage.create_one_image() self.image = image_fakes.FakeImage.create_one_image()
self.flavor = compute_fakes.FakeFlavor.create_one_flavor() self.flavor = compute_fakes.FakeFlavor.create_one_flavor()
self.topology = {
'nodes': [{'vcpu_set': [0, 1]}, {'vcpu_set': [2, 3]}],
'pagesize_kb': None,
}
server_info = { server_info = {
'image': {'id': self.image.id}, 'image': {'id': self.image.id},
'flavor': {'id': self.flavor.id}, 'flavor': {'id': self.flavor.id},
@ -6298,6 +6302,7 @@ class TestServerShow(TestServer):
resp.status_code = 200 resp.status_code = 200
server_method = { server_method = {
'diagnostics': (resp, {'test': 'test'}), 'diagnostics': (resp, {'test': 'test'}),
'topology': self.topology,
} }
self.server = compute_fakes.FakeServer.create_one_server( self.server = compute_fakes.FakeServer.create_one_server(
attrs=server_info, methods=server_method) attrs=server_info, methods=server_method)
@ -6348,6 +6353,7 @@ class TestServerShow(TestServer):
] ]
verifylist = [ verifylist = [
('diagnostics', False), ('diagnostics', False),
('topology', False),
('server', self.server.name), ('server', self.server.name),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@ -6365,6 +6371,7 @@ class TestServerShow(TestServer):
] ]
verifylist = [ verifylist = [
('diagnostics', False), ('diagnostics', False),
('topology', False),
('server', self.server.name), ('server', self.server.name),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@ -6391,6 +6398,7 @@ class TestServerShow(TestServer):
] ]
verifylist = [ verifylist = [
('diagnostics', True), ('diagnostics', True),
('topology', False),
('server', self.server.name), ('server', self.server.name),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@ -6400,6 +6408,47 @@ class TestServerShow(TestServer):
self.assertEqual(('test',), columns) self.assertEqual(('test',), columns)
self.assertEqual(('test',), data) self.assertEqual(('test',), data)
def test_show_topology(self):
self.app.client_manager.compute.api_version = \
api_versions.APIVersion('2.78')
arglist = [
'--topology',
self.server.name,
]
verifylist = [
('diagnostics', False),
('topology', True),
('server', self.server.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.columns += ('topology',)
self.data += (format_columns.DictColumn(self.topology),)
columns, data = self.cmd.take_action(parsed_args)
self.assertCountEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
def test_show_topology_pre_v278(self):
self.app.client_manager.compute.api_version = \
api_versions.APIVersion('2.77')
arglist = [
'--topology',
self.server.name,
]
verifylist = [
('diagnostics', False),
('topology', True),
('server', self.server.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(
exceptions.CommandError, self.cmd.take_action, parsed_args)
class TestServerStart(TestServer): class TestServerStart(TestServer):

@ -0,0 +1,5 @@
---
features:
- |
Add support for ``openstack server show --topology`` flag, which will
include NUMA topology information in the output.