Skip to content

Commit 4eafc9d

Browse files
author
Balazs Gibizer
committed
Func test for failed and aborted live migration
The failed case covers the situation when the IntancePCIRequest cannot be updated with the PF device names on the target host due to incorrect naming of the device RPs in placement. The abort case covers when the API user cancels the running live migration. Change-Id: I1222fc21bde4158df1db70370c7f3bd319ec081f blueprint: support-move-ops-with-qos-ports-ussuri
1 parent a948a80 commit 4eafc9d

File tree

2 files changed

+149
-10
lines changed

2 files changed

+149
-10
lines changed

nova/tests/functional/test_servers.py

Lines changed: 138 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5838,6 +5838,26 @@ def _delete_server_and_check_allocations(
58385838
binding_profile = updated_qos_sriov_port['binding:profile']
58395839
self.assertNotIn('allocation', binding_profile)
58405840

5841+
def _create_server_with_ports_and_check_allocation(
5842+
self, non_qos_normal_port, qos_normal_port, qos_sriov_port):
5843+
server = self._create_server_with_ports(
5844+
non_qos_normal_port, qos_normal_port, qos_sriov_port)
5845+
# check that the server allocates from the current host properly
5846+
self._check_allocation(
5847+
server, self.compute1_rp_uuid, non_qos_normal_port,
5848+
qos_normal_port, qos_sriov_port, self.flavor_with_group_policy)
5849+
return server
5850+
5851+
def _assert_pci_request_pf_device_name(self, server, device_name):
5852+
ctxt = context.get_admin_context()
5853+
pci_requests = objects.InstancePCIRequests.get_by_instance_uuid(
5854+
ctxt, server['id'])
5855+
self.assertEqual(1, len(pci_requests.requests))
5856+
self.assertEqual(1, len(pci_requests.requests[0].spec))
5857+
self.assertEqual(
5858+
device_name,
5859+
pci_requests.requests[0].spec[0]['parent_ifname'])
5860+
58415861
def _turn_off_api_check(self):
58425862
# The API actively rejecting the move operations with resource
58435863
# request so we have to turn off that check.
@@ -7394,20 +7414,128 @@ def test_live_migrate_with_qos_port_reschedule_fails(self):
73947414

73957415
# Assert that the InstancePCIRequests also rolled back to point to
73967416
# host1
7397-
ctxt = context.get_admin_context()
7398-
pci_requests = objects.InstancePCIRequests.get_by_instance_uuid(
7399-
ctxt, server['id'])
7400-
self.assertEqual(1, len(pci_requests.requests))
7401-
self.assertEqual(1, len(pci_requests.requests[0].spec))
7402-
self.assertEqual(
7403-
'host1-ens2',
7404-
pci_requests.requests[0].spec[0]['parent_ifname'])
7417+
self._assert_pci_request_pf_device_name(server, 'host1-ens2')
74057418

74067419
self._delete_server_and_check_allocations(
74077420
server, qos_normal_port, qos_sriov_port)
74087421

7409-
# TODO(gibi): add tests for live migration cases:
7410-
# * abort / cancel -> dest / pci request cleanup?
7422+
def test_live_migrate_with_qos_port_pci_update_fails(self):
7423+
# TODO(gibi): remove this when live migration is fully supported and
7424+
# therefore the check is removed from the api
7425+
self._turn_off_api_check()
7426+
7427+
# Update the name of the network device RP of PF2 on host2 to something
7428+
# unexpected. This will cause
7429+
# update_pci_request_spec_with_allocated_interface_name() to raise
7430+
# when the instance is live migrated to the host2.
7431+
rsp = self.placement_api.put(
7432+
'/resource_providers/%s'
7433+
% self.sriov_dev_rp_per_host[self.compute2_rp_uuid][self.PF2],
7434+
{"name": "invalid-device-rp-name"})
7435+
self.assertEqual(200, rsp.status)
7436+
7437+
non_qos_normal_port = self.neutron.port_1
7438+
qos_normal_port = self.neutron.port_with_resource_request
7439+
qos_sriov_port = self.neutron.port_with_sriov_resource_request
7440+
7441+
server = self._create_server_with_ports_and_check_allocation(
7442+
non_qos_normal_port, qos_normal_port, qos_sriov_port)
7443+
7444+
self.api.post_server_action(
7445+
server['id'],
7446+
{
7447+
'os-migrateLive': {
7448+
'host': None,
7449+
'block_migration': 'auto'
7450+
}
7451+
}
7452+
)
7453+
7454+
# pci update will fail after scheduling to host2
7455+
self._wait_for_migration_status(server, ['error'])
7456+
server = self._wait_for_server_parameter(
7457+
server,
7458+
{'OS-EXT-SRV-ATTR:host': 'host1',
7459+
'status': 'ERROR'})
7460+
self.assertIn(
7461+
'does not have a properly formatted name',
7462+
server['fault']['message'])
7463+
7464+
self._check_allocation(
7465+
server, self.compute1_rp_uuid, non_qos_normal_port,
7466+
qos_normal_port, qos_sriov_port, self.flavor_with_group_policy)
7467+
7468+
# Assert that the InstancePCIRequests still point to host1
7469+
self._assert_pci_request_pf_device_name(server, 'host1-ens2')
7470+
7471+
self._delete_server_and_check_allocations(
7472+
server, qos_normal_port, qos_sriov_port)
7473+
7474+
7475+
class LiveMigrateAbortWithPortResourceRequestTest(
7476+
PortResourceRequestBasedSchedulingTestBase):
7477+
7478+
compute_driver = "fake.FakeLiveMigrateDriverWithPciResources"
7479+
7480+
def setUp(self):
7481+
# Use a custom weigher to make sure that we have a predictable host
7482+
# order in the alternate list returned by the scheduler for migration.
7483+
self.useFixture(nova_fixtures.HostNameWeigherFixture())
7484+
super(LiveMigrateAbortWithPortResourceRequestTest, self).setUp()
7485+
self.compute2 = self._start_compute('host2')
7486+
self.compute2_rp_uuid = self._get_provider_uuid_by_host('host2')
7487+
self._create_networking_rp_tree('host2', self.compute2_rp_uuid)
7488+
self.compute2_service_id = self.admin_api.get_services(
7489+
host='host2', binary='nova-compute')[0]['id']
7490+
7491+
def test_live_migrate_with_qos_port_abort_migration(self):
7492+
# TODO(gibi): remove this when live migration is fully supported and
7493+
# therefore the check is removed from the api
7494+
self._turn_off_api_check()
7495+
7496+
non_qos_normal_port = self.neutron.port_1
7497+
qos_normal_port = self.neutron.port_with_resource_request
7498+
qos_sriov_port = self.neutron.port_with_sriov_resource_request
7499+
7500+
server = self._create_server_with_ports_and_check_allocation(
7501+
non_qos_normal_port, qos_normal_port, qos_sriov_port)
7502+
7503+
# The special virt driver will keep the live migration running until it
7504+
# is aborted.
7505+
self.api.post_server_action(
7506+
server['id'],
7507+
{
7508+
'os-migrateLive': {
7509+
'host': None,
7510+
'block_migration': 'auto'
7511+
}
7512+
}
7513+
)
7514+
7515+
# wait for the migration to start
7516+
migration = self._wait_for_migration_status(server, ['running'])
7517+
7518+
# delete the migration to abort it
7519+
self.api.delete_migration(server['id'], migration['id'])
7520+
7521+
self._wait_for_migration_status(server, ['cancelled'])
7522+
self._wait_for_server_parameter(
7523+
server,
7524+
{'OS-EXT-SRV-ATTR:host': 'host1',
7525+
'status': 'ACTIVE'})
7526+
7527+
self._check_allocation(
7528+
server, self.compute1_rp_uuid, non_qos_normal_port,
7529+
qos_normal_port, qos_sriov_port, self.flavor_with_group_policy)
7530+
7531+
# Assert that the InstancePCIRequests rolled back to point to host1
7532+
# This assert is fails now as the abort does not change the PCI device
7533+
# back
7534+
# TODO(gibi): come up with an idea to fix this
7535+
# self._assert_pci_request_pf_device_name(server, 'host1-ens2')
7536+
7537+
self._delete_server_and_check_allocations(
7538+
server, qos_normal_port, qos_sriov_port)
74117539

74127540

74137541
class PortResourceRequestReSchedulingTest(

nova/virt/fake.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,17 @@ def get_available_resource(self, nodename):
10301030
return host_status
10311031

10321032

1033+
class FakeLiveMigrateDriverWithPciResources(
1034+
FakeLiveMigrateDriver, FakeDriverWithPciResources):
1035+
"""FakeDriver derivative to handle force_complete and abort calls.
1036+
1037+
This module serves those tests that need to abort or force-complete
1038+
the live migration, thus the live migration will never be finished
1039+
without the force_complete_migration or delete_migration API calls.
1040+
1041+
"""
1042+
1043+
10331044
class FakeDriverWithCaching(FakeDriver):
10341045
def __init__(self, *a, **k):
10351046
super(FakeDriverWithCaching, self).__init__(*a, **k)

0 commit comments

Comments
 (0)