Skip to content

Commit c3a60e1

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Add --name-lookup-one-by-one option to server list"
2 parents 9b1e5f0 + e782f49 commit c3a60e1

3 files changed

Lines changed: 91 additions & 23 deletions

File tree

openstackclient/compute/v2/server.py

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,11 +1087,22 @@ def get_parser(self, prog_name):
10871087
default=False,
10881088
help=_('List additional fields in output'),
10891089
)
1090-
parser.add_argument(
1090+
name_lookup_group = parser.add_mutually_exclusive_group()
1091+
name_lookup_group.add_argument(
10911092
'-n', '--no-name-lookup',
10921093
action='store_true',
10931094
default=False,
1094-
help=_('Skip flavor and image name lookup.'),
1095+
help=_('Skip flavor and image name lookup.'
1096+
'Mutually exclusive with "--name-lookup-one-by-one"'
1097+
' option.'),
1098+
)
1099+
name_lookup_group.add_argument(
1100+
'--name-lookup-one-by-one',
1101+
action='store_true',
1102+
default=False,
1103+
help=_('When looking up flavor and image names, look them up'
1104+
'one by one as needed instead of all together (default). '
1105+
'Mutually exclusive with "--no-name-lookup|-n" option.'),
10951106
)
10961107
parser.add_argument(
10971108
'--marker',
@@ -1266,28 +1277,43 @@ def take_action(self, parsed_args):
12661277
limit=parsed_args.limit)
12671278

12681279
images = {}
1269-
# Create a dict that maps image_id to image object.
1270-
# Needed so that we can display the "Image Name" column.
1271-
# "Image Name" is not crucial, so we swallow any exceptions.
1272-
if data and not parsed_args.no_name_lookup:
1273-
try:
1274-
images_list = self.app.client_manager.image.images.list()
1275-
for i in images_list:
1276-
images[i.id] = i
1277-
except Exception:
1278-
pass
1279-
12801280
flavors = {}
1281-
# Create a dict that maps flavor_id to flavor object.
1282-
# Needed so that we can display the "Flavor Name" column.
1283-
# "Flavor Name" is not crucial, so we swallow any exceptions.
12841281
if data and not parsed_args.no_name_lookup:
1285-
try:
1286-
flavors_list = compute_client.flavors.list(is_public=None)
1287-
for i in flavors_list:
1288-
flavors[i.id] = i
1289-
except Exception:
1290-
pass
1282+
# Create a dict that maps image_id to image object.
1283+
# Needed so that we can display the "Image Name" column.
1284+
# "Image Name" is not crucial, so we swallow any exceptions.
1285+
if parsed_args.name_lookup_one_by_one or image_id:
1286+
for i_id in set(filter(lambda x: x is not None,
1287+
(s.image.get('id') for s in data))):
1288+
try:
1289+
images[i_id] = image_client.images.get(i_id)
1290+
except Exception:
1291+
pass
1292+
else:
1293+
try:
1294+
images_list = image_client.images.list()
1295+
for i in images_list:
1296+
images[i.id] = i
1297+
except Exception:
1298+
pass
1299+
1300+
# Create a dict that maps flavor_id to flavor object.
1301+
# Needed so that we can display the "Flavor Name" column.
1302+
# "Flavor Name" is not crucial, so we swallow any exceptions.
1303+
if parsed_args.name_lookup_one_by_one or flavor_id:
1304+
for f_id in set(filter(lambda x: x is not None,
1305+
(s.flavor.get('id') for s in data))):
1306+
try:
1307+
flavors[f_id] = compute_client.flavors.get(f_id)
1308+
except Exception:
1309+
pass
1310+
else:
1311+
try:
1312+
flavors_list = compute_client.flavors.list(is_public=None)
1313+
for i in flavors_list:
1314+
flavors[i.id] = i
1315+
except Exception:
1316+
pass
12911317

12921318
# Populate image_name, image_id, flavor_name and flavor_id attributes
12931319
# of server objects so that we can display those columns.

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

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2086,12 +2086,18 @@ def test_server_list_no_option(self):
20862086
('all_projects', False),
20872087
('long', False),
20882088
('deleted', False),
2089+
('name_lookup_one_by_one', False),
20892090
]
20902091
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
20912092

20922093
columns, data = self.cmd.take_action(parsed_args)
20932094

20942095
self.servers_mock.list.assert_called_with(**self.kwargs)
2096+
self.images_mock.list.assert_called()
2097+
self.flavors_mock.list.assert_called()
2098+
# we did not pass image or flavor, so gets on those must be absent
2099+
self.assertFalse(self.flavors_mock.get.call_count)
2100+
self.assertFalse(self.images_mock.get.call_count)
20952101
self.assertEqual(self.columns, columns)
20962102
self.assertEqual(tuple(self.data), tuple(data))
20972103

@@ -2162,6 +2168,28 @@ def test_server_list_n_option(self):
21622168
self.assertEqual(self.columns, columns)
21632169
self.assertEqual(tuple(self.data_no_name_lookup), tuple(data))
21642170

2171+
def test_server_list_name_lookup_one_by_one(self):
2172+
arglist = [
2173+
'--name-lookup-one-by-one'
2174+
]
2175+
verifylist = [
2176+
('all_projects', False),
2177+
('no_name_lookup', False),
2178+
('name_lookup_one_by_one', True),
2179+
]
2180+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
2181+
2182+
columns, data = self.cmd.take_action(parsed_args)
2183+
2184+
self.servers_mock.list.assert_called_with(**self.kwargs)
2185+
self.assertFalse(self.images_mock.list.call_count)
2186+
self.assertFalse(self.flavors_mock.list.call_count)
2187+
self.images_mock.get.assert_called()
2188+
self.flavors_mock.get.assert_called()
2189+
2190+
self.assertEqual(self.columns, columns)
2191+
self.assertEqual(tuple(self.data), tuple(data))
2192+
21652193
def test_server_list_with_image(self):
21662194

21672195
arglist = [
@@ -2194,7 +2222,7 @@ def test_server_list_with_flavor(self):
21942222
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
21952223
columns, data = self.cmd.take_action(parsed_args)
21962224

2197-
self.flavors_mock.get.assert_called_with(self.flavor.id)
2225+
self.flavors_mock.get.has_calls(self.flavor.id)
21982226

21992227
self.search_opts['flavor'] = self.flavor.id
22002228
self.servers_mock.list.assert_called_with(**self.kwargs)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
features:
3+
- |
4+
Add ``--name-lookup-one-by-one`` option to the ``server list`` command
5+
that is (mutually exclusive with ``-n | --no-name-lookup``).
6+
When provided, the names of images and flavors will be resolved one by one
7+
only for those images and flavors that are needed to display the obtained
8+
list of servers instead of fetching all the images and flavors.
9+
Depending on amount of images in your deployment this can speed up the
10+
execution of this command.
11+
- |
12+
When given ``--image`` or ``--flavor`` argument, the ``server list``
13+
command now resolves only single image or flavor instead of fetching
14+
all the images or flavors for name lookup purposes.

0 commit comments

Comments
 (0)