|
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