summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Tantsur <dtantsur@protonmail.com>2023-03-30 15:47:08 +0200
committerDmitry Tantsur <dtantsur@protonmail.com>2023-03-31 14:28:32 +0200
commit0304c73c0e95699650a147c1bb5ea0a5ef6861f1 (patch)
tree6614a024b7cff09e7d34558760d63d365d4c903e
parent2ddb693491a18bbc4c6eda96ff6a89587dac6d66 (diff)
downloadironic-python-agent-0304c73c0e95699650a147c1bb5ea0a5ef6861f1.tar.gz
Report system firmware information in the inventory
Change-Id: I5b6ceb9cdcf4baa97a6f0482d1030d14f3f2ecff
-rw-r--r--doc/source/admin/how_it_works.rst4
-rw-r--r--ironic_python_agent/hardware.py51
-rw-r--r--ironic_python_agent/tests/unit/samples/hardware_samples.py28
-rw-r--r--ironic_python_agent/tests/unit/test_hardware.py10
-rw-r--r--ironic_python_agent/utils.py12
-rw-r--r--releasenotes/notes/bmo-extra-147559c8d1776e8c.yaml5
6 files changed, 90 insertions, 20 deletions
diff --git a/doc/source/admin/how_it_works.rst b/doc/source/admin/how_it_works.rst
index e4d63a2f..803ac7a8 100644
--- a/doc/source/admin/how_it_works.rst
+++ b/doc/source/admin/how_it_works.rst
@@ -198,7 +198,9 @@ fields:
``system_vendor``
system vendor information from SMBIOS as reported by ``dmidecode``:
- ``product_name``, ``serial_number`` and ``manufacturer``.
+ ``product_name``, ``serial_number`` and ``manufacturer``, as well as
+ a ``firmware`` structure with fields ``vendor``, ``version`` and
+ ``build_date``.
``boot``
boot information with fields: ``current_boot_mode`` (boot mode used for
diff --git a/ironic_python_agent/hardware.py b/ironic_python_agent/hardware.py
index e3d408e0..8dd3a961 100644
--- a/ironic_python_agent/hardware.py
+++ b/ironic_python_agent/hardware.py
@@ -339,22 +339,16 @@ def get_component_devices(raid_device):
def _calc_memory(sys_dict):
physical = 0
- for sys_child in sys_dict['children']:
- if sys_child['id'] != 'core':
- continue
- for core_child in sys_child['children']:
- if not _MEMORY_ID_RE.match(core_child['id']):
- continue
- if core_child.get('size'):
- value = ("%(size)s %(units)s" % core_child)
- physical += int(UNIT_CONVERTER(value).to
- ('MB').magnitude)
- else:
- for bank in core_child.get('children', ()):
- if bank.get('size'):
- value = ("%(size)s %(units)s" % bank)
- physical += int(UNIT_CONVERTER(value).to
- ('MB').magnitude)
+ core_dict = next(utils.find_in_lshw(sys_dict, 'core'), {})
+ for core_child in utils.find_in_lshw(core_dict, _MEMORY_ID_RE):
+ if core_child.get('size'):
+ value = ("%(size)s %(units)s" % core_child)
+ physical += int(UNIT_CONVERTER(value).to('MB').magnitude)
+ else:
+ for bank in core_child.get('children', ()):
+ if bank.get('size'):
+ value = ("%(size)s %(units)s" % bank)
+ physical += int(UNIT_CONVERTER(value).to('MB').magnitude)
return physical
@@ -835,13 +829,24 @@ class Memory(encoding.SerializableComparable):
self.physical_mb = physical_mb
+class SystemFirmware(encoding.SerializableComparable):
+ serializable_fields = ('vendor', 'version', 'build_date')
+
+ def __init__(self, vendor, version, build_date):
+ self.version = version
+ self.build_date = build_date
+ self.vendor = vendor
+
+
class SystemVendorInfo(encoding.SerializableComparable):
- serializable_fields = ('product_name', 'serial_number', 'manufacturer')
+ serializable_fields = ('product_name', 'serial_number', 'manufacturer',
+ 'firmware')
- def __init__(self, product_name, serial_number, manufacturer):
+ def __init__(self, product_name, serial_number, manufacturer, firmware):
self.product_name = product_name
self.serial_number = serial_number
self.manufacturer = manufacturer
+ self.firmware = firmware
class BootInfo(encoding.SerializableComparable):
@@ -1512,9 +1517,17 @@ class GenericHardwareManager(HardwareManager):
except (processutils.ProcessExecutionError, OSError, ValueError) as e:
LOG.warning('Could not retrieve vendor info from lshw: %s', e)
sys_dict = {}
+
+ core_dict = next(utils.find_in_lshw(sys_dict, 'core'), {})
+ fw_dict = next(utils.find_in_lshw(core_dict, 'firmware'), {})
+
+ firmware = SystemFirmware(vendor=fw_dict.get('vendor', ''),
+ version=fw_dict.get('version', ''),
+ build_date=fw_dict.get('date', ''))
return SystemVendorInfo(product_name=sys_dict.get('product', ''),
serial_number=sys_dict.get('serial', ''),
- manufacturer=sys_dict.get('vendor', ''))
+ manufacturer=sys_dict.get('vendor', ''),
+ firmware=firmware)
def get_boot_info(self):
boot_mode = 'uefi' if os.path.isdir('/sys/firmware/efi') else 'bios'
diff --git a/ironic_python_agent/tests/unit/samples/hardware_samples.py b/ironic_python_agent/tests/unit/samples/hardware_samples.py
index c00d637b..88378a18 100644
--- a/ironic_python_agent/tests/unit/samples/hardware_samples.py
+++ b/ironic_python_agent/tests/unit/samples/hardware_samples.py
@@ -491,6 +491,34 @@ LSHW_JSON_OUTPUT_V2 = ("""
"slot" : "NULL",
"children" : [
{
+ "id": "firmware",
+ "class": "memory",
+ "claimed": true,
+ "description": "BIOS",
+ "vendor": "BIOSVNDR",
+ "physid": "0",
+ "version": "1.2.3",
+ "date": "03/30/2023",
+ "units": "bytes",
+ "size": 65536,
+ "capacity": 16777216,
+ "capabilities": {
+ "isa": "ISA bus",
+ "pci": "PCI bus",
+ "pnp": "Plug-and-Play",
+ "upgrade": "BIOS EEPROM can be upgraded",
+ "shadowing": "BIOS shadowing",
+ "cdboot": "Booting from CD-ROM/DVD",
+ "bootselect": "Selectable boot path",
+ "edd": "Enhanced Disk Drive extensions",
+ "acpi": "ACPI",
+ "usb": "USB legacy emulation",
+ "biosbootspecification": "BIOS boot specification",
+ "netboot": "Function-key initiated network service boot",
+ "uefi": "UEFI specification is supported"
+ }
+ },
+ {
"id" : "memory:0",
"class" : "memory",
"claimed" : true,
diff --git a/ironic_python_agent/tests/unit/test_hardware.py b/ironic_python_agent/tests/unit/test_hardware.py
index fdb5c8df..d0122f7a 100644
--- a/ironic_python_agent/tests/unit/test_hardware.py
+++ b/ironic_python_agent/tests/unit/test_hardware.py
@@ -5247,6 +5247,10 @@ class TestGenericHardwareManager(base.IronicAgentTest):
self.assertEqual('ABC123 (GENERIC_SERVER)', vendor_info.product_name)
self.assertEqual('1234567', vendor_info.serial_number)
self.assertEqual('GENERIC', vendor_info.manufacturer)
+ # This sample does not have firmware information
+ self.assertEqual('', vendor_info.firmware.vendor)
+ self.assertEqual('', vendor_info.firmware.build_date)
+ self.assertEqual('', vendor_info.firmware.version)
@mock.patch.object(il_utils, 'execute', autospec=True)
def test_get_system_vendor_info_lshw_list(self, mocked_execute):
@@ -5255,6 +5259,9 @@ class TestGenericHardwareManager(base.IronicAgentTest):
self.assertEqual('ABCD', vendor_info.product_name)
self.assertEqual('1234', vendor_info.serial_number)
self.assertEqual('ABCD', vendor_info.manufacturer)
+ self.assertEqual('BIOSVNDR', vendor_info.firmware.vendor)
+ self.assertEqual('03/30/2023', vendor_info.firmware.build_date)
+ self.assertEqual('1.2.3', vendor_info.firmware.version)
@mock.patch.object(il_utils, 'execute', autospec=True)
def test_get_system_vendor_info_failure(self, mocked_execute):
@@ -5263,6 +5270,9 @@ class TestGenericHardwareManager(base.IronicAgentTest):
self.assertEqual('', vendor_info.product_name)
self.assertEqual('', vendor_info.serial_number)
self.assertEqual('', vendor_info.manufacturer)
+ self.assertEqual('', vendor_info.firmware.vendor)
+ self.assertEqual('', vendor_info.firmware.build_date)
+ self.assertEqual('', vendor_info.firmware.version)
@mock.patch.object(utils, 'get_agent_params',
lambda: {'BOOTIF': 'boot:if'})
diff --git a/ironic_python_agent/utils.py b/ironic_python_agent/utils.py
index b7b98c03..c490b1af 100644
--- a/ironic_python_agent/utils.py
+++ b/ironic_python_agent/utils.py
@@ -917,3 +917,15 @@ def rescan_device(device):
except processutils.ProcessExecutionError as e:
LOG.warning('Something went wrong when waiting for udev '
'to settle. Error: %s', e)
+
+
+def find_in_lshw(lshw, by_id):
+ """Yield all suitable records from lshw."""
+ for child in lshw.get('children', ()):
+ lshw_id = child.get('id', '')
+ if isinstance(by_id, re.Pattern):
+ if by_id.match(lshw_id) is not None:
+ yield child
+ else:
+ if by_id == lshw_id:
+ yield child
diff --git a/releasenotes/notes/bmo-extra-147559c8d1776e8c.yaml b/releasenotes/notes/bmo-extra-147559c8d1776e8c.yaml
new file mode 100644
index 00000000..00974546
--- /dev/null
+++ b/releasenotes/notes/bmo-extra-147559c8d1776e8c.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ The hardware inventory now contains information about the system firmware:
+ vendor, version and the build date.