Closed BwL1289 closed 1 week ago
Thanks for reporting! I'll see if I can find a quick fix. Can you share the full public ips list for the two (feel free to obfuscate part of the ips, I mainly want to see if the lists are the same and how the order differs)? The ordering hasn't ever technically been meaningful, but it's nice when a guess is useful and consistency is important.
Unfortunately I only have the full list of public ips for the new behavior (before we filter) but here's the list:
['169.254.XXX.X', '10.0.XX.XX']
Let me know what else I can provide!
Ah, sorry. You can still compute them both if you have both netifaces and psutil:
import netifaces
import psutil
from jupyter_client import localinterfaces
localinterfaces._load_ips_psutil()
print("psutil ", localinterfaces.PUBLIC_IPS)
localinterfaces._load_ips_netifaces()
print("netifaces", localinterfaces.PUBLIC_IPS)
print("psutil ", list(psutil.net_if_addrs()))
print("netifaces", list(netifaces.interfaces()))
which give me:
psutil ['192.168.1.50', '192.168.69.1']
netifaces ['192.168.1.50', '192.168.69.1']
psutil ['lo0', 'en0', 'bridge100', 'anpi0', 'anpi1', 'anpi2', 'en4', 'en5', 'en6', 'en1', 'en2', 'en3', 'bridge0', 'ap1', 'awdl0', 'llw0', 'vmenet0', 'utun0', 'utun1', 'utun2', 'utun3', 'utun4', 'utun5', 'utun6', 'utun7']
netifaces ['lo0', 'gif0', 'stf0', 'anpi0', 'anpi1', 'anpi2', 'en4', 'en5', 'en6', 'en1', 'en2', 'en3', 'bridge0', 'ap1', 'en0', 'awdl0', 'llw0', 'utun0', 'utun1', 'utun2', 'utun3', 'utun4', 'utun5', 'utun6', 'utun7', 'vmenet0', 'bridge100']
and if you can identify the interface label for each of the ipv4 addresses, e.g. with:
ifconfig | grep -B 5 'inet '
But public_ips
should effectively be considered an unordered set. We can manually sort 169.254
to last.
Got it! I can keep the filtering we have.
Manually sorting link locals to last or updating the docs that it should be considered an unordered set sounds like a good solution. Might help some users down the road.
Thanks!
Thinking about it, 169.254 probably should be filtered out of public_ips like 127 is. I can't think of what that change would break, but probably something.
Makes sense to me (though not sure about the unintended breaking changes that may result). The method name public_ips
makes me think this is the behavior users expect.
There are only two hard things in Computer Science: cache invalidation and naming things. -- Phil Karlton
public_ips
is specifically meant to be for "pick some ips that other machines on some network will be able to connect to me", and link-local isn't that, so it makes sense to exclude it just like we do for 127.BTW, how were you using this? I've used public_ips()[0]
in some jupyterhub demos, but it's never been guaranteed to work since ordering is unstable and not consistent across systems, and the right answer depends on your networking situation. Specifying an actual network interface is far more reliable (but tedious, because every environment has different networking interfaces):
import socket
import psutil
def ip_for_iface(iface="en0"):
"""Return ipv4 address for the given named network interface"""
# select interface
iface_addrs = psutil.net_if_addrs()[iface]
# filter to ipv4
iface_inet = [addr for addr in iface_addrs if addr.family == socket.AF_INET]
# return first ip
return iface_inet[0].address
print(ip_for_iface("en0"))
This was a naive implementation in dev
.
Deploying to prod will include specifying a network interface as you indicated above.
Thank you and appreciate the prompt patch.
Introduced in 5d4888116a69b8f8edb69e51a22b8d4df3a54741 in
jupyter_client/localinterfaces.py
, the changes made topublic_ips()
method breaks existing deployments.Previously, the following yielded the correct public ip address:
Now, it yields the linked local address:
For now, I am manually filtering out IPs that are one of: ipv4 link local ips (unicast), ipv6 ips (unicast), ipv4 multicast ips, or ipv6 multicast ips, but would love to see this get fixed upstream.