Skip to content

Commit bd4e674

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "compute: Only retrieve necessary images"
2 parents 36f58c2 + 725b7de commit bd4e674

3 files changed

Lines changed: 51 additions & 12 deletions

File tree

openstackclient/compute/v2/server.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2500,28 +2500,45 @@ def take_action(self, parsed_args):
25002500
data = compute_client.servers.list(
25012501
search_opts=search_opts,
25022502
marker=marker_id,
2503-
limit=parsed_args.limit)
2503+
limit=parsed_args.limit,
2504+
)
25042505

25052506
images = {}
25062507
flavors = {}
25072508
if data and not parsed_args.no_name_lookup:
2509+
# partial responses from down cells will not have an image
2510+
# attribute so we use getattr
2511+
image_ids = {
2512+
s.image['id'] for s in data
2513+
if getattr(s, 'image', None) and s.image.get('id')
2514+
}
2515+
25082516
# create a dict that maps image_id to image object, which is used
25092517
# to display the "Image Name" column. Note that 'image.id' can be
25102518
# empty for BFV instances and 'image' can be missing entirely if
25112519
# there are infra failures
25122520
if parsed_args.name_lookup_one_by_one or image_id:
2513-
for i_id in set(
2514-
s.image['id'] for s in data
2515-
if s.image and s.image.get('id')
2516-
):
2521+
for image_id in image_ids:
25172522
# "Image Name" is not crucial, so we swallow any exceptions
25182523
try:
2519-
images[i_id] = image_client.get_image(i_id)
2524+
images[image_id] = image_client.get_image(image_id)
25202525
except Exception:
25212526
pass
25222527
else:
25232528
try:
2524-
images_list = image_client.images()
2529+
# some deployments can have *loads* of images so we only
2530+
# want to list the ones we care about. It would be better
2531+
# to only retrun the *fields* we care about (name) but
2532+
# glance doesn't support that
2533+
# NOTE(stephenfin): This could result in super long URLs
2534+
# but it seems unlikely to cause issues. Apache supports
2535+
# URL lengths of up to 8190 characters by default, which
2536+
# should allow for more than 220 unique image ID (different
2537+
# servers are likely use the same image ID) in the filter.
2538+
# Who'd need more than that in a single command?
2539+
images_list = image_client.images(
2540+
id=f"in:{','.join(image_ids)}"
2541+
)
25252542
for i in images_list:
25262543
images[i.id] = i
25272544
except Exception:

openstackclient/tests/unit/compute/v2/test_server.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4449,8 +4449,8 @@ def test_server_list_no_servers(self):
44494449
columns, data = self.cmd.take_action(parsed_args)
44504450

44514451
self.servers_mock.list.assert_called_with(**self.kwargs)
4452-
self.assertEqual(0, self.images_mock.list.call_count)
4453-
self.assertEqual(0, self.flavors_mock.list.call_count)
4452+
self.images_mock.assert_not_called()
4453+
self.flavors_mock.list.assert_not_called()
44544454
self.assertEqual(self.columns, columns)
44554455
self.assertEqual(self.data, tuple(data))
44564456

@@ -4473,7 +4473,8 @@ def test_server_list_long_option(self):
44734473
getattr(s, 'OS-EXT-AZ:availability_zone'),
44744474
getattr(s, 'OS-EXT-SRV-ATTR:host'),
44754475
s.Metadata,
4476-
) for s in self.servers)
4476+
) for s in self.servers
4477+
)
44774478
arglist = [
44784479
'--long',
44794480
]
@@ -4485,6 +4486,11 @@ def test_server_list_long_option(self):
44854486

44864487
columns, data = self.cmd.take_action(parsed_args)
44874488
self.servers_mock.list.assert_called_with(**self.kwargs)
4489+
image_ids = {s.image['id'] for s in self.servers if s.image}
4490+
self.images_mock.assert_called_once_with(
4491+
id=f'in:{",".join(image_ids)}',
4492+
)
4493+
self.flavors_mock.list.assert_called_once_with(is_public=None)
44884494
self.assertEqual(self.columns_long, columns)
44894495
self.assertEqual(self.data, tuple(data))
44904496

@@ -4548,6 +4554,8 @@ def test_server_list_no_name_lookup_option(self):
45484554
columns, data = self.cmd.take_action(parsed_args)
45494555

45504556
self.servers_mock.list.assert_called_with(**self.kwargs)
4557+
self.images_mock.assert_not_called()
4558+
self.flavors_mock.list.assert_not_called()
45514559
self.assertEqual(self.columns, columns)
45524560
self.assertEqual(self.data, tuple(data))
45534561

@@ -4576,6 +4584,8 @@ def test_server_list_n_option(self):
45764584
columns, data = self.cmd.take_action(parsed_args)
45774585

45784586
self.servers_mock.list.assert_called_with(**self.kwargs)
4587+
self.images_mock.assert_not_called()
4588+
self.flavors_mock.list.assert_not_called()
45794589
self.assertEqual(self.columns, columns)
45804590
self.assertEqual(self.data, tuple(data))
45814591

@@ -4593,8 +4603,8 @@ def test_server_list_name_lookup_one_by_one(self):
45934603
columns, data = self.cmd.take_action(parsed_args)
45944604

45954605
self.servers_mock.list.assert_called_with(**self.kwargs)
4596-
self.assertFalse(self.images_mock.list.call_count)
4597-
self.assertFalse(self.flavors_mock.list.call_count)
4606+
self.images_mock.assert_not_called()
4607+
self.flavors_mock.list.assert_not_called()
45984608
self.get_image_mock.assert_called()
45994609
self.flavors_mock.get.assert_called()
46004610

@@ -4618,6 +4628,8 @@ def test_server_list_with_image(self):
46184628

46194629
self.search_opts['image'] = self.image.id
46204630
self.servers_mock.list.assert_called_with(**self.kwargs)
4631+
self.images_mock.assert_not_called()
4632+
self.flavors_mock.list.assert_called_once()
46214633

46224634
self.assertEqual(self.columns, columns)
46234635
self.assertEqual(self.data, tuple(data))
@@ -4638,6 +4650,8 @@ def test_server_list_with_flavor(self):
46384650

46394651
self.search_opts['flavor'] = self.flavor.id
46404652
self.servers_mock.list.assert_called_with(**self.kwargs)
4653+
self.images_mock.assert_called_once()
4654+
self.flavors_mock.list.assert_not_called()
46414655

46424656
self.assertEqual(self.columns, columns)
46434657
self.assertEqual(self.data, tuple(data))
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
features:
3+
- |
4+
The ``server list`` needs to query the image service API to retrieve
5+
image names as part of the response. This command will now retrieve only
6+
the images that are relevant, i.e. those used by the server included in
7+
the output. This should result in signficantly faster responses when
8+
using a deployment with a large number of public images.

0 commit comments

Comments
 (0)