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

View File

@ -13,13 +13,13 @@
# License for the specific language governing permissions and limitations
# under the License.
from collections import namedtuple
import contextlib
import io
import socket
from unittest import mock
import netaddr
import netifaces
from oslotest import base as test_base
from oslo_utils import netutils
@ -358,31 +358,75 @@ class NetworkUtilsTest(test_base.BaseTestCase):
addr = netutils.get_my_ipv6()
self.assertEqual(addr, '2001:db8::2')
@mock.patch('netifaces.gateways')
@mock.patch('netifaces.ifaddresses')
def test_get_my_ip_address_with_default_route(
self, ifaddr, gateways):
ifaddr.return_value = {netifaces.AF_INET: [{'addr': '172.18.204.1'}],
netifaces.AF_INET6: [{'addr': '2001:db8::2'}]}
self.assertEqual('172.18.204.1', netutils._get_my_ipv4_address())
@mock.patch('builtins.open')
@mock.patch('psutil.net_if_addrs')
def test_get_my_ipv4_address_with_default_route(
self, mock_ifaddrs, mock_open):
mock_open.return_value = io.StringIO(
"""Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
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())
mock_open.assert_called_once_with('/proc/net/ipv6_route')
@mock.patch('netifaces.gateways')
@mock.patch('netifaces.ifaddresses')
def test_get_my_ip_address_without_default_route(
self, ifaddr, gateways):
ifaddr.return_value = {}
self.assertEqual('127.0.0.1', netutils._get_my_ipv4_address())
self.assertEqual('::1', netutils._get_my_ipv6_address())
@mock.patch('builtins.open')
@mock.patch('psutil.net_if_addrs')
def test_get_my_ipv4_address_without_default_route(
self, mock_ifaddrs, mock_open):
mock_open.return_value = io.StringIO(
"""Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
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())
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.assertFalse(ifaddr.called)
mock_open.assert_called_once_with('/proc/net/ipv6_route')
mock_ifaddrs.assert_not_called()
class IPv6byEUI64TestCase(test_base.BaseTestCase):

View File

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