Correct REST API response fields for /os-migrations API

The compute APIs are unfortunately inconsistent with regard to the
response parameters for migrations.

* GET /servers/{server_id}/migrations returns server_uuid
* GET /os-migrations returns instance_uuid

Because the 'Server UUID' column is being specified for parsing the
response from GET /os-migrations, it is always showing as an empty
string to users.

There are a few other mismatches between the column names and the REST
API response fields [1]:

* 'Old Flavor' vs 'old_instance_type_id'
* 'New Flavor' vs 'new_instance_type_id'
* 'Type' vs 'migration_type'

This adds a new list containing the REST API response field names to
pass to utils.get_item_properties so that the responses are correctly
parsed and the client output contains the response data instead of
empty strings.

Story: 2009078
Task: 42890

[1] https://docs.openstack.org/api-ref/compute/?expanded=list-migrations-detail#list-migrations

Change-Id: I8aab60619e0225047f6a1c31e44917ca8fcc799e
This commit is contained in:
melanie witt 2021-07-26 22:13:55 +00:00
parent 59256becc9
commit ed87f7949e
3 changed files with 77 additions and 12 deletions

View File

@ -2781,28 +2781,41 @@ class ListMigration(command.Lister):
return parser return parser
def print_migrations(self, parsed_args, compute_client, migrations): def print_migrations(self, parsed_args, compute_client, migrations):
columns = [ column_headers = [
'Source Node', 'Dest Node', 'Source Compute', 'Dest Compute', 'Source Node', 'Dest Node', 'Source Compute', 'Dest Compute',
'Dest Host', 'Status', 'Server UUID', 'Old Flavor', 'New Flavor', 'Dest Host', 'Status', 'Server UUID', 'Old Flavor', 'New Flavor',
'Created At', 'Updated At', 'Created At', 'Updated At',
] ]
# Response fields coming back from the REST API are not always exactly
# the same as the column header names.
columns = [
'source_node', 'dest_node', 'source_compute', 'dest_compute',
'dest_host', 'status', 'instance_uuid', 'old_instance_type_id',
'new_instance_type_id', 'created_at', 'updated_at',
]
# Insert migrations UUID after ID # Insert migrations UUID after ID
if compute_client.api_version >= api_versions.APIVersion("2.59"): if compute_client.api_version >= api_versions.APIVersion("2.59"):
columns.insert(0, "UUID") column_headers.insert(0, "UUID")
columns.insert(0, "uuid")
if compute_client.api_version >= api_versions.APIVersion("2.23"): if compute_client.api_version >= api_versions.APIVersion("2.23"):
columns.insert(0, "Id") column_headers.insert(0, "Id")
columns.insert(len(columns) - 2, "Type") columns.insert(0, "id")
column_headers.insert(len(column_headers) - 2, "Type")
columns.insert(len(columns) - 2, "migration_type")
if compute_client.api_version >= api_versions.APIVersion("2.80"): if compute_client.api_version >= api_versions.APIVersion("2.80"):
if parsed_args.project: if parsed_args.project:
columns.insert(len(columns) - 2, "Project") column_headers.insert(len(column_headers) - 2, "Project")
columns.insert(len(columns) - 2, "project_id")
if parsed_args.user: if parsed_args.user:
columns.insert(len(columns) - 2, "User") column_headers.insert(len(column_headers) - 2, "User")
columns.insert(len(columns) - 2, "user_id")
return ( return (
columns, column_headers,
(utils.get_item_properties(mig, columns) for mig in migrations), (utils.get_item_properties(mig, columns) for mig in migrations),
) )

View File

@ -1587,20 +1587,20 @@ class FakeMigration(object):
migration_info = { migration_info = {
"dest_host": "10.0.2.15", "dest_host": "10.0.2.15",
"status": "migrating", "status": "migrating",
"type": "migration", "migration_type": "migration",
"updated_at": "2017-01-31T08:03:25.000000", "updated_at": "2017-01-31T08:03:25.000000",
"created_at": "2017-01-31T08:03:21.000000", "created_at": "2017-01-31T08:03:21.000000",
"dest_compute": "compute-" + uuid.uuid4().hex, "dest_compute": "compute-" + uuid.uuid4().hex,
"id": random.randint(1, 999), "id": random.randint(1, 999),
"source_node": "node-" + uuid.uuid4().hex, "source_node": "node-" + uuid.uuid4().hex,
"server": uuid.uuid4().hex, "instance_uuid": uuid.uuid4().hex,
"dest_node": "node-" + uuid.uuid4().hex, "dest_node": "node-" + uuid.uuid4().hex,
"source_compute": "compute-" + uuid.uuid4().hex, "source_compute": "compute-" + uuid.uuid4().hex,
"uuid": uuid.uuid4().hex, "uuid": uuid.uuid4().hex,
"old_instance_type_id": uuid.uuid4().hex, "old_instance_type_id": uuid.uuid4().hex,
"new_instance_type_id": uuid.uuid4().hex, "new_instance_type_id": uuid.uuid4().hex,
"project": uuid.uuid4().hex, "project_id": uuid.uuid4().hex,
"user": uuid.uuid4().hex "user_id": uuid.uuid4().hex
} }
# Overwrite default attributes. # Overwrite default attributes.

View File

@ -4909,6 +4909,13 @@ class TestListMigration(TestServer):
'Old Flavor', 'New Flavor', 'Created At', 'Updated At' 'Old Flavor', 'New Flavor', 'Created At', 'Updated At'
] ]
# These are the fields that come back in the response from the REST API.
MIGRATION_FIELDS = [
'source_node', 'dest_node', 'source_compute', 'dest_compute',
'dest_host', 'status', 'instance_uuid', 'old_instance_type_id',
'new_instance_type_id', 'created_at', 'updated_at'
]
def setUp(self): def setUp(self):
super(TestListMigration, self).setUp() super(TestListMigration, self).setUp()
@ -4920,7 +4927,7 @@ class TestListMigration(TestServer):
self.migrations_mock.list.return_value = self.migrations self.migrations_mock.list.return_value = self.migrations
self.data = (common_utils.get_item_properties( self.data = (common_utils.get_item_properties(
s, self.MIGRATION_COLUMNS) for s in self.migrations) s, self.MIGRATION_FIELDS) for s in self.migrations)
# Get the command object to test # Get the command object to test
self.cmd = server.ListMigration(self.app, None) self.cmd = server.ListMigration(self.app, None)
@ -4982,6 +4989,13 @@ class TestListMigrationV223(TestListMigration):
'Type', 'Created At', 'Updated At' 'Type', 'Created At', 'Updated At'
] ]
# These are the fields that come back in the response from the REST API.
MIGRATION_FIELDS = [
'id', 'source_node', 'dest_node', 'source_compute', 'dest_compute',
'dest_host', 'status', 'instance_uuid', 'old_instance_type_id',
'new_instance_type_id', 'migration_type', 'created_at', 'updated_at'
]
def setUp(self): def setUp(self):
super(TestListMigrationV223, self).setUp() super(TestListMigrationV223, self).setUp()
@ -5019,6 +5033,14 @@ class TestListMigrationV259(TestListMigration):
'Old Flavor', 'New Flavor', 'Type', 'Created At', 'Updated At' 'Old Flavor', 'New Flavor', 'Type', 'Created At', 'Updated At'
] ]
# These are the fields that come back in the response from the REST API.
MIGRATION_FIELDS = [
'id', 'uuid', 'source_node', 'dest_node', 'source_compute',
'dest_compute', 'dest_host', 'status', 'instance_uuid',
'old_instance_type_id', 'new_instance_type_id', 'migration_type',
'created_at', 'updated_at'
]
def setUp(self): def setUp(self):
super(TestListMigrationV259, self).setUp() super(TestListMigrationV259, self).setUp()
@ -5125,6 +5147,14 @@ class TestListMigrationV266(TestListMigration):
'Old Flavor', 'New Flavor', 'Type', 'Created At', 'Updated At' 'Old Flavor', 'New Flavor', 'Type', 'Created At', 'Updated At'
] ]
# These are the fields that come back in the response from the REST API.
MIGRATION_FIELDS = [
'id', 'uuid', 'source_node', 'dest_node', 'source_compute',
'dest_compute', 'dest_host', 'status', 'instance_uuid',
'old_instance_type_id', 'new_instance_type_id', 'migration_type',
'created_at', 'updated_at'
]
def setUp(self): def setUp(self):
super(TestListMigrationV266, self).setUp() super(TestListMigrationV266, self).setUp()
@ -5194,6 +5224,14 @@ class TestListMigrationV280(TestListMigration):
'Old Flavor', 'New Flavor', 'Type', 'Created At', 'Updated At' 'Old Flavor', 'New Flavor', 'Type', 'Created At', 'Updated At'
] ]
# These are the fields that come back in the response from the REST API.
MIGRATION_FIELDS = [
'id', 'uuid', 'source_node', 'dest_node', 'source_compute',
'dest_compute', 'dest_host', 'status', 'instance_uuid',
'old_instance_type_id', 'new_instance_type_id', 'migration_type',
'created_at', 'updated_at'
]
project = identity_fakes.FakeProject.create_one_project() project = identity_fakes.FakeProject.create_one_project()
user = identity_fakes.FakeUser.create_one_user() user = identity_fakes.FakeUser.create_one_user()
@ -5247,10 +5285,14 @@ class TestListMigrationV280(TestListMigration):
self.MIGRATION_COLUMNS.insert( self.MIGRATION_COLUMNS.insert(
len(self.MIGRATION_COLUMNS) - 2, "Project") len(self.MIGRATION_COLUMNS) - 2, "Project")
self.MIGRATION_FIELDS.insert(
len(self.MIGRATION_FIELDS) - 2, "project_id")
self.assertEqual(self.MIGRATION_COLUMNS, columns) self.assertEqual(self.MIGRATION_COLUMNS, columns)
self.assertEqual(tuple(self.data), tuple(data)) self.assertEqual(tuple(self.data), tuple(data))
# Clean up global variables MIGRATION_COLUMNS # Clean up global variables MIGRATION_COLUMNS
self.MIGRATION_COLUMNS.remove('Project') self.MIGRATION_COLUMNS.remove('Project')
# Clean up global variables MIGRATION_FIELDS
self.MIGRATION_FIELDS.remove('project_id')
def test_get_migrations_with_project_pre_v280(self): def test_get_migrations_with_project_pre_v280(self):
self.app.client_manager.compute.api_version = api_versions.APIVersion( self.app.client_manager.compute.api_version = api_versions.APIVersion(
@ -5309,10 +5351,14 @@ class TestListMigrationV280(TestListMigration):
self.MIGRATION_COLUMNS.insert( self.MIGRATION_COLUMNS.insert(
len(self.MIGRATION_COLUMNS) - 2, "User") len(self.MIGRATION_COLUMNS) - 2, "User")
self.MIGRATION_FIELDS.insert(
len(self.MIGRATION_FIELDS) - 2, "user_id")
self.assertEqual(self.MIGRATION_COLUMNS, columns) self.assertEqual(self.MIGRATION_COLUMNS, columns)
self.assertEqual(tuple(self.data), tuple(data)) self.assertEqual(tuple(self.data), tuple(data))
# Clean up global variables MIGRATION_COLUMNS # Clean up global variables MIGRATION_COLUMNS
self.MIGRATION_COLUMNS.remove('User') self.MIGRATION_COLUMNS.remove('User')
# Clean up global variables MIGRATION_FIELDS
self.MIGRATION_FIELDS.remove('user_id')
def test_get_migrations_with_user_pre_v280(self): def test_get_migrations_with_user_pre_v280(self):
self.app.client_manager.compute.api_version = api_versions.APIVersion( self.app.client_manager.compute.api_version = api_versions.APIVersion(
@ -5371,13 +5417,19 @@ class TestListMigrationV280(TestListMigration):
self.MIGRATION_COLUMNS.insert( self.MIGRATION_COLUMNS.insert(
len(self.MIGRATION_COLUMNS) - 2, "Project") len(self.MIGRATION_COLUMNS) - 2, "Project")
self.MIGRATION_FIELDS.insert(
len(self.MIGRATION_FIELDS) - 2, "project_id")
self.MIGRATION_COLUMNS.insert( self.MIGRATION_COLUMNS.insert(
len(self.MIGRATION_COLUMNS) - 2, "User") len(self.MIGRATION_COLUMNS) - 2, "User")
self.MIGRATION_FIELDS.insert(
len(self.MIGRATION_FIELDS) - 2, "user_id")
self.assertEqual(self.MIGRATION_COLUMNS, columns) self.assertEqual(self.MIGRATION_COLUMNS, columns)
self.assertEqual(tuple(self.data), tuple(data)) self.assertEqual(tuple(self.data), tuple(data))
# Clean up global variables MIGRATION_COLUMNS # Clean up global variables MIGRATION_COLUMNS
self.MIGRATION_COLUMNS.remove('Project') self.MIGRATION_COLUMNS.remove('Project')
self.MIGRATION_FIELDS.remove('project_id')
self.MIGRATION_COLUMNS.remove('User') self.MIGRATION_COLUMNS.remove('User')
self.MIGRATION_FIELDS.remove('user_id')
def test_get_migrations_with_project_and_user_pre_v280(self): def test_get_migrations_with_project_and_user_pre_v280(self):
self.app.client_manager.compute.api_version = api_versions.APIVersion( self.app.client_manager.compute.api_version = api_versions.APIVersion(