Software RAID: try to assemble RAID on start-up
TinyIPA does not do it, which prevents deployment on RAID devices. Story: #2004581 Task: #36196 Change-Id: I6c1d90b4669102ab59588ab15f7166626c4d72be
This commit is contained in:
parent
258d963e40
commit
c7c307c497
@ -212,6 +212,17 @@ def md_restart(raid_device):
|
||||
raise errors.CommandExecutionError(error_msg)
|
||||
|
||||
|
||||
def _md_scan_and_assemble():
|
||||
"""Scan all md devices and assemble RAID arrays from them.
|
||||
|
||||
This call does not fail if no md devices are present.
|
||||
"""
|
||||
try:
|
||||
utils.execute('mdadm', '--assemble', '--scan', '--verbose')
|
||||
except processutils.ProcessExecutionError:
|
||||
LOG.info('No new RAID devices assembled during start-up')
|
||||
|
||||
|
||||
def list_all_block_devices(block_type='disk',
|
||||
ignore_raid=False):
|
||||
"""List all physical block devices
|
||||
@ -700,6 +711,7 @@ class GenericHardwareManager(HardwareManager):
|
||||
def evaluate_hardware_support(self):
|
||||
# Do some initialization before we declare ourself ready
|
||||
_check_for_iscsi()
|
||||
_md_scan_and_assemble()
|
||||
self.wait_for_disks()
|
||||
return HardwareSupport.GENERIC
|
||||
|
||||
|
@ -128,6 +128,8 @@ class TestHeartbeater(ironic_agent_base.IronicAgentTest):
|
||||
self.assertEqual(2.7, self.heartbeater.error_delay)
|
||||
|
||||
|
||||
@mock.patch.object(hardware, '_md_scan_and_assemble', lambda: None)
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', lambda: None)
|
||||
@mock.patch.object(hardware.GenericHardwareManager, 'wait_for_disks',
|
||||
lambda self: None)
|
||||
class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
@ -173,7 +175,6 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
self.assertEqual(pkg_resources.get_distribution('ironic-python-agent')
|
||||
.version, status.version)
|
||||
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', mock.Mock())
|
||||
@mock.patch(
|
||||
'ironic_python_agent.hardware_managers.cna._detect_cna_card',
|
||||
mock.Mock())
|
||||
@ -219,7 +220,6 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
self.agent.heartbeater.start.assert_called_once_with()
|
||||
|
||||
@mock.patch('ironic_lib.mdns.get_endpoint', autospec=True)
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', mock.Mock())
|
||||
@mock.patch(
|
||||
'ironic_python_agent.hardware_managers.cna._detect_cna_card',
|
||||
mock.Mock())
|
||||
@ -276,7 +276,6 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
self.agent.heartbeater.start.assert_called_once_with()
|
||||
|
||||
@mock.patch('ironic_lib.mdns.get_endpoint', autospec=True)
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', mock.Mock())
|
||||
@mock.patch(
|
||||
'ironic_python_agent.hardware_managers.cna._detect_cna_card',
|
||||
mock.Mock())
|
||||
@ -338,7 +337,6 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
# changed via mdns
|
||||
self.assertEqual(42, CONF.disk_wait_attempts)
|
||||
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', mock.Mock())
|
||||
@mock.patch(
|
||||
'ironic_python_agent.hardware_managers.cna._detect_cna_card',
|
||||
mock.Mock())
|
||||
@ -382,7 +380,6 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
self.agent.heartbeater.start.assert_called_once_with()
|
||||
self.assertTrue(wsgi_server.handle_request.called)
|
||||
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', mock.Mock())
|
||||
@mock.patch('ironic_python_agent.hardware_managers.cna._detect_cna_card',
|
||||
mock.Mock())
|
||||
@mock.patch.object(agent.IronicPythonAgent,
|
||||
@ -436,7 +433,6 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
self.agent.heartbeater.start.assert_called_once_with()
|
||||
|
||||
@mock.patch('ironic_lib.mdns.get_endpoint', autospec=True)
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', mock.Mock())
|
||||
@mock.patch(
|
||||
'ironic_python_agent.hardware_managers.cna._detect_cna_card',
|
||||
mock.Mock())
|
||||
@ -494,7 +490,6 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
self.assertFalse(mock_dispatch.called)
|
||||
|
||||
@mock.patch('ironic_lib.mdns.get_endpoint', autospec=True)
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', mock.Mock())
|
||||
@mock.patch(
|
||||
'ironic_python_agent.hardware_managers.cna._detect_cna_card',
|
||||
mock.Mock())
|
||||
@ -710,6 +705,8 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
mock_log.warning.assert_called_once()
|
||||
|
||||
|
||||
@mock.patch.object(hardware, '_md_scan_and_assemble', lambda: None)
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', lambda: None)
|
||||
@mock.patch.object(hardware.GenericHardwareManager, 'wait_for_disks',
|
||||
lambda self: None)
|
||||
class TestAgentStandalone(ironic_agent_base.IronicAgentTest):
|
||||
@ -730,7 +727,6 @@ class TestAgentStandalone(ironic_agent_base.IronicAgentTest):
|
||||
'agent_ipmitool',
|
||||
True)
|
||||
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', mock.Mock())
|
||||
@mock.patch(
|
||||
'ironic_python_agent.hardware_managers.cna._detect_cna_card',
|
||||
mock.Mock())
|
||||
@ -768,6 +764,7 @@ class TestAgentStandalone(ironic_agent_base.IronicAgentTest):
|
||||
self.assertFalse(self.agent.api_client.lookup_node.called)
|
||||
|
||||
|
||||
@mock.patch.object(hardware, '_md_scan_and_assemble', lambda: None)
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', lambda: None)
|
||||
@mock.patch.object(hardware.GenericHardwareManager, 'wait_for_disks',
|
||||
lambda self: None)
|
||||
|
@ -3069,12 +3069,44 @@ class TestGenericHardwareManager(base.IronicAgentTest):
|
||||
self.assertEqual('', vendor_info.serial_number)
|
||||
self.assertEqual('', vendor_info.manufacturer)
|
||||
|
||||
@mock.patch.object(hardware.GenericHardwareManager,
|
||||
'get_os_install_device', autospec=True)
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', autospec=True)
|
||||
@mock.patch.object(time, 'sleep', autospec=True)
|
||||
@mock.patch.object(utils, 'get_agent_params',
|
||||
lambda: {'BOOTIF': 'boot:if'})
|
||||
@mock.patch.object(os.path, 'isdir', autospec=True)
|
||||
def test_get_boot_info_pxe_interface(self, mocked_isdir):
|
||||
mocked_isdir.return_value = False
|
||||
result = self.hardware.get_boot_info()
|
||||
self.assertEqual(hardware.BootInfo(current_boot_mode='bios',
|
||||
pxe_interface='boot:if'),
|
||||
result)
|
||||
|
||||
@mock.patch.object(os.path, 'isdir', autospec=True)
|
||||
def test_get_boot_info_bios(self, mocked_isdir):
|
||||
mocked_isdir.return_value = False
|
||||
result = self.hardware.get_boot_info()
|
||||
self.assertEqual(hardware.BootInfo(current_boot_mode='bios'), result)
|
||||
mocked_isdir.assert_called_once_with('/sys/firmware/efi')
|
||||
|
||||
@mock.patch.object(os.path, 'isdir', autospec=True)
|
||||
def test_get_boot_info_uefi(self, mocked_isdir):
|
||||
mocked_isdir.return_value = True
|
||||
result = self.hardware.get_boot_info()
|
||||
self.assertEqual(hardware.BootInfo(current_boot_mode='uefi'), result)
|
||||
mocked_isdir.assert_called_once_with('/sys/firmware/efi')
|
||||
|
||||
|
||||
@mock.patch.object(hardware.GenericHardwareManager,
|
||||
'get_os_install_device', autospec=True)
|
||||
@mock.patch.object(hardware, '_md_scan_and_assemble', autospec=True)
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', autospec=True)
|
||||
@mock.patch.object(time, 'sleep', autospec=True)
|
||||
class TestEvaluateHardwareSupport(base.IronicAgentTest):
|
||||
def setUp(self):
|
||||
super(TestEvaluateHardwareSupport, self).setUp()
|
||||
self.hardware = hardware.GenericHardwareManager()
|
||||
|
||||
def test_evaluate_hw_waits_for_disks(
|
||||
self, mocked_sleep, mocked_check_for_iscsi, mocked_get_inst_dev):
|
||||
self, mocked_sleep, mocked_check_for_iscsi,
|
||||
mocked_md_assemble, mocked_get_inst_dev):
|
||||
mocked_get_inst_dev.side_effect = [
|
||||
errors.DeviceNotFound('boom'),
|
||||
None
|
||||
@ -3083,19 +3115,16 @@ class TestGenericHardwareManager(base.IronicAgentTest):
|
||||
result = self.hardware.evaluate_hardware_support()
|
||||
|
||||
self.assertTrue(mocked_check_for_iscsi.called)
|
||||
self.assertTrue(mocked_md_assemble.called)
|
||||
self.assertEqual(hardware.HardwareSupport.GENERIC, result)
|
||||
mocked_get_inst_dev.assert_called_with(mock.ANY)
|
||||
self.assertEqual(2, mocked_get_inst_dev.call_count)
|
||||
mocked_sleep.assert_called_once_with(CONF.disk_wait_delay)
|
||||
|
||||
@mock.patch.object(hardware, 'LOG', autospec=True)
|
||||
@mock.patch.object(hardware.GenericHardwareManager,
|
||||
'get_os_install_device', autospec=True)
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', autospec=True)
|
||||
@mock.patch.object(time, 'sleep', autospec=True)
|
||||
def test_evaluate_hw_no_wait_for_disks(
|
||||
self, mocked_sleep, mocked_check_for_iscsi, mocked_get_inst_dev,
|
||||
mocked_log):
|
||||
self, mocked_log, mocked_sleep, mocked_check_for_iscsi,
|
||||
mocked_md_assemble, mocked_get_inst_dev):
|
||||
CONF.set_override('disk_wait_attempts', '0')
|
||||
|
||||
result = self.hardware.evaluate_hardware_support()
|
||||
@ -3107,12 +3136,9 @@ class TestGenericHardwareManager(base.IronicAgentTest):
|
||||
self.assertFalse(mocked_log.called)
|
||||
|
||||
@mock.patch.object(hardware, 'LOG', autospec=True)
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', mock.Mock())
|
||||
@mock.patch.object(hardware.GenericHardwareManager,
|
||||
'get_os_install_device', autospec=True)
|
||||
@mock.patch.object(time, 'sleep', autospec=True)
|
||||
def test_evaluate_hw_waits_for_disks_nonconfigured(
|
||||
self, mocked_sleep, mocked_get_inst_dev, mocked_log):
|
||||
self, mocked_log, mocked_sleep, mocked_check_for_iscsi,
|
||||
mocked_md_assemble, mocked_get_inst_dev):
|
||||
mocked_get_inst_dev.side_effect = [
|
||||
errors.DeviceNotFound('boom'),
|
||||
errors.DeviceNotFound('boom'),
|
||||
@ -3139,13 +3165,11 @@ class TestGenericHardwareManager(base.IronicAgentTest):
|
||||
CONF.disk_wait_delay * 9)
|
||||
|
||||
@mock.patch.object(hardware, 'LOG', autospec=True)
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', mock.Mock())
|
||||
@mock.patch.object(hardware.GenericHardwareManager,
|
||||
'get_os_install_device', autospec=True)
|
||||
@mock.patch.object(time, 'sleep', autospec=True)
|
||||
def test_evaluate_hw_waits_for_disks_configured(self, mocked_sleep,
|
||||
mocked_get_inst_dev,
|
||||
mocked_log):
|
||||
def test_evaluate_hw_waits_for_disks_configured(self, mocked_log,
|
||||
mocked_sleep,
|
||||
mocked_check_for_iscsi,
|
||||
mocked_md_assemble,
|
||||
mocked_get_inst_dev):
|
||||
CONF.set_override('disk_wait_attempts', '1')
|
||||
|
||||
mocked_get_inst_dev.side_effect = [
|
||||
@ -3162,21 +3186,17 @@ class TestGenericHardwareManager(base.IronicAgentTest):
|
||||
mocked_log.warning.assert_called_once_with(
|
||||
'The root device was not detected')
|
||||
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', mock.Mock())
|
||||
@mock.patch.object(hardware.GenericHardwareManager,
|
||||
'get_os_install_device', autospec=True)
|
||||
@mock.patch.object(time, 'sleep', autospec=True)
|
||||
def test_evaluate_hw_disks_timeout_unconfigured(self, mocked_sleep,
|
||||
mocked_check_for_iscsi,
|
||||
mocked_md_assemble,
|
||||
mocked_get_inst_dev):
|
||||
mocked_get_inst_dev.side_effect = errors.DeviceNotFound('boom')
|
||||
self.hardware.evaluate_hardware_support()
|
||||
mocked_sleep.assert_called_with(3)
|
||||
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', mock.Mock())
|
||||
@mock.patch.object(hardware.GenericHardwareManager,
|
||||
'get_os_install_device', autospec=True)
|
||||
@mock.patch.object(time, 'sleep', autospec=True)
|
||||
def test_evaluate_hw_disks_timeout_configured(self, mocked_sleep,
|
||||
mocked_check_for_iscsi,
|
||||
mocked_md_assemble,
|
||||
mocked_root_dev):
|
||||
CONF.set_override('disk_wait_delay', '5')
|
||||
mocked_root_dev.side_effect = errors.DeviceNotFound('boom')
|
||||
@ -3184,12 +3204,9 @@ class TestGenericHardwareManager(base.IronicAgentTest):
|
||||
self.hardware.evaluate_hardware_support()
|
||||
mocked_sleep.assert_called_with(5)
|
||||
|
||||
@mock.patch.object(hardware.GenericHardwareManager,
|
||||
'get_os_install_device', autospec=True)
|
||||
@mock.patch.object(hardware, '_check_for_iscsi', autospec=True)
|
||||
@mock.patch.object(time, 'sleep', autospec=True)
|
||||
def test_evaluate_hw_disks_timeout(
|
||||
self, mocked_sleep, mocked_check_for_iscsi, mocked_get_inst_dev):
|
||||
self, mocked_sleep, mocked_check_for_iscsi,
|
||||
mocked_md_assemble, mocked_get_inst_dev):
|
||||
mocked_get_inst_dev.side_effect = errors.DeviceNotFound('boom')
|
||||
result = self.hardware.evaluate_hardware_support()
|
||||
self.assertEqual(hardware.HardwareSupport.GENERIC, result)
|
||||
@ -3198,30 +3215,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
|
||||
mocked_get_inst_dev.call_count)
|
||||
mocked_sleep.assert_called_with(CONF.disk_wait_delay)
|
||||
|
||||
@mock.patch.object(utils, 'get_agent_params',
|
||||
lambda: {'BOOTIF': 'boot:if'})
|
||||
@mock.patch.object(os.path, 'isdir', autospec=True)
|
||||
def test_get_boot_info_pxe_interface(self, mocked_isdir):
|
||||
mocked_isdir.return_value = False
|
||||
result = self.hardware.get_boot_info()
|
||||
self.assertEqual(hardware.BootInfo(current_boot_mode='bios',
|
||||
pxe_interface='boot:if'),
|
||||
result)
|
||||
|
||||
@mock.patch.object(os.path, 'isdir', autospec=True)
|
||||
def test_get_boot_info_bios(self, mocked_isdir):
|
||||
mocked_isdir.return_value = False
|
||||
result = self.hardware.get_boot_info()
|
||||
self.assertEqual(hardware.BootInfo(current_boot_mode='bios'), result)
|
||||
mocked_isdir.assert_called_once_with('/sys/firmware/efi')
|
||||
|
||||
@mock.patch.object(os.path, 'isdir', autospec=True)
|
||||
def test_get_boot_info_uefi(self, mocked_isdir):
|
||||
mocked_isdir.return_value = True
|
||||
result = self.hardware.get_boot_info()
|
||||
self.assertEqual(hardware.BootInfo(current_boot_mode='uefi'), result)
|
||||
mocked_isdir.assert_called_once_with('/sys/firmware/efi')
|
||||
|
||||
|
||||
@mock.patch.object(os, 'listdir', lambda *_: [])
|
||||
@mock.patch.object(utils, 'execute', autospec=True)
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Tries to assemble software RAID automatically on start up to avoid problems
|
||||
with ramdisks that don't do it automatically (like tinyipa).
|
Loading…
Reference in New Issue
Block a user