Skip to content

Commit 8f356ef

Browse files
committed
Update ws_client_test.py
Update configuration.py What type of PR is this? /kind bug What this PR does / why we need it: This PRs will read environment variables assigned for proxy and no_proxy.
1 parent afd1d44 commit 8f356ef

File tree

1 file changed

+118
-20
lines changed

1 file changed

+118
-20
lines changed

kubernetes/base/stream/ws_client_test.py

+118-20
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,70 @@
1717
from .ws_client import get_websocket_url
1818
from .ws_client import websocket_proxycare
1919
from kubernetes.client.configuration import Configuration
20+
import os
21+
import socket
22+
import threading
23+
import pytest
24+
from kubernetes import stream, client, config
2025

2126
try:
2227
import urllib3
2328
urllib3.disable_warnings()
2429
except ImportError:
2530
pass
31+
@pytest.fixture(autouse=True)
32+
def dummy_kubeconfig(tmp_path, monkeypatch):
33+
# Creating a kubeconfig
34+
content = """
35+
apiVersion: v1
36+
kind: Config
37+
clusters:
38+
- name: default
39+
cluster:
40+
server: http://127.0.0.1:8888
41+
contexts:
42+
- name: default
43+
context:
44+
cluster: default
45+
user: default
46+
users:
47+
- name: default
48+
user: {}
49+
current-context: default
50+
"""
51+
cfg_file = tmp_path / "kubeconfig"
52+
cfg_file.write_text(content)
53+
monkeypatch.setenv("KUBECONFIG", str(cfg_file))
2654

27-
def dictval(dict, key, default=None):
28-
try:
29-
val = dict[key]
30-
except KeyError:
31-
val = default
32-
return val
55+
56+
def dictval(dict_obj, key, default=None):
57+
58+
return dict_obj.get(key, default)
59+
60+
class DummyProxy(threading.Thread):
61+
"""
62+
A minimal HTTP proxy that flags any CONNECT request and returns 200 OK.
63+
Listens on 127.0.0.1:8888 by default.
64+
"""
65+
def __init__(self, host='127.0.0.1', port=8888):
66+
super().__init__(daemon=True)
67+
self.host = host
68+
self.port = port
69+
self.received_connect = False
70+
self._server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
71+
self._server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
72+
self._server_sock.bind((self.host, self.port))
73+
self._server_sock.listen(1)
74+
75+
def run(self):
76+
conn, _ = self._server_sock.accept()
77+
try:
78+
data = conn.recv(1024).decode('utf-8', errors='ignore')
79+
if data.startswith('CONNECT '):
80+
self.received_connect = True
81+
conn.sendall(b"HTTP/1.1 200 Connection established\r\n\r\n")
82+
finally:
83+
conn.close()
3384

3485
class WSClientTest(unittest.TestCase):
3586

@@ -56,21 +107,68 @@ def test_websocket_proxycare(self):
56107
( 'http://proxy.example.com:8080/', 'user:pass', '.example.com', 'proxy.example.com', 8080, ('user','pass'), ['.example.com']),
57108
( 'http://proxy.example.com:8080/', 'user:pass', 'localhost,.local,.example.com', 'proxy.example.com', 8080, ('user','pass'), ['localhost','.local','.example.com']),
58109
]:
59-
# setup input
60-
config = Configuration()
61-
if proxy is not None:
62-
setattr(config, 'proxy', proxy)
63-
if idpass is not None:
64-
setattr(config, 'proxy_headers', urllib3.util.make_headers(proxy_basic_auth=idpass))
110+
# input setup
111+
cfg = Configuration()
112+
if proxy:
113+
cfg.proxy = proxy
114+
if idpass:
115+
cfg.proxy_headers = urllib3.util.make_headers(proxy_basic_auth=idpass)
65116
if no_proxy is not None:
66-
setattr(config, 'no_proxy', no_proxy)
67-
# setup done
68-
# test starts
69-
connect_opt = websocket_proxycare( {}, config, None, None)
70-
self.assertEqual( dictval(connect_opt,'http_proxy_host'), expect_host)
71-
self.assertEqual( dictval(connect_opt,'http_proxy_port'), expect_port)
72-
self.assertEqual( dictval(connect_opt,'http_proxy_auth'), expect_auth)
73-
self.assertEqual( dictval(connect_opt,'http_no_proxy'), expect_noproxy)
117+
cfg.no_proxy = no_proxy
118+
119+
120+
connect_opts = websocket_proxycare({}, cfg, None, None)
121+
assert dictval(connect_opts, 'http_proxy_host') == expect_host
122+
assert dictval(connect_opts, 'http_proxy_port') == expect_port
123+
assert dictval(connect_opts, 'http_proxy_auth') == expect_auth
124+
assert dictval(connect_opts, 'http_no_proxy') == expect_noproxy
125+
126+
@pytest.fixture(scope="module")
127+
def dummy_proxy():
128+
#Dummy Proxy
129+
proxy = DummyProxy(port=8888)
130+
proxy.start()
131+
yield proxy
132+
133+
@pytest.fixture(autouse=True)
134+
def clear_proxy_env(monkeypatch):
135+
for var in ("HTTP_PROXY", "http_proxy", "HTTPS_PROXY", "https_proxy", "NO_PROXY", "no_proxy"):
136+
monkeypatch.delenv(var, raising=False)
137+
138+
def apply_proxy_to_conf():
139+
#apply HTTPS_PROXY env var and set it as global.
140+
cfg = client.Configuration.get_default_copy()
141+
cfg.proxy = os.getenv("HTTPS_PROXY")
142+
cfg.no_proxy = os.getenv("NO_PROXY", "")
143+
client.Configuration.set_default(cfg)
144+
145+
def test_rest_call_ignores_env(dummy_proxy, monkeypatch):
146+
# HTTPS_PROXY to dummy proxy
147+
monkeypatch.setenv("HTTPS_PROXY", "http://127.0.0.1:8888")
148+
# Avoid real HTTP request
149+
monkeypatch.setattr(client.CoreV1Api, "list_namespace", lambda self, *_args, **_kwargs: None)
150+
# Load config using kubeconfig
151+
config.load_kube_config(config_file=os.environ["KUBECONFIG"])
152+
apply_proxy_to_conf()
153+
# HTTPS_PROXY to dummy proxy
154+
monkeypatch.setenv("HTTPS_PROXY", "http://127.0.0.1:8888")
155+
config.load_kube_config(config_file=os.environ["KUBECONFIG"])
156+
apply_proxy_to_conf()
157+
v1 = client.CoreV1Api()
158+
v1.list_namespace(_preload_content=False)
159+
assert not dummy_proxy.received_connect, "REST path should ignore HTTPS_PROXY"
160+
161+
def test_websocket_call_honors_env(dummy_proxy, monkeypatch):
162+
# set HTTPS_PROXY again
163+
monkeypatch.setenv("HTTPS_PROXY", "http://127.0.0.1:8888")
164+
# Load kubeconfig
165+
config.load_kube_config(config_file=os.environ["KUBECONFIG"])
166+
apply_proxy_to_conf()
167+
opts = websocket_proxycare({}, client.Configuration.get_default_copy(), None, None)
168+
assert opts.get('http_proxy_host') == '127.0.0.1'
169+
assert opts.get('http_proxy_port') == 8888
170+
# Optionally verify no_proxy parsing
171+
assert opts.get('http_no_proxy') is None
74172

75173
if __name__ == '__main__':
76174
unittest.main()

0 commit comments

Comments
 (0)