Merge "Allow driver to properly unplug VIFs on destination on confirm resize"

This commit is contained in:
Zuul 2019-05-24 22:14:13 +00:00 committed by Gerrit Code Review
commit 212607dc6f
3 changed files with 127 additions and 8 deletions

View File

@ -3995,6 +3995,33 @@ class ComputeManager(manager.Manager):
do_confirm_resize(context, instance, migration.id)
def _get_updated_nw_info_with_pci_mapping(self, nw_info, pci_mapping):
# NOTE(adrianc): This method returns a copy of nw_info if modifications
# are made else it returns the original nw_info.
updated_nw_info = nw_info
if nw_info and pci_mapping:
updated_nw_info = copy.deepcopy(nw_info)
for vif in updated_nw_info:
if vif['vnic_type'] in network_model.VNIC_TYPES_SRIOV:
try:
vif_pci_addr = vif['profile']['pci_slot']
new_addr = pci_mapping[vif_pci_addr].address
vif['profile']['pci_slot'] = new_addr
LOG.debug("Updating VIF's PCI address for VIF %(id)s. "
"Original value %(orig_val)s, "
"new value %(new_val)s",
{'id': vif['id'],
'orig_val': vif_pci_addr,
'new_val': new_addr})
except (KeyError, AttributeError):
with excutils.save_and_reraise_exception():
# NOTE(adrianc): This should never happen. If we
# get here it means there is some inconsistency
# with either 'nw_info' or 'pci_mapping'.
LOG.error("Unexpected error when updating network "
"information with PCI mapping.")
return updated_nw_info
def _confirm_resize(self, context, instance, migration=None):
"""Destroys the source instance."""
self._notify_about_instance_usage(context, instance,
@ -4013,9 +4040,16 @@ class ComputeManager(manager.Manager):
# NOTE(tr3buchet): tear down networks on source host
self.network_api.setup_networks_on_host(context, instance,
migration.source_compute, teardown=True)
network_info = self.network_api.get_instance_nw_info(context,
instance)
# NOTE(adrianc): Populate old PCI device in VIF profile
# to allow virt driver to properly unplug it from Hypervisor.
pci_mapping = (instance.migration_context.
get_pci_mapping_for_migration(True))
network_info = self._get_updated_nw_info_with_pci_mapping(
network_info, pci_mapping)
# TODO(mriedem): Get BDMs here and pass them to the driver.
self.driver.confirm_migration(context, migration, instance,
network_info)

View File

@ -5773,6 +5773,8 @@ class ComputeTestCase(BaseTestCase,
migration_context.migration_id = migration.id
migration_context.old_numa_topology = old_inst_topology
migration_context.new_numa_topology = new_inst_topology
migration_context.old_pci_devices = None
migration_context.new_pci_devices = None
instance.migration_context = migration_context
instance.vm_state = vm_states.RESIZED
@ -5809,12 +5811,14 @@ class ComputeTestCase(BaseTestCase,
old_pci_devices = objects.PciDeviceList(
objects=[objects.PciDevice(vendor_id='1377',
product_id='0047',
address='0000:0a:00.1')])
address='0000:0a:00.1',
request_id=uuids.req1)])
new_pci_devices = objects.PciDeviceList(
objects=[objects.PciDevice(vendor_id='1377',
product_id='0047',
address='0000:0b:00.1')])
address='0000:0b:00.1',
request_id=uuids.req2)])
if expected_pci_addr == old_pci_devices[0].address:
expected_pci_device = old_pci_devices[0]
@ -8230,7 +8234,10 @@ class ComputeTestCase(BaseTestCase,
self.compute.confirm_resize(self.context, instance=instance,
migration=migration)
def test_allow_confirm_resize_on_instance_in_deleting_task_state(self):
@mock.patch.object(objects.MigrationContext,
'get_pci_mapping_for_migration')
def test_allow_confirm_resize_on_instance_in_deleting_task_state(
self, mock_pci_mapping):
instance = self._create_fake_instance_obj()
old_type = instance.flavor
new_type = flavors.get_flavor_by_flavor_id('4')
@ -8238,6 +8245,7 @@ class ComputeTestCase(BaseTestCase,
instance.flavor = new_type
instance.old_flavor = old_type
instance.new_flavor = new_type
instance.migration_context = objects.MigrationContext()
def fake_drop_move_claim(*args, **kwargs):
pass

View File

@ -7177,7 +7177,9 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase,
mock_confirm, mock_nwapi, mock_notify,
mock_mig_save, mock_mig_get, mock_inst_get):
self._mock_rt()
self.instance.migration_context = objects.MigrationContext()
self.instance.migration_context = objects.MigrationContext(
new_pci_devices=None,
old_pci_devices=None)
self.migration.source_compute = self.instance['host']
self.migration.source_node = self.instance['node']
self.migration.status = 'confirming'
@ -7193,6 +7195,7 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase,
do_confirm_resize()
@mock.patch('nova.objects.MigrationContext.get_pci_mapping_for_migration')
@mock.patch('nova.compute.utils.add_instance_fault_from_exc')
@mock.patch('nova.objects.Migration.get_by_id')
@mock.patch('nova.objects.Instance.get_by_uuid')
@ -7201,7 +7204,7 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase,
@mock.patch('nova.objects.Instance.save')
def test_confirm_resize_driver_confirm_migration_fails(
self, instance_save, notify_action, notify_usage,
instance_get_by_uuid, migration_get_by_id, add_fault):
instance_get_by_uuid, migration_get_by_id, add_fault, get_mapping):
"""Tests the scenario that driver.confirm_migration raises some error
to make sure the error is properly handled, like the instance and
migration status is set to 'error'.
@ -7209,6 +7212,7 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase,
self.migration.status = 'confirming'
migration_get_by_id.return_value = self.migration
instance_get_by_uuid.return_value = self.instance
self.instance.migration_context = objects.MigrationContext()
error = exception.HypervisorUnavailable(
host=self.migration.source_compute)
@ -7216,9 +7220,11 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase,
mock.patch.object(self.compute, 'network_api'),
mock.patch.object(self.compute.driver, 'confirm_migration',
side_effect=error),
mock.patch.object(self.compute, '_delete_allocation_after_move')
mock.patch.object(self.compute, '_delete_allocation_after_move'),
mock.patch.object(self.compute,
'_get_updated_nw_info_with_pci_mapping')
) as (
network_api, confirm_migration, delete_allocation
network_api, confirm_migration, delete_allocation, pci_mapping
):
self.assertRaises(exception.HypervisorUnavailable,
self.compute.confirm_resize,
@ -7245,6 +7251,59 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase,
instance_get_by_uuid.assert_called_once()
migration_get_by_id.assert_called_once()
def test_confirm_resize_calls_virt_driver_with_old_pci(self):
@mock.patch.object(self.migration, 'save')
@mock.patch.object(self.compute, '_notify_about_instance_usage')
@mock.patch.object(self.compute, 'network_api')
@mock.patch.object(self.compute.driver, 'confirm_migration')
@mock.patch.object(self.compute, '_delete_allocation_after_move')
@mock.patch.object(self.instance, 'drop_migration_context')
@mock.patch.object(self.instance, 'save')
def do_confirm_resize(mock_save, mock_drop, mock_delete,
mock_confirm, mock_nwapi, mock_notify,
mock_mig_save):
# Mock virt driver confirm_resize() to save the provided
# network_info, we will check it later.
updated_nw_info = []
def driver_confirm_resize(*args, **kwargs):
if 'network_info' in kwargs:
nw_info = kwargs['network_info']
else:
nw_info = args[3]
updated_nw_info.extend(nw_info)
mock_confirm.side_effect = driver_confirm_resize
self._mock_rt()
old_devs = objects.PciDeviceList(
objects=[objects.PciDevice(
address='0000:04:00.2',
request_id=uuids.pcidev1)])
new_devs = objects.PciDeviceList(
objects=[objects.PciDevice(
address='0000:05:00.3',
request_id=uuids.pcidev1)])
self.instance.migration_context = objects.MigrationContext(
new_pci_devices=new_devs,
old_pci_devices=old_devs)
# Create VIF with new_devs[0] PCI address.
nw_info = network_model.NetworkInfo([
network_model.VIF(
id=uuids.port1,
vnic_type=network_model.VNIC_TYPE_DIRECT,
profile={'pci_slot': new_devs[0].address})])
mock_nwapi.get_instance_nw_info.return_value = nw_info
self.migration.source_compute = self.instance['host']
self.migration.source_node = self.instance['node']
self.compute._confirm_resize(self.context, self.instance,
self.migration)
# Assert virt driver confirm_migration() was called
# with the updated nw_info object.
self.assertEqual(old_devs[0].address,
updated_nw_info[0]['profile']['pci_slot'])
do_confirm_resize()
def test_delete_allocation_after_move_confirm_by_migration(self):
with mock.patch.object(self.compute, 'reportclient') as mock_report:
mock_report.delete_allocation_for_instance.return_value = True
@ -8750,6 +8809,24 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase,
# i.e 'profile' attribute does not exist.
self.assertNotIn('profile', unchanged_mig_vif)
def test_get_updated_nw_info_with_pci_mapping(self):
old_dev = objects.PciDevice(address='0000:04:00.2')
new_dev = objects.PciDevice(address='0000:05:00.3')
pci_mapping = {old_dev.address: new_dev}
nw_info = network_model.NetworkInfo([
network_model.VIF(
id=uuids.port1,
vnic_type=network_model.VNIC_TYPE_NORMAL),
network_model.VIF(
id=uuids.port2,
vnic_type=network_model.VNIC_TYPE_DIRECT,
profile={'pci_slot': old_dev.address})])
updated_nw_info = self.compute._get_updated_nw_info_with_pci_mapping(
nw_info, pci_mapping)
self.assertDictEqual(nw_info[0], updated_nw_info[0])
self.assertEqual(new_dev.address,
updated_nw_info[1]['profile']['pci_slot'])
class ComputeManagerInstanceUsageAuditTestCase(test.TestCase):
def setUp(self):