Wait for device to be mapped
There's a race condition when trying to perform file injection without libguestfs, which causes a fallback to nbd device. Although the kpartx command succeeds, it does so after the code has tested for success, so Nova thinks it failed. Retry a few times to avoid this. Co-Authored-By: Paul Carlton <paul.carlton2@hp.com> Change-Id: Ie5c186562475cd56c55520ad7123f47a0130b2a4 Closes-Bug: #1428639 Closes-Bug: #1484586
This commit is contained in:
parent
4c18867424
commit
2c1b19761b
|
@ -59,9 +59,11 @@ class MountTestCase(test.NoDBTestCase):
|
|||
self.fail("Unexpected call with: %s" % filename)
|
||||
return exists_effect
|
||||
|
||||
def _check_calls(self, exists, filenames):
|
||||
def _check_calls(self, exists, filenames, trailing=0):
|
||||
self.assertEqual([mock.call(x) for x in filenames],
|
||||
exists.call_args_list)
|
||||
exists.call_args_list[:len(filenames)])
|
||||
self.assertEqual([mock.call(MAP_PARTITION)] * trailing,
|
||||
exists.call_args_list[len(filenames):])
|
||||
|
||||
@mock.patch('os.path.exists')
|
||||
def test_map_dev_partition_search(self, exists):
|
||||
|
@ -79,8 +81,7 @@ class MountTestCase(test.NoDBTestCase):
|
|||
AUTOMAP_PARTITION: False,
|
||||
MAP_PARTITION: [False, True]})
|
||||
mount = self._test_map_dev_with_trycmd(PARTITION)
|
||||
self._check_calls(exists,
|
||||
[ORIG_DEVICE, AUTOMAP_PARTITION, MAP_PARTITION, MAP_PARTITION])
|
||||
self._check_calls(exists, [ORIG_DEVICE, AUTOMAP_PARTITION], 2)
|
||||
self.assertEqual("", mount.error)
|
||||
self.assertTrue(mount.mapped)
|
||||
|
||||
|
@ -91,11 +92,22 @@ class MountTestCase(test.NoDBTestCase):
|
|||
AUTOMAP_PARTITION: False,
|
||||
MAP_PARTITION: False})
|
||||
mount = self._test_map_dev_with_trycmd(PARTITION)
|
||||
self._check_calls(exists,
|
||||
[ORIG_DEVICE, AUTOMAP_PARTITION, MAP_PARTITION, MAP_PARTITION])
|
||||
self._check_calls(exists, [ORIG_DEVICE, AUTOMAP_PARTITION],
|
||||
api.MAX_FILE_CHECKS + 1)
|
||||
self.assertNotEqual("", mount.error)
|
||||
self.assertFalse(mount.mapped)
|
||||
|
||||
@mock.patch('os.path.exists')
|
||||
def test_map_dev_error_then_pass(self, exists):
|
||||
exists.side_effect = self._exists_effect({
|
||||
ORIG_DEVICE: True,
|
||||
AUTOMAP_PARTITION: False,
|
||||
MAP_PARTITION: [False, False, True]})
|
||||
mount = self._test_map_dev_with_trycmd(PARTITION)
|
||||
self._check_calls(exists, [ORIG_DEVICE, AUTOMAP_PARTITION], 3)
|
||||
self.assertEqual("", mount.error)
|
||||
self.assertTrue(mount.mapped)
|
||||
|
||||
@mock.patch('os.path.exists')
|
||||
def test_map_dev_automap(self, exists):
|
||||
exists.side_effect = self._exists_effect({
|
||||
|
|
|
@ -17,6 +17,7 @@ import os
|
|||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslo_service import loopingcall
|
||||
from oslo_utils import importutils
|
||||
|
||||
from nova import exception
|
||||
|
@ -27,6 +28,8 @@ from nova.virt.image import model as imgmodel
|
|||
LOG = logging.getLogger(__name__)
|
||||
|
||||
MAX_DEVICE_WAIT = 30
|
||||
MAX_FILE_CHECKS = 6
|
||||
FILE_CHECK_INTERVAL = 0.25
|
||||
|
||||
|
||||
class Mount(object):
|
||||
|
@ -200,15 +203,24 @@ class Mount(object):
|
|||
_out, err = utils.trycmd('kpartx', '-a', self.device,
|
||||
run_as_root=True, discard_warnings=True)
|
||||
|
||||
@loopingcall.RetryDecorator(
|
||||
max_retry_count=MAX_FILE_CHECKS - 1,
|
||||
max_sleep_time=FILE_CHECK_INTERVAL,
|
||||
exceptions=IOError)
|
||||
def recheck_path(map_path):
|
||||
if not os.path.exists(map_path):
|
||||
raise IOError()
|
||||
|
||||
# Note kpartx does nothing when presented with a raw image,
|
||||
# so given we only use it when we expect a partitioned image, fail
|
||||
if not os.path.exists(map_path):
|
||||
try:
|
||||
recheck_path(map_path)
|
||||
self.mapped_device = map_path
|
||||
self.mapped = True
|
||||
except IOError:
|
||||
if not err:
|
||||
err = _('partition %s not found') % self.partition
|
||||
self.error = _('Failed to map partitions: %s') % err
|
||||
else:
|
||||
self.mapped_device = map_path
|
||||
self.mapped = True
|
||||
elif self.partition and os.path.exists(automapped_path):
|
||||
# Note auto mapping can be enabled with the 'max_part' option
|
||||
# to the nbd or loop kernel modules. Beware of possible races
|
||||
|
|
Loading…
Reference in New Issue