Fix microversion 2.100

This change fixes missing conditional logic for microversion
2.100 which adds support for showing `scheduler_hints` field
to `openstack server list --long` output.

Change-Id: I2820e02a91deb73850f37dc737dbec79dea99e8d
Signed-off-by: Rajesh Tailor <ratailor@redhat.com>
(cherry picked from commit e7554603ac)
This commit is contained in:
Rajesh Tailor
2025-08-29 12:15:39 +05:30
parent f2c9fbf622
commit 78ef2f5922
2 changed files with 173 additions and 16 deletions

View File

@@ -184,8 +184,13 @@ def _prep_server_detail(compute_client, image_client, server, *, refresh=True):
'user_data': 'OS-EXT-SRV-ATTR:user_data',
'vm_state': 'OS-EXT-STS:vm_state',
'pinned_availability_zone': 'pinned_availability_zone',
'scheduler_hints': 'scheduler_hints',
}
# NOTE(ratailor): microversion 2.100 introduces
# scheduler_hints support
if sdk_utils.supports_microversion(compute_client, '2.100'):
column_map['scheduler_hints'] = 'scheduler_hints'
# Some columns returned by openstacksdk should not be shown because they're
# either irrelevant or duplicates
ignored_columns = {
@@ -326,6 +331,7 @@ def _prep_server_detail(compute_client, image_client, server, *, refresh=True):
info['OS-EXT-STS:power_state']
)
if sdk_utils.supports_microversion(compute_client, '2.100'):
if 'scheduler_hints' in info:
info['scheduler_hints'] = format_columns.DictListColumn(
info.pop('scheduler_hints', {}),
@@ -2841,16 +2847,18 @@ class ListServer(command.Lister):
'pinned_availability_zone',
'hypervisor_hostname',
'metadata',
'scheduler_hints',
)
column_headers += (
'Availability Zone',
'Pinned Availability Zone',
'Host',
'Properties',
'Scheduler Hints',
)
if sdk_utils.supports_microversion(compute_client, '2.100'):
columns += ('scheduler_hints',)
column_headers += ('Scheduler Hints',)
if parsed_args.all_projects:
columns += ('project_id',)
column_headers += ('Project ID',)
@@ -2900,6 +2908,9 @@ class ListServer(command.Lister):
if c in (
'scheduler_hints',
"Scheduler Hints",
):
if sdk_utils.supports_microversion(
compute_client, '2.100'
):
columns += ('scheduler_hints',)
column_headers += ('Scheduler Hints',)

View File

@@ -4587,7 +4587,6 @@ class _TestServerList(TestServer):
'Pinned Availability Zone',
'Host',
'Properties',
'Scheduler Hints',
)
columns_all_projects = (
'ID',
@@ -4738,7 +4737,6 @@ class TestServerList(_TestServerList):
getattr(s, 'pinned_availability_zone', ''),
server.HostColumn(getattr(s, 'hypervisor_hostname')),
format_columns.DictColumn(s.metadata),
format_columns.DictListColumn(None),
)
for s in self.servers
)
@@ -4817,8 +4815,6 @@ class TestServerList(_TestServerList):
'Host',
'-c',
'Properties',
'-c',
'Scheduler Hints',
'--long',
]
verifylist = [
@@ -4841,7 +4837,6 @@ class TestServerList(_TestServerList):
self.assertIn('Pinned Availability Zone', columns)
self.assertIn('Host', columns)
self.assertIn('Properties', columns)
self.assertIn('Scheduler Hints', columns)
self.assertCountEqual(columns, set(columns))
def test_server_list_no_name_lookup_option(self):
@@ -5255,7 +5250,6 @@ class TestServerList(_TestServerList):
getattr(s, 'pinned_availability_zone', ''),
server.HostColumn(getattr(s, 'hypervisor_hostname')),
format_columns.DictColumn(s.metadata),
format_columns.DictListColumn(s.scheduler_hints),
)
for s in self.servers
)
@@ -5312,7 +5306,6 @@ class TestServerList(_TestServerList):
getattr(s, 'pinned_availability_zone', ''),
server.HostColumn(getattr(s, 'hypervisor_hostname')),
format_columns.DictColumn(s.metadata),
format_columns.DictListColumn(s.scheduler_hints),
s.host_status,
)
for s in servers
@@ -5546,6 +5539,159 @@ class TestServerListV273(_TestServerList):
self.assertEqual(expected_row, partial_server)
class TestServerListV2100(_TestServerList):
columns = (
'ID',
'Name',
'Status',
'Networks',
'Image',
'Flavor',
)
columns_long = (
'ID',
'Name',
'Status',
'Task State',
'Power State',
'Networks',
'Image Name',
'Image ID',
'Flavor',
'Availability Zone',
'Pinned Availability Zone',
'Host',
'Properties',
'Scheduler Hints',
)
def setUp(self):
super().setUp()
self.set_compute_api_version('2.100')
self.image_client.images.return_value = [
sdk_fakes.generate_fake_resource(
_image.Image, id=s.image['id'], name=self.image.name
)
# Image will be an empty string if boot-from-volume
for s in self.servers
if s.image
]
self.compute_client.flavors.return_value = [
sdk_fakes.generate_fake_resource(
_flavor.Flavor, id=s.flavor['id'], name=self.flavor.name
)
for s in self.servers
]
self.data = tuple(
(
s.id,
s.name,
s.status,
server.AddressesColumn(s.addresses),
# Image will be an empty string if boot-from-volume
self.image.name if s.image else server.IMAGE_STRING_FOR_BFV,
self.flavor.name,
)
for s in self.servers
)
def test_server_list_long_option(self):
self.data = tuple(
(
s.id,
s.name,
s.status,
getattr(s, 'task_state'),
server.PowerStateColumn(getattr(s, 'power_state')),
server.AddressesColumn(s.addresses),
# Image will be an empty string if boot-from-volume
self.image.name if s.image else server.IMAGE_STRING_FOR_BFV,
s.image['id'] if s.image else server.IMAGE_STRING_FOR_BFV,
self.flavor.name,
getattr(s, 'availability_zone'),
getattr(s, 'pinned_availability_zone', ''),
server.HostColumn(getattr(s, 'hypervisor_hostname')),
format_columns.DictColumn(s.metadata),
format_columns.DictListColumn(None),
)
for s in self.servers
)
arglist = [
'--long',
]
verifylist = [
('all_projects', False),
('long', True),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.compute_client.servers.assert_called_with(**self.kwargs)
image_ids = {s.image['id'] for s in self.servers if s.image}
self.image_client.images.assert_called_once_with(
id=f'in:{",".join(image_ids)}',
)
self.compute_client.flavors.assert_called_once_with(is_public=None)
self.assertEqual(self.columns_long, columns)
self.assertEqual(self.data, tuple(data))
def test_server_list_column_option(self):
arglist = [
'-c',
'Project ID',
'-c',
'User ID',
'-c',
'Created At',
'-c',
'Security Groups',
'-c',
'Task State',
'-c',
'Power State',
'-c',
'Image ID',
'-c',
'Flavor ID',
'-c',
'Availability Zone',
'-c',
'Pinned Availability Zone',
'-c',
'Host',
'-c',
'Properties',
'-c',
'Scheduler Hints',
'--long',
]
verifylist = [
('long', True),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.compute_client.servers.assert_called_with(**self.kwargs)
self.assertIn('Project ID', columns)
self.assertIn('User ID', columns)
self.assertIn('Created At', columns)
self.assertIn('Security Groups', columns)
self.assertIn('Task State', columns)
self.assertIn('Power State', columns)
self.assertIn('Image ID', columns)
self.assertIn('Flavor ID', columns)
self.assertIn('Availability Zone', columns)
self.assertIn('Pinned Availability Zone', columns)
self.assertIn('Host', columns)
self.assertIn('Properties', columns)
self.assertIn('Scheduler Hints', columns)
self.assertCountEqual(columns, set(columns))
class TestServerAction(compute_fakes.TestComputev2):
def run_method_with_sdk_servers(self, method_name, server_count):
servers = compute_fakes.create_servers(count=server_count)