From b74be57300badc97b93f77ad6288b2a5a0b0523e Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Tue, 5 Jul 2016 14:58:51 -0700 Subject: [PATCH] "server list": "Image Name", "Image ID" columns The `Image Name` column is shown by default (i.e.: without passing `--long`). E.g.: ``` $ openstack server list WARNING: openstackclient.common.utils is deprecated and will be removed after Jun 2017. Please use osc_lib.utils +--------------------------------------+-----------------+---------+----------------------+----------------------+ | ID | Name | Status | Networks | Image Name | +--------------------------------------+-----------------+---------+----------------------+----------------------+ | abe67035-b14f-4541-b436-e0e778ec4227 | n9anonw302mgm1 | ACTIVE | mnky3-3000=10.3.0.55 | Koala.2016-07-01-175 | | 8f6a2d12-2bc3-4d89-ba94-8916ce9cdf92 | n9anonw301mgm1 | ACTIVE | mnky3-3000=10.3.0.37 | Koala.2016-07-01-175 | | b316d6d1-67cf-4f75-94a4-4c9a2b03f6a4 | n9dobby301mgm0 | ACTIVE | mnky3-3000=10.3.0.36 | Koala.2016-05-04-130 | +--------------------------------------+-----------------+---------+----------------------+----------------------+ ``` The `Image ID` column is only available with `--long`. E.g.: ``` $ openstack server list --long -c Name -c "Image Name" -c "Image ID" WARNING: openstackclient.common.utils is deprecated and will be removed after Jun 2017. Please use osc_lib.utils +-----------------+----------------------+--------------------------------------+ | Name | Image Name | Image ID | +-----------------+----------------------+--------------------------------------+ | n9anonw302mgm1 | Koala.2016-07-01-175 | f587c6fc-1df3-42cd-ac86-8cd2c995a8d9 | | n9anonw301mgm1 | Koala.2016-07-01-175 | f587c6fc-1df3-42cd-ac86-8cd2c995a8d9 | | n9dobby301mgm0 | Koala.2016-05-04-130 | 37ff47a6-3e51-4986-bfa5-62afbfad5dfc | +-----------------+----------------------+--------------------------------------+ ``` Closes-Bug: #1599304 Change-Id: I477995b840eb9520b285948926ebbfe1777dd86c --- openstackclient/compute/v2/server.py | 53 +++++++++++++++---- .../tests/compute/v2/test_server.py | 15 +++++- 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index 7e4b0dc1f..93d913a06 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -776,6 +776,8 @@ class ListServer(command.Lister): 'OS-EXT-STS:task_state', 'OS-EXT-STS:power_state', 'Networks', + 'Image Name', + 'Image ID', 'OS-EXT-AZ:availability_zone', 'OS-EXT-SRV-ATTR:host', 'Metadata', @@ -787,6 +789,8 @@ class ListServer(command.Lister): 'Task State', 'Power State', 'Networks', + 'Image Name', + 'Image ID', 'Availability Zone', 'Host', 'Properties', @@ -803,12 +807,14 @@ class ListServer(command.Lister): 'Name', 'Status', 'Networks', + 'Image Name', ) column_headers = ( 'ID', 'Name', 'Status', 'Networks', + 'Image Name', ) mixed_case_fields = [] @@ -820,17 +826,42 @@ class ListServer(command.Lister): data = compute_client.servers.list(search_opts=search_opts, marker=marker_id, limit=parsed_args.limit) - return (column_headers, - (utils.get_item_properties( - s, columns, - mixed_case_fields=mixed_case_fields, - formatters={ - 'OS-EXT-STS:power_state': - _format_servers_list_power_state, - 'Networks': _format_servers_list_networks, - 'Metadata': utils.format_dict, - }, - ) for s in data)) + + images = {} + # 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 + + # Populate image_name and image_id attributes of server objects + # so that we can display "Image Name" and "Image ID" columns. + for s in data: + if 'id' in s.image: + image = images.get(s.image['id']) + if image: + s.image_name = image.name + s.image_id = s.image['id'] + else: + s.image_name = '' + s.image_id = '' + + table = (column_headers, + (utils.get_item_properties( + s, columns, + mixed_case_fields=mixed_case_fields, + formatters={ + 'OS-EXT-STS:power_state': + _format_servers_list_power_state, + 'Networks': _format_servers_list_networks, + 'Metadata': utils.format_dict, + }, + ) for s in data)) + return table class LockServer(command.Command): diff --git a/openstackclient/tests/compute/v2/test_server.py b/openstackclient/tests/compute/v2/test_server.py index 0bfe13101..a737f0711 100644 --- a/openstackclient/tests/compute/v2/test_server.py +++ b/openstackclient/tests/compute/v2/test_server.py @@ -12,6 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. # +import collections import getpass import mock from mock import call @@ -519,6 +520,7 @@ class TestServerList(TestServer): 'Name', 'Status', 'Networks', + 'Image Name', ) columns_long = ( 'ID', @@ -527,6 +529,8 @@ class TestServerList(TestServer): 'Task State', 'Power State', 'Networks', + 'Image Name', + 'Image ID', 'Availability Zone', 'Host', 'Properties', @@ -589,12 +593,19 @@ class TestServerList(TestServer): self.data = [] self.data_long = [] + Image = collections.namedtuple('Image', 'id name') + self.images_mock.list.return_value = [ + Image(id=s.image['id'], name=self.image.name) + for s in self.servers + ] + for s in self.servers: self.data.append(( s.id, s.name, s.status, server._format_servers_list_networks(s.networks), + self.image.name, )) self.data_long.append(( s.id, @@ -605,6 +616,8 @@ class TestServerList(TestServer): getattr(s, 'OS-EXT-STS:power_state') ), server._format_servers_list_networks(s.networks), + self.image.name, + s.image['id'], getattr(s, 'OS-EXT-AZ:availability_zone'), getattr(s, 'OS-EXT-SRV-ATTR:host'), s.Metadata, @@ -652,7 +665,7 @@ class TestServerList(TestServer): parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) - self.cimages_mock.get.assert_called_with(self.image.id) + self.cimages_mock.get.assert_any_call(self.image.id) self.search_opts['image'] = self.image.id self.servers_mock.list.assert_called_with(**self.kwargs)