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 <instance_path>/<instance_uuid>_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 <vdrok@mirantis.com>
Change-Id: Id687e11e235fd6c2f99bb647184310dfdce9a08d
(cherry picked from commit 966192704c)
(cherry picked from commit f1280ab849)
This commit is contained in:
jichenjc 2018-05-21 02:03:51 +08:00 committed by Lee Yarwood
parent 8e130e2be7
commit fd5c454738
2 changed files with 37 additions and 5 deletions

View File

@ -14917,8 +14917,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.
@ -14938,7 +14939,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 = "<domain/>"
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

View File

@ -75,6 +75,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
@ -8151,14 +8152,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