Add vendor, product to interface information

This patch updates the interfaces JSON to include
vendor and  product
u'interfaces': [
    {
        u'mac_address': u'00:0c:29:8c:11:b1',
        u'name': u'eth0',
        u'ipv4_address': None,
        u'switch_chassis_descr': None,
        u'switch_port_descr': None,
        u'lldp': None,
        u'vendor': u'0x15b3',
        u'product': u'0x1014,
    }]

Co-Authored-By: yogananth subramanian <ysubrama@redhat.com>

Closes-Bug: #1611856

Change-Id: I8fa58dde29601abee959f74b69b692ed9eaffb94
This commit is contained in:
Moshe Levi 2016-02-11 14:00:01 +02:00 committed by Jim Rollenhagen
parent 9f52f47acd
commit fe3b630360
5 changed files with 75 additions and 22 deletions

View File

@ -118,13 +118,15 @@ fields:
``interfaces`` ``interfaces``
list of network interfaces with fields: ``name``, ``mac_address``, list of network interfaces with fields: ``name``, ``mac_address``,
``ipv4_address``, ``lldp``. If configuration option ``collect_lldp`` is ``ipv4_address``, ``lldp``, ``vendor`` and ``product``.
set to True the ``lldp`` field will be populated by a list of If configuration option ``collect_lldp`` is set to True the ``lldp``
type-length-value (TLV) fields retrieved using the Link Layer Discovery field will be populated by a list of type-length-value (TLV) fields
Protocol (LLDP). Currently IPA also returns 2 fields ``switch_port_descr`` retrieved using the Link Layer Discovery Protocol (LLDP).
Currently IPA also returns 2 fields ``switch_port_descr``
and ``switch_chassis_descr`` which were reserved for future use, these are and ``switch_chassis_descr`` which were reserved for future use, these are
now deprecated to be removed in Ocata in favor of including all LLDP data now deprecated to be removed in Ocata in favor of including all LLDP data
in the ``lddp`` field. in the ``lldp`` field.
``system_vendor`` ``system_vendor``
system vendor information from SMBIOS as reported by ``dmidecode``: system vendor information from SMBIOS as reported by ``dmidecode``:

View File

@ -48,14 +48,17 @@ UNIT_CONVERTER.define('GB = 1024 MB')
NODE = None NODE = None
def _get_device_vendor(dev): def _get_device_info(dev, devclass, field):
"""Get the vendor name of a given device.""" """Get the device info according to device class and field."""
try: try:
devname = os.path.basename(dev) devname = os.path.basename(dev)
with open('/sys/class/block/%s/device/vendor' % devname, 'r') as f: with open('/sys/class/%s/%s/device/%s' % (devclass, devname, field),
'r') as f:
return f.read().strip() return f.read().strip()
except IOError: except IOError:
LOG.warning("Can't find the device vendor for device %s", dev) LOG.warning(
"Can't find field {0} for device {1} in device class {2}".format(
field, dev, devclass))
def _udev_settle(): def _udev_settle():
@ -157,7 +160,8 @@ def list_all_block_devices(block_type='disk'):
model=device['MODEL'], model=device['MODEL'],
size=int(device['SIZE']), size=int(device['SIZE']),
rotational=bool(int(device['ROTA'])), rotational=bool(int(device['ROTA'])),
vendor=_get_device_vendor(device['KNAME']), vendor=_get_device_info(device['KNAME'],
'block', 'vendor'),
**extra)) **extra))
return devices return devices
@ -205,15 +209,17 @@ class BlockDevice(encoding.SerializableComparable):
class NetworkInterface(encoding.SerializableComparable): class NetworkInterface(encoding.SerializableComparable):
serializable_fields = ('name', 'mac_address', 'switch_port_descr', serializable_fields = ('name', 'mac_address', 'switch_port_descr',
'switch_chassis_descr', 'ipv4_address', 'switch_chassis_descr', 'ipv4_address',
'has_carrier', 'lldp') 'has_carrier', 'lldp', 'vendor', 'product')
def __init__(self, name, mac_addr, ipv4_address=None, has_carrier=True, def __init__(self, name, mac_addr, ipv4_address=None, has_carrier=True,
lldp=None): lldp=None, vendor=None, product=None):
self.name = name self.name = name
self.mac_address = mac_addr self.mac_address = mac_addr
self.ipv4_address = ipv4_address self.ipv4_address = ipv4_address
self.has_carrier = has_carrier self.has_carrier = has_carrier
self.lldp = lldp self.lldp = lldp
self.vendor = vendor
self.product = product
# TODO(sambetts) Remove these fields in Ocata, they have been # TODO(sambetts) Remove these fields in Ocata, they have been
# superseded by self.lldp # superseded by self.lldp
self.switch_port_descr = None self.switch_port_descr = None
@ -501,7 +507,9 @@ class GenericHardwareManager(HardwareManager):
interface_name, mac_addr, interface_name, mac_addr,
ipv4_address=self.get_ipv4_addr(interface_name), ipv4_address=self.get_ipv4_addr(interface_name),
has_carrier=self._interface_has_carrier(interface_name), has_carrier=self._interface_has_carrier(interface_name),
lldp=self._get_lldp_data(interface_name)) lldp=self._get_lldp_data(interface_name),
vendor=_get_device_info(interface_name, 'net', 'vendor'),
product=_get_device_info(interface_name, 'net', 'device'))
def get_ipv4_addr(self, interface_id): def get_ipv4_addr(self, interface_id):
try: try:

View File

@ -423,6 +423,35 @@ class TestGenericHardwareManager(test_base.BaseTestCase):
self.assertEqual('00:0c:29:8c:11:b1', interfaces[0].mac_address) self.assertEqual('00:0c:29:8c:11:b1', interfaces[0].mac_address)
self.assertEqual('192.168.1.2', interfaces[0].ipv4_address) self.assertEqual('192.168.1.2', interfaces[0].ipv4_address)
self.assertFalse(interfaces[0].has_carrier) self.assertFalse(interfaces[0].has_carrier)
self.assertIsNone(interfaces[0].vendor)
@mock.patch('netifaces.ifaddresses')
@mock.patch('os.listdir')
@mock.patch('os.path.exists')
@mock.patch('six.moves.builtins.open')
def test_list_network_interfaces_with_vendor_info(self,
mocked_open,
mocked_exists,
mocked_listdir,
mocked_ifaddresses):
mocked_listdir.return_value = ['lo', 'eth0']
mocked_exists.side_effect = [False, True]
mocked_open.return_value.__enter__ = lambda s: s
mocked_open.return_value.__exit__ = mock.Mock()
read_mock = mocked_open.return_value.read
mac = '00:0c:29:8c:11:b1'
read_mock.side_effect = [mac + '\n', '1', '0x15b3\n', '0x1014\n']
mocked_ifaddresses.return_value = {
netifaces.AF_INET: [{'addr': '192.168.1.2'}]
}
interfaces = self.hardware.list_network_interfaces()
self.assertEqual(1, len(interfaces))
self.assertEqual('eth0', interfaces[0].name)
self.assertEqual(mac, interfaces[0].mac_address)
self.assertEqual('192.168.1.2', interfaces[0].ipv4_address)
self.assertTrue(interfaces[0].has_carrier)
self.assertEqual('0x15b3', interfaces[0].vendor)
self.assertEqual('0x1014', interfaces[0].product)
@mock.patch.object(hardware, 'get_cached_node') @mock.patch.object(hardware, 'get_cached_node')
@mock.patch.object(utils, 'execute') @mock.patch.object(utils, 'execute')
@ -558,11 +587,12 @@ class TestGenericHardwareManager(test_base.BaseTestCase):
mock_cached_node.assert_called_once_with() mock_cached_node.assert_called_once_with()
mock_dev.assert_called_once_with() mock_dev.assert_called_once_with()
def test__get_device_vendor(self): def test__get_device_info(self):
fileobj = mock.mock_open(read_data='fake-vendor') fileobj = mock.mock_open(read_data='fake-vendor')
with mock.patch( with mock.patch(
'six.moves.builtins.open', fileobj, create=True) as mock_open: 'six.moves.builtins.open', fileobj, create=True) as mock_open:
vendor = hardware._get_device_vendor('/dev/sdfake') vendor = hardware._get_device_info(
'/dev/sdfake', 'block', 'vendor')
mock_open.assert_called_once_with( mock_open.assert_called_once_with(
'/sys/class/block/sdfake/device/vendor', 'r') '/sys/class/block/sdfake/device/vendor', 'r')
self.assertEqual('fake-vendor', vendor) self.assertEqual('fake-vendor', vendor)
@ -692,7 +722,7 @@ class TestGenericHardwareManager(test_base.BaseTestCase):
list_mock.assert_called_once_with() list_mock.assert_called_once_with()
@mock.patch.object(hardware, '_get_device_vendor') @mock.patch.object(hardware, '_get_device_info')
@mock.patch.object(pyudev.Device, 'from_device_file') @mock.patch.object(pyudev.Device, 'from_device_file')
@mock.patch.object(utils, 'execute') @mock.patch.object(utils, 'execute')
def test_list_all_block_device(self, mocked_execute, mocked_udev, def test_list_all_block_device(self, mocked_execute, mocked_udev,
@ -732,7 +762,7 @@ class TestGenericHardwareManager(test_base.BaseTestCase):
self.assertEqual(getattr(expected, attr), self.assertEqual(getattr(expected, attr),
getattr(device, attr)) getattr(device, attr))
@mock.patch.object(hardware, '_get_device_vendor') @mock.patch.object(hardware, '_get_device_info')
@mock.patch.object(pyudev.Device, 'from_device_file') @mock.patch.object(pyudev.Device, 'from_device_file')
@mock.patch.object(utils, 'execute') @mock.patch.object(utils, 'execute')
def test_list_all_block_device_udev_17(self, mocked_execute, mocked_udev, def test_list_all_block_device_udev_17(self, mocked_execute, mocked_udev,
@ -744,7 +774,7 @@ class TestGenericHardwareManager(test_base.BaseTestCase):
devices = hardware.list_all_block_devices() devices = hardware.list_all_block_devices()
self.assertEqual(4, len(devices)) self.assertEqual(4, len(devices))
@mock.patch.object(hardware, '_get_device_vendor') @mock.patch.object(hardware, '_get_device_info')
@mock.patch.object(pyudev.Device, 'from_device_file') @mock.patch.object(pyudev.Device, 'from_device_file')
@mock.patch.object(utils, 'execute') @mock.patch.object(utils, 'execute')
def test_list_all_block_device_with_udev(self, mocked_execute, mocked_udev, def test_list_all_block_device_with_udev(self, mocked_execute, mocked_udev,
@ -1461,7 +1491,8 @@ class TestGenericHardwareManager(test_base.BaseTestCase):
@mock.patch.object(utils, 'execute', autospec=True) @mock.patch.object(utils, 'execute', autospec=True)
class TestModuleFunctions(test_base.BaseTestCase): class TestModuleFunctions(test_base.BaseTestCase):
@mock.patch.object(hardware, '_get_device_vendor', lambda x: "FooTastic") @mock.patch.object(hardware, '_get_device_info',
lambda x, y, z: 'FooTastic')
@mock.patch.object(hardware, '_udev_settle', autospec=True) @mock.patch.object(hardware, '_udev_settle', autospec=True)
@mock.patch.object(hardware.pyudev.Device, "from_device_file") @mock.patch.object(hardware.pyudev.Device, "from_device_file")
def test_list_all_block_devices_success(self, mocked_fromdevfile, def test_list_all_block_devices_success(self, mocked_fromdevfile,
@ -1475,7 +1506,8 @@ class TestModuleFunctions(test_base.BaseTestCase):
self.assertEqual(BLK_DEVICE_TEMPLATE_SMALL_DEVICES, result) self.assertEqual(BLK_DEVICE_TEMPLATE_SMALL_DEVICES, result)
mocked_udev.assert_called_once_with() mocked_udev.assert_called_once_with()
@mock.patch.object(hardware, '_get_device_vendor', lambda x: "FooTastic") @mock.patch.object(hardware, '_get_device_info',
lambda x, y: "FooTastic")
@mock.patch.object(hardware, '_udev_settle', autospec=True) @mock.patch.object(hardware, '_udev_settle', autospec=True)
def test_list_all_block_devices_wrong_block_type(self, mocked_udev, def test_list_all_block_devices_wrong_block_type(self, mocked_udev,
mocked_execute): mocked_execute):

View File

@ -41,11 +41,14 @@ class TestBaseIronicPythonAgent(test_base.BaseTestCase):
self.api_client = ironic_api_client.APIClient(API_URL, DRIVER) self.api_client = ironic_api_client.APIClient(API_URL, DRIVER)
self.hardware_info = { self.hardware_info = {
'interfaces': [ 'interfaces': [
hardware.NetworkInterface('eth0', '00:0c:29:8c:11:b1'), hardware.NetworkInterface(
'eth0', '00:0c:29:8c:11:b1', vendor='0x15b3',
product='0x1014'),
hardware.NetworkInterface( hardware.NetworkInterface(
'eth1', '00:0c:29:8c:11:b2', 'eth1', '00:0c:29:8c:11:b2',
lldp=[(1, '04885a92ec5459'), lldp=[(1, '04885a92ec5459'),
(2, '0545746865726e6574312f3138')]), (2, '0545746865726e6574312f3138')],
vendor='0x15b3', product='0x1014'),
], ],
'cpu': hardware.CPU('Awesome Jay CPU x10 9001', '9001', '10', 'cpu': hardware.CPU('Awesome Jay CPU x10 9001', '9001', '10',
'ARMv9'), 'ARMv9'),
@ -298,6 +301,8 @@ class TestBaseIronicPythonAgent(test_base.BaseTestCase):
u'switch_port_descr': None, u'switch_port_descr': None,
u'has_carrier': True, u'has_carrier': True,
u'lldp': None, u'lldp': None,
u'vendor': u'0x15b3',
u'product': u'0x1014'
}, },
{ {
u'mac_address': u'00:0c:29:8c:11:b2', u'mac_address': u'00:0c:29:8c:11:b2',
@ -308,6 +313,8 @@ class TestBaseIronicPythonAgent(test_base.BaseTestCase):
u'has_carrier': True, u'has_carrier': True,
u'lldp': [[1, u'04885a92ec5459'], u'lldp': [[1, u'04885a92ec5459'],
[2, u'0545746865726e6574312f3138']], [2, u'0545746865726e6574312f3138']],
u'vendor': u'0x15b3',
u'product': u'0x1014'
} }
], ],
u'cpu': { u'cpu': {

View File

@ -0,0 +1,4 @@
---
features:
- Add 'vendor' and 'product' fields to
interfaces data for future use in Ironic Inspector.