Add server list -n and --no-name-lookup arguments

Remove translation of Image ID and Flavor ID to Image and Flavor names

In large environments amount of images can be very large (thousands)
Which requires ~hundreds of requests to Glance to get all images
(by default client request only 20 images)
As a result listing even few servers is going to take minutes

This patch allows to avoid these queries by not doing translation,
which allows one to get information about servers in seconds.

Change-Id: I4ae00e6324a41c4c79bf5b620179dae99aea5431
This commit is contained in:
Boris Pavlovic 2017-06-29 15:17:33 -07:00 committed by Boris Pavlovic
parent ca4b9be8a2
commit 2c57f7bfb2
3 changed files with 87 additions and 19 deletions

View File

@ -330,6 +330,7 @@ List servers
[--all-projects]
[--project <project> [--project-domain <project-domain>]]
[--long]
[-n | --no-name-lookup]
[--marker <server>]
[--limit <num-servers>]
[--deleted]
@ -397,6 +398,10 @@ List servers
List additional fields in output
.. option:: --no-name-lookup
Skips image and flavor names lookup
.. option:: --marker <server>
The last server of the previous page. Display list of servers

View File

@ -921,6 +921,12 @@ class ListServer(command.Lister):
default=False,
help=_('List additional fields in output'),
)
parser.add_argument(
'-n', '--no-name-lookup',
action='store_true',
default=False,
help=_('Skip flavor and image name lookup.'),
)
parser.add_argument(
'--marker',
metavar='<server>',
@ -1054,6 +1060,17 @@ class ListServer(command.Lister):
'OS-EXT-AZ:availability_zone',
'OS-EXT-SRV-ATTR:host',
]
elif parsed_args.no_name_lookup:
columns = (
'ID',
'Name',
'Status',
'Image ID',
'Flavor ID',
)
column_headers = tuple(columns)
mixed_case_fields = []
else:
columns = (
'ID',
@ -1062,13 +1079,7 @@ class ListServer(command.Lister):
'Networks',
'Image Name',
)
column_headers = (
'ID',
'Name',
'Status',
'Networks',
'Image Name',
)
column_headers = tuple(columns)
mixed_case_fields = []
marker_id = None
@ -1084,23 +1095,25 @@ class ListServer(command.Lister):
# Create a dict that maps image_id to image object.
# Needed so that we can display the "Image Name" column.
# "Image Name" is not crucial, so we swallow any exceptions.
try:
images_list = self.app.client_manager.image.images.list()
for i in images_list:
images[i.id] = i
except Exception:
pass
if not parsed_args.no_name_lookup:
try:
images_list = self.app.client_manager.image.images.list()
for i in images_list:
images[i.id] = i
except Exception:
pass
flavors = {}
# Create a dict that maps flavor_id to flavor object.
# Needed so that we can display the "Flavor Name" column.
# "Flavor Name" is not crucial, so we swallow any exceptions.
try:
flavors_list = compute_client.flavors.list()
for i in flavors_list:
flavors[i.id] = i
except Exception:
pass
if not parsed_args.no_name_lookup:
try:
flavors_list = compute_client.flavors.list()
for i in flavors_list:
flavors[i.id] = i
except Exception:
pass
# Populate image_name, image_id, flavor_name and flavor_id attributes
# of server objects so that we can display those columns.

View File

@ -395,6 +395,8 @@ class TestServerCreate(TestServer):
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist(), data)
self.assertFalse(self.images_mock.called)
self.assertFalse(self.flavors_mock.called)
def test_server_create_with_options(self):
arglist = [
@ -1457,6 +1459,14 @@ class TestServerList(TestServer):
'Properties',
)
columns_no_name_lookup = (
'ID',
'Name',
'Status',
'Image ID',
'Flavor ID',
)
def setUp(self):
super(TestServerList, self).setUp()
@ -1515,6 +1525,7 @@ class TestServerList(TestServer):
# Prepare data returned by fake Nova API.
self.data = []
self.data_long = []
self.data_no_name_lookup = []
Image = collections.namedtuple('Image', 'id name')
self.images_mock.list.return_value = [
@ -1553,6 +1564,13 @@ class TestServerList(TestServer):
getattr(s, 'OS-EXT-SRV-ATTR:host'),
s.Metadata,
))
self.data_no_name_lookup.append((
s.id,
s.name,
s.status,
s.image['id'],
s.flavor['id']
))
def test_server_list_no_option(self):
arglist = []
@ -1585,6 +1603,38 @@ class TestServerList(TestServer):
self.assertEqual(self.columns_long, columns)
self.assertEqual(tuple(self.data_long), tuple(data))
def test_server_list_no_name_lookup_option(self):
arglist = [
'--no-name-lookup',
]
verifylist = [
('all_projects', False),
('no_name_lookup', True),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.servers_mock.list.assert_called_with(**self.kwargs)
self.assertEqual(self.columns_no_name_lookup, columns)
self.assertEqual(tuple(self.data_no_name_lookup), tuple(data))
def test_server_list_n_option(self):
arglist = [
'-n',
]
verifylist = [
('all_projects', False),
('no_name_lookup', True),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.servers_mock.list.assert_called_with(**self.kwargs)
self.assertEqual(self.columns_no_name_lookup, columns)
self.assertEqual(tuple(self.data_no_name_lookup), tuple(data))
def test_server_list_with_image(self):
arglist = [