[FUP] Follow-up patch for SR-IOV live migration
This commit addresses some of the non-blocking comments/nits in[1]. Main changes: - Add 'source' property to InstancePCIRequest object which contains the source of the request i.e. flavor alias or neutron port. this avoids duplication of logic and comments in the code. - Move class method create_skeleton_migrate_vifs from LiveMigrateData object to VIFMigrateData object as frankly its more sensible to have it there. - Separate unit test, test__claim_pci_for_instance_vifs, to two separate unit tests for clarity. - Some trivial nits and typos. [1] https://review.opendev.org/#/c/620115/ Change-Id: I292a0e2d840bbf657ba6d0932f9a3decbcb2778f
This commit is contained in:
parent
9b98bbd312
commit
7824909048
@ -6298,7 +6298,7 @@ class ComputeManager(manager.Manager):
|
||||
dest_check_data)
|
||||
# Create migrate_data vifs
|
||||
migrate_data.vifs = \
|
||||
migrate_data_obj.LiveMigrateData.create_skeleton_migrate_vifs(
|
||||
migrate_data_obj.VIFMigrateData.create_skeleton_migrate_vifs(
|
||||
instance.get_network_info())
|
||||
# Claim PCI devices for VIFs on destination (if needed)
|
||||
port_id_to_pci = self._claim_pci_for_instance_vifs(ctxt, instance)
|
||||
|
@ -309,13 +309,11 @@ class ResourceTracker(object):
|
||||
new_pci_requests = pci_request.get_pci_requests_from_flavor(
|
||||
new_instance_type)
|
||||
new_pci_requests.instance_uuid = instance.uuid
|
||||
# PCI requests come from two sources: instance flavor and
|
||||
# SR-IOV ports. SR-IOV ports pci_request don't have an alias_name.
|
||||
# On resize merge the SR-IOV ports pci_requests with the new
|
||||
# instance flavor pci_requests.
|
||||
# On resize merge the SR-IOV ports pci_requests
|
||||
# with the new instance flavor pci_requests.
|
||||
if instance.pci_requests:
|
||||
for request in instance.pci_requests.requests:
|
||||
if request.alias_name is None:
|
||||
if request.source == objects.InstancePCIRequest.NEUTRON_PORT:
|
||||
new_pci_requests.requests.append(request)
|
||||
claim = claims.MoveClaim(context, instance, nodename,
|
||||
new_instance_type, image_meta, self, cn,
|
||||
|
@ -214,14 +214,8 @@ class LiveMigrationTask(base.TaskBase):
|
||||
return
|
||||
|
||||
for pci_request in self.instance.pci_requests.requests:
|
||||
if pci_request.alias_name is not None:
|
||||
if pci_request.source != objects.InstancePCIRequest.NEUTRON_PORT:
|
||||
# allow only VIF related PCI requests in live migration.
|
||||
# PCI requests come from two sources: instance flavor and
|
||||
# SR-IOV ports.
|
||||
# SR-IOV ports pci_request don't have an alias_name.
|
||||
# TODO(adrianc): add an is_sriov_port property to PCIRequest
|
||||
# to make this cryptic check clearer (also in resource_tracker)
|
||||
|
||||
raise exception.MigrationPreCheckError(
|
||||
reason= "non-VIF related PCI requests for instance "
|
||||
"are not allowed for live migration.")
|
||||
@ -232,6 +226,7 @@ class LiveMigrationTask(base.TaskBase):
|
||||
raise exception.MigrationPreCheckError(
|
||||
reason="Cannot live migrate VIF with related PCI, Neutron "
|
||||
"does not support required port binding extension.")
|
||||
|
||||
if not (supports_vif_related_pci_allocations(self.context,
|
||||
src_host) and
|
||||
supports_vif_related_pci_allocations(self.context,
|
||||
@ -340,8 +335,8 @@ class LiveMigrationTask(base.TaskBase):
|
||||
# migrate data vifs were not constructed in dest compute
|
||||
# during check_can_live_migrate_destination, construct a
|
||||
# skeleton to be updated after port binding.
|
||||
# TODO(adrianc): This can be removed once we move to T release
|
||||
self.migrate_data.vifs = migrate_data_obj.LiveMigrateData.\
|
||||
# TODO(adrianc): This can be removed once we move to U release
|
||||
self.migrate_data.vifs = migrate_data_obj.VIFMigrateData.\
|
||||
create_skeleton_migrate_vifs(
|
||||
self.instance.get_network_info())
|
||||
bindings = self._bind_ports_on_destination(destination)
|
||||
@ -356,7 +351,7 @@ class LiveMigrationTask(base.TaskBase):
|
||||
# that was bound. This information is then stuffed into the
|
||||
# migrate_data.
|
||||
try:
|
||||
# Note(adrianc): migrate_data.vifs was partially filled
|
||||
# NOTE(adrianc): migrate_data.vifs was partially filled
|
||||
# by destination compute if compute is new enough.
|
||||
# if that is the case, it may have updated the required port
|
||||
# profile for the destination node (e.g new PCI address if SR-IOV)
|
||||
@ -372,7 +367,8 @@ class LiveMigrationTask(base.TaskBase):
|
||||
for mig_vif in migrate_vifs_with_profile}
|
||||
|
||||
bindings = self.network_api.bind_ports_to_host(
|
||||
self.context, self.instance, destination, None, ports_profile)
|
||||
context=self.context, instance=self.instance, host=destination,
|
||||
vnic_types=None, port_profiles=ports_profile)
|
||||
except exception.PortBindingFailed as e:
|
||||
# Port binding failed for that host, try another one.
|
||||
raise exception.MigrationPreCheckError(
|
||||
|
@ -28,6 +28,12 @@ class InstancePCIRequest(base.NovaObject,
|
||||
# Version 1.3: Add requester_id
|
||||
VERSION = '1.3'
|
||||
|
||||
# Possible sources for a PCI request:
|
||||
# FLAVOR_ALIAS : Request originated from a flavor alias.
|
||||
# NEUTRON_PORT : Request originated from a neutron port.
|
||||
FLAVOR_ALIAS = 0
|
||||
NEUTRON_PORT = 1
|
||||
|
||||
fields = {
|
||||
'count': fields.IntegerField(),
|
||||
'spec': fields.ListOfDictOfNullableStringsField(),
|
||||
@ -40,6 +46,14 @@ class InstancePCIRequest(base.NovaObject,
|
||||
'numa_policy': fields.PCINUMAAffinityPolicyField(nullable=True),
|
||||
}
|
||||
|
||||
@property
|
||||
def source(self):
|
||||
# PCI requests originate from two sources: instance flavor alias and
|
||||
# neutron SR-IOV ports.
|
||||
# SR-IOV ports pci_request don't have an alias_name.
|
||||
return (InstancePCIRequest.NEUTRON_PORT if self.alias_name is None
|
||||
else InstancePCIRequest.FLAVOR_ALIAS)
|
||||
|
||||
def obj_load_attr(self, attr):
|
||||
setattr(self, attr, None)
|
||||
|
||||
|
@ -94,6 +94,21 @@ class VIFMigrateData(obj_base.NovaObject):
|
||||
vif['details'] = self.vif_details
|
||||
return vif
|
||||
|
||||
@classmethod
|
||||
def create_skeleton_migrate_vifs(cls, vifs):
|
||||
"""Create migrate vifs for live migration.
|
||||
|
||||
:param vifs: a list of VIFs.
|
||||
:return: list of VIFMigrateData object corresponding to the provided
|
||||
VIFs.
|
||||
"""
|
||||
vif_mig_data = []
|
||||
|
||||
for vif in vifs:
|
||||
mig_vif = cls(port_id=vif['id'], source_vif=vif)
|
||||
vif_mig_data.append(mig_vif)
|
||||
return vif_mig_data
|
||||
|
||||
|
||||
@obj_base.NovaObjectRegistry.register_if(False)
|
||||
class LiveMigrateData(obj_base.NovaObject):
|
||||
@ -120,23 +135,6 @@ class LiveMigrateData(obj_base.NovaObject):
|
||||
'vifs': fields.ListOfObjectsField('VIFMigrateData'),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def create_skeleton_migrate_vifs(vifs):
|
||||
"""Create migrate vifs for live migration.
|
||||
|
||||
:param vifs: a list of VIFs.
|
||||
:return: list of VIFMigrateData object corresponding to the provided
|
||||
VIFs.
|
||||
"""
|
||||
vif_mig_data = []
|
||||
|
||||
for vif in vifs:
|
||||
mig_vif = VIFMigrateData(
|
||||
port_id=vif['id'],
|
||||
source_vif=vif)
|
||||
vif_mig_data.append(mig_vif)
|
||||
return vif_mig_data
|
||||
|
||||
|
||||
@obj_base.NovaObjectRegistry.register
|
||||
class LibvirtLiveMigrateBDMInfo(obj_base.NovaObject):
|
||||
|
@ -2716,7 +2716,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase,
|
||||
'cleanup_live_migration_destination_check'),
|
||||
mock.patch.object(db, 'instance_fault_create'),
|
||||
mock.patch.object(compute_utils, 'EventReporter'),
|
||||
mock.patch.object(migrate_data_obj.LiveMigrateData,
|
||||
mock.patch.object(migrate_data_obj.VIFMigrateData,
|
||||
'create_skeleton_migrate_vifs'),
|
||||
mock.patch.object(instance, 'get_network_info'),
|
||||
mock.patch.object(self.compute, '_claim_pci_for_instance_vifs'),
|
||||
@ -8911,7 +8911,7 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase,
|
||||
# (_error_out_instance_on_exception will set to ACTIVE by default).
|
||||
self.assertEqual(vm_states.STOPPED, instance.vm_state)
|
||||
|
||||
def test__claim_pci_for_instance_vifs(self):
|
||||
def test__claim_pci_for_instance_no_vifs(self):
|
||||
@mock.patch.object(self.compute, 'rt')
|
||||
@mock.patch.object(pci_request, 'get_instance_pci_request_from_vif')
|
||||
@mock.patch.object(self.instance, 'get_network_info')
|
||||
@ -8925,6 +8925,16 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase,
|
||||
self.instance)
|
||||
rt_mock.claim_pci_devices.assert_not_called()
|
||||
self.assertEqual(0, len(port_id_to_pci))
|
||||
|
||||
_test()
|
||||
|
||||
def test__claim_pci_for_instance_vifs(self):
|
||||
@mock.patch.object(self.compute, 'rt')
|
||||
@mock.patch.object(pci_request, 'get_instance_pci_request_from_vif')
|
||||
@mock.patch.object(self.instance, 'get_network_info')
|
||||
def _test(mock_get_network_info,
|
||||
mock_get_instance_pci_request_from_vif,
|
||||
rt_mock):
|
||||
# when there are VIFs, expect only ones with related PCI to be
|
||||
# claimed and their migrate vif profile to be updated.
|
||||
|
||||
@ -9001,7 +9011,7 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase,
|
||||
vendor_id='15b3',
|
||||
product_id='1018')
|
||||
port_id_to_pci_dev = {uuids.port0: pci_dev}
|
||||
mig_vifs = migrate_data_obj.LiveMigrateData.\
|
||||
mig_vifs = migrate_data_obj.VIFMigrateData.\
|
||||
create_skeleton_migrate_vifs(nw_vifs)
|
||||
self.compute._update_migrate_vifs_profile_with_pci(mig_vifs,
|
||||
port_id_to_pci_dev)
|
||||
|
@ -181,6 +181,24 @@ class _TestInstancePCIRequests(object):
|
||||
self.assertNotIn('requester_id', primitive['nova_object.data'])
|
||||
self.assertIn('numa_policy', primitive['nova_object.data'])
|
||||
|
||||
def test_source_property(self):
|
||||
neutron_port_pci_req = objects.InstancePCIRequest(
|
||||
count=1,
|
||||
spec=[{'vendor_id': '15b3', 'device_id': '1018'}],
|
||||
request_id=uuids.pci_request_id1,
|
||||
requester_id=uuids.requester_id1,
|
||||
alias_name = None)
|
||||
flavor_alias_pci_req = objects.InstancePCIRequest(
|
||||
count=1,
|
||||
spec=[{'vendor_id': '15b3', 'device_id': '1810'}],
|
||||
request_id=uuids.pci_request_id2,
|
||||
requester_id=uuids.requester_id2,
|
||||
alias_name = 'alias_1')
|
||||
self.assertEqual(neutron_port_pci_req.source,
|
||||
objects.InstancePCIRequest.NEUTRON_PORT)
|
||||
self.assertEqual(flavor_alias_pci_req.source,
|
||||
objects.InstancePCIRequest.FLAVOR_ALIAS)
|
||||
|
||||
|
||||
class TestInstancePCIRequests(test_objects._LocalTest,
|
||||
_TestInstancePCIRequests):
|
||||
|
@ -44,15 +44,7 @@ class _TestLiveMigrateData(object):
|
||||
|
||||
class TestLiveMigrateData(test_objects._LocalTest,
|
||||
_TestLiveMigrateData):
|
||||
def test_create_skeleton_migrate_vifs(self):
|
||||
vifs = [
|
||||
network_model.VIF(id=uuids.port1),
|
||||
network_model.VIF(id=uuids.port2)]
|
||||
mig_vifs = migrate_data.LiveMigrateData.create_skeleton_migrate_vifs(
|
||||
vifs)
|
||||
self.assertEqual(len(vifs), len(mig_vifs))
|
||||
self.assertEqual([vif['id'] for vif in vifs],
|
||||
[mig_vif.port_id for mig_vif in mig_vifs])
|
||||
pass
|
||||
|
||||
|
||||
class TestRemoteLiveMigrateData(test_objects._RemoteTest,
|
||||
@ -311,3 +303,13 @@ class TestVIFMigrateData(test.NoDBTestCase):
|
||||
self.assertEqual(migrate_vif.vif_details, dest_vif['details'])
|
||||
self.assertEqual(migrate_vif.profile, dest_vif['profile'])
|
||||
self.assertEqual(uuids.ovs_interfaceid, dest_vif['ovs_interfaceid'])
|
||||
|
||||
def test_create_skeleton_migrate_vifs(self):
|
||||
vifs = [
|
||||
network_model.VIF(id=uuids.port1),
|
||||
network_model.VIF(id=uuids.port2)]
|
||||
mig_vifs = migrate_data.VIFMigrateData.create_skeleton_migrate_vifs(
|
||||
vifs)
|
||||
self.assertEqual(len(vifs), len(mig_vifs))
|
||||
self.assertEqual([vif['id'] for vif in vifs],
|
||||
[mig_vif.port_id for mig_vif in mig_vifs])
|
||||
|
Loading…
x
Reference in New Issue
Block a user