Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Support single-host mode on the multi-user server #14335

Merged
merged 13 commits into from
Sep 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions assembly/assembly-root-war/src/main/webapp/_app/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,10 +278,8 @@ class Loader {
* @param {string} token
*/
asyncAuthenticate(redirectUrl, token) {
const re = new RegExp(/(https?:\/\/[^\/]+?)(?:$|\/).*/),
// \ / \ /
// scheme host:port
url = redirectUrl.replace(re, "$1" + "/jwt/auth");
redirectUrl = new URL(redirectUrl);
const url = redirectUrl.origin + redirectUrl.pathname.replace("//", "/") + "jwt/auth";
return new Promise((resolve, reject) => {
const request = new XMLHttpRequest();
request.open('GET', url);
Expand All @@ -293,7 +291,7 @@ class Loader {
return;
}
if (request.status !== 204) {
const errorMessage = 'Failed to authenticate: "' + this.getRequestErrorMessage(xhr) + '"';
const errorMessage = 'Failed to authenticate: "' + this.getRequestErrorMessage(request) + '"';
reject(new Error(errorMessage));
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,7 @@ che.server.secure_exposer=default
che.server.secure_exposer.jwtproxy.token.issuer=wsmaster
che.server.secure_exposer.jwtproxy.token.ttl=8800h
che.server.secure_exposer.jwtproxy.auth.loader.path=/_app/loader.html
che.server.secure_exposer.jwtproxy.image=eclipse/che-jwtproxy:latest
metlos marked this conversation as resolved.
Show resolved Hide resolved
che.server.secure_exposer.jwtproxy.image=quay.io/eclipse/che-jwtproxy:dbd0578
che.server.secure_exposer.jwtproxy.memory_limit=128mb


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.CommonPVCStrategy.COMMON_STRATEGY;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.PerWorkspacePVCStrategy.PER_WORKSPACE_STRATEGY;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.UniqueWorkspacePVCStrategy.UNIQUE_STRATEGY;
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.DefaultHostIngressServiceExposureStrategy.DEFAULT_HOST_STRATEGY;
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.MultiHostIngressServiceExposureStrategy.MULTI_HOST_STRATEGY;
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.SingleHostIngressServiceExposureStrategy.SINGLE_HOST_STRATEGY;
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.DefaultHostExternalServiceExposureStrategy.DEFAULT_HOST_STRATEGY;
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.MultiHostExternalServiceExposureStrategy.MULTI_HOST_STRATEGY;
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.SingleHostExternalServiceExposureStrategy.SINGLE_HOST_STRATEGY;

import com.google.inject.AbstractModule;
import com.google.inject.TypeLiteral;
Expand Down Expand Up @@ -60,11 +60,11 @@
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.env.LogsRootEnvVariableProvider;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.server.ServersConverter;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.IngressAnnotationsProvider;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.DefaultHostIngressServiceExposureStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.IngressServiceExposureStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.DefaultHostExternalServiceExposureStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServiceExposureStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.IngressServiceExposureStrategyProvider;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.MultiHostIngressServiceExposureStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.SingleHostIngressServiceExposureStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.MultiHostExternalServiceExposureStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.SingleHostExternalServiceExposureStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.DefaultSecureServersFactory;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactory;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactoryProvider;
Expand Down Expand Up @@ -117,18 +117,18 @@ protected void configure() {
.addBinding()
.to(KubernetesClientTermination.class);

MapBinder<String, IngressServiceExposureStrategy> ingressStrategies =
MapBinder.newMapBinder(binder(), String.class, IngressServiceExposureStrategy.class);
MapBinder<String, ExternalServiceExposureStrategy> ingressStrategies =
MapBinder.newMapBinder(binder(), String.class, ExternalServiceExposureStrategy.class);
ingressStrategies
.addBinding(MULTI_HOST_STRATEGY)
.to(MultiHostIngressServiceExposureStrategy.class);
.to(MultiHostExternalServiceExposureStrategy.class);
ingressStrategies
.addBinding(SINGLE_HOST_STRATEGY)
.to(SingleHostIngressServiceExposureStrategy.class);
.to(SingleHostExternalServiceExposureStrategy.class);
ingressStrategies
.addBinding(DEFAULT_HOST_STRATEGY)
.to(DefaultHostIngressServiceExposureStrategy.class);
bind(IngressServiceExposureStrategy.class)
.to(DefaultHostExternalServiceExposureStrategy.class);
bind(ExternalServiceExposureStrategy.class)
.toProvider(IngressServiceExposureStrategyProvider.class);

bind(ServersConverter.class).to(new TypeLiteral<ServersConverter<KubernetesEnvironment>>() {});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,17 @@
* @author Sergii Leshchenko
* @author Guy Daich
*/
public class DefaultHostIngressServiceExposureStrategy implements IngressServiceExposureStrategy {
public class DefaultHostExternalServiceExposureStrategy implements ExternalServiceExposureStrategy {

public static final String DEFAULT_HOST_STRATEGY = "default-host";

@Override
public String getIngressHost(String serviceName, ServicePort servicePort) {
public String getExternalHost(String serviceName, ServicePort servicePort) {
return null;
}

@Override
public String getIngressPath(String serviceName, ServicePort servicePort) {
public String getExternalPath(String serviceName, ServicePort servicePort) {
return "/" + serviceName + "/" + servicePort.getName();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ public class ExternalServerExposer<T extends KubernetesEnvironment> {
*/
static final String PATH_TRANSFORM_PATH_CATCH = "%s";

private final IngressServiceExposureStrategy strategy;
private final ExternalServiceExposureStrategy strategy;
private final Map<String, String> ingressAnnotations;
private final String pathTransformFmt;

@Inject
public ExternalServerExposer(
IngressServiceExposureStrategy strategy,
ExternalServiceExposureStrategy strategy,
@Named("infra.kubernetes.ingress.annotations") Map<String, String> annotations,
@Nullable @Named("che.infra.kubernetes.ingress.path_transform") String pathTransformFmt) {
this.strategy = strategy;
Expand Down Expand Up @@ -71,7 +71,7 @@ private Ingress generateIngress(
Map<String, ServerConfig> ingressesServers) {

ExternalServerIngressBuilder ingressBuilder = new ExternalServerIngressBuilder();
String host = strategy.getIngressHost(serviceName, servicePort);
String host = strategy.getExternalHost(serviceName, servicePort);
if (host != null) {
ingressBuilder = ingressBuilder.withHost(host);
}
Expand All @@ -80,7 +80,7 @@ private Ingress generateIngress(
.withPath(
String.format(
pathTransformFmt,
ensureEndsWithSlash(strategy.getIngressPath(serviceName, servicePort))))
ensureEndsWithSlash(strategy.getExternalPath(serviceName, servicePort))))
.withName(getIngressName(serviceName, servicePort))
.withMachineName(machineName)
.withServiceName(serviceName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
* Implementations of this strategy are used by the {@link ExternalServerExposer} to compose an
* Ingress rule that exposes the services.
*/
public interface IngressServiceExposureStrategy {
public interface ExternalServiceExposureStrategy {

/** Returns a host that should be used to expose the service */
@Nullable
String getIngressHost(String serviceName, ServicePort servicePort);
String getExternalHost(String serviceName, ServicePort servicePort);

/** Returns the path on which the service should be exposed */
String getIngressPath(String serviceName, ServicePort servicePort);
String getExternalPath(String serviceName, ServicePort servicePort);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@

@Singleton
public class IngressServiceExposureStrategyProvider
implements Provider<IngressServiceExposureStrategy> {
implements Provider<ExternalServiceExposureStrategy> {

static final String STRATEGY_PROPERTY = "che.infra.kubernetes.server_strategy";
public static final String STRATEGY_PROPERTY = "che.infra.kubernetes.server_strategy";

private final IngressServiceExposureStrategy namingStrategy;
private final ExternalServiceExposureStrategy namingStrategy;

@Inject
public IngressServiceExposureStrategyProvider(
@Named(STRATEGY_PROPERTY) String strategy,
Map<String, IngressServiceExposureStrategy> strategies) {
Map<String, ExternalServiceExposureStrategy> strategies) {

namingStrategy = strategies.get(strategy);

Expand All @@ -42,7 +42,7 @@ public IngressServiceExposureStrategyProvider(
}

@Override
public IngressServiceExposureStrategy get() {
public ExternalServiceExposureStrategy get() {
return namingStrategy;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@
* @author Sergii Leshchenko
* @author Guy Daich
*/
public class MultiHostIngressServiceExposureStrategy implements IngressServiceExposureStrategy {
public class MultiHostExternalServiceExposureStrategy implements ExternalServiceExposureStrategy {

public static final String MULTI_HOST_STRATEGY = "multi-host";
private static final String INGRESS_DOMAIN_PROPERTY = "che.infra.kubernetes.ingress.domain";

private final String domain;

@Inject
public MultiHostIngressServiceExposureStrategy(
public MultiHostExternalServiceExposureStrategy(
@Named(INGRESS_DOMAIN_PROPERTY) String domain, @Named(STRATEGY_PROPERTY) String strategy) {
if (Strings.isNullOrEmpty(domain) && MULTI_HOST_STRATEGY.equals(strategy)) {
throw new ConfigurationException(
Expand All @@ -65,12 +65,12 @@ public MultiHostIngressServiceExposureStrategy(
}

@Override
public String getIngressHost(String serviceName, ServicePort servicePort) {
public String getExternalHost(String serviceName, ServicePort servicePort) {
return serviceName + "-" + servicePort.getName() + "." + domain;
}

@Override
public String getIngressPath(String serviceName, ServicePort servicePort) {
public String getExternalPath(String serviceName, ServicePort servicePort) {
return "/";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,23 +42,23 @@
* @author Sergii Leshchenko
* @author Guy Daich
*/
public class SingleHostIngressServiceExposureStrategy implements IngressServiceExposureStrategy {
public class SingleHostExternalServiceExposureStrategy implements ExternalServiceExposureStrategy {

public static final String SINGLE_HOST_STRATEGY = "single-host";
private final String cheHost;

@Inject
public SingleHostIngressServiceExposureStrategy(@Named("che.host") String cheHost) {
public SingleHostExternalServiceExposureStrategy(@Named("che.host") String cheHost) {
this.cheHost = cheHost;
}

@Override
public String getIngressHost(String serviceName, ServicePort servicePort) {
public String getExternalHost(String serviceName, ServicePort servicePort) {
return cheHost;
}

@Override
public String getIngressPath(String serviceName, ServicePort servicePort) {
public String getExternalPath(String serviceName, ServicePort servicePort) {
return "/" + serviceName + "/" + servicePort.getName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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.server.secure.jwtproxy;

import static java.lang.String.format;
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.DefaultHostExternalServiceExposureStrategy.DEFAULT_HOST_STRATEGY;
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.MultiHostExternalServiceExposureStrategy.MULTI_HOST_STRATEGY;
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.SingleHostExternalServiceExposureStrategy.SINGLE_HOST_STRATEGY;

import io.fabric8.kubernetes.api.model.ServicePort;
import java.util.function.BiFunction;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.IngressServiceExposureStrategyProvider;

/**
* The cookie path for the access token cookie is server-strategy dependent. This class represents
* the different strategies for getting the cookie path.
*
* <p>Note that instead of going with full-blown strategy pattern and different implementations of
* some interface and a provider for the currently active strategy (as is done for example with
* {@link
* org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServiceExposureStrategy}),
* this class merely internally uses different functions for different service exposure strategies.
* This is done because the full-blown stragegy pattern implementation felt like over-engineering
* when compared with the simplicity of the functions.
*/
@Singleton
public class CookiePathStrategy {

private final BiFunction<String, ServicePort, String> getCookiePath;

@Inject
public CookiePathStrategy(
@Named(IngressServiceExposureStrategyProvider.STRATEGY_PROPERTY) String serverStrategy) {
switch (serverStrategy) {
case MULTI_HOST_STRATEGY:
getCookiePath = (__, ___) -> "/";
break;
case SINGLE_HOST_STRATEGY:
case DEFAULT_HOST_STRATEGY:
getCookiePath = (serviceName, __) -> serviceName;
break;
default:
throw new IllegalArgumentException(
format("Unsupported server strategy: %s", serverStrategy));
}
}

public String get(String serviceName, ServicePort port) {
return getCookiePath.apply(serviceName, port);
}
}
Loading