Skip to content

Commit 1f36622

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Allow driver to properly unplug VIFs on destination on confirm resize" into stable/stein
2 parents d45bbdd + 77a339c commit 1f36622

File tree

3 files changed

+128
-8
lines changed

3 files changed

+128
-8
lines changed

nova/compute/manager.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import base64
2929
import binascii
3030
import contextlib
31+
import copy
3132
import functools
3233
import inspect
3334
import sys
@@ -4025,6 +4026,33 @@ def do_confirm_resize(context, instance, migration_id):
40254026

40264027
do_confirm_resize(context, instance, migration.id)
40274028

4029+
def _get_updated_nw_info_with_pci_mapping(self, nw_info, pci_mapping):
4030+
# NOTE(adrianc): This method returns a copy of nw_info if modifications
4031+
# are made else it returns the original nw_info.
4032+
updated_nw_info = nw_info
4033+
if nw_info and pci_mapping:
4034+
updated_nw_info = copy.deepcopy(nw_info)
4035+
for vif in updated_nw_info:
4036+
if vif['vnic_type'] in network_model.VNIC_TYPES_SRIOV:
4037+
try:
4038+
vif_pci_addr = vif['profile']['pci_slot']
4039+
new_addr = pci_mapping[vif_pci_addr].address
4040+
vif['profile']['pci_slot'] = new_addr
4041+
LOG.debug("Updating VIF's PCI address for VIF %(id)s. "
4042+
"Original value %(orig_val)s, "
4043+
"new value %(new_val)s",
4044+
{'id': vif['id'],
4045+
'orig_val': vif_pci_addr,
4046+
'new_val': new_addr})
4047+
except (KeyError, AttributeError):
4048+
with excutils.save_and_reraise_exception():
4049+
# NOTE(adrianc): This should never happen. If we
4050+
# get here it means there is some inconsistency
4051+
# with either 'nw_info' or 'pci_mapping'.
4052+
LOG.error("Unexpected error when updating network "
4053+
"information with PCI mapping.")
4054+
return updated_nw_info
4055+
40284056
def _confirm_resize(self, context, instance, migration=None):
40294057
"""Destroys the source instance."""
40304058
self._notify_about_instance_usage(context, instance,
@@ -4043,9 +4071,16 @@ def _confirm_resize(self, context, instance, migration=None):
40434071
# NOTE(tr3buchet): tear down networks on source host
40444072
self.network_api.setup_networks_on_host(context, instance,
40454073
migration.source_compute, teardown=True)
4046-
40474074
network_info = self.network_api.get_instance_nw_info(context,
40484075
instance)
4076+
4077+
# NOTE(adrianc): Populate old PCI device in VIF profile
4078+
# to allow virt driver to properly unplug it from Hypervisor.
4079+
pci_mapping = (instance.migration_context.
4080+
get_pci_mapping_for_migration(True))
4081+
network_info = self._get_updated_nw_info_with_pci_mapping(
4082+
network_info, pci_mapping)
4083+
40494084
# TODO(mriedem): Get BDMs here and pass them to the driver.
40504085
self.driver.confirm_migration(context, migration, instance,
40514086
network_info)

nova/tests/unit/compute/test_compute.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5814,6 +5814,8 @@ def test_confirm_resize_with_numa_topology_and_cpu_pinning(
58145814
migration_context.migration_id = migration.id
58155815
migration_context.old_numa_topology = old_inst_topology
58165816
migration_context.new_numa_topology = new_inst_topology
5817+
migration_context.old_pci_devices = None
5818+
migration_context.new_pci_devices = None
58175819

58185820
instance.migration_context = migration_context
58195821
instance.vm_state = vm_states.RESIZED
@@ -5850,12 +5852,14 @@ def _test_resize_with_pci(self, method, expected_pci_addr):
58505852
old_pci_devices = objects.PciDeviceList(
58515853
objects=[objects.PciDevice(vendor_id='1377',
58525854
product_id='0047',
5853-
address='0000:0a:00.1')])
5855+
address='0000:0a:00.1',
5856+
request_id=uuids.req1)])
58545857

58555858
new_pci_devices = objects.PciDeviceList(
58565859
objects=[objects.PciDevice(vendor_id='1377',
58575860
product_id='0047',
5858-
address='0000:0b:00.1')])
5861+
address='0000:0b:00.1',
5862+
request_id=uuids.req2)])
58595863

58605864
if expected_pci_addr == old_pci_devices[0].address:
58615865
expected_pci_device = old_pci_devices[0]
@@ -8270,14 +8274,18 @@ def test_confirm_resize_roll_back_quota_status_dummy(self,
82708274
self.compute.confirm_resize(self.context, instance=instance,
82718275
migration=migration)
82728276

8273-
def test_allow_confirm_resize_on_instance_in_deleting_task_state(self):
8277+
@mock.patch.object(objects.MigrationContext,
8278+
'get_pci_mapping_for_migration')
8279+
def test_allow_confirm_resize_on_instance_in_deleting_task_state(
8280+
self, mock_pci_mapping):
82748281
instance = self._create_fake_instance_obj()
82758282
old_type = instance.flavor
82768283
new_type = flavors.get_flavor_by_flavor_id('4')
82778284

82788285
instance.flavor = new_type
82798286
instance.old_flavor = old_type
82808287
instance.new_flavor = new_type
8288+
instance.migration_context = objects.MigrationContext()
82818289

82828290
def fake_drop_move_claim(*args, **kwargs):
82838291
pass

nova/tests/unit/compute/test_compute_mgr.py

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7294,7 +7294,9 @@ def do_confirm_resize(mock_save, mock_drop, mock_delete,
72947294
mock_confirm, mock_nwapi, mock_notify,
72957295
mock_mig_save, mock_mig_get, mock_inst_get):
72967296
self._mock_rt()
7297-
self.instance.migration_context = objects.MigrationContext()
7297+
self.instance.migration_context = objects.MigrationContext(
7298+
new_pci_devices=None,
7299+
old_pci_devices=None)
72987300
self.migration.source_compute = self.instance['host']
72997301
self.migration.source_node = self.instance['node']
73007302
self.migration.status = 'confirming'
@@ -7310,6 +7312,7 @@ def do_confirm_resize(mock_save, mock_drop, mock_delete,
73107312

73117313
do_confirm_resize()
73127314

7315+
@mock.patch('nova.objects.MigrationContext.get_pci_mapping_for_migration')
73137316
@mock.patch('nova.compute.utils.add_instance_fault_from_exc')
73147317
@mock.patch('nova.objects.Migration.get_by_id')
73157318
@mock.patch('nova.objects.Instance.get_by_uuid')
@@ -7318,24 +7321,27 @@ def do_confirm_resize(mock_save, mock_drop, mock_delete,
73187321
@mock.patch('nova.objects.Instance.save')
73197322
def test_confirm_resize_driver_confirm_migration_fails(
73207323
self, instance_save, notify_action, notify_usage,
7321-
instance_get_by_uuid, migration_get_by_id, add_fault):
7324+
instance_get_by_uuid, migration_get_by_id, add_fault, get_mapping):
73227325
"""Tests the scenario that driver.confirm_migration raises some error
73237326
to make sure the error is properly handled, like the instance and
73247327
migration status is set to 'error'.
73257328
"""
73267329
self.migration.status = 'confirming'
73277330
migration_get_by_id.return_value = self.migration
73287331
instance_get_by_uuid.return_value = self.instance
7332+
self.instance.migration_context = objects.MigrationContext()
73297333

73307334
error = exception.HypervisorUnavailable(
73317335
host=self.migration.source_compute)
73327336
with test.nested(
73337337
mock.patch.object(self.compute, 'network_api'),
73347338
mock.patch.object(self.compute.driver, 'confirm_migration',
73357339
side_effect=error),
7336-
mock.patch.object(self.compute, '_delete_allocation_after_move')
7340+
mock.patch.object(self.compute, '_delete_allocation_after_move'),
7341+
mock.patch.object(self.compute,
7342+
'_get_updated_nw_info_with_pci_mapping')
73377343
) as (
7338-
network_api, confirm_migration, delete_allocation
7344+
network_api, confirm_migration, delete_allocation, pci_mapping
73397345
):
73407346
self.assertRaises(exception.HypervisorUnavailable,
73417347
self.compute.confirm_resize,
@@ -7362,6 +7368,59 @@ def test_confirm_resize_driver_confirm_migration_fails(
73627368
instance_get_by_uuid.assert_called_once()
73637369
migration_get_by_id.assert_called_once()
73647370

7371+
def test_confirm_resize_calls_virt_driver_with_old_pci(self):
7372+
@mock.patch.object(self.migration, 'save')
7373+
@mock.patch.object(self.compute, '_notify_about_instance_usage')
7374+
@mock.patch.object(self.compute, 'network_api')
7375+
@mock.patch.object(self.compute.driver, 'confirm_migration')
7376+
@mock.patch.object(self.compute, '_delete_allocation_after_move')
7377+
@mock.patch.object(self.instance, 'drop_migration_context')
7378+
@mock.patch.object(self.instance, 'save')
7379+
def do_confirm_resize(mock_save, mock_drop, mock_delete,
7380+
mock_confirm, mock_nwapi, mock_notify,
7381+
mock_mig_save):
7382+
# Mock virt driver confirm_resize() to save the provided
7383+
# network_info, we will check it later.
7384+
updated_nw_info = []
7385+
7386+
def driver_confirm_resize(*args, **kwargs):
7387+
if 'network_info' in kwargs:
7388+
nw_info = kwargs['network_info']
7389+
else:
7390+
nw_info = args[3]
7391+
updated_nw_info.extend(nw_info)
7392+
7393+
mock_confirm.side_effect = driver_confirm_resize
7394+
self._mock_rt()
7395+
old_devs = objects.PciDeviceList(
7396+
objects=[objects.PciDevice(
7397+
address='0000:04:00.2',
7398+
request_id=uuids.pcidev1)])
7399+
new_devs = objects.PciDeviceList(
7400+
objects=[objects.PciDevice(
7401+
address='0000:05:00.3',
7402+
request_id=uuids.pcidev1)])
7403+
self.instance.migration_context = objects.MigrationContext(
7404+
new_pci_devices=new_devs,
7405+
old_pci_devices=old_devs)
7406+
# Create VIF with new_devs[0] PCI address.
7407+
nw_info = network_model.NetworkInfo([
7408+
network_model.VIF(
7409+
id=uuids.port1,
7410+
vnic_type=network_model.VNIC_TYPE_DIRECT,
7411+
profile={'pci_slot': new_devs[0].address})])
7412+
mock_nwapi.get_instance_nw_info.return_value = nw_info
7413+
self.migration.source_compute = self.instance['host']
7414+
self.migration.source_node = self.instance['node']
7415+
self.compute._confirm_resize(self.context, self.instance,
7416+
self.migration)
7417+
# Assert virt driver confirm_migration() was called
7418+
# with the updated nw_info object.
7419+
self.assertEqual(old_devs[0].address,
7420+
updated_nw_info[0]['profile']['pci_slot'])
7421+
7422+
do_confirm_resize()
7423+
73657424
def test_delete_allocation_after_move_confirm_by_migration(self):
73667425
with mock.patch.object(self.compute, 'reportclient') as mock_report:
73677426
mock_report.delete_allocation_for_instance.return_value = True
@@ -8757,6 +8816,24 @@ def doit(mock_pr, mock_r):
87578816

87588817
doit()
87598818

8819+
def test_get_updated_nw_info_with_pci_mapping(self):
8820+
old_dev = objects.PciDevice(address='0000:04:00.2')
8821+
new_dev = objects.PciDevice(address='0000:05:00.3')
8822+
pci_mapping = {old_dev.address: new_dev}
8823+
nw_info = network_model.NetworkInfo([
8824+
network_model.VIF(
8825+
id=uuids.port1,
8826+
vnic_type=network_model.VNIC_TYPE_NORMAL),
8827+
network_model.VIF(
8828+
id=uuids.port2,
8829+
vnic_type=network_model.VNIC_TYPE_DIRECT,
8830+
profile={'pci_slot': old_dev.address})])
8831+
updated_nw_info = self.compute._get_updated_nw_info_with_pci_mapping(
8832+
nw_info, pci_mapping)
8833+
self.assertDictEqual(nw_info[0], updated_nw_info[0])
8834+
self.assertEqual(new_dev.address,
8835+
updated_nw_info[1]['profile']['pci_slot'])
8836+
87608837

87618838
class ComputeManagerInstanceUsageAuditTestCase(test.TestCase):
87628839
def setUp(self):

0 commit comments

Comments
 (0)