@@ -149,16 +149,13 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
149149 # Some commands using this routine were originally implemented with the
150150 # nova python wrappers, and were later migrated to use the SDK. Map the
151151 # SDK's property names to the original property names to maintain backward
152- # compatibility for existing users. Data is duplicated under both the old
153- # and new name so users can consume the data by either name.
152+ # compatibility for existing users.
154153 column_map = {
155154 'access_ipv4' : 'accessIPv4' ,
156155 'access_ipv6' : 'accessIPv6' ,
157156 'admin_password' : 'adminPass' ,
158- 'admin_password' : 'adminPass' ,
159- 'volumes' : 'os-extended-volumes:volumes_attached' ,
157+ 'attached_volumes' : 'volumes_attached' ,
160158 'availability_zone' : 'OS-EXT-AZ:availability_zone' ,
161- 'block_device_mapping' : 'block_device_mapping_v2' ,
162159 'compute_host' : 'OS-EXT-SRV-ATTR:host' ,
163160 'created_at' : 'created' ,
164161 'disk_config' : 'OS-DCF:diskConfig' ,
@@ -168,7 +165,6 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
168165 'fault' : 'fault' ,
169166 'hostname' : 'OS-EXT-SRV-ATTR:hostname' ,
170167 'hypervisor_hostname' : 'OS-EXT-SRV-ATTR:hypervisor_hostname' ,
171- 'image_id' : 'imageRef' ,
172168 'instance_name' : 'OS-EXT-SRV-ATTR:instance_name' ,
173169 'is_locked' : 'locked' ,
174170 'kernel_id' : 'OS-EXT-SRV-ATTR:kernel_id' ,
@@ -179,21 +175,56 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
179175 'ramdisk_id' : 'OS-EXT-SRV-ATTR:ramdisk_id' ,
180176 'reservation_id' : 'OS-EXT-SRV-ATTR:reservation_id' ,
181177 'root_device_name' : 'OS-EXT-SRV-ATTR:root_device_name' ,
182- 'scheduler_hints' : 'OS-SCH-HNT:scheduler_hints' ,
183178 'task_state' : 'OS-EXT-STS:task_state' ,
184179 'terminated_at' : 'OS-SRV-USG:terminated_at' ,
185180 'updated_at' : 'updated' ,
186181 'user_data' : 'OS-EXT-SRV-ATTR:user_data' ,
187182 'vm_state' : 'OS-EXT-STS:vm_state' ,
188183 }
184+ # Some columns returned by openstacksdk should not be shown because they're
185+ # either irrelevant or duplicates
186+ ignored_columns = {
187+ # computed columns
188+ 'interface_ip' ,
189+ 'location' ,
190+ 'private_v4' ,
191+ 'private_v6' ,
192+ 'public_v4' ,
193+ 'public_v6' ,
194+ # create-only columns
195+ 'block_device_mapping' ,
196+ 'image_id' ,
197+ 'max_count' ,
198+ 'min_count' ,
199+ 'scheduler_hints' ,
200+ # aliases
201+ 'volumes' ,
202+ # unnecessary
203+ 'links' ,
204+ }
205+ # Some columns are only present in certain responses and should not be
206+ # shown otherwise.
207+ optional_columns = {
208+ 'admin_password' , # removed in 2.14
209+ 'fault' , # only present in errored servers
210+ 'flavor_id' , # removed in 2.47
211+ 'networks' , # only present in create responses
212+ 'security_groups' , # only present in create, detail responses
213+ }
189214
190- info .update (
191- {
192- column_map [column ]: data
193- for column , data in info .items ()
194- if column in column_map
195- }
196- )
215+ data = {}
216+ for key , value in info .items ():
217+ if key in ignored_columns :
218+ continue
219+
220+ if key in optional_columns :
221+ if info [key ] is None :
222+ continue
223+
224+ alias = column_map .get (key )
225+ data [alias or key ] = value
226+
227+ info = data
197228
198229 # Convert the image blob to a name
199230 image_info = info .get ('image' , {})
@@ -214,46 +245,57 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
214245 # Convert the flavor blob to a name
215246 flavor_info = info .get ('flavor' , {})
216247 # Microversion 2.47 puts the embedded flavor into the server response
217- # body but omits the id, so if not present we just expose the flavor
218- # dict in the server output.
219- if 'id' in flavor_info :
248+ # body. The presence of the 'original_name' attribute indicates this.
249+ if flavor_info .get ('original_name' ) is None : # microversion < 2.47
220250 flavor_id = flavor_info .get ('id' , '' )
221251 try :
222252 flavor = utils .find_resource (compute_client .flavors , flavor_id )
223253 info ['flavor' ] = "%s (%s)" % (flavor .name , flavor_id )
224254 except Exception :
225255 info ['flavor' ] = flavor_id
226- else :
256+ else : # microversion >= 2.47
227257 info ['flavor' ] = format_columns .DictColumn (flavor_info )
228258
229- if 'os-extended-volumes:volumes_attached' in info :
259+ # there's a lot of redundant information in BDMs - strip it
260+ if 'volumes_attached' in info :
230261 info .update (
231262 {
232263 'volumes_attached' : format_columns .ListDictColumn (
233- info .pop ('os-extended-volumes:volumes_attached' )
264+ [
265+ {
266+ k : v
267+ for k , v in volume .items ()
268+ if v is not None and k != 'location'
269+ }
270+ for volume in info .pop ('volumes_attached' ) or []
271+ ]
234272 )
235273 }
236274 )
275+
237276 if 'security_groups' in info :
238277 info .update (
239278 {
240279 'security_groups' : format_columns .ListDictColumn (
241- info .pop ('security_groups' )
280+ info .pop ('security_groups' ),
242281 )
243282 }
244283 )
284+
245285 if 'tags' in info :
246286 info .update ({'tags' : format_columns .ListColumn (info .pop ('tags' ))})
247287
248- # NOTE(dtroyer): novaclient splits these into separate entries...
249- # Format addresses in a useful way
250- info ['addresses' ] = (
251- AddressesColumn (info ['addresses' ])
252- if 'addresses' in info
253- else format_columns .DictListColumn (info .get ('networks' ))
254- )
288+ # Map 'networks' to 'addresses', if present. Note that the 'networks' key
289+ # is used for create responses, otherwise it's 'addresses'. We know it'll
290+ # be set because this is one of our optional columns.
291+ if 'networks' in info :
292+ info ['addresses' ] = format_columns .DictListColumn (
293+ info .pop ('networks' , {}),
294+ )
295+ else :
296+ info ['addresses' ] = AddressesColumn (info .get ('addresses' , {}))
255297
256- # Map 'metadata' field to 'properties'
298+ # Map 'metadata' field to 'properties' and format
257299 info ['properties' ] = format_columns .DictColumn (info .pop ('metadata' ))
258300
259301 # Migrate tenant_id to project_id naming
@@ -266,9 +308,6 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
266308 info ['OS-EXT-STS:power_state' ]
267309 )
268310
269- # Remove values that are long and not too useful
270- info .pop ('links' , None )
271-
272311 return info
273312
274313
0 commit comments