Skip to content

Commit

Permalink
converting the interceptor logic to a simplified interface
Browse files Browse the repository at this point in the history
  • Loading branch information
shawkins committed Oct 29, 2021
1 parent 8958cf1 commit 669b451
Show file tree
Hide file tree
Showing 28 changed files with 548 additions and 245 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,8 @@ private void closeForwarder() {
};
CompletableFuture<WebSocket> socket = client
.newWebSocketBuilder()
.buildAsync(URI.create(URLUtils.join(resourceBaseUrl.toString(), "portforward?ports=" + port)), listener);
.uri(URI.create(URLUtils.join(resourceBaseUrl.toString(), "portforward?ports=" + port)))
.buildAsync(listener);

socket.whenComplete((w, t) -> {
if (t != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ protected void run(URL url, Map<String, String> headers) {
this.listener = new WatcherWebSocketListener<>(this);
Builder builder = client.newWebSocketBuilder();
headers.forEach((k, v) -> builder.header(k, v));
CompletableFuture<WebSocket> future = websocketFuture = builder.buildAsync(URI.create(url.toString()), this.listener);
builder.uri(URI.create(url.toString()));
CompletableFuture<WebSocket> future = websocketFuture = builder.buildAsync(this.listener);
this.websocketFuture.whenComplete((w, t) -> {
if (t instanceof WebSocketHandshakeException) {
WebSocketHandshakeException wshe = (WebSocketHandshakeException)t;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,8 @@ public ExecWatch exec(String... command) {
final ExecWebSocketListener execWebSocketListener = new ExecWebSocketListener(in, out, err, errChannel, inPipe, outPipe, errPipe, errChannelPipe, execListener, bufferSize);
CompletableFuture<WebSocket> startedFuture = clone.newWebSocketBuilder()
.header("Sec-WebSocket-Protocol", "v4.channel.k8s.io")
.buildAsync(url.toURI(), execWebSocketListener);
.uri(url.toURI())
.buildAsync(execWebSocketListener);
startedFuture.whenComplete((w, t) -> {
if (t != null) {
execWebSocketListener.onError​(w, t);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ private static PodUploadWebSocketListener initWebSocket(URL url, HttpClient clie
final HttpClient clone = client.newBuilder().readTimeout(0, TimeUnit.MILLISECONDS).build();
CompletableFuture<WebSocket> startedFuture = clone.newWebSocketBuilder()
.header("Sec-WebSocket-Protocol", "v4.channel.k8s.io")
.buildAsync(URI.create(url.toString()), podUploadWebSocketListener);
.uri(URI.create(url.toString()))
.buildAsync(podUploadWebSocketListener);
startedFuture.whenComplete((w, t) -> {
if (t != null) {
podUploadWebSocketListener.onError​(w, t);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* 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.http;

import java.net.URI;

public interface BasicBuilder {

BasicBuilder uri(URI uri);

/**
* Add the key value pair. Will append to an existing key.
* @param k key
* @param v value
* @return the builder
*/
BasicBuilder header(String k, String v);

/**
* Set the key value pair. Will overwrite an existing key.
* @param k key
* @param v value
* @return the builder
*/
BasicBuilder setHeader(String k, String v);

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ public interface Builder {

Builder writeTimeout(long timeout, TimeUnit timeoutUnit);

Builder addOrReplaceInterceptor(String name, Interceptor interceptor);

Builder authenticatorNone();
}

void close();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* 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.http;

import java.util.List;

public interface HttpHeaders {

List<String> headers(String key);

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,19 @@
import java.net.URI;
import java.net.URL;

public interface HttpRequest {
public interface HttpRequest extends HttpHeaders {

public interface Builder {
public interface Builder extends BasicBuilder {

HttpRequest build();

Builder uri(String uri);

// TODO: should be uri
Builder url(URL url);

@Override
Builder uri(URI uri);

Builder put(String contentType, String writeValueAsString);

Expand All @@ -43,13 +46,23 @@ public interface Builder {

Builder patch(String contentType, String patchForUpdate);

@Override
Builder header(String k, String v);


@Override
Builder setHeader(String k, String v);

}

URI uri();

String method();

/**
* Return the body as a string, but only if one of the String valued {@link Builder} methods were used
* otherwise null
* @return the body
*/
String bodyString();

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Optional;

import static java.nio.charset.StandardCharsets.UTF_8;

public interface HttpResponse<T> {
public interface HttpResponse<T> extends HttpHeaders {

default boolean isSuccessful() {
int code = code();
return isSuccessful(code());
}

public static boolean isSuccessful(int code) {
return code >= 200 && code < 300;
}

Expand All @@ -52,5 +56,9 @@ default String bodyString() throws IOException {
}
return IOHelpers.readFully((InputStream)body, UTF_8);
}

HttpRequest request();

public Optional<HttpResponse<T>> previousResponse();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* 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.http;

/**
* TODO: consider if this should return a Future<Boolean> rather
* than be blocking
*/
public interface Interceptor {

/**
* Called before a request to allow for the manipulation of the request
* @param builder
*/
default void before(BasicBuilder builder, HttpHeaders headers) {}

/**
* Called after a websocket failure or by default from a normal request
* @param builder
* @param response
* @return true if the builder should be used to execute a new request
*/
default boolean afterFailure(BasicBuilder builder, HttpResponse<?> response) {
return false;
}

/**
* Called after a non-websocket failure
* @param builder
* @param response
* @return true if the builder should be used to execute a new request
*/
default boolean afterFailure(HttpRequest.Builder builder, HttpResponse<?> response) {
return afterFailure((BasicBuilder)builder, response);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

package io.fabric8.kubernetes.client.http;

/**
* TODO: determine if java names should be used here as well or instead
*/
public enum TlsVersion {
TLS_1_3,
TLS_1_2,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,19 @@ default void onClose(WebSocket webSocket, int code, String reason) {}

}

public interface Builder {
public interface Builder extends BasicBuilder {

CompletableFuture<WebSocket> buildAsync(URI uri, Listener listener);
CompletableFuture<WebSocket> buildAsync(Listener listener);

@Override
Builder header(String name, String value);

@Override
Builder setHeader(String k, String v);

@Override
Builder uri(URI uri);

}

boolean send(ByteBuffer buffer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,23 @@

import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.http.BasicBuilder;
import io.fabric8.kubernetes.client.http.HttpClient.Builder;
import io.fabric8.kubernetes.client.http.HttpHeaders;
import io.fabric8.kubernetes.client.http.Interceptor;
import io.fabric8.kubernetes.client.internal.SSLUtils;
import io.fabric8.kubernetes.client.utils.BackwardsCompatibilityInterceptor;
import io.fabric8.kubernetes.client.utils.ImpersonatorInterceptor;
import io.fabric8.kubernetes.client.utils.IpAddressMatcher;
import io.fabric8.kubernetes.client.utils.TokenRefreshInterceptor;
import io.fabric8.kubernetes.client.utils.Utils;
import okhttp3.*;
import okhttp3.ConnectionSpec;
import okhttp3.Credentials;
import okhttp3.Dispatcher;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.TlsVersion;
import okhttp3.logging.HttpLoggingInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -29,15 +42,15 @@
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -110,8 +123,6 @@ public static io.fabric8.kubernetes.client.http.HttpClient createHttpClient(fina
httpClientBuilder.sslSocketFactory(context.getSocketFactory(), (X509TrustManager) trustManagers[0]);
}

List<Interceptor> interceptors = createApplicableInterceptors(config);
interceptors.forEach(httpClientBuilder::addInterceptor);
Logger reqLogger = LoggerFactory.getLogger(HttpLoggingInterceptor.class);
if (reqLogger.isTraceEnabled()) {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
Expand Down Expand Up @@ -193,7 +204,9 @@ public static io.fabric8.kubernetes.client.http.HttpClient createHttpClient(fina
});
}

return new OkHttpClientImpl(httpClientBuilder.build());
Builder builderWrapper = new OkHttpClientImpl(httpClientBuilder.build()).newBuilder();
createApplicableInterceptors(config).forEach((s, i) -> builderWrapper.addOrReplaceInterceptor(s, i));
return builderWrapper.build();
} catch (Exception e) {
throw KubernetesClientException.launderThrowable(e);
}
Expand Down Expand Up @@ -241,30 +254,34 @@ private static boolean shouldDisableHttp2() {
return System.getProperty("java.version", "").startsWith("1.8");
}

static List<Interceptor> createApplicableInterceptors(Config config) {
List<Interceptor> interceptors = new ArrayList<>();
static Map<String, io.fabric8.kubernetes.client.http.Interceptor> createApplicableInterceptors(Config config) {
Map<String, io.fabric8.kubernetes.client.http.Interceptor> interceptors = new LinkedHashMap<>();
// Header Interceptor
interceptors.add(chain -> {
Request request = chain.request();
if (Utils.isNotNullOrEmpty(config.getUsername()) && Utils.isNotNullOrEmpty(config.getPassword())) {
Request authReq = chain.request().newBuilder().addHeader("Authorization", Credentials.basic(config.getUsername(), config.getPassword())).build();
return chain.proceed(authReq);
} else if (Utils.isNotNullOrEmpty(config.getOauthToken())) {
Request authReq = chain.request().newBuilder().addHeader("Authorization", "Bearer " + config.getOauthToken()).build();
return chain.proceed(authReq);
interceptors.put("HEADER", new Interceptor() {

@Override
public void before(BasicBuilder builder, HttpHeaders headers) {
if (Utils.isNotNullOrEmpty(config.getUsername()) && Utils.isNotNullOrEmpty(config.getPassword())) {
builder.header("Authorization", basicCredentials(config.getUsername(), config.getPassword()));
} else if (Utils.isNotNullOrEmpty(config.getOauthToken())) {
builder.header("Authorization", "Bearer " + config.getOauthToken());
}
}
return chain.proceed(request);
});
// Impersonator Interceptor
interceptors.add(new ImpersonatorInterceptor(config));
interceptors.put("IMPERSONATOR", new ImpersonatorInterceptor(config));
// Token Refresh Interceptor
interceptors.add(new TokenRefreshInterceptor(config));
interceptors.put(TokenRefreshInterceptor.NAME, new TokenRefreshInterceptor(config));
// Backwards Compatibility Interceptor
String shouldDisableBackwardsCompatibilityInterceptor = Utils.getSystemPropertyOrEnvVar(KUBERNETES_BACKWARDS_COMPATIBILITY_INTERCEPTOR_DISABLE, "false");
if (!Boolean.parseBoolean(shouldDisableBackwardsCompatibilityInterceptor)) {
interceptors.add(new BackwardsCompatibilityInterceptor());
interceptors.put("BACKWARDS", new BackwardsCompatibilityInterceptor());
}

return interceptors;
}

public static String basicCredentials(String username, String password) {
return Credentials.basic(username, password);
}
}
Loading

0 comments on commit 669b451

Please sign in to comment.