Skip to content

Commit e17488c

Browse files
Drop netifaces dependency
The netifaces library is no longer maintained, which is why we need to drop this dependency. There is only one place in which netifaces is being used, a trivial function that retrives the mac address for a given ip address. Thankfully, we already have a cloudbase-init "get_adapter_addresses" function that uses ctypes to call GetAdaptersAddresses, which happens to be the same Windows function used by netifaces. Worth mentioning that netifaces is the only compilable cloudbase-init dependency that does not provide a wheel package. Fixes: #140 Change-Id: Ie52ff722cbf42da7b9bfa9f9942adc1996ce5dd8
1 parent dc03674 commit e17488c

File tree

6 files changed

+58
-34
lines changed

6 files changed

+58
-34
lines changed

cloudbaseinit/osutils/base.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ def get_network_adapters(self):
9191
def get_network_adapter_name_by_mac_address(self, mac_address):
9292
raise NotImplementedError()
9393

94+
def get_mac_address_by_local_ip(self, ip_addr):
95+
raise NotImplementedError()
96+
9497
def set_network_adapter_mtu(self, name, mtu):
9598
raise NotImplementedError()
9699

cloudbaseinit/osutils/windows.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,13 @@ def get_network_adapter_name_by_mac_address(self, mac_address):
819819

820820
return iface_index_list[0]["friendly_name"]
821821

822+
def get_mac_address_by_local_ip(self, ip_addr):
823+
for iface in network.get_adapter_addresses():
824+
addrs = iface.get('unicast_addresses', [])
825+
for addr, family in addrs:
826+
if ip_addr and addr and ip_addr.lower() == addr.lower():
827+
return iface['mac_address'].lower()
828+
822829
@retry_decorator.retry_decorator(
823830
max_retry_count=3, exceptions=exception.ItemNotFoundException)
824831
def set_network_adapter_mtu(self, name, mtu):

cloudbaseinit/tests/osutils/test_windows.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2153,6 +2153,44 @@ def test_get_network_adapter_name_by_mac_address_multiple_adapters(self):
21532153
self._test_get_network_adapter_name_by_mac_address(
21542154
multiple_adapters_found=True)
21552155

2156+
@mock.patch("cloudbaseinit.utils.windows.network."
2157+
"get_adapter_addresses")
2158+
def test_get_mac_address_by_local_ip(self, mock_get_adapter_addresses):
2159+
fake_addresses = [
2160+
{
2161+
"friendly_name": "mgmt",
2162+
"mac_address": "24:6E:96:E0:FE:76",
2163+
"interface_type": 6,
2164+
"unicast_addresses": [("fe80::499d:b2f9:48c0:c88e%20", 23),
2165+
("10.11.12.13", 2)],
2166+
},
2167+
{
2168+
"friendly_name": "Loopback Pseudo-Interface 1",
2169+
"mac_address": "",
2170+
"interface_type": 24,
2171+
"unicast_addresses": [("::1", 23), ("127.0.0.1", 2)],
2172+
},
2173+
]
2174+
2175+
mock_get_adapter_addresses.return_value = fake_addresses
2176+
2177+
self.assertEqual(
2178+
"24:6e:96:e0:fe:76",
2179+
self._winutils.get_mac_address_by_local_ip("10.11.12.13"))
2180+
self.assertEqual(
2181+
"24:6e:96:e0:fe:76",
2182+
self._winutils.get_mac_address_by_local_ip(
2183+
"fe80::499d:b2f9:48c0:c88e%20"))
2184+
self.assertEqual(
2185+
"24:6e:96:e0:fe:76",
2186+
self._winutils.get_mac_address_by_local_ip(
2187+
"FE80::499D:B2F9:48C0:C88E%20"))
2188+
self.assertEqual(
2189+
"",
2190+
self._winutils.get_mac_address_by_local_ip("127.0.0.1"))
2191+
self.assertIsNone(
2192+
self._winutils.get_mac_address_by_local_ip("10.10.10.10"))
2193+
21562194
@mock.patch('cloudbaseinit.osutils.windows.WindowsUtils'
21572195
'.execute_process')
21582196
@mock.patch('cloudbaseinit.osutils.windows.WindowsUtils'

cloudbaseinit/tests/utils/test_dhcp.py

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
# License for the specific language governing permissions and limitations
1313
# under the License.
1414

15-
import netifaces
1615
import socket
1716
import struct
1817
import unittest
@@ -108,35 +107,19 @@ def test_parse_dhcp_reply_other_than_cookie(self):
108107
self._test_parse_dhcp_reply(message_type=3, id_reply=111,
109108
equals_cookie=False)
110109

111-
@mock.patch('netifaces.ifaddresses')
112-
@mock.patch('netifaces.interfaces')
113-
def test_get_mac_address_by_local_ip(self, mock_interfaces,
114-
mock_ifaddresses):
115-
fake_addresses = {}
116-
fake_addresses[netifaces.AF_INET] = [{'addr': 'fake address'}]
117-
fake_addresses[netifaces.AF_LINK] = [{'addr': 'fake mac'}]
118-
119-
mock_interfaces.return_value = ['fake interface']
120-
mock_ifaddresses.return_value = fake_addresses
121-
122-
response = dhcp._get_mac_address_by_local_ip('fake address')
123-
124-
mock_interfaces.assert_called_once_with()
125-
mock_ifaddresses.assert_called_once_with('fake interface')
126-
self.assertEqual(fake_addresses[netifaces.AF_LINK][0]['addr'],
127-
response)
128-
129110
@mock.patch('random.randint')
130111
@mock.patch('socket.socket')
131-
@mock.patch('cloudbaseinit.utils.dhcp._get_mac_address_by_local_ip')
132112
@mock.patch('cloudbaseinit.utils.dhcp._get_dhcp_request_data')
133113
@mock.patch('cloudbaseinit.utils.dhcp._parse_dhcp_reply')
134-
def test_get_dhcp_options(self, mock_parse_dhcp_reply,
114+
@mock.patch('cloudbaseinit.osutils.factory.get_os_utils')
115+
def test_get_dhcp_options(self, mock_get_os_utils,
116+
mock_parse_dhcp_reply,
135117
mock_get_dhcp_request_data,
136-
mock_get_mac_address_by_local_ip, mock_socket,
137-
mock_randint):
118+
mock_socket, mock_randint):
138119
mock_randint.return_value = 'fake int'
139120
mock_socket().getsockname.return_value = ['fake local ip']
121+
mock_get_mac_address_by_local_ip = (
122+
mock_get_os_utils.return_value.get_mac_address_by_local_ip)
140123
mock_get_mac_address_by_local_ip.return_value = 'fake mac'
141124
mock_get_dhcp_request_data.return_value = 'fake data'
142125
mock_parse_dhcp_reply.return_value = (True, 'fake replied options')

cloudbaseinit/utils/dhcp.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@
1313
# under the License.
1414

1515
import datetime
16-
import netifaces
1716
import random
1817
import socket
1918
import struct
2019
import time
2120

2221
from oslo_log import log as oslo_logging
2322

23+
from cloudbaseinit.osutils import factory as osutils_factory
2424
from cloudbaseinit.utils import network
2525

2626
_DHCP_COOKIE = b'\x63\x82\x53\x63'
@@ -96,14 +96,6 @@ def _parse_dhcp_reply(data, id_req):
9696
return True, options
9797

9898

99-
def _get_mac_address_by_local_ip(ip_addr):
100-
for iface in netifaces.interfaces():
101-
addrs = netifaces.ifaddresses(iface)
102-
for addr in addrs.get(netifaces.AF_INET, []):
103-
if addr['addr'] == ip_addr:
104-
return addrs[netifaces.AF_LINK][0]['addr']
105-
106-
10799
def _bind_dhcp_client_socket(s, max_bind_attempts, bind_retry_interval):
108100
bind_attempts = 1
109101
while True:
@@ -138,7 +130,9 @@ def get_dhcp_options(dhcp_host=None, requested_options=[], timeout=5.0,
138130
s.settimeout(timeout)
139131

140132
local_ip_addr = network.get_local_ip(dhcp_host)
141-
mac_address = _get_mac_address_by_local_ip(local_ip_addr)
133+
134+
osutils = osutils_factory.get_os_utils()
135+
mac_address = osutils.get_mac_address_by_local_ip(local_ip_addr)
142136

143137
data = _get_dhcp_request_data(id_req, mac_address, requested_options,
144138
vendor_id)

requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ oslo.config
66
oslo.log
77
Babel>=1.3
88
oauthlib
9-
netifaces
109
PyYAML
1110
requests
1211
untangle==1.2.1

0 commit comments

Comments
 (0)