diff --git a/CHANGELOG.md b/CHANGELOG.md index ec83e89482c..4de09d5586d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * Fix #6052: Removed dependency on no longer maintained com.github.mifmif:generex #### New Features +* Fix #6150: Config uses `proxy-url` in kubeconfig's cluster configuration #### _**Note**_: Breaking changes * Check detailed migration documentation for breaking changes in [7.0.0](./doc/MIGRATION-v7.md) diff --git a/README.md b/README.md index 1eeaf5027a1..0bca4a6896c 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,8 @@ System properties are preferred over environment variables. The following system | `kubernetes.keystore.passphrase` / `KUBERNETES_KEYSTORE_PASSPHRASE` | | | | `kubernetes.backwardsCompatibilityInterceptor.disable` / `KUBERNETES_BACKWARDSCOMPATIBILITYINTERCEPTOR_DISABLE` | Disable the `BackwardsCompatibilityInterceptor` | `true` | | `no.proxy` / `NO_PROXY` | comma-separated list of domain extensions [proxy](http://www.gnu.org/software/wget/manual/html_node/Proxies.html) should not be used for | | +| `http.proxy` / `HTTP_PROXY` | URL to the [proxy](http://www.gnu.org/software/wget/manual/html_node/Proxies.html) for HTTP requests (See [Proxy precedence](./doc/FAQ.md#how-does-kubernetesclient-loads-proxy-url-from-various-sources)) | | +| `https.proxy` / `HTTPS_PROXY` | URL to the [proxy](http://www.gnu.org/software/wget/manual/html_node/Proxies.html) for HTTPS requests (See [Proxy precedence](./doc/FAQ.md#how-does-kubernetesclient-loads-proxy-url-from-various-sources)) | | Alternatively you can use the `ConfigBuilder` to create a config object for the Kubernetes client: diff --git a/doc/FAQ.md b/doc/FAQ.md index b361ed4bf93..b4a5a09990c 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -110,6 +110,17 @@ we should provide it like this: NO_PROXY: localhost,127.0.0.1,.google.com,.github.com ``` +### How does KubernetesClient loads proxy URL from various sources? + +KubernetesClient loads proxy URL from the following sources (in decreasing order of precedence): +- `ConfigBuilder.withHttpProxy` / `ConfigBuilder.withHttpsProxy` +- Cluster's `proxy-url` in `~/.kube/config` +- System Properties or Environment Variables + - `HTTP_PROXY` : Should be used for HTTP requests (when Kubernetes ApiServer is serving plain HTTP requests) + - `HTTPS_PROXY` : Should be used for HTTPS requests (when Kubernetes ApiServer is serving HTTPS) + +URLs with `http`, `https`, and `socks5` schemes are supported. + ### Optimistic Locking Behavior Unfortunately it's a little complicated as it depends on what operation you are doing - we'll work towards ensuring the Javadocs are as informative as possible. Here is quick overview: diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Config.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Config.java index 34260a58748..0d4e09637ba 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Config.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Config.java @@ -153,6 +153,7 @@ public class Config { private static final int DEFAULT_WATCH_RECONNECT_INTERVAL = 1000; private static final int DEFAULT_CONNECTION_TIMEOUT = 10 * 1000; private static final String DEFAULT_CLIENT_KEY_PASSPHRASE = "changeit"; + private static final String SOCKS5_PROTOCOL_PREFIX = "socks5://"; private Boolean trustCerts; private Boolean disableHostnameVerification; @@ -696,11 +697,17 @@ public static void configFromSysPropsOrEnvVars(Config config) { config.setHttp2Disable(Utils.getSystemPropertyOrEnvVar(KUBERNETES_HTTP2_DISABLE, config.isHttp2Disable())); - config.setHttpProxy(Utils.getSystemPropertyOrEnvVar(KUBERNETES_ALL_PROXY, config.getHttpProxy())); - config.setHttpsProxy(Utils.getSystemPropertyOrEnvVar(KUBERNETES_ALL_PROXY, config.getHttpsProxy())); - - config.setHttpsProxy(Utils.getSystemPropertyOrEnvVar(KUBERNETES_HTTPS_PROXY, config.getHttpsProxy())); - config.setHttpProxy(Utils.getSystemPropertyOrEnvVar(KUBERNETES_HTTP_PROXY, config.getHttpProxy())); + // Only set http(s) proxy fields if they're not set. This is done in order to align behavior of + // KubernetesClient with kubectl / client-go . Please see https://github.com/fabric8io/kubernetes-client/issues/6150 + // Precedence is given to proxy-url read from kubeconfig . + if (Utils.isNullOrEmpty(config.getHttpProxy())) { + config.setHttpProxy(Utils.getSystemPropertyOrEnvVar(KUBERNETES_ALL_PROXY, config.getHttpProxy())); + config.setHttpProxy(Utils.getSystemPropertyOrEnvVar(KUBERNETES_HTTP_PROXY, config.getHttpProxy())); + } + if (Utils.isNullOrEmpty(config.getHttpsProxy())) { + config.setHttpsProxy(Utils.getSystemPropertyOrEnvVar(KUBERNETES_ALL_PROXY, config.getHttpsProxy())); + config.setHttpsProxy(Utils.getSystemPropertyOrEnvVar(KUBERNETES_HTTPS_PROXY, config.getHttpsProxy())); + } config.setProxyUsername(Utils.getSystemPropertyOrEnvVar(KUBERNETES_PROXY_USERNAME, config.getProxyUsername())); config.setProxyPassword(Utils.getSystemPropertyOrEnvVar(KUBERNETES_PROXY_PASSWORD, config.getProxyPassword())); @@ -926,6 +933,18 @@ private static void mergeKubeConfigContents(Config config, String context, io.fa if (currentAuthInfo != null) { mergeKubeConfigAuthInfo(config, currentCluster, currentAuthInfo); } + String proxyUrl = currentCluster.getProxyUrl(); + if (Utils.isNotNullOrEmpty(proxyUrl)) { + if (proxyUrl.startsWith(SOCKS5_PROTOCOL_PREFIX) && config.getMasterUrl().startsWith(HTTPS_PROTOCOL_PREFIX)) { + config.setHttpsProxy(proxyUrl); + } else if (proxyUrl.startsWith(SOCKS5_PROTOCOL_PREFIX)) { + config.setHttpProxy(proxyUrl); + } else if (proxyUrl.startsWith(HTTP_PROTOCOL_PREFIX)) { + config.setHttpProxy(proxyUrl); + } else if (proxyUrl.startsWith(HTTPS_PROTOCOL_PREFIX)) { + config.setHttpsProxy(proxyUrl); + } + } } } diff --git a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/ConfigProxySourceTest.java b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/ConfigProxySourceTest.java index fa1ef152670..c21a45a2ae0 100644 --- a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/ConfigProxySourceTest.java +++ b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/ConfigProxySourceTest.java @@ -15,257 +15,530 @@ */ package io.fabric8.kubernetes.client; +import io.fabric8.kubernetes.client.utils.Serialization; import io.fabric8.kubernetes.client.utils.Utils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; class ConfigProxySourceTest { + @TempDir + private File temporaryFolder; + @Nested - @DisplayName("http.proxy System property") - class HttpProxySystemProperty { - @BeforeEach - void setup() { - System.setProperty("http.proxy", "http://proxy-via-http-proxy-property:3128"); - } + @DisplayName("HTTP Proxy") + class HttpProxyConfig { + @Nested + @DisplayName("http.proxy System property") + class HttpProxySystemProperty { + @BeforeEach + void setup() { + System.setProperty("http.proxy", "http://proxy-via-http-proxy-property:3128"); + } - @AfterEach - void tearDown() { - System.clearProperty("http.proxy"); + @AfterEach + void tearDown() { + System.clearProperty("http.proxy"); + } + + @Test + @DisplayName("no other proxy configuration, then http.proxy property takes precedence") + void noOtherConfiguration() { + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-http-proxy-property:3128"); + } + + @Test + @DisplayName("all.proxy property configuration, then http.proxy property takes precedence") + void allProxySystemProperty() { + try { + System.setProperty("all.proxy", "http://proxy-via-all-proxy-property:3128"); + + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-http-proxy-property:3128"); + } finally { + System.clearProperty("all.proxy"); + } + } + + @Test + @DisplayName("user configures proxy via builder, then user configuration via builder takes precedence") + void httpProxyViaBuilder() { + assertThat(new ConfigBuilder().withHttpProxy("http://proxy-via-builder:3128").build()) + .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-builder:3128"); + } + + @Test + @DisplayName("kubeconfig cluster has http proxy-url, then kubeconfig proxy-url takes precedence") + void kubeConfigProxyUrl() throws IOException { + try { + // Given + System.setProperty("kubeconfig", + createKubeConfigWithCluster("http://kubernetes-remote-server.example:6443", "http://proxy-server.example:80") + .getAbsolutePath()); + // When + Then + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-server.example:80"); + } finally { + System.clearProperty("kubeconfig"); + } + } } - @Test - @DisplayName("no other proxy configuration, then http.proxy property takes precedence") - void noOtherConfiguration() { - assertThat(new ConfigBuilder().build()) - .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-http-proxy-property:3128") - .hasFieldOrPropertyWithValue("httpsProxy", null); + @Nested + @DisplayName("withHttpProxy via builder") + class ProxyViaBuilder { + private ConfigBuilder configBuilder; + + @BeforeEach + void setUp() { + configBuilder = new ConfigBuilder().withHttpProxy("http://proxy-via-builder:3128"); + } + + @Test + @DisplayName("no other proxy configuration, then user configuration via builder takes precedence") + void noOtherConfiguration() { + assertThat(configBuilder.build()) + .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-builder:3128"); + } + + @Test + @DisplayName("http.proxy property configuration, then user configuration via builder takes precedence") + void httpProxySystemProperty() { + try { + System.setProperty("http.proxy", "http://proxy-via-http-proxy-property:3128"); + + assertThat(configBuilder.build()) + .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-builder:3128"); + } finally { + System.clearProperty("http.proxy"); + } + } + + @Test + @DisplayName("all.proxy property configuration, then user configuration via builder takes precedence") + void allProxySystemProperty() { + try { + System.setProperty("all.proxy", "http://proxy-via-all-proxy-property:3128"); + + assertThat(configBuilder.build()) + .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-builder:3128"); + } finally { + System.clearProperty("all.proxy"); + } + } + + @Test + @DisplayName("kubeconfig cluster has proxy-url, then user configuration via builder takes precedence") + void kubeConfigProxyUrl() throws IOException { + try { + // Given + System.setProperty("kubeconfig", + createKubeConfigWithCluster("http://kubernetes-remote-server.example:6443", "http://proxy-server.example:80") + .getAbsolutePath()); + // When + Then + assertThat(configBuilder.build()) + .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-builder:3128"); + } finally { + System.clearProperty("kubeconfig"); + } + } } - @Test - @DisplayName("all.proxy property configuration, then http.proxy property takes precedence") - void allProxySystemProperty() { - try { + @Nested + @DisplayName("all.proxy System property") + class AllProxySystemProperty { + @BeforeEach + void setup() { System.setProperty("all.proxy", "http://proxy-via-all-proxy-property:3128"); + } - assertThat(new ConfigBuilder().build()) - .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-http-proxy-property:3128") - .hasFieldOrPropertyWithValue("httpsProxy", "http://proxy-via-all-proxy-property:3128"); - } finally { + @AfterEach + void tearDown() { System.clearProperty("all.proxy"); } - } - - @Test - @DisplayName("user configures proxy via builder, then user configuration via builder takes precedence") - void httpProxyViaBuilder() { - assertThat(new ConfigBuilder().withHttpProxy("http://proxy-via-builder:3128").build()) - .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-builder:3128") - .hasFieldOrPropertyWithValue("httpsProxy", null); - } - @Test - @DisplayName("kubeconfig cluster has proxy-url, then http.proxy property takes precedence") - void kubeConfigProxyUrl() { - try { - // Given - System.setProperty("kubeconfig", Utils - .filePath(ConfigTest.class.getResource("/config-proxy-source/kubeconfig-with-proxy-url"))); - // When + Then + @Test + @DisplayName("no other proxy configuration, then all.proxy property takes precedence") + void noOtherConfiguration() { assertThat(new ConfigBuilder().build()) - .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-http-proxy-property:3128") - .hasFieldOrPropertyWithValue("httpsProxy", null); - } finally { - System.clearProperty("kubeconfig"); + .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-all-proxy-property:3128"); } - } - } - @Nested - @DisplayName("all.proxy System property") - class AllProxySystemProperty { - @BeforeEach - void setup() { - System.setProperty("all.proxy", "http://proxy-via-all-proxy-property:3128"); - } + @Test + @DisplayName("http.proxy property configuration, then http.proxy property takes precedence") + void allProxySystemProperty() { + try { + System.setProperty("http.proxy", "http://proxy-via-http-proxy-property:3128"); + + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-http-proxy-property:3128"); + } finally { + System.clearProperty("http.proxy"); + } + } - @AfterEach - void tearDown() { - System.clearProperty("all.proxy"); - } + @Test + @DisplayName("user configures proxy via builder, then user configuration via builder takes precedence") + void httpProxyViaBuilder() { + assertThat(new ConfigBuilder().withHttpProxy("http://proxy-via-builder:3128").build()) + .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-builder:3128"); + } - @Test - @DisplayName("no other proxy configuration, then all.proxy property takes precedence") - void noOtherConfiguration() { - assertThat(new ConfigBuilder().build()) - .hasFieldOrPropertyWithValue("httpsProxy", "http://proxy-via-all-proxy-property:3128") - .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-all-proxy-property:3128"); + @Test + @DisplayName("kubeconfig cluster has proxy-url, then kubeconfig proxy-url takes precedence") + void kubeConfigProxyUrl() throws IOException { + try { + // Given + System.setProperty("kubeconfig", + createKubeConfigWithCluster("http://kubernetes-remote-server.example:6443", "http://proxy-server.example:80") + .getAbsolutePath()); + // When + Then + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-server.example:80"); + } finally { + System.clearProperty("kubeconfig"); + } + } } - @Test - @DisplayName("http.proxy property configuration, then http.proxy property takes precedence") - void allProxySystemProperty() { - try { - System.setProperty("http.proxy", "http://proxy-via-http-proxy-property:3128"); + @Nested + @DisplayName("kubeconfig contains proxy-url in cluster configuration") + class KubeConfigWithProxyUrl { + @BeforeEach + void setup() throws IOException { + System.setProperty("kubeconfig", + createKubeConfigWithCluster("http://kubernetes-remote-server.example:6443", "socks5://proxy-server.example:80") + .getAbsolutePath()); + } - assertThat(new ConfigBuilder().build()) - .hasFieldOrPropertyWithValue("httpsProxy", "http://proxy-via-all-proxy-property:3128") - .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-http-proxy-property:3128"); - } finally { - System.clearProperty("http.proxy"); + @AfterEach + void tearDown() { + System.clearProperty("kubeconfig"); } - } - @Test - @DisplayName("user configures proxy via builder, then user configuration via builder takes precedence") - void httpProxyViaBuilder() { - assertThat(new ConfigBuilder().withHttpProxy("http://proxy-via-builder:3128").build()) - .hasFieldOrPropertyWithValue("httpsProxy", "http://proxy-via-all-proxy-property:3128") - .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-builder:3128"); - } + @Test + @DisplayName("proxy-url with sock5 scheme, masterUrl with http scheme, then Config sets httpProxy") + void whenProxyUrlSocks5MasterUrlHttp_thenHttpProxySetInConfig() { + // When + Then + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpProxy", "socks5://proxy-server.example:80") + .hasFieldOrPropertyWithValue("httpsProxy", null); + } - @Test - @DisplayName("kubeconfig cluster has proxy-url, then all.proxy property takes precedence") - void kubeConfigProxyUrl() { - try { + @Test + @DisplayName("proxy-url with http scheme, masterUrl with http scheme, then Config sets httpProxy") + void whenProxyUrlHttp_thenHttpProxySetInConfig() throws IOException { // Given - System.setProperty("kubeconfig", Utils - .filePath(ConfigTest.class.getResource("/config-proxy-source/kubeconfig-with-proxy-url"))); + System.setProperty("kubeconfig", + createKubeConfigWithCluster("http://kubernetes-remote-server.example:6443", "http://proxy-server.example:80") + .getAbsolutePath()); // When + Then assertThat(new ConfigBuilder().build()) - .hasFieldOrPropertyWithValue("httpsProxy", "http://proxy-via-all-proxy-property:3128") - .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-all-proxy-property:3128"); - } finally { - System.clearProperty("kubeconfig"); + .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-server.example:80") + .hasFieldOrPropertyWithValue("httpsProxy", null); + } + + @Test + @DisplayName("http.proxy property configuration, kubeconfig proxy-url takes precedence") + void httpProxySystemProperty() { + try { + System.setProperty("http.proxy", "http://proxy-via-http-proxy-property:3128"); + + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpProxy", "socks5://proxy-server.example:80"); + } finally { + System.clearProperty("http.proxy"); + } + } + + @Test + @DisplayName("all.proxy property configuration, then kubeconfig proxy-url takes precedence") + void allProxySystemProperty() { + try { + System.setProperty("all.proxy", "http://proxy-via-all-proxy-property:3128"); + + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpProxy", "socks5://proxy-server.example:80"); + } finally { + System.clearProperty("all.proxy"); + } + } + + @Test + @DisplayName("user configures proxy via builder, then user configuration via builder takes precedence") + void httpProxyViaBuilder() { + assertThat(new ConfigBuilder().withHttpProxy("http://proxy-via-builder:3128").build()) + .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-builder:3128"); } } } @Nested - @DisplayName("withHttpProxy via builder") - class ProxyViaBuilder { - private ConfigBuilder configBuilder; + @DisplayName("HTTPS Proxy") + class HttpsProxyConfig { + @Nested + @DisplayName("https.proxy System property") + class HttpsProxySystemProperty { + @BeforeEach + void setup() { + System.setProperty("https.proxy", "http://proxy-via-http-proxy-property:3128"); + } - @BeforeEach - void setUp() { - configBuilder = new ConfigBuilder().withHttpProxy("http://proxy-via-builder:3128"); - } + @AfterEach + void tearDown() { + System.clearProperty("https.proxy"); + } + + @Test + @DisplayName("no other proxy configuration, then https.proxy property takes precedence") + void noOtherConfiguration() { + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpsProxy", "http://proxy-via-http-proxy-property:3128"); + } + + @Test + @DisplayName("all.proxy property configuration, then https.proxy property takes precedence") + void allProxySystemProperty() { + try { + System.setProperty("all.proxy", "http://proxy-via-all-proxy-property:3128"); + + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpsProxy", "http://proxy-via-http-proxy-property:3128"); + } finally { + System.clearProperty("all.proxy"); + } + } - @Test - @DisplayName("no other proxy configuration, then user configuration via builder takes precedence") - void noOtherConfiguration() { - assertThat(configBuilder.build()) - .hasFieldOrPropertyWithValue("httpsProxy", null) - .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-builder:3128"); + @Test + @DisplayName("user configures proxy via builder, then user configuration via builder takes precedence") + void httpsProxyViaBuilder() { + assertThat(new ConfigBuilder().withHttpsProxy("https://proxy-via-builder:3128").build()) + .hasFieldOrPropertyWithValue("httpsProxy", "https://proxy-via-builder:3128"); + } + + @Test + @DisplayName("kubeconfig cluster has proxy-url, then kubeconfig proxy-url takes precedence") + void kubeConfigProxyUrl() { + try { + // Given + System.setProperty("kubeconfig", Utils + .filePath(ConfigTest.class.getResource("/config-proxy-source/kubeconfig-with-proxy-url"))); + // When + Then + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpsProxy", "socks5://proxy-via-kubeconfig-proxy-url:1080"); + } finally { + System.clearProperty("kubeconfig"); + } + } } - @Test - @DisplayName("http.proxy property configuration, then user configuration via builder takes precedence") - void httpProxySystemProperty() { - try { - System.setProperty("http.proxy", "http://proxy-via-http-proxy-property:3128"); + @Nested + @DisplayName("withHttpsProxy via builder") + class ProxyViaBuilder { + private ConfigBuilder configBuilder; + @BeforeEach + void setUp() { + configBuilder = new ConfigBuilder().withHttpsProxy("https://proxy-via-builder:3128"); + } + + @Test + @DisplayName("no other proxy configuration, then user configuration via builder takes precedence") + void noOtherConfiguration() { assertThat(configBuilder.build()) - .hasFieldOrPropertyWithValue("httpsProxy", null) - .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-builder:3128"); - } finally { - System.clearProperty("http.proxy"); + .hasFieldOrPropertyWithValue("httpsProxy", "https://proxy-via-builder:3128"); + } + + @Test + @DisplayName("https.proxy property configuration, then user configuration via builder takes precedence") + void httpsProxySystemProperty() { + try { + System.setProperty("https.proxy", "https://proxy-via-https-proxy-property:3128"); + + assertThat(configBuilder.build()) + .hasFieldOrPropertyWithValue("httpsProxy", "https://proxy-via-builder:3128"); + } finally { + System.clearProperty("https.proxy"); + } + } + + @Test + @DisplayName("all.proxy property configuration, then user configuration via builder takes precedence") + void allProxySystemProperty() { + try { + System.setProperty("all.proxy", "https://proxy-via-all-proxy-property:3128"); + + assertThat(configBuilder.build()) + .hasFieldOrPropertyWithValue("httpsProxy", "https://proxy-via-builder:3128"); + } finally { + System.clearProperty("all.proxy"); + } + } + + @Test + @DisplayName("kubeconfig cluster has proxy-url, then user configuration via builder takes precedence") + void kubeConfigProxyUrl() { + try { + // Given + System.setProperty("kubeconfig", Utils + .filePath(ConfigTest.class.getResource("/config-proxy-source/kubeconfig-with-proxy-url"))); + // When + Then + assertThat(configBuilder.build()) + .hasFieldOrPropertyWithValue("httpsProxy", "https://proxy-via-builder:3128"); + } finally { + System.clearProperty("kubeconfig"); + } } } - @Test - @DisplayName("all.proxy property configuration, then user configuration via builder takes precedence") - void allProxySystemProperty() { - try { + @Nested + @DisplayName("all.proxy System property") + class AllProxySystemProperty { + @BeforeEach + void setup() { System.setProperty("all.proxy", "http://proxy-via-all-proxy-property:3128"); + } - assertThat(configBuilder.build()) - .hasFieldOrPropertyWithValue("httpsProxy", "http://proxy-via-all-proxy-property:3128") - .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-builder:3128"); - } finally { + @AfterEach + void tearDown() { System.clearProperty("all.proxy"); } - } - @Test - @DisplayName("kubeconfig cluster has proxy-url, then user configuration via builder takes precedence") - void kubeConfigProxyUrl() { - try { - // Given - System.setProperty("kubeconfig", Utils - .filePath(ConfigTest.class.getResource("/config-proxy-source/kubeconfig-with-proxy-url"))); - // When + Then - assertThat(configBuilder.build()) - .hasFieldOrPropertyWithValue("httpsProxy", null) - .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-builder:3128"); - } finally { - System.clearProperty("kubeconfig"); + @Test + @DisplayName("no other proxy configuration, then all.proxy property takes precedence") + void noOtherConfiguration() { + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpsProxy", "http://proxy-via-all-proxy-property:3128"); } - } - } - @Nested - @DisplayName("kubeconfig contains proxy-url in cluster configuration") - class KubeConfigWithProxyUrl { - @BeforeEach - void setup() { - System.setProperty("kubeconfig", Utils - .filePath(ConfigTest.class.getResource("/config-proxy-source/kubeconfig-with-proxy-url"))); - } + @Test + @DisplayName("https.proxy property configuration, then https.proxy property takes precedence") + void allProxySystemProperty() { + try { + System.setProperty("https.proxy", "http://proxy-via-http-proxy-property:3128"); + + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpsProxy", "http://proxy-via-http-proxy-property:3128"); + } finally { + System.clearProperty("https.proxy"); + } + } - @AfterEach - void tearDown() { - System.clearProperty("kubeconfig"); - } + @Test + @DisplayName("user configures proxy via builder, then user configuration via builder takes precedence") + void httpsProxyViaBuilder() { + assertThat(new ConfigBuilder().withHttpsProxy("https://proxy-via-builder:3128").build()) + .hasFieldOrPropertyWithValue("httpsProxy", "https://proxy-via-builder:3128"); + } - @Test - @Disabled("https://github.com/fabric8io/kubernetes-client/issues/6150") - void noOtherConfiguration() { - // When + Then - assertThat(new ConfigBuilder().build()) - .hasFieldOrPropertyWithValue("httpProxy", null) - .hasFieldOrPropertyWithValue("httpsProxy", "socks5://proxy-via-kubeconfig-proxy-url:1080"); + @Test + @DisplayName("kubeconfig cluster has proxy-url, then kubeconfig proxy-url takes precedence") + void kubeConfigProxyUrl() throws IOException { + try { + // Given + System.setProperty("kubeconfig", + createKubeConfigWithCluster("https://kubernetes-remote-server.example:6443", "https://proxy-server.example:80") + .getAbsolutePath()); + // When + Then + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpsProxy", "https://proxy-server.example:80"); + } finally { + System.clearProperty("kubeconfig"); + } + } } - @Test - @DisplayName("http.proxy property configuration, then http.proxy takes precedence") - void httpProxySystemProperty() { - try { - System.setProperty("http.proxy", "http://proxy-via-http-proxy-property:3128"); + @Nested + @DisplayName("kubeconfig contains proxy-url in cluster configuration") + class KubeConfigWithProxyUrl { + @BeforeEach + void setup() { + System.setProperty("kubeconfig", Utils + .filePath(ConfigTest.class.getResource("/config-proxy-source/kubeconfig-with-proxy-url"))); + } - assertThat(new ConfigBuilder().build()) - .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-http-proxy-property:3128") - .hasFieldOrPropertyWithValue("httpsProxy", null); - } finally { - System.clearProperty("http.proxy"); + @AfterEach + void tearDown() { + System.clearProperty("kubeconfig"); } - } - @Test - @DisplayName("all.proxy property configuration, then all.proxy takes precedence") - void allProxySystemProperty() { - try { - System.setProperty("all.proxy", "http://proxy-via-all-proxy-property:3128"); + @Test + @DisplayName("proxy-url with socks5 scheme, masterUrl with https scheme, then Config sets httpsProxy") + void whenProxyUrlSocks5_thenHttpsProxySetInConfig() { + // Given + System.setProperty("kubeconfig", Utils + .filePath(ConfigTest.class.getResource("/config-proxy-source/kubeconfig-with-proxy-url"))); + // When + Then + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpsProxy", "socks5://proxy-via-kubeconfig-proxy-url:1080"); + } + @Test + @DisplayName("proxy-url with https scheme, masterUrl with https scheme, then Config sets httpsProxy") + void whenProxyUrlHttps_thenHttpsProxySetInConfig() throws IOException { + // Given + System.setProperty("kubeconfig", + createKubeConfigWithCluster("https://kubernetes-remote-server.example:6443", "https://proxy-server.example:80") + .getAbsolutePath()); + // When + Then assertThat(new ConfigBuilder().build()) - .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-all-proxy-property:3128") - .hasFieldOrPropertyWithValue("httpsProxy", "http://proxy-via-all-proxy-property:3128"); - } finally { - System.clearProperty("all.proxy"); + .hasFieldOrPropertyWithValue("httpsProxy", "https://proxy-server.example:80"); } - } - @Test - @DisplayName("user configures proxy via builder, then user configuration via builder takes precedence") - void httpProxyViaBuilder() { - assertThat(new ConfigBuilder().withHttpProxy("http://proxy-via-builder:3128").build()) - .hasFieldOrPropertyWithValue("httpProxy", "http://proxy-via-builder:3128") - .hasFieldOrPropertyWithValue("httpsProxy", null); + @Test + @DisplayName("https.proxy property configuration, kubeconfig proxy-url takes precedence") + void httpsProxySystemProperty() { + try { + System.setProperty("https.proxy", "https://proxy-via-http-proxy-property:3128"); + + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpsProxy", "socks5://proxy-via-kubeconfig-proxy-url:1080"); + } finally { + System.clearProperty("https.proxy"); + } + } + + @Test + @DisplayName("all.proxy property configuration, then kubeconfig proxy-url takes precedence") + void allProxySystemProperty() { + try { + System.setProperty("all.proxy", "https://proxy-via-all-proxy-property:3128"); + + assertThat(new ConfigBuilder().build()) + .hasFieldOrPropertyWithValue("httpsProxy", "socks5://proxy-via-kubeconfig-proxy-url:1080"); + } finally { + System.clearProperty("all.proxy"); + } + } + + @Test + @DisplayName("user configures proxy via builder, then user configuration via builder takes precedence") + void httpsProxyViaBuilder() { + assertThat(new ConfigBuilder().withHttpsProxy("https://proxy-via-builder:3128").build()) + .hasFieldOrPropertyWithValue("httpsProxy", "https://proxy-via-builder:3128"); + } } } + + private File createKubeConfigWithCluster(String masterUrl, String proxyUrl) throws IOException { + io.fabric8.kubernetes.api.model.Config kubeConfig = Serialization.unmarshal( + ConfigTest.class.getResourceAsStream("/config-proxy-source/kubeconfig-with-proxy-url"), + io.fabric8.kubernetes.api.model.Config.class); + kubeConfig.getClusters().get(0).getCluster().setServer(masterUrl); + kubeConfig.getClusters().get(0).getCluster().setProxyUrl(proxyUrl); + File updatedKubeConfig = new File(temporaryFolder, "kubeconfig"); + Files.write(updatedKubeConfig.toPath(), Serialization.asYaml(kubeConfig).getBytes(StandardCharsets.UTF_8)); + return updatedKubeConfig; + } }