@@ -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 )
0 commit comments