diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/ServerConfig.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/ServerConfig.java index 3c2f4bea8e6..8b0ee1a715a 100644 --- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/ServerConfig.java +++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/ServerConfig.java @@ -11,6 +11,11 @@ */ package org.eclipse.che.api.core.model.workspace.config; +import static java.lang.String.join; +import static java.util.Collections.emptyList; + +import java.util.Arrays; +import java.util.List; import java.util.Map; import org.eclipse.che.api.core.model.workspace.runtime.Server; import org.eclipse.che.commons.annotation.Nullable; @@ -51,6 +56,12 @@ public interface ServerConfig { */ String SECURE_SERVER_COOKIES_AUTH_ENABLED_ATTRIBUTE = "cookiesAuthEnabled"; + /** + * {@link ServerConfig} and {@link Server} attribute name which sets the server as unique, meaning + * that, if exposed, it has its own endpoint even if it shares the same port with other servers. + */ + String UNIQUE_SERVER_ATTRIBUTE = "unique"; + /** * Port used by server. * @@ -87,4 +98,140 @@ public interface ServerConfig { /** Attributes of the server */ Map getAttributes(); + + /** + * Determines whether the attributes configure the server to be internal. + * + * @param attributes the attributes with additional server configuration + * @see #INTERNAL_SERVER_ATTRIBUTE + */ + static boolean isInternal(Map attributes) { + return AttributesEvaluator.booleanAttr(attributes, INTERNAL_SERVER_ATTRIBUTE, false); + } + + /** + * Sets the "internal" flag in the provided attributes to the provided value. + * + * @param attributes the attributes with the additional server configuration + */ + static void setInternal(Map attributes, boolean value) { + attributes.put(INTERNAL_SERVER_ATTRIBUTE, Boolean.toString(value)); + } + + /** + * Determines whether the attributes configure the server to be secure. + * + * @param attributes the attributes with additional server configuration + * @see #SECURE_SERVER_ATTRIBUTE + */ + static boolean isSecure(Map attributes) { + return AttributesEvaluator.booleanAttr(attributes, SECURE_SERVER_ATTRIBUTE, false); + } + + /** + * Sets the "secure" flag in the provided attributes to the provided value. + * + * @param attributes the attributes with the additional server configuration + */ + static void setSecure(Map attributes, boolean value) { + attributes.put(SECURE_SERVER_ATTRIBUTE, Boolean.toString(value)); + } + + /** + * Determines whether the attributes configure the server to be unique. + * + * @param attributes the attributes with additional server configuration + * @see #UNIQUE_SERVER_ATTRIBUTE + */ + static boolean isUnique(Map attributes) { + return AttributesEvaluator.booleanAttr(attributes, UNIQUE_SERVER_ATTRIBUTE, false); + } + + /** + * Sets the "unique" flag in the provided attributes to the provided value. + * + * @param attributes the attributes with the additional server configuration + */ + static void setUnique(Map attributes, boolean value) { + attributes.put(UNIQUE_SERVER_ATTRIBUTE, Boolean.toString(value)); + } + + /** + * Determines whether the attributes configure the server to be authenticated using JWT cookies. + * + * @param attributes the attributes with additional server configuration + * @see #SECURE_SERVER_COOKIES_AUTH_ENABLED_ATTRIBUTE + */ + static boolean isCookiesAuthEnabled(Map attributes) { + return AttributesEvaluator.booleanAttr( + attributes, SECURE_SERVER_COOKIES_AUTH_ENABLED_ATTRIBUTE, false); + } + + /** + * Sets the "cookiesAuthEnabled" flag in the provided attributes to the provided value. + * + * @param attributes the attributes with the additional server configuration + */ + static void setCookiesAuthEnabled(Map attributes, boolean value) { + attributes.put(SECURE_SERVER_COOKIES_AUTH_ENABLED_ATTRIBUTE, Boolean.toString(value)); + } + + /** + * Finds the unsecured paths configuration in the provided attributes.s + * + * @param attributes the attributes with additional server configuration + * @see #UNSECURED_PATHS_ATTRIBUTE + */ + static List getUnsecuredPaths(Map attributes) { + if (attributes == null) { + return emptyList(); + } + + String paths = attributes.get(UNSECURED_PATHS_ATTRIBUTE); + if (paths == null) { + return emptyList(); + } + + return Arrays.asList(paths.split("\\s*,\\s*")); + } + + static void setUnsecuredPaths(Map attributes, List value) { + attributes.put(UNSECURED_PATHS_ATTRIBUTE, join(",", value)); + } + + default boolean isInternal() { + return isInternal(getAttributes()); + } + + default boolean isSecure() { + return isSecure(getAttributes()); + } + + default boolean isUnique() { + return isUnique(getAttributes()); + } + + default boolean isCookiesAuthEnabled() { + return isCookiesAuthEnabled(getAttributes()); + } + + default List getUnsecuredPaths() { + return getUnsecuredPaths(getAttributes()); + } +} + +// helper class for the default methods in the above interface +class AttributesEvaluator { + static boolean booleanAttr(Map attrs, String name, boolean defaultValue) { + if (attrs == null) { + return defaultValue; + } + + String attr = attrs.get(name); + if (attr == null) { + return defaultValue; + } + + return Boolean.parseBoolean(attr); + } } diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/runtime/Server.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/runtime/Server.java index e759230923d..72f21a3f4cb 100644 --- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/runtime/Server.java +++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/runtime/Server.java @@ -26,6 +26,10 @@ public interface Server { /** @return the status */ ServerStatus getStatus(); - /** Returns attributes of the server with some metadata */ + /** + * Returns attributes of the server with some metadata. You can use static methods on {@link + * org.eclipse.che.api.core.model.workspace.config.ServerConfig} to evaluate attributes in this + * map easily. + */ Map getAttributes(); } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/devfile/DockerimageComponentToWorkspaceApplier.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/devfile/DockerimageComponentToWorkspaceApplier.java index d27dbf81f78..0aadc5d075c 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/devfile/DockerimageComponentToWorkspaceApplier.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/devfile/DockerimageComponentToWorkspaceApplier.java @@ -229,7 +229,7 @@ private ServerConfigImpl toServerConfig(Endpoint endpoint) { String isPublic = attributes.remove(PUBLIC_ENDPOINT_ATTRIBUTE); if ("false".equals(isPublic)) { - attributes.put(ServerConfig.INTERNAL_SERVER_ATTRIBUTE, "true"); + ServerConfig.setInternal(attributes, true); } return new ServerConfigImpl(Integer.toString(endpoint.getPort()), protocol, path, attributes); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/KubernetesServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/KubernetesServerExposer.java index 190605d38c2..cccd0ef27c4 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/KubernetesServerExposer.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/KubernetesServerExposer.java @@ -13,10 +13,10 @@ import static java.lang.Integer.parseInt; import static java.util.stream.Collectors.toMap; -import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.INTERNAL_SERVER_ATTRIBUTE; import static org.eclipse.che.commons.lang.NameGenerator.generate; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_ORIGINAL_NAME_LABEL; +import com.google.common.collect.ImmutableMap; import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.ContainerPort; import io.fabric8.kubernetes.api.model.ContainerPortBuilder; @@ -126,6 +126,41 @@ public KubernetesServerExposer( this.k8sEnv = k8sEnv; } + /** + * A helper method to split the servers to unique sets that should be exposed together. + * + *

The consumer is responsible for doing the actual exposure and is supplied 2 pieces of data. + * The first is the server ID, which is non-null for any unique server from the input set and null + * for any compound set of servers that should be exposed together. The caller is responsible for + * figuring out an appropriate ID in such case. + * + * @param allServers all unique and non-unique servers mixed together + * @param consumer the consumer responsible for handling the split sets of servers + */ + private static void onEachExposableServerSet( + Map allServers, ServerSetExposer consumer) + throws InfrastructureException { + Map nonUniqueServers = new HashMap<>(); + + for (Map.Entry e : allServers.entrySet()) { + String serverId = makeServerNameValidForDns(e.getKey()); + if (e.getValue().isUnique()) { + consumer.expose(serverId, ImmutableMap.of(serverId, e.getValue())); + } else { + nonUniqueServers.put(serverId, e.getValue()); + } + } + + if (!nonUniqueServers.isEmpty()) { + consumer.expose(null, nonUniqueServers); + } + } + + /** Replaces {@code /} with {@code -} in the provided name in an attempt to make it DNS safe. */ + public static String makeServerNameValidForDns(String name) { + return name.replaceAll("/", "-"); + } + /** * Exposes specified servers. * @@ -143,13 +178,13 @@ public void expose(Map servers) throws Infrastru servers.forEach( (key, value) -> { - if ("true".equals(value.getAttributes().get(INTERNAL_SERVER_ATTRIBUTE))) { + if (value.isInternal()) { // Server is internal. It doesn't make sense to make an it secure since // it is available only within workspace servers internalServers.put(key, value); } else { // Server is external. Check if it should be secure or not - if ("true".equals(value.getAttributes().get(ServerConfig.SECURE_SERVER_ATTRIBUTE))) { + if (value.isSecure()) { secureServers.put(key, value); } else { externalServers.put(key, value); @@ -174,15 +209,23 @@ public void expose(Map servers) throws Infrastru // expose service port related external servers if exist Map matchedExternalServers = match(externalServers, servicePort); if (!matchedExternalServers.isEmpty()) { - externalServerExposer.expose( - k8sEnv, machineName, serviceName, servicePort, matchedExternalServers); + onEachExposableServerSet( + matchedExternalServers, + (serverId, srvrs) -> { + externalServerExposer.expose( + k8sEnv, machineName, serviceName, serverId, servicePort, srvrs); + }); } // expose service port related secure servers if exist Map matchedSecureServers = match(secureServers, servicePort); if (!matchedSecureServers.isEmpty()) { - secureServerExposer.expose( - k8sEnv, machineName, serviceName, servicePort, matchedSecureServers); + onEachExposableServerSet( + matchedSecureServers, + (serverId, srvrs) -> { + secureServerExposer.expose( + k8sEnv, machineName, serviceName, serverId, servicePort, matchedSecureServers); + }); } } } @@ -233,4 +276,10 @@ private Collection exposePorts(Collection s } return exposedPorts.values(); } + + @FunctionalInterface + private interface ServerSetExposer { + void expose(String serverId, Map serverSet) + throws InfrastructureException; + } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/PreviewUrlExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/PreviewUrlExposer.java index 1c7fe206694..2cae39b2d5a 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/PreviewUrlExposer.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/PreviewUrlExposer.java @@ -73,12 +73,9 @@ public void expose(T env) throws InternalInfrastructureException { String.format( "Port '%d' in service '%s' not found. This is not expected, please report a bug!", port, foundService.get().getMetadata().getName()))); + String serviceName = foundService.get().getMetadata().getName(); externalServerExposer.expose( - env, - null, - foundService.get().getMetadata().getName(), - servicePort, - Collections.emptyMap()); + env, null, serviceName, serviceName, servicePort, Collections.emptyMap()); } } else { portsToProvision.add(createServicePort(port)); @@ -86,16 +83,19 @@ public void expose(T env) throws InternalInfrastructureException { } if (!portsToProvision.isEmpty()) { + String serverName = generate(SERVER_PREFIX, SERVER_UNIQUE_PART_SIZE) + "-previewUrl"; Service service = - new ServerServiceBuilder() - .withName(generate(SERVER_PREFIX, SERVER_UNIQUE_PART_SIZE) + "-previewUrl") - .withPorts(portsToProvision) - .build(); - env.getServices().put(service.getMetadata().getName(), service); + new ServerServiceBuilder().withName(serverName).withPorts(portsToProvision).build(); + env.getServices().put(serverName, service); portsToProvision.forEach( port -> externalServerExposer.expose( - env, null, service.getMetadata().getName(), port, Collections.emptyMap())); + env, + null, + service.getMetadata().getName(), + service.getMetadata().getName(), + port, + Collections.emptyMap())); } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/DefaultHostExternalServiceExposureStrategy.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/DefaultHostExternalServiceExposureStrategy.java index 62850687d26..76f6e96b595 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/DefaultHostExternalServiceExposureStrategy.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/DefaultHostExternalServiceExposureStrategy.java @@ -11,8 +11,6 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; -import io.fabric8.kubernetes.api.model.ServicePort; - /** * Provides a path-based strategy for exposing service ports outside the cluster using Ingress * Ingresses will be created without an explicit host (defaulting to *). @@ -45,12 +43,12 @@ public class DefaultHostExternalServiceExposureStrategy implements ExternalServi public static final String DEFAULT_HOST_STRATEGY = "default-host"; @Override - public String getExternalHost(String serviceName, ServicePort servicePort) { + public String getExternalHost(String serviceName, String serverName) { return null; } @Override - public String getExternalPath(String serviceName, ServicePort servicePort) { - return "/" + serviceName + "/" + servicePort.getName(); + public String getExternalPath(String serviceName, String serverName) { + return "/" + serviceName + "/" + serverName; } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/ExternalServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/ExternalServerExposer.java index dcad785bbdf..172421146cb 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/ExternalServerExposer.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/ExternalServerExposer.java @@ -19,6 +19,7 @@ import org.eclipse.che.api.core.model.workspace.config.ServerConfig; import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.server.KubernetesServerExposer; import org.eclipse.che.workspace.infrastructure.kubernetes.server.KubernetesServerResolver; public class ExternalServerExposer { @@ -44,34 +45,47 @@ public ExternalServerExposer( } /** - * Exposes service ports on given service externally (outside kubernetes cluster). Each exposed + * Exposes service port on given service externally (outside kubernetes cluster). The exposed * service port is associated with a specific Server configuration. Server configuration should be * encoded in the exposing object's annotations, to be used by {@link KubernetesServerResolver}. * * @param k8sEnv Kubernetes environment * @param machineName machine containing servers * @param serviceName service associated with machine, mapping all machine server ports + * @param serverId non-null for a unique server, null for a compound set of servers that should be + * exposed together. * @param servicePort specific service port to be exposed externally * @param externalServers server configs of servers to be exposed externally */ public void expose( T k8sEnv, - String machineName, + @Nullable String machineName, String serviceName, + String serverId, ServicePort servicePort, Map externalServers) { - Ingress ingress = generateIngress(machineName, serviceName, servicePort, externalServers); + + if (serverId == null) { + // this is the ID for non-unique servers + serverId = servicePort.getName(); + } + + Ingress ingress = + generateIngress(machineName, serviceName, serverId, servicePort, externalServers); + k8sEnv.getIngresses().put(ingress.getMetadata().getName(), ingress); } private Ingress generateIngress( String machineName, String serviceName, + String serverId, ServicePort servicePort, - Map ingressesServers) { + Map servers) { + String serverName = KubernetesServerExposer.makeServerNameValidForDns(serverId); ExternalServerIngressBuilder ingressBuilder = new ExternalServerIngressBuilder(); - String host = strategy.getExternalHost(serviceName, servicePort); + String host = strategy.getExternalHost(serviceName, serverName); if (host != null) { ingressBuilder = ingressBuilder.withHost(host); } @@ -80,13 +94,13 @@ private Ingress generateIngress( .withPath( String.format( pathTransformFmt, - ensureEndsWithSlash(strategy.getExternalPath(serviceName, servicePort)))) - .withName(getIngressName(serviceName, servicePort)) + ensureEndsWithSlash(strategy.getExternalPath(serviceName, serverName)))) + .withName(getIngressName(serviceName, serverName)) .withMachineName(machineName) .withServiceName(serviceName) .withAnnotations(ingressAnnotations) .withServicePort(servicePort.getName()) - .withServers(ingressesServers) + .withServers(servers) .build(); } @@ -94,7 +108,7 @@ private static String ensureEndsWithSlash(String path) { return path.endsWith("/") ? path : path + '/'; } - private static String getIngressName(String serviceName, ServicePort servicePort) { - return serviceName + "-" + servicePort.getName(); + private static String getIngressName(String serviceName, String serverName) { + return serviceName + "-" + serverName; } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/ExternalServiceExposureStrategy.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/ExternalServiceExposureStrategy.java index 01e3a6551df..61212a13135 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/ExternalServiceExposureStrategy.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/ExternalServiceExposureStrategy.java @@ -11,7 +11,6 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; -import io.fabric8.kubernetes.api.model.ServicePort; import org.eclipse.che.commons.annotation.Nullable; /** @@ -22,8 +21,8 @@ public interface ExternalServiceExposureStrategy { /** Returns a host that should be used to expose the service */ @Nullable - String getExternalHost(String serviceName, ServicePort servicePort); + String getExternalHost(String serviceName, String serverName); /** Returns the path on which the service should be exposed */ - String getExternalPath(String serviceName, ServicePort servicePort); + String getExternalPath(String serviceName, String serverName); } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/MultiHostExternalServiceExposureStrategy.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/MultiHostExternalServiceExposureStrategy.java index 4fdcba9a69d..070df9f2a5f 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/MultiHostExternalServiceExposureStrategy.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/MultiHostExternalServiceExposureStrategy.java @@ -15,7 +15,6 @@ import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.IngressServiceExposureStrategyProvider.STRATEGY_PROPERTY; import com.google.common.base.Strings; -import io.fabric8.kubernetes.api.model.ServicePort; import javax.inject.Inject; import javax.inject.Named; import org.eclipse.che.inject.ConfigurationException; @@ -65,12 +64,12 @@ public MultiHostExternalServiceExposureStrategy( } @Override - public String getExternalHost(String serviceName, ServicePort servicePort) { - return serviceName + "-" + servicePort.getName() + "." + domain; + public String getExternalHost(String serviceName, String serverName) { + return serviceName + "-" + serverName + "." + domain; } @Override - public String getExternalPath(String serviceName, ServicePort servicePort) { + public String getExternalPath(String serviceName, String serverName) { return "/"; } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/SingleHostExternalServiceExposureStrategy.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/SingleHostExternalServiceExposureStrategy.java index f614ba4a8c0..69d7395684f 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/SingleHostExternalServiceExposureStrategy.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/SingleHostExternalServiceExposureStrategy.java @@ -11,7 +11,6 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; -import io.fabric8.kubernetes.api.model.ServicePort; import javax.inject.Inject; import javax.inject.Named; @@ -53,12 +52,12 @@ public SingleHostExternalServiceExposureStrategy(@Named("che.host") String cheHo } @Override - public String getExternalHost(String serviceName, ServicePort servicePort) { + public String getExternalHost(String serviceName, String serverName) { return cheHost; } @Override - public String getExternalPath(String serviceName, ServicePort servicePort) { - return "/" + serviceName + "/" + servicePort.getName(); + public String getExternalPath(String serviceName, String serverName) { + return "/" + serviceName + "/" + serverName; } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/DefaultSecureServersFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/DefaultSecureServersFactory.java index c2eb5dc6598..284c8d85bb4 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/DefaultSecureServersFactory.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/DefaultSecureServersFactory.java @@ -46,9 +46,10 @@ public void expose( T k8sEnv, String machineName, String serviceName, + String serverId, ServicePort servicePort, Map secureServers) { - exposer.expose(k8sEnv, machineName, serviceName, servicePort, secureServers); + exposer.expose(k8sEnv, machineName, serviceName, serverId, servicePort, secureServers); } } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/SecureServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/SecureServerExposer.java index 4dd1c39c99f..0529827ed90 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/SecureServerExposer.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/SecureServerExposer.java @@ -32,6 +32,8 @@ public interface SecureServerExposer { * @param k8sEnv Kubernetes environment that should be modified. * @param machineName machine name to which secure servers belong to * @param serviceName service name that exposes secure servers + * @param serverId non-null for a unique server, null for a compound set of servers that should be + * exposed together. * @param servicePort service port that exposes secure servers * @param secureServers secure servers to expose * @throws InfrastructureException when any exception occurs during servers exposing @@ -40,6 +42,7 @@ void expose( T k8sEnv, String machineName, String serviceName, + String serverId, ServicePort servicePort, Map secureServers) throws InfrastructureException; diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxyProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxyProvisioner.java index 5885fba1bcb..ef49f2914fc 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxyProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxyProvisioner.java @@ -168,8 +168,6 @@ public ServicePort expose( secureServers != null && !secureServers.isEmpty(), "Secure servers are missing"); ensureJwtProxyInjected(k8sEnv); - int listenPort = availablePort++; - Set excludes = new HashSet<>(); Boolean cookiesAuthEnabled = null; for (ServerConfig config : secureServers.values()) { @@ -192,6 +190,8 @@ public ServicePort expose( } } + int listenPort = availablePort++; + ServicePort exposedPort = new ServicePortBuilder() .withName("server-" + listenPort) @@ -208,7 +208,7 @@ public ServicePort expose( excludes, cookiesAuthEnabled, cookiePathStrategy.get(serviceName, exposedPort), - externalServiceExposureStrategy.getExternalPath(serviceName, exposedPort)); + externalServiceExposureStrategy.getExternalPath(serviceName, exposedPort.getName())); k8sEnv .getConfigMaps() .get(getConfigMapName()) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxySecureServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxySecureServerExposer.java index ee15085a29a..185e509ad3a 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxySecureServerExposer.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxySecureServerExposer.java @@ -65,14 +65,21 @@ public void expose( T k8sEnv, String machineName, String serviceName, + String serverId, ServicePort servicePort, Map secureServers) throws InfrastructureException { + ServicePort exposedServicePort = proxyProvisioner.expose( k8sEnv, serviceName, servicePort, servicePort.getProtocol(), secureServers); exposer.expose( - k8sEnv, machineName, proxyProvisioner.getServiceName(), exposedServicePort, secureServers); + k8sEnv, + machineName, + proxyProvisioner.getServiceName(), + serverId, + exposedServicePort, + secureServers); } } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/KubernetesServerExposerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/KubernetesServerExposerTest.java index 8bc2c94332f..c4c0009c761 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/KubernetesServerExposerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/KubernetesServerExposerTest.java @@ -15,6 +15,8 @@ import static java.util.Collections.singletonMap; import static org.eclipse.che.workspace.infrastructure.kubernetes.server.KubernetesServerExposer.SERVER_PREFIX; import static org.eclipse.che.workspace.infrastructure.kubernetes.server.KubernetesServerExposer.SERVER_UNIQUE_PART_SIZE; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; @@ -24,10 +26,12 @@ import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.ContainerBuilder; import io.fabric8.kubernetes.api.model.ContainerPortBuilder; +import io.fabric8.kubernetes.api.model.IntOrString; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodBuilder; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.ServicePort; +import io.fabric8.kubernetes.api.model.ServicePortBuilder; import java.util.ArrayList; import java.util.Map; import java.util.Map.Entry; @@ -35,6 +39,7 @@ import java.util.regex.Pattern; import org.eclipse.che.api.core.model.workspace.config.ServerConfig; import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; @@ -67,6 +72,9 @@ public class KubernetesServerExposerTest { private static final Pattern SERVER_PREFIX_REGEX = Pattern.compile('^' + SERVER_PREFIX + "[A-z0-9]{" + SERVER_UNIQUE_PART_SIZE + "}-pod-main$"); private static final String MACHINE_NAME = "pod/main"; + private static final Map UNIQUE_SERVER_ATTRIBUTES = + ImmutableMap.of("key", "value", ServerConfig.UNIQUE_SERVER_ATTRIBUTE, "true"); + private static final String SERVICE_NAME = SERVER_PREFIX + "12345678" + "-" + MACHINE_NAME; private KubernetesServerExposer serverExposer; private KubernetesEnvironment kubernetesEnvironment; @@ -313,6 +321,80 @@ public void shouldExposeInternalAndExternalAndSecureServers() throws Exception { MACHINE_NAME, "tcp", 8282, "secure-server", new ServerConfigImpl(secureServerConfig)); } + @Test + public void shouldCreateIngressPerUniqueServerWithTheSamePort() throws Exception { + // given + ServerConfigImpl httpServerConfig = + new ServerConfigImpl("8080/tcp", "http", "/api", UNIQUE_SERVER_ATTRIBUTES); + ServerConfigImpl wsServerConfig = + new ServerConfigImpl("8080/tcp", "ws", "/connect", UNIQUE_SERVER_ATTRIBUTES); + ServicePort servicePort = + new ServicePortBuilder() + .withName("server-8080") + .withPort(8080) + .withProtocol("TCP") + .withTargetPort(new IntOrString(8080)) + .build(); + + Map serversToExpose = + ImmutableMap.of( + "http-server", httpServerConfig, + "ws-server", wsServerConfig); + + // when + serverExposer.expose(serversToExpose); + + // then + assertThatExternalServerIsExposed( + MACHINE_NAME, + "tcp", + 8080, + "http-server", + new ServerConfigImpl(httpServerConfig).withAttributes(UNIQUE_SERVER_ATTRIBUTES)); + assertThatExternalServerIsExposed( + MACHINE_NAME, + "tcp", + 8080, + "ws-server", + new ServerConfigImpl(wsServerConfig).withAttributes(UNIQUE_SERVER_ATTRIBUTES)); + } + + @Test + public void shouldCreateIngressForServerWhenTwoServersHasTheSamePort() + throws InfrastructureException { + // given + ServerConfigImpl httpServerConfig = + new ServerConfigImpl("8080/tcp", "http", "/api", ATTRIBUTES_MAP); + ServerConfigImpl wsServerConfig = + new ServerConfigImpl("8080/tcp", "ws", "/connect", ATTRIBUTES_MAP); + IntOrString targetPort = new IntOrString(8080); + + ServicePort servicePort = + new ServicePortBuilder() + .withName("server-8080") + .withPort(8080) + .withProtocol("TCP") + .withTargetPort(targetPort) + .build(); + + Map serversToExpose = + ImmutableMap.of( + "http-server", httpServerConfig, + "ws-server", wsServerConfig); + + // when + serverExposer.expose(serversToExpose); + + // then + assertThatExternalServersAreExposed( + MACHINE_NAME, + "tcp", + 8080, + ImmutableMap.of( + "http-server", new ServerConfigImpl(httpServerConfig).withAttributes(ATTRIBUTES_MAP), + "ws-server", new ServerConfigImpl(wsServerConfig).withAttributes(ATTRIBUTES_MAP))); + } + @SuppressWarnings("SameParameterValue") private void assertThatExternalServerIsExposed( String machineName, @@ -346,11 +428,12 @@ private void assertThatExternalServersAreExposed( verify(externalServerExposer) .expose( - kubernetesEnvironment, - machineName, - service.getMetadata().getName(), - servicePort, - expectedServers); + eq(kubernetesEnvironment), + eq(machineName), + eq(service.getMetadata().getName()), + any(), + eq(servicePort), + eq(expectedServers)); } @SuppressWarnings("SameParameterValue") @@ -377,11 +460,12 @@ private void assertThatSecureServerIsExposed( verify(secureServerExposer) .expose( - kubernetesEnvironment, - machineName, - service.getMetadata().getName(), - servicePort, - ImmutableMap.of(serverName, serverConfig)); + eq(kubernetesEnvironment), + eq(machineName), + eq(service.getMetadata().getName()), + any(), + eq(servicePort), + eq(ImmutableMap.of(serverName, serverConfig))); } @SuppressWarnings("SameParameterValue") diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/DefaultHostExternalServiceExposureStrategyTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/DefaultHostExternalServiceExposureStrategyTest.java index 26071a203a7..a486f7f64a6 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/DefaultHostExternalServiceExposureStrategyTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/DefaultHostExternalServiceExposureStrategyTest.java @@ -11,6 +11,7 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; +import static java.lang.String.format; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; import static org.eclipse.che.workspace.infrastructure.kubernetes.server.KubernetesServerExposer.SERVER_PREFIX; @@ -32,6 +33,7 @@ import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl; import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -39,6 +41,7 @@ public class DefaultHostExternalServiceExposureStrategyTest { private static final Map ATTRIBUTES_MAP = singletonMap("key", "value"); + private static final String MACHINE_NAME = "pod/main"; private static final String SERVICE_NAME = SERVER_PREFIX + "12345678" + "-" + MACHINE_NAME; @@ -81,7 +84,7 @@ public void shouldCreateIngressForServer() { // when externalServerExposer.expose( - kubernetesEnvironment, MACHINE_NAME, SERVICE_NAME, servicePort, serversToExpose); + kubernetesEnvironment, MACHINE_NAME, SERVICE_NAME, null, servicePort, serversToExpose); // then assertThatExternalServerIsExposed( @@ -93,7 +96,7 @@ public void shouldCreateIngressForServer() { } @Test - public void shouldCreateIngressForServerWhenTwoServersHasTheSamePort() { + public void shouldCreateSingleIngressForTwoNonUniqueServersWithTheSamePort() { // given ServerConfigImpl httpServerConfig = new ServerConfigImpl("8080/tcp", "http", "/api", ATTRIBUTES_MAP); @@ -114,7 +117,7 @@ public void shouldCreateIngressForServerWhenTwoServersHasTheSamePort() { // when externalServerExposer.expose( - kubernetesEnvironment, MACHINE_NAME, SERVICE_NAME, servicePort, serversToExpose); + kubernetesEnvironment, MACHINE_NAME, SERVICE_NAME, null, servicePort, serversToExpose); // then assertEquals(kubernetesEnvironment.getIngresses().size(), 1); @@ -141,18 +144,32 @@ private void assertThatExternalServerIsExposed( ServerConfigImpl expected) { // ensure that required ingress is created - Ingress ingress = kubernetesEnvironment.getIngresses().values().iterator().next(); - IngressRule ingressRule = ingress.getSpec().getRules().get(0); - IngressBackend backend = ingressRule.getHttp().getPaths().get(0).getBackend(); - assertEquals(backend.getServiceName(), serviceName); - assertEquals(backend.getServicePort().getStrVal(), servicePort.getName()); - - Annotations.Deserializer ingressAnnotations = - Annotations.newDeserializer(ingress.getMetadata().getAnnotations()); - Map servers = ingressAnnotations.servers(); - ServerConfig serverConfig = servers.get(serverNameRegex); - assertEquals(serverConfig, expected); - - assertEquals(ingressAnnotations.machineName(), machineName); + for (Ingress ingress : kubernetesEnvironment.getIngresses().values()) { + IngressRule ingressRule = ingress.getSpec().getRules().get(0); + IngressBackend backend = ingressRule.getHttp().getPaths().get(0).getBackend(); + if (serviceName.equals(backend.getServiceName())) { + assertEquals(backend.getServicePort().getStrVal(), servicePort.getName()); + + Annotations.Deserializer ingressAnnotations = + Annotations.newDeserializer(ingress.getMetadata().getAnnotations()); + Map servers = ingressAnnotations.servers(); + ServerConfig serverConfig = servers.get(serverNameRegex); + + if (serverConfig == null) { + // ok, this ingress is not for this particular server + continue; + } + + assertEquals(serverConfig, expected); + + assertEquals(ingressAnnotations.machineName(), machineName); + return; + } + } + + Assert.fail( + format( + "Could not find an ingress for machine '%s' and service '%s'", + machineName, serviceName)); } } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/MultiHostExternalServiceExposureStrategyTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/MultiHostExternalServiceExposureStrategyTest.java index ad4247e18bc..7f67b0dec75 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/MultiHostExternalServiceExposureStrategyTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/MultiHostExternalServiceExposureStrategyTest.java @@ -40,6 +40,8 @@ public class MultiHostExternalServiceExposureStrategyTest { private static final Map ATTRIBUTES_MAP = singletonMap("key", "value"); + private static final Map UNIQUE_SERVER_ATTRIBUTES = + ImmutableMap.of("key", "value", ServerConfig.UNIQUE_SERVER_ATTRIBUTE, "true"); private static final String MACHINE_NAME = "pod/main"; private static final String SERVICE_NAME = SERVER_PREFIX + "12345678" + "-" + MACHINE_NAME; private static final String DOMAIN = "che.com"; @@ -86,7 +88,7 @@ public void shouldCreateIngressForServer() { // when externalServerExposer.expose( - kubernetesEnvironment, MACHINE_NAME, SERVICE_NAME, servicePort, serversToExpose); + kubernetesEnvironment, MACHINE_NAME, SERVICE_NAME, null, servicePort, serversToExpose); // then assertThatExternalServerIsExposed( @@ -99,52 +101,6 @@ public void shouldCreateIngressForServer() { new ServerConfigImpl(httpServerConfig).withAttributes(ATTRIBUTES_MAP)); } - @Test - public void shouldCreateIngressForServerWhenTwoServersHasTheSamePort() { - // given - ServerConfigImpl httpServerConfig = - new ServerConfigImpl("8080/tcp", "http", "/api", ATTRIBUTES_MAP); - ServerConfigImpl wsServerConfig = - new ServerConfigImpl("8080/tcp", "ws", "/connect", ATTRIBUTES_MAP); - IntOrString targetPort = new IntOrString(8080); - - ServicePort servicePort = - new ServicePortBuilder() - .withName("server-8080") - .withPort(8080) - .withProtocol("TCP") - .withTargetPort(targetPort) - .build(); - - Map serversToExpose = - ImmutableMap.of( - "http-server", httpServerConfig, - "ws-server", wsServerConfig); - - // when - externalServerExposer.expose( - kubernetesEnvironment, MACHINE_NAME, SERVICE_NAME, servicePort, serversToExpose); - - // then - assertEquals(kubernetesEnvironment.getIngresses().size(), 1); - assertThatExternalServerIsExposed( - MACHINE_NAME, - SERVICE_NAME, - "http-server", - "tcp", - 8080, - servicePort, - new ServerConfigImpl(httpServerConfig).withAttributes(ATTRIBUTES_MAP)); - assertThatExternalServerIsExposed( - MACHINE_NAME, - SERVICE_NAME, - "ws-server", - "tcp", - 8080, - servicePort, - new ServerConfigImpl(wsServerConfig).withAttributes(ATTRIBUTES_MAP)); - } - private void assertThatExternalServerIsExposed( String machineName, String serviceName, @@ -155,9 +111,11 @@ private void assertThatExternalServerIsExposed( ServerConfigImpl expected) { // ensure that required ingress is created - Ingress ingress = kubernetesEnvironment.getIngresses().get(serviceName + "-server-" + port); + String ingressName = + serviceName + "-" + (expected.isUnique() ? serverNameRegex : servicePort.getName()); + Ingress ingress = kubernetesEnvironment.getIngresses().get(ingressName); IngressRule ingressRule = ingress.getSpec().getRules().get(0); - assertEquals(ingressRule.getHost(), serviceName + "-" + servicePort.getName() + "." + DOMAIN); + assertEquals(ingressRule.getHost(), ingressName + "." + DOMAIN); assertEquals(ingressRule.getHttp().getPaths().get(0).getPath(), "/"); IngressBackend backend = ingressRule.getHttp().getPaths().get(0).getBackend(); assertEquals(backend.getServiceName(), serviceName); diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxyProvisionerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxyProvisionerTest.java index bbef5d8b88e..d22f03cddcb 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxyProvisionerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxyProvisionerTest.java @@ -158,7 +158,7 @@ public void shouldProvisionJwtProxyRelatedObjectsIntoKubernetesEnvironment() thr expectedExceptionsMessageRegExp = "Secure servers which expose the same port should have " + "the same `cookiesAuthEnabled` value\\.") - public void shouldThrowAnExceptionIsServersHaveDifferentValueForCookiesAuthEnabled() + public void shouldThrowAnExceptionIfServersHaveDifferentValueForCookiesAuthEnabled() throws Exception { // given ServerConfigImpl server1 = @@ -221,7 +221,7 @@ public void shouldUseCookiesAuthEnabledFromServersConfigs() throws Exception { // when jwtProxyProvisioner.expose( - k8sEnv, "terminal", port, "TCP", ImmutableMap.of("server1", server1, "server2", server2)); + k8sEnv, "terminal", port, "TCP", ImmutableMap.of("server1", server1)); // then verify(configBuilder).addVerifierProxy(any(), any(), any(), eq(true), any(), any()); diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxySecureServerExposerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxySecureServerExposerTest.java index 175e288d2c0..8518cfa10ca 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxySecureServerExposerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxySecureServerExposerTest.java @@ -12,9 +12,9 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -73,23 +73,23 @@ public void shouldExposeSecureServersWithNewJwtProxyServicePort() throws Excepti ServicePort jwtProxyServicePort = new ServicePort(); doReturn(jwtProxyServicePort) .when(jwtProxyProvisioner) - .expose(any(), anyString(), any(), anyString(), anyMap()); + .expose(any(), anyString(), any(), anyString(), any()); when(jwtProxyProvisioner.getServiceName()).thenReturn(JWT_PROXY_SERVICE_NAME); // when secureServerExposer.expose( - k8sEnv, MACHINE_NAME, MACHINE_SERVICE_NAME, machineServicePort, servers); + k8sEnv, MACHINE_NAME, MACHINE_SERVICE_NAME, null, machineServicePort, servers); // then verify(jwtProxyProvisioner) - .expose( - eq(k8sEnv), eq(MACHINE_SERVICE_NAME), eq(machineServicePort), eq("TCP"), eq(servers)); + .expose(eq(k8sEnv), eq(MACHINE_SERVICE_NAME), eq(machineServicePort), eq("TCP"), any()); verify(externalServerExposer) .expose( eq(k8sEnv), eq(MACHINE_NAME), eq(JWT_PROXY_SERVICE_NAME), + isNull(), eq(jwtProxyServicePort), eq(servers)); } diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/server/OpenShiftExternalServerExposer.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/server/OpenShiftExternalServerExposer.java index a63fdb42a10..cbb73fe2c26 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/server/OpenShiftExternalServerExposer.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/server/OpenShiftExternalServerExposer.java @@ -11,11 +11,13 @@ */ package org.eclipse.che.workspace.infrastructure.openshift.server; +import com.google.common.collect.ImmutableMap; import io.fabric8.kubernetes.api.model.IntOrString; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.ServicePort; import io.fabric8.openshift.api.model.Route; import java.util.Collections; +import java.util.HashMap; import java.util.Map; import org.eclipse.che.api.core.model.workspace.config.ServerConfig; import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; @@ -95,12 +97,13 @@ public OpenShiftExternalServerExposer() { @Override public void expose( - OpenShiftEnvironment openShiftEnvironment, + OpenShiftEnvironment env, String machineName, String serviceName, + String serverId, ServicePort servicePort, Map externalServers) { - Route route = + Route commonRoute = new RouteBuilder() .withName(Names.generateName("route")) .withMachineName(machineName) @@ -108,7 +111,7 @@ public void expose( .withServers(externalServers) .withTo(serviceName) .build(); - openShiftEnvironment.getRoutes().put(route.getMetadata().getName(), route); + env.getRoutes().put(commonRoute.getMetadata().getName(), commonRoute); } private static class RouteBuilder { @@ -116,7 +119,7 @@ private static class RouteBuilder { private String name; private String serviceName; private IntOrString targetPort; - private Map serversConfigs; + private Map servers; private String machineName; private RouteBuilder withName(String name) { @@ -134,8 +137,17 @@ private RouteBuilder withTargetPort(String targetPortName) { return this; } - private RouteBuilder withServers(Map serversConfigs) { - this.serversConfigs = serversConfigs; + private RouteBuilder withServer(String serverName, ServerConfig serverConfig) { + return withServers(ImmutableMap.of(serverName, serverConfig)); + } + + private RouteBuilder withServers(Map servers) { + if (this.servers == null) { + this.servers = new HashMap<>(); + } + + this.servers.putAll(servers); + return this; } @@ -152,10 +164,7 @@ private Route build() { .withNewMetadata() .withName(name.replace("/", "-")) .withAnnotations( - Annotations.newSerializer() - .servers(serversConfigs) - .machineName(machineName) - .annotations()) + Annotations.newSerializer().servers(servers).machineName(machineName).annotations()) .endMetadata() .withNewSpec() .withNewTo() diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/server/OpenShiftServerExposureStrategy.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/server/OpenShiftServerExposureStrategy.java index c3bbebff735..5ad6ac1fd27 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/server/OpenShiftServerExposureStrategy.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/server/OpenShiftServerExposureStrategy.java @@ -11,7 +11,6 @@ */ package org.eclipse.che.workspace.infrastructure.openshift.server; -import io.fabric8.kubernetes.api.model.ServicePort; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServiceExposureStrategy; /** @@ -21,12 +20,12 @@ */ public class OpenShiftServerExposureStrategy implements ExternalServiceExposureStrategy { @Override - public String getExternalHost(String serviceName, ServicePort servicePort) { + public String getExternalHost(String serviceName, String serverName) { return null; } @Override - public String getExternalPath(String serviceName, ServicePort servicePort) { + public String getExternalPath(String serviceName, String serverName) { return "/"; } } diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/server/OpenShiftExternalServerExposerTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/server/OpenShiftExternalServerExposerTest.java index 2890d0f003c..9f938bc6641 100644 --- a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/server/OpenShiftExternalServerExposerTest.java +++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/server/OpenShiftExternalServerExposerTest.java @@ -19,6 +19,7 @@ import java.util.HashMap; import java.util.Map; import org.eclipse.che.api.core.model.workspace.config.ServerConfig; +import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl; import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations.Deserializer; import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment; @@ -39,12 +40,14 @@ public void shouldAddRouteToEnvForExposingSpecifiedServer() { // given OpenShiftEnvironment osEnv = OpenShiftEnvironment.builder().build(); Map servers = new HashMap<>(); + servers.put("server", new ServerConfigImpl()); // when osExternalServerExposer.expose( osEnv, "machine123", "service123", + null, new ServicePort("servicePort", null, null, "TCP", null), servers); diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java index c27bfc5ca36..3bdd19148f8 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java @@ -978,8 +978,7 @@ private WorkspaceDto filterServers(WorkspaceDto workspace, boolean includeIntern .getServers() .forEach( (name, server) -> { - if (!"true" - .equals(server.getAttributes().get(ServerConfig.INTERNAL_SERVER_ATTRIBUTE))) { + if (!ServerConfig.isInternal(server.getAttributes())) { filteredServers.put(name, server); } }); diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/InternalRuntime.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/InternalRuntime.java index b2cb702877e..4055a337f7e 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/InternalRuntime.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/InternalRuntime.java @@ -12,7 +12,6 @@ package org.eclipse.che.api.workspace.server.spi; import static java.util.stream.Collectors.toMap; -import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.INTERNAL_SERVER_ATTRIBUTE; import java.util.HashMap; import java.util.List; @@ -20,6 +19,7 @@ import org.eclipse.che.api.core.model.workspace.Warning; import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; import org.eclipse.che.api.core.model.workspace.config.Command; +import org.eclipse.che.api.core.model.workspace.config.ServerConfig; import org.eclipse.che.api.core.model.workspace.runtime.Machine; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.core.model.workspace.runtime.Server; @@ -219,7 +219,7 @@ private Map rewriteExternalServers( for (Map.Entry entry : incoming.entrySet()) { String name = entry.getKey(); Server incomingServer = entry.getValue(); - if (Boolean.parseBoolean(incomingServer.getAttributes().get(INTERNAL_SERVER_ATTRIBUTE))) { + if (ServerConfig.isInternal(incomingServer.getAttributes())) { outgoing.put(name, incomingServer); } else { try {