Add PCI devices collector to inspector

Adds a new collector, which gathers list of PCI devices.
Each entry is a dictionary containing 2 keys:
- vendor-id
- product-id
Such information can then be used by the inspector to distinguish
appropriate PCI devices.

Change-Id: Id7521d66410e7d408d7eada692b6123e769ce084
Partial-Bug: #1580893
This commit is contained in:
Szymon Borkowski 2016-06-06 15:16:11 +02:00
parent 0c5a1cfd56
commit f7e080c8bf
4 changed files with 115 additions and 0 deletions

View File

@ -16,6 +16,7 @@
import base64
import io
import json
import os
import tarfile
import time
@ -381,3 +382,52 @@ def collect_extra_hardware(data, failures):
except ValueError as exc:
msg = 'JSON returned from hardware-detect cannot be decoded: %s'
failures.add(msg, exc)
def collect_pci_devices_info(data, failures):
"""Collect a list of PCI devices.
Each PCI device entry in list is a dictionary containing vendor_id and
product_id keys, which will be then used by the ironic inspector to
distinguish various PCI devices.
The data is gathered from /sys/bus/pci/devices directory.
:param data: mutable data that we'll send to inspector
:param failures: AccumulatedFailures object
"""
pci_devices_path = '/sys/bus/pci/devices'
pci_devices_info = []
try:
subdirs = os.listdir(pci_devices_path)
except OSError as exc:
msg = 'Failed to get list of PCI devices: %s'
failures.add(msg, exc)
return
for subdir in subdirs:
if not os.path.isdir(os.path.join(pci_devices_path, subdir)):
continue
try:
# note(sborkows): ids located in files inside PCI devices
# directory are stored in hex format (0x1234 for example) and
# we only need that part after 'x' delimiter
with open(os.path.join(pci_devices_path, subdir,
'vendor')) as vendor_file:
vendor = vendor_file.read().strip().split('x')[1]
with open(os.path.join(pci_devices_path, subdir,
'device')) as vendor_device:
device = vendor_device.read().strip().split('x')[1]
except IOError as exc:
LOG.warning('Failed to gather vendor id or product id '
'from PCI device %s: %s', subdir, exc)
continue
except IndexError as exc:
LOG.warning('Wrong format of vendor id or product id in PCI '
'device %s: %s', subdir, exc)
continue
LOG.debug(
'Found a PCI device with vendor id %s and product id %s',
vendor, device)
pci_devices_info.append({'vendor_id': vendor,
'product_id': device})
data['pci_devices'] = pci_devices_info

View File

@ -17,6 +17,7 @@ import base64
import collections
import copy
import io
import os
import tarfile
import time
@ -461,6 +462,60 @@ class TestCollectExtraHardware(test_base.BaseTestCase):
mock_execute.assert_called_once_with('hardware-detect')
@mock.patch.object(os, 'listdir', autospec=True)
class TestCollectPciDevicesInfo(test_base.BaseTestCase):
def setUp(self):
super(TestCollectPciDevicesInfo, self).setUp()
self.data = {}
self.failures = utils.AccumulatedFailures()
@mock.patch.object(os.path, 'isdir', autospec=True)
def test_success(self, mock_isdir, mock_listdir):
subdirs = ['foo', 'bar']
mock_listdir.return_value = subdirs
mock_isdir.return_value = True
reads = ['0x1234', '0x5678', '0x9876', '0x5432']
expected_pci_devices = [{'vendor_id': '1234', 'product_id': '5678'},
{'vendor_id': '9876', 'product_id': '5432'}]
mock_open = mock.mock_open()
with mock.patch('six.moves.builtins.open', mock_open):
mock_read = mock_open.return_value.read
mock_read.side_effect = reads
inspector.collect_pci_devices_info(self.data, self.failures)
self.assertEqual(2 * len(subdirs), mock_open.call_count)
self.assertListEqual(expected_pci_devices, self.data['pci_devices'])
def test_wrong_path(self, mock_listdir):
mock_listdir.side_effect = OSError()
inspector.collect_pci_devices_info(self.data, self.failures)
self.assertFalse('pci_devices' in self.data)
self.assertEqual(1, len(self.failures._failures))
@mock.patch.object(os.path, 'isdir', autospec=True)
def test_bad_pci_device_info(self, mock_isdir, mock_listdir):
subdirs = ['foo', 'bar', 'baz']
mock_listdir.return_value = subdirs
mock_isdir.return_value = True
reads = ['0x1234', '0x5678', '0x9876', IOError, IndexError,
'0x5432']
expected_pci_devices = [{'vendor_id': '1234', 'product_id': '5678'}]
mock_open = mock.mock_open()
with mock.patch('six.moves.builtins.open', mock_open):
mock_read = mock_open.return_value.read
mock_read.side_effect = reads
inspector.collect_pci_devices_info(self.data, self.failures)
# note(sborkows): due to throwing IOError, the corresponding mock_open
# will not be called, so there are 5 mock_open calls in total
self.assertEqual(5, mock_open.call_count)
self.assertListEqual(expected_pci_devices, self.data['pci_devices'])
@mock.patch.object(utils, 'get_agent_params', lambda: {'BOOTIF': '01-cdef'})
@mock.patch.object(hardware, 'dispatch_to_managers', autospec=True)
class TestWaitForDhcp(test_base.BaseTestCase):

View File

@ -0,0 +1,9 @@
---
features:
- Adds new PCI devices collector named "pci_devices"
to inspector module.
Data is gathered from /sys/bus/pci/devices directory
and is stored under "pci_devices" key as a dictionary
containing "vendor_id" and "product_id" keys, which
then will be used by the inspector to distinguish
various PCI devices.

View File

@ -33,6 +33,7 @@ ironic_python_agent.inspector.collectors =
default = ironic_python_agent.inspector:collect_default
logs = ironic_python_agent.inspector:collect_logs
extra-hardware = ironic_python_agent.inspector:collect_extra_hardware
pci-devices = ironic_python_agent.inspector:collect_pci_devices_info
[pbr]
autodoc_index_modules = True