Drop dependency on netifaces

The netifaces library was abandoned and archived. Replace it by own
parse logic from proc files + psutil.

Closes-Bug: #2071596
Change-Id: I334e10b869694eaa8c6afd842ce8d4dc606a4f5b
This commit is contained in:
Takashi Kajinami 2024-10-06 20:15:47 +09:00
parent 756af007d1
commit 2ec1ce3661
3 changed files with 99 additions and 39 deletions

View File

@ -27,7 +27,7 @@ from urllib import parse
import netaddr import netaddr
from netaddr.core import INET_ATON from netaddr.core import INET_ATON
from netaddr.core import INET_PTON from netaddr.core import INET_PTON
import netifaces import psutil
from oslo_utils._i18n import _ from oslo_utils._i18n import _
@ -417,16 +417,23 @@ def _get_my_ipv4_address():
"""Figure out the best ipv4 """Figure out the best ipv4
""" """
LOCALHOST = '127.0.0.1' LOCALHOST = '127.0.0.1'
gtw = netifaces.gateways() interface = None
try:
interface = gtw['default'][netifaces.AF_INET][1] with open('/proc/net/route') as routes:
except (KeyError, IndexError): for route in routes:
LOG.info('Could not determine default network interface, ' route_attrs = route.strip().split('\t')
'using 127.0.0.1 for IPv4 address') if route_attrs[1] == '00000000':
return LOCALHOST interface = route_attrs[0]
break
else:
LOG.info('Could not determine default network interface, '
'using %s for IPv4 address', LOCALHOST)
return LOCALHOST
try: try:
return netifaces.ifaddresses(interface)[netifaces.AF_INET][0]['addr'] addrs = psutil.net_if_addrs()[interface]
v4addrs = [addr for addr in addrs if addr.family == socket.AF_INET]
return v4addrs[0].address
except (KeyError, IndexError): except (KeyError, IndexError):
LOG.info('Could not determine IPv4 address for interface %s, ' LOG.info('Could not determine IPv4 address for interface %s, '
'using 127.0.0.1', 'using 127.0.0.1',
@ -461,16 +468,25 @@ def _get_my_ipv6_address():
"""Figure out the best IPv6 address """Figure out the best IPv6 address
""" """
LOCALHOST = '::1' LOCALHOST = '::1'
gtw = netifaces.gateways() interface = None
try: ZERO_ADDRESS = '00000000000000000000000000000000'
interface = gtw['default'][netifaces.AF_INET6][1]
except (KeyError, IndexError): with open('/proc/net/ipv6_route') as routes:
LOG.info('Could not determine default network interface, ' for route in routes:
'using %s for IPv6 address', LOCALHOST) route_attrs = route.strip().split(' ')
return LOCALHOST if ((route_attrs[0], route_attrs[1]) == (ZERO_ADDRESS, '00') and
(route_attrs[2], route_attrs[3]) == (ZERO_ADDRESS, '00')):
interface = route_attrs[-1]
break
else:
LOG.info('Could not determine default network interface, '
'using %s for IPv6 address', LOCALHOST)
return LOCALHOST
try: try:
return netifaces.ifaddresses(interface)[netifaces.AF_INET6][0]['addr'] addrs = psutil.net_if_addrs()[interface]
v6addrs = [addr for addr in addrs if addr.family == socket.AF_INET6]
return v6addrs[0].address
except (KeyError, IndexError): except (KeyError, IndexError):
LOG.info('Could not determine IPv6 address for interface ' LOG.info('Could not determine IPv6 address for interface '
'%(interface)s, using %(address)s', '%(interface)s, using %(address)s',

View File

@ -13,13 +13,13 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from collections import namedtuple
import contextlib import contextlib
import io import io
import socket import socket
from unittest import mock from unittest import mock
import netaddr import netaddr
import netifaces
from oslotest import base as test_base from oslotest import base as test_base
from oslo_utils import netutils from oslo_utils import netutils
@ -358,31 +358,75 @@ class NetworkUtilsTest(test_base.BaseTestCase):
addr = netutils.get_my_ipv6() addr = netutils.get_my_ipv6()
self.assertEqual(addr, '2001:db8::2') self.assertEqual(addr, '2001:db8::2')
@mock.patch('netifaces.gateways') @mock.patch('builtins.open')
@mock.patch('netifaces.ifaddresses') @mock.patch('psutil.net_if_addrs')
def test_get_my_ip_address_with_default_route( def test_get_my_ipv4_address_with_default_route(
self, ifaddr, gateways): self, mock_ifaddrs, mock_open):
ifaddr.return_value = {netifaces.AF_INET: [{'addr': '172.18.204.1'}], mock_open.return_value = io.StringIO(
netifaces.AF_INET6: [{'addr': '2001:db8::2'}]} """Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
self.assertEqual('172.18.204.1', netutils._get_my_ipv4_address()) eth0 00000000 01cc12ac 0003 0 0 600 00000000 0 0 0
eth0 00cc12ac 00000000 0001 0 0 600 00FFFFFF 0 0 0
eth1 00cd12ac 00000000 0001 0 0 600 00FFFFFF 0 0 0""") # noqa : E501
addr = namedtuple('addr', ['family', 'address'])
mock_ifaddrs.return_value = {
'eth0': [
addr(family=socket.AF_INET, address='172.18.204.2'),
addr(family=socket.AF_INET6, address='2001:db8::2')
],
'eth1': [
addr(family=socket.AF_INET, address='172.18.205.2'),
addr(family=socket.AF_INET6, address='2001:db8::1000::2')
]}
self.assertEqual('172.18.204.2', netutils._get_my_ipv4_address())
mock_open.assert_called_once_with('/proc/net/route')
@mock.patch('builtins.open')
@mock.patch('psutil.net_if_addrs')
def test_get_my_ipv6_address_with_default_route(
self, mock_ifaddrs, mock_open):
mock_open.return_value = io.StringIO(
"""00000000000000000000000000000000 00 00000000000000000000000000000000 00 20010db8000000000000000000000001 00000000 00000000 00000000 08000000 eth0
20010db8000000000000000000000000 31 00000000000000000000000000000000 00 00000000000000000000000000000000 00000000 00000000 00000000 08000000 eth0
20010db8100000000000000000000000 31 00000000000000000000000000000000 00 00000000000000000000000000000000 00000000 00000000 00000000 08000000 eth1""") # noqa: E501
addr = namedtuple('addr', ['family', 'address'])
mock_ifaddrs.return_value = {
'eth0': [
addr(family=socket.AF_INET, address='172.18.204.2'),
addr(family=socket.AF_INET6, address='2001:db8::2')
],
'eth1': [
addr(family=socket.AF_INET, address='172.18.205.2'),
addr(family=socket.AF_INET6, address='2001:db8::1000::2')
]}
self.assertEqual('2001:db8::2', netutils._get_my_ipv6_address()) self.assertEqual('2001:db8::2', netutils._get_my_ipv6_address())
mock_open.assert_called_once_with('/proc/net/ipv6_route')
@mock.patch('netifaces.gateways') @mock.patch('builtins.open')
@mock.patch('netifaces.ifaddresses') @mock.patch('psutil.net_if_addrs')
def test_get_my_ip_address_without_default_route( def test_get_my_ipv4_address_without_default_route(
self, ifaddr, gateways): self, mock_ifaddrs, mock_open):
ifaddr.return_value = {} mock_open.return_value = io.StringIO(
self.assertEqual('127.0.0.1', netutils._get_my_ipv4_address()) """Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
self.assertEqual('::1', netutils._get_my_ipv6_address()) eth0 00cc12ac 00000000 0001 0 0 600 00FFFFFF 0 0 0
eth1 00cd12ac 00000000 0001 0 0 600 00FFFFFF 0 0 0""") # noqa : E501
@mock.patch('netifaces.gateways')
@mock.patch('netifaces.ifaddresses')
def test_get_my_ipv4_address_without_default_interface(
self, ifaddr, gateways):
gateways.return_value = {}
self.assertEqual('127.0.0.1', netutils._get_my_ipv4_address()) self.assertEqual('127.0.0.1', netutils._get_my_ipv4_address())
mock_open.assert_called_once_with('/proc/net/route')
mock_ifaddrs.assert_not_called()
@mock.patch('builtins.open')
@mock.patch('psutil.net_if_addrs')
def test_get_my_ipv6_address_without_default_route(
self, mock_ifaddrs, mock_open):
mock_open.return_value = io.StringIO(
"""20010db8000000000000000000000000 31 00000000000000000000000000000000 00 00000000000000000000000000000000 00000000 00000000 00000000 08000000 eth0
20010db8100000000000000000000000 31 00000000000000000000000000000000 00 00000000000000000000000000000000 00000000 00000000 00000000 08000000 eth1""") # noqa: E501
self.assertEqual('::1', netutils._get_my_ipv6_address()) self.assertEqual('::1', netutils._get_my_ipv6_address())
self.assertFalse(ifaddr.called) mock_open.assert_called_once_with('/proc/net/ipv6_route')
mock_ifaddrs.assert_not_called()
class IPv6byEUI64TestCase(test_base.BaseTestCase): class IPv6byEUI64TestCase(test_base.BaseTestCase):

View File

@ -6,9 +6,9 @@
iso8601>=0.1.11 # MIT iso8601>=0.1.11 # MIT
oslo.i18n>=3.15.3 # Apache-2.0 oslo.i18n>=3.15.3 # Apache-2.0
netaddr>=0.10.0 # BSD netaddr>=0.10.0 # BSD
netifaces>=0.10.4 # MIT
debtcollector>=1.2.0 # Apache-2.0 debtcollector>=1.2.0 # Apache-2.0
pyparsing>=2.1.0 # MIT pyparsing>=2.1.0 # MIT
packaging>=20.4 # BSD packaging>=20.4 # BSD
tzdata>=2022.4 # MIT tzdata>=2022.4 # MIT
PyYAML>=3.13 # MIT PyYAML>=3.13 # MIT
psutil>=3.2.2 # BST