def _test_guess_root_disk(self, size=8, device_name='/dev/vda'): devices = [ hardware.BlockDevice(name='/dev/sdd', model='NWD-BLP4-1600', size=207374182400, rotational=False, vendor='Super Vendor', hctl='1:0:0:0'), hardware.BlockDevice(name='/dev/sda', model='TinyUSB Drive', size=3116853504, rotational=False, vendor='Super Vendor', hctl='1:0:0:0'), hardware.BlockDevice(name='/dev/sdc', model='NWD-BLP4-1600', size=107374182400, rotational=False, vendor='Super Vendor', hctl='1:0:0:0'), hardware.BlockDevice(name='/dev/sdb', model='Fastable SD131 7', size=107374182400, rotational=False, vendor='Super Vendor', hctl='1:0:0:0'), ] require_device_name = device_name device = utils.guess_root_disk(devices, size * units.Gi) self.assertEqual(device.name, require_device_name)
def _wait_for_disks(self): # Wait for at least one suitable disk to show up, otherwise neither # inspection not deployment have any chances to succeed. for attempt in range(_DISK_WAIT_ATTEMPTS): try: block_devices = self.list_block_devices() utils.guess_root_disk(block_devices) except errors.DeviceNotFound: LOG.debug('Still waiting for at least one disk to appear, ' 'attempt %d of %d', attempt + 1, _DISK_WAIT_ATTEMPTS) time.sleep(_DISK_WAIT_DELAY) else: break else: LOG.warning('No disks detected in %d seconds', _DISK_WAIT_DELAY * _DISK_WAIT_ATTEMPTS)
def collect_default(data, failures): """The default inspection collector. This is the only collector that is called by default. It collects the whole inventory as returned by the hardware manager(s). It also tries to get BMC address, PXE boot device and the expected root device. :param data: mutable data that we'll send to inspector :param failures: AccumulatedFailures object """ wait_for_dhcp() inventory = hardware.list_hardware_info() data['inventory'] = inventory # Replicate the same logic as in deploy. We need to make sure that when # root device hints are not set, inspector will use the same root disk as # will be used for deploy. try: root_disk = utils.guess_root_disk(inventory['disks'][:]) except errors.DeviceNotFound: root_disk = None LOG.warning('no suitable root device detected') else: data['root_disk'] = root_disk LOG.debug('default root device is %s', root_disk.name) # The boot interface might not be present, we don't count it as failure. # TODO(dtantsur): stop using the boot_interface field. data['boot_interface'] = inventory['boot'].pxe_interface LOG.debug('boot devices was %s', data['boot_interface']) LOG.debug('BMC IP address: %s', inventory.get('bmc_address'))
def collect_default(data, failures): """The default inspection collector. This is the only collector that is called by default. It collects the whole inventory as returned by the hardware manager(s). It also tries to get BMC address, PXE boot device and the expected root device. :param data: mutable data that we'll send to inspector :param failures: AccumulatedFailures object """ wait_for_dhcp() inventory = hardware.dispatch_to_managers('list_hardware_info') data['inventory'] = inventory # Replicate the same logic as in deploy. We need to make sure that when # root device hints are not set, inspector will use the same root disk as # will be used for deploy. try: root_disk = utils.guess_root_disk(inventory['disks'][:]) except errors.DeviceNotFound: root_disk = None LOG.warning('no suitable root device detected') else: data['root_disk'] = root_disk LOG.debug('default root device is %s', root_disk.name) # The boot interface might not be present, we don't count it as failure. # TODO(dtantsur): stop using the boot_interface field. data['boot_interface'] = inventory['boot'].pxe_interface LOG.debug('boot devices was %s', data['boot_interface']) LOG.debug('BMC IP address: %s', inventory.get('bmc_address'))
def get_os_install_device(self): cached_node = get_cached_node() root_device_hints = None if cached_node is not None: root_device_hints = cached_node['properties'].get('root_device') block_devices = self.list_block_devices() if not root_device_hints: return utils.guess_root_disk(block_devices).name else: serialized_devs = [dev.serialize() for dev in block_devices] try: device = il_utils.match_root_device_hints(serialized_devs, root_device_hints) except ValueError as e: # NOTE(lucasagomes): Just playing on the safe side # here, this exception should never be raised because # Ironic should validate the root device hints before the # deployment starts. raise errors.DeviceNotFound( 'No devices could be found using the root device hints ' '%(hints)s because they failed to validate. Error: ' '%(error)s' % {'hints': root_device_hints, 'error': e}) if not device: raise errors.DeviceNotFound( "No suitable device was found for " "deployment using these hints %s" % root_device_hints) return device['name']
def get_os_install_device(self): cached_node = get_cached_node() root_device_hints = None if cached_node is not None: root_device_hints = cached_node['properties'].get('root_device') block_devices = self.list_block_devices() if not root_device_hints: return utils.guess_root_disk(block_devices).name else: def match(hint, current_value, device): hint_value = root_device_hints[hint] if hint_value != current_value: LOG.debug( "Root device hint %(hint)s=%(value)s does not " "match the device %(device)s value of " "%(current)s", { 'hint': hint, 'value': hint_value, 'device': device, 'current': current_value }) return False return True def check_device_attrs(device): for key in ('model', 'wwn', 'serial', 'vendor', 'wwn_with_extension', 'wwn_vendor_extension', 'name'): if key not in root_device_hints: continue value = getattr(device, key) if not value: return False value = utils.normalize(value) if not match(key, value, device.name): return False return True for dev in block_devices: # TODO(lucasagomes): Add support for operators <, >, =, etc... # to better deal with sizes. if 'size' in root_device_hints: # Since we don't support units yet we expect the size # in GiB for now size = dev.size / units.Gi if not match('size', size, dev.name): continue if check_device_attrs(dev): return dev.name else: raise errors.DeviceNotFound("No suitable device was found for " "deployment using these hints %s" % root_device_hints)
def get_os_install_device(self): cached_node = get_cached_node() root_device_hints = None if cached_node is not None: root_device_hints = cached_node['properties'].get('root_device') block_devices = self.list_block_devices() if not root_device_hints: return utils.guess_root_disk(block_devices).name else: def match(hint, current_value, device): hint_value = root_device_hints[hint] if hint_value != current_value: LOG.debug("Root device hint %(hint)s=%(value)s does not " "match the device %(device)s value of " "%(current)s", { 'hint': hint, 'value': hint_value, 'device': device, 'current': current_value}) return False return True def check_device_attrs(device): for key in ('model', 'wwn', 'serial', 'vendor', 'wwn_with_extension', 'wwn_vendor_extension', 'name'): if key not in root_device_hints: continue value = getattr(device, key) if not value: return False value = utils.normalize(value) if not match(key, value, device.name): return False return True for dev in block_devices: # TODO(lucasagomes): Add support for operators <, >, =, etc... # to better deal with sizes. if 'size' in root_device_hints: # Since we don't support units yet we expect the size # in GiB for now size = dev.size / units.Gi if not match('size', size, dev.name): continue if check_device_attrs(dev): return dev.name else: raise errors.DeviceNotFound( "No suitable device was found for " "deployment using these hints %s" % root_device_hints)
def _wait_for_disks(self): """Wait for disk to appear Wait for at least one suitable disk to show up, otherwise neither inspection not deployment have any chances to succeed. """ for attempt in range(CONF.disk_wait_attempts): try: block_devices = self.list_block_devices() utils.guess_root_disk(block_devices) except errors.DeviceNotFound: LOG.debug('Still waiting for at least one disk to appear, ' 'attempt %d of %d', attempt + 1, CONF.disk_wait_attempts) time.sleep(CONF.disk_wait_delay) else: break else: LOG.warning('No disks detected in %d seconds', CONF.disk_wait_delay * CONF.disk_wait_attempts)
def collect_default(data, failures): """The default inspection collector. This is the only collector that is called by default. It is designed to be both backward and future compatible: 1. it collects exactly the same data as the old bash-based ramdisk 2. it also posts the whole inventory which we'll eventually use. In both cases it tries to get BMC address, PXE boot device and the expected root device. :param data: mutable data that we'll send to inspector :param failures: AccumulatedFailures object """ wait_for_dhcp() inventory = hardware.dispatch_to_managers('list_hardware_info') # In the future we will only need the current version of inventory, # a guessed root disk, PXE boot interface and IPMI address. # Everything else will be done by inspector itself and its plugins. data['inventory'] = inventory # Replicate the same logic as in deploy. We need to make sure that when # root device hints are not set, inspector will use the same root disk as # will be used for deploy. try: root_disk = utils.guess_root_disk(inventory['disks'][:]) except errors.DeviceNotFound: root_disk = None LOG.warning('no suitable root device detected') else: data['root_disk'] = root_disk LOG.debug('default root device is %s', root_disk.name) # Both boot interface and IPMI address might not be present, # we don't count it as failure data['boot_interface'] = inventory['boot'].pxe_interface LOG.debug('boot devices was %s', data['boot_interface']) data['ipmi_address'] = inventory.get('bmc_address') LOG.debug('BMC IP address: %s', data['ipmi_address']) # These 2 calls are required for backward compatibility and should be # dropped after inspector is ready (probably in Mitaka cycle). discover_network_properties(inventory, data, failures) discover_scheduling_properties(inventory, data, root_disk)
def test_guess_root_disk_primary_sort(self, mock_call): block_devices = [ hardware.BlockDevice(name='/dev/sdc', model='too small', size=4294967295, rotational=True), hardware.BlockDevice(name='/dev/sda', model='bigger than sdb', size=21474836480, rotational=True), hardware.BlockDevice(name='/dev/sdb', model='', size=10737418240, rotational=True), hardware.BlockDevice(name='/dev/sdd', model='bigger than sdb', size=21474836480, rotational=True), ] device = utils.guess_root_disk(block_devices) self.assertEqual(device.name, '/dev/sdb')
def test_guess_root_disk_secondary_sort(self, mock_call): block_devices = [ hardware.BlockDevice(name='/dev/sdc', model='_', size=10737418240, rotational=True), hardware.BlockDevice(name='/dev/sdb', model='_', size=10737418240, rotational=True), hardware.BlockDevice(name='/dev/sda', model='_', size=10737418240, rotational=True), hardware.BlockDevice(name='/dev/sdd', model='_', size=10737418240, rotational=True), ] device = utils.guess_root_disk(block_devices) self.assertEqual(device.name, '/dev/sda')
def get_os_install_device(self): cached_node = get_cached_node() root_device_hints = None if cached_node is not None: root_device_hints = cached_node['properties'].get('root_device') LOG.debug('Looking for a device matching root hints %s', root_device_hints) block_devices = self.list_block_devices() if not root_device_hints: dev_name = utils.guess_root_disk(block_devices).name else: serialized_devs = [dev.serialize() for dev in block_devices] try: device = il_utils.match_root_device_hints(serialized_devs, root_device_hints) except ValueError as e: # NOTE(lucasagomes): Just playing on the safe side # here, this exception should never be raised because # Ironic should validate the root device hints before the # deployment starts. raise errors.DeviceNotFound( 'No devices could be found using the root device hints ' '%(hints)s because they failed to validate. Error: ' '%(error)s' % {'hints': root_device_hints, 'error': e}) if not device: raise errors.DeviceNotFound( "No suitable device was found for " "deployment using these hints %s" % root_device_hints) dev_name = device['name'] LOG.info('Picked root device %(dev)s for node %(node)s based on ' 'root device hints %(hints)s', {'dev': dev_name, 'hints': root_device_hints, 'node': cached_node['uuid'] if cached_node else None}) return dev_name
def get_os_install_device(self): cached_node = get_cached_node() root_device_hints = None if cached_node is not None: root_device_hints = cached_node['properties'].get('root_device') block_devices = self.list_block_devices() if not root_device_hints: return utils.guess_root_disk(block_devices).name else: def match(hint, current_value, device): hint_value = root_device_hints[hint] if hint == 'rotational': hint_value = strutils.bool_from_string(hint_value) elif hint == 'size': try: hint_value = int(hint_value) except (ValueError, TypeError): LOG.warning( 'Root device hint "size" is not an integer. ' 'Current value: "%(value)s"; and type: "%(type)s"', { 'value': hint_value, 'type': type(hint_value) }) return False if hint_value != current_value: LOG.debug( "Root device hint %(hint)s=%(value)s does not " "match the device %(device)s value of " "%(current)s", { 'hint': hint, 'value': hint_value, 'device': device, 'current': current_value }) return False return True def check_device_attrs(device): for key in ('model', 'wwn', 'serial', 'vendor', 'wwn_with_extension', 'wwn_vendor_extension', 'name', 'rotational', 'size'): if key not in root_device_hints: continue value = getattr(device, key) if value is None: return False if isinstance(value, six.string_types): value = utils.normalize(value) if key == 'size': # Since we don't support units yet we expect the size # in GiB for now value = value / units.Gi if not match(key, value, device.name): return False return True for dev in block_devices: if check_device_attrs(dev): return dev.name else: raise errors.DeviceNotFound("No suitable device was found for " "deployment using these hints %s" % root_device_hints)