Skip to content

Commit 2814b18

Browse files
committed
utility functions in net_utils
1 parent 03ec1bc commit 2814b18

File tree

2 files changed

+69
-24
lines changed

2 files changed

+69
-24
lines changed

PandaPkgInfo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
release_version = "0.1.0"
1+
release_version = "0.1.1"

pandacommon/pandautils/net_utils.py

Lines changed: 68 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,32 +22,15 @@
2222
class HTTPAdapterWithRandomDnsResolver(HTTPAdapter):
2323
# override to get connection to random host
2424
def get_connection(self, url, proxies=None):
25+
# resolve cname to hostnames
26+
dns_records = resolve_host_in_url(url)
27+
random.shuffle(dns_records)
2528
# parse URL
2629
parsed = urlparse(url)
27-
host = parsed.hostname
28-
port = parsed.port
29-
if port is None:
30-
if parsed.scheme == "http":
31-
port = 80
32-
else:
33-
port = 443
34-
# check record
35-
if parsed.hostname in dnsMap:
36-
dns_records = dnsMap[parsed.hostname]
37-
else:
38-
family = allowed_gai_family()
39-
dns_records = socket.getaddrinfo(host, port, family, socket.SOCK_STREAM)
40-
dns_records = list(set([socket.getfqdn(record[4][0]) for record in dns_records]))
41-
dnsMap[parsed.hostname] = dns_records
42-
dns_records = copy.copy(dns_records)
43-
random.shuffle(dns_records)
4430
# loop over all hosts
4531
err = None
4632
for hostname in dns_records:
47-
addr = hostname
48-
if parsed.port is not None:
49-
addr += ":{0}".format(parsed.port)
50-
tmp_url = parsed._replace(netloc=addr).geturl()
33+
tmp_url = replace_hostname_in_url(url, hostname)
5134
try:
5235
con = HTTPAdapter.get_connection(self, tmp_url, proxies=proxies)
5336
# return if valid
@@ -60,8 +43,12 @@ def get_connection(self, url, proxies=None):
6043
return None
6144

6245

63-
# utility function to get HTTPAdapterWithRandomDnsResolver
64-
def get_http_adapter_with_random_dns_resolution():
46+
# utility function to get a session object with HTTPAdapterWithRandomDnsResolver
47+
def get_http_adapter_with_random_dns_resolution() -> requests.Session:
48+
"""
49+
Utility function to get a session object with custom HTTPAdapter which resolves host in URL randomly to distribute access to DNS load balanced HTTP services
50+
:return: session object
51+
"""
6552
session = requests.Session()
6653
# no randomization if panda is behind real load balancer than DNS LB
6754
if "PANDA_BEHIND_REAL_LB" in os.environ:
@@ -70,3 +57,61 @@ def get_http_adapter_with_random_dns_resolution():
7057
session.mount("http://", adapter)
7158
session.mount("https://", adapter)
7259
return session
60+
61+
62+
# resolve a host in a given URL to hostnames
63+
def resolve_host_in_url(url: str) -> list[str]:
64+
"""
65+
Resolve a host in a given URL to hostnames
66+
:param url: URL
67+
:return: list of hostnames
68+
"""
69+
# parse URL
70+
parsed = urlparse(url)
71+
host = parsed.hostname
72+
port = parsed.port
73+
if port is None:
74+
if parsed.scheme == "http":
75+
port = 80
76+
else:
77+
port = 443
78+
# check record
79+
if parsed.hostname in dnsMap:
80+
dns_records = dnsMap[parsed.hostname]
81+
else:
82+
family = allowed_gai_family()
83+
dns_records = socket.getaddrinfo(host, port, family, socket.SOCK_STREAM)
84+
dns_records = list(set([socket.getfqdn(record[4][0]) for record in dns_records]))
85+
dnsMap[parsed.hostname] = dns_records
86+
return copy.copy(dns_records)
87+
88+
89+
# replace hostname in URL
90+
def replace_hostname_in_url(url: str, new_host: str) -> str:
91+
"""
92+
Replace hostname in URL
93+
:param url: original URL
94+
:param new_host: new hostname
95+
:return: new URL with replaced hostname
96+
"""
97+
parsed = urlparse(url)
98+
if parsed.port is not None:
99+
new_host += f":{parsed.port}"
100+
return parsed._replace(netloc=new_host).geturl()
101+
102+
103+
# replace hostname in URL randomly
104+
def replace_hostname_in_url_randomly(url: str) -> str:
105+
"""
106+
Replace hostname in URL randomly
107+
:param url: original URL
108+
:return: new URL with new hostname randomly chosen from resolved hostnames
109+
"""
110+
# no replacement if panda is behind real load balancer than DNS LB
111+
if "PANDA_BEHIND_REAL_LB" in os.environ:
112+
return url
113+
# resolve cname to hostnames
114+
dns_records = resolve_host_in_url(url)
115+
# choose one IP randomly
116+
random.shuffle(dns_records)
117+
return replace_hostname_in_url(url, dns_records[0])

0 commit comments

Comments
 (0)