Skip to content

Commit

Permalink
Issue 1415 (#1416)
Browse files Browse the repository at this point in the history
* Don't rely on localhost being resolvable.  #1415

* Fixups.  #1415
  • Loading branch information
mfeit-internet2 authored Mar 14, 2024
1 parent 60c4786 commit ef4f56a
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@

@application.route("/", methods=['GET'])
def root():
return ok_json("This is the pScheduler API server on %s (%s)."
% (server_hostname(), pscheduler.api_local_host_name()),
return ok_json('This is the pScheduler API server'
f' on {server_hostname()} ({socket.gethostname()})',
sanitize=False)


Expand Down
51 changes: 49 additions & 2 deletions python-pscheduler/pscheduler/pscheduler/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

import multiprocessing
import multiprocessing.dummy
import netaddr
import netifaces
import os
import re
import socket
import threading
import urllib
Expand All @@ -23,9 +26,53 @@ def api_local_host():
"Return a hostname and, optionally, a port that should point to the server on this host."
return os.environ.get("PSCHEDULER_LOCALHOST", api_local_host_name())


def api_local_host_name():
"Return the local system's hostname"
return socket.gethostname()
"""
Return a host name or IP suitable for reaching the local system
"""

# Try the system's hostname. This shoud cover most cases.

hostname = socket.gethostname()
try:
socket.gethostbyname(hostname)
# Local host name resolves. Use that.
return hostname
except socket.gaierror:
# Local host name didn't resolve. Do what's next.
pass

# Enumerate the interface addresses on the system and pick the
# first one, preferring loopbacks and IPv6. This is based loosely
# on the code in pScheduler's LocalIPList class and is duplicated
# here so it can be used elsewhere without the rest of the
# pScehduler library.

if_regex = r'%.*$'

addresses = []

# Netifaces returns a very deep structure.
for ifhash in [ netifaces.ifaddresses(iface)
for iface in netifaces.interfaces() ]:
for afamily in ifhash:
for iface in ifhash[afamily]:
address = re.sub(if_regex, '', iface["addr"])
try:
addresses.append(netaddr.IPAddress(address))
except netaddr.core.AddrFormatError:
# Don't care about things that don't look like IPS.
pass

addresses = sorted(addresses,
key=lambda v: [v.is_loopback(), v.version, v.sort_key()],
reverse=True)
try:
return str(addresses[0])
except IndexError:
raise RuntimeError('No interfaces found on this system')


def __host_per_rfc_2732(host):
"Format a host name or IP for a URL according to RFC 2732"
Expand Down
10 changes: 10 additions & 0 deletions python-pscheduler/pscheduler/tests/api_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
test for the api module.
"""

import socket
import unittest

from pscheduler.api import *
Expand All @@ -15,6 +16,15 @@ class TestApi(PschedTestBase):
Api tests.
"""


def test_local_host(self):
self.assertTrue(api_local_host_name() in [
socket.gethostname(),
'::1',
'127.0.0.1'
])


def test_api(self):
"""taken from api.__main__"""

Expand Down

0 comments on commit ef4f56a

Please sign in to comment.