From c5d8594cb62c1397183888133bef68fe28c62c7a Mon Sep 17 00:00:00 2001 From: paul-carlton2 Date: Thu, 6 Oct 2016 12:02:15 +0100 Subject: [PATCH] Update nova network info when doing rebuild for evacuate operation When nova evacuate or host-evacuate are used to recreate instances with sriov ports the instances are allocated new device ids on the target and neutron is updated accordingly. However the network info data passed to the driver spawn method is not updated and thus the instance tries to use the device id they were allocated on the source node. If a pre existing instance is using that device id or no such device exists on the target node then the instance will fail to start. Conflicts: nova/compute/manager.py nova/tests/unit/compute/test_compute_mgr.py NOTE(mriedem): The conflicts are due to change I00eab47edf1150788777300680e853a872c1db40 and change I752617066bb2167b49239ab9d17b0c89754a3e12 not being in Pike. Co-Authored-By: Steven Webster Change-Id: I860ab9cf3f9a38bd4ea5bceecda8105b6fee93dc Closes-Bug: #1630698 Related-Bug: #1677621 (cherry picked from commit 8e052c7fe9262c38da9d8b5f9a0ee889d9c1c6be) (cherry picked from commit 559de0d0a3df92ef9dca21edfaa754a2848013c3) --- nova/compute/manager.py | 8 ++- nova/tests/unit/compute/test_compute_mgr.py | 80 +++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 51ee9a1d07ca..673a1e6c600b 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -2959,8 +2959,14 @@ class ComputeManager(manager.Manager): # are so similar, we should really try to unify them. self.network_api.setup_instance_network_on_host( context, instance, self.host, migration) + # TODO(mriedem): Consider decorating setup_instance_network_on_host + # with @base_api.refresh_cache and then we wouldn't need this + # explicit call to get_instance_nw_info. + network_info = self.network_api.get_instance_nw_info(context, + instance) + else: + network_info = instance.get_network_info() - network_info = instance.get_network_info() if bdms is None: bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( context, instance.uuid) diff --git a/nova/tests/unit/compute/test_compute_mgr.py b/nova/tests/unit/compute/test_compute_mgr.py index 3231f30344fe..704db5a5a8c4 100644 --- a/nova/tests/unit/compute/test_compute_mgr.py +++ b/nova/tests/unit/compute/test_compute_mgr.py @@ -3754,6 +3754,86 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): mock_set.assert_called_once_with(None, 'done') mock_rt.assert_called_once_with() + @mock.patch.object(compute_utils, 'notify_usage_exists') + @mock.patch.object(compute_utils, 'notify_about_instance_action') + @mock.patch.object(objects.ImageMeta, 'from_instance') + @mock.patch.object(objects.Instance, 'save', return_value=None) + def test_rebuild_nw_updated_if_recreate(self, + mock_save, + mock_image_ref, + mock_notify, + mock_notify_exists): + with test.nested( + mock.patch.object(self.compute, + '_notify_about_instance_usage'), + mock.patch.object(self.compute.network_api, + 'setup_networks_on_host'), + mock.patch.object(self.compute.network_api, + 'setup_instance_network_on_host'), + mock.patch.object(self.compute.network_api, + 'get_instance_nw_info'), + mock.patch.object(self.compute, + '_get_instance_block_device_info', + return_value='fake-bdminfo'), + ) as( + mock_notify_usage, + mock_setup, + mock_setup_inst, + mock_get_nw_info, + mock_get_blk + ): + self.flags(group="glance", api_servers="http://127.0.0.1:9292") + instance = fake_instance.fake_instance_obj(self.context) + orig_vif = fake_network_cache_model.new_vif( + {'profile': {"pci_slot": "0000:01:00.1"}}) + orig_nw_info = network_model.NetworkInfo([orig_vif]) + new_vif = fake_network_cache_model.new_vif( + {'profile': {"pci_slot": "0000:02:00.1"}}) + new_nw_info = network_model.NetworkInfo([new_vif]) + + info_cache = objects.InstanceInfoCache(network_info=orig_nw_info, + instance_uuid=instance.uuid) + + instance.info_cache = info_cache + instance.task_state = task_states.REBUILDING + instance.migration_context = None + instance.numa_topology = None + instance.pci_requests = None + instance.pci_devices = None + orig_image_ref = None + image_ref = None + injected_files = [] + new_pass = None + orig_sys_metadata = None + bdms = [] + recreate = True + on_shared_storage = None + preserve_ephemeral = None + + mock_get_nw_info.return_value = new_nw_info + + self.compute._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, {}) + + mock_notify_usage.assert_has_calls( + [mock.call(self.context, instance, "rebuild.start", + extra_usage_info=mock.ANY), + mock.call(self.context, instance, "rebuild.end", + network_info=new_nw_info, + extra_usage_info=mock.ANY)]) + self.assertTrue(mock_image_ref.called) + self.assertTrue(mock_save.called) + self.assertTrue(mock_notify_exists.called) + mock_setup.assert_called_once_with(self.context, instance, + mock.ANY) + mock_setup_inst.assert_called_once_with(self.context, instance, + mock.ANY, mock.ANY) + mock_get_nw_info.assert_called_once_with(self.context, instance) + def test_rebuild_default_impl(self): def _detach(context, bdms): # NOTE(rpodolyaka): check that instance has been powered off by