USB device discovery

The idea is to retreive USB devices informations via 'lshw' and
return the list to ironic in order to be able to create introspection
rules based on USB devices.

Change-Id: I39d60cb467614fca7a7f701dbe576154213580a5
This commit is contained in:
Damien Rannou 2023-12-06 13:50:45 +01:00
parent beccfe8c92
commit 3fd68c0848
7 changed files with 88 additions and 0 deletions

View File

@ -152,6 +152,12 @@ collectors are:
* ``lldp_raw`` - mapping of interface names to lists of raw
type-length-value (TLV) records.
``usb-devices``
Collects USB devices information. Adds one key:
* ``usb_devices`` - list of objects with keys ``product``, ``vendor`` and
``handle``
.. _hardware: https://pypi.org/project/hardware/
.. _NUMA: https://en.wikipedia.org/wiki/Non-uniform_memory_access
.. _LLDP: https://en.wikipedia.org/wiki/Link_Layer_Discovery_Protocol

View File

@ -848,6 +848,15 @@ class SystemVendorInfo(encoding.SerializableComparable):
self.firmware = firmware
class USBInfo(encoding.SerializableComparable):
serializable_fields = ('product', 'vendor', 'handle')
def __init__(self, product, vendor, handle):
self.product = product
self.vendor = vendor
self.handle = handle
class BootInfo(encoding.SerializableComparable):
serializable_fields = ('current_boot_mode', 'pxe_interface')
@ -925,6 +934,15 @@ class HardwareManager(object, metaclass=abc.ABCMeta):
def generate_tls_certificate(self, ip_address):
raise errors.IncompatibleHardwareMethodError()
def get_usb_devices(self):
"""Collect USB devices
List all USB final devices, based on lshw information
:return: a dict, containing product, vendor, and handle information
"""
raise errors.IncompatibleHardwareMethodError()
def erase_block_device(self, node, block_device):
"""Attempt to erase a block device.
@ -1615,6 +1633,23 @@ class GenericHardwareManager(HardwareManager):
'node': cached_node['uuid'] if cached_node else None})
return dev_name
def get_usb_devices(self):
sys_dict = self._get_system_lshw_dict()
try:
usb_dict = utils.find_in_lshw(sys_dict, by_id='usb',
by_class='generic', recursive=True)
except StopIteration:
LOG.warning('Cannot find detailed information about USB')
return None
devices = []
for dev in usb_dict:
usb_info = USBInfo(product=dev.get('product', ''),
vendor=dev.get('vendor', ''),
handle=dev.get('handle', ''))
devices.append(usb_info)
return devices
def get_system_vendor_info(self):
try:
sys_dict = self._get_system_lshw_dict()

View File

@ -387,3 +387,12 @@ def collect_lldp(data, failures):
:param failures: AccumulatedFailures object
"""
data['lldp_raw'] = hardware.dispatch_to_managers('collect_lldp_data')
def collect_usb_devices(data, failures):
"""Collect USB information for connected devices.
:param data: mutable data that we'll send to inspector
:param failures: AccumulatedFailures object
"""
data['usb_devices'] = hardware.dispatch_to_managers('get_usb_devices')

View File

@ -447,6 +447,28 @@ LSHW_JSON_OUTPUT_V1 = ("""
"ethernet": true,
"physical": "Physical interface"
}
},
{
"id": "usb",
"class": "bus",
"children": [
{
"id": "usbhost:0",
"class": "bus",
"children": [
{
"id": "usb",
"class": "generic",
"handle": "USB:1:2",
"description": "Generic USB device",
"product": "MyProduct",
"vendor": "MyVendor",
"physid": "1",
"businfo": "usb@1:1"
}
]
}
]
}
]
}

View File

@ -4897,6 +4897,16 @@ class TestGenericHardwareManager(base.IronicAgentTest):
self.assertEqual('', vendor_info.firmware.build_date)
self.assertEqual('', vendor_info.firmware.version)
@mock.patch.object(il_utils, 'execute', autospec=True)
def test_get_usb_devices(self, mocked_execute):
device = hardware.USBInfo('MyProduct', 'MyVendor', 'USB:1:2')
mocked_execute.return_value = hws.LSHW_JSON_OUTPUT_V1
detected_usb_devices = self.hardware.get_usb_devices()
self.assertEqual([device], detected_usb_devices)
@mock.patch.object(utils, 'get_agent_params',
lambda: {'BOOTIF': 'boot:if'})
@mock.patch.object(os.path, 'isdir', autospec=True)

View File

@ -0,0 +1,5 @@
---
features:
- Add attached USB device auto discovery. The information is
retrieived from `lshw` tool and store in introspection data result.

View File

@ -58,6 +58,7 @@ ironic_python_agent.inspector.collectors =
numa-topology = ironic_python_agent.numa_inspector:collect_numa_topology_info
dmi-decode = ironic_python_agent.dmi_inspector:collect_dmidecode_info
lldp = ironic_python_agent.inspector:collect_lldp
usb-devices = ironic_python_agent.inspector:collect_usb_devices
[pbr]
autodoc_index_modules = True