|
21 | 21 | from oslo_utils import encodeutils |
22 | 22 |
|
23 | 23 | from nova import context |
24 | | -from nova import exception |
25 | 24 | from nova import test |
26 | 25 | from nova.tests.unit.virt.libvirt import fakelibvirt |
27 | 26 | from nova.virt.libvirt import config as vconfig |
@@ -213,212 +212,6 @@ def test_detach_device_persistent_live(self): |
213 | 212 | "</xml>", flags=(fakelibvirt.VIR_DOMAIN_AFFECT_CONFIG | |
214 | 213 | fakelibvirt.VIR_DOMAIN_AFFECT_LIVE)) |
215 | 214 |
|
216 | | - def test_detach_device_with_retry_from_transient_domain(self): |
217 | | - conf = mock.Mock(spec=vconfig.LibvirtConfigGuestDevice) |
218 | | - conf.to_xml.return_value = "</xml>" |
219 | | - get_config = mock.Mock() |
220 | | - get_config.side_effect = [conf, conf, conf, None, None] |
221 | | - dev_path = "/dev/vdb" |
222 | | - self.domain.isPersistent.return_value = False |
223 | | - retry_detach = self.guest.detach_device_with_retry( |
224 | | - get_config, dev_path, live=True, inc_sleep_time=.01) |
225 | | - self.domain.detachDeviceFlags.assert_called_once_with( |
226 | | - "</xml>", flags=fakelibvirt.VIR_DOMAIN_AFFECT_LIVE) |
227 | | - self.domain.detachDeviceFlags.reset_mock() |
228 | | - retry_detach() |
229 | | - self.assertEqual(1, self.domain.detachDeviceFlags.call_count) |
230 | | - |
231 | | - def test_detach_device_with_retry_detach_success(self): |
232 | | - conf = mock.Mock(spec=vconfig.LibvirtConfigGuestDevice) |
233 | | - conf.to_xml.return_value = "</xml>" |
234 | | - get_config = mock.Mock() |
235 | | - # Force multiple retries of detach |
236 | | - get_config.side_effect = [conf, conf, conf, conf, conf, None, None] |
237 | | - dev_path = "/dev/vdb" |
238 | | - self.domain.isPersistent.return_value = True |
239 | | - |
240 | | - retry_detach = self.guest.detach_device_with_retry( |
241 | | - get_config, dev_path, live=True, inc_sleep_time=.01) |
242 | | - # Ensure we've only done the initial detach call |
243 | | - self.domain.detachDeviceFlags.assert_called_once_with( |
244 | | - "</xml>", flags=(fakelibvirt.VIR_DOMAIN_AFFECT_CONFIG | |
245 | | - fakelibvirt.VIR_DOMAIN_AFFECT_LIVE)) |
246 | | - |
247 | | - get_config.assert_called_with(dev_path) |
248 | | - |
249 | | - # Some time later, we can do the wait/retry to ensure detach succeeds |
250 | | - self.domain.detachDeviceFlags.reset_mock() |
251 | | - retry_detach() |
252 | | - # Should have two retries before we pretend device is detached |
253 | | - self.assertEqual(2, self.domain.detachDeviceFlags.call_count) |
254 | | - |
255 | | - def test_detach_device_with_retry_detach_failure(self): |
256 | | - conf = mock.Mock(spec=vconfig.LibvirtConfigGuestDevice) |
257 | | - conf.to_xml.return_value = "</xml>" |
258 | | - # Continue to return some value for the disk config |
259 | | - get_config = mock.Mock(return_value=conf) |
260 | | - self.domain.isPersistent.return_value = True |
261 | | - |
262 | | - retry_detach = self.guest.detach_device_with_retry( |
263 | | - get_config, "/dev/vdb", live=True, inc_sleep_time=.01, |
264 | | - max_retry_count=3) |
265 | | - # Ensure we've only done the initial detach call |
266 | | - self.domain.detachDeviceFlags.assert_called_once_with( |
267 | | - "</xml>", flags=(fakelibvirt.VIR_DOMAIN_AFFECT_CONFIG | |
268 | | - fakelibvirt.VIR_DOMAIN_AFFECT_LIVE)) |
269 | | - |
270 | | - # Some time later, we can do the wait/retry to ensure detach |
271 | | - self.domain.detachDeviceFlags.reset_mock() |
272 | | - # Should hit max # of retries |
273 | | - self.assertRaises(exception.DeviceDetachFailed, retry_detach) |
274 | | - self.assertEqual(4, self.domain.detachDeviceFlags.call_count) |
275 | | - |
276 | | - def test_detach_device_with_retry_device_not_found(self): |
277 | | - get_config = mock.Mock(return_value=None) |
278 | | - self.domain.isPersistent.return_value = True |
279 | | - ex = self.assertRaises( |
280 | | - exception.DeviceNotFound, self.guest.detach_device_with_retry, |
281 | | - get_config, "/dev/vdb", live=True) |
282 | | - self.assertIn("/dev/vdb", str(ex)) |
283 | | - |
284 | | - def test_detach_device_with_retry_device_not_found_alt_name(self): |
285 | | - """Tests to make sure we use the alternative name in errors.""" |
286 | | - get_config = mock.Mock(return_value=None) |
287 | | - self.domain.isPersistent.return_value = True |
288 | | - ex = self.assertRaises( |
289 | | - exception.DeviceNotFound, self.guest.detach_device_with_retry, |
290 | | - get_config, mock.sentinel.device, live=True, |
291 | | - alternative_device_name='foo') |
292 | | - self.assertIn('foo', str(ex)) |
293 | | - |
294 | | - @mock.patch.object(libvirt_guest.Guest, "detach_device") |
295 | | - def _test_detach_device_with_retry_second_detach_failure( |
296 | | - self, mock_detach, error_code=None, error_message=None, |
297 | | - supports_device_missing=False): |
298 | | - # This simulates a retry of the transient/live domain detach |
299 | | - # failing because the device is not found |
300 | | - conf = mock.Mock(spec=vconfig.LibvirtConfigGuestDevice) |
301 | | - conf.to_xml.return_value = "</xml>" |
302 | | - self.domain.isPersistent.return_value = True |
303 | | - |
304 | | - get_config = mock.Mock(return_value=conf) |
305 | | - fake_device = "vdb" |
306 | | - fake_exc = fakelibvirt.make_libvirtError( |
307 | | - fakelibvirt.libvirtError, "", |
308 | | - error_message=error_message, |
309 | | - error_code=error_code, |
310 | | - error_domain=fakelibvirt.VIR_FROM_DOMAIN) |
311 | | - mock_detach.side_effect = [None, fake_exc] |
312 | | - retry_detach = self.guest.detach_device_with_retry( |
313 | | - get_config, fake_device, live=True, |
314 | | - inc_sleep_time=.01, max_retry_count=3) |
315 | | - # Some time later, we can do the wait/retry to ensure detach |
316 | | - self.assertRaises(exception.DeviceNotFound, retry_detach) |
317 | | - # Check that the save_and_reraise_exception context manager didn't log |
318 | | - # a traceback when the libvirtError was caught and DeviceNotFound was |
319 | | - # raised. |
320 | | - self.assertNotIn('Original exception being dropped', |
321 | | - self.stdlog.logger.output) |
322 | | - |
323 | | - def test_detach_device_with_retry_second_detach_device_missing(self): |
324 | | - self._test_detach_device_with_retry_second_detach_failure( |
325 | | - error_code=fakelibvirt.VIR_ERR_DEVICE_MISSING, |
326 | | - error_message="device not found: disk vdb not found", |
327 | | - supports_device_missing=True) |
328 | | - |
329 | | - def _test_detach_device_with_retry_first_detach_failure( |
330 | | - self, error_code=None, error_message=None, |
331 | | - supports_device_missing=False): |
332 | | - # This simulates a persistent or live domain detach failing because the |
333 | | - # device is not found during the first attempt to detach the device. |
334 | | - # We should still attempt to detach the device from the live config if |
335 | | - # the detach from persistent failed OR we should retry the detach from |
336 | | - # the live config if the first detach from live config failed. |
337 | | - # Note that the side effects in this test case [fake_exc, None] could |
338 | | - # not happen in real life if the first detach failed because the detach |
339 | | - # from live raised not found. In real life, the second attempt to |
340 | | - # detach from live would raise not found again because the device is |
341 | | - # not present. The purpose of this test is to verify that we try to |
342 | | - # detach a second time if the first detach fails, so we are OK with the |
343 | | - # unrealistic side effects for detach from live failing the first time. |
344 | | - conf = mock.Mock(spec=vconfig.LibvirtConfigGuestDevice) |
345 | | - conf.to_xml.return_value = "</xml>" |
346 | | - self.domain.isPersistent.return_value = True |
347 | | - |
348 | | - get_config = mock.Mock() |
349 | | - # Simulate an inactive or live detach attempt which fails (not found) |
350 | | - # followed by a live config detach attempt that is successful |
351 | | - get_config.side_effect = [conf, conf, conf, None, None] |
352 | | - fake_device = "vdb" |
353 | | - fake_exc = fakelibvirt.make_libvirtError( |
354 | | - fakelibvirt.libvirtError, "", |
355 | | - error_message=error_message, |
356 | | - error_code=error_code, |
357 | | - error_domain=fakelibvirt.VIR_FROM_DOMAIN) |
358 | | - # Detach from persistent or live raises not found, detach from live |
359 | | - # succeeds afterward |
360 | | - self.domain.detachDeviceFlags.side_effect = [fake_exc, None] |
361 | | - retry_detach = self.guest.detach_device_with_retry(get_config, |
362 | | - fake_device, live=True, inc_sleep_time=.01, max_retry_count=3) |
363 | | - # We should have tried to detach from the persistent domain |
364 | | - self.domain.detachDeviceFlags.assert_called_once_with( |
365 | | - "</xml>", flags=(fakelibvirt.VIR_DOMAIN_AFFECT_CONFIG | |
366 | | - fakelibvirt.VIR_DOMAIN_AFFECT_LIVE)) |
367 | | - # During the retry detach, should detach from the live domain |
368 | | - self.domain.detachDeviceFlags.reset_mock() |
369 | | - retry_detach() |
370 | | - # We should have tried to detach from the live domain |
371 | | - self.domain.detachDeviceFlags.assert_called_once_with( |
372 | | - "</xml>", flags=fakelibvirt.VIR_DOMAIN_AFFECT_LIVE) |
373 | | - |
374 | | - def test_detach_device_with_retry_first_detach_device_missing(self): |
375 | | - self._test_detach_device_with_retry_first_detach_failure( |
376 | | - error_code=fakelibvirt.VIR_ERR_DEVICE_MISSING, |
377 | | - error_message="device not found: disk vdb not found", |
378 | | - supports_device_missing=True) |
379 | | - |
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 | | - |
422 | 215 | def test_get_xml_desc(self): |
423 | 216 | self.guest.get_xml_desc() |
424 | 217 | self.domain.XMLDesc.assert_called_once_with(flags=0) |
|
0 commit comments