values = e.getValue();
+ for (String value : values) {
+ headersBuilder.add(name, value);
+ }
+ }
+ }
+
+ return headersBuilder.build();
+ }
+
+ private static final class InputStreamBasedRequestBody extends RequestBody {
+ private final InputStream inputStream;
+ private final MediaType mediaType;
+
+ private InputStreamBasedRequestBody(InputStream is, String contentType) {
+ this.inputStream = is;
+ this.mediaType = contentType == null ? null : MediaType.parse(contentType);
+ }
+
+ @Override
+ public MediaType contentType() {
+ return mediaType;
+ }
+
+ @Override
+ public void writeTo(BufferedSink sink) throws IOException {
+ byte[] buffer = new byte[1024];
+ int cnt;
+ while ((cnt = inputStream.read(buffer)) != -1) {
+ sink.write(buffer, 0, cnt);
+ }
+ }
+ }
+}
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesClientFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesClientFactory.java
index 7b9d022b7f..d07cba726f 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesClientFactory.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesClientFactory.java
@@ -45,7 +45,7 @@ import org.eclipse.che.commons.annotation.Nullable;
public class KubernetesClientFactory {
/** {@link OkHttpClient} instance shared by all Kubernetes clients. */
- private OkHttpClient httpClient;
+ private final OkHttpClient httpClient;
/**
* Default Kubernetes {@link Config} that will be the base configuration to create per-workspace
@@ -129,11 +129,28 @@ public class KubernetesClientFactory {
return httpClient;
}
+ /**
+ * Unlike {@link #getHttpClient()} method, this method always returns an HTTP client that contains
+ * interceptors that augment the request with authentication information available in the global
+ * context.
+ *
+ * Unlike {@link #getHttpClient()}, this method creates a new HTTP client instance each time it
+ * is called.
+ *
+ * @return HTTP client with authorization set up
+ * @throws InfrastructureException if it is not possible to build the client with authentication
+ * infromation
+ */
+ public OkHttpClient getAuthenticatedHttpClient() throws InfrastructureException {
+ throw new InfrastructureException(
+ "Impersonating the current user is not supported in the Kubernetes Client.");
+ }
+
/**
* Retrieves the default Kubernetes {@link Config} that will be the base configuration to create
* per-workspace configurations.
*/
- protected Config getDefaultConfig() {
+ public Config getDefaultConfig() {
return defaultConfig;
}
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfrastructure.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfrastructure.java
index e488198631..5ccdc298e2 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfrastructure.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfrastructure.java
@@ -14,9 +14,13 @@ package org.eclipse.che.workspace.infrastructure.kubernetes;
import static java.lang.String.format;
import com.google.common.collect.ImmutableSet;
+import java.io.InputStream;
+import java.net.URI;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.workspace.server.NoEnvironmentFactory.NoEnvInternalEnvironment;
@@ -27,6 +31,7 @@ import org.eclipse.che.api.workspace.server.spi.RuntimeInfrastructure;
import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironment;
import org.eclipse.che.api.workspace.server.spi.provision.InternalEnvironmentProvisioner;
import org.eclipse.che.api.workspace.shared.Constants;
+import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesRuntimeStateCache;
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory;
@@ -41,6 +46,7 @@ public class KubernetesInfrastructure extends RuntimeInfrastructure {
private final KubernetesRuntimeContextFactory runtimeContextFactory;
private final KubernetesRuntimeStateCache runtimeStatusesCache;
private final KubernetesNamespaceFactory namespaceFactory;
+ private final KubernetesClientFactory kubernetesClientFactory;
@Inject
public KubernetesInfrastructure(
@@ -48,7 +54,8 @@ public class KubernetesInfrastructure extends RuntimeInfrastructure {
KubernetesRuntimeContextFactory runtimeContextFactory,
Set internalEnvProvisioners,
KubernetesRuntimeStateCache runtimeStatusesCache,
- KubernetesNamespaceFactory namespaceFactory) {
+ KubernetesNamespaceFactory namespaceFactory,
+ KubernetesClientFactory kubernetesClientFactory) {
super(
NAME,
ImmutableSet.of(KubernetesEnvironment.TYPE, Constants.NO_ENVIRONMENT_RECIPE_TYPE),
@@ -57,6 +64,7 @@ public class KubernetesInfrastructure extends RuntimeInfrastructure {
this.runtimeContextFactory = runtimeContextFactory;
this.runtimeStatusesCache = runtimeStatusesCache;
this.namespaceFactory = namespaceFactory;
+ this.kubernetesClientFactory = kubernetesClientFactory;
}
@Override
@@ -81,6 +89,19 @@ public class KubernetesInfrastructure extends RuntimeInfrastructure {
return NamespaceNameValidator.isValid(name);
}
+ @Override
+ public Response sendDirectInfrastructureRequest(
+ String httpMethod, URI relativeUri, @Nullable HttpHeaders headers, @Nullable InputStream body)
+ throws InfrastructureException {
+ return DirectKubernetesAPIAccessHelper.call(
+ kubernetesClientFactory.getDefaultConfig().getMasterUrl(),
+ kubernetesClientFactory.getAuthenticatedHttpClient(),
+ httpMethod,
+ relativeUri,
+ headers,
+ body);
+ }
+
@Override
protected KubernetesRuntimeContext internalPrepare(
RuntimeIdentity id, InternalEnvironment environment) throws InfrastructureException {
diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/DirectKubernetesAPIAccessHelperTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/DirectKubernetesAPIAccessHelperTest.java
new file mode 100644
index 0000000000..c856a87ad8
--- /dev/null
+++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/DirectKubernetesAPIAccessHelperTest.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2012-2018 Red Hat, Inc.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.workspace.infrastructure.kubernetes;
+
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MultivaluedHashMap;
+import okhttp3.Call;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Protocol;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+import okio.Buffer;
+import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
+import org.eclipse.che.commons.lang.IoUtil;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.testng.MockitoTestNGListener;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Listeners;
+import org.testng.annotations.Test;
+
+@Listeners(MockitoTestNGListener.class)
+public class DirectKubernetesAPIAccessHelperTest {
+
+ @Mock private OkHttpClient client;
+ @Mock private Call call;
+ @Mock private HttpHeaders headers;
+ ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(Request.class);
+
+ @BeforeMethod
+ public void setup() {
+ when(headers.getRequestHeaders()).thenReturn(new MultivaluedHashMap<>());
+ when(client.newCall(requestCaptor.capture())).thenReturn(call);
+ }
+
+ @Test(expectedExceptions = InfrastructureException.class)
+ public void testFailsOnAbsoluteUrlSuppliedAsRelative() throws Exception {
+ DirectKubernetesAPIAccessHelper.call(
+ "https://master/", client, "GET", URI.create("https://not-this-way"), headers, null);
+ }
+
+ @Test(expectedExceptions = InfrastructureException.class)
+ public void testFailsOnOpaqueUrlSuppliedAsRelative() throws Exception {
+ DirectKubernetesAPIAccessHelper.call(
+ "https://master/", client, "GET", URI.create("opaque:not-this-way"), headers, null);
+ }
+
+ @Test
+ public void testSendsDataAsApplicationJsonUtf8IfNotSpecifiedInRequest() throws Exception {
+ // given
+ setupResponse(new Response.Builder().code(200));
+
+ // when
+ DirectKubernetesAPIAccessHelper.call(
+ "https://master/",
+ client,
+ "POST",
+ URI.create("somewhere/over/the/rainbow"),
+ headers,
+ new ByteArrayInputStream(
+ "Žluťoučký kůň úpěl ďábelské ódy.".getBytes(StandardCharsets.UTF_8)));
+
+ // then
+ assertEquals(
+ requestCaptor.getValue().body().contentType(),
+ MediaType.get("application/json;charset=UTF-8"));
+
+ Buffer expectedBody = new Buffer();
+ expectedBody.write(StandardCharsets.UTF_8.encode("Žluťoučký kůň úpěl ďábelské ódy."));
+
+ Buffer body = new Buffer();
+ requestCaptor.getValue().body().writeTo(body);
+
+ assertEquals(body, expectedBody);
+ }
+
+ @Test
+ public void testSendsRequestHeaders() throws Exception {
+ // given
+ when(headers.getRequestHeaders())
+ .thenReturn(
+ new MultivaluedHashMap<>(
+ ImmutableMap.of(
+ "ducks", "many", "geese", "volumes", "Content-Type", "text/literary")));
+ setupResponse(new Response.Builder().code(200));
+
+ // when
+ javax.ws.rs.core.Response response =
+ DirectKubernetesAPIAccessHelper.call(
+ "https://master/",
+ client,
+ "POST",
+ URI.create("somewhere/over/the/rainbow"),
+ headers,
+ new ByteArrayInputStream("null".getBytes(StandardCharsets.UTF_8)));
+
+ // then
+ assertEquals(requestCaptor.getValue().header("ducks"), "many");
+ assertEquals(requestCaptor.getValue().header("geese"), "volumes");
+ assertEquals(requestCaptor.getValue().header("Content-Type"), "text/literary");
+ }
+
+ @Test
+ public void testBodySentIntact() throws Exception {
+ // given
+ when(headers.getRequestHeaders())
+ .thenReturn(
+ new MultivaluedHashMap<>(
+ ImmutableMap.of(
+ "ducks", "many", "geese", "volumes", "Content-Type", "text/literary")));
+ setupResponse(new Response.Builder().code(200));
+
+ // when
+ javax.ws.rs.core.Response response =
+ DirectKubernetesAPIAccessHelper.call(
+ "https://master/",
+ client,
+ "POST",
+ URI.create("somewhere/over/the/rainbow"),
+ headers,
+ new ByteArrayInputStream(
+ "Žluťoučký kůň úpěl ďábelské ódy.".getBytes(StandardCharsets.UTF_16BE)));
+
+ // then
+ Buffer expectedBody = new Buffer();
+ expectedBody.write(StandardCharsets.UTF_16BE.encode("Žluťoučký kůň úpěl ďábelské ódy."));
+
+ Buffer body = new Buffer();
+ requestCaptor.getValue().body().writeTo(body);
+
+ assertEquals(body, expectedBody);
+ }
+
+ @Test
+ public void testHonorsRequestCharset() throws Exception {
+ // given
+ when(headers.getRequestHeaders())
+ .thenReturn(
+ new MultivaluedHashMap<>(
+ ImmutableMap.of("Content-Type", "text/plain;charset=utf-16be")));
+ when(headers.getMediaType())
+ .thenReturn(javax.ws.rs.core.MediaType.valueOf("text/plain;charset=utf-16be"));
+
+ setupResponse(new Response.Builder().code(200));
+
+ // when
+ DirectKubernetesAPIAccessHelper.call(
+ "https://master/",
+ client,
+ "POST",
+ URI.create("somewhere/over/the/rainbow"),
+ headers,
+ new ByteArrayInputStream(
+ "Žluťoučký kůň úpěl ďábelské ódy.".getBytes(StandardCharsets.UTF_16BE)));
+
+ // then
+ Request req = requestCaptor.getValue();
+
+ assertEquals(req.header("Content-Type"), "text/plain;charset=utf-16be");
+ assertEquals(req.body().contentType(), MediaType.parse("text/plain;charset=utf-16be"));
+
+ Buffer expectedBody = new Buffer();
+ expectedBody.write(StandardCharsets.UTF_16BE.encode("Žluťoučký kůň úpěl ďábelské ódy."));
+
+ Buffer body = new Buffer();
+ req.body().writeTo(body);
+
+ assertEquals(body, expectedBody);
+ }
+
+ @Test
+ public void testResponseContainsHeaders() throws Exception {
+ // given
+ setupResponse(new Response.Builder().code(200).header("header", "value"));
+
+ // when
+ javax.ws.rs.core.Response response =
+ DirectKubernetesAPIAccessHelper.call(
+ "https://master/",
+ client,
+ "POST",
+ URI.create("somewhere/over/the/rainbow"),
+ headers,
+ new ByteArrayInputStream("null".getBytes(StandardCharsets.UTF_8)));
+
+ // then
+ assertEquals(response.getStringHeaders().get("header").get(0), "value");
+ }
+
+ @Test
+ public void testResponseContainsBody() throws Exception {
+ // given
+ setupResponse(
+ new Response.Builder()
+ .code(200)
+ .body(ResponseBody.create(MediaType.get("application/json"), "true")));
+
+ // when
+ javax.ws.rs.core.Response response =
+ DirectKubernetesAPIAccessHelper.call(
+ "https://master/",
+ client,
+ "POST",
+ URI.create("somewhere/over/the/rainbow"),
+ headers,
+ new ByteArrayInputStream("null".getBytes(StandardCharsets.UTF_8)));
+
+ // then
+ assertEquals(
+ response.getMediaType(),
+ javax.ws.rs.core.MediaType.valueOf("application/json; charset=utf-8"));
+ assertEquals(IoUtil.readAndCloseQuietly((InputStream) response.getEntity()), "true");
+ }
+
+ @Test
+ public void testEmptyHeadersHandled() throws Exception {
+ setupResponse(new Response.Builder().code(200));
+
+ // when
+ javax.ws.rs.core.Response response =
+ DirectKubernetesAPIAccessHelper.call(
+ "https://master/", client, "GET", URI.create("somewhere/over/the/rainbow"), null, null);
+
+ // then
+ assertEquals(200, response.getStatus());
+ }
+
+ private void setupResponse(Response.Builder response) throws Exception {
+ when(call.execute())
+ .thenAnswer(
+ inv ->
+ response
+ .request(requestCaptor.getValue())
+ .message("")
+ .protocol(Protocol.HTTP_1_1)
+ .build());
+ }
+}
diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfrastructureTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfrastructureTest.java
new file mode 100644
index 0000000000..84dcac31f4
--- /dev/null
+++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfrastructureTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012-2018 Red Hat, Inc.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.workspace.infrastructure.kubernetes;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import io.fabric8.kubernetes.client.Config;
+import java.net.URI;
+import java.util.Collections;
+import javax.ws.rs.core.HttpHeaders;
+import org.eclipse.che.api.core.notification.EventService;
+import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesRuntimeStateCache;
+import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory;
+import org.mockito.Mock;
+import org.mockito.testng.MockitoTestNGListener;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Listeners;
+import org.testng.annotations.Test;
+
+@Listeners(MockitoTestNGListener.class)
+public class KubernetesInfrastructureTest {
+
+ @Mock private KubernetesClientFactory factory;
+ private KubernetesInfrastructure infra;
+
+ @BeforeMethod
+ public void setup() {
+ infra =
+ new KubernetesInfrastructure(
+ mock(EventService.class),
+ mock(KubernetesRuntimeContextFactory.class),
+ Collections.emptySet(),
+ mock(KubernetesRuntimeStateCache.class),
+ mock(KubernetesNamespaceFactory.class),
+ factory);
+
+ when(factory.getDefaultConfig()).thenReturn(mock(Config.class));
+ }
+
+ @Test
+ public void testUsesAuthenticatedKubernetesClient() throws Exception {
+ // when
+ try {
+ infra.sendDirectInfrastructureRequest(
+ "GET", URI.create("somewhere/over/the/rainbow"), mock(HttpHeaders.class), null);
+ } catch (Exception e) {
+ // we don't care that this fails, because it fails during the execution of the HTTP request
+ // that we intentionally don't set up fully.
+ // it is enough for this test to verify that the code is trying to use the authenticated HTTP
+ // client.
+ }
+
+ // then
+ verify(factory).getAuthenticatedHttpClient();
+ }
+}
diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftClientFactory.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftClientFactory.java
index c086f15952..8918e0954e 100644
--- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftClientFactory.java
+++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftClientFactory.java
@@ -115,6 +115,15 @@ public class OpenShiftClientFactory extends KubernetesClientFactory {
return createOC(buildConfig(getDefaultConfig(), null));
}
+ @Override
+ public OkHttpClient getAuthenticatedHttpClient() throws InfrastructureException {
+ if (!configBuilder.isPersonalized()) {
+ throw new InfrastructureException(
+ "Not able to construct impersonating openshift API client.");
+ }
+ return clientForConfig(buildConfig(getDefaultConfig(), null));
+ }
+
@Override
protected Config buildDefaultConfig(String masterUrl, Boolean doTrustCerts) {
OpenShiftConfigBuilder configBuilder = new OpenShiftConfigBuilder();
@@ -206,18 +215,19 @@ public class OpenShiftClientFactory extends KubernetesClientFactory {
}
private OpenShiftClient createOC(Config config) {
+ return new UnclosableOpenShiftClient(clientForConfig(config), config);
+ }
+
+ private OkHttpClient clientForConfig(Config config) {
OkHttpClient clientHttpClient =
getHttpClient().newBuilder().authenticator(Authenticator.NONE).build();
OkHttpClient.Builder builder = clientHttpClient.newBuilder();
builder.interceptors().clear();
- clientHttpClient =
- builder
- .addInterceptor(
- new OpenShiftOAuthInterceptor(clientHttpClient, OpenShiftConfig.wrap(config)))
- .addInterceptor(new ImpersonatorInterceptor(config))
- .build();
-
- return new UnclosableOpenShiftClient(clientHttpClient, config);
+ return builder
+ .addInterceptor(
+ new OpenShiftOAuthInterceptor(clientHttpClient, OpenShiftConfig.wrap(config)))
+ .addInterceptor(new ImpersonatorInterceptor(config))
+ .build();
}
/** Decorates the {@link DefaultOpenShiftClient} so that it can not be closed from the outside. */
diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructure.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructure.java
index da1fb05314..12a493b5c3 100644
--- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructure.java
+++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructure.java
@@ -15,9 +15,13 @@ import static java.lang.String.format;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
+import java.io.InputStream;
+import java.net.URI;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.workspace.server.NoEnvironmentFactory.NoEnvInternalEnvironment;
@@ -28,6 +32,8 @@ import org.eclipse.che.api.workspace.server.spi.RuntimeInfrastructure;
import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironment;
import org.eclipse.che.api.workspace.server.spi.provision.InternalEnvironmentProvisioner;
import org.eclipse.che.api.workspace.shared.Constants;
+import org.eclipse.che.commons.annotation.Nullable;
+import org.eclipse.che.workspace.infrastructure.kubernetes.DirectKubernetesAPIAccessHelper;
import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesRuntimeStateCache;
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.NamespaceNameValidator;
@@ -43,6 +49,7 @@ public class OpenShiftInfrastructure extends RuntimeInfrastructure {
private final OpenShiftRuntimeContextFactory runtimeContextFactory;
private final KubernetesRuntimeStateCache runtimeStatusesCache;
private final OpenShiftProjectFactory projectFactory;
+ private final OpenShiftClientFactory openShiftClientFactory;
@Inject
public OpenShiftInfrastructure(
@@ -50,7 +57,8 @@ public class OpenShiftInfrastructure extends RuntimeInfrastructure {
OpenShiftRuntimeContextFactory runtimeContextFactory,
Set internalEnvProvisioners,
KubernetesRuntimeStateCache runtimeStatusesCache,
- OpenShiftProjectFactory projectFactory) {
+ OpenShiftProjectFactory projectFactory,
+ OpenShiftClientFactory openShiftClientFactory) {
super(
NAME,
ImmutableSet.of(
@@ -62,6 +70,7 @@ public class OpenShiftInfrastructure extends RuntimeInfrastructure {
this.runtimeContextFactory = runtimeContextFactory;
this.runtimeStatusesCache = runtimeStatusesCache;
this.projectFactory = projectFactory;
+ this.openShiftClientFactory = openShiftClientFactory;
}
@Override
@@ -92,6 +101,19 @@ public class OpenShiftInfrastructure extends RuntimeInfrastructure {
return runtimeContextFactory.create(asOpenShiftEnv(environment), identity, this);
}
+ @Override
+ public Response sendDirectInfrastructureRequest(
+ String httpMethod, URI relativeUri, @Nullable HttpHeaders headers, @Nullable InputStream body)
+ throws InfrastructureException {
+ return DirectKubernetesAPIAccessHelper.call(
+ openShiftClientFactory.getDefaultConfig().getMasterUrl(),
+ openShiftClientFactory.getAuthenticatedHttpClient(),
+ httpMethod,
+ relativeUri,
+ headers,
+ body);
+ }
+
private OpenShiftEnvironment asOpenShiftEnv(InternalEnvironment source)
throws InfrastructureException {
if (source instanceof NoEnvInternalEnvironment) {
diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructureTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructureTest.java
new file mode 100644
index 0000000000..4f8f4ddd4c
--- /dev/null
+++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructureTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012-2018 Red Hat, Inc.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.workspace.infrastructure.openshift;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import io.fabric8.kubernetes.client.Config;
+import java.net.URI;
+import java.util.Collections;
+import javax.ws.rs.core.HttpHeaders;
+import org.eclipse.che.api.core.notification.EventService;
+import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesRuntimeStateCache;
+import org.eclipse.che.workspace.infrastructure.openshift.project.OpenShiftProjectFactory;
+import org.mockito.Mock;
+import org.mockito.testng.MockitoTestNGListener;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Listeners;
+import org.testng.annotations.Test;
+
+@Listeners(MockitoTestNGListener.class)
+public class OpenShiftInfrastructureTest {
+ @Mock private OpenShiftClientFactory factory;
+ private OpenShiftInfrastructure infra;
+
+ @BeforeMethod
+ public void setup() {
+ infra =
+ new OpenShiftInfrastructure(
+ mock(EventService.class),
+ mock(OpenShiftRuntimeContextFactory.class),
+ Collections.emptySet(),
+ mock(KubernetesRuntimeStateCache.class),
+ mock(OpenShiftProjectFactory.class),
+ factory);
+
+ when(factory.getDefaultConfig()).thenReturn(mock(Config.class));
+ }
+
+ @Test
+ public void testUsesAuthenticatedKubernetesClient() throws Exception {
+ // when
+ try {
+ infra.sendDirectInfrastructureRequest(
+ "GET", URI.create("somewhere/over/the/rainbow"), mock(HttpHeaders.class), null);
+ } catch (Exception e) {
+ // we don't care that this fails, because it fails during the execution of the HTTP request
+ // that we intentionally don't set up fully.
+ // it is enough for this test to verify that the code is trying to use the authenticated HTTP
+ // client.
+ }
+
+ // then
+ verify(factory).getAuthenticatedHttpClient();
+ }
+}
diff --git a/pom.xml b/pom.xml
index ad22ea85e0..5423ba96b0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -60,6 +60,7 @@
2.4.0
0.1.54
3.12.6
+ 1.15.0
1.11
1.19
1.3.3
@@ -251,6 +252,11 @@
okhttp
${com.squareup.okhttp3.version}