From d3bdeb26155c2d3b53850b790d3800a2dd78cada Mon Sep 17 00:00:00 2001 From: jichenjc Date: Mon, 21 May 2018 02:03:51 +0800 Subject: [PATCH] libvirt: Do not reraise DiskNotFound exceptions during resize When an instance has VERIFY_RESIZE status, the instance disk on the source compute host has moved to /_resize folder, which leads to disk not found errors if the update available resource periodic task on the source compute runs before resize is actually confirmed. Icec2769bf42455853cbe686fb30fda73df791b25 almost fixed this issue but it will only set reraise to False when task_state is not None, that isn't the case when an instance is resized but resize is not yet confirmed. This patch adds a condition based on vm_state to ensure we don't reraise DiskNotFound exceptions while resize is not confirmed. Closes-Bug: 1774249 Co-Authored-By: Vladyslav Drok Change-Id: Id687e11e235fd6c2f99bb647184310dfdce9a08d (cherry picked from commit 966192704c20d1b4e9faf384c8dafac8ea6e06ea) (cherry picked from commit f1280ab849d20819791f7c4030f570a917d3e91d) (cherry picked from commit fd5c45473823105d8572d7940980163c6f09169c) --- nova/tests/unit/virt/libvirt/test_driver.py | 30 +++++++++++++++++++-- nova/virt/libvirt/driver.py | 12 ++++++--- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index d4512ee3f039..59e536293071 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -14210,8 +14210,9 @@ class LibvirtConnTestCase(test.NoDBTestCase, @mock.patch('nova.objects.InstanceList.get_by_filters', return_value=objects.InstanceList(objects=[ objects.Instance(uuid=uuids.instance, + vm_state=vm_states.ACTIVE, task_state=task_states.DELETING)])) - def test_disk_over_committed_size_total_disk_not_found_ignore( + def test_disk_over_committed_size_total_disk_not_found_ignore_task_state( self, mock_get, mock_bdms, mock_get_disk_info, mock_list_domains): """Tests that we handle DiskNotFound gracefully for an instance that is undergoing a task_state transition. @@ -14231,7 +14232,32 @@ class LibvirtConnTestCase(test.NoDBTestCase, return_value=objects.BlockDeviceMappingList()) @mock.patch('nova.objects.InstanceList.get_by_filters', return_value=objects.InstanceList(objects=[ - objects.Instance(uuid=uuids.instance, task_state=None)])) + objects.Instance(uuid=uuids.instance, + task_state=None, + vm_state=vm_states.RESIZED)])) + def test_disk_over_committed_size_total_disk_not_found_ignore_vmstate( + self, mock_get, mock_bdms, mock_get_disk_info, mock_list_domains): + """Tests that we handle DiskNotFound gracefully for an instance that + is resized but resize is not confirmed yet. + """ + mock_dom = mock.Mock() + mock_dom.XMLDesc.return_value = "" + mock_dom.UUIDString.return_value = uuids.instance + mock_list_domains.return_value = [mock_dom] + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) + self.assertEqual(0, drvr._get_disk_over_committed_size_total()) + + @mock.patch('nova.virt.libvirt.host.Host.list_instance_domains') + @mock.patch('nova.virt.libvirt.driver.LibvirtDriver.' + '_get_instance_disk_info_from_config', + side_effect=exception.DiskNotFound(location='/opt/stack/foo')) + @mock.patch('nova.objects.BlockDeviceMappingList.bdms_by_instance_uuid', + return_value=objects.BlockDeviceMappingList()) + @mock.patch('nova.objects.InstanceList.get_by_filters', + return_value=objects.InstanceList(objects=[ + objects.Instance(uuid=uuids.instance, + vm_state=vm_states.ACTIVE, + task_state=None)])) def test_disk_over_committed_size_total_disk_not_found_reraise( self, mock_get, mock_bdms, mock_get_disk_info, mock_list_domains): """Tests that we handle DiskNotFound gracefully for an instance that diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 44cdc7d53a58..b30a901d22af 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -73,6 +73,7 @@ from nova import block_device from nova.compute import power_state from nova.compute import task_states from nova.compute import utils as compute_utils +from nova.compute import vm_states import nova.conf from nova.console import serial as serial_console from nova.console import type as ctype @@ -8010,14 +8011,19 @@ class LibvirtDriver(driver.ComputeDriver): # should ignore this instance and move on. if guest.uuid in local_instances: inst = local_instances[guest.uuid] - if inst.task_state is not None: + # bug 1774249 indicated when instance is in RESIZED + # state it might also can't find back disk + if (inst.task_state is not None or + inst.vm_state == vm_states.RESIZED): LOG.info('Periodic task is updating the host ' 'stats; it is trying to get disk info ' 'for %(i_name)s, but the backing disk ' 'was removed by a concurrent operation ' - '(task_state=%(task_state)s)', + '(task_state=%(task_state)s) and ' + '(vm_state=%(vm_state)s)', {'i_name': guest.name, - 'task_state': inst.task_state}, + 'task_state': inst.task_state, + 'vm_state': inst.vm_state}, instance=inst) err_ctxt.reraise = False