From b930336854bffec1bb81b6d67079a4df59e0af19 Mon Sep 17 00:00:00 2001 From: Steven Webster Date: Mon, 12 Jun 2017 17:10:03 -0400 Subject: [PATCH] Fix instance evacuation with PCI devices update_port_binding_for_instance() now checks that a valid migration object exists as a parameter before any mapping between old/new PCI devices can occur. A migration should be present in the case of a cold migration, resize, or evacuation. An evacuation (being a special case of a rebuild) however, will not pass a migration to update_port_binding_for_instance, as it is called directly from setup_instance_network(). This calling function does not currently take a migration parameter, even though one will certainly exist for an evacuation. This commit adds an optional migration parameter to setup_instance_network_on_host() and passes any migration object to the port update routine. Closes-Bug: #1703629 Related-Bug: #1677621 Related-Bug: #1630698 Change-Id: I4e394c8d275995eac4b049a7b1329ea90f2394be --- nova/compute/manager.py | 8 +++++--- nova/network/api.py | 3 ++- nova/network/base_api.py | 5 ++++- nova/network/neutronv2/api.py | 6 ++++-- nova/tests/unit/compute/test_compute.py | 2 +- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 253f104cdf98..cb71624c7107 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -2805,7 +2805,8 @@ class ComputeManager(manager.Manager): self._do_rebuild_instance_with_claim( claim_ctxt, context, instance, orig_image_ref, image_ref, injected_files, new_pass, orig_sys_metadata, - bdms, recreate, on_shared_storage, preserve_ephemeral) + bdms, recreate, on_shared_storage, preserve_ephemeral, + migration) except exception.ComputeResourcesUnavailable as e: LOG.debug("Could not rebuild instance on this host, not " "enough resources available.", instance=instance) @@ -2858,7 +2859,8 @@ class ComputeManager(manager.Manager): def _do_rebuild_instance(self, context, instance, orig_image_ref, image_ref, injected_files, new_pass, orig_sys_metadata, bdms, recreate, - on_shared_storage, preserve_ephemeral): + on_shared_storage, preserve_ephemeral, + migration): orig_vm_state = instance.vm_state if recreate: @@ -2930,7 +2932,7 @@ class ComputeManager(manager.Manager): # TODO(cfriesen): this network_api call and the one above # are so similar, we should really try to unify them. self.network_api.setup_instance_network_on_host( - context, instance, self.host) + context, instance, self.host, migration) network_info = instance.get_network_info() if bdms is None: diff --git a/nova/network/api.py b/nova/network/api.py index 663e53f3368f..141e77e4c5ad 100644 --- a/nova/network/api.py +++ b/nova/network/api.py @@ -520,7 +520,8 @@ class API(base_api.NetworkAPI): self.network_rpcapi.migrate_instance_finish(context, **args) - def setup_instance_network_on_host(self, context, instance, host): + def setup_instance_network_on_host(self, context, instance, host, + migration=None): """Setup network for specified instance on host.""" self.migrate_instance_finish(context, instance, {'source_compute': None, diff --git a/nova/network/base_api.py b/nova/network/base_api.py index 12bef299497c..a80f3b0a7d3f 100644 --- a/nova/network/base_api.py +++ b/nova/network/base_api.py @@ -334,12 +334,15 @@ class NetworkAPI(base.Base): """Finish migrating the network of an instance.""" raise NotImplementedError() - def setup_instance_network_on_host(self, context, instance, host): + def setup_instance_network_on_host(self, context, instance, host, + migration=None): """Setup network for specified instance on host. :param context: The request context. :param instance: nova.objects.instance.Instance object. :param host: The host which network should be setup for instance. + :param migration: The migration object if the instance is being + tracked with a migration. """ raise NotImplementedError() diff --git a/nova/network/neutronv2/api.py b/nova/network/neutronv2/api.py index 7955746e84b2..fbfcd9f976b0 100644 --- a/nova/network/neutronv2/api.py +++ b/nova/network/neutronv2/api.py @@ -2398,9 +2398,11 @@ class API(base_api.NetworkAPI): """Create a private DNS domain with optional nova project.""" raise NotImplementedError() - def setup_instance_network_on_host(self, context, instance, host): + def setup_instance_network_on_host(self, context, instance, host, + migration=None): """Setup network for specified instance on host.""" - self._update_port_binding_for_instance(context, instance, host) + self._update_port_binding_for_instance(context, instance, host, + migration) def cleanup_instance_network_on_host(self, context, instance, host): """Cleanup network for specified instance on host.""" diff --git a/nova/tests/unit/compute/test_compute.py b/nova/tests/unit/compute/test_compute.py index 90f956dcdd33..afc92f322bd4 100644 --- a/nova/tests/unit/compute/test_compute.py +++ b/nova/tests/unit/compute/test_compute.py @@ -12081,7 +12081,7 @@ class EvacuateHostTestCase(BaseTestCase): mock_setup_networks_on_host.assert_called_once_with( ctxt, self.inst, self.inst.host) mock_setup_instance_network_on_host.assert_called_once_with( - ctxt, self.inst, self.inst.host) + ctxt, self.inst, self.inst.host, migration) _test_rebuild(vm_is_stopped=vm_states_is_stopped)