Wait for udev to settle before listing the block devices
This patch is making the list_all_block_devices() method to wait for udev to settle it's event queue prior to listing the devices. Sometimes the ironic-python-agent service may start before all devices were detected and end up erroring out because it couldn't find a suitable disk for deployment. Closes-Bug: #1551300 Change-Id: I1ae2062a711115a1ea14b79ae9ace7ddd2fff9d5
This commit is contained in:
parent
1971ad7023
commit
055998c812
@ -49,6 +49,21 @@ def _get_device_vendor(dev):
|
|||||||
LOG.warning("Can't find the device vendor for device %s", dev)
|
LOG.warning("Can't find the device vendor for device %s", dev)
|
||||||
|
|
||||||
|
|
||||||
|
def _udev_settle():
|
||||||
|
"""Wait for the udev event queue to settle.
|
||||||
|
|
||||||
|
Wait for the udev event queue to settle to make sure all devices
|
||||||
|
are detected once the machine boots up.
|
||||||
|
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
utils.execute('udevadm', 'settle')
|
||||||
|
except processutils.ProcessExecutionError as e:
|
||||||
|
LOG.warning('Something went wrong when waiting for udev '
|
||||||
|
'to settle. Error: %s', e)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
def list_all_block_devices(block_type='disk'):
|
def list_all_block_devices(block_type='disk'):
|
||||||
"""List all physical block devices
|
"""List all physical block devices
|
||||||
|
|
||||||
@ -63,6 +78,8 @@ def list_all_block_devices(block_type='disk'):
|
|||||||
:return: A list of BlockDevices
|
:return: A list of BlockDevices
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
_udev_settle()
|
||||||
|
|
||||||
columns = ['KNAME', 'MODEL', 'SIZE', 'ROTA', 'TYPE']
|
columns = ['KNAME', 'MODEL', 'SIZE', 'ROTA', 'TYPE']
|
||||||
report = utils.execute('lsblk', '-Pbdi', '-o{}'.format(','.join(columns)),
|
report = utils.execute('lsblk', '-Pbdi', '-o{}'.format(','.join(columns)),
|
||||||
check_exit_code=[0])[0]
|
check_exit_code=[0])[0]
|
||||||
|
@ -246,6 +246,7 @@ class TestHardwareManagerLoading(test_base.BaseTestCase):
|
|||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.object(hardware, '_udev_settle', lambda *_: None)
|
||||||
class TestGenericHardwareManager(test_base.BaseTestCase):
|
class TestGenericHardwareManager(test_base.BaseTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestGenericHardwareManager, self).setUp()
|
super(TestGenericHardwareManager, self).setUp()
|
||||||
@ -889,13 +890,14 @@ class TestGenericHardwareManager(test_base.BaseTestCase):
|
|||||||
self.hardware.get_system_vendor_info().manufacturer)
|
self.hardware.get_system_vendor_info().manufacturer)
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.object(utils, 'execute', autospec=True)
|
||||||
class TestModuleFunctions(test_base.BaseTestCase):
|
class TestModuleFunctions(test_base.BaseTestCase):
|
||||||
|
|
||||||
@mock.patch.object(hardware, '_get_device_vendor', lambda x: "FooTastic")
|
@mock.patch.object(hardware, '_get_device_vendor', lambda x: "FooTastic")
|
||||||
|
@mock.patch.object(hardware, '_udev_settle', autospec=True)
|
||||||
@mock.patch.object(hardware.pyudev.Device, "from_device_file")
|
@mock.patch.object(hardware.pyudev.Device, "from_device_file")
|
||||||
@mock.patch.object(utils, 'execute', autospec=True)
|
def test_list_all_block_devices_success(self, mocked_fromdevfile,
|
||||||
def test_list_all_block_devices_success(self, mocked_execute,
|
mocked_udev, mocked_execute):
|
||||||
mocked_fromdevfile):
|
|
||||||
mocked_fromdevfile.return_value = {}
|
mocked_fromdevfile.return_value = {}
|
||||||
mocked_execute.return_value = (BLK_DEVICE_TEMPLATE_SMALL, '')
|
mocked_execute.return_value = (BLK_DEVICE_TEMPLATE_SMALL, '')
|
||||||
result = hardware.list_all_block_devices()
|
result = hardware.list_all_block_devices()
|
||||||
@ -903,19 +905,23 @@ class TestModuleFunctions(test_base.BaseTestCase):
|
|||||||
'lsblk', '-Pbdi', '-oKNAME,MODEL,SIZE,ROTA,TYPE',
|
'lsblk', '-Pbdi', '-oKNAME,MODEL,SIZE,ROTA,TYPE',
|
||||||
check_exit_code=[0])
|
check_exit_code=[0])
|
||||||
self.assertEqual(BLK_DEVICE_TEMPLATE_SMALL_DEVICES, result)
|
self.assertEqual(BLK_DEVICE_TEMPLATE_SMALL_DEVICES, result)
|
||||||
|
mocked_udev.assert_called_once_with()
|
||||||
|
|
||||||
@mock.patch.object(utils, 'execute', autospec=True)
|
|
||||||
@mock.patch.object(hardware, '_get_device_vendor', lambda x: "FooTastic")
|
@mock.patch.object(hardware, '_get_device_vendor', lambda x: "FooTastic")
|
||||||
def test_list_all_block_devices_wrong_block_type(self, mocked_execute):
|
@mock.patch.object(hardware, '_udev_settle', autospec=True)
|
||||||
|
def test_list_all_block_devices_wrong_block_type(self, mocked_udev,
|
||||||
|
mocked_execute):
|
||||||
mocked_execute.return_value = ('TYPE="foo" MODEL="model"', '')
|
mocked_execute.return_value = ('TYPE="foo" MODEL="model"', '')
|
||||||
result = hardware.list_all_block_devices()
|
result = hardware.list_all_block_devices()
|
||||||
mocked_execute.assert_called_once_with(
|
mocked_execute.assert_called_once_with(
|
||||||
'lsblk', '-Pbdi', '-oKNAME,MODEL,SIZE,ROTA,TYPE',
|
'lsblk', '-Pbdi', '-oKNAME,MODEL,SIZE,ROTA,TYPE',
|
||||||
check_exit_code=[0])
|
check_exit_code=[0])
|
||||||
self.assertEqual([], result)
|
self.assertEqual([], result)
|
||||||
|
mocked_udev.assert_called_once_with()
|
||||||
|
|
||||||
@mock.patch.object(utils, 'execute', autospec=True)
|
@mock.patch.object(hardware, '_udev_settle', autospec=True)
|
||||||
def test_list_all_block_devices_missing(self, mocked_execute):
|
def test_list_all_block_devices_missing(self, mocked_udev,
|
||||||
|
mocked_execute):
|
||||||
"""Test for missing values returned from lsblk"""
|
"""Test for missing values returned from lsblk"""
|
||||||
mocked_execute.return_value = ('TYPE="disk" MODEL="model"', '')
|
mocked_execute.return_value = ('TYPE="disk" MODEL="model"', '')
|
||||||
self.assertRaisesRegexp(
|
self.assertRaisesRegexp(
|
||||||
@ -923,3 +929,8 @@ class TestModuleFunctions(test_base.BaseTestCase):
|
|||||||
r'^Block device caused unknown error: KNAME, ROTA, SIZE must be '
|
r'^Block device caused unknown error: KNAME, ROTA, SIZE must be '
|
||||||
r'returned by lsblk.$',
|
r'returned by lsblk.$',
|
||||||
hardware.list_all_block_devices)
|
hardware.list_all_block_devices)
|
||||||
|
mocked_udev.assert_called_once_with()
|
||||||
|
|
||||||
|
def test__udev_settle(self, mocked_execute):
|
||||||
|
hardware._udev_settle()
|
||||||
|
mocked_execute.assert_called_once_with('udevadm', 'settle')
|
||||||
|
3
releasenotes/notes/udev-settle-f75db34db990ad68.yaml
Normal file
3
releasenotes/notes/udev-settle-f75db34db990ad68.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- Ensure block devices are detected by the host OS before listing them.
|
Loading…
Reference in New Issue
Block a user