From cb5aeba9702625cc5b2e90992b39d44480c8e810 Mon Sep 17 00:00:00 2001 From: Steve Hawkins Date: Wed, 19 Apr 2023 06:56:26 -0400 Subject: [PATCH] fix #4911: initial work towards consolidating timeouts --- CHANGELOG.md | 3 + .../client/jdkhttp/JdkHttpClientImpl.java | 7 +- .../jdkhttp/JdkHttpClientBuilderTest.java | 5 +- .../client/jetty/JettyHttpClient.java | 11 +-- .../client/jetty/JettyHttpClientBuilder.java | 10 --- .../client/jetty/JettyHttpClientTest.java | 14 ++-- .../okhttp/OkHttpClientBuilderImpl.java | 23 ++----- .../client/okhttp/OkHttpClientImpl.java | 18 ++++- .../client/vertx/VertxHttpClient.java | 12 ++-- .../client/vertx/VertxHttpClientBuilder.java | 4 -- .../vertx/VertxHttpClientBuilderTest.java | 5 +- .../io/fabric8/kubernetes/client/Config.java | 26 ++----- .../kubernetes/client/RequestConfig.java | 13 +--- .../kubernetes/client/dsl/Deletable.java | 15 +++- .../client/dsl/DeletableWithOptions.java | 10 +-- .../kubernetes/client/dsl/Scalable.java | 2 + .../client/dsl/ScalableResource.java | 2 +- .../client/dsl/TimeoutableScalable.java | 36 ++++++++++ .../client/extension/ExtensibleResource.java | 12 +++- .../client/extension/ResourceAdapter.java | 5 +- .../kubernetes/client/http/HttpClient.java | 34 ---------- .../kubernetes/client/http/HttpRequest.java | 13 ++++ .../http/StandardHttpClientBuilder.java | 23 ------- .../client/http/StandardHttpRequest.java | 44 +++++++++--- .../client/http/StandardWebSocketBuilder.java | 8 +++ .../kubernetes/client/http/WebSocket.java | 3 + .../client/utils/HttpClientUtils.java | 4 -- .../fabric8/kubernetes/client/ConfigTest.java | 1 - .../AbstractSimultaneousConnectionsTest.java | 4 +- .../http/AbstractWebSocketSendTest.java | 5 +- .../dsl/internal/AbstractWatchManager.java | 5 +- .../client/dsl/internal/BaseOperation.java | 4 +- .../dsl/internal/HasMetadataOperation.java | 19 ++++-- .../client/dsl/internal/LogWatchCallback.java | 6 +- .../client/dsl/internal/OperationSupport.java | 8 ++- .../client/dsl/internal/PortForwarder.java | 39 ----------- .../dsl/internal/PortForwarderWebsocket.java | 20 ++---- .../dsl/internal/WatchConnectionManager.java | 10 ++- .../client/dsl/internal/WatchHTTPManager.java | 10 +-- .../internal/core/v1/PodOperationsImpl.java | 26 +++---- .../client/osgi/ManagedKubernetesClient.java | 4 -- .../internal/AbstractWatchManagerTest.java | 3 +- .../internal/PortForwarderWebsocketTest.java | 2 +- .../openshift/client/OpenShiftConfig.java | 5 +- .../build/BuildConfigOperationsImpl.java | 8 +-- .../client/impl/OpenShiftClientImpl.java | 68 +++++++++++-------- .../client/osgi/ManagedOpenShiftClient.java | 4 -- .../build/BuildConfigOperationsImplTest.java | 3 +- 48 files changed, 272 insertions(+), 344 deletions(-) create mode 100644 kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/TimeoutableScalable.java delete mode 100644 kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/PortForwarder.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 4606010e7aa..fc3088a7bc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,9 @@ * Fix #4875: Removed unused options from the java-generator * Fix #4910: all Pod file uploads not require commons-compress * Fix #4998: Serialization.yamlMapper and Serialization.clearYamlMapper have been deprecated +* Fix #4911: Config/RequestConfig.scaleTimeout has been deprectated. withTimeout may be called before the scale operation. +* Fix #4911: Config/RequestConfig.websocketTimeout has been removed. Config/RequestConfig.requestTimeout will be used for websocket connection timeouts. +* Fix #4911: HttpClient api/building changes - writeTimeout has been removed, readTimeout has moved to the HttpRequest ### 6.5.1 (2023-03-20) diff --git a/httpclient-jdk/src/main/java/io/fabric8/kubernetes/client/jdkhttp/JdkHttpClientImpl.java b/httpclient-jdk/src/main/java/io/fabric8/kubernetes/client/jdkhttp/JdkHttpClientImpl.java index 01e9b1c609d..27ed3713c5d 100644 --- a/httpclient-jdk/src/main/java/io/fabric8/kubernetes/client/jdkhttp/JdkHttpClientImpl.java +++ b/httpclient-jdk/src/main/java/io/fabric8/kubernetes/client/jdkhttp/JdkHttpClientImpl.java @@ -59,7 +59,6 @@ /** * TODO: * - Mapping to a Reader is always UTF-8 - * - determine if write timeout should be implemented */ public class JdkHttpClientImpl extends StandardHttpClient { @@ -258,7 +257,7 @@ public CompletableFuture> consumeBytesDirect(StandardHtt java.net.http.HttpRequest.Builder requestBuilder(StandardHttpRequest request) { java.net.http.HttpRequest.Builder requestBuilder = java.net.http.HttpRequest.newBuilder(); - Duration readTimeout = this.builder.getReadTimeout(); + Duration readTimeout = request.getReadTimeout(); if (readTimeout != null && !java.time.Duration.ZERO.equals(readTimeout)) { requestBuilder.timeout(readTimeout); } @@ -311,9 +310,7 @@ public CompletableFuture buildWebSocketDirect( if (standardWebSocketBuilder.getSubprotocol() != null) { newBuilder.subprotocols(standardWebSocketBuilder.getSubprotocol()); } - // the Watch logic sets a websocketTimeout as the readTimeout - // TODO: this should probably be made clearer in the docs - Duration readTimeout = this.builder.getReadTimeout(); + Duration readTimeout = request.getReadTimeout(); if (readTimeout != null && !java.time.Duration.ZERO.equals(readTimeout)) { newBuilder.connectTimeout(readTimeout); } diff --git a/httpclient-jdk/src/test/java/io/fabric8/kubernetes/client/jdkhttp/JdkHttpClientBuilderTest.java b/httpclient-jdk/src/test/java/io/fabric8/kubernetes/client/jdkhttp/JdkHttpClientBuilderTest.java index e2bacc73635..c5991b34573 100644 --- a/httpclient-jdk/src/test/java/io/fabric8/kubernetes/client/jdkhttp/JdkHttpClientBuilderTest.java +++ b/httpclient-jdk/src/test/java/io/fabric8/kubernetes/client/jdkhttp/JdkHttpClientBuilderTest.java @@ -30,10 +30,7 @@ void testZeroTimeouts() { JdkHttpClientBuilderImpl builder = factory.newBuilder(); // should build and be usable without an issue - try (HttpClient client = builder.readTimeout(0, TimeUnit.MILLISECONDS).connectTimeout(0, TimeUnit.MILLISECONDS) - .writeTimeout(0, - TimeUnit.MILLISECONDS) - .build();) { + try (HttpClient client = builder.connectTimeout(0, TimeUnit.MILLISECONDS).build();) { assertNotNull(client.newHttpRequestBuilder().uri("http://localhost").build()); } } diff --git a/httpclient-jetty/src/main/java/io/fabric8/kubernetes/client/jetty/JettyHttpClient.java b/httpclient-jetty/src/main/java/io/fabric8/kubernetes/client/jetty/JettyHttpClient.java index 09385856043..bd06edb9e02 100644 --- a/httpclient-jetty/src/main/java/io/fabric8/kubernetes/client/jetty/JettyHttpClient.java +++ b/httpclient-jetty/src/main/java/io/fabric8/kubernetes/client/jetty/JettyHttpClient.java @@ -18,7 +18,6 @@ import io.fabric8.kubernetes.client.KubernetesClientException; import io.fabric8.kubernetes.client.http.AsyncBody; import io.fabric8.kubernetes.client.http.AsyncBody.Consumer; -import io.fabric8.kubernetes.client.http.HttpRequest; import io.fabric8.kubernetes.client.http.HttpResponse; import io.fabric8.kubernetes.client.http.StandardHttpClient; import io.fabric8.kubernetes.client.http.StandardHttpClientBuilder; @@ -100,7 +99,9 @@ private Request newRequest(StandardHttpRequest originalRequest) { final var request = requestBuilder.build(); var jettyRequest = jetty.newRequest(request.uri()).method(request.method()); - jettyRequest.timeout(builder.getReadTimeout().toMillis() + builder.getWriteTimeout().toMillis(), TimeUnit.MILLISECONDS); + if (originalRequest.getReadTimeout() != null) { + jettyRequest.timeout(originalRequest.getReadTimeout().toMillis(), TimeUnit.MILLISECONDS); + } jettyRequest.headers(m -> request.headers().forEach((k, l) -> l.forEach(v -> m.add(k, v)))); final var contentType = Optional.ofNullable(request.getContentType()); @@ -136,14 +137,14 @@ public CompletableFuture buildWebSocketDirect(StandardWebSock Listener listener) { try { jettyWs.start(); - HttpRequest request = standardWebSocketBuilder.asHttpRequest(); + StandardHttpRequest request = standardWebSocketBuilder.asHttpRequest(); final ClientUpgradeRequest cur = new ClientUpgradeRequest(); if (Utils.isNotNullOrEmpty(standardWebSocketBuilder.getSubprotocol())) { cur.setSubProtocols(standardWebSocketBuilder.getSubprotocol()); } cur.setHeaders(request.headers()); - if (builder.getReadTimeout() != null) { - cur.setTimeout(builder.getReadTimeout().toMillis(), TimeUnit.MILLISECONDS); + if (request.getReadTimeout() != null) { + cur.setTimeout(request.getReadTimeout().toMillis(), TimeUnit.MILLISECONDS); } // Extra-future required because we can't Map the UpgradeException to a WebSocketHandshakeException easily final CompletableFuture future = new CompletableFuture<>(); diff --git a/httpclient-jetty/src/main/java/io/fabric8/kubernetes/client/jetty/JettyHttpClientBuilder.java b/httpclient-jetty/src/main/java/io/fabric8/kubernetes/client/jetty/JettyHttpClientBuilder.java index 8daa983bcf9..b14ddd0d155 100644 --- a/httpclient-jetty/src/main/java/io/fabric8/kubernetes/client/jetty/JettyHttpClientBuilder.java +++ b/httpclient-jetty/src/main/java/io/fabric8/kubernetes/client/jetty/JettyHttpClientBuilder.java @@ -105,16 +105,6 @@ protected JettyHttpClientBuilder newInstance(JettyHttpClientFactory clientFactor return new JettyHttpClientBuilder(clientFactory); } - @Override - public Duration getReadTimeout() { - return Optional.ofNullable(readTimeout).orElse(Duration.ZERO); - } - - @Override - public Duration getWriteTimeout() { - return Optional.ofNullable(writeTimeout).orElse(Duration.ZERO); - } - @Override public Duration getConnectTimeout() { return Optional.ofNullable(connectTimeout).orElse(Duration.ZERO); diff --git a/httpclient-jetty/src/test/java/io/fabric8/kubernetes/client/jetty/JettyHttpClientTest.java b/httpclient-jetty/src/test/java/io/fabric8/kubernetes/client/jetty/JettyHttpClientTest.java index 13a5a9b1c85..c21aa98fa39 100644 --- a/httpclient-jetty/src/test/java/io/fabric8/kubernetes/client/jetty/JettyHttpClientTest.java +++ b/httpclient-jetty/src/test/java/io/fabric8/kubernetes/client/jetty/JettyHttpClientTest.java @@ -68,14 +68,12 @@ void newBuilderInstantiatesJettyHttpClientBuilderWithSameSettings() throws Excep final var originalBuilder = new JettyHttpClientBuilder(null); originalBuilder .connectTimeout(1337, TimeUnit.SECONDS) - .readTimeout(1337, TimeUnit.SECONDS) .tlsVersions(TlsVersion.SSL_3_0) .followAllRedirects(); try (var firstClient = new JettyHttpClient( originalBuilder, httpClient, webSocketClient)) { // When - final var result = firstClient.newBuilder() - .readTimeout(313373, TimeUnit.SECONDS); + final var result = firstClient.newBuilder(); // Then assertThat(result) .isNotNull() @@ -90,11 +88,11 @@ void newBuilderInstantiatesJettyHttpClientBuilderWithSameSettings() throws Excep .isEqualTo(method.invoke(originalBuilder)) .isEqualTo(entry.getValue()); } - var readTimeout = StandardHttpClientBuilder.class.getDeclaredField("readTimeout"); - readTimeout.setAccessible(true); - assertThat(readTimeout.get(result)).isEqualTo(Duration.ofSeconds(313373)); - assertThat(readTimeout.get(originalBuilder)).isEqualTo(Duration.ofSeconds(1337)); - readTimeout.setAccessible(false); + var connectTimeout = StandardHttpClientBuilder.class.getDeclaredField("connectTimeout"); + connectTimeout.setAccessible(true); + assertThat(connectTimeout.get(result)).isEqualTo(Duration.ofSeconds(1337)); + assertThat(connectTimeout.get(originalBuilder)).isEqualTo(Duration.ofSeconds(1337)); + connectTimeout.setAccessible(false); } } diff --git a/httpclient-okhttp/src/main/java/io/fabric8/kubernetes/client/okhttp/OkHttpClientBuilderImpl.java b/httpclient-okhttp/src/main/java/io/fabric8/kubernetes/client/okhttp/OkHttpClientBuilderImpl.java index 0186c1f752d..176cdec1229 100644 --- a/httpclient-okhttp/src/main/java/io/fabric8/kubernetes/client/okhttp/OkHttpClientBuilderImpl.java +++ b/httpclient-okhttp/src/main/java/io/fabric8/kubernetes/client/okhttp/OkHttpClientBuilderImpl.java @@ -93,27 +93,16 @@ public OkHttpClientImpl initialBuild(okhttp3.OkHttpClient.Builder builder) { } private OkHttpClientImpl derivedBuild(okhttp3.OkHttpClient.Builder builder) { - if (readTimeout != null) { - builder.readTimeout(this.readTimeout); - } - if (writeTimeout != null) { - builder.writeTimeout(this.writeTimeout); - } if (authenticatorNone) { builder.authenticator(Authenticator.NONE); } - if (forStreaming) { - builder.cache(null); - } OkHttpClient client = builder.build(); - if (this.forStreaming) { - // If we set the HttpLoggingInterceptor's logging level to Body (as it is by default), it does - // not let us stream responses from the server. - for (Interceptor i : client.networkInterceptors()) { - if (i instanceof HttpLoggingInterceptor) { - HttpLoggingInterceptor interceptor = (HttpLoggingInterceptor) i; - interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC); - } + // If we set the HttpLoggingInterceptor's logging level to Body (as it is by default), it does + // not let us stream responses from the server. + for (Interceptor i : client.networkInterceptors()) { + if (i instanceof HttpLoggingInterceptor) { + HttpLoggingInterceptor interceptor = (HttpLoggingInterceptor) i; + interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC); } } diff --git a/httpclient-okhttp/src/main/java/io/fabric8/kubernetes/client/okhttp/OkHttpClientImpl.java b/httpclient-okhttp/src/main/java/io/fabric8/kubernetes/client/okhttp/OkHttpClientImpl.java index 12b9da04bd8..bbf694550ca 100644 --- a/httpclient-okhttp/src/main/java/io/fabric8/kubernetes/client/okhttp/OkHttpClientImpl.java +++ b/httpclient-okhttp/src/main/java/io/fabric8/kubernetes/client/okhttp/OkHttpClientImpl.java @@ -291,10 +291,24 @@ public void close() { } } - private CompletableFuture> sendAsync(HttpRequest request, + private CompletableFuture> sendAsync(StandardHttpRequest request, Function handler) { CompletableFuture> future = new CompletableFuture<>(); - Call call = httpClient.newCall(requestBuilder((StandardHttpRequest) request).build()); + + okhttp3.OkHttpClient.Builder clientBuilder = null; + if (request.getReadTimeout() != null) { + clientBuilder = httpClient.newBuilder(); + clientBuilder.readTimeout(request.getReadTimeout()); + } + if (request.isForStreaming()) { + if (clientBuilder == null) { + clientBuilder = httpClient.newBuilder(); + } + clientBuilder.cache(null); + } + + Call call = Optional.ofNullable(clientBuilder).map(okhttp3.OkHttpClient.Builder::build).orElse(httpClient) + .newCall(requestBuilder(request).build()); try { call.enqueue(new Callback() { diff --git a/httpclient-vertx/src/main/java/io/fabric8/kubernetes/client/vertx/VertxHttpClient.java b/httpclient-vertx/src/main/java/io/fabric8/kubernetes/client/vertx/VertxHttpClient.java index f5f1f03927a..551f12effa1 100644 --- a/httpclient-vertx/src/main/java/io/fabric8/kubernetes/client/vertx/VertxHttpClient.java +++ b/httpclient-vertx/src/main/java/io/fabric8/kubernetes/client/vertx/VertxHttpClient.java @@ -63,16 +63,16 @@ public CompletableFuture buildWebSocketDirect(StandardWebSock WebSocket.Listener listener) { WebSocketConnectOptions options = new WebSocketConnectOptions(); - if (builder.getReadTimeout() != null) { - options.setTimeout(builder.getReadTimeout().toMillis()); - } - if (standardWebSocketBuilder.getSubprotocol() != null) { options.setSubProtocols(Collections.singletonList(standardWebSocketBuilder.getSubprotocol())); } StandardHttpRequest request = standardWebSocketBuilder.asHttpRequest(); + if (request.getReadTimeout() != null) { + options.setTimeout(request.getReadTimeout().toMillis()); + } + request.headers().entrySet().stream() .forEach(e -> e.getValue().stream().forEach(v -> options.addHeader(e.getKey(), v))); options.setAbsoluteURI(request.uri().toString()); @@ -140,6 +140,10 @@ public CompletableFuture> consumeBytesDirect(StandardHtt options.setAbsoluteURI(request.uri().toString()); options.setMethod(HttpMethod.valueOf(request.method())); + if (request.getReadTimeout() != null) { + options.setTimeout(request.getReadTimeout().toMillis()); + } + // Proxy authorization is handled manually since the proxyAuthorization value is the actual header if (proxyAuthorization != null) { options.putHeader(HttpHeaders.PROXY_AUTHORIZATION, proxyAuthorization); diff --git a/httpclient-vertx/src/main/java/io/fabric8/kubernetes/client/vertx/VertxHttpClientBuilder.java b/httpclient-vertx/src/main/java/io/fabric8/kubernetes/client/vertx/VertxHttpClientBuilder.java index eb335fe4a96..fe37665c4a3 100644 --- a/httpclient-vertx/src/main/java/io/fabric8/kubernetes/client/vertx/VertxHttpClientBuilder.java +++ b/httpclient-vertx/src/main/java/io/fabric8/kubernetes/client/vertx/VertxHttpClientBuilder.java @@ -56,10 +56,6 @@ public VertxHttpClient build() { options.setConnectTimeout((int) this.connectTimeout.toMillis()); } - if (this.writeTimeout != null) { - options.setWriteIdleTimeout((int) this.writeTimeout.getSeconds()); - } - if (this.followRedirects) { options.setFollowRedirects(followRedirects); } diff --git a/httpclient-vertx/src/test/java/io/fabric8/kubernetes/client/vertx/VertxHttpClientBuilderTest.java b/httpclient-vertx/src/test/java/io/fabric8/kubernetes/client/vertx/VertxHttpClientBuilderTest.java index 3e212073c24..1662bd1ad90 100644 --- a/httpclient-vertx/src/test/java/io/fabric8/kubernetes/client/vertx/VertxHttpClientBuilderTest.java +++ b/httpclient-vertx/src/test/java/io/fabric8/kubernetes/client/vertx/VertxHttpClientBuilderTest.java @@ -30,10 +30,7 @@ void testZeroTimeouts() { HttpClient.Builder builder = factory.newBuilder(); // should build and be usable without an issue - try (HttpClient client = builder.readTimeout(0, TimeUnit.MILLISECONDS).connectTimeout(0, TimeUnit.MILLISECONDS) - .writeTimeout(0, - TimeUnit.MILLISECONDS) - .build();) { + try (HttpClient client = builder.connectTimeout(0, TimeUnit.MILLISECONDS).build();) { assertNotNull(client.newHttpRequestBuilder().uri("http://localhost").build()); } } 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 f1c3f2889e7..f2be749b7e9 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 @@ -98,7 +98,6 @@ public class Config { public static final String KUBERNETES_REQUEST_RETRY_BACKOFFINTERVAL_SYSTEM_PROPERTY = "kubernetes.request.retry.backoffInterval"; public static final String KUBERNETES_LOGGING_INTERVAL_SYSTEM_PROPERTY = "kubernetes.logging.interval"; public static final String KUBERNETES_SCALE_TIMEOUT_SYSTEM_PROPERTY = "kubernetes.scale.timeout"; - public static final String KUBERNETES_WEBSOCKET_TIMEOUT_SYSTEM_PROPERTY = "kubernetes.websocket.timeout"; public static final String KUBERNETES_WEBSOCKET_PING_INTERVAL_SYSTEM_PROPERTY = "kubernetes.websocket.ping.interval"; public static final String KUBERNETES_MAX_CONCURRENT_REQUESTS = "kubernetes.max.concurrent.requests"; public static final String KUBERNETES_MAX_CONCURRENT_REQUESTS_PER_HOST = "kubernetes.max.concurrent.requests.per.host"; @@ -136,7 +135,6 @@ public class Config { public static final Long DEFAULT_SCALE_TIMEOUT = 10 * 60 * 1000L; public static final int DEFAULT_REQUEST_TIMEOUT = 10 * 1000; public static final int DEFAULT_LOGGING_INTERVAL = 20 * 1000; - public static final Long DEFAULT_WEBSOCKET_TIMEOUT = 5 * 1000L; public static final Long DEFAULT_WEBSOCKET_PING_INTERVAL = 30 * 1000L; public static final Integer DEFAULT_MAX_CONCURRENT_REQUESTS = 64; @@ -197,7 +195,6 @@ public class Config { private int requestTimeout = DEFAULT_REQUEST_TIMEOUT; private long scaleTimeout = DEFAULT_SCALE_TIMEOUT; private int loggingInterval = DEFAULT_LOGGING_INTERVAL; - private long websocketTimeout = DEFAULT_WEBSOCKET_TIMEOUT; private String impersonateUsername; /** @@ -321,14 +318,14 @@ public Config(String masterUrl, String apiVersion, String namespace, boolean tru String oauthToken, int watchReconnectInterval, int watchReconnectLimit, int connectionTimeout, int requestTimeout, long rollingTimeout, long scaleTimeout, int loggingInterval, int maxConcurrentRequests, int maxConcurrentRequestsPerHost, String httpProxy, String httpsProxy, String[] noProxy, Map errorMessages, String userAgent, - TlsVersion[] tlsVersions, long websocketTimeout, long websocketPingInterval, String proxyUsername, String proxyPassword, + TlsVersion[] tlsVersions, long websocketPingInterval, String proxyUsername, String proxyPassword, String trustStoreFile, String trustStorePassphrase, String keyStoreFile, String keyStorePassphrase, String impersonateUsername, String[] impersonateGroups, Map> impersonateExtras) { this(masterUrl, apiVersion, namespace, trustCerts, disableHostnameVerification, caCertFile, caCertData, clientCertFile, clientCertData, clientKeyFile, clientKeyData, clientKeyAlgo, clientKeyPassphrase, username, password, oauthToken, watchReconnectInterval, watchReconnectLimit, connectionTimeout, requestTimeout, scaleTimeout, loggingInterval, maxConcurrentRequests, maxConcurrentRequestsPerHost, false, httpProxy, httpsProxy, noProxy, - errorMessages, userAgent, tlsVersions, websocketTimeout, websocketPingInterval, proxyUsername, proxyPassword, + errorMessages, userAgent, tlsVersions, websocketPingInterval, proxyUsername, proxyPassword, trustStoreFile, trustStorePassphrase, keyStoreFile, keyStorePassphrase, impersonateUsername, impersonateGroups, impersonateExtras, null, null, DEFAULT_REQUEST_RETRY_BACKOFFLIMIT, DEFAULT_REQUEST_RETRY_BACKOFFINTERVAL, DEFAULT_UPLOAD_REQUEST_TIMEOUT); @@ -341,7 +338,7 @@ public Config(String masterUrl, String apiVersion, String namespace, boolean tru String oauthToken, int watchReconnectInterval, int watchReconnectLimit, int connectionTimeout, int requestTimeout, long scaleTimeout, int loggingInterval, int maxConcurrentRequests, int maxConcurrentRequestsPerHost, boolean http2Disable, String httpProxy, String httpsProxy, String[] noProxy, Map errorMessages, - String userAgent, TlsVersion[] tlsVersions, long websocketTimeout, long websocketPingInterval, String proxyUsername, + String userAgent, TlsVersion[] tlsVersions, long websocketPingInterval, String proxyUsername, String proxyPassword, String trustStoreFile, String trustStorePassphrase, String keyStoreFile, String keyStorePassphrase, String impersonateUsername, String[] impersonateGroups, Map> impersonateExtras, OAuthTokenProvider oauthTokenProvider, Map customHeaders, int requestRetryBackoffLimit, @@ -365,7 +362,7 @@ public Config(String masterUrl, String apiVersion, String namespace, boolean tru this.connectionTimeout = connectionTimeout; this.requestConfig = new RequestConfig(watchReconnectLimit, watchReconnectInterval, - requestTimeout, scaleTimeout, loggingInterval, websocketTimeout, + requestTimeout, scaleTimeout, loggingInterval, requestRetryBackoffLimit, requestRetryBackoffInterval, uploadRequestTimeout); this.requestConfig.setImpersonateUsername(impersonateUsername); this.requestConfig.setImpersonateGroups(impersonateGroups); @@ -473,12 +470,6 @@ public static void configFromSysPropsOrEnvVars(Config config) { config.setRequestRetryBackoffInterval(Utils.getSystemPropertyOrEnvVar( KUBERNETES_REQUEST_RETRY_BACKOFFINTERVAL_SYSTEM_PROPERTY, config.getRequestRetryBackoffInterval())); - String configuredWebsocketTimeout = Utils.getSystemPropertyOrEnvVar(KUBERNETES_WEBSOCKET_TIMEOUT_SYSTEM_PROPERTY, - String.valueOf(config.getWebsocketTimeout())); - if (configuredWebsocketTimeout != null) { - config.setWebsocketTimeout(Long.parseLong(configuredWebsocketTimeout)); - } - String configuredWebsocketPingInterval = Utils.getSystemPropertyOrEnvVar(KUBERNETES_WEBSOCKET_PING_INTERVAL_SYSTEM_PROPERTY, String.valueOf(config.getWebsocketPingInterval())); if (configuredWebsocketPingInterval != null) { @@ -1304,15 +1295,6 @@ public void setTlsVersions(TlsVersion[] tlsVersions) { this.tlsVersions = tlsVersions; } - @JsonProperty("websocketTimeout") - public long getWebsocketTimeout() { - return getRequestConfig().getWebsocketTimeout(); - } - - public void setWebsocketTimeout(long websocketTimeout) { - this.requestConfig.setWebsocketTimeout(websocketTimeout); - } - @JsonProperty("websocketPingInterval") public long getWebsocketPingInterval() { return websocketPingInterval; diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/RequestConfig.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/RequestConfig.java index d8ca0b549d3..91eb1a9b9bc 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/RequestConfig.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/RequestConfig.java @@ -29,7 +29,6 @@ import static io.fabric8.kubernetes.client.Config.DEFAULT_REQUEST_TIMEOUT; import static io.fabric8.kubernetes.client.Config.DEFAULT_SCALE_TIMEOUT; import static io.fabric8.kubernetes.client.Config.DEFAULT_UPLOAD_REQUEST_TIMEOUT; -import static io.fabric8.kubernetes.client.Config.DEFAULT_WEBSOCKET_TIMEOUT; public class RequestConfig { @@ -46,20 +45,18 @@ public class RequestConfig { private int requestTimeout = DEFAULT_REQUEST_TIMEOUT; private long scaleTimeout = DEFAULT_SCALE_TIMEOUT; private int loggingInterval = DEFAULT_LOGGING_INTERVAL; - private long websocketTimeout = DEFAULT_WEBSOCKET_TIMEOUT; RequestConfig() { } @Buildable(builderPackage = "io.fabric8.kubernetes.api.builder", editableEnabled = false) public RequestConfig(int watchReconnectLimit, int watchReconnectInterval, int requestTimeout, - long scaleTimeout, int loggingInterval, long websocketTimeout, int requestRetryBackoffLimit, + long scaleTimeout, int loggingInterval, int requestRetryBackoffLimit, int requestRetryBackoffInterval, int uploadRequestTimeout) { this.watchReconnectLimit = watchReconnectLimit; this.watchReconnectInterval = watchReconnectInterval; this.requestTimeout = requestTimeout; this.scaleTimeout = scaleTimeout; - this.websocketTimeout = websocketTimeout; this.loggingInterval = loggingInterval; this.requestRetryBackoffLimit = requestRetryBackoffLimit; this.requestRetryBackoffInterval = requestRetryBackoffInterval; @@ -130,14 +127,6 @@ public void setLoggingInterval(int loggingInterval) { this.loggingInterval = loggingInterval; } - public long getWebsocketTimeout() { - return websocketTimeout; - } - - public void setWebsocketTimeout(long websocketTimeout) { - this.websocketTimeout = websocketTimeout; - } - public void setImpersonateUsername(String impersonateUsername) { this.impersonateUsername = impersonateUsername; } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/Deletable.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/Deletable.java index b1c72b0bd2b..88d1abfa872 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/Deletable.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/Deletable.java @@ -18,8 +18,9 @@ import io.fabric8.kubernetes.api.model.StatusDetails; import java.util.List; +import java.util.concurrent.TimeUnit; -public interface Deletable { +public interface Deletable extends Timeoutable { /** * Deletes the resources at this context and returns the {@link StatusDetails} of resources marked for deletion @@ -32,4 +33,16 @@ public interface Deletable { */ List delete(); + /** + * Perform the delete operation as blocking, waiting for finalizers, for up to the given timeout + */ + @Override + Deletable withTimeout(long timeout, TimeUnit unit); + + /** + * Perform the delete operation as blocking, waiting for finalizers, for up to the given timeout + */ + @Override + Deletable withTimeoutInMillis(long timeoutInMillis); + } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/DeletableWithOptions.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/DeletableWithOptions.java index 3227c322651..c6b3bcf5b8e 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/DeletableWithOptions.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/DeletableWithOptions.java @@ -19,15 +19,7 @@ import io.fabric8.kubernetes.client.GracePeriodConfigurable; import io.fabric8.kubernetes.client.PropagationPolicyConfigurable; -import java.util.concurrent.TimeUnit; - public interface DeletableWithOptions extends GracePeriodConfigurable>, - PropagationPolicyConfigurable>, Timeoutable { - - @Override - DeletableWithOptions withTimeout(long timeout, TimeUnit unit); - - @Override - DeletableWithOptions withTimeoutInMillis(long timeoutInMillis); + PropagationPolicyConfigurable> { } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/Scalable.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/Scalable.java index be7e484d56c..c55877ebfb3 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/Scalable.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/Scalable.java @@ -35,7 +35,9 @@ public interface Scalable { * @param wait if true, wait for the number of instances to exist - no guarantee is made * as to readiness * @return the resource + * @deprecated use {@link TimeoutableScalable} instead */ + @Deprecated T scale(int count, boolean wait); default Scale scale() { diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/ScalableResource.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/ScalableResource.java index 2b320809179..a52865bb09c 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/ScalableResource.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/ScalableResource.java @@ -18,6 +18,6 @@ public interface ScalableResource extends Resource, Loggable, Containerable, - TimestampBytesLimitTerminateTimeTailPrettyLoggable { + TimestampBytesLimitTerminateTimeTailPrettyLoggable, TimeoutableScalable { } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/TimeoutableScalable.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/TimeoutableScalable.java new file mode 100644 index 00000000000..e0f7942c7c2 --- /dev/null +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/TimeoutableScalable.java @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.fabric8.kubernetes.client.dsl; + +import java.util.concurrent.TimeUnit; + +public interface TimeoutableScalable extends Deletable { + + /** + * Scale the resource to given count + * + * @param count the desired instance count + * @return the resource + */ + T scale(int count); + + @Override + TimeoutableScalable withTimeout(long timeout, TimeUnit unit); + + @Override + TimeoutableScalable withTimeoutInMillis(long timeoutInMillis); + +} diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ExtensibleResource.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ExtensibleResource.java index 443a6f17d09..56b95598c93 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ExtensibleResource.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ExtensibleResource.java @@ -18,9 +18,10 @@ import io.fabric8.kubernetes.api.model.DeletionPropagation; import io.fabric8.kubernetes.client.Client; +import io.fabric8.kubernetes.client.KubernetesClientException; import io.fabric8.kubernetes.client.dsl.Nameable; import io.fabric8.kubernetes.client.dsl.Resource; -import io.fabric8.kubernetes.client.dsl.WritableOperation; +import io.fabric8.kubernetes.client.dsl.TimeoutableScalable; import java.util.List; import java.util.Map; @@ -31,7 +32,7 @@ * Provides an interface that is usable by the {@link ExtensibleResourceAdapter} that returns * a non-specialized value */ -public interface ExtensibleResource extends Resource { +public interface ExtensibleResource extends Resource, TimeoutableScalable { @Override ExtensibleResource lockResourceVersion(String resourceVersion); @@ -90,8 +91,13 @@ public interface ExtensibleResource extends Resource { ExtensibleResource withTimeout(long timeout, TimeUnit unit); @Override - default WritableOperation withTimeoutInMillis(long timeoutInMillis) { + default ExtensibleResource withTimeoutInMillis(long timeoutInMillis) { return withTimeout(timeoutInMillis, TimeUnit.MILLISECONDS); } + @Override + default T scale(int count) { + throw new KubernetesClientException("not implemented"); + } + } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ResourceAdapter.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ResourceAdapter.java index 08e7c7860c2..836e241ad84 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ResourceAdapter.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ResourceAdapter.java @@ -27,7 +27,6 @@ import io.fabric8.kubernetes.client.Watch; import io.fabric8.kubernetes.client.Watcher; import io.fabric8.kubernetes.client.dsl.Deletable; -import io.fabric8.kubernetes.client.dsl.DeletableWithOptions; import io.fabric8.kubernetes.client.dsl.Gettable; import io.fabric8.kubernetes.client.dsl.Informable; import io.fabric8.kubernetes.client.dsl.NonDeletingOperation; @@ -332,12 +331,12 @@ public T item() { } @Override - public DeletableWithOptions withTimeout(long timeout, TimeUnit unit) { + public Deletable withTimeout(long timeout, TimeUnit unit) { return resource.withTimeout(timeout, unit); } @Override - public DeletableWithOptions withTimeoutInMillis(long timeoutInMillis) { + public Deletable withTimeoutInMillis(long timeoutInMillis) { return withTimeout(timeoutInMillis, TimeUnit.MILLISECONDS); } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/HttpClient.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/HttpClient.java index 12771abbb55..6f503008099 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/HttpClient.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/HttpClient.java @@ -72,22 +72,6 @@ interface DerivedClientBuilder { HttpClient build(); - /** - * Sets the read timeout for normal http requests. Will also - * be used as the connection timeout for {@link WebSocket}s - */ - DerivedClientBuilder readTimeout(long readTimeout, TimeUnit unit); - - DerivedClientBuilder writeTimeout(long writeTimeout, TimeUnit unit); - - /** - * Sets the HttpClient to be used to perform HTTP requests whose responses - * will be streamed. - * - * @return this Builder instance. - */ - DerivedClientBuilder forStreaming(); - DerivedClientBuilder addOrReplaceInterceptor(String name, Interceptor interceptor); /** @@ -113,26 +97,8 @@ interface Builder extends DerivedClientBuilder { @Override HttpClient build(); - /** - * {@inheritDoc} - */ - @Override - Builder readTimeout(long readTimeout, TimeUnit unit); - - /** - * {@inheritDoc} - */ - @Override - Builder writeTimeout(long writeTimeout, TimeUnit unit); - Builder connectTimeout(long connectTimeout, TimeUnit unit); - /** - * {@inheritDoc} - */ - @Override - Builder forStreaming(); - /** * {@inheritDoc} */ diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/HttpRequest.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/HttpRequest.java index d5bb95d0647..b90eb29fef5 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/HttpRequest.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/HttpRequest.java @@ -23,6 +23,7 @@ import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Map; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; public interface HttpRequest extends HttpHeaders { @@ -88,6 +89,18 @@ default Builder post(Map formData) { Builder expectContinue(); + /** + * Sets the read timeout for normal http requests. + */ + Builder readTimeout(long readTimeout, TimeUnit unit); + + /** + * Sets the request to be used for streaming. + * + * @return this Builder instance. + */ + Builder forStreaming(); + } static String formURLEncode(String value) { diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/StandardHttpClientBuilder.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/StandardHttpClientBuilder.java index 22fefd8427b..06858df29f6 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/StandardHttpClientBuilder.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/StandardHttpClientBuilder.java @@ -36,15 +36,12 @@ public abstract class StandardHttpClientBuilder interceptors = new LinkedHashMap<>(); protected Duration connectTimeout; - protected Duration readTimeout; - protected Duration writeTimeout; protected SSLContext sslContext; protected String proxyAuthorization; protected InetSocketAddress proxyAddress; protected boolean followRedirects; protected boolean preferHttp11; protected TlsVersion[] tlsVersions; - protected boolean forStreaming; protected boolean authenticatorNone; protected C client; protected F clientFactory; @@ -56,30 +53,12 @@ protected StandardHttpClientBuilder(F clientFactory) { this.clientFactory = clientFactory; } - @Override - public T readTimeout(long readTimeout, TimeUnit unit) { - this.readTimeout = Duration.ofNanos(unit.toNanos(readTimeout)); - return (T) this; - } - - @Override - public T writeTimeout(long writeTimeout, TimeUnit unit) { - this.writeTimeout = Duration.ofNanos(unit.toNanos(writeTimeout)); - return (T) this; - } - @Override public T connectTimeout(long connectTimeout, TimeUnit unit) { this.connectTimeout = Duration.ofNanos(unit.toNanos(connectTimeout)); return (T) this; } - @Override - public T forStreaming() { - this.forStreaming = true; - return (T) this; - } - @Override public T addOrReplaceInterceptor(String name, Interceptor interceptor) { if (interceptor == null) { @@ -152,7 +131,6 @@ public DerivedClientBuilder tag(Object value) { public T copy(C client) { T copy = newInstance(clientFactory); copy.connectTimeout = this.connectTimeout; - copy.readTimeout = this.readTimeout; copy.sslContext = this.sslContext; copy.trustManagers = this.trustManagers; copy.keyManagers = this.keyManagers; @@ -163,7 +141,6 @@ public T copy(C client) { copy.preferHttp11 = this.preferHttp11; copy.followRedirects = this.followRedirects; copy.authenticatorNone = this.authenticatorNone; - copy.writeTimeout = this.writeTimeout; copy.client = client; copy.tags = new LinkedHashMap<>(this.tags); return copy; diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/StandardHttpRequest.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/StandardHttpRequest.java index ddf7537c855..0a98ad9c46a 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/StandardHttpRequest.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/StandardHttpRequest.java @@ -21,9 +21,11 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.time.Duration; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.TimeUnit; /** * Standard representation of a request. HttpClient implementations need to handle the special fields, @@ -90,6 +92,8 @@ public long getLength() { private final String bodyString; private final BodyContent body; private final boolean expectContinue; + private final Duration readTimeout; + private final boolean forStreaming; /** * Constructor that provides the public information @@ -100,17 +104,11 @@ public long getLength() { * @param bodyString */ public StandardHttpRequest(Map> headers, URI uri, String method, String bodyString) { - super(headers); - this.uri = uri; - this.method = method; - this.bodyString = bodyString; - expectContinue = false; - this.body = null; - this.contentType = null; + this(headers, uri, method, bodyString, null, false, null, null, false); } StandardHttpRequest(Map> headers, URI uri, String method, String bodyString, - BodyContent body, boolean expectContinue, String contentType) { + BodyContent body, boolean expectContinue, String contentType, Duration readTimeout, boolean forStreaming) { super(headers); this.uri = uri; this.method = method; @@ -118,6 +116,8 @@ public StandardHttpRequest(Map> headers, URI uri, String me this.body = body; this.expectContinue = expectContinue; this.contentType = contentType; + this.readTimeout = readTimeout; + this.forStreaming = forStreaming; } @Override @@ -154,6 +154,14 @@ public Builder newBuilder() { return new Builder(this); } + public boolean isForStreaming() { + return forStreaming; + } + + public Duration getReadTimeout() { + return readTimeout; + } + public static final class Builder extends AbstractBasicBuilder implements HttpRequest.Builder { private String method = "GET"; @@ -161,6 +169,8 @@ public static final class Builder extends AbstractBasicBuilder implemen private String bodyAsString; private boolean expectContinue; private String contentType; + protected Duration readTimeout; + protected boolean forStreaming; public Builder() { } @@ -173,12 +183,26 @@ public Builder(StandardHttpRequest original) { body = original.body; expectContinue = original.expectContinue; contentType = original.contentType; + readTimeout = original.readTimeout; + forStreaming = original.forStreaming; } @Override public StandardHttpRequest build() { - return new StandardHttpRequest( - getHeaders(), Objects.requireNonNull(getUri()), method, bodyAsString, body, expectContinue, contentType); + return new StandardHttpRequest(getHeaders(), Objects.requireNonNull(getUri()), method, bodyAsString, body, expectContinue, + contentType, readTimeout, forStreaming); + } + + @Override + public HttpRequest.Builder readTimeout(long readTimeout, TimeUnit unit) { + this.readTimeout = Duration.ofNanos(unit.toNanos(readTimeout)); + return this; + } + + @Override + public HttpRequest.Builder forStreaming() { + this.forStreaming = true; + return this; } @Override diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/StandardWebSocketBuilder.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/StandardWebSocketBuilder.java index 4be46eba502..618d550a9ee 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/StandardWebSocketBuilder.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/StandardWebSocketBuilder.java @@ -16,11 +16,13 @@ package io.fabric8.kubernetes.client.http; +import io.fabric8.kubernetes.client.http.WebSocket.Builder; import io.fabric8.kubernetes.client.http.WebSocket.Listener; import lombok.Getter; import java.net.URI; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; @Getter public class StandardWebSocketBuilder implements WebSocket.Builder { @@ -75,4 +77,10 @@ public StandardHttpRequest asHttpRequest() { return this.builder.build(); } + @Override + public Builder connectTimeout(long timeout, TimeUnit timeUnit) { + this.builder.readTimeout(timeout, timeUnit); + return this; + } + } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/WebSocket.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/WebSocket.java index bed6a592983..083c605e697 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/WebSocket.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/WebSocket.java @@ -19,6 +19,7 @@ import java.net.URI; import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; public interface WebSocket { @@ -101,6 +102,8 @@ interface Builder extends BasicBuilder { @Override Builder uri(URI uri); + Builder connectTimeout(long timeout, TimeUnit timeUnit); + } /** diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/HttpClientUtils.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/HttpClientUtils.java index e1bf99b8031..47cfa2addeb 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/HttpClientUtils.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/HttpClientUtils.java @@ -209,10 +209,6 @@ public static void applyCommonConfiguration(Config config, HttpClient.Builder bu builder.connectTimeout(config.getConnectionTimeout(), TimeUnit.MILLISECONDS); } - if (config.getRequestTimeout() > 0) { - builder.readTimeout(config.getRequestTimeout(), TimeUnit.MILLISECONDS); - } - if (config.isHttp2Disable()) { builder.preferHttp11(); } diff --git a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/ConfigTest.java b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/ConfigTest.java index ffde9029b01..4967ddde509 100644 --- a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/ConfigTest.java +++ b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/ConfigTest.java @@ -594,7 +594,6 @@ void testEmptyConfig() { assertEquals(10000, emptyConfig.getRequestTimeout()); assertEquals(600000, emptyConfig.getScaleTimeout()); assertEquals(20000, emptyConfig.getLoggingInterval()); - assertEquals(5000, emptyConfig.getWebsocketTimeout()); assertEquals(30000, emptyConfig.getWebsocketPingInterval()); assertEquals(120000, emptyConfig.getUploadRequestTimeout()); assertTrue(emptyConfig.getImpersonateExtras().isEmpty()); diff --git a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/http/AbstractSimultaneousConnectionsTest.java b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/http/AbstractSimultaneousConnectionsTest.java index 7515bbad592..0c6914bbcb4 100644 --- a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/http/AbstractSimultaneousConnectionsTest.java +++ b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/http/AbstractSimultaneousConnectionsTest.java @@ -80,8 +80,7 @@ void prepareServerAndBuilder() throws IOException { httpServer.setExecutor(httpExecutor); httpServer.start(); clientBuilder = getHttpClientFactory().newBuilder() - .connectTimeout(60, TimeUnit.SECONDS) - .readTimeout(60, TimeUnit.SECONDS); + .connectTimeout(60, TimeUnit.SECONDS); } @AfterEach @@ -246,6 +245,7 @@ final long activeConnections() { return connections.stream().filter(Socket::isConnected).filter(s -> !s.isClosed()).count(); } + @Override public final void close() { for (Socket socket : connections) { try { diff --git a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/http/AbstractWebSocketSendTest.java b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/http/AbstractWebSocketSendTest.java index 2f5eaa453ed..9095812ad2d 100644 --- a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/http/AbstractWebSocketSendTest.java +++ b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/http/AbstractWebSocketSendTest.java @@ -63,9 +63,8 @@ void sendEmitsMessageToWebSocketServer() throws Exception { .always(); final BlockingQueue receivedText = new ArrayBlockingQueue<>(1); final WebSocket ws = client - // ensure that both a derived builder and a 0, or no, timeout works - // as that is a common logic path in the client - .newBuilder().readTimeout(0, TimeUnit.SECONDS).build().newWebSocketBuilder() + // ensure that a derived builder works + .newBuilder().build().newWebSocketBuilder() // TODO: JDK HttpClient implementation doesn't work with ws URIs // - Currently we are using an HttpRequest.Builder which is then // mapped to a WebSocket.Builder. We should probably user the WebSocket.Builder diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/AbstractWatchManager.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/AbstractWatchManager.java index d25d66e6cda..ca800ae00e5 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/AbstractWatchManager.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/AbstractWatchManager.java @@ -45,7 +45,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Supplier; import static java.net.HttpURLConnection.HTTP_GONE; @@ -115,7 +114,7 @@ public static class WatchRequestState { AbstractWatchManager( Watcher watcher, BaseOperation baseOperation, ListOptions listOptions, int reconnectLimit, - int reconnectInterval, Supplier clientSupplier) throws MalformedURLException { + int reconnectInterval, HttpClient client) throws MalformedURLException { // prevent the callbacks from happening in the httpclient thread this.watcher = new SerialWatcher<>(watcher, new SerialExecutor(baseOperation.getOperationContext().getExecutor())); this.reconnectLimit = reconnectLimit; @@ -130,7 +129,7 @@ public static class WatchRequestState { this.baseOperation = baseOperation; this.requestUrl = baseOperation.getNamespacedUrl(); this.listOptions = listOptions; - this.client = clientSupplier.get(); + this.client = client; startWatch(); } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/BaseOperation.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/BaseOperation.java index 3f6c9cfc692..c7cf55e705f 100755 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/BaseOperation.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/BaseOperation.java @@ -401,7 +401,7 @@ public L list(Integer limitVal, String continueVal) { public CompletableFuture submitList(ListOptions listOptions) { try { URL fetchListUrl = fetchListUrl(getNamespacedUrl(), defaultListOptions(listOptions, null)); - HttpRequest.Builder requestBuilder = httpClient.newHttpRequestBuilder().url(fetchListUrl); + HttpRequest.Builder requestBuilder = withReadTimeout(httpClient.newHttpRequestBuilder()).url(fetchListUrl); Type refinedType = listType.equals(DefaultKubernetesResourceList.class) ? Serialization.jsonMapper().getTypeFactory().constructParametricType(listType, type) : listType; @@ -629,7 +629,7 @@ public CompletableFuture> submitWatch(ListOptions option watcherToggle, getRequestConfig().getWatchReconnectInterval(), getRequestConfig().getWatchReconnectLimit(), - getRequestConfig().getWebsocketTimeout()); + getRequestConfig().getRequestTimeout()); } catch (MalformedURLException e) { throw KubernetesClientException.launderThrowable(forOperationType(WATCH), e); } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/HasMetadataOperation.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/HasMetadataOperation.java index 8cff5378e81..3e1da40d695 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/HasMetadataOperation.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/HasMetadataOperation.java @@ -25,6 +25,7 @@ import io.fabric8.kubernetes.api.model.autoscaling.v1.ScaleBuilder; import io.fabric8.kubernetes.client.KubernetesClientException; import io.fabric8.kubernetes.client.dsl.Resource; +import io.fabric8.kubernetes.client.dsl.Scalable; import io.fabric8.kubernetes.client.dsl.base.PatchContext; import io.fabric8.kubernetes.client.dsl.base.PatchType; import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil; @@ -280,23 +281,27 @@ public HasMetadataOperation newInstance(OperationContext context) { @Override public T scale(int count) { - return scale(count, false); - } - - @Override - public T scale(int count, boolean wait) { // TODO: this could be a simple patch, rather than an edit // we're also not giving the user the option here of doing this as a locked operation // kubectl does support specifying the resourceVersion scale(new ScaleBuilder(scale()).editOrNewMetadata().withResourceVersion(null).endMetadata().editOrNewSpec() .withReplicas(count) .endSpec().build()); - if (wait) { + if (context.getTimeout() > 0) { waitUntilScaled(count); } return get(); } + @Override + public T scale(int count, boolean wait) { + Scalable scalable = this; + if (wait) { + scalable = this.withTimeoutInMillis(getRequestConfig().getScaleTimeout()); + } + return scalable.scale(count); + } + @Override public Scale scale(Scale scaleParam) { return handleScale(scaleParam, Scale.class); @@ -326,7 +331,7 @@ protected void waitUntilScaled(final Integer count) { } }, 0, () -> 1, TimeUnit.SECONDS); - if (!Utils.waitUntilReady(completion, getRequestConfig().getScaleTimeout(), TimeUnit.MILLISECONDS)) { + if (!Utils.waitUntilReady(completion, this.context.getTimeout(), this.context.getTimeoutUnit())) { completion.complete(null); throw new KubernetesClientException( String.format("%s/%s pod(s) ready for %s: %s in namespace: %s after waiting for %s seconds so giving up", diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/LogWatchCallback.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/LogWatchCallback.java index aa108fefd6b..98c84cba4b1 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/LogWatchCallback.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/LogWatchCallback.java @@ -33,7 +33,6 @@ import java.nio.channels.WritableByteChannel; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; public class LogWatchCallback implements LogWatch, AutoCloseable { @@ -71,11 +70,10 @@ private void cleanUp() { public LogWatchCallback callAndWait(HttpClient client, URL url) { HttpRequest request = client.newHttpRequestBuilder().url(url).build(); - HttpClient clone = client.newBuilder().readTimeout(0, TimeUnit.MILLISECONDS).build(); if (out == null) { // we can pass the input stream directly to the consumer - clone.sendAsync(request, InputStream.class).whenComplete((r, e) -> { + client.sendAsync(request, InputStream.class).whenComplete((r, e) -> { if (e != null) { onFailure(e); } @@ -86,7 +84,7 @@ public LogWatchCallback callAndWait(HttpClient client, URL url) { } else { // we need to write the bytes to the given output // we don't know if the write will be blocking, so hand it off to another thread - clone.consumeBytes(request, (buffers, a) -> CompletableFuture.runAsync(() -> { + client.consumeBytes(request, (buffers, a) -> CompletableFuture.runAsync(() -> { for (ByteBuffer byteBuffer : buffers) { try { outChannel.write(byteBuffer); diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/OperationSupport.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/OperationSupport.java index 251940af8dc..b6e641c89c1 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/OperationSupport.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/OperationSupport.java @@ -504,13 +504,17 @@ protected T handleApproveOrDeny(T csr, Class type) th * NOTE: Currently does not utilize the retry logic */ protected T handleRawGet(URL resourceUrl, Class type) throws IOException { - HttpRequest.Builder requestBuilder = httpClient.newHttpRequestBuilder().url(resourceUrl); + HttpRequest.Builder requestBuilder = withReadTimeout(httpClient.newHttpRequestBuilder()).url(resourceUrl); HttpRequest request = requestBuilder.build(); HttpResponse response = waitForResult(httpClient.sendAsync(request, type)); assertResponseCode(request, response); return response.body(); } + HttpRequest.Builder withReadTimeout(HttpRequest.Builder builder) { + return builder.readTimeout(getRequestConfig().getRequestTimeout(), TimeUnit.MILLISECONDS); + } + /** * Waits for the provided {@link CompletableFuture} to complete and returns the result in case of success. * @@ -562,7 +566,7 @@ protected T waitForResult(CompletableFuture future) throws IOException { * @throws IOException IOException */ protected T handleResponse(HttpRequest.Builder requestBuilder, Class type) throws IOException { - return waitForResult(handleResponse(httpClient, requestBuilder, new TypeReference() { + return waitForResult(handleResponse(httpClient, withReadTimeout(requestBuilder), new TypeReference() { @Override public Type getType() { return type; diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/PortForwarder.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/PortForwarder.java deleted file mode 100644 index ab8aac58a73..00000000000 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/PortForwarder.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (C) 2015 Red Hat, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.fabric8.kubernetes.client.dsl.internal; - -import io.fabric8.kubernetes.client.LocalPortForward; -import io.fabric8.kubernetes.client.PortForward; - -import java.net.InetAddress; -import java.net.URL; -import java.nio.channels.ReadableByteChannel; -import java.nio.channels.WritableByteChannel; - -/** - * Allows to forward local ports (or nio channels) to remote ports in Kubernetes pods. - */ -public interface PortForwarder { - - LocalPortForward forward(URL resourceBaseUrl, int port); - - LocalPortForward forward(URL resourceBaseUrl, int port, int localPort); - - LocalPortForward forward(URL resourceBaseUrl, int port, InetAddress localHost, int localPort); - - PortForward forward(URL resourceBaseUrl, int port, ReadableByteChannel in, WritableByteChannel out); - -} diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/PortForwarderWebsocket.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/PortForwarderWebsocket.java index 72740c98e2b..69d1f604c4c 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/PortForwarderWebsocket.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/PortForwarderWebsocket.java @@ -40,35 +40,27 @@ import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; /** * A port-forwarder using the websocket protocol. * It requires Kubernetes 1.6+ (previous versions support the SPDY protocol only). */ -public class PortForwarderWebsocket implements PortForwarder { +public class PortForwarderWebsocket { private static final Logger LOG = LoggerFactory.getLogger(PortForwarderWebsocket.class); private final HttpClient client; private final Executor executor; + private final long connectTimeoutMills; - public PortForwarderWebsocket(HttpClient client, Executor executor) { + public PortForwarderWebsocket(HttpClient client, Executor executor, long connectTimeoutMillis) { this.client = client; this.executor = executor; + this.connectTimeoutMills = connectTimeoutMillis; } - @Override - public LocalPortForward forward(URL resourceBaseUrl, int port) { - return forward(resourceBaseUrl, port, 0); - } - - @Override - public LocalPortForward forward(URL resourceBaseUrl, int port, int localPort) { - return forward(resourceBaseUrl, port, null, localPort); - } - - @Override public LocalPortForward forward(final URL resourceBaseUrl, final int port, final InetAddress localHost, final int localPort) { try { InetSocketAddress inetSocketAddress = createNewInetSocketAddress(localHost, localPort); @@ -167,12 +159,12 @@ public Collection getServerThrowables() { } } - @Override public PortForward forward(URL resourceBaseUrl, int port, final ReadableByteChannel in, final WritableByteChannel out) { final PortForwarderWebsocketListener listener = new PortForwarderWebsocketListener(in, out, executor); CompletableFuture socket = client .newWebSocketBuilder() .uri(URI.create(URLUtils.join(resourceBaseUrl.toString(), "portforward?ports=" + port))) + .connectTimeout(connectTimeoutMills, TimeUnit.MILLISECONDS) .buildAsync(listener); socket.whenComplete((w, t) -> { diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/WatchConnectionManager.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/WatchConnectionManager.java index 327deaf67e8..62dc917d7d5 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/WatchConnectionManager.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/WatchConnectionManager.java @@ -46,10 +46,9 @@ public class WatchConnectionManager> extends AbstractWatchManager { - public static final int BACKOFF_MAX_EXPONENT = 5; - private static final Logger logger = LoggerFactory.getLogger(WatchConnectionManager.class); + private final long connectTimeoutMillis; protected WatcherWebSocketListener listener; private volatile CompletableFuture websocketFuture; @@ -71,9 +70,8 @@ static void closeWebSocket(WebSocket webSocket) { public WatchConnectionManager(final HttpClient client, final BaseOperation baseOperation, final ListOptions listOptions, final Watcher watcher, final int reconnectInterval, final int reconnectLimit, long websocketTimeout) throws MalformedURLException { - super(watcher, baseOperation, listOptions, reconnectLimit, reconnectInterval, () -> client.newBuilder() - .readTimeout(websocketTimeout, TimeUnit.MILLISECONDS) - .build()); + super(watcher, baseOperation, listOptions, reconnectLimit, reconnectInterval, client); + this.connectTimeoutMillis = websocketTimeout; } @Override @@ -97,7 +95,7 @@ protected void start(URL url, Map headers, WatchRequestState sta this.listener = new WatcherWebSocketListener<>(this, state); Builder builder = client.newWebSocketBuilder(); headers.forEach(builder::header); - builder.uri(URI.create(url.toString())); + builder.uri(URI.create(url.toString())).connectTimeout(connectTimeoutMillis, TimeUnit.MILLISECONDS); this.websocketFuture = builder.buildAsync(this.listener).handle((w, t) -> { if (t != null) { diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/WatchHTTPManager.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/WatchHTTPManager.java index eca91132b19..9f453cca26b 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/WatchHTTPManager.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/WatchHTTPManager.java @@ -33,7 +33,6 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; public class WatchHTTPManager> extends AbstractWatchManager { private static final Logger logger = LoggerFactory.getLogger(WatchHTTPManager.class); @@ -45,17 +44,12 @@ public WatchHTTPManager(final HttpClient client, final ListOptions listOptions, final Watcher watcher, final int reconnectInterval, final int reconnectLimit) throws MalformedURLException { - super( - watcher, baseOperation, listOptions, reconnectLimit, reconnectInterval, - () -> client.newBuilder() - .readTimeout(0, TimeUnit.MILLISECONDS) - .forStreaming() - .build()); + super(watcher, baseOperation, listOptions, reconnectLimit, reconnectInterval, client); } @Override protected synchronized void start(URL url, Map headers, WatchRequestState state) { - HttpRequest.Builder builder = client.newHttpRequestBuilder().url(url); + HttpRequest.Builder builder = client.newHttpRequestBuilder().url(url).forStreaming(); headers.forEach(builder::header); StringBuffer buffer = new StringBuffer(); call = client.consumeBytes(builder.build(), (b, a) -> { diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/core/v1/PodOperationsImpl.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/core/v1/PodOperationsImpl.java index a0866c186bf..def5c1c3be5 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/core/v1/PodOperationsImpl.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/core/v1/PodOperationsImpl.java @@ -54,7 +54,6 @@ import io.fabric8.kubernetes.client.dsl.internal.PodOperationContext.StreamContext; import io.fabric8.kubernetes.client.dsl.internal.PortForwarderWebsocket; import io.fabric8.kubernetes.client.dsl.internal.uploadable.PodUpload; -import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.http.HttpRequest; import io.fabric8.kubernetes.client.http.WebSocket; import io.fabric8.kubernetes.client.lib.FilenameUtils; @@ -201,7 +200,8 @@ public Loggable withLogWaitTimeout(Integer logWaitTimeout) { @Override public PortForward portForward(int port, ReadableByteChannel in, WritableByteChannel out) { try { - return new PortForwarderWebsocket(httpClient, this.context.getExecutor()).forward(getResourceUrl(), port, in, out); + return new PortForwarderWebsocket(httpClient, this.context.getExecutor(), getRequestConfig().getRequestTimeout()) + .forward(getResourceUrl(), port, in, out); } catch (Exception e) { throw KubernetesClientException.launderThrowable(e); } @@ -209,27 +209,19 @@ public PortForward portForward(int port, ReadableByteChannel in, WritableByteCha @Override public LocalPortForward portForward(int port) { - try { - return new PortForwarderWebsocket(httpClient, this.context.getExecutor()).forward(getResourceUrl(), port); - } catch (Exception e) { - throw KubernetesClientException.launderThrowable(e); - } + return portForward(port, 0); } @Override public LocalPortForward portForward(int port, int localPort) { - try { - return new PortForwarderWebsocket(httpClient, this.context.getExecutor()).forward(getResourceUrl(), port, localPort); - } catch (Exception e) { - throw KubernetesClientException.launderThrowable(e); - } + return portForward(port, null, localPort); } @Override public LocalPortForward portForward(int port, InetAddress localInetAddress, int localPort) { try { - return new PortForwarderWebsocket(httpClient, this.context.getExecutor()).forward(getResourceUrl(), port, - localInetAddress, localPort); + return new PortForwarderWebsocket(httpClient, this.context.getExecutor(), getRequestConfig().getRequestTimeout()) + .forward(getResourceUrl(), port, localInetAddress, localPort); } catch (MalformedURLException ex) { throw KubernetesClientException.launderThrowable(ex); } @@ -375,18 +367,18 @@ private boolean hasEphemeralContainer(List containers, Strin } private ExecWebSocketListener setupConnectionToPod(URI uri) { - HttpClient clone = httpClient.newBuilder().readTimeout(0, TimeUnit.MILLISECONDS).build(); ExecWebSocketListener execWebSocketListener = new ExecWebSocketListener(getContext(), this.context.getExecutor()); - CompletableFuture startedFuture = clone.newWebSocketBuilder() + CompletableFuture startedFuture = httpClient.newWebSocketBuilder() .subprotocol("v4.channel.k8s.io") .uri(uri) + .connectTimeout(getRequestConfig().getRequestTimeout(), TimeUnit.MILLISECONDS) .buildAsync(execWebSocketListener); startedFuture.whenComplete((w, t) -> { if (t != null) { execWebSocketListener.onError(w, t); } }); - Utils.waitUntilReadyOrFail(startedFuture, getRequestConfig().getWebsocketTimeout(), TimeUnit.MILLISECONDS); + Utils.waitUntilReadyOrFail(startedFuture, getRequestConfig().getRequestTimeout(), TimeUnit.MILLISECONDS); return execWebSocketListener; } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/osgi/ManagedKubernetesClient.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/osgi/ManagedKubernetesClient.java index 4caf4caeebd..be6427bb5c2 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/osgi/ManagedKubernetesClient.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/osgi/ManagedKubernetesClient.java @@ -60,7 +60,6 @@ import static io.fabric8.kubernetes.client.Config.KUBERNETES_WATCH_RECONNECT_INTERVAL_SYSTEM_PROPERTY; import static io.fabric8.kubernetes.client.Config.KUBERNETES_WATCH_RECONNECT_LIMIT_SYSTEM_PROPERTY; import static io.fabric8.kubernetes.client.Config.KUBERNETES_WEBSOCKET_PING_INTERVAL_SYSTEM_PROPERTY; -import static io.fabric8.kubernetes.client.Config.KUBERNETES_WEBSOCKET_TIMEOUT_SYSTEM_PROPERTY; @Component(configurationPid = "io.fabric8.kubernetes.client", policy = ConfigurationPolicy.REQUIRE) @Service({ KubernetesClient.class, NamespacedKubernetesClient.class }) @@ -143,9 +142,6 @@ public void activate(Map properties) { String noProxyProperty = (String) properties.get(KUBERNETES_NO_PROXY); builder.withNoProxy(noProxyProperty.split(",")); } - if (properties.containsKey(KUBERNETES_WEBSOCKET_TIMEOUT_SYSTEM_PROPERTY)) { - builder.withWebsocketTimeout(Long.parseLong((String) properties.get(KUBERNETES_WEBSOCKET_TIMEOUT_SYSTEM_PROPERTY))); - } if (properties.containsKey(KUBERNETES_WEBSOCKET_PING_INTERVAL_SYSTEM_PROPERTY)) { builder.withWebsocketPingInterval( Long.parseLong((String) properties.get(KUBERNETES_WEBSOCKET_PING_INTERVAL_SYSTEM_PROPERTY))); diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/AbstractWatchManagerTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/AbstractWatchManagerTest.java index 8f1517302d0..c3e6843457a 100644 --- a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/AbstractWatchManagerTest.java +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/AbstractWatchManagerTest.java @@ -251,8 +251,7 @@ private static class WatchManager extends AbstractWatchMa public WatchManager(Watcher watcher, ListOptions listOptions, int reconnectLimit, int reconnectInterval) throws MalformedURLException { - super(watcher, mockOperation(), listOptions, reconnectLimit, reconnectInterval, - () -> null); + super(watcher, mockOperation(), listOptions, reconnectLimit, reconnectInterval, null); } @Override diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/PortForwarderWebsocketTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/PortForwarderWebsocketTest.java index 61862633492..68ff6d339e9 100644 --- a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/PortForwarderWebsocketTest.java +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/PortForwarderWebsocketTest.java @@ -34,7 +34,7 @@ class PortForwarderWebsocketTest { @BeforeEach void initPortForwarderWebsocket() { - this.portForwarderWebsocket = new PortForwarderWebsocket(mockHttpClient, CommonThreadPool.get()); + this.portForwarderWebsocket = new PortForwarderWebsocket(mockHttpClient, CommonThreadPool.get(), 0); } @Test diff --git a/openshift-client-api/src/main/java/io/fabric8/openshift/client/OpenShiftConfig.java b/openshift-client-api/src/main/java/io/fabric8/openshift/client/OpenShiftConfig.java index bd4daba4d2e..5caf479b72e 100644 --- a/openshift-client-api/src/main/java/io/fabric8/openshift/client/OpenShiftConfig.java +++ b/openshift-client-api/src/main/java/io/fabric8/openshift/client/OpenShiftConfig.java @@ -81,7 +81,6 @@ public OpenShiftConfig(String openShiftUrl, String oapiVersion, String masterUrl int maxConcurrentRequests, int maxConcurrentRequestsPerHost, boolean http2Disable, String httpProxy, String httpsProxy, String[] noProxy, Map errorMessages, String userAgent, TlsVersion[] tlsVersions, - long websocketTimeout, long websocketPingInterval, String proxyUsername, String proxyPassword, String trustStoreFile, String trustStorePassphrase, String keyStoreFile, String keyStorePassphrase, String impersonateUsername, String[] impersonateGroups, Map> impersonateExtras, OAuthTokenProvider oauthTokenProvider, @@ -95,7 +94,7 @@ public OpenShiftConfig(String openShiftUrl, String oapiVersion, String masterUrl watchReconnectInterval, watchReconnectLimit, connectionTimeout, requestTimeout, scaleTimeout, loggingInterval, maxConcurrentRequests, maxConcurrentRequestsPerHost, http2Disable, httpProxy, httpsProxy, noProxy, - errorMessages, userAgent, tlsVersions, websocketTimeout, websocketPingInterval, proxyUsername, proxyPassword, + errorMessages, userAgent, tlsVersions, websocketPingInterval, proxyUsername, proxyPassword, trustStoreFile, trustStorePassphrase, keyStoreFile, keyStorePassphrase, impersonateUsername, impersonateGroups, impersonateExtras, oauthTokenProvider, customHeaders, requestRetryBackoffLimit, requestRetryBackoffInterval, uploadRequestTimeout); @@ -129,7 +128,7 @@ public OpenShiftConfig(Config kubernetesConfig, String openShiftUrl, String oapi kubernetesConfig.getMaxConcurrentRequestsPerHost(), kubernetesConfig.isHttp2Disable(), kubernetesConfig.getHttpProxy(), kubernetesConfig.getHttpsProxy(), kubernetesConfig.getNoProxy(), kubernetesConfig.getErrorMessages(), kubernetesConfig.getUserAgent(), - kubernetesConfig.getTlsVersions(), kubernetesConfig.getWebsocketTimeout(), + kubernetesConfig.getTlsVersions(), kubernetesConfig.getWebsocketPingInterval(), kubernetesConfig.getProxyUsername(), kubernetesConfig.getProxyPassword(), kubernetesConfig.getTrustStoreFile(), kubernetesConfig.getTrustStorePassphrase(), kubernetesConfig.getKeyStoreFile(), diff --git a/openshift-client/src/main/java/io/fabric8/openshift/client/dsl/internal/build/BuildConfigOperationsImpl.java b/openshift-client/src/main/java/io/fabric8/openshift/client/dsl/internal/build/BuildConfigOperationsImpl.java index 18cb47873fe..67a4828121a 100644 --- a/openshift-client/src/main/java/io/fabric8/openshift/client/dsl/internal/build/BuildConfigOperationsImpl.java +++ b/openshift-client/src/main/java/io/fabric8/openshift/client/dsl/internal/build/BuildConfigOperationsImpl.java @@ -27,7 +27,6 @@ import io.fabric8.kubernetes.client.dsl.internal.HasMetadataOperationsImpl; import io.fabric8.kubernetes.client.dsl.internal.OperationContext; import io.fabric8.kubernetes.client.dsl.internal.OperationSupport; -import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.http.HttpRequest; import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil; import io.fabric8.kubernetes.client.utils.URLUtils; @@ -260,15 +259,12 @@ public Typeable> withSecret(String secret) { protected Build submitToApiServer(InputStream inputStream, long contentLength) { try { - HttpClient newClient = this.httpClient.newBuilder() - .readTimeout(getOperationContext().getTimeout(), getOperationContext().getTimeoutUnit()) - .writeTimeout(getOperationContext().getTimeout(), getOperationContext().getTimeoutUnit()) - .build(); HttpRequest.Builder requestBuilder = this.httpClient.newHttpRequestBuilder() .post("application/octet-stream", inputStream, contentLength) .expectContinue() + .readTimeout(getOperationContext().getTimeout(), getOperationContext().getTimeoutUnit()) .uri(getQueryParameters()); - return waitForResult(handleResponse(newClient, requestBuilder, new TypeReference() { + return waitForResult(handleResponse(this.httpClient, requestBuilder, new TypeReference() { @Override public Type getType() { return Build.class; diff --git a/openshift-client/src/main/java/io/fabric8/openshift/client/impl/OpenShiftClientImpl.java b/openshift-client/src/main/java/io/fabric8/openshift/client/impl/OpenShiftClientImpl.java index 347e3d99915..97d66fc7c15 100644 --- a/openshift-client/src/main/java/io/fabric8/openshift/client/impl/OpenShiftClientImpl.java +++ b/openshift-client/src/main/java/io/fabric8/openshift/client/impl/OpenShiftClientImpl.java @@ -26,6 +26,7 @@ import io.fabric8.kubernetes.client.VersionInfo; import io.fabric8.kubernetes.client.WithRequestCallable; import io.fabric8.kubernetes.client.dsl.CreateOrDeleteable; +import io.fabric8.kubernetes.client.dsl.Deletable; import io.fabric8.kubernetes.client.dsl.FunctionCallable; import io.fabric8.kubernetes.client.dsl.Gettable; import io.fabric8.kubernetes.client.dsl.InOutCreateable; @@ -173,6 +174,7 @@ import java.text.ParseException; import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; import java.util.function.Supplier; /** @@ -182,6 +184,42 @@ public class OpenShiftClientImpl extends KubernetesClientImpl implements NamespacedOpenShiftClient { + private static final class NameableCreateOrDeleteableImpl implements NameableCreateOrDeleteable { + private final HasMetadataOperation> nameable; + private final Resource operation; + + private NameableCreateOrDeleteableImpl(HasMetadataOperation> nameable, + Resource operation) { + this.nameable = nameable; + this.operation = operation; + } + + @Override + public List delete() { + return operation.delete(); + } + + @Override + public ImageSignature create(ImageSignature item) { + return operation.create(item); + } + + @Override + public CreateOrDeleteable withName(String name) { + return new NameableCreateOrDeleteableImpl(nameable, nameable.withName(name)); + } + + @Override + public Deletable withTimeout(long timeout, TimeUnit unit) { + return operation.withTimeout(timeout, unit); + } + + @Override + public Deletable withTimeoutInMillis(long timeoutInMillis) { + return operation.withTimeoutInMillis(timeoutInMillis); + } + } + public static final String OPENSHIFT_VERSION_ENDPOINT = "version/openshift"; private URL openShiftUrl; @@ -331,35 +369,7 @@ public Namespaceable>> imageStream public NameableCreateOrDeleteable imageSignatures() { HasMetadataOperation> operation = getHandlers() .getNonListingOperation(ImageSignature.class, this); - return new NameableCreateOrDeleteable() { - - @Override - public List delete() { - return operation.delete(); - } - - @Override - public ImageSignature create(ImageSignature item) { - return operation.create(item); - } - - @Override - public CreateOrDeleteable withName(String name) { - return new CreateOrDeleteable() { - - @Override - public ImageSignature create(ImageSignature item) { - return operation.withName(name).create(item); - } - - @Override - public List delete() { - return operation.withName(name).delete(); - } - - }; - } - }; + return new NameableCreateOrDeleteableImpl(operation, operation); } @Override diff --git a/openshift-client/src/main/java/io/fabric8/openshift/client/osgi/ManagedOpenShiftClient.java b/openshift-client/src/main/java/io/fabric8/openshift/client/osgi/ManagedOpenShiftClient.java index 691aaa1ce82..06c85fde1e1 100644 --- a/openshift-client/src/main/java/io/fabric8/openshift/client/osgi/ManagedOpenShiftClient.java +++ b/openshift-client/src/main/java/io/fabric8/openshift/client/osgi/ManagedOpenShiftClient.java @@ -51,7 +51,6 @@ import static io.fabric8.kubernetes.client.Config.KUBERNETES_WATCH_RECONNECT_INTERVAL_SYSTEM_PROPERTY; import static io.fabric8.kubernetes.client.Config.KUBERNETES_WATCH_RECONNECT_LIMIT_SYSTEM_PROPERTY; import static io.fabric8.kubernetes.client.Config.KUBERNETES_WEBSOCKET_PING_INTERVAL_SYSTEM_PROPERTY; -import static io.fabric8.kubernetes.client.Config.KUBERNETES_WEBSOCKET_TIMEOUT_SYSTEM_PROPERTY; import static io.fabric8.openshift.client.OpenShiftConfig.DEFAULT_BUILD_TIMEOUT; import static io.fabric8.openshift.client.OpenShiftConfig.OPENSHIFT_BUILD_TIMEOUT_SYSTEM_PROPERTY; import static io.fabric8.openshift.client.OpenShiftConfig.OPENSHIFT_URL_SYSTEM_PROPERTY; @@ -137,9 +136,6 @@ public void activate(Map properties) { } else { builder.withBuildTimeout(DEFAULT_BUILD_TIMEOUT); } - if (properties.containsKey(KUBERNETES_WEBSOCKET_TIMEOUT_SYSTEM_PROPERTY)) { - builder.withWebsocketTimeout(Long.parseLong((String) properties.get(KUBERNETES_WEBSOCKET_TIMEOUT_SYSTEM_PROPERTY))); - } if (properties.containsKey(KUBERNETES_WEBSOCKET_PING_INTERVAL_SYSTEM_PROPERTY)) { builder.withWebsocketPingInterval( Long.parseLong((String) properties.get(KUBERNETES_WEBSOCKET_PING_INTERVAL_SYSTEM_PROPERTY))); diff --git a/openshift-client/src/test/java/io/fabric8/openshift/client/dsl/internal/build/BuildConfigOperationsImplTest.java b/openshift-client/src/test/java/io/fabric8/openshift/client/dsl/internal/build/BuildConfigOperationsImplTest.java index 6a38bafb298..be9a2fc1a03 100644 --- a/openshift-client/src/test/java/io/fabric8/openshift/client/dsl/internal/build/BuildConfigOperationsImplTest.java +++ b/openshift-client/src/test/java/io/fabric8/openshift/client/dsl/internal/build/BuildConfigOperationsImplTest.java @@ -55,12 +55,11 @@ public void setUp() { when(response.uri()).thenReturn(URI.create("https://localhost:8443/")); when(httpClient.newBuilder() - .readTimeout(anyLong(), any()) - .writeTimeout(anyLong(), any()) .build()).thenReturn(httpClient); when(httpClient.newHttpRequestBuilder() .post(any(), any(), anyLong()) .header(any(), any()) + .readTimeout(anyLong(), any()) .uri(any(String.class)) .build()).thenReturn(response);