diff --git a/ironic_python_agent/hardware.py b/ironic_python_agent/hardware.py index bf90e5cf0..49473ac2b 100644 --- a/ironic_python_agent/hardware.py +++ b/ironic_python_agent/hardware.py @@ -392,12 +392,18 @@ class GenericHardwareManager(HardwareManager): if not root_device_hints: # If no hints are passed find the first device larger than - # 4GB, assume it is the OS disk + # 4GiB, assume it is the OS disk + min_size_required = 4 * units.Gi # TODO(russellhaering): This isn't a valid assumption in # all cases, is there a more reasonable default behavior? block_devices.sort(key=lambda device: device.size) + if block_devices[-1].size < min_size_required: + raise errors.DeviceNotFound("No suitable device was found " + "for deployment - root device hints were not provided " + "and all found block devices are smaller than %iB." + % min_size_required) for device in block_devices: - if device.size >= (4 * pow(1024, 3)): + if device.size >= min_size_required: return device.name else: diff --git a/ironic_python_agent/tests/unit/test_hardware.py b/ironic_python_agent/tests/unit/test_hardware.py index ceac031fe..ab1679679 100644 --- a/ironic_python_agent/tests/unit/test_hardware.py +++ b/ironic_python_agent/tests/unit/test_hardware.py @@ -16,6 +16,7 @@ import mock import netifaces import os from oslo_concurrency import processutils +from oslo_utils import units from oslotest import base as test_base import pyudev import six @@ -132,6 +133,14 @@ BLK_DEVICE_TEMPLATE = ( 'KNAME="loop0" MODEL="" SIZE="109109248" ROTA="1" TYPE="loop"' ) +# NOTE(pas-ha) largest device is 1 byte smaller than 4GiB +BLK_DEVICE_TEMPLATE_SMALL = ( + 'KNAME="sda" MODEL="TinyUSB Drive" SIZE="3116853504" ' + 'ROTA="0" TYPE="disk"\n' + 'KNAME="sdb" MODEL="AlmostBigEnough Drive" SIZE="4294967295" ' + 'ROTA="0" TYPE="disk"' +) + SHRED_OUTPUT = ( 'shred: /dev/sda: pass 1/2 (random)...\n' 'shred: /dev/sda: pass 1/2 (random)...4.9GiB/29GiB 17%\n' @@ -271,6 +280,16 @@ class TestGenericHardwareManager(test_base.BaseTestCase): 'lsblk', '-PbdioKNAME,MODEL,SIZE,ROTA,TYPE', check_exit_code=[0]) + @mock.patch.object(utils, 'execute') + def test_get_os_install_device_fails(self, mocked_execute): + """Fail to find device >=4GB w/o root device hints""" + mocked_execute.return_value = (BLK_DEVICE_TEMPLATE_SMALL, '') + ex = self.assertRaises(errors.DeviceNotFound, + self.hardware.get_os_install_device) + mocked_execute.assert_called_once_with( + 'lsblk', '-PbdioKNAME,MODEL,SIZE,ROTA,TYPE', check_exit_code=[0]) + self.assertIn(str(4 * units.Gi), ex.details) + @mock.patch.object(hardware.GenericHardwareManager, '_get_device_vendor') @mock.patch.object(pyudev.Device, 'from_device_file') @mock.patch.object(utils, 'parse_root_device_hints')