Skip to content

Commit 11acae8

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "libvirt: Ignore device already in the process of unplug errors" into stable/wallaby
2 parents f99f667 + 972a86d commit 11acae8

File tree

2 files changed

+59
-2
lines changed

2 files changed

+59
-2
lines changed

nova/tests/unit/virt/libvirt/test_guest.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,48 @@ def test_detach_device_with_retry_first_detach_device_missing(self):
377377
error_message="device not found: disk vdb not found",
378378
supports_device_missing=True)
379379

380+
def test_detach_device_with_already_in_process_of_unplug_error(self):
381+
# Assert that DeviceNotFound is raised when encountering
382+
# https://bugzilla.redhat.com/show_bug.cgi?id=1878659
383+
# This is raised as QEMU returns a VIR_ERR_INTERNAL_ERROR when
384+
# a request to device_del is made while another is about to complete.
385+
386+
self.domain.isPersistent.return_value = True
387+
conf = mock.Mock(spec=vconfig.LibvirtConfigGuestDevice)
388+
conf.to_xml.return_value = "</xml>"
389+
390+
existing_unplug_exc = fakelibvirt.make_libvirtError(
391+
fakelibvirt.libvirtError, "",
392+
error_message='device vdb is already in the process of unplug',
393+
error_code=fakelibvirt.VIR_ERR_INTERNAL_ERROR,
394+
error_domain=fakelibvirt.VIR_FROM_DOMAIN
395+
)
396+
device_missing_exc = fakelibvirt.make_libvirtError(
397+
fakelibvirt.libvirtError, "",
398+
error_message='device not found: disk vdb not found',
399+
error_code=fakelibvirt.VIR_ERR_DEVICE_MISSING,
400+
error_domain=fakelibvirt.VIR_FROM_DOMAIN
401+
)
402+
403+
# Raise VIR_ERR_INTERNAL_ERROR on the second call before raising
404+
# VIR_ERR_DEVICE_MISSING to mock the first call successfully detaching
405+
# the device asynchronously.
406+
self.domain.detachDeviceFlags.side_effect = [
407+
None,
408+
existing_unplug_exc,
409+
device_missing_exc
410+
]
411+
412+
retry_detach = self.guest.detach_device_with_retry(
413+
mock.Mock(return_value=conf),
414+
'vdb',
415+
live=True,
416+
inc_sleep_time=.01
417+
)
418+
419+
# Assert that we raise exception.DeviceNotFound
420+
self.assertRaises(exception.DeviceNotFound, retry_detach)
421+
380422
def test_get_xml_desc(self):
381423
self.guest.get_xml_desc()
382424
self.domain.XMLDesc.assert_called_once_with(flags=0)

nova/virt/libvirt/guest.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,12 +434,27 @@ def _try_detach_device(conf, persistent=False, live=False):
434434
LOG.debug('Successfully detached device %s from guest. '
435435
'Persistent? %s. Live? %s',
436436
device, persistent, live)
437-
438437
except libvirt.libvirtError as ex:
439438
with excutils.save_and_reraise_exception(reraise=False) as ctx:
440-
if ex.get_error_code() == libvirt.VIR_ERR_DEVICE_MISSING:
439+
code = ex.get_error_code()
440+
msg = ex.get_error_message()
441+
if code == libvirt.VIR_ERR_DEVICE_MISSING:
441442
raise exception.DeviceNotFound(
442443
device=alternative_device_name)
444+
# NOTE(lyarwood): https://bugzilla.redhat.com/1878659
445+
# Ignore this known QEMU bug for the time being allowing
446+
# our retry logic to fire again and hopefully see that
447+
# the device has been removed asynchronously by QEMU
448+
# in the meantime when the next call to detach raises
449+
# VIR_ERR_DEVICE_MISSING.
450+
if (code == libvirt.VIR_ERR_INTERNAL_ERROR and
451+
msg and 'already in the process of unplug' in msg
452+
):
453+
LOG.debug('Ignoring QEMU rejecting our request to '
454+
'detach as it is caused by a previous '
455+
'request still being in progress.')
456+
return
457+
443458
# Re-raise the original exception if we're not raising
444459
# DeviceNotFound instead. This will avoid logging of a
445460
# "Original exception being dropped" traceback.

0 commit comments

Comments
 (0)