Merge "USB device discovery"

This commit is contained in:
Zuul 2024-03-28 21:22:53 +00:00 committed by Gerrit Code Review
commit b6075156b3
7 changed files with 88 additions and 0 deletions

View File

@ -164,6 +164,12 @@ collectors are:
* ``lldp_raw`` - mapping of interface names to lists of raw * ``lldp_raw`` - mapping of interface names to lists of raw
type-length-value (TLV) records. 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/ .. _hardware: https://pypi.org/project/hardware/
.. _NUMA: https://en.wikipedia.org/wiki/Non-uniform_memory_access .. _NUMA: https://en.wikipedia.org/wiki/Non-uniform_memory_access
.. _LLDP: https://en.wikipedia.org/wiki/Link_Layer_Discovery_Protocol .. _LLDP: https://en.wikipedia.org/wiki/Link_Layer_Discovery_Protocol

View File

@ -849,6 +849,15 @@ class SystemVendorInfo(encoding.SerializableComparable):
self.firmware = firmware 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): class BootInfo(encoding.SerializableComparable):
serializable_fields = ('current_boot_mode', 'pxe_interface') serializable_fields = ('current_boot_mode', 'pxe_interface')
@ -926,6 +935,15 @@ class HardwareManager(object, metaclass=abc.ABCMeta):
def generate_tls_certificate(self, ip_address): def generate_tls_certificate(self, ip_address):
raise errors.IncompatibleHardwareMethodError() 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): def erase_block_device(self, node, block_device):
"""Attempt to erase a block device. """Attempt to erase a block device.
@ -1617,6 +1635,23 @@ class GenericHardwareManager(HardwareManager):
'node': cached_node['uuid'] if cached_node else None}) 'node': cached_node['uuid'] if cached_node else None})
return dev_name 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): def get_system_vendor_info(self):
try: try:
sys_dict = self._get_system_lshw_dict() sys_dict = self._get_system_lshw_dict()

View File

@ -425,3 +425,12 @@ def collect_lldp(data, failures):
:param failures: AccumulatedFailures object :param failures: AccumulatedFailures object
""" """
data['lldp_raw'] = hardware.dispatch_to_managers('collect_lldp_data') 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, "ethernet": true,
"physical": "Physical interface" "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

@ -4899,6 +4899,16 @@ class TestGenericHardwareManager(base.IronicAgentTest):
self.assertEqual('', vendor_info.firmware.build_date) self.assertEqual('', vendor_info.firmware.build_date)
self.assertEqual('', vendor_info.firmware.version) 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', @mock.patch.object(utils, 'get_agent_params',
lambda: {'BOOTIF': 'boot:if'}) lambda: {'BOOTIF': 'boot:if'})
@mock.patch.object(os.path, 'isdir', autospec=True) @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

@ -59,6 +59,7 @@ ironic_python_agent.inspector.collectors =
numa-topology = ironic_python_agent.numa_inspector:collect_numa_topology_info numa-topology = ironic_python_agent.numa_inspector:collect_numa_topology_info
dmi-decode = ironic_python_agent.dmi_inspector:collect_dmidecode_info dmi-decode = ironic_python_agent.dmi_inspector:collect_dmidecode_info
lldp = ironic_python_agent.inspector:collect_lldp lldp = ironic_python_agent.inspector:collect_lldp
usb-devices = ironic_python_agent.inspector:collect_usb_devices
[extras] [extras]
burnin-network-kazoo = burnin-network-kazoo =