2020"""
2121
2222import logging
23+ import os
24+
25+ from cliff import lister
26+ from cliff import show
2327
2428from openstackclient .common import command
2529from openstackclient .common import utils
2630
2731
28- def _find_server (cs , server ):
29- """Get a server by name or ID."""
30- return utils .find_resource (cs .servers , server )
31-
32-
33- def _print_server (cs , server ):
34- # By default when searching via name we will do a
35- # findall(name=blah) and due a REST /details which is not the same
36- # as a .get() and doesn't get the information about flavors and
37- # images. This fix it as we redo the call with the id which does a
38- # .get() to get all informations.
39- if not 'flavor' in server ._info :
40- server = _find_server (cs , server .id )
41-
42- networks = server .networks
43- info = server ._info .copy ()
44- for network_label , address_list in networks .items ():
45- info ['%s network' % network_label ] = ', ' .join (address_list )
46-
47- flavor = info .get ('flavor' , {})
48- flavor_id = flavor .get ('id' , '' )
49- info ['flavor' ] = _find_flavor (cs , flavor_id ).name
50-
51- image = info .get ('image' , {})
52- image_id = image .get ('id' , '' )
53- info ['image' ] = _find_image (cs , image_id ).name
54-
55- info .pop ('links' , None )
56- info .pop ('addresses' , None )
57-
58- utils .print_dict (info )
59-
60-
61- class List_Server (command .OpenStackCommand ):
32+ def _format_servers_list_networks (server ):
33+ """Return a string containing the networks a server is attached to.
34+
35+ :param server: a single Server resource
36+ """
37+ output = []
38+ for (network , addresses ) in server .networks .items ():
39+ if not addresses :
40+ continue
41+ addresses_csv = ', ' .join (addresses )
42+ group = "%s=%s" % (network , addresses_csv )
43+ output .append (group )
44+ return '; ' .join (output )
45+
46+
47+ def get_server_properties (server , fields , formatters = {}):
48+ """Return a tuple containing the server properties.
49+
50+ :param server: a single Server resource
51+ :param fields: tuple of strings with the desired field names
52+ :param formatters: dictionary mapping field names to callables
53+ to format the values
54+ """
55+ row = []
56+ mixed_case_fields = ['serverId' ]
57+
58+ for field in fields :
59+ if field in formatters :
60+ row .append (formatters [field ](server ))
61+ else :
62+ if field in mixed_case_fields :
63+ field_name = field .replace (' ' , '_' )
64+ else :
65+ field_name = field .lower ().replace (' ' , '_' )
66+ data = getattr (server , field_name , '' )
67+ row .append (data )
68+ return tuple (row )
69+
70+
71+ class List_Server (command .OpenStackCommand , lister .Lister ):
6272 "List server command."
6373
6474 api = 'compute'
@@ -67,17 +77,79 @@ class List_Server(command.OpenStackCommand):
6777 def get_parser (self , prog_name ):
6878 parser = super (List_Server , self ).get_parser (prog_name )
6979 parser .add_argument (
70- '--long' ,
80+ '--reservation-id' ,
81+ help = 'only return instances that match the reservation' ,
82+ )
83+ parser .add_argument (
84+ '--ip' ,
85+ help = 'regular expression to match IP address' ,
86+ )
87+ parser .add_argument (
88+ '--ip6' ,
89+ help = 'regular expression to match IPv6 address' ,
90+ )
91+ parser .add_argument (
92+ '--name' ,
93+ help = 'regular expression to match name' ,
94+ )
95+ parser .add_argument (
96+ '--instance-name' ,
97+ help = 'regular expression to match instance name' ,
98+ )
99+ parser .add_argument (
100+ '--status' ,
101+ help = 'search by server status' ,
102+ # FIXME(dhellmann): Add choices?
103+ )
104+ parser .add_argument (
105+ '--flavor' ,
106+ help = 'search by flavor ID' ,
107+ )
108+ parser .add_argument (
109+ '--image' ,
110+ help = 'search by image ID' ,
111+ )
112+ parser .add_argument (
113+ '--host' ,
114+ metavar = 'HOSTNAME' ,
115+ help = 'search by hostname' ,
116+ )
117+ parser .add_argument (
118+ '--all-tenants' ,
71119 action = 'store_true' ,
72- default = False ,
73- help = 'Additional fields are listed in output' )
120+ default = bool (int (os .environ .get ("ALL_TENANTS" , 0 ))),
121+ help = 'display information from all tenants (admin only)' ,
122+ )
74123 return parser
75124
76- def run (self , parsed_args ):
77- self .log .info ('v2.List_Server.run(%s)' % parsed_args )
78-
79-
80- class Show_Server (command .OpenStackCommand ):
125+ def get_data (self , parsed_args ):
126+ self .log .debug ('v2.List_Server.run(%s)' % parsed_args )
127+ nova_client = self .app .client_manager .compute
128+ search_opts = {
129+ 'all_tenants' : parsed_args .all_tenants ,
130+ 'reservation_id' : parsed_args .reservation_id ,
131+ 'ip' : parsed_args .ip ,
132+ 'ip6' : parsed_args .ip6 ,
133+ 'name' : parsed_args .name ,
134+ 'image' : parsed_args .image ,
135+ 'flavor' : parsed_args .flavor ,
136+ 'status' : parsed_args .status ,
137+ 'host' : parsed_args .host ,
138+ 'instance_name' : parsed_args .instance_name ,
139+ }
140+ self .log .debug ('search options: %s' , search_opts )
141+ # FIXME(dhellmann): Consider adding other columns
142+ columns = ('ID' , 'Name' , 'Status' , 'Networks' )
143+ data = nova_client .servers .list (search_opts = search_opts )
144+ return (columns ,
145+ (get_server_properties (
146+ s , columns ,
147+ formatters = {'Networks' : _format_servers_list_networks },
148+ ) for s in data ),
149+ )
150+
151+
152+ class Show_Server (command .OpenStackCommand , show .ShowOne ):
81153 "Show server command."
82154
83155 api = 'compute'
@@ -91,7 +163,32 @@ def get_parser(self, prog_name):
91163 help = 'Name or ID of server to display' )
92164 return parser
93165
94- def run (self , parsed_args ):
95- self .log .info ('v2.Show_Server.run(%s)' % parsed_args )
96- #s = _find_server(cs, args.server)
97- #_print_server(cs, s)
166+ def get_data (self , parsed_args ):
167+ self .log .debug ('v2.Show_Server.run(%s)' % parsed_args )
168+ nova_client = self .app .client_manager .compute
169+ server = utils .find_resource (nova_client .servers , parsed_args .server )
170+
171+ info = {}
172+ info .update (server ._info )
173+
174+ # Convert the flavor blob to a name
175+ flavor_info = info .get ('flavor' , {})
176+ flavor_id = flavor_info .get ('id' , '' )
177+ flavor = utils .find_resource (nova_client .flavors , flavor_id )
178+ info ['flavor' ] = flavor .name
179+
180+ # Convert the image blob to a name
181+ image_info = info .get ('image' , {})
182+ image_id = image_info .get ('id' , '' )
183+ image = utils .find_resource (nova_client .images , image_id )
184+ info ['image' ] = image .name
185+
186+ # Format addresses in a useful way
187+ info ['addresses' ] = _format_servers_list_networks (server )
188+
189+ # Remove a couple of values that are long and not too useful
190+ info .pop ('links' , None )
191+
192+ columns = sorted (info .keys ())
193+ values = [info [c ] for c in columns ]
194+ return (columns , values )
0 commit comments