Skip to content

fix: Use HTTP_PROXY and HTTPS_PROXY environment variables for proxy #2397

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 11, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,19 +96,16 @@ export OPENSHIFT_PYTHON_WRAPPER_LOG_LEVEL=<LOG_LEVEL> # can be: "DEBUG", "INFO",
## Proxy Enablement

This configuration allows the client to route traffic through a specified proxy server.
It can be enabled via the environment variable `OPENSHIFT_PYTHON_WRAPPER_CLIENT_USE_PROXY`.

To enable proxy configuration for the client:

1. Set the environment variable `OPENSHIFT_PYTHON_WRAPPER_CLIENT_USE_PROXY=<any value>`
1. Define either `HTTPS_PROXY` or `HTTP_PROXY` environment variable with your proxy URL:

2. Define either `HTTPS_PROXY` or `HTTP_PROXY` environment variable with your proxy URL:
```bash
export HTTPS_PROXY="http://proxy.example.com:8080"
# or
export HTTP_PROXY="http://proxy.example.com:8080"
```
If neither variable is set when proxy is enabled, a `ValueError` will be raised.

## Code check

Expand Down
65 changes: 32 additions & 33 deletions ocp_resources/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,13 @@ def _get_api_version(dyn_client: DynamicClient, api_group: str, kind: str) -> st


def get_client(
config_file: str = "",
config_file: str | None = None,
config_dict: dict[str, Any] | None = None,
context: str = "",
**kwargs: Any,
context: str | None = None,
client_configuration: kubernetes.client.Configuration | None = None,
persist_config: bool = True,
temp_file_path: str | None = None,
try_refresh_token: bool = True,
) -> DynamicClient:
"""
Get a kubernetes client.
Expand All @@ -97,19 +100,23 @@ def get_client(
config_file (str): path to a kubeconfig file.
config_dict (dict): dict with kubeconfig configuration.
context (str): name of the context to use.
persist_config (bool): whether to persist config file.
temp_file_path (str): path to a temporary kubeconfig file.
try_refresh_token (bool): try to refresh token

Returns:
DynamicClient: a kubernetes client.
"""
# Ref: https://github.com/kubernetes-client/python/blob/v26.1.0/kubernetes/base/config/kube_config.py
if config_dict:
return kubernetes.dynamic.DynamicClient(
client=kubernetes.config.new_client_from_config_dict(
config_dict=config_dict, context=context or None, **kwargs
)
_client = kubernetes.config.new_client_from_config_dict(
config_dict=config_dict,
context=context,
client_configuration=client_configuration,
persist_config=persist_config,
temp_file_path=temp_file_path,
)
client_configuration = kwargs.get("client_configuration", kubernetes.client.Configuration())
try:
else:
# Ref: https://github.com/kubernetes-client/python/blob/v26.1.0/kubernetes/base/config/__init__.py
LOGGER.info("Trying to get client via new_client_from_config")

Expand All @@ -118,36 +125,28 @@ def get_client(
# is populated during import which comes before setting the variable in code.
config_file = config_file or os.environ.get("KUBECONFIG", "~/.kube/config")

if os.environ.get("OPENSHIFT_PYTHON_WRAPPER_CLIENT_USE_PROXY"):
proxy = os.environ.get("HTTPS_PROXY") or os.environ.get("HTTP_PROXY")
if not proxy:
raise ValueError(
"Proxy configuration is enabled but neither HTTPS_PROXY nor HTTP_PROXY environment variables are set."
)
if client_configuration.proxy and client_configuration.proxy != proxy:
raise ValueError(
f"Conflicting proxy settings: client_configuration.proxy={client_configuration.proxy}, "
f"but the environment variable 'HTTPS_PROXY/HTTP_PROXY' defines proxy as {proxy}."
)
client_configuration.proxy = proxy

kwargs["client_configuration"] = client_configuration

return kubernetes.dynamic.DynamicClient(
client=kubernetes.config.new_client_from_config(
config_file=config_file,
context=context or None,
**kwargs,
)
_client = kubernetes.config.new_client_from_config(
config_file=config_file,
context=context,
client_configuration=client_configuration,
persist_config=persist_config,
)

proxy = os.environ.get("HTTPS_PROXY") or os.environ.get("HTTP_PROXY")

if not _client.configuration.proxy and proxy:
LOGGER.info(f"Setting proxy from environment variable: {proxy}")
_client.configuration.proxy = proxy

try:
return kubernetes.dynamic.DynamicClient(client=_client)
except MaxRetryError:
# Ref: https://github.com/kubernetes-client/python/blob/v26.1.0/kubernetes/base/config/incluster_config.py
LOGGER.info("Trying to get client via incluster_config")
return kubernetes.dynamic.DynamicClient(
client=kubernetes.config.incluster_config.load_incluster_config(
client_configuration=client_configuration,
try_refresh_token=kwargs.get("try_refresh_token", True),
)
client_configuration=client_configuration, try_refresh_token=try_refresh_token
),
)


Expand Down
43 changes: 17 additions & 26 deletions tests/test_resources.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from __future__ import annotations

import pytest
import yaml
from docker.errors import DockerException
import kubernetes
from testcontainers.k3s import K3SContainer

from ocp_resources.exceptions import ResourceTeardownError
Expand All @@ -19,13 +20,18 @@ def clean_up(self, wait: bool = True, timeout: int | None = None) -> bool:
return False


@pytest.fixture(scope="session")
def client():
@pytest.fixture(scope="class")
def k3scontainer_config():
try:
with K3SContainer() as k3s:
yield get_client(config_dict=yaml.safe_load(k3s.config_yaml()))
except DockerException:
pytest.skip("K3S container not available")
yield yaml.safe_load(k3s.config_yaml())
except DockerException as ex:
pytest.skip(f"K3S container not available. {ex}")


@pytest.fixture(scope="class")
def client(k3scontainer_config):
yield get_client(config_dict=k3scontainer_config)


@pytest.fixture(scope="class")
Expand Down Expand Up @@ -109,25 +115,10 @@ def test_resource_context_manager_exit(self, client):
with SecretTestExit(name="test-context-manager-exit", namespace="default", client=client):
pass

def test_proxy_enabled_but_no_proxy_set(self, monkeypatch):
monkeypatch.setenv(name="OPENSHIFT_PYTHON_WRAPPER_CLIENT_USE_PROXY", value="1")

with pytest.raises(
ValueError,
match="Proxy configuration is enabled but neither HTTPS_PROXY nor HTTP_PROXY environment variables are set.",
):
get_client()

def test_proxy_conflict_raises_value_error(self, monkeypatch):
monkeypatch.setenv(name="OPENSHIFT_PYTHON_WRAPPER_CLIENT_USE_PROXY", value="1")
monkeypatch.setenv(name="HTTPS_PROXY", value="http://env-proxy.com")

client_configuration = kubernetes.client.Configuration()
client_configuration.proxy = "http://not-env-proxy.com"
def test_client_with_proxy(monkeypatch, k3scontainer_config):
proxy = "http://env-proxy.com"
monkeypatch.setenv(name="HTTPS_PROXY", value=proxy)

with pytest.raises(
ValueError,
match="Conflicting proxy settings: client_configuration.proxy=http://not-env-proxy.com, "
"but the environment variable 'HTTPS_PROXY/HTTP_PROXY' defines proxy as http://env-proxy.com.",
):
get_client(client_configuration=client_configuration)
client = get_client(config_dict=k3scontainer_config)
assert client.configuration.proxy == proxy