Merge "compute: Fix formatting of 'server show'"
This commit is contained in:
commit
50544ae78b
openstackclient
@ -149,16 +149,13 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
|
|||||||
# Some commands using this routine were originally implemented with the
|
# Some commands using this routine were originally implemented with the
|
||||||
# nova python wrappers, and were later migrated to use the SDK. Map the
|
# nova python wrappers, and were later migrated to use the SDK. Map the
|
||||||
# SDK's property names to the original property names to maintain backward
|
# SDK's property names to the original property names to maintain backward
|
||||||
# compatibility for existing users. Data is duplicated under both the old
|
# compatibility for existing users.
|
||||||
# and new name so users can consume the data by either name.
|
|
||||||
column_map = {
|
column_map = {
|
||||||
'access_ipv4': 'accessIPv4',
|
'access_ipv4': 'accessIPv4',
|
||||||
'access_ipv6': 'accessIPv6',
|
'access_ipv6': 'accessIPv6',
|
||||||
'admin_password': 'adminPass',
|
'admin_password': 'adminPass',
|
||||||
'admin_password': 'adminPass',
|
'attached_volumes': 'volumes_attached',
|
||||||
'volumes': 'os-extended-volumes:volumes_attached',
|
|
||||||
'availability_zone': 'OS-EXT-AZ:availability_zone',
|
'availability_zone': 'OS-EXT-AZ:availability_zone',
|
||||||
'block_device_mapping': 'block_device_mapping_v2',
|
|
||||||
'compute_host': 'OS-EXT-SRV-ATTR:host',
|
'compute_host': 'OS-EXT-SRV-ATTR:host',
|
||||||
'created_at': 'created',
|
'created_at': 'created',
|
||||||
'disk_config': 'OS-DCF:diskConfig',
|
'disk_config': 'OS-DCF:diskConfig',
|
||||||
@ -168,7 +165,6 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
|
|||||||
'fault': 'fault',
|
'fault': 'fault',
|
||||||
'hostname': 'OS-EXT-SRV-ATTR:hostname',
|
'hostname': 'OS-EXT-SRV-ATTR:hostname',
|
||||||
'hypervisor_hostname': 'OS-EXT-SRV-ATTR:hypervisor_hostname',
|
'hypervisor_hostname': 'OS-EXT-SRV-ATTR:hypervisor_hostname',
|
||||||
'image_id': 'imageRef',
|
|
||||||
'instance_name': 'OS-EXT-SRV-ATTR:instance_name',
|
'instance_name': 'OS-EXT-SRV-ATTR:instance_name',
|
||||||
'is_locked': 'locked',
|
'is_locked': 'locked',
|
||||||
'kernel_id': 'OS-EXT-SRV-ATTR:kernel_id',
|
'kernel_id': 'OS-EXT-SRV-ATTR:kernel_id',
|
||||||
@ -179,21 +175,56 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
|
|||||||
'ramdisk_id': 'OS-EXT-SRV-ATTR:ramdisk_id',
|
'ramdisk_id': 'OS-EXT-SRV-ATTR:ramdisk_id',
|
||||||
'reservation_id': 'OS-EXT-SRV-ATTR:reservation_id',
|
'reservation_id': 'OS-EXT-SRV-ATTR:reservation_id',
|
||||||
'root_device_name': 'OS-EXT-SRV-ATTR:root_device_name',
|
'root_device_name': 'OS-EXT-SRV-ATTR:root_device_name',
|
||||||
'scheduler_hints': 'OS-SCH-HNT:scheduler_hints',
|
|
||||||
'task_state': 'OS-EXT-STS:task_state',
|
'task_state': 'OS-EXT-STS:task_state',
|
||||||
'terminated_at': 'OS-SRV-USG:terminated_at',
|
'terminated_at': 'OS-SRV-USG:terminated_at',
|
||||||
'updated_at': 'updated',
|
'updated_at': 'updated',
|
||||||
'user_data': 'OS-EXT-SRV-ATTR:user_data',
|
'user_data': 'OS-EXT-SRV-ATTR:user_data',
|
||||||
'vm_state': 'OS-EXT-STS:vm_state',
|
'vm_state': 'OS-EXT-STS:vm_state',
|
||||||
}
|
}
|
||||||
|
# Some columns returned by openstacksdk should not be shown because they're
|
||||||
info.update(
|
# either irrelevant or duplicates
|
||||||
{
|
ignored_columns = {
|
||||||
column_map[column]: data
|
# computed columns
|
||||||
for column, data in info.items()
|
'interface_ip',
|
||||||
if column in column_map
|
'location',
|
||||||
|
'private_v4',
|
||||||
|
'private_v6',
|
||||||
|
'public_v4',
|
||||||
|
'public_v6',
|
||||||
|
# create-only columns
|
||||||
|
'block_device_mapping',
|
||||||
|
'image_id',
|
||||||
|
'max_count',
|
||||||
|
'min_count',
|
||||||
|
'scheduler_hints',
|
||||||
|
# aliases
|
||||||
|
'volumes',
|
||||||
|
# unnecessary
|
||||||
|
'links',
|
||||||
}
|
}
|
||||||
)
|
# Some columns are only present in certain responses and should not be
|
||||||
|
# shown otherwise.
|
||||||
|
optional_columns = {
|
||||||
|
'admin_password', # removed in 2.14
|
||||||
|
'fault', # only present in errored servers
|
||||||
|
'flavor_id', # removed in 2.47
|
||||||
|
'networks', # only present in create responses
|
||||||
|
'security_groups', # only present in create, detail responses
|
||||||
|
}
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
for key, value in info.items():
|
||||||
|
if key in ignored_columns:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if key in optional_columns:
|
||||||
|
if info[key] is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
alias = column_map.get(key)
|
||||||
|
data[alias or key] = value
|
||||||
|
|
||||||
|
info = data
|
||||||
|
|
||||||
# Convert the image blob to a name
|
# Convert the image blob to a name
|
||||||
image_info = info.get('image', {})
|
image_info = info.get('image', {})
|
||||||
@ -214,46 +245,57 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
|
|||||||
# Convert the flavor blob to a name
|
# Convert the flavor blob to a name
|
||||||
flavor_info = info.get('flavor', {})
|
flavor_info = info.get('flavor', {})
|
||||||
# Microversion 2.47 puts the embedded flavor into the server response
|
# Microversion 2.47 puts the embedded flavor into the server response
|
||||||
# body but omits the id, so if not present we just expose the flavor
|
# body. The presence of the 'original_name' attribute indicates this.
|
||||||
# dict in the server output.
|
if flavor_info.get('original_name') is None: # microversion < 2.47
|
||||||
if 'id' in flavor_info:
|
|
||||||
flavor_id = flavor_info.get('id', '')
|
flavor_id = flavor_info.get('id', '')
|
||||||
try:
|
try:
|
||||||
flavor = utils.find_resource(compute_client.flavors, flavor_id)
|
flavor = utils.find_resource(compute_client.flavors, flavor_id)
|
||||||
info['flavor'] = "%s (%s)" % (flavor.name, flavor_id)
|
info['flavor'] = "%s (%s)" % (flavor.name, flavor_id)
|
||||||
except Exception:
|
except Exception:
|
||||||
info['flavor'] = flavor_id
|
info['flavor'] = flavor_id
|
||||||
else:
|
else: # microversion >= 2.47
|
||||||
info['flavor'] = format_columns.DictColumn(flavor_info)
|
info['flavor'] = format_columns.DictColumn(flavor_info)
|
||||||
|
|
||||||
if 'os-extended-volumes:volumes_attached' in info:
|
# there's a lot of redundant information in BDMs - strip it
|
||||||
|
if 'volumes_attached' in info:
|
||||||
info.update(
|
info.update(
|
||||||
{
|
{
|
||||||
'volumes_attached': format_columns.ListDictColumn(
|
'volumes_attached': format_columns.ListDictColumn(
|
||||||
info.pop('os-extended-volumes:volumes_attached')
|
[
|
||||||
|
{
|
||||||
|
k: v
|
||||||
|
for k, v in volume.items()
|
||||||
|
if v is not None and k != 'location'
|
||||||
|
}
|
||||||
|
for volume in info.pop('volumes_attached') or []
|
||||||
|
]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if 'security_groups' in info:
|
if 'security_groups' in info:
|
||||||
info.update(
|
info.update(
|
||||||
{
|
{
|
||||||
'security_groups': format_columns.ListDictColumn(
|
'security_groups': format_columns.ListDictColumn(
|
||||||
info.pop('security_groups')
|
info.pop('security_groups'),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if 'tags' in info:
|
if 'tags' in info:
|
||||||
info.update({'tags': format_columns.ListColumn(info.pop('tags'))})
|
info.update({'tags': format_columns.ListColumn(info.pop('tags'))})
|
||||||
|
|
||||||
# NOTE(dtroyer): novaclient splits these into separate entries...
|
# Map 'networks' to 'addresses', if present. Note that the 'networks' key
|
||||||
# Format addresses in a useful way
|
# is used for create responses, otherwise it's 'addresses'. We know it'll
|
||||||
info['addresses'] = (
|
# be set because this is one of our optional columns.
|
||||||
AddressesColumn(info['addresses'])
|
if 'networks' in info:
|
||||||
if 'addresses' in info
|
info['addresses'] = format_columns.DictListColumn(
|
||||||
else format_columns.DictListColumn(info.get('networks'))
|
info.pop('networks', {}),
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
info['addresses'] = AddressesColumn(info.get('addresses', {}))
|
||||||
|
|
||||||
# Map 'metadata' field to 'properties'
|
# Map 'metadata' field to 'properties' and format
|
||||||
info['properties'] = format_columns.DictColumn(info.pop('metadata'))
|
info['properties'] = format_columns.DictColumn(info.pop('metadata'))
|
||||||
|
|
||||||
# Migrate tenant_id to project_id naming
|
# Migrate tenant_id to project_id naming
|
||||||
@ -266,9 +308,6 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
|
|||||||
info['OS-EXT-STS:power_state']
|
info['OS-EXT-STS:power_state']
|
||||||
)
|
)
|
||||||
|
|
||||||
# Remove values that are long and not too useful
|
|
||||||
info.pop('links', None)
|
|
||||||
|
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
|
@ -1313,7 +1313,6 @@ class TestServerCreate(TestServer):
|
|||||||
'id',
|
'id',
|
||||||
'image',
|
'image',
|
||||||
'name',
|
'name',
|
||||||
'networks',
|
|
||||||
'properties',
|
'properties',
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1327,7 +1326,6 @@ class TestServerCreate(TestServer):
|
|||||||
self.new_server.id,
|
self.new_server.id,
|
||||||
self.image.name + ' (' + self.new_server.image.get('id') + ')',
|
self.image.name + ' (' + self.new_server.image.get('id') + ')',
|
||||||
self.new_server.name,
|
self.new_server.name,
|
||||||
self.new_server.networks,
|
|
||||||
format_columns.DictColumn(self.new_server.metadata),
|
format_columns.DictColumn(self.new_server.metadata),
|
||||||
)
|
)
|
||||||
return datalist
|
return datalist
|
||||||
@ -2310,7 +2308,7 @@ class TestServerCreate(TestServer):
|
|||||||
self.new_server.name, self.image, self.flavor, **kwargs
|
self.new_server.name, self.image, self.flavor, **kwargs
|
||||||
)
|
)
|
||||||
self.assertEqual(self.columns, columns)
|
self.assertEqual(self.columns, columns)
|
||||||
self.assertEqual(self.datalist(), data)
|
self.assertTupleEqual(self.datalist(), data)
|
||||||
|
|
||||||
@mock.patch.object(common_utils, 'wait_for_status', return_value=False)
|
@mock.patch.object(common_utils, 'wait_for_status', return_value=False)
|
||||||
def test_server_create_with_wait_fails(self, mock_wait_for_status):
|
def test_server_create_with_wait_fails(self, mock_wait_for_status):
|
||||||
@ -8209,7 +8207,7 @@ class TestServerShow(TestServer):
|
|||||||
'image': {'id': self.image.id},
|
'image': {'id': self.image.id},
|
||||||
'flavor': {'id': self.flavor.id},
|
'flavor': {'id': self.flavor.id},
|
||||||
'tenant_id': 'tenant-id-xxx',
|
'tenant_id': 'tenant-id-xxx',
|
||||||
'networks': {'public': ['10.20.30.40', '2001:db8::f']},
|
'addresses': {'public': ['10.20.30.40', '2001:db8::f']},
|
||||||
}
|
}
|
||||||
self.compute_sdk_client.get_server_diagnostics.return_value = {
|
self.compute_sdk_client.get_server_diagnostics.return_value = {
|
||||||
'test': 'test'
|
'test': 'test'
|
||||||
@ -8236,7 +8234,6 @@ class TestServerShow(TestServer):
|
|||||||
'id',
|
'id',
|
||||||
'image',
|
'image',
|
||||||
'name',
|
'name',
|
||||||
'networks',
|
|
||||||
'project_id',
|
'project_id',
|
||||||
'properties',
|
'properties',
|
||||||
)
|
)
|
||||||
@ -8245,12 +8242,11 @@ class TestServerShow(TestServer):
|
|||||||
server.PowerStateColumn(
|
server.PowerStateColumn(
|
||||||
getattr(self.server, 'OS-EXT-STS:power_state')
|
getattr(self.server, 'OS-EXT-STS:power_state')
|
||||||
),
|
),
|
||||||
format_columns.DictListColumn(self.server.networks),
|
|
||||||
self.flavor.name + " (" + self.flavor.id + ")",
|
self.flavor.name + " (" + self.flavor.id + ")",
|
||||||
self.server.id,
|
self.server.id,
|
||||||
self.image.name + " (" + self.image.id + ")",
|
self.image.name + " (" + self.image.id + ")",
|
||||||
self.server.name,
|
self.server.name,
|
||||||
{'public': ['10.20.30.40', '2001:db8::f']},
|
server.AddressesColumn({'public': ['10.20.30.40', '2001:db8::f']}),
|
||||||
'tenant-id-xxx',
|
'tenant-id-xxx',
|
||||||
format_columns.DictColumn({}),
|
format_columns.DictColumn({}),
|
||||||
)
|
)
|
||||||
@ -9059,7 +9055,7 @@ class TestServerGeneral(TestServer):
|
|||||||
'image': {u'id': _image.id},
|
'image': {u'id': _image.id},
|
||||||
'flavor': {u'id': _flavor.id},
|
'flavor': {u'id': _flavor.id},
|
||||||
'tenant_id': u'tenant-id-xxx',
|
'tenant_id': u'tenant-id-xxx',
|
||||||
'networks': {u'public': [u'10.20.30.40', u'2001:db8::f']},
|
'addresses': {u'public': [u'10.20.30.40', u'2001:db8::f']},
|
||||||
'links': u'http://xxx.yyy.com',
|
'links': u'http://xxx.yyy.com',
|
||||||
'properties': '',
|
'properties': '',
|
||||||
'volumes_attached': [{"id": "6344fe9d-ef20-45b2-91a6"}],
|
'volumes_attached': [{"id": "6344fe9d-ef20-45b2-91a6"}],
|
||||||
@ -9079,7 +9075,7 @@ class TestServerGeneral(TestServer):
|
|||||||
),
|
),
|
||||||
'properties': '',
|
'properties': '',
|
||||||
'volumes_attached': [{"id": "6344fe9d-ef20-45b2-91a6"}],
|
'volumes_attached': [{"id": "6344fe9d-ef20-45b2-91a6"}],
|
||||||
'addresses': format_columns.DictListColumn(_server.networks),
|
'addresses': format_columns.DictListColumn(_server.addresses),
|
||||||
'project_id': 'tenant-id-xxx',
|
'project_id': 'tenant-id-xxx',
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9089,8 +9085,6 @@ class TestServerGeneral(TestServer):
|
|||||||
self.image_client,
|
self.image_client,
|
||||||
_server,
|
_server,
|
||||||
)
|
)
|
||||||
# 'networks' is used to create _server. Remove it.
|
|
||||||
server_detail.pop('networks')
|
|
||||||
|
|
||||||
# Check the results.
|
# Check the results.
|
||||||
self.assertCountEqual(info, server_detail)
|
self.assertCountEqual(info, server_detail)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user