WIP: Remove netifaces usage

Change-Id: I1a7c01d16eb8d2a2e372bd0d2474a601d3d2c1f4
This commit is contained in:
Julia Kreger 2023-04-10 08:47:06 -07:00
parent 0304c73c0e
commit d767d0be84
3 changed files with 153 additions and 79 deletions

View File

@ -19,7 +19,6 @@ import socket
import struct
import sys
import netifaces
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import netutils
@ -213,31 +212,51 @@ def _get_lldp_info(interfaces):
return lldp_info
def get_default_ip_addr(type, interface_id):
"""Retrieve default IPv4 or IPv6 address."""
try:
addrs = netifaces.ifaddresses(interface_id)
return addrs[type][0]['addr']
except (ValueError, IndexError, KeyError):
# No default IP address found
return None
def _extract_address(lines):
"""Extract an usable IP address from the supplied lines.
:param lines: The split lines of an "ip addr show $interface" command.
:returns: The first found global/non-temporary IP address.
"""
for line in lines:
# Get a global, non-temporary (i.e. v6 privacy) address
if 'global' in line and 'temporary' not in line:
line = line.lstrip()
# line is the list of addresses
address = line.split(' ')[1]
# strip tailing / off of the result, as v4 and v6 addresses
return address.split('/')[0]
def get_ipv4_addr(interface_id):
return get_default_ip_addr(netifaces.AF_INET, interface_id)
try:
out, _ = utils.execute('ip', '-4', 'addr', 'show', interface_id)
except OSError:
LOG.error('The IP command is required. Could not get IPv4 address.')
return None
return _extract_address(out.splitlines())
def get_ipv6_addr(interface_id):
return get_default_ip_addr(netifaces.AF_INET6, interface_id)
try:
out, _ = utils.execute('ip', '-6', 'addr', 'show', interface_id)
except OSError:
LOG.error('The IP command is required. Could not get IPv4 address.')
return None
return _extract_address(out.splitlines())
def get_mac_addr(interface_id):
path = '/sys/class/net/{}/address'.format(interface_id)
try:
addrs = netifaces.ifaddresses(interface_id)
return addrs[netifaces.AF_LINK][0]['addr']
except (ValueError, IndexError, KeyError):
# No mac address found
with open(path, 'rt') as fp:
return fp.read().strip()
except OSError as e:
LOG.debug('Encountered error while attempting to access the address '
'for %s. Error: %s', interface_id, e)
return None
LOG.debug('No MAC Address found for interface %s.', interface_id)
return None
# Other options...

View File

@ -15,6 +15,8 @@
import os
from unittest import mock
from ironic_lib import utils as il_utils
from ironic_python_agent import errors
from ironic_python_agent import hardware
from ironic_python_agent.hardware_managers import mlnx
@ -25,6 +27,13 @@ IB_ADDRESS = 'a0:00:00:27:fe:80:00:00:00:00:00:00:7c:fe:90:03:00:29:26:52'
CLIENT_ID = 'ff:00:00:00:00:00:02:00:00:02:c9:00:7c:fe:90:03:00:29:26:52'
IPV4_ADDRESS = """
3: ib0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
inet 192.168.1.2/24 brd 192.168.1.255 scope global dynamic noprefixroute eth0
valid_lft 30541sec preferred_lft 30541sec
""" # noqa
class MlnxHardwareManager(base.IronicAgentTest):
def setUp(self):
super(MlnxHardwareManager, self).setUp()
@ -121,12 +130,20 @@ class MlnxHardwareManager(base.IronicAgentTest):
hardware.HardwareSupport.NONE,
self.hardware.evaluate_hardware_support())
@mock.patch.object(il_utils, 'execute', autospec=True)
@mock.patch.object(netutils, 'get_mac_addr', autospec=True)
@mock.patch.object(hardware, '_get_device_info', autospec=True)
def test_get_interface_info(self, mocked_get_device_info, mock_get_mac):
def test_get_interface_info(self, mocked_get_device_info, mock_get_mac,
mocked_execute):
mocked_get_device_info.side_effect = ['0x15b3', '0x0014']
mock_get_mac.return_value = IB_ADDRESS
mocked_execute.side_effect = [
(IPV4_ADDRESS, '')
]
network_interface = self.hardware.get_interface_info('ib0')
mocked_execute.assert_has_calls([
mock.call('ip', '-4', 'addr', 'show', 'ib0')
])
self.assertEqual('ib0', network_interface.name)
self.assertEqual('7c:fe:90:29:26:52', network_interface.mac_address)
self.assertEqual('0x15b3', network_interface.vendor)

View File

@ -22,7 +22,6 @@ from unittest import mock
from ironic_lib import disk_utils
from ironic_lib import utils as il_utils
import netifaces
from oslo_concurrency import processutils
from oslo_config import cfg
from oslo_utils import units
@ -80,6 +79,26 @@ BLK_DEVICE_TEMPLATE_PARTUUID_DEVICE = [
partuuid="1234-5678", serial="sda1123"),
]
IPV4_ADDRESS = """
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
inet 192.168.1.2/24 brd 192.168.1.255 scope global dynamic noprefixroute eth0
valid_lft 30541sec preferred_lft 30541sec
""" # noqa
IPV6_ADDRESS = """
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
inet6 fd00::101/128 scope global dynamic noprefixroute
valid_lft 379301sec preferred_lft 379301sec
inet6 fd9b:f401:ddb1::f01/128 scope global noprefixroute
valid_lft forever preferred_lft forever
inet6 fd9b:f401:ddb1:0:ffe5:3caa:b00e:b54d/64 scope global temporary dynamic
valid_lft 592077sec preferred_lft 73462sec
inet6 fd9b:f401:ddb1:0:fad1:11ff:fead:6fcb/64 scope global mngtmpaddr noprefixroute
valid_lft forever preferred_lft forever
inet6 fe80::fad1:aaff:fead:11cb/64 scope link noprefixroute
valid_lft forever preferred_lft forever
""" # noqa
class FakeHardwareManager(hardware.GenericHardwareManager):
def __init__(self, hardware_support):
@ -270,7 +289,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
self.assertEqual(expected_lldp_data, result)
@mock.patch('ironic_python_agent.hardware.get_managers', autospec=True)
@mock.patch('netifaces.ifaddresses', autospec=True)
@mock.patch('os.listdir', autospec=True)
@mock.patch('os.path.exists', autospec=True)
@mock.patch('builtins.open', autospec=True)
@ -284,7 +302,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_open,
mocked_exists,
mocked_listdir,
mocked_ifaddresses,
mockedget_managers):
mockedget_managers.return_value = [hardware.GenericHardwareManager()]
mocked_listdir.return_value = ['lo', 'eth0', 'foobar']
@ -293,17 +310,22 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_open.return_value.__exit__ = mock.Mock()
read_mock = mocked_open.return_value.read
read_mock.side_effect = ['1']
mocked_ifaddresses.return_value = {
netifaces.AF_INET: [{'addr': '192.168.1.2'}],
netifaces.AF_INET6: [{'addr': 'fd00::101'}]
}
mocked_execute.return_value = ('em0\n', '')
mocked_execute.side_effect = [
(IPV4_ADDRESS, ''),
(IPV6_ADDRESS, ''),
('em0\n', '')
]
mock_has_carrier.return_value = True
mock_get_mac.side_effect = [
'00:0c:29:8c:11:b1',
None,
]
interfaces = self.hardware.list_network_interfaces()
mocked_execute.assert_has_calls([
mock.call('ip', '-4', 'addr', 'show', 'eth0'),
mock.call('ip', '-6', 'addr', 'show', 'eth0'),
mock.call('biosdevname', '-i', 'eth0')
])
self.assertEqual(1, len(interfaces))
self.assertEqual('eth0', interfaces[0].name)
self.assertEqual('00:0c:29:8c:11:b1', interfaces[0].mac_address)
@ -314,7 +336,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
self.assertEqual('em0', interfaces[0].biosdevname)
@mock.patch('ironic_python_agent.hardware.get_managers', autospec=True)
@mock.patch('netifaces.ifaddresses', autospec=True)
@mock.patch('os.listdir', autospec=True)
@mock.patch('os.path.exists', autospec=True)
@mock.patch('builtins.open', autospec=True)
@ -328,7 +349,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_open,
mocked_exists,
mocked_listdir,
mocked_ifaddresses,
mockedget_managers):
mockedget_managers.return_value = [hardware.GenericHardwareManager()]
mocked_listdir.return_value = ['lo', 'eth0']
@ -337,14 +357,19 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_open.return_value.__exit__ = mock.Mock()
read_mock = mocked_open.return_value.read
read_mock.side_effect = ['1']
mocked_ifaddresses.return_value = {
netifaces.AF_INET: [{'addr': '192.168.1.2'}],
netifaces.AF_INET6: [{'addr': 'fd00::101'}]
}
mocked_execute.return_value = ('em0\n', '')
mocked_execute.side_effect = [
(IPV4_ADDRESS, ''),
(IPV6_ADDRESS, ''),
('em0\n', '')
]
mock_get_mac.return_value = '00:0c:29:8c:11:b1'
mock_has_carrier.return_value = True
interfaces = self.hardware.list_network_interfaces()
mocked_execute.assert_has_calls([
mock.call('ip', '-4', 'addr', 'show', 'eth0'),
mock.call('ip', '-6', 'addr', 'show', 'eth0'),
mock.call('biosdevname', '-i', 'eth0')
])
self.assertEqual(1, len(interfaces))
self.assertEqual('eth0', interfaces[0].name)
self.assertEqual('00:0c:29:8c:11:b1', interfaces[0].mac_address)
@ -407,7 +432,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
@mock.patch('ironic_python_agent.hardware.get_managers', autospec=True)
@mock.patch('ironic_python_agent.netutils.get_lldp_info', autospec=True)
@mock.patch('netifaces.ifaddresses', autospec=True)
@mock.patch('os.listdir', autospec=True)
@mock.patch('os.path.exists', autospec=True)
@mock.patch('builtins.open', autospec=True)
@ -421,7 +445,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_open,
mocked_exists,
mocked_listdir,
mocked_ifaddresses,
mocked_lldp_info,
mockedget_managers):
mockedget_managers.return_value = [hardware.GenericHardwareManager()]
@ -432,10 +455,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_open.return_value.__exit__ = mock.Mock()
read_mock = mocked_open.return_value.read
read_mock.side_effect = ['1']
mocked_ifaddresses.return_value = {
netifaces.AF_INET: [{'addr': '192.168.1.2'}],
netifaces.AF_INET6: [{'addr': 'fd00::101'}]
}
mocked_lldp_info.return_value = {'eth0': [
(0, b''),
(1, b'\x04\x88Z\x92\xecTY'),
@ -444,8 +463,17 @@ class TestGenericHardwareManager(base.IronicAgentTest):
}
mock_has_carrier.return_value = True
mock_get_mac.return_value = '00:0c:29:8c:11:b1'
mocked_execute.return_value = ('em0\n', '')
mocked_execute.side_effect = [
(IPV4_ADDRESS, ''),
(IPV6_ADDRESS, ''),
('em0\n', '')
]
interfaces = self.hardware.list_network_interfaces()
mocked_execute.assert_has_calls([
mock.call('ip', '-4', 'addr', 'show', 'eth0'),
mock.call('ip', '-6', 'addr', 'show', 'eth0'),
mock.call('biosdevname', '-i', 'eth0')
])
self.assertEqual(1, len(interfaces))
self.assertEqual('eth0', interfaces[0].name)
self.assertEqual('00:0c:29:8c:11:b1', interfaces[0].mac_address)
@ -465,14 +493,13 @@ class TestGenericHardwareManager(base.IronicAgentTest):
@mock.patch.object(netutils, 'get_mac_addr', autospec=True)
@mock.patch('ironic_python_agent.hardware.get_managers', autospec=True)
@mock.patch('ironic_python_agent.netutils.get_lldp_info', autospec=True)
@mock.patch('netifaces.ifaddresses', autospec=True)
@mock.patch('os.listdir', autospec=True)
@mock.patch('os.path.exists', autospec=True)
@mock.patch('builtins.open', autospec=True)
@mock.patch.object(il_utils, 'execute', autospec=True)
def test_list_network_interfaces_with_lldp_error(
self, mocked_execute, mocked_open, mocked_exists, mocked_listdir,
mocked_ifaddresses, mocked_lldp_info, mockedget_managers,
mocked_lldp_info, mockedget_managers,
mock_get_mac, mock_has_carrier):
mockedget_managers.return_value = [hardware.GenericHardwareManager()]
CONF.set_override('collect_lldp', True)
@ -482,15 +509,20 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_open.return_value.__exit__ = mock.Mock()
read_mock = mocked_open.return_value.read
read_mock.side_effect = ['1']
mocked_ifaddresses.return_value = {
netifaces.AF_INET: [{'addr': '192.168.1.2'}],
netifaces.AF_INET6: [{'addr': 'fd00::101'}]
}
mocked_lldp_info.side_effect = Exception('Boom!')
mocked_execute.return_value = ('em0\n', '')
mocked_execute.side_effect = [
(IPV4_ADDRESS, ''),
(IPV6_ADDRESS, ''),
('em0\n', '')
]
mock_has_carrier.return_value = True
mock_get_mac.return_value = '00:0c:29:8c:11:b1'
interfaces = self.hardware.list_network_interfaces()
mocked_execute.assert_has_calls([
mock.call('ip', '-4', 'addr', 'show', 'eth0'),
mock.call('ip', '-6', 'addr', 'show', 'eth0'),
mock.call('biosdevname', '-i', 'eth0')
])
self.assertEqual(1, len(interfaces))
self.assertEqual('eth0', interfaces[0].name)
self.assertEqual('00:0c:29:8c:11:b1', interfaces[0].mac_address)
@ -525,14 +557,19 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_open.return_value.__exit__ = mock.Mock()
read_mock = mocked_open.return_value.read
read_mock.side_effect = [OSError('boom')]
mocked_ifaddresses.return_value = {
netifaces.AF_INET: [{'addr': '192.168.1.2'}],
netifaces.AF_INET6: [{'addr': 'fd00::101'}]
}
mocked_execute.return_value = ('em0\n', '')
mocked_execute.side_effect = [
(IPV4_ADDRESS, ''),
(IPV6_ADDRESS, ''),
('em0\n', '')
]
mock_has_carrier.return_value = False
mock_get_mac.return_value = '00:0c:29:8c:11:b1'
interfaces = self.hardware.list_network_interfaces()
mocked_execute.assert_has_calls([
mock.call('ip', '-4', 'addr', 'show', 'eth0'),
mock.call('ip', '-6', 'addr', 'show', 'eth0'),
mock.call('biosdevname', '-i', 'eth0')
])
self.assertEqual(1, len(interfaces))
self.assertEqual('eth0', interfaces[0].name)
self.assertEqual('00:0c:29:8c:11:b1', interfaces[0].mac_address)
@ -543,7 +580,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
self.assertEqual('em0', interfaces[0].biosdevname)
@mock.patch('ironic_python_agent.hardware.get_managers', autospec=True)
@mock.patch('netifaces.ifaddresses', autospec=True)
@mock.patch('os.listdir', autospec=True)
@mock.patch('os.path.exists', autospec=True)
@mock.patch('builtins.open', autospec=True)
@ -557,7 +593,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_open,
mocked_exists,
mocked_listdir,
mocked_ifaddresses,
mockedget_managers):
mockedget_managers.return_value = [hardware.GenericHardwareManager()]
mocked_listdir.return_value = ['lo', 'eth0']
@ -567,14 +602,19 @@ class TestGenericHardwareManager(base.IronicAgentTest):
read_mock = mocked_open.return_value.read
mac = '00:0c:29:8c:11:b1'
read_mock.side_effect = ['0x15b3\n', '0x1014\n']
mocked_ifaddresses.return_value = {
netifaces.AF_INET: [{'addr': '192.168.1.2'}],
netifaces.AF_INET6: [{'addr': 'fd00::101'}]
}
mocked_execute.return_value = ('em0\n', '')
mocked_execute.side_effect = [
(IPV4_ADDRESS, ''),
(IPV6_ADDRESS, ''),
('em0\n', '')
]
mock_has_carrier.return_value = True
mock_get_mac.return_value = mac
interfaces = self.hardware.list_network_interfaces()
mocked_execute.assert_has_calls([
mock.call('ip', '-4', 'addr', 'show', 'eth0'),
mock.call('ip', '-6', 'addr', 'show', 'eth0'),
mock.call('biosdevname', '-i', 'eth0')
])
self.assertEqual(1, len(interfaces))
self.assertEqual('eth0', interfaces[0].name)
self.assertEqual(mac, interfaces[0].mac_address)
@ -586,7 +626,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
self.assertEqual('em0', interfaces[0].biosdevname)
@mock.patch('ironic_python_agent.hardware.get_managers', autospec=True)
@mock.patch('netifaces.ifaddresses', autospec=True)
@mock.patch('os.listdir', autospec=True)
@mock.patch('os.path.exists', autospec=True)
@mock.patch('builtins.open', autospec=True)
@ -600,7 +639,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_open,
mocked_exists,
mocked_listdir,
mocked_ifaddresses,
mockedget_managers):
mockedget_managers.return_value = [hardware.GenericHardwareManager()]
mocked_listdir.return_value = ['lo', 'bond0']
@ -609,17 +647,22 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_open.return_value.__exit__ = mock.Mock()
read_mock = mocked_open.return_value.read
read_mock.side_effect = ['1']
mocked_ifaddresses.return_value = {
netifaces.AF_INET: [{'addr': '192.168.1.2'}],
netifaces.AF_INET6: [{'addr': 'fd00::101'}]
}
mocked_execute.return_value = ('\n', '')
mocked_execute.side_effect = [
(IPV4_ADDRESS, ''),
(IPV6_ADDRESS, ''),
('\n', '')
]
mock_has_carrier.return_value = True
mock_get_mac.side_effect = [
'00:0c:29:8c:11:b1',
None,
]
interfaces = self.hardware.list_network_interfaces()
mocked_execute.assert_has_calls([
mock.call('ip', '-4', 'addr', 'show', 'bond0'),
mock.call('ip', '-6', 'addr', 'show', 'bond0'),
mock.call('biosdevname', '-i', 'bond0')
])
self.assertEqual(1, len(interfaces))
self.assertEqual('bond0', interfaces[0].name)
self.assertEqual('00:0c:29:8c:11:b1', interfaces[0].mac_address)
@ -630,7 +673,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
self.assertEqual('', interfaces[0].biosdevname)
@mock.patch('ironic_python_agent.hardware.get_managers', autospec=True)
@mock.patch('netifaces.ifaddresses', autospec=True)
@mock.patch('os.listdir', autospec=True)
@mock.patch('os.path.exists', autospec=True)
@mock.patch('builtins.open', autospec=True)
@ -644,7 +686,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_open,
mocked_exists,
mocked_listdir,
mocked_ifaddresses,
mockedget_managers):
mockedget_managers.return_value = [hardware.GenericHardwareManager()]
CONF.set_override('enable_vlan_interfaces', 'eth0.100')
@ -654,14 +695,19 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_open.return_value.__exit__ = mock.Mock()
read_mock = mocked_open.return_value.read
read_mock.side_effect = ['1']
mocked_ifaddresses.return_value = {
netifaces.AF_INET: [{'addr': '192.168.1.2'}],
netifaces.AF_INET6: [{'addr': 'fd00::101'}]
}
mocked_execute.return_value = ('em0\n', '')
mocked_execute.side_effect = [
(IPV4_ADDRESS, ''),
(IPV6_ADDRESS, ''),
('em0\n', '')
]
mock_get_mac.mock_has_carrier = True
mock_get_mac.return_value = '00:0c:29:8c:11:b1'
interfaces = self.hardware.list_network_interfaces()
mocked_execute.assert_has_calls([
mock.call('ip', '-4', 'addr', 'show', 'eth0'),
mock.call('ip', '-6', 'addr', 'show', 'eth0'),
mock.call('biosdevname', '-i', 'eth0')
])
self.assertEqual(2, len(interfaces))
self.assertEqual('eth0', interfaces[0].name)
self.assertEqual('00:0c:29:8c:11:b1', interfaces[0].mac_address)
@ -674,7 +720,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
@mock.patch('ironic_python_agent.hardware.get_managers', autospec=True)
@mock.patch('ironic_python_agent.netutils.get_lldp_info', autospec=True)
@mock.patch('netifaces.ifaddresses', autospec=True)
@mock.patch('os.listdir', autospec=True)
@mock.patch('os.path.exists', autospec=True)
@mock.patch('builtins.open', autospec=True)
@ -688,7 +733,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_open,
mocked_exists,
mocked_listdir,
mocked_ifaddresses,
mocked_lldp_info,
mockedget_managers):
mockedget_managers.return_value = [hardware.GenericHardwareManager()]
@ -727,7 +771,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
@mock.patch.object(netutils, 'LOG', autospec=True)
@mock.patch('ironic_python_agent.hardware.get_managers', autospec=True)
@mock.patch('netifaces.ifaddresses', autospec=True)
@mock.patch('os.listdir', autospec=True)
@mock.patch('os.path.exists', autospec=True)
@mock.patch('builtins.open', autospec=True)
@ -741,7 +784,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_open,
mocked_exists,
mocked_listdir,
mocked_ifaddresses,
mockedget_managers,
mocked_log):
mockedget_managers.return_value = [hardware.GenericHardwareManager()]
@ -753,10 +795,6 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mocked_open.return_value.__exit__ = mock.Mock()
read_mock = mocked_open.return_value.read
read_mock.side_effect = ['1']
mocked_ifaddresses.return_value = {
netifaces.AF_INET: [{'addr': '192.168.1.2'}],
netifaces.AF_INET6: [{'addr': 'fd00::101'}]
}
mocked_execute.return_value = ('em0\n', '')
mock_get_mac.mock_has_carrier = True
mock_get_mac.return_value = '00:0c:29:8c:11:b1'