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>
This commit is contained in:
Rajesh Tailor
2025-08-29 12:15:39 +05:30
parent 5f1ffe742c
commit e7554603ac
2 changed files with 170 additions and 19 deletions

View File

@@ -183,13 +183,17 @@ def _prep_server_detail(compute_client, image_client, server, *, refresh=True):
'updated_at': 'updated',
'user_data': 'OS-EXT-SRV-ATTR:user_data',
'vm_state': 'OS-EXT-STS:vm_state',
'scheduler_hints': 'scheduler_hints',
}
# NOTE(ratailor): microversion 2.96 introduces
# pinned_availability_zone support
if sdk_utils.supports_microversion(compute_client, '2.96'):
column_map['pinned_availability_zone'] = 'pinned_availability_zone'
# 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 = {
@@ -335,10 +339,11 @@ def _prep_server_detail(compute_client, image_client, server, *, refresh=True):
info['OS-EXT-STS:power_state']
)
if 'scheduler_hints' in info:
info['scheduler_hints'] = format_columns.DictListColumn(
info.pop('scheduler_hints', {}),
)
if sdk_utils.supports_microversion(compute_client, '2.100'):
if 'scheduler_hints' in info:
info['scheduler_hints'] = format_columns.DictListColumn(
info.pop('scheduler_hints', {}),
)
return info
@@ -2849,18 +2854,20 @@ class ListServer(command.Lister):
'availability_zone',
'hypervisor_hostname',
'metadata',
'scheduler_hints',
)
column_headers += (
'Availability Zone',
'Host',
'Properties',
'Scheduler Hints',
)
if sdk_utils.supports_microversion(compute_client, '2.96'):
columns += ('pinned_availability_zone',)
column_headers += ('Pinned Availability Zone',)
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',)
@@ -2912,8 +2919,11 @@ class ListServer(command.Lister):
'scheduler_hints',
"Scheduler Hints",
):
columns += ('scheduler_hints',)
column_headers += ('Scheduler Hints',)
if sdk_utils.supports_microversion(
compute_client, '2.100'
):
columns += ('scheduler_hints',)
column_headers += ('Scheduler Hints',)
# remove duplicates
column_headers = tuple(dict.fromkeys(column_headers))

View File

@@ -4584,7 +4584,6 @@ class _TestServerList(TestServer):
'Availability Zone',
'Host',
'Properties',
'Scheduler Hints',
)
columns_all_projects = (
'ID',
@@ -4734,7 +4733,6 @@ class TestServerList(_TestServerList):
getattr(s, 'availability_zone'),
server.HostColumn(getattr(s, 'hypervisor_hostname')),
format_columns.DictColumn(s.metadata),
format_columns.DictListColumn(None),
)
for s in self.servers
)
@@ -4811,8 +4809,6 @@ class TestServerList(_TestServerList):
'Host',
'-c',
'Properties',
'-c',
'Scheduler Hints',
'--long',
]
verifylist = [
@@ -4834,7 +4830,6 @@ class TestServerList(_TestServerList):
self.assertIn('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):
@@ -5247,7 +5242,6 @@ class TestServerList(_TestServerList):
getattr(s, 'availability_zone'),
server.HostColumn(getattr(s, 'hypervisor_hostname')),
format_columns.DictColumn(s.metadata),
format_columns.DictListColumn(s.scheduler_hints),
)
for s in self.servers
)
@@ -5303,7 +5297,6 @@ class TestServerList(_TestServerList):
getattr(s, '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
@@ -5558,7 +5551,6 @@ class TestServerListV296(_TestServerList):
'Availability Zone',
'Host',
'Properties',
'Scheduler Hints',
'Pinned Availability Zone',
)
@@ -5611,7 +5603,6 @@ class TestServerListV296(_TestServerList):
getattr(s, 'availability_zone'),
server.HostColumn(getattr(s, 'hypervisor_hostname')),
format_columns.DictColumn(s.metadata),
format_columns.DictListColumn(None),
getattr(s, 'pinned_availability_zone', ''),
)
for s in self.servers
@@ -5660,9 +5651,159 @@ class TestServerListV296(_TestServerList):
'-c',
'Properties',
'-c',
'Scheduler Hints',
'Pinned Availability Zone',
'--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.assertCountEqual(columns, set(columns))
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',
'Host',
'Properties',
'Pinned Availability Zone',
'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'),
server.HostColumn(getattr(s, 'hypervisor_hostname')),
format_columns.DictColumn(s.metadata),
getattr(s, 'pinned_availability_zone', ''),
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',
'Host',
'-c',
'Properties',
'-c',
'Pinned Availability Zone',
'-c',
'Scheduler Hints',
'--long',
]
verifylist = [