From a2bb8c9c09b1c6beac69ce2c1dc8735e29337cc6 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Tue, 4 Aug 2020 11:25:01 +0200 Subject: [PATCH 01/47] first treafik config generator implementation Signed-off-by: Michal Vala --- .../kubernetes/KubernetesInfraModule.java | 3 + .../external/GatewayRouteConfigGenerator.java | 24 ++++ .../server/external/GatewayServerExposer.java | 104 +++++++++++++++++- .../TraefikGatewayRouteConfigGenerator.java | 91 +++++++++++++++ .../TraefikGatewayConfigGeneratorTest.java | 38 +++++++ 5 files changed, 257 insertions(+), 3 deletions(-) create mode 100644 infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java create mode 100644 infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java create mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java index 9e36d256434..96db3cb771a 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java @@ -70,11 +70,13 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.DefaultHostExternalServiceExposureStrategy; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServerExposer; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServiceExposureStrategy; +import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGenerator; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayServerExposer; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.IngressServerExposer; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.IngressServiceExposureStrategyProvider; 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.external.TraefikGatewayRouteConfigGenerator; import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposer; import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactoryProvider; @@ -161,6 +163,7 @@ protected void configure() { bind(ExternalServiceExposureStrategy.class) .toProvider(IngressServiceExposureStrategyProvider.class); + bind(GatewayRouteConfigGenerator.class).to(TraefikGatewayRouteConfigGenerator.class); MapBinder> exposureStrategies = MapBinder.newMapBinder( diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java new file mode 100644 index 00000000000..d781df1b530 --- /dev/null +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java @@ -0,0 +1,24 @@ +package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; + +/** + * Generates config for single external server that we want to expose in the Gateway. + *

+ * Implementation provides configuration for specific Gateway technology (e.g., Traefik). + */ +public interface GatewayRouteConfigGenerator { + + /** + * Generates content of configuration for service, defined by passed parameters, that should be + * exposed by the Gateway. + *

+ * Implementation must ensure that Gateway configured with returned content will route the + * requests on {@code path} into {@code serviceUrl}. Also it must strip {@code path} from request + * url. + * + * @param name name of the service + * @param serviceUrl url of service we want to route to + * @param path path to route and strip + * @return full content of configuration for the service + */ + String generate(String name, String serviceUrl, String path); +} diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java index b50d6b37bc7..893786f8a67 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java @@ -11,13 +11,22 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.ServicePort; +import java.util.HashMap; import java.util.Map; +import javax.inject.Inject; import org.eclipse.che.api.core.model.workspace.config.ServerConfig; +import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl; +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; 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.resolver.IngressServerResolver; /** - * Uses Traefik gateway configured with ConfigMaps to expose servers. + * Uses gateway configured with ConfigMaps to expose servers. * *

TODO: implement * @@ -26,14 +35,103 @@ public class GatewayServerExposer implements ExternalServerExposer { + private final ExternalServiceExposureStrategy strategy; + private final GatewayRouteConfigGenerator gatewayConfigGenerator; + + @Inject + public GatewayServerExposer( + ExternalServiceExposureStrategy strategy, + GatewayRouteConfigGenerator gatewayConfigGenerator) { + this.strategy = strategy; + this.gatewayConfigGenerator = gatewayConfigGenerator; + } + + /** + * TODO: rewrite + * 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 IngressServerResolver}. + * + * @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 + */ @Override public void expose( T k8sEnv, - String machineName, + @Nullable String machineName, String serviceName, String serverId, ServicePort servicePort, Map externalServers) { - throw new UnsupportedOperationException("Not implemented yet."); + + if (serverId == null) { + // this is the ID for non-unique servers + serverId = servicePort.getName(); + } + ConfigMap traefikGatewayConfig = + generateTraefikConfig(machineName, serviceName, serverId, servicePort, externalServers); + + k8sEnv.getConfigMaps().put(traefikGatewayConfig.getMetadata().getName(), traefikGatewayConfig); + } + + private ConfigMap generateTraefikConfig( + String machineName, + String serviceName, + String serverId, + ServicePort servicePort, + Map serversConfigs) { + String serverName = KubernetesServerExposer.makeServerNameValidForDns(serverId); + String name = getIngressName(serviceName, serverName); + + String serviceClusterUrl = + "http://" + + serviceName + + ".che.svc.cluster.local:" + + servicePort.getTargetPort().getIntVal().toString(); + String path = ensureEndsWithSlash(strategy.getExternalPath(serviceName, serverName)); + Map configData = new HashMap<>(); + + String routeConfig = gatewayConfigGenerator.generate(name, serviceClusterUrl, path); + + configData.put(name + ".yml", routeConfig); + Map labels = new HashMap<>(); + labels.put("app", "che"); + labels.put("role", "gateway-config"); + + Map configsWithPaths = new HashMap<>(); + for (String scKey : serversConfigs.keySet()) { + ServerConfigImpl sc = new ServerConfigImpl(serversConfigs.get(scKey)); + sc.setPath(path); + configsWithPaths.put(scKey, sc); + } + + Map cmAnnotations = + new HashMap<>( + Annotations.newSerializer() + .servers(configsWithPaths) + .machineName(machineName) + .annotations()); + + return new ConfigMapBuilder() + .withNewMetadata() + .withName(name) + .withLabels(labels) + .withAnnotations(cmAnnotations) + .endMetadata() + .withData(configData) + .build(); + } + + private static String ensureEndsWithSlash(String path) { + return path.endsWith("/") ? path : path + '/'; + } + + 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/TraefikGatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java new file mode 100644 index 00000000000..0fd83214563 --- /dev/null +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java @@ -0,0 +1,91 @@ +package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; + +/** + * Traefik configuration for single route looks like this (values in {} are parameters of {@link + * GatewayRouteConfigGenerator#generate(String, String, String)} method): + * + *

+ * http:
+ *   routers:
+ *     {name}:
+ *       rule: "PathPrefix(`{path}`)"
+ *       service: {name}
+ *       middlewares:
+ *       - "{name}"
+ *       priority: 100
+ *   services:
+ *     {name}:
+ *       loadBalancer:
+ *         servers:
+ *         - url: '{serviceUrl}'
+ *   middlewares:
+ *     {name}:
+ *       stripPrefix:
+ *         prefixes:
+ *         - "{path}"
+ * 
+ */ +public class TraefikGatewayRouteConfigGenerator implements GatewayRouteConfigGenerator { + + /** + * Generates Traefik specific configuration for single service. + * + * @param name name of the service + * @param serviceUrl url of service we want to route to + * @param path path to route and strip + * @return traefik service route config + */ + @Override + public String generate(String name, String serviceUrl, String path) { + return "http:" + + "\n" + + " routers:" + + "\n" + + " " + + name + + ":" + + "\n" + + " rule: \"PathPrefix(`" + + path + + "`)\"" + + "\n" + + " service: " + + name + + "\n" + + " middlewares:" + + "\n" + + " - \"" + + name + + "\"" + + "\n" + + " priority: 100" + + "\n" + + " services:" + + "\n" + + " " + + name + + ":" + + "\n" + + " loadBalancer:" + + "\n" + + " servers:" + + "\n" + + " - url: '" + + serviceUrl + + "'" + + "\n" + + " middlewares:" + + "\n" + + " " + + name + + ":" + + "\n" + + " stripPrefix:" + + "\n" + + " prefixes:" + + "\n" + + " - \"" + + path + + "\""; + } +} diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java new file mode 100644 index 00000000000..7a10d5eb807 --- /dev/null +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java @@ -0,0 +1,38 @@ +package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; + +import static org.testng.Assert.*; + +import org.testng.annotations.Test; + + +public class TraefikGatewayConfigGeneratorTest { + private final GatewayRouteConfigGenerator gatewayConfigGenerator = new TraefikGatewayRouteConfigGenerator(); + + @Test + public void testGenerateGatewayConfig() { + String expectedConfig = "http:\n" + + " routers:\n" + + " external-server-1:\n" + + " rule: \"PathPrefix(`/blabol-cesta`)\"\n" + + " service: external-server-1\n" + + " middlewares:\n" + + " - \"external-server-1\"\n" + + " priority: 100\n" + + " services:\n" + + " external-server-1:\n" + + " loadBalancer:\n" + + " servers:\n" + + " - url: 'http://service-url:1234'\n" + + " middlewares:\n" + + " external-server-1:\n" + + " stripPrefix:\n" + + " prefixes:\n" + + " - \"/blabol-cesta\""; + + String generatedConfig = gatewayConfigGenerator + .generate("external-server-1", "http://service-url:1234", "/blabol-cesta"); + System.out.println(generatedConfig); + + assertEquals(generatedConfig, expectedConfig); + } +} From 56a3f8e83ae0ca9691956bacddc194794ede0b66 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Tue, 4 Aug 2020 14:51:12 +0200 Subject: [PATCH 02/47] refactor generating gateway config Signed-off-by: Michal Vala --- .../external/GatewayRouteConfigGenerator.java | 30 ++- .../server/external/GatewayServerExposer.java | 84 ++++---- .../TraefikGatewayRouteConfigGenerator.java | 188 +++++++++++++----- .../TraefikGatewayConfigGeneratorTest.java | 58 +++--- 4 files changed, 234 insertions(+), 126 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java index d781df1b530..866806b1156 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java @@ -1,24 +1,38 @@ +/* + * 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.external; +import java.util.Map; + /** * Generates config for single external server that we want to expose in the Gateway. - *

- * Implementation provides configuration for specific Gateway technology (e.g., Traefik). + * + *

Implementation provides configuration for specific Gateway technology (e.g., Traefik). */ public interface GatewayRouteConfigGenerator { /** * Generates content of configuration for service, defined by passed parameters, that should be - * exposed by the Gateway. - *

- * Implementation must ensure that Gateway configured with returned content will route the + * exposed by the Gateway. Returned {@code Map} will be used as a value of + * ConfigMap. + * + *

Implementation must ensure that Gateway configured with returned content will route the * requests on {@code path} into {@code serviceUrl}. Also it must strip {@code path} from request * url. * - * @param name name of the service + * @param name name of the service * @param serviceUrl url of service we want to route to - * @param path path to route and strip + * @param path path to route and strip * @return full content of configuration for the service */ - String generate(String name, String serviceUrl, String path); + Map generate(String name, String serviceUrl, String path); } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java index 893786f8a67..daa80daad6e 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java @@ -11,6 +11,7 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; +import com.google.common.collect.ImmutableMap; import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.ServicePort; @@ -23,18 +24,21 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; 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.resolver.IngressServerResolver; /** * Uses gateway configured with ConfigMaps to expose servers. * - *

TODO: implement - * * @param type of environment */ public class GatewayServerExposer implements ExternalServerExposer { + private static final Map GATEWAY_CONFIGMAP_LABELS = + ImmutableMap.builder() + .put("app", "che") + .put("role", "gateway-config") + .build(); + private final ExternalServiceExposureStrategy strategy; private final GatewayRouteConfigGenerator gatewayConfigGenerator; @@ -47,10 +51,8 @@ public GatewayServerExposer( } /** - * TODO: rewrite - * 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 IngressServerResolver}. + * Exposes service port on given service externally (outside kubernetes cluster) using the Gateway + * specific configurations. * * @param k8sEnv Kubernetes environment * @param machineName machine containing servers @@ -85,53 +87,51 @@ private ConfigMap generateTraefikConfig( String serverId, ServicePort servicePort, Map serversConfigs) { - String serverName = KubernetesServerExposer.makeServerNameValidForDns(serverId); - String name = getIngressName(serviceName, serverName); - - String serviceClusterUrl = - "http://" - + serviceName - + ".che.svc.cluster.local:" - + servicePort.getTargetPort().getIntVal().toString(); - String path = ensureEndsWithSlash(strategy.getExternalPath(serviceName, serverName)); - Map configData = new HashMap<>(); - - String routeConfig = gatewayConfigGenerator.generate(name, serviceClusterUrl, path); - - configData.put(name + ".yml", routeConfig); - Map labels = new HashMap<>(); - labels.put("app", "che"); - labels.put("role", "gateway-config"); - - Map configsWithPaths = new HashMap<>(); - for (String scKey : serversConfigs.keySet()) { - ServerConfigImpl sc = new ServerConfigImpl(serversConfigs.get(scKey)); - sc.setPath(path); - configsWithPaths.put(scKey, sc); - } - - Map cmAnnotations = - new HashMap<>( - Annotations.newSerializer() - .servers(configsWithPaths) - .machineName(machineName) - .annotations()); + final String serverName = KubernetesServerExposer.makeServerNameValidForDns(serverId); + final String name = createName(serviceName, serverName); + final String serviceClusterUrl = createServiceUrl(serviceName, servicePort); + final String path = ensureEndsWithSlash(strategy.getExternalPath(serviceName, serverName)); + final Map configData = + gatewayConfigGenerator.generate(name, serviceClusterUrl, path); + final Map annotations = createAnnotations(serversConfigs, path, machineName); return new ConfigMapBuilder() .withNewMetadata() .withName(name) - .withLabels(labels) - .withAnnotations(cmAnnotations) + .withLabels(GATEWAY_CONFIGMAP_LABELS) + .withAnnotations(annotations) .endMetadata() .withData(configData) .build(); } - private static String ensureEndsWithSlash(String path) { + private String ensureEndsWithSlash(String path) { return path.endsWith("/") ? path : path + '/'; } - private static String getIngressName(String serviceName, String serverName) { + private String createName(String serviceName, String serverName) { return serviceName + "-" + serverName; } + + private String createServiceUrl(String serviceName, ServicePort servicePort) { + return "http://" + + serviceName + + ".che.svc.cluster.local:" + + servicePort.getTargetPort().getIntVal().toString(); + } + + private Map createAnnotations( + Map serversConfigs, String path, String machineName) { + Map configsWithPaths = new HashMap<>(); + for (String scKey : serversConfigs.keySet()) { + ServerConfigImpl sc = new ServerConfigImpl(serversConfigs.get(scKey)); + sc.setPath(path); + configsWithPaths.put(scKey, sc); + } + + return Annotations.newSerializer() + .servers(configsWithPaths) + .machineName(machineName) + .annotations(); + } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java index 0fd83214563..9506e6ffe86 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java @@ -1,5 +1,25 @@ +/* + * 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.external; +import static com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature.WRITE_DOC_START_MARKER; + +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; +import java.io.IOException; +import java.io.StringWriter; +import java.util.Collections; +import java.util.Map; + /** * Traefik configuration for single route looks like this (values in {} are parameters of {@link * GatewayRouteConfigGenerator#generate(String, String, String)} method): @@ -30,62 +50,124 @@ public class TraefikGatewayRouteConfigGenerator implements GatewayRouteConfigGen /** * Generates Traefik specific configuration for single service. * - * @param name name of the service + * @param name name of the service * @param serviceUrl url of service we want to route to - * @param path path to route and strip + * @param path path to route and strip * @return traefik service route config */ @Override - public String generate(String name, String serviceUrl, String path) { - return "http:" - + "\n" - + " routers:" - + "\n" - + " " - + name - + ":" - + "\n" - + " rule: \"PathPrefix(`" - + path - + "`)\"" - + "\n" - + " service: " - + name - + "\n" - + " middlewares:" - + "\n" - + " - \"" - + name - + "\"" - + "\n" - + " priority: 100" - + "\n" - + " services:" - + "\n" - + " " - + name - + ":" - + "\n" - + " loadBalancer:" - + "\n" - + " servers:" - + "\n" - + " - url: '" - + serviceUrl - + "'" - + "\n" - + " middlewares:" - + "\n" - + " " - + name - + ":" - + "\n" - + " stripPrefix:" - + "\n" - + " prefixes:" - + "\n" - + " - \"" - + path - + "\""; + public Map generate(String name, String serviceUrl, String path) { + StringWriter sw = new StringWriter(); + + try { + YAMLGenerator generator = + YAMLFactory.builder().disable(WRITE_DOC_START_MARKER).build().createGenerator(sw); + + generator.writeStartObject(); + generator.writeFieldName("http"); + generator.writeStartObject(); + + generator.writeFieldName("routers"); + generateRouters(generator, name, path); + + generator.writeFieldName("services"); + generateServices(generator, name, serviceUrl); + + generator.writeFieldName("middlewares"); + generateMiddlewares(generator, name, path); + + generator.flush(); + + return Collections.singletonMap(name + ".yml", sw.toString()); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + /** + * generates Routers part of Traefik config + * + *

+   * {name}:
+   *   rule: "PathPrefix(`{path}`)"
+   *   service: "{name}"
+   *   middlewares:
+   *   - "{name}"
+   *   priority: 100
+   * 
+ */ + private void generateRouters(YAMLGenerator generator, String name, String path) + throws IOException { + generator.writeStartObject(); + generator.writeFieldName(name); + generator.writeStartObject(); + generator.writeFieldName("rule"); + generator.writeString("PathPrefix(`" + path + "`)"); + generator.writeFieldName("service"); + generator.writeString(name); + generator.writeFieldName("middlewares"); + generator.writeStartArray(); + generator.writeString(name); + generator.writeEndArray(); + generator.writeFieldName("priority"); + generator.writeNumber(100); + generator.writeEndObject(); + generator.writeEndObject(); + } + + /** + * generates Services part of Traefik config + * + *
+   * {name}:
+   *   loadBalancer:
+   *     servers:
+   *     - url: "{serviceUrl}"
+   * 
+ */ + private void generateServices(YAMLGenerator generator, String name, String serviceUrl) + throws IOException { + generator.writeStartObject(); + generator.writeFieldName(name); + generator.writeStartObject(); + generator.writeFieldName("loadBalancer"); + generator.writeStartObject(); + generator.writeFieldName("servers"); + generator.writeStartArray(); + generator.writeStartObject(); + generator.writeFieldName("url"); + generator.writeString(serviceUrl); + generator.writeEndObject(); + generator.writeEndArray(); + generator.writeEndObject(); + generator.writeEndObject(); + generator.writeEndObject(); + } + + /** + * generates Middlewares part of Traefik config + * + *
+   * {name}:
+   *   stripPrefix:
+   *     prefixes:
+   *     - "{path}"
+   * 
+ */ + private void generateMiddlewares(YAMLGenerator generator, String name, String path) + throws IOException { + generator.writeStartObject(); + generator.writeFieldName(name); + generator.writeStartObject(); + generator.writeFieldName("stripPrefix"); + generator.writeStartObject(); + generator.writeFieldName("prefixes"); + generator.writeStartArray(); + generator.writeString(path); + generator.writeEndArray(); + generator.writeEndObject(); + generator.writeEndObject(); + generator.writeEndObject(); } } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java index 7a10d5eb807..84e8309f434 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java @@ -1,37 +1,49 @@ +/* + * 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.external; import static org.testng.Assert.*; import org.testng.annotations.Test; - public class TraefikGatewayConfigGeneratorTest { - private final GatewayRouteConfigGenerator gatewayConfigGenerator = new TraefikGatewayRouteConfigGenerator(); + private final GatewayRouteConfigGenerator gatewayConfigGenerator = + new TraefikGatewayRouteConfigGenerator(); @Test public void testGenerateGatewayConfig() { - String expectedConfig = "http:\n" - + " routers:\n" - + " external-server-1:\n" - + " rule: \"PathPrefix(`/blabol-cesta`)\"\n" - + " service: external-server-1\n" - + " middlewares:\n" - + " - \"external-server-1\"\n" - + " priority: 100\n" - + " services:\n" - + " external-server-1:\n" - + " loadBalancer:\n" - + " servers:\n" - + " - url: 'http://service-url:1234'\n" - + " middlewares:\n" - + " external-server-1:\n" - + " stripPrefix:\n" - + " prefixes:\n" - + " - \"/blabol-cesta\""; + String expectedConfig = + "http:\n" + + " routers:\n" + + " external-server-1:\n" + + " rule: \"PathPrefix(`/blabol-cesta`)\"\n" + + " service: \"external-server-1\"\n" + + " middlewares:\n" + + " - \"external-server-1\"\n" + + " priority: 100\n" + + " services:\n" + + " external-server-1:\n" + + " loadBalancer:\n" + + " servers:\n" + + " - url: \"http://service-url:1234\"\n" + + " middlewares:\n" + + " external-server-1:\n" + + " stripPrefix:\n" + + " prefixes:\n" + + " - \"/blabol-cesta\""; - String generatedConfig = gatewayConfigGenerator - .generate("external-server-1", "http://service-url:1234", "/blabol-cesta"); - System.out.println(generatedConfig); + String generatedConfig = + gatewayConfigGenerator.generate( + "external-server-1", "http://service-url:1234", "/blabol-cesta"); assertEquals(generatedConfig, expectedConfig); } From 1417611bfe59e96a3c525a0023d9b0c340d1eb9c Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Tue, 4 Aug 2020 16:15:29 +0200 Subject: [PATCH 03/47] fix TraefikGatewayConfigGeneratorTest Signed-off-by: Michal Vala --- .../server/external/TraefikGatewayConfigGeneratorTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java index 84e8309f434..588d2d0fc90 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java @@ -13,6 +13,7 @@ import static org.testng.Assert.*; +import java.util.Map; import org.testng.annotations.Test; public class TraefikGatewayConfigGeneratorTest { @@ -41,10 +42,11 @@ public void testGenerateGatewayConfig() { + " prefixes:\n" + " - \"/blabol-cesta\""; - String generatedConfig = + Map generatedConfig = gatewayConfigGenerator.generate( "external-server-1", "http://service-url:1234", "/blabol-cesta"); - assertEquals(generatedConfig, expectedConfig); + assertTrue(generatedConfig.containsKey("external-server-1.yml")); + assertEquals(generatedConfig.get("external-server-1.yml"), expectedConfig); } } From 5d3e6251348e5bcd630ca8ea65b182c7246be5a5 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Tue, 4 Aug 2020 17:24:46 +0200 Subject: [PATCH 04/47] test GatewayServerExposer Signed-off-by: Michal Vala --- .../server/external/GatewayServerExposer.java | 6 +- .../external/GatewayServerExposerTest.java | 78 +++++++++++++++++++ 2 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java index daa80daad6e..98bbbd8f46c 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java @@ -33,7 +33,7 @@ public class GatewayServerExposer implements ExternalServerExposer { - private static final Map GATEWAY_CONFIGMAP_LABELS = + protected static final Map GATEWAY_CONFIGMAP_LABELS = ImmutableMap.builder() .put("app", "che") .put("role", "gateway-config") @@ -124,9 +124,7 @@ private Map createAnnotations( Map serversConfigs, String path, String machineName) { Map configsWithPaths = new HashMap<>(); for (String scKey : serversConfigs.keySet()) { - ServerConfigImpl sc = new ServerConfigImpl(serversConfigs.get(scKey)); - sc.setPath(path); - configsWithPaths.put(scKey, sc); + configsWithPaths.put(scKey, new ServerConfigImpl(serversConfigs.get(scKey)).withPath(path)); } return Annotations.newSerializer() diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java new file mode 100644 index 00000000000..62f9d887c27 --- /dev/null +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java @@ -0,0 +1,78 @@ +/* + * 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.external; + +import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayServerExposer.GATEWAY_CONFIGMAP_LABELS; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.IntOrString; +import io.fabric8.kubernetes.api.model.ServicePort; +import java.util.Collections; +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.environment.KubernetesEnvironment; +import org.testng.annotations.Test; + +public class GatewayServerExposerTest { + + private final String machineName = "machine"; + private final String serviceName = "service"; + private final String serverId = "server"; + private final ServicePort servicePort = + new ServicePort("portName", 1, 1, "http", new IntOrString(1234)); + + private final Map s1attrs = Collections.singletonMap("s1attr", "s1val"); + + private final Map servers = + Collections.singletonMap("serverOne", new ServerConfigImpl("1111", "ws", null, s1attrs)); + + private final ExternalServerExposer serverExposer = + new GatewayServerExposer<>( + new SingleHostExternalServiceExposureStrategy("che-host"), + (name, serviceUrl, path) -> + Collections.singletonMap("hello", name + "#" + serviceUrl + "#" + path)); + + @Test + public void testExposeServiceWithGatewayConfigmap() { + KubernetesEnvironment k8sEnv = KubernetesEnvironment.builder().build(); + serverExposer.expose(k8sEnv, machineName, serviceName, serverId, servicePort, servers); + Map configMaps = k8sEnv.getConfigMaps(); + + assertTrue(configMaps.containsKey(serviceName + "-" + serverId)); + + ConfigMap serverConfigMap = configMaps.get("service-server"); + + Map serverConfigMapData = serverConfigMap.getData(); + assertTrue(serverConfigMapData.containsKey("hello")); + assertEquals( + serverConfigMapData.get("hello"), + "service-server#http://service.che.svc.cluster.local:1234#/service/server/"); + assertEquals(serverConfigMap.getMetadata().getLabels(), GATEWAY_CONFIGMAP_LABELS); + + Map annotations = serverConfigMap.getMetadata().getAnnotations(); + Annotations.Deserializer deserializer = Annotations.newDeserializer(annotations); + assertEquals(deserializer.machineName(), machineName); + + Map exposedServers = deserializer.servers(); + assertTrue(exposedServers.containsKey("serverOne")); + + ServerConfig s1 = exposedServers.get("serverOne"); + assertEquals(s1.getAttributes(), s1attrs); + assertEquals(s1.getPort(), "1111"); + assertEquals(s1.getProtocol(), "ws"); + assertEquals(s1.getPath(), "/service/server/"); + } +} From 9e275c443ae86d1ba6fceea54a8c5486c2299f28 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Tue, 4 Aug 2020 17:41:42 +0200 Subject: [PATCH 05/47] nullsafer way how to get port Signed-off-by: Michal Vala --- .../kubernetes/server/external/GatewayServerExposer.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java index 98bbbd8f46c..17c8bcb15c8 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java @@ -14,6 +14,7 @@ import com.google.common.collect.ImmutableMap; import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.IntOrString; import io.fabric8.kubernetes.api.model.ServicePort; import java.util.HashMap; import java.util.Map; @@ -117,7 +118,13 @@ private String createServiceUrl(String serviceName, ServicePort servicePort) { return "http://" + serviceName + ".che.svc.cluster.local:" - + servicePort.getTargetPort().getIntVal().toString(); + + getTargetPort(servicePort.getTargetPort()); + } + + private String getTargetPort(IntOrString targetPort) { + return targetPort.getIntVal() != null + ? targetPort.getIntVal().toString() + : targetPort.getStrVal(); } private Map createAnnotations( From 3cfabf467b7a143b7a76ab20a026f0b5cf529658 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 6 Aug 2020 15:08:51 +0200 Subject: [PATCH 06/47] create route configmaps in che namespace Signed-off-by: Michal Vala --- .../che/api/deploy/WsMasterModule.java | 1 + .../kubernetes/GatewayRouterProvisioner.java | 75 +++++++++ .../kubernetes/KubernetesInfraModule.java | 1 - .../kubernetes/KubernetesInternalRuntime.java | 4 + .../kubernetes/KubernetesRuntimeContext.java | 3 +- .../namespace/KubernetesConfigsMaps.java | 1 + .../provision/GatewayTlsProvisioner.java | 13 +- .../external/GatewayRouteConfigGenerator.java | 4 +- .../server/external/GatewayServerExposer.java | 44 +---- .../TraefikGatewayRouteConfigGenerator.java | 47 +++++- .../KubernetesInternalRuntimeTest.java | 1 + .../external/GatewayServerExposerTest.java | 156 +++++++++--------- .../TraefikGatewayConfigGeneratorTest.java | 104 ++++++------ .../openshift/OpenShiftInternalRuntime.java | 3 + .../OpenShiftInternalRuntimeTest.java | 1 + .../spi/environment/GatewayRouteConfig.java | 74 +++++++++ .../spi/environment/InternalEnvironment.java | 9 + 17 files changed, 356 insertions(+), 185 deletions(-) create mode 100644 infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterProvisioner.java create mode 100644 wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java diff --git a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java index 88ddc7aae85..e6c75de4f64 100644 --- a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java +++ b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java @@ -89,6 +89,7 @@ import org.eclipse.che.security.oauth.EmbeddedOAuthAPI; import org.eclipse.che.security.oauth.OAuthAPI; import org.eclipse.che.security.oauth.OpenShiftOAuthModule; +import org.eclipse.che.workspace.infrastructure.kubernetes.GatewayRouterProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfraModule; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructure; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterProvisioner.java new file mode 100644 index 00000000000..69304ea7702 --- /dev/null +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterProvisioner.java @@ -0,0 +1,75 @@ +package org.eclipse.che.workspace.infrastructure.kubernetes; + +import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.TlsProvisioner.getSecureProtocol; + +import com.google.common.collect.ImmutableMap; +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.Executor; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; +import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironment; +import org.eclipse.che.api.workspace.server.spi.provision.InternalEnvironmentProvisioner; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespace; +import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGenerator; +import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.TraefikGatewayRouteConfigGenerator; +import org.eclipse.che.workspace.infrastructure.kubernetes.util.KubernetesSharedPool; + +@Singleton +public class GatewayRouterProvisioner { + + protected static final Map GATEWAY_CONFIGMAP_LABELS = + ImmutableMap.builder() + .put("app", "che") + .put("role", "gateway-config") + .build(); + + private final KubernetesClientFactory clientFactory; + private final Executor k8sExecutor; + + @Inject + public GatewayRouterProvisioner(KubernetesClientFactory clientFactory, + KubernetesSharedPool sharedPool) { + this.clientFactory = clientFactory; + this.k8sExecutor = sharedPool.getExecutor(); + } + + public List provision(RuntimeIdentity id, InternalEnvironment internalEnvironment) + throws InfrastructureException { + if (internalEnvironment.getGatewayRouteConfigs().isEmpty()) { + return Collections.emptyList(); + } + List routeConfigMaps = new ArrayList<>(); + KubernetesNamespace cheNamespace = new KubernetesNamespace(clientFactory, k8sExecutor, "che", + id.getWorkspaceId()); + + for (GatewayRouteConfig routeConfig : internalEnvironment.getGatewayRouteConfigs()) { + GatewayRouteConfigGenerator gatewayRouteConfigGenerator = new TraefikGatewayRouteConfigGenerator( + id.getInfrastructureNamespace()); + gatewayRouteConfigGenerator.addRouteConfig(routeConfig); + ConfigMapBuilder configMapBuilder = new ConfigMapBuilder() + .withNewMetadata() + .withName(id.getWorkspaceId() + routeConfig.getName()) + .withLabels(GATEWAY_CONFIGMAP_LABELS) + .withAnnotations(routeConfig.getAnnotations()) + .endMetadata() + .withData(gatewayRouteConfigGenerator.generate()); + + ConfigMap routeConfigMap = cheNamespace.configMaps().create(configMapBuilder.build()); + routeConfigMaps.add(routeConfigMap); + } + + return routeConfigMaps; + } +} diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java index 96db3cb771a..e4bfe4c4745 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java @@ -163,7 +163,6 @@ protected void configure() { bind(ExternalServiceExposureStrategy.class) .toProvider(IngressServiceExposureStrategyProvider.class); - bind(GatewayRouteConfigGenerator.class).to(TraefikGatewayRouteConfigGenerator.class); MapBinder> exposureStrategies = MapBinder.newMapBinder( diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java index c45a8efcc06..d12b0ec5919 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java @@ -131,6 +131,7 @@ public class KubernetesInternalRuntime private final PreviewUrlCommandProvisioner previewUrlCommandProvisioner; private final SecretAsContainerResourceProvisioner secretAsContainerResourceProvisioner; private final KubernetesServerResolverFactory serverResolverFactory; + private final GatewayRouterProvisioner gatewayRouterProvisioner; protected final Tracer tracer; @Inject @@ -155,6 +156,7 @@ public KubernetesInternalRuntime( PreviewUrlCommandProvisioner previewUrlCommandProvisioner, SecretAsContainerResourceProvisioner secretAsContainerResourceProvisioner, KubernetesServerResolverFactory kubernetesServerResolverFactory, + GatewayRouterProvisioner gatewayRouterProvisioner, Tracer tracer, @Assisted KubernetesRuntimeContext context, @Assisted KubernetesNamespace namespace) { @@ -180,6 +182,7 @@ public KubernetesInternalRuntime( this.secretAsContainerResourceProvisioner = secretAsContainerResourceProvisioner; this.serverResolverFactory = kubernetesServerResolverFactory; this.tracer = tracer; + this.gatewayRouterProvisioner = gatewayRouterProvisioner; } @Override @@ -615,6 +618,7 @@ protected void startMachines() throws InfrastructureException { createSecrets(k8sEnv, workspaceId); List createdConfigMaps = createConfigMaps(k8sEnv, workspaceId); + createdConfigMaps.addAll(gatewayRouterProvisioner.provision(getContext().getIdentity(), k8sEnv)); List createdServices = createServices(k8sEnv, workspaceId); // needed for resolution later on, even though n routes are actually created by ingress diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesRuntimeContext.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesRuntimeContext.java index c34350dbf0a..baa204beeec 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesRuntimeContext.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesRuntimeContext.java @@ -47,8 +47,7 @@ public KubernetesRuntimeContext( KubernetesRuntimeStateCache runtimeStatuses, @Assisted T kubernetesEnvironment, @Assisted RuntimeIdentity identity, - @Assisted RuntimeInfrastructure infrastructure) - throws ValidationException, InfrastructureException { + @Assisted RuntimeInfrastructure infrastructure) { super(kubernetesEnvironment, identity, infrastructure); this.namespaceFactory = namespaceFactory; this.runtimeFactory = runtimeFactory; diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesConfigsMaps.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesConfigsMaps.java index eb14faec307..694f87a4ea0 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesConfigsMaps.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesConfigsMaps.java @@ -20,6 +20,7 @@ import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructureException; +import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.model.Config; /** * Defines an internal API for managing {@link ConfigMap} instances in {@link diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java index 483cd725242..63abca14516 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java @@ -20,6 +20,7 @@ import javax.inject.Singleton; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl; +import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructureException; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; @@ -45,14 +46,14 @@ public void provision(T k8sEnv, RuntimeIdentity identity) return; } - for (ConfigMap cm : k8sEnv.getConfigMaps().values()) { - useSecureProtocolForGatewayServers(cm); + for (GatewayRouteConfig routeConfig : k8sEnv.getGatewayRouteConfigs()) { + useSecureProtocolForGatewayServers(routeConfig); } } - private void useSecureProtocolForGatewayServers(ConfigMap cm) { + private void useSecureProtocolForGatewayServers(GatewayRouteConfig routeConfig) { Map servers = - Annotations.newDeserializer(cm.getMetadata().getAnnotations()).servers(); + Annotations.newDeserializer(routeConfig.getAnnotations()).servers(); if (servers.isEmpty()) { return; @@ -61,8 +62,8 @@ private void useSecureProtocolForGatewayServers(ConfigMap cm) { servers.values().forEach(s -> s.setProtocol(getSecureProtocol(s.getProtocol()))); Map annotations = Annotations.newSerializer().servers(servers).annotations(); - if (!annotations.isEmpty() && cm.getMetadata().getAnnotations() != null) { - cm.getMetadata().getAnnotations().putAll(annotations); + if (!annotations.isEmpty() && routeConfig.getAnnotations() != null) { + routeConfig.getAnnotations().putAll(annotations); } } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java index 866806b1156..ce255b5f3ed 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java @@ -12,6 +12,7 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; import java.util.Map; +import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; /** * Generates config for single external server that we want to expose in the Gateway. @@ -19,6 +20,7 @@ *

Implementation provides configuration for specific Gateway technology (e.g., Traefik). */ public interface GatewayRouteConfigGenerator { + void addRouteConfig(GatewayRouteConfig routeConfig); /** * Generates content of configuration for service, defined by passed parameters, that should be @@ -34,5 +36,5 @@ public interface GatewayRouteConfigGenerator { * @param path path to route and strip * @return full content of configuration for the service */ - Map generate(String name, String serviceUrl, String path); + Map generate(); } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java index 17c8bcb15c8..5991b965b4a 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java @@ -11,9 +11,6 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; -import com.google.common.collect.ImmutableMap; -import io.fabric8.kubernetes.api.model.ConfigMap; -import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.IntOrString; import io.fabric8.kubernetes.api.model.ServicePort; import java.util.HashMap; @@ -21,6 +18,7 @@ import javax.inject.Inject; 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.environment.GatewayRouteConfig; import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; @@ -34,21 +32,12 @@ public class GatewayServerExposer implements ExternalServerExposer { - protected static final Map GATEWAY_CONFIGMAP_LABELS = - ImmutableMap.builder() - .put("app", "che") - .put("role", "gateway-config") - .build(); - private final ExternalServiceExposureStrategy strategy; - private final GatewayRouteConfigGenerator gatewayConfigGenerator; @Inject public GatewayServerExposer( - ExternalServiceExposureStrategy strategy, - GatewayRouteConfigGenerator gatewayConfigGenerator) { + ExternalServiceExposureStrategy strategy) { this.strategy = strategy; - this.gatewayConfigGenerator = gatewayConfigGenerator; } /** @@ -76,34 +65,22 @@ public void expose( // this is the ID for non-unique servers serverId = servicePort.getName(); } - ConfigMap traefikGatewayConfig = - generateTraefikConfig(machineName, serviceName, serverId, servicePort, externalServers); - k8sEnv.getConfigMaps().put(traefikGatewayConfig.getMetadata().getName(), traefikGatewayConfig); + k8sEnv.addGatewayRouteConfig( + createGatewayRouteConfig(machineName, serviceName, serverId, servicePort, externalServers)); } - private ConfigMap generateTraefikConfig( - String machineName, + private GatewayRouteConfig createGatewayRouteConfig(String machineName, String serviceName, String serverId, ServicePort servicePort, Map serversConfigs) { final String serverName = KubernetesServerExposer.makeServerNameValidForDns(serverId); final String name = createName(serviceName, serverName); - final String serviceClusterUrl = createServiceUrl(serviceName, servicePort); final String path = ensureEndsWithSlash(strategy.getExternalPath(serviceName, serverName)); - final Map configData = - gatewayConfigGenerator.generate(name, serviceClusterUrl, path); final Map annotations = createAnnotations(serversConfigs, path, machineName); - - return new ConfigMapBuilder() - .withNewMetadata() - .withName(name) - .withLabels(GATEWAY_CONFIGMAP_LABELS) - .withAnnotations(annotations) - .endMetadata() - .withData(configData) - .build(); + return new GatewayRouteConfig(name, serviceName, getTargetPort(servicePort.getTargetPort()), + path, annotations); } private String ensureEndsWithSlash(String path) { @@ -114,13 +91,6 @@ private String createName(String serviceName, String serverName) { return serviceName + "-" + serverName; } - private String createServiceUrl(String serviceName, ServicePort servicePort) { - return "http://" - + serviceName - + ".che.svc.cluster.local:" - + getTargetPort(servicePort.getTargetPort()); - } - private String getTargetPort(IntOrString targetPort) { return targetPort.getIntVal() != null ? targetPort.getIntVal().toString() diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java index 9506e6ffe86..0b05e98c701 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java @@ -17,11 +17,14 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; import java.io.IOException; import java.io.StringWriter; -import java.util.Collections; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.Map; +import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; /** - * Traefik configuration for single route looks like this (values in {} are parameters of {@link + * Traefik configuration for single route looks like this (values in {} are parameters of {link * GatewayRouteConfigGenerator#generate(String, String, String)} method): * *

@@ -47,18 +50,24 @@
  */
 public class TraefikGatewayRouteConfigGenerator implements GatewayRouteConfigGenerator {
 
+  private final List routeConfigs = new ArrayList<>();
+
+  private final String serviceNamespace;
+
+  public TraefikGatewayRouteConfigGenerator(String serviceNamespace) {
+    this.serviceNamespace = serviceNamespace;
+  }
+
   /**
    * Generates Traefik specific configuration for single service.
    *
-   * @param name name of the service
+   * @param name       name of the service
    * @param serviceUrl url of service we want to route to
-   * @param path path to route and strip
+   * @param path       path to route and strip
    * @return traefik service route config
    */
-  @Override
-  public Map generate(String name, String serviceUrl, String path) {
+  public String generate(String name, String serviceUrl, String path) {
     StringWriter sw = new StringWriter();
-
     try {
       YAMLGenerator generator =
           YAMLFactory.builder().disable(WRITE_DOC_START_MARKER).build().createGenerator(sw);
@@ -78,7 +87,7 @@ public Map generate(String name, String serviceUrl, String path)
 
       generator.flush();
 
-      return Collections.singletonMap(name + ".yml", sw.toString());
+      return sw.toString();
     } catch (IOException e) {
       e.printStackTrace();
       throw new RuntimeException(e);
@@ -170,4 +179,26 @@ private void generateMiddlewares(YAMLGenerator generator, String name, String pa
     generator.writeEndObject();
     generator.writeEndObject();
   }
+
+  @Override
+  public void addRouteConfig(GatewayRouteConfig routeConfig) {
+    this.routeConfigs.add(routeConfig);
+  }
+
+  @Override
+  public Map generate() {
+    Map cmData = new HashMap<>();
+    for (GatewayRouteConfig routeConfig : routeConfigs) {
+      String traefikRouteConfig = generate(routeConfig.getName(),
+          createServiceUrl(routeConfig.getServiceName(), routeConfig.getServicePort()),
+          routeConfig.getRoutePath());
+      cmData.put(routeConfig.getName() + ".yml", traefikRouteConfig);
+    }
+    return cmData;
+  }
+
+  private String createServiceUrl(String serviceName, String servicePort) {
+    return String
+        .format("http://%s.%s.svc.cluster.local:%s", serviceName, serviceNamespace, servicePort);
+  }
 }
diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java
index f53cf07efcc..404050966f2 100644
--- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java
+++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java
@@ -285,6 +285,7 @@ public void setup() throws Exception {
             previewUrlCommandProvisioner,
             secretAsContainerResourceProvisioner,
             serverResolverFactory,
+            null,
             tracer,
             context,
             namespace);
diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java
index 62f9d887c27..07625dc79c0 100644
--- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java
+++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java
@@ -1,78 +1,78 @@
-/*
- * 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.external;
-
-import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayServerExposer.GATEWAY_CONFIGMAP_LABELS;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-import io.fabric8.kubernetes.api.model.ConfigMap;
-import io.fabric8.kubernetes.api.model.IntOrString;
-import io.fabric8.kubernetes.api.model.ServicePort;
-import java.util.Collections;
-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.environment.KubernetesEnvironment;
-import org.testng.annotations.Test;
-
-public class GatewayServerExposerTest {
-
-  private final String machineName = "machine";
-  private final String serviceName = "service";
-  private final String serverId = "server";
-  private final ServicePort servicePort =
-      new ServicePort("portName", 1, 1, "http", new IntOrString(1234));
-
-  private final Map s1attrs = Collections.singletonMap("s1attr", "s1val");
-
-  private final Map servers =
-      Collections.singletonMap("serverOne", new ServerConfigImpl("1111", "ws", null, s1attrs));
-
-  private final ExternalServerExposer serverExposer =
-      new GatewayServerExposer<>(
-          new SingleHostExternalServiceExposureStrategy("che-host"),
-          (name, serviceUrl, path) ->
-              Collections.singletonMap("hello", name + "#" + serviceUrl + "#" + path));
-
-  @Test
-  public void testExposeServiceWithGatewayConfigmap() {
-    KubernetesEnvironment k8sEnv = KubernetesEnvironment.builder().build();
-    serverExposer.expose(k8sEnv, machineName, serviceName, serverId, servicePort, servers);
-    Map configMaps = k8sEnv.getConfigMaps();
-
-    assertTrue(configMaps.containsKey(serviceName + "-" + serverId));
-
-    ConfigMap serverConfigMap = configMaps.get("service-server");
-
-    Map serverConfigMapData = serverConfigMap.getData();
-    assertTrue(serverConfigMapData.containsKey("hello"));
-    assertEquals(
-        serverConfigMapData.get("hello"),
-        "service-server#http://service.che.svc.cluster.local:1234#/service/server/");
-    assertEquals(serverConfigMap.getMetadata().getLabels(), GATEWAY_CONFIGMAP_LABELS);
-
-    Map annotations = serverConfigMap.getMetadata().getAnnotations();
-    Annotations.Deserializer deserializer = Annotations.newDeserializer(annotations);
-    assertEquals(deserializer.machineName(), machineName);
-
-    Map exposedServers = deserializer.servers();
-    assertTrue(exposedServers.containsKey("serverOne"));
-
-    ServerConfig s1 = exposedServers.get("serverOne");
-    assertEquals(s1.getAttributes(), s1attrs);
-    assertEquals(s1.getPort(), "1111");
-    assertEquals(s1.getProtocol(), "ws");
-    assertEquals(s1.getPath(), "/service/server/");
-  }
-}
+///*
+// * 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.external;
+//
+//import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayServerExposer.GATEWAY_CONFIGMAP_LABELS;
+//import static org.testng.Assert.assertEquals;
+//import static org.testng.Assert.assertTrue;
+//
+//import io.fabric8.kubernetes.api.model.ConfigMap;
+//import io.fabric8.kubernetes.api.model.IntOrString;
+//import io.fabric8.kubernetes.api.model.ServicePort;
+//import java.util.Collections;
+//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.environment.KubernetesEnvironment;
+//import org.testng.annotations.Test;
+//
+//public class GatewayServerExposerTest {
+//
+//  private final String machineName = "machine";
+//  private final String serviceName = "service";
+//  private final String serverId = "server";
+//  private final ServicePort servicePort =
+//      new ServicePort("portName", 1, 1, "http", new IntOrString(1234));
+//
+//  private final Map s1attrs = Collections.singletonMap("s1attr", "s1val");
+//
+//  private final Map servers =
+//      Collections.singletonMap("serverOne", new ServerConfigImpl("1111", "ws", null, s1attrs));
+//
+//  private final ExternalServerExposer serverExposer =
+//      new GatewayServerExposer<>(
+//          new SingleHostExternalServiceExposureStrategy("che-host"),
+//          (name, serviceUrl, path) ->
+//              Collections.singletonMap("hello", name + "#" + serviceUrl + "#" + path));
+//
+//  @Test
+//  public void testExposeServiceWithGatewayConfigmap() {
+//    KubernetesEnvironment k8sEnv = KubernetesEnvironment.builder().build();
+//    serverExposer.expose(k8sEnv, machineName, serviceName, serverId, servicePort, servers);
+//    Map configMaps = k8sEnv.getConfigMaps();
+//
+//    assertTrue(configMaps.containsKey(serviceName + "-" + serverId));
+//
+//    ConfigMap serverConfigMap = configMaps.get("service-server");
+//
+//    Map serverConfigMapData = serverConfigMap.getData();
+//    assertTrue(serverConfigMapData.containsKey("hello"));
+//    assertEquals(
+//        serverConfigMapData.get("hello"),
+//        "service-server#http://service.che.svc.cluster.local:1234#/service/server/");
+//    assertEquals(serverConfigMap.getMetadata().getLabels(), GATEWAY_CONFIGMAP_LABELS);
+//
+//    Map annotations = serverConfigMap.getMetadata().getAnnotations();
+//    Annotations.Deserializer deserializer = Annotations.newDeserializer(annotations);
+//    assertEquals(deserializer.machineName(), machineName);
+//
+//    Map exposedServers = deserializer.servers();
+//    assertTrue(exposedServers.containsKey("serverOne"));
+//
+//    ServerConfig s1 = exposedServers.get("serverOne");
+//    assertEquals(s1.getAttributes(), s1attrs);
+//    assertEquals(s1.getPort(), "1111");
+//    assertEquals(s1.getProtocol(), "ws");
+//    assertEquals(s1.getPath(), "/service/server/");
+//  }
+//}
diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java
index 588d2d0fc90..2b39ef82456 100644
--- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java
+++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java
@@ -1,52 +1,52 @@
-/*
- * 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.external;
-
-import static org.testng.Assert.*;
-
-import java.util.Map;
-import org.testng.annotations.Test;
-
-public class TraefikGatewayConfigGeneratorTest {
-  private final GatewayRouteConfigGenerator gatewayConfigGenerator =
-      new TraefikGatewayRouteConfigGenerator();
-
-  @Test
-  public void testGenerateGatewayConfig() {
-    String expectedConfig =
-        "http:\n"
-            + "  routers:\n"
-            + "    external-server-1:\n"
-            + "      rule: \"PathPrefix(`/blabol-cesta`)\"\n"
-            + "      service: \"external-server-1\"\n"
-            + "      middlewares:\n"
-            + "      - \"external-server-1\"\n"
-            + "      priority: 100\n"
-            + "  services:\n"
-            + "    external-server-1:\n"
-            + "      loadBalancer:\n"
-            + "        servers:\n"
-            + "        - url: \"http://service-url:1234\"\n"
-            + "  middlewares:\n"
-            + "    external-server-1:\n"
-            + "      stripPrefix:\n"
-            + "        prefixes:\n"
-            + "        - \"/blabol-cesta\"";
-
-    Map generatedConfig =
-        gatewayConfigGenerator.generate(
-            "external-server-1", "http://service-url:1234", "/blabol-cesta");
-
-    assertTrue(generatedConfig.containsKey("external-server-1.yml"));
-    assertEquals(generatedConfig.get("external-server-1.yml"), expectedConfig);
-  }
-}
+///*
+// * 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.external;
+//
+//import static org.testng.Assert.*;
+//
+//import java.util.Map;
+//import org.testng.annotations.Test;
+//
+//public class TraefikGatewayConfigGeneratorTest {
+//  private final GatewayRouteConfigGenerator gatewayConfigGenerator =
+//      new TraefikGatewayRouteConfigGenerator();
+//
+//  @Test
+//  public void testGenerateGatewayConfig() {
+//    String expectedConfig =
+//        "http:\n"
+//            + "  routers:\n"
+//            + "    external-server-1:\n"
+//            + "      rule: \"PathPrefix(`/blabol-cesta`)\"\n"
+//            + "      service: \"external-server-1\"\n"
+//            + "      middlewares:\n"
+//            + "      - \"external-server-1\"\n"
+//            + "      priority: 100\n"
+//            + "  services:\n"
+//            + "    external-server-1:\n"
+//            + "      loadBalancer:\n"
+//            + "        servers:\n"
+//            + "        - url: \"http://service-url:1234\"\n"
+//            + "  middlewares:\n"
+//            + "    external-server-1:\n"
+//            + "      stripPrefix:\n"
+//            + "        prefixes:\n"
+//            + "        - \"/blabol-cesta\"";
+//
+//    Map generatedConfig =
+//        gatewayConfigGenerator.generate(
+//            "external-server-1", "http://service-url:1234", "/blabol-cesta");
+//
+//    assertTrue(generatedConfig.containsKey("external-server-1.yml"));
+//    assertEquals(generatedConfig.get("external-server-1.yml"), expectedConfig);
+//  }
+//}
diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java
index e4d8520fb9b..56d21c07cd6 100644
--- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java
+++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java
@@ -32,6 +32,7 @@
 import org.eclipse.che.api.workspace.server.spi.provision.InternalEnvironmentProvisioner;
 import org.eclipse.che.commons.annotation.Traced;
 import org.eclipse.che.commons.tracing.TracingTags;
+import org.eclipse.che.workspace.infrastructure.kubernetes.GatewayRouterProvisioner;
 import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInternalRuntime;
 import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesRuntimeContext;
 import org.eclipse.che.workspace.infrastructure.kubernetes.RuntimeHangingDetector;
@@ -83,6 +84,7 @@ public OpenShiftInternalRuntime(
       SecretAsContainerResourceProvisioner
           secretAsContainerResourceProvisioner,
       OpenShiftServerResolverFactory serverResolverFactory,
+      GatewayRouterProvisioner gatewayRouterProvisioner,
       Tracer tracer,
       Openshift4TrustedCAProvisioner trustedCAProvisioner,
       @Assisted OpenShiftRuntimeContext context,
@@ -108,6 +110,7 @@ public OpenShiftInternalRuntime(
         previewUrlCommandProvisioner,
         secretAsContainerResourceProvisioner,
         null,
+        gatewayRouterProvisioner,
         tracer,
         context,
         project);
diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntimeTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntimeTest.java
index c0724b5319c..d011f4e8352 100644
--- a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntimeTest.java
+++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntimeTest.java
@@ -192,6 +192,7 @@ public void setup() throws Exception {
             previewUrlCommandProvisioner,
             secretAsContainerResourceProvisioner,
             serverResolverFactory,
+            null,
             tracer,
             trustedCAProvisioner,
             context,
diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java
new file mode 100644
index 00000000000..eec5f8fea6b
--- /dev/null
+++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java
@@ -0,0 +1,74 @@
+package org.eclipse.che.api.workspace.server.spi.environment;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.StringJoiner;
+
+public class GatewayRouteConfig {
+  private final String name;
+  private final String serviceName;
+  private final String servicePort;
+  private final String routePath;
+  private final Map annotations;
+
+  public GatewayRouteConfig(String name, String serviceName, String servicePort,
+      String routePath, Map annotations) {
+    this.name = name;
+    this.serviceName = serviceName;
+    this.servicePort = servicePort;
+    this.routePath = routePath;
+    this.annotations = annotations;
+  }
+
+  @Override
+  public String toString() {
+    return new StringJoiner(", ", GatewayRouteConfig.class.getSimpleName() + "[", "]")
+        .add("name='" + name + "'")
+        .add("serviceName='" + serviceName + "'")
+        .add("servicePort='" + servicePort + "'")
+        .add("routePath='" + routePath + "'")
+        .add("annotations=" + annotations)
+        .toString();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    GatewayRouteConfig that = (GatewayRouteConfig) o;
+    return Objects.equals(name, that.name) &&
+        Objects.equals(serviceName, that.serviceName) &&
+        Objects.equals(servicePort, that.servicePort) &&
+        Objects.equals(routePath, that.routePath) &&
+        Objects.equals(annotations, that.annotations);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(name, serviceName, servicePort, routePath, annotations);
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public String getServiceName() {
+    return serviceName;
+  }
+
+  public String getRoutePath() {
+    return routePath;
+  }
+
+  public Map getAnnotations() {
+    return annotations;
+  }
+
+  public String getServicePort() {
+    return servicePort;
+  }
+}
diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironment.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironment.java
index 80da8a1c4b0..8b6922ed2ef 100644
--- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironment.java
+++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironment.java
@@ -46,6 +46,7 @@ public abstract class InternalEnvironment {
   private Map attributes;
   private List commands;
   private DevfileImpl devfile;
+  private final List gatewayRouteConfigs = new ArrayList<>();
 
   protected InternalEnvironment() {
     this.warnings = new CopyOnWriteArrayList<>();
@@ -192,4 +193,12 @@ public DevfileImpl getDevfile() {
   public void setDevfile(DevfileImpl devfile) {
     this.devfile = devfile;
   }
+
+  public List getGatewayRouteConfigs() {
+    return gatewayRouteConfigs;
+  }
+
+  public void addGatewayRouteConfig(GatewayRouteConfig gatewayRouteConfig) {
+    gatewayRouteConfigs.add(gatewayRouteConfig);
+  }
 }

From e0ec48ceb02f98388bbf15b74ca43fc9a5eb1673 Mon Sep 17 00:00:00 2001
From: Michal Vala 
Date: Wed, 12 Aug 2020 10:33:34 +0200
Subject: [PATCH 07/47] create gateway configmaps in che namespace

Signed-off-by: Michal Vala 
---
 .../che/api/deploy/WsMasterModule.java        |   1 -
 .../kubernetes/GatewayRouterProvisioner.java  |  56 ++++----
 .../kubernetes/KubernetesInfraModule.java     |   2 -
 .../kubernetes/KubernetesInternalRuntime.java |  22 ++-
 .../kubernetes/KubernetesRuntimeContext.java  |   1 -
 .../environment/CheInstallationLocation.java} |  21 +--
 .../kubernetes/namespace/CheNamespace.java    | 136 ++++++++++++++++++
 .../namespace/KubernetesConfigsMaps.java      |   1 -
 .../provision/GatewayTlsProvisioner.java      |   1 -
 .../server/external/GatewayServerExposer.java |  10 +-
 .../TraefikGatewayRouteConfigGenerator.java   |  16 ++-
 .../KubernetesInternalRuntimeTest.java        |   8 +-
 .../external/GatewayServerExposerTest.java    |  46 +++---
 .../TraefikGatewayConfigGeneratorTest.java    |  25 +++-
 .../openshift/OpenShiftInfraModule.java       |  18 ++-
 .../openshift/OpenShiftInternalRuntime.java   |   2 +
 .../oauth/IdentityProviderConfigFactory.java  |   1 +
 ...OpenShiftStopWorkspaceRoleProvisioner.java |   4 +-
 .../Openshift4TrustedCAProvisioner.java       |   4 +-
 ...ShiftStopWorkspaceRoleProvisionerTest.java |   4 +-
 .../Openshift4TrustedCAProvisionerTest.java   |   4 +-
 .../spi/environment/GatewayRouteConfig.java   |  29 +++-
 22 files changed, 309 insertions(+), 103 deletions(-)
 rename infrastructures/{openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftCheInstallationLocation.java => kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java} (59%)
 create mode 100644 infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java

diff --git a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java
index e6c75de4f64..88ddc7aae85 100644
--- a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java
+++ b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java
@@ -89,7 +89,6 @@
 import org.eclipse.che.security.oauth.EmbeddedOAuthAPI;
 import org.eclipse.che.security.oauth.OAuthAPI;
 import org.eclipse.che.security.oauth.OpenShiftOAuthModule;
-import org.eclipse.che.workspace.infrastructure.kubernetes.GatewayRouterProvisioner;
 import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfraModule;
 import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructure;
 import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterProvisioner.java
index 69304ea7702..37560240e9c 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterProvisioner.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterProvisioner.java
@@ -1,30 +1,32 @@
+/*
+ * 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.eclipse.che.workspace.infrastructure.kubernetes.provision.TlsProvisioner.getSecureProtocol;
-
 import com.google.common.collect.ImmutableMap;
 import io.fabric8.kubernetes.api.model.ConfigMap;
 import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.Executor;
 import javax.inject.Inject;
-import javax.inject.Named;
 import javax.inject.Singleton;
 import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
-import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
 import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
 import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig;
 import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironment;
-import org.eclipse.che.api.workspace.server.spi.provision.InternalEnvironmentProvisioner;
-import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespace;
+import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.CheNamespace;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGenerator;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.TraefikGatewayRouteConfigGenerator;
-import org.eclipse.che.workspace.infrastructure.kubernetes.util.KubernetesSharedPool;
 
 @Singleton
 public class GatewayRouterProvisioner {
@@ -35,14 +37,11 @@ public class GatewayRouterProvisioner {
           .put("role", "gateway-config")
           .build();
 
-  private final KubernetesClientFactory clientFactory;
-  private final Executor k8sExecutor;
+  private final CheNamespace cheNamespace;
 
   @Inject
-  public GatewayRouterProvisioner(KubernetesClientFactory clientFactory,
-      KubernetesSharedPool sharedPool) {
-    this.clientFactory = clientFactory;
-    this.k8sExecutor = sharedPool.getExecutor();
+  public GatewayRouterProvisioner(CheNamespace cheNamespace) {
+    this.cheNamespace = cheNamespace;
   }
 
   public List provision(RuntimeIdentity id, InternalEnvironment internalEnvironment)
@@ -51,22 +50,23 @@ public List provision(RuntimeIdentity id, InternalEnvironment interna
       return Collections.emptyList();
     }
     List routeConfigMaps = new ArrayList<>();
-    KubernetesNamespace cheNamespace = new KubernetesNamespace(clientFactory, k8sExecutor, "che",
-        id.getWorkspaceId());
 
     for (GatewayRouteConfig routeConfig : internalEnvironment.getGatewayRouteConfigs()) {
-      GatewayRouteConfigGenerator gatewayRouteConfigGenerator = new TraefikGatewayRouteConfigGenerator(
-          id.getInfrastructureNamespace());
+      GatewayRouteConfigGenerator gatewayRouteConfigGenerator =
+          new TraefikGatewayRouteConfigGenerator(id.getInfrastructureNamespace());
       gatewayRouteConfigGenerator.addRouteConfig(routeConfig);
-      ConfigMapBuilder configMapBuilder = new ConfigMapBuilder()
-          .withNewMetadata()
-          .withName(id.getWorkspaceId() + routeConfig.getName())
-          .withLabels(GATEWAY_CONFIGMAP_LABELS)
-          .withAnnotations(routeConfig.getAnnotations())
-          .endMetadata()
-          .withData(gatewayRouteConfigGenerator.generate());
+      ConfigMapBuilder configMapBuilder =
+          new ConfigMapBuilder()
+              .withNewMetadata()
+              .withName(id.getWorkspaceId() + routeConfig.getName())
+              .withLabels(GATEWAY_CONFIGMAP_LABELS)
+              .withAnnotations(routeConfig.getAnnotations())
+              .endMetadata()
+              .withData(gatewayRouteConfigGenerator.generate());
 
-      ConfigMap routeConfigMap = cheNamespace.configMaps().create(configMapBuilder.build());
+      ConfigMap routeConfigMap =
+          cheNamespace.createConfigMap(configMapBuilder.build(), id.getWorkspaceId());
+      //      ConfigMap routeConfigMap = cheNamespace.configMaps().create(configMapBuilder.build());
       routeConfigMaps.add(routeConfigMap);
     }
 
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java
index e4bfe4c4745..9e36d256434 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java
@@ -70,13 +70,11 @@
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.DefaultHostExternalServiceExposureStrategy;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServerExposer;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServiceExposureStrategy;
-import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGenerator;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayServerExposer;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.IngressServerExposer;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.IngressServiceExposureStrategyProvider;
 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.external.TraefikGatewayRouteConfigGenerator;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposer;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactory;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactoryProvider;
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java
index d12b0ec5919..9c8daa83e83 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java
@@ -85,6 +85,7 @@
 import org.eclipse.che.workspace.infrastructure.kubernetes.environment.PodMerger;
 import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesMachineImpl;
 import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState;
+import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.CheNamespace;
 import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespace;
 import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.event.PodEvent;
 import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.log.LogWatchTimeouts;
@@ -131,7 +132,8 @@ public class KubernetesInternalRuntime
   private final PreviewUrlCommandProvisioner previewUrlCommandProvisioner;
   private final SecretAsContainerResourceProvisioner secretAsContainerResourceProvisioner;
   private final KubernetesServerResolverFactory serverResolverFactory;
-  private final GatewayRouterProvisioner gatewayRouterProvisioner;
+  private final CheNamespace cheNamespace;
+  protected final GatewayRouterProvisioner gatewayRouterProvisioner;
   protected final Tracer tracer;
 
   @Inject
@@ -157,6 +159,7 @@ public KubernetesInternalRuntime(
       SecretAsContainerResourceProvisioner secretAsContainerResourceProvisioner,
       KubernetesServerResolverFactory kubernetesServerResolverFactory,
       GatewayRouterProvisioner gatewayRouterProvisioner,
+      CheNamespace cheNamespace,
       Tracer tracer,
       @Assisted KubernetesRuntimeContext context,
       @Assisted KubernetesNamespace namespace) {
@@ -169,6 +172,7 @@ public KubernetesInternalRuntime(
     this.probeScheduler = probeScheduler;
     this.probesFactory = probesFactory;
     this.namespace = namespace;
+    this.cheNamespace = cheNamespace;
     this.eventPublisher = eventPublisher;
     this.executor = sharedPool.getExecutor();
     this.runtimeStates = runtimeStates;
@@ -193,7 +197,7 @@ protected void internalStart(Map startOptions) throws Infrastruc
       startSynchronizer.setStartThread();
       startSynchronizer.start();
 
-      namespace.cleanUp();
+      cleanUp(workspaceId);
       provisionWorkspace(startOptions, context, workspaceId);
 
       volumesStrategy.prepare(
@@ -258,7 +262,7 @@ protected void internalStart(Map startOptions) throws Infrastruc
       // stop watching before namespace cleaning up
       namespace.deployments().stopWatch(true);
       try {
-        namespace.cleanUp();
+        cleanUp(workspaceId);
       } catch (InfrastructureException cleanUppingEx) {
         LOG.warn(
             "Failed to clean up namespace after workspace '{}' start failing. Cause: {}",
@@ -275,6 +279,11 @@ protected void internalStart(Map startOptions) throws Infrastruc
     }
   }
 
+  private void cleanUp(String workspaceId) throws InfrastructureException {
+    namespace.cleanUp();
+    cheNamespace.cleanUp(workspaceId);
+  }
+
   protected void provisionWorkspace(
       Map startOptions, KubernetesRuntimeContext context, String workspaceId)
       throws InfrastructureException {
@@ -587,7 +596,7 @@ protected void internalStop(Map stopOptions) throws Infrastructu
           // Che Server that is crashed so start is hung up in STOPPING phase.
           // Need to clean up runtime resources
           probeScheduler.cancel(identity.getWorkspaceId());
-          namespace.cleanUp();
+          cleanUp(identity.getWorkspaceId());
         }
       } catch (InterruptedException e) {
         throw new InfrastructureException(
@@ -597,7 +606,7 @@ protected void internalStop(Map stopOptions) throws Infrastructu
       // runtime is RUNNING. Clean up used resources
       // Cancels workspace servers probes if any
       probeScheduler.cancel(identity.getWorkspaceId());
-      namespace.cleanUp();
+      cleanUp(identity.getWorkspaceId());
     }
   }
 
@@ -618,7 +627,8 @@ protected void startMachines() throws InfrastructureException {
 
     createSecrets(k8sEnv, workspaceId);
     List createdConfigMaps = createConfigMaps(k8sEnv, workspaceId);
-    createdConfigMaps.addAll(gatewayRouterProvisioner.provision(getContext().getIdentity(), k8sEnv));
+    createdConfigMaps.addAll(
+        gatewayRouterProvisioner.provision(getContext().getIdentity(), k8sEnv));
     List createdServices = createServices(k8sEnv, workspaceId);
 
     // needed for resolution later on, even though n routes are actually created by ingress
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesRuntimeContext.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesRuntimeContext.java
index baa204beeec..dde6eefd172 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesRuntimeContext.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesRuntimeContext.java
@@ -16,7 +16,6 @@
 import java.util.Optional;
 import javax.inject.Inject;
 import javax.inject.Named;
-import org.eclipse.che.api.core.ValidationException;
 import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
 import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
 import org.eclipse.che.api.workspace.server.spi.InternalInfrastructureException;
diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftCheInstallationLocation.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java
similarity index 59%
rename from infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftCheInstallationLocation.java
rename to infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java
index 8b292f10b1b..ad086529583 100644
--- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftCheInstallationLocation.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java
@@ -9,7 +9,7 @@
  * Contributors:
  *   Red Hat, Inc. - initial API and implementation
  */
-package org.eclipse.che.workspace.infrastructure.openshift.environment;
+package org.eclipse.che.workspace.infrastructure.kubernetes.environment;
 
 import com.google.inject.Inject;
 import javax.inject.Named;
@@ -18,26 +18,29 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * OpenShiftCheInstallationLocation checks the KUBERNETES_NAMESPACE and POD_NAMESPACE environment
- * variables to determine what namespace Che is installed in. Users should use this class to
- * retrieve the installation namespace name.
+ * This class checks the KUBERNETES_NAMESPACE and POD_NAMESPACE environment variables to determine
+ * what namespace Che is installed in. Users should use this class to retrieve the installation
+ * namespace name.
  *
  * @author Tom George
  */
 @Singleton
-public class OpenShiftCheInstallationLocation {
+public class CheInstallationLocation {
 
-  private static final Logger LOG = LoggerFactory.getLogger(OpenShiftCheInstallationLocation.class);
+  private static final Logger LOG = LoggerFactory.getLogger(CheInstallationLocation.class);
 
   @Inject(optional = true)
   @Named("env.KUBERNETES_NAMESPACE")
-  private String kubernetesNamespace = null;
+  private String kubernetesNamespace;
 
   @Inject(optional = true)
   @Named("env.POD_NAMESPACE")
-  private String podNamespace = null;
+  private String podNamespace;
 
-  /** @return The name of the namespace where Che is installed */
+  /**
+   * @return The name of the namespace where Che is installed or null if both {@code
+   *     KUBERNETES_NAMESPACE} and {@code POD_NAMESPACE} environment variables are not set
+   */
   public String getInstallationLocationNamespace() {
     if (kubernetesNamespace == null && podNamespace == null) {
       LOG.warn(
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java
new file mode 100644
index 00000000000..556972e3018
--- /dev/null
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java
@@ -0,0 +1,136 @@
+/*
+ * 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.namespace;
+
+import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_WORKSPACE_ID_LABEL;
+import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.putLabel;
+
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import io.fabric8.kubernetes.client.KubernetesClientException;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import okhttp3.EventListener;
+import org.eclipse.che.api.core.NotFoundException;
+import org.eclipse.che.api.core.ServerException;
+import org.eclipse.che.api.core.model.workspace.Workspace;
+import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
+import org.eclipse.che.api.workspace.server.WorkspaceManager;
+import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
+import org.eclipse.che.commons.annotation.Nullable;
+import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory;
+import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructureException;
+import org.eclipse.che.workspace.infrastructure.kubernetes.environment.CheInstallationLocation;
+
+@Singleton
+public class CheNamespace {
+
+  private final String cheNamespaceName;
+  private final CheKubernetesClientFactory clientFactory;
+  private final WorkspaceManager workspaceManager;
+
+  @Inject
+  public CheNamespace(
+      CheInstallationLocation installationLocation,
+      CheKubernetesClientFactory clientFactory,
+      WorkspaceManager workspaceManager) {
+    this.cheNamespaceName = installationLocation.getInstallationLocationNamespace();
+    this.clientFactory = clientFactory;
+    this.workspaceManager = workspaceManager;
+  }
+
+  public ConfigMap createConfigMap(ConfigMap configMap, String workspaceId)
+      throws InfrastructureException {
+    validate(workspaceId);
+
+    putLabel(configMap, CHE_WORKSPACE_ID_LABEL, workspaceId);
+    try {
+      return clientFactory.create().configMaps().inNamespace(cheNamespaceName).create(configMap);
+    } catch (KubernetesClientException e) {
+      throw new KubernetesInfrastructureException(e);
+    }
+  }
+
+  private void validate(String workspaceId) throws InfrastructureException {
+    if (cheNamespaceName == null) {
+      throw new InfrastructureException("Unable to determine Che installation location");
+    }
+
+    try {
+      Workspace ws = workspaceManager.getWorkspace(workspaceId);
+      if (ws.getStatus() != WorkspaceStatus.STARTING) {
+        throw new InfrastructureException("only for starting workspace");
+      }
+    } catch (NotFoundException | ServerException e) {
+      throw new InfrastructureException(e);
+    }
+  }
+
+  public void cleanUp(String workspaceId) throws InfrastructureException {
+    cleanUpConfigMaps(workspaceId);
+  }
+
+  private void cleanUpConfigMaps(String workspaceId) throws InfrastructureException {
+    try {
+      clientFactory
+          .create()
+          .configMaps()
+          .inNamespace(cheNamespaceName)
+          .withLabel(CHE_WORKSPACE_ID_LABEL, workspaceId)
+          .withPropagationPolicy("Background")
+          .delete();
+    } catch (KubernetesClientException e) {
+      throw new KubernetesInfrastructureException(e);
+    }
+  }
+
+  @Singleton
+  private static class CheKubernetesClientFactory extends KubernetesClientFactory {
+
+    @Inject
+    public CheKubernetesClientFactory(
+        @Nullable @Named("che.infra.kubernetes.master_url") String masterUrl,
+        @Nullable @Named("che.infra.kubernetes.trust_certs") Boolean doTrustCerts,
+        @Named("che.infra.kubernetes.client.http.async_requests.max") int maxConcurrentRequests,
+        @Named("che.infra.kubernetes.client.http.async_requests.max_per_host")
+            int maxConcurrentRequestsPerHost,
+        @Named("che.infra.kubernetes.client.http.connection_pool.max_idle") int maxIdleConnections,
+        @Named("che.infra.kubernetes.client.http.connection_pool.keep_alive_min")
+            int connectionPoolKeepAlive,
+        EventListener eventListener) {
+      super(
+          masterUrl,
+          doTrustCerts,
+          maxConcurrentRequests,
+          maxConcurrentRequestsPerHost,
+          maxIdleConnections,
+          connectionPoolKeepAlive,
+          eventListener);
+    }
+
+    /** @param workspaceId ignored */
+    @Override
+    public KubernetesClient create(String workspaceId) throws InfrastructureException {
+      return create();
+    }
+
+    /**
+     * creates an instance of {@link KubernetesClient} that is meant to be used on Che installation
+     * namespace
+     */
+    @Override
+    public KubernetesClient create() throws InfrastructureException {
+      return super.create();
+    }
+  }
+}
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesConfigsMaps.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesConfigsMaps.java
index 694f87a4ea0..eb14faec307 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesConfigsMaps.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesConfigsMaps.java
@@ -20,7 +20,6 @@
 import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
 import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory;
 import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructureException;
-import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.model.Config;
 
 /**
  * Defines an internal API for managing {@link ConfigMap} instances in {@link
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java
index 63abca14516..42cfc53c1a6 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java
@@ -13,7 +13,6 @@
 
 import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.TlsProvisioner.getSecureProtocol;
 
-import io.fabric8.kubernetes.api.model.ConfigMap;
 import java.util.Map;
 import javax.inject.Inject;
 import javax.inject.Named;
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java
index 5991b965b4a..ddb8479b7a4 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java
@@ -35,8 +35,7 @@ public class GatewayServerExposer
   private final ExternalServiceExposureStrategy strategy;
 
   @Inject
-  public GatewayServerExposer(
-      ExternalServiceExposureStrategy strategy) {
+  public GatewayServerExposer(ExternalServiceExposureStrategy strategy) {
     this.strategy = strategy;
   }
 
@@ -70,7 +69,8 @@ public void expose(
         createGatewayRouteConfig(machineName, serviceName, serverId, servicePort, externalServers));
   }
 
-  private GatewayRouteConfig createGatewayRouteConfig(String machineName,
+  private GatewayRouteConfig createGatewayRouteConfig(
+      String machineName,
       String serviceName,
       String serverId,
       ServicePort servicePort,
@@ -79,8 +79,8 @@ private GatewayRouteConfig createGatewayRouteConfig(String machineName,
     final String name = createName(serviceName, serverName);
     final String path = ensureEndsWithSlash(strategy.getExternalPath(serviceName, serverName));
     final Map annotations = createAnnotations(serversConfigs, path, machineName);
-    return new GatewayRouteConfig(name, serviceName, getTargetPort(servicePort.getTargetPort()),
-        path, annotations);
+    return new GatewayRouteConfig(
+        name, serviceName, getTargetPort(servicePort.getTargetPort()), path, annotations);
   }
 
   private String ensureEndsWithSlash(String path) {
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java
index 0b05e98c701..54dd3dec238 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java
@@ -61,9 +61,9 @@ public TraefikGatewayRouteConfigGenerator(String serviceNamespace) {
   /**
    * Generates Traefik specific configuration for single service.
    *
-   * @param name       name of the service
+   * @param name name of the service
    * @param serviceUrl url of service we want to route to
-   * @param path       path to route and strip
+   * @param path path to route and strip
    * @return traefik service route config
    */
   public String generate(String name, String serviceUrl, String path) {
@@ -189,16 +189,18 @@ public void addRouteConfig(GatewayRouteConfig routeConfig) {
   public Map generate() {
     Map cmData = new HashMap<>();
     for (GatewayRouteConfig routeConfig : routeConfigs) {
-      String traefikRouteConfig = generate(routeConfig.getName(),
-          createServiceUrl(routeConfig.getServiceName(), routeConfig.getServicePort()),
-          routeConfig.getRoutePath());
+      String traefikRouteConfig =
+          generate(
+              routeConfig.getName(),
+              createServiceUrl(routeConfig.getServiceName(), routeConfig.getServicePort()),
+              routeConfig.getRoutePath());
       cmData.put(routeConfig.getName() + ".yml", traefikRouteConfig);
     }
     return cmData;
   }
 
   private String createServiceUrl(String serviceName, String servicePort) {
-    return String
-        .format("http://%s.%s.svc.cluster.local:%s", serviceName, serviceNamespace, servicePort);
+    return String.format(
+        "http://%s.%s.svc.cluster.local:%s", serviceName, serviceNamespace, servicePort);
   }
 }
diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java
index 404050966f2..4b8a056fd38 100644
--- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java
+++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java
@@ -121,6 +121,7 @@
 import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeCommandImpl;
 import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState;
 import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesServerImpl;
+import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.CheNamespace;
 import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesConfigsMaps;
 import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesDeployments;
 import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesIngresses;
@@ -196,6 +197,7 @@ public class KubernetesInternalRuntimeTest {
   @Mock private UnrecoverablePodEventListenerFactory unrecoverablePodEventListenerFactory;
   @Mock private KubernetesEnvironment k8sEnv;
   @Mock private KubernetesNamespace namespace;
+  @Mock private CheNamespace cheNamespace;
   @Mock private KubernetesServices services;
   @Mock private KubernetesIngresses ingresses;
   @Mock private KubernetesSecrets secrets;
@@ -211,6 +213,7 @@ public class KubernetesInternalRuntimeTest {
   @Mock private RuntimeHangingDetector runtimeHangingDetector;
   @Mock private KubernetesPreviewUrlCommandProvisioner previewUrlCommandProvisioner;
   @Mock private SecretAsContainerResourceProvisioner secretAsContainerResourceProvisioner;
+  @Mock private GatewayRouterProvisioner gatewayRouterProvisioner;
   private KubernetesServerResolverFactory serverResolverFactory;
 
   @Mock
@@ -264,7 +267,7 @@ public void setup() throws Exception {
     when(startSynchronizerFactory.create(any())).thenReturn(startSynchronizer);
 
     internalRuntime =
-        new KubernetesInternalRuntime(
+        new KubernetesInternalRuntime<>(
             13,
             5,
             new URLRewriter.NoOpURLRewriter(),
@@ -285,7 +288,8 @@ public void setup() throws Exception {
             previewUrlCommandProvisioner,
             secretAsContainerResourceProvisioner,
             serverResolverFactory,
-            null,
+            gatewayRouterProvisioner,
+            cheNamespace,
             tracer,
             context,
             namespace);
diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java
index 07625dc79c0..ee4a8821b52 100644
--- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java
+++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java
@@ -1,4 +1,15 @@
-///*
+/*
+ * 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
+ */
+/// *
 // * 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
@@ -9,24 +20,25 @@
 // * Contributors:
 // *   Red Hat, Inc. - initial API and implementation
 // */
-//package org.eclipse.che.workspace.infrastructure.kubernetes.server.external;
+// package org.eclipse.che.workspace.infrastructure.kubernetes.server.external;
 //
-//import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayServerExposer.GATEWAY_CONFIGMAP_LABELS;
-//import static org.testng.Assert.assertEquals;
-//import static org.testng.Assert.assertTrue;
+// import static
+// org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayServerExposer.GATEWAY_CONFIGMAP_LABELS;
+// import static org.testng.Assert.assertEquals;
+// import static org.testng.Assert.assertTrue;
 //
-//import io.fabric8.kubernetes.api.model.ConfigMap;
-//import io.fabric8.kubernetes.api.model.IntOrString;
-//import io.fabric8.kubernetes.api.model.ServicePort;
-//import java.util.Collections;
-//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.environment.KubernetesEnvironment;
-//import org.testng.annotations.Test;
+// import io.fabric8.kubernetes.api.model.ConfigMap;
+// import io.fabric8.kubernetes.api.model.IntOrString;
+// import io.fabric8.kubernetes.api.model.ServicePort;
+// import java.util.Collections;
+// 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.environment.KubernetesEnvironment;
+// import org.testng.annotations.Test;
 //
-//public class GatewayServerExposerTest {
+// public class GatewayServerExposerTest {
 //
 //  private final String machineName = "machine";
 //  private final String serviceName = "service";
@@ -75,4 +87,4 @@
 //    assertEquals(s1.getProtocol(), "ws");
 //    assertEquals(s1.getPath(), "/service/server/");
 //  }
-//}
+// }
diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java
index 2b39ef82456..157685109a1 100644
--- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java
+++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java
@@ -1,4 +1,15 @@
-///*
+/*
+ * 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
+ */
+/// *
 // * 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
@@ -9,14 +20,14 @@
 // * Contributors:
 // *   Red Hat, Inc. - initial API and implementation
 // */
-//package org.eclipse.che.workspace.infrastructure.kubernetes.server.external;
+// package org.eclipse.che.workspace.infrastructure.kubernetes.server.external;
 //
-//import static org.testng.Assert.*;
+// import static org.testng.Assert.*;
 //
-//import java.util.Map;
-//import org.testng.annotations.Test;
+// import java.util.Map;
+// import org.testng.annotations.Test;
 //
-//public class TraefikGatewayConfigGeneratorTest {
+// public class TraefikGatewayConfigGeneratorTest {
 //  private final GatewayRouteConfigGenerator gatewayConfigGenerator =
 //      new TraefikGatewayRouteConfigGenerator();
 //
@@ -49,4 +60,4 @@
 //    assertTrue(generatedConfig.containsKey("external-server-1.yml"));
 //    assertEquals(generatedConfig.get("external-server-1.yml"), expectedConfig);
 //  }
-//}
+// }
diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java
index 9c167bf8c48..c78c950b5e4 100644
--- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java
+++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java
@@ -17,6 +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.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;
@@ -68,9 +71,12 @@
 import org.eclipse.che.workspace.infrastructure.kubernetes.provision.server.ServersConverter;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.PreviewUrlExposer;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.WorkspaceExposureType;
+import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.DefaultHostExternalServiceExposureStrategy;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServerExposer;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServiceExposureStrategy;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayServerExposer;
+import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.IngressServiceExposureStrategyProvider;
+import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.SingleHostExternalServiceExposureStrategy;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposer;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactory;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactoryProvider;
@@ -249,7 +255,17 @@ protected void configure() {
     KubernetesDevfileBindings.addAllowedEnvironmentTypeUpgradeBindings(
         binder(), OpenShiftEnvironment.TYPE, KubernetesEnvironment.TYPE);
 
-    bind(ExternalServiceExposureStrategy.class).to(OpenShiftServerExposureStrategy.class);
+    MapBinder ingressStrategies =
+        MapBinder.newMapBinder(binder(), String.class, ExternalServiceExposureStrategy.class);
+    ingressStrategies.addBinding(MULTI_HOST_STRATEGY).to(OpenShiftServerExposureStrategy.class);
+    ingressStrategies
+        .addBinding(SINGLE_HOST_STRATEGY)
+        .to(SingleHostExternalServiceExposureStrategy.class);
+    ingressStrategies
+        .addBinding(DEFAULT_HOST_STRATEGY)
+        .to(DefaultHostExternalServiceExposureStrategy.class);
+    bind(ExternalServiceExposureStrategy.class)
+        .toProvider(IngressServiceExposureStrategyProvider.class);
     bind(CookiePathStrategy.class).to(OpenShiftCookiePathStrategy.class);
     bind(NonTlsDistributedClusterModeNotifier.class);
     bind(AsyncStorageProvisioner.class);
diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java
index 56d21c07cd6..0159b2c4d42 100644
--- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java
+++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java
@@ -111,6 +111,7 @@ public OpenShiftInternalRuntime(
         secretAsContainerResourceProvisioner,
         null,
         gatewayRouterProvisioner,
+        null,
         tracer,
         context,
         project);
@@ -137,6 +138,7 @@ protected void startMachines() throws InfrastructureException {
 
     createSecrets(osEnv, workspaceId);
     List createdConfigMaps = createConfigMaps(osEnv, workspaceId);
+    createdConfigMaps.addAll(gatewayRouterProvisioner.provision(getContext().getIdentity(), osEnv));
     List createdServices = createServices(osEnv, workspaceId);
     List createdRoutes = createRoutes(osEnv, workspaceId);
 
diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/multiuser/oauth/IdentityProviderConfigFactory.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/multiuser/oauth/IdentityProviderConfigFactory.java
index 2d741e44186..83f4e057ba8 100644
--- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/multiuser/oauth/IdentityProviderConfigFactory.java
+++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/multiuser/oauth/IdentityProviderConfigFactory.java
@@ -118,6 +118,7 @@ public boolean isPersonalized() {
    * Builds the OpenShift {@link Config} object based on a default {@link Config} object and an
    * optional workspace Id.
    */
+  @Override
   public Config buildConfig(Config defaultConfig, @Nullable String workspaceId)
       throws InfrastructureException {
     Subject subject = EnvironmentContext.getCurrent().getSubject();
diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/OpenShiftStopWorkspaceRoleProvisioner.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/OpenShiftStopWorkspaceRoleProvisioner.java
index 28e0f255f95..9efc6849d66 100644
--- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/OpenShiftStopWorkspaceRoleProvisioner.java
+++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/OpenShiftStopWorkspaceRoleProvisioner.java
@@ -21,8 +21,8 @@
 import javax.inject.Inject;
 import javax.inject.Named;
 import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
+import org.eclipse.che.workspace.infrastructure.kubernetes.environment.CheInstallationLocation;
 import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftClientFactory;
-import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftCheInstallationLocation;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,7 +44,7 @@ public class OpenShiftStopWorkspaceRoleProvisioner {
   @Inject
   public OpenShiftStopWorkspaceRoleProvisioner(
       OpenShiftClientFactory clientFactory,
-      OpenShiftCheInstallationLocation installationLocation,
+      CheInstallationLocation installationLocation,
       @Named("che.workspace.stop.role.enabled") boolean stopWorkspaceRoleEnabled) {
     this.clientFactory = clientFactory;
     this.installationLocation = installationLocation.getInstallationLocationNamespace();
diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisioner.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisioner.java
index 6e2dcac442b..dbd31428388 100644
--- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisioner.java
+++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisioner.java
@@ -26,11 +26,11 @@
 import javax.inject.Named;
 import javax.inject.Singleton;
 import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
+import org.eclipse.che.workspace.infrastructure.kubernetes.environment.CheInstallationLocation;
 import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
 import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData;
 import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodRole;
 import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftClientFactory;
-import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftCheInstallationLocation;
 import org.eclipse.che.workspace.infrastructure.openshift.project.OpenShiftProject;
 
 /**
@@ -53,7 +53,7 @@ public Openshift4TrustedCAProvisioner(
       @Named("che.infra.openshift.trusted_ca_bundles_config_map") String configMapName,
       @Named("che.infra.openshift.trusted_ca_bundles_config_map_labels") String configMapLabel,
       @Named("che.infra.openshift.trusted_ca_bundles_mount_path") String certificateMountPath,
-      OpenShiftCheInstallationLocation cheInstallationLocation,
+      CheInstallationLocation cheInstallationLocation,
       OpenShiftClientFactory clientFactory)
       throws InfrastructureException {
     this.configMapName = configMapName;
diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/OpenShiftStopWorkspaceRoleProvisionerTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/OpenShiftStopWorkspaceRoleProvisionerTest.java
index 99d82964123..f188a459e3a 100644
--- a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/OpenShiftStopWorkspaceRoleProvisionerTest.java
+++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/OpenShiftStopWorkspaceRoleProvisionerTest.java
@@ -36,8 +36,8 @@
 import io.fabric8.openshift.api.model.PolicyRuleBuilder;
 import io.fabric8.openshift.client.OpenShiftClient;
 import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
+import org.eclipse.che.workspace.infrastructure.kubernetes.environment.CheInstallationLocation;
 import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftClientFactory;
-import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftCheInstallationLocation;
 import org.mockito.Mock;
 import org.mockito.testng.MockitoTestNGListener;
 import org.testng.annotations.BeforeMethod;
@@ -52,7 +52,7 @@
 @Listeners(MockitoTestNGListener.class)
 public class OpenShiftStopWorkspaceRoleProvisionerTest {
 
-  @Mock private OpenShiftCheInstallationLocation cheInstallationLocation;
+  @Mock private CheInstallationLocation cheInstallationLocation;
   private OpenShiftStopWorkspaceRoleProvisioner stopWorkspaceRoleProvisioner;
 
   @Mock private OpenShiftClientFactory clientFactory;
diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisionerTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisionerTest.java
index a284d19def2..3b9e9870d56 100644
--- a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisionerTest.java
+++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisionerTest.java
@@ -37,11 +37,11 @@
 import io.fabric8.openshift.client.OpenShiftClient;
 import java.util.HashMap;
 import java.util.Map;
+import org.eclipse.che.workspace.infrastructure.kubernetes.environment.CheInstallationLocation;
 import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
 import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData;
 import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesConfigsMaps;
 import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftClientFactory;
-import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftCheInstallationLocation;
 import org.eclipse.che.workspace.infrastructure.openshift.project.OpenShiftProject;
 import org.mockito.Mock;
 import org.mockito.testng.MockitoTestNGListener;
@@ -59,7 +59,7 @@ public class Openshift4TrustedCAProvisionerTest {
   private static final String CONFIGMAP_KEY = "testConfigMapKey";
   private static final String CONFIGMAP_VALUE = "testConfigMapValue";
 
-  @Mock OpenShiftCheInstallationLocation cheInstallationLocation;
+  @Mock CheInstallationLocation cheInstallationLocation;
   @Mock OpenShiftClientFactory clientFactory;
 
   @Mock private KubernetesEnvironment k8sEnv;
diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java
index eec5f8fea6b..83769d03958 100644
--- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java
+++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java
@@ -1,3 +1,14 @@
+/*
+ * 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.api.workspace.server.spi.environment;
 
 import java.util.Map;
@@ -11,8 +22,12 @@ public class GatewayRouteConfig {
   private final String routePath;
   private final Map annotations;
 
-  public GatewayRouteConfig(String name, String serviceName, String servicePort,
-      String routePath, Map annotations) {
+  public GatewayRouteConfig(
+      String name,
+      String serviceName,
+      String servicePort,
+      String routePath,
+      Map annotations) {
     this.name = name;
     this.serviceName = serviceName;
     this.servicePort = servicePort;
@@ -40,11 +55,11 @@ public boolean equals(Object o) {
       return false;
     }
     GatewayRouteConfig that = (GatewayRouteConfig) o;
-    return Objects.equals(name, that.name) &&
-        Objects.equals(serviceName, that.serviceName) &&
-        Objects.equals(servicePort, that.servicePort) &&
-        Objects.equals(routePath, that.routePath) &&
-        Objects.equals(annotations, that.annotations);
+    return Objects.equals(name, that.name)
+        && Objects.equals(serviceName, that.serviceName)
+        && Objects.equals(servicePort, that.servicePort)
+        && Objects.equals(routePath, that.routePath)
+        && Objects.equals(annotations, that.annotations);
   }
 
   @Override

From 641d6ae533b43b97904c898697bb2f4967b534af Mon Sep 17 00:00:00 2001
From: Michal Vala 
Date: Wed, 12 Aug 2020 14:54:43 +0200
Subject: [PATCH 08/47] gateway prefix path without slash

Signed-off-by: Michal Vala 
---
 .../infrastructure/kubernetes/GatewayRouterProvisioner.java | 2 +-
 .../infrastructure/kubernetes/namespace/CheNamespace.java   | 6 ++++++
 .../kubernetes/server/external/GatewayServerExposer.java    | 6 +++---
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterProvisioner.java
index 37560240e9c..b82774e970b 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterProvisioner.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterProvisioner.java
@@ -55,6 +55,7 @@ public List provision(RuntimeIdentity id, InternalEnvironment interna
       GatewayRouteConfigGenerator gatewayRouteConfigGenerator =
           new TraefikGatewayRouteConfigGenerator(id.getInfrastructureNamespace());
       gatewayRouteConfigGenerator.addRouteConfig(routeConfig);
+
       ConfigMapBuilder configMapBuilder =
           new ConfigMapBuilder()
               .withNewMetadata()
@@ -66,7 +67,6 @@ public List provision(RuntimeIdentity id, InternalEnvironment interna
 
       ConfigMap routeConfigMap =
           cheNamespace.createConfigMap(configMapBuilder.build(), id.getWorkspaceId());
-      //      ConfigMap routeConfigMap = cheNamespace.configMaps().create(configMapBuilder.build());
       routeConfigMaps.add(routeConfigMap);
     }
 
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java
index 556972e3018..8653cd70c35 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java
@@ -15,6 +15,7 @@
 import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.putLabel;
 
 import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.client.Config;
 import io.fabric8.kubernetes.client.KubernetesClient;
 import io.fabric8.kubernetes.client.KubernetesClientException;
 import javax.inject.Inject;
@@ -132,5 +133,10 @@ public KubernetesClient create(String workspaceId) throws InfrastructureExceptio
     public KubernetesClient create() throws InfrastructureException {
       return super.create();
     }
+
+    @Override
+    protected Config buildConfig(Config config, String workspaceId) {
+      return config;
+    }
   }
 }
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java
index ddb8479b7a4..cf89772fd04 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java
@@ -77,14 +77,14 @@ private GatewayRouteConfig createGatewayRouteConfig(
       Map serversConfigs) {
     final String serverName = KubernetesServerExposer.makeServerNameValidForDns(serverId);
     final String name = createName(serviceName, serverName);
-    final String path = ensureEndsWithSlash(strategy.getExternalPath(serviceName, serverName));
+    final String path = ensureDontEndsWithSlash(strategy.getExternalPath(serviceName, serverName));
     final Map annotations = createAnnotations(serversConfigs, path, machineName);
     return new GatewayRouteConfig(
         name, serviceName, getTargetPort(servicePort.getTargetPort()), path, annotations);
   }
 
-  private String ensureEndsWithSlash(String path) {
-    return path.endsWith("/") ? path : path + '/';
+  private String ensureDontEndsWithSlash(String path) {
+    return path.endsWith("/") ? path.substring(0, path.length() - 1) : path;
   }
 
   private String createName(String serviceName, String serverName) {

From 2fcd61d2b77c6dbea6ce7b5f589eb9b888b4aaad Mon Sep 17 00:00:00 2001
From: Michal Vala 
Date: Wed, 12 Aug 2020 15:04:19 +0200
Subject: [PATCH 09/47] cleanup

Signed-off-by: Michal Vala 
---
 .../openshift/provision/Openshift4TrustedCAProvisionerTest.java | 2 --
 1 file changed, 2 deletions(-)

diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisionerTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisionerTest.java
index 8cdd300d003..919eb9d3b4b 100644
--- a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisionerTest.java
+++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/Openshift4TrustedCAProvisionerTest.java
@@ -28,7 +28,6 @@
 import io.fabric8.openshift.client.OpenShiftClient;
 import java.util.HashMap;
 import java.util.Map;
-import org.eclipse.che.workspace.infrastructure.kubernetes.environment.CheInstallationLocation;
 import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
 import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData;
 import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesConfigsMaps;
@@ -50,7 +49,6 @@ public class Openshift4TrustedCAProvisionerTest {
   private static final String CONFIGMAP_KEY = "testConfigMapKey";
   private static final String CONFIGMAP_VALUE = "testConfigMapValue";
 
-  @Mock CheInstallationLocation cheInstallationLocation;
   @Mock OpenShiftClientFactory clientFactory;
 
   @Mock private KubernetesEnvironment k8sEnv;

From b9de1888185d5f3fcfa3e82ce6f09366dd8bd4cd Mon Sep 17 00:00:00 2001
From: Michal Vala 
Date: Wed, 12 Aug 2020 16:44:53 +0200
Subject: [PATCH 10/47] rename GatewayRouterProvisioner to Resolver and create
 configmaps in InternalRuntime, error when KUBERNETES_NAMESPACE and
 POD_NAMESPACE are both null

Signed-off-by: Michal Vala 
---
 ...sioner.java => GatewayRouterResolver.java} | 27 +++---
 .../kubernetes/KubernetesInternalRuntime.java | 19 ++--
 .../environment/CheInstallationLocation.java  |  6 +-
 .../kubernetes/namespace/CheNamespace.java    |  2 +-
 .../external/GatewayRouteConfigGenerator.java | 32 +++++--
 .../GatewayRouteConfigGeneratorFactory.java   | 11 +++
 .../TraefikGatewayRouteConfigGenerator.java   | 96 ++++++++++---------
 .../KubernetesInternalRuntimeTest.java        |  2 +-
 .../openshift/OpenShiftInternalRuntime.java   | 25 ++---
 ...OpenShiftStopWorkspaceRoleProvisioner.java |  3 +-
 .../OpenShiftInternalRuntimeTest.java         |  7 +-
 ...ShiftStopWorkspaceRoleProvisionerTest.java |  2 +-
 12 files changed, 132 insertions(+), 100 deletions(-)
 rename infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/{GatewayRouterProvisioner.java => GatewayRouterResolver.java} (71%)
 create mode 100644 infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java

diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolver.java
similarity index 71%
rename from infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterProvisioner.java
rename to infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolver.java
index b82774e970b..7607a5a8d88 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterProvisioner.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolver.java
@@ -21,15 +21,18 @@
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
-import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
 import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig;
 import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironment;
-import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.CheNamespace;
 import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGenerator;
-import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.TraefikGatewayRouteConfigGenerator;
+import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGeneratorFactory;
 
+/**
+ * Resolves {@link GatewayRouteConfig}s from {@link InternalEnvironment} into {@link ConfigMap}s.
+ * Created instance of {@link ConfigMap} is annotated with {@link GatewayRouterResolver#GATEWAY_CONFIGMAP_LABELS},
+ * which are needed so Configbump tool can pick them up and provide them to the Gateway pod.
+ */
 @Singleton
-public class GatewayRouterProvisioner {
+public class GatewayRouterResolver {
 
   protected static final Map GATEWAY_CONFIGMAP_LABELS =
       ImmutableMap.builder()
@@ -37,15 +40,15 @@ public class GatewayRouterProvisioner {
           .put("role", "gateway-config")
           .build();
 
-  private final CheNamespace cheNamespace;
+  private final GatewayRouteConfigGeneratorFactory configGeneratorFactory;
 
   @Inject
-  public GatewayRouterProvisioner(CheNamespace cheNamespace) {
-    this.cheNamespace = cheNamespace;
+  public GatewayRouterResolver(
+      GatewayRouteConfigGeneratorFactory configGeneratorFactory) {
+    this.configGeneratorFactory = configGeneratorFactory;
   }
 
-  public List provision(RuntimeIdentity id, InternalEnvironment internalEnvironment)
-      throws InfrastructureException {
+  public List resolve(RuntimeIdentity id, InternalEnvironment internalEnvironment) {
     if (internalEnvironment.getGatewayRouteConfigs().isEmpty()) {
       return Collections.emptyList();
     }
@@ -53,7 +56,7 @@ public List provision(RuntimeIdentity id, InternalEnvironment interna
 
     for (GatewayRouteConfig routeConfig : internalEnvironment.getGatewayRouteConfigs()) {
       GatewayRouteConfigGenerator gatewayRouteConfigGenerator =
-          new TraefikGatewayRouteConfigGenerator(id.getInfrastructureNamespace());
+          configGeneratorFactory.create(id.getInfrastructureNamespace());
       gatewayRouteConfigGenerator.addRouteConfig(routeConfig);
 
       ConfigMapBuilder configMapBuilder =
@@ -65,9 +68,7 @@ public List provision(RuntimeIdentity id, InternalEnvironment interna
               .endMetadata()
               .withData(gatewayRouteConfigGenerator.generate());
 
-      ConfigMap routeConfigMap =
-          cheNamespace.createConfigMap(configMapBuilder.build(), id.getWorkspaceId());
-      routeConfigMaps.add(routeConfigMap);
+      routeConfigMaps.add(configMapBuilder.build());
     }
 
     return routeConfigMaps;
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java
index 9c8daa83e83..4dc63cb28ee 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java
@@ -132,8 +132,8 @@ public class KubernetesInternalRuntime
   private final PreviewUrlCommandProvisioner previewUrlCommandProvisioner;
   private final SecretAsContainerResourceProvisioner secretAsContainerResourceProvisioner;
   private final KubernetesServerResolverFactory serverResolverFactory;
-  private final CheNamespace cheNamespace;
-  protected final GatewayRouterProvisioner gatewayRouterProvisioner;
+  protected final CheNamespace cheNamespace;
+  protected final GatewayRouterResolver gatewayRouterResolver;
   protected final Tracer tracer;
 
   @Inject
@@ -158,7 +158,7 @@ public KubernetesInternalRuntime(
       PreviewUrlCommandProvisioner previewUrlCommandProvisioner,
       SecretAsContainerResourceProvisioner secretAsContainerResourceProvisioner,
       KubernetesServerResolverFactory kubernetesServerResolverFactory,
-      GatewayRouterProvisioner gatewayRouterProvisioner,
+      GatewayRouterResolver gatewayRouterResolver,
       CheNamespace cheNamespace,
       Tracer tracer,
       @Assisted KubernetesRuntimeContext context,
@@ -186,7 +186,7 @@ public KubernetesInternalRuntime(
     this.secretAsContainerResourceProvisioner = secretAsContainerResourceProvisioner;
     this.serverResolverFactory = kubernetesServerResolverFactory;
     this.tracer = tracer;
-    this.gatewayRouterProvisioner = gatewayRouterProvisioner;
+    this.gatewayRouterResolver = gatewayRouterResolver;
   }
 
   @Override
@@ -626,9 +626,7 @@ protected void startMachines() throws InfrastructureException {
     String workspaceId = getContext().getIdentity().getWorkspaceId();
 
     createSecrets(k8sEnv, workspaceId);
-    List createdConfigMaps = createConfigMaps(k8sEnv, workspaceId);
-    createdConfigMaps.addAll(
-        gatewayRouterProvisioner.provision(getContext().getIdentity(), k8sEnv));
+    List createdConfigMaps = createConfigMaps(k8sEnv, getContext().getIdentity());
     List createdServices = createServices(k8sEnv, workspaceId);
 
     // needed for resolution later on, even though n routes are actually created by ingress
@@ -699,14 +697,17 @@ void createSecrets(KubernetesEnvironment env, String workspaceId) throws Infrast
 
   @Traced
   @SuppressWarnings("WeakerAccess") // package-private so that interception is possible
-  List createConfigMaps(KubernetesEnvironment env, String workspaceId)
+  protected List createConfigMaps(KubernetesEnvironment env, RuntimeIdentity identity)
       throws InfrastructureException {
-    TracingTags.WORKSPACE_ID.set(workspaceId);
+    TracingTags.WORKSPACE_ID.set(identity.getWorkspaceId());
 
     List createdConfigMaps = new ArrayList<>();
     for (ConfigMap configMap : env.getConfigMaps().values()) {
       createdConfigMaps.add(namespace.configMaps().create(configMap));
     }
+    for (ConfigMap routeConfigMap : gatewayRouterResolver.resolve(identity, env)) {
+      createdConfigMaps.add(cheNamespace.createConfigMap(routeConfigMap, identity.getWorkspaceId()));
+    }
     return createdConfigMaps;
   }
 
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java
index ad086529583..bd4569c2090 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java
@@ -14,6 +14,7 @@
 import com.google.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
+import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,10 +42,9 @@ public class CheInstallationLocation {
    * @return The name of the namespace where Che is installed or null if both {@code
    *     KUBERNETES_NAMESPACE} and {@code POD_NAMESPACE} environment variables are not set
    */
-  public String getInstallationLocationNamespace() {
+  public String getInstallationLocationNamespace() throws InfrastructureException {
     if (kubernetesNamespace == null && podNamespace == null) {
-      LOG.warn(
-          "Neither KUBERNETES_NAMESPACE nor POD_NAMESPACE is defined. Unable to determine Che installation location");
+      throw new InfrastructureException("Neither KUBERNETES_NAMESPACE nor POD_NAMESPACE is defined. Unable to determine Che installation location");
     }
     return kubernetesNamespace == null ? podNamespace : kubernetesNamespace;
   }
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java
index 8653cd70c35..0a0eba16c55 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java
@@ -44,7 +44,7 @@ public class CheNamespace {
   public CheNamespace(
       CheInstallationLocation installationLocation,
       CheKubernetesClientFactory clientFactory,
-      WorkspaceManager workspaceManager) {
+      WorkspaceManager workspaceManager) throws InfrastructureException {
     this.cheNamespaceName = installationLocation.getInstallationLocationNamespace();
     this.clientFactory = clientFactory;
     this.workspaceManager = workspaceManager;
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java
index ce255b5f3ed..04ca2d080d8 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java
@@ -15,26 +15,42 @@
 import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig;
 
 /**
- * Generates config for single external server that we want to expose in the Gateway.
+ * Generates config for external servers that we want to expose in the Gateway.
+ *
+ * 

Implementation must accept new {@link GatewayRouteConfig}s with {@link + * GatewayRouteConfigGenerator#addRouteConfig(GatewayRouteConfig)}. Then call to {@link + * GatewayRouteConfigGenerator#generate()} must generate gateway specific configuration for all + * added {@link GatewayRouteConfig}s. * *

Implementation provides configuration for specific Gateway technology (e.g., Traefik). */ public interface GatewayRouteConfigGenerator { + + /** + * Add {@link GatewayRouteConfig} to the generator so it can be generated later with {@link + * GatewayRouteConfigGenerator#generate()} + * + * @param routeConfig config to add + */ void addRouteConfig(GatewayRouteConfig routeConfig); /** - * Generates content of configuration for service, defined by passed parameters, that should be - * exposed by the Gateway. Returned {@code Map} will be used as a value of - * ConfigMap. + * Generates content of configurations for services, defined earlier by added {@link + * GatewayRouteConfig}s with {@link GatewayRouteConfigGenerator#addRouteConfig(GatewayRouteConfig)}. + * Returned {@code Map} will be used as a value of ConfigMap and injected into + * Gateway pod. * *

Implementation must ensure that Gateway configured with returned content will route the * requests on {@code path} into {@code serviceUrl}. Also it must strip {@code path} from request * url. * - * @param name name of the service - * @param serviceUrl url of service we want to route to - * @param path path to route and strip - * @return full content of configuration for the service + *

Keys and Values of returned {@link Map} depends on gateway technology. e.g.: + *

+   *   service1.yml: {config-content-for-service-1}
+   *   service2.yml: {config-content-for-service-2}
+   * 
+ * + * @return full content of configuration for the services */ Map generate(); } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java new file mode 100644 index 00000000000..74c3fcc2f8e --- /dev/null +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java @@ -0,0 +1,11 @@ +package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; + +import javax.inject.Singleton; + +@Singleton +public class GatewayRouteConfigGeneratorFactory { + + public GatewayRouteConfigGenerator create(String namespace) { + return new TraefikGatewayRouteConfigGenerator(namespace); + } +} diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java index 54dd3dec238..c69512c7375 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java @@ -24,29 +24,7 @@ import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; /** - * Traefik configuration for single route looks like this (values in {} are parameters of {link - * GatewayRouteConfigGenerator#generate(String, String, String)} method): - * - *
- * http:
- *   routers:
- *     {name}:
- *       rule: "PathPrefix(`{path}`)"
- *       service: {name}
- *       middlewares:
- *       - "{name}"
- *       priority: 100
- *   services:
- *     {name}:
- *       loadBalancer:
- *         servers:
- *         - url: '{serviceUrl}'
- *   middlewares:
- *     {name}:
- *       stripPrefix:
- *         prefixes:
- *         - "{path}"
- * 
+ * Config generator for Traefik Gateway */ public class TraefikGatewayRouteConfigGenerator implements GatewayRouteConfigGenerator { @@ -58,15 +36,62 @@ public TraefikGatewayRouteConfigGenerator(String serviceNamespace) { this.serviceNamespace = serviceNamespace; } + @Override + public void addRouteConfig(GatewayRouteConfig routeConfig) { + this.routeConfigs.add(routeConfig); + } + + /** + * Generate Traefik configuration for all added {@link GatewayRouteConfig}s. + *

+ * Each {@link GatewayRouteConfig} is translated into Traefik configuration under extra key in + * returned {@link Map} `{GatewayRouteConfig#name}.yml`. + *

+ * Content of single service configuration looks like this: + *

+   * http:
+   *   routers:
+   *     {name}:
+   *       rule: "PathPrefix(`{GatewayRouteConfig#routePath}`)"
+   *       service: {GatewayRouteConfig#name}
+   *       middlewares:
+   *       - "{GatewayRouteConfig#name}"
+   *       priority: 100
+   *   services:
+   *     {name}:
+   *       loadBalancer:
+   *         servers:
+   *         - url: '{serviceUrl}'
+   *   middlewares:
+   *     {name}:
+   *       stripPrefix:
+   *         prefixes:
+   *         - "{GatewayRouteConfig#routePath}"
+   * 
+ */ + @Override + public Map generate() { + Map cmData = new HashMap<>(); + for (GatewayRouteConfig routeConfig : routeConfigs) { + String traefikRouteConfig = + generate( + routeConfig.getName(), + createServiceUrl(routeConfig.getServiceName(), routeConfig.getServicePort()), + routeConfig.getRoutePath()); + cmData.put(routeConfig.getName() + ".yml", traefikRouteConfig); + } + return cmData; + } + /** * Generates Traefik specific configuration for single service. * - * @param name name of the service + * @param name name of the service * @param serviceUrl url of service we want to route to - * @param path path to route and strip + * @param path path to route and strip * @return traefik service route config */ - public String generate(String name, String serviceUrl, String path) { + private String generate(String name, String serviceUrl, String path) { StringWriter sw = new StringWriter(); try { YAMLGenerator generator = @@ -180,25 +205,6 @@ private void generateMiddlewares(YAMLGenerator generator, String name, String pa generator.writeEndObject(); } - @Override - public void addRouteConfig(GatewayRouteConfig routeConfig) { - this.routeConfigs.add(routeConfig); - } - - @Override - public Map generate() { - Map cmData = new HashMap<>(); - for (GatewayRouteConfig routeConfig : routeConfigs) { - String traefikRouteConfig = - generate( - routeConfig.getName(), - createServiceUrl(routeConfig.getServiceName(), routeConfig.getServicePort()), - routeConfig.getRoutePath()); - cmData.put(routeConfig.getName() + ".yml", traefikRouteConfig); - } - return cmData; - } - private String createServiceUrl(String serviceName, String servicePort) { return String.format( "http://%s.%s.svc.cluster.local:%s", serviceName, serviceNamespace, servicePort); diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java index 4b8a056fd38..00e2538b430 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java @@ -213,7 +213,7 @@ public class KubernetesInternalRuntimeTest { @Mock private RuntimeHangingDetector runtimeHangingDetector; @Mock private KubernetesPreviewUrlCommandProvisioner previewUrlCommandProvisioner; @Mock private SecretAsContainerResourceProvisioner secretAsContainerResourceProvisioner; - @Mock private GatewayRouterProvisioner gatewayRouterProvisioner; + @Mock private GatewayRouterResolver gatewayRouterProvisioner; private KubernetesServerResolverFactory serverResolverFactory; @Mock diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java index 0159b2c4d42..8f8651e3b37 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java @@ -24,6 +24,7 @@ import java.util.Set; import javax.inject.Inject; import javax.inject.Named; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.workspace.server.URLRewriter.NoOpURLRewriter; import org.eclipse.che.api.workspace.server.hc.ServersCheckerFactory; import org.eclipse.che.api.workspace.server.hc.probe.ProbeScheduler; @@ -32,13 +33,15 @@ import org.eclipse.che.api.workspace.server.spi.provision.InternalEnvironmentProvisioner; import org.eclipse.che.commons.annotation.Traced; import org.eclipse.che.commons.tracing.TracingTags; -import org.eclipse.che.workspace.infrastructure.kubernetes.GatewayRouterProvisioner; +import org.eclipse.che.workspace.infrastructure.kubernetes.GatewayRouterResolver; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInternalRuntime; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesRuntimeContext; import org.eclipse.che.workspace.infrastructure.kubernetes.RuntimeHangingDetector; import org.eclipse.che.workspace.infrastructure.kubernetes.StartSynchronizerFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesMachineCache; 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.CheNamespace; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.WorkspaceVolumesStrategy; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.secret.SecretAsContainerResourceProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.util.KubernetesSharedPool; @@ -84,7 +87,8 @@ public OpenShiftInternalRuntime( SecretAsContainerResourceProvisioner secretAsContainerResourceProvisioner, OpenShiftServerResolverFactory serverResolverFactory, - GatewayRouterProvisioner gatewayRouterProvisioner, + GatewayRouterResolver gatewayRouterProvisioner, + CheNamespace cheNamespace, Tracer tracer, Openshift4TrustedCAProvisioner trustedCAProvisioner, @Assisted OpenShiftRuntimeContext context, @@ -111,7 +115,7 @@ public OpenShiftInternalRuntime( secretAsContainerResourceProvisioner, null, gatewayRouterProvisioner, - null, + cheNamespace, tracer, context, project); @@ -137,8 +141,7 @@ protected void startMachines() throws InfrastructureException { String workspaceId = getContext().getIdentity().getWorkspaceId(); createSecrets(osEnv, workspaceId); - List createdConfigMaps = createConfigMaps(osEnv, workspaceId); - createdConfigMaps.addAll(gatewayRouterProvisioner.provision(getContext().getIdentity(), osEnv)); + List createdConfigMaps = createConfigMaps(osEnv, getContext().getIdentity()); List createdServices = createServices(osEnv, workspaceId); List createdRoutes = createRoutes(osEnv, workspaceId); @@ -156,18 +159,6 @@ void createSecrets(OpenShiftEnvironment env, String workspaceId) throws Infrastr } } - @Traced - @SuppressWarnings("WeakerAccess") // package-private so that interception is possible - List createConfigMaps(OpenShiftEnvironment env, String workspaceId) - throws InfrastructureException { - TracingTags.WORKSPACE_ID.set(workspaceId); - List createdConfigMaps = new ArrayList<>(); - for (ConfigMap configMap : env.getConfigMaps().values()) { - createdConfigMaps.add(project.configMaps().create(configMap)); - } - return createdConfigMaps; - } - @Traced @SuppressWarnings("WeakerAccess") // package-private so that interception is possible List createServices(OpenShiftEnvironment env, String workspaceId) diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/OpenShiftStopWorkspaceRoleProvisioner.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/OpenShiftStopWorkspaceRoleProvisioner.java index 9efc6849d66..2b55aa3a988 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/OpenShiftStopWorkspaceRoleProvisioner.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/OpenShiftStopWorkspaceRoleProvisioner.java @@ -45,7 +45,8 @@ public class OpenShiftStopWorkspaceRoleProvisioner { public OpenShiftStopWorkspaceRoleProvisioner( OpenShiftClientFactory clientFactory, CheInstallationLocation installationLocation, - @Named("che.workspace.stop.role.enabled") boolean stopWorkspaceRoleEnabled) { + @Named("che.workspace.stop.role.enabled") boolean stopWorkspaceRoleEnabled) + throws InfrastructureException { this.clientFactory = clientFactory; this.installationLocation = installationLocation.getInstallationLocationNamespace(); this.stopWorkspaceRoleEnabled = stopWorkspaceRoleEnabled; diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntimeTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntimeTest.java index d011f4e8352..c6687762d6f 100644 --- a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntimeTest.java +++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntimeTest.java @@ -66,11 +66,13 @@ import org.eclipse.che.api.workspace.server.spi.environment.InternalMachineConfig; import org.eclipse.che.api.workspace.server.spi.provision.InternalEnvironmentProvisioner; import org.eclipse.che.api.workspace.shared.dto.event.MachineStatusEvent; +import org.eclipse.che.workspace.infrastructure.kubernetes.GatewayRouterResolver; import org.eclipse.che.workspace.infrastructure.kubernetes.RuntimeHangingDetector; import org.eclipse.che.workspace.infrastructure.kubernetes.StartSynchronizer; import org.eclipse.che.workspace.infrastructure.kubernetes.StartSynchronizerFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesMachineCache; import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesRuntimeStateCache; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.CheNamespace; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesConfigsMaps; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesDeployments; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesSecrets; @@ -148,6 +150,8 @@ public class OpenShiftInternalRuntimeTest { @Mock private OpenShiftPreviewUrlCommandProvisioner previewUrlCommandProvisioner; @Mock private SecretAsContainerResourceProvisioner secretAsContainerResourceProvisioner; @Mock private Openshift4TrustedCAProvisioner trustedCAProvisioner; + @Mock private GatewayRouterResolver gatewayRouterProvisioner; + @Mock private CheNamespace cheNamespace; private OpenShiftServerResolverFactory serverResolverFactory; @Mock(answer = Answers.RETURNS_MOCKS) @@ -192,7 +196,8 @@ public void setup() throws Exception { previewUrlCommandProvisioner, secretAsContainerResourceProvisioner, serverResolverFactory, - null, + gatewayRouterProvisioner, + cheNamespace, tracer, trustedCAProvisioner, context, diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/OpenShiftStopWorkspaceRoleProvisionerTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/OpenShiftStopWorkspaceRoleProvisionerTest.java index f188a459e3a..02d35e79920 100644 --- a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/OpenShiftStopWorkspaceRoleProvisionerTest.java +++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/OpenShiftStopWorkspaceRoleProvisionerTest.java @@ -174,7 +174,7 @@ public void shouldCreateRole() { } @Test - public void shouldCreateRoleBinding() { + public void shouldCreateRoleBinding() throws InfrastructureException { when(cheInstallationLocation.getInstallationLocationNamespace()).thenReturn("che"); assertEquals( stopWorkspaceRoleProvisioner.createStopWorkspacesRoleBinding("developer-che"), From 6e599ecdc112c3dbb37070e7e0da440a77f39681 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Wed, 12 Aug 2020 16:57:53 +0200 Subject: [PATCH 11/47] minor fixes Signed-off-by: Michal Vala --- .../kubernetes/GatewayRouterResolver.java | 12 +- .../kubernetes/KubernetesInternalRuntime.java | 4 +- .../environment/CheInstallationLocation.java | 5 +- .../kubernetes/namespace/CheNamespace.java | 3 +- .../external/GatewayRouteConfigGenerator.java | 12 +- .../TraefikGatewayRouteConfigGenerator.java | 26 +-- .../external/GatewayServerExposerTest.java | 156 ++++++++---------- .../TraefikGatewayConfigGeneratorTest.java | 92 +++++------ .../openshift/OpenShiftInternalRuntime.java | 2 - 9 files changed, 145 insertions(+), 167 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolver.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolver.java index 7607a5a8d88..c6d24c3b901 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolver.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolver.java @@ -21,6 +21,7 @@ import javax.inject.Inject; import javax.inject.Singleton; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironment; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGenerator; @@ -28,8 +29,9 @@ /** * Resolves {@link GatewayRouteConfig}s from {@link InternalEnvironment} into {@link ConfigMap}s. - * Created instance of {@link ConfigMap} is annotated with {@link GatewayRouterResolver#GATEWAY_CONFIGMAP_LABELS}, - * which are needed so Configbump tool can pick them up and provide them to the Gateway pod. + * Created instance of {@link ConfigMap} is annotated with {@link + * GatewayRouterResolver#GATEWAY_CONFIGMAP_LABELS}, which are needed so Configbump tool can pick + * them up and provide them to the Gateway pod. */ @Singleton public class GatewayRouterResolver { @@ -43,12 +45,12 @@ public class GatewayRouterResolver { private final GatewayRouteConfigGeneratorFactory configGeneratorFactory; @Inject - public GatewayRouterResolver( - GatewayRouteConfigGeneratorFactory configGeneratorFactory) { + public GatewayRouterResolver(GatewayRouteConfigGeneratorFactory configGeneratorFactory) { this.configGeneratorFactory = configGeneratorFactory; } - public List resolve(RuntimeIdentity id, InternalEnvironment internalEnvironment) { + public List resolve(RuntimeIdentity id, InternalEnvironment internalEnvironment) + throws InfrastructureException { if (internalEnvironment.getGatewayRouteConfigs().isEmpty()) { return Collections.emptyList(); } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java index 4dc63cb28ee..acdbd74fee2 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java @@ -696,7 +696,6 @@ void createSecrets(KubernetesEnvironment env, String workspaceId) throws Infrast } @Traced - @SuppressWarnings("WeakerAccess") // package-private so that interception is possible protected List createConfigMaps(KubernetesEnvironment env, RuntimeIdentity identity) throws InfrastructureException { TracingTags.WORKSPACE_ID.set(identity.getWorkspaceId()); @@ -706,7 +705,8 @@ protected List createConfigMaps(KubernetesEnvironment env, RuntimeIde createdConfigMaps.add(namespace.configMaps().create(configMap)); } for (ConfigMap routeConfigMap : gatewayRouterResolver.resolve(identity, env)) { - createdConfigMaps.add(cheNamespace.createConfigMap(routeConfigMap, identity.getWorkspaceId())); + createdConfigMaps.add( + cheNamespace.createConfigMap(routeConfigMap, identity.getWorkspaceId())); } return createdConfigMaps; } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java index bd4569c2090..087a983fdf9 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java @@ -41,10 +41,13 @@ public class CheInstallationLocation { /** * @return The name of the namespace where Che is installed or null if both {@code * KUBERNETES_NAMESPACE} and {@code POD_NAMESPACE} environment variables are not set + * @throws InfrastructureException when both {@code KUBERNETES_NAMESPACE} and {@code + * POD_NAMESPACE} are null */ public String getInstallationLocationNamespace() throws InfrastructureException { if (kubernetesNamespace == null && podNamespace == null) { - throw new InfrastructureException("Neither KUBERNETES_NAMESPACE nor POD_NAMESPACE is defined. Unable to determine Che installation location"); + throw new InfrastructureException( + "Neither KUBERNETES_NAMESPACE nor POD_NAMESPACE is defined. Unable to determine Che installation location"); } return kubernetesNamespace == null ? podNamespace : kubernetesNamespace; } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java index 0a0eba16c55..30b6e7f435a 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java @@ -44,7 +44,8 @@ public class CheNamespace { public CheNamespace( CheInstallationLocation installationLocation, CheKubernetesClientFactory clientFactory, - WorkspaceManager workspaceManager) throws InfrastructureException { + WorkspaceManager workspaceManager) + throws InfrastructureException { this.cheNamespaceName = installationLocation.getInstallationLocationNamespace(); this.clientFactory = clientFactory; this.workspaceManager = workspaceManager; diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java index 04ca2d080d8..ccdf151d790 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java @@ -12,6 +12,7 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; import java.util.Map; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; /** @@ -36,15 +37,16 @@ public interface GatewayRouteConfigGenerator { /** * Generates content of configurations for services, defined earlier by added {@link - * GatewayRouteConfig}s with {@link GatewayRouteConfigGenerator#addRouteConfig(GatewayRouteConfig)}. - * Returned {@code Map} will be used as a value of ConfigMap and injected into - * Gateway pod. + * GatewayRouteConfig}s with {@link + * GatewayRouteConfigGenerator#addRouteConfig(GatewayRouteConfig)}. Returned {@code Map} will be used as a value of ConfigMap and injected into Gateway pod. * *

Implementation must ensure that Gateway configured with returned content will route the * requests on {@code path} into {@code serviceUrl}. Also it must strip {@code path} from request * url. * - *

Keys and Values of returned {@link Map} depends on gateway technology. e.g.: + *

Keys and Values of returned {@link Map} depends on gateway technology. e.g.: + * *

    *   service1.yml: {config-content-for-service-1}
    *   service2.yml: {config-content-for-service-2}
@@ -52,5 +54,5 @@ public interface GatewayRouteConfigGenerator {
    *
    * @return full content of configuration for the services
    */
-  Map generate();
+  Map generate() throws InfrastructureException;
 }
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java
index c69512c7375..33243aae0af 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java
@@ -21,11 +21,10 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
 import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig;
 
-/**
- * Config generator for Traefik Gateway
- */
+/** Config generator for Traefik Gateway */
 public class TraefikGatewayRouteConfigGenerator implements GatewayRouteConfigGenerator {
 
   private final List routeConfigs = new ArrayList<>();
@@ -43,11 +42,12 @@ public void addRouteConfig(GatewayRouteConfig routeConfig) {
 
   /**
    * Generate Traefik configuration for all added {@link GatewayRouteConfig}s.
-   * 

- * Each {@link GatewayRouteConfig} is translated into Traefik configuration under extra key in + * + *

Each {@link GatewayRouteConfig} is translated into Traefik configuration under extra key in * returned {@link Map} `{GatewayRouteConfig#name}.yml`. - *

- * Content of single service configuration looks like this: + * + *

Content of single service configuration looks like this: + * *

    * http:
    *   routers:
@@ -70,7 +70,7 @@ public void addRouteConfig(GatewayRouteConfig routeConfig) {
    * 
*/ @Override - public Map generate() { + public Map generate() throws InfrastructureException { Map cmData = new HashMap<>(); for (GatewayRouteConfig routeConfig : routeConfigs) { String traefikRouteConfig = @@ -86,12 +86,13 @@ public Map generate() { /** * Generates Traefik specific configuration for single service. * - * @param name name of the service + * @param name name of the service * @param serviceUrl url of service we want to route to - * @param path path to route and strip + * @param path path to route and strip * @return traefik service route config */ - private String generate(String name, String serviceUrl, String path) { + private String generate(String name, String serviceUrl, String path) + throws InfrastructureException { StringWriter sw = new StringWriter(); try { YAMLGenerator generator = @@ -114,8 +115,7 @@ private String generate(String name, String serviceUrl, String path) { return sw.toString(); } catch (IOException e) { - e.printStackTrace(); - throw new RuntimeException(e); + throw new InfrastructureException(e); } } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java index ee4a8821b52..30388bcdd21 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java @@ -1,90 +1,74 @@ /* - * 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/ + *Copyright(c)2012-2018Red Hat,Inc. + *This program and the accompanying materials are made + *available under the terms of the Eclipse Public License2.0 + *which is available at https://www.eclipse.org/legal/epl-2.0/ * - * SPDX-License-Identifier: EPL-2.0 + *SPDX-License-Identifier:EPL-2.0 * - * Contributors: - * Red Hat, Inc. - initial API and implementation + *Contributors: + *Red Hat,Inc.-initial API and implementation */ -/// * -// * 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.external; -// -// import static -// org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayServerExposer.GATEWAY_CONFIGMAP_LABELS; -// import static org.testng.Assert.assertEquals; -// import static org.testng.Assert.assertTrue; -// -// import io.fabric8.kubernetes.api.model.ConfigMap; -// import io.fabric8.kubernetes.api.model.IntOrString; -// import io.fabric8.kubernetes.api.model.ServicePort; -// import java.util.Collections; -// 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.environment.KubernetesEnvironment; -// import org.testng.annotations.Test; -// -// public class GatewayServerExposerTest { -// -// private final String machineName = "machine"; -// private final String serviceName = "service"; -// private final String serverId = "server"; -// private final ServicePort servicePort = -// new ServicePort("portName", 1, 1, "http", new IntOrString(1234)); -// -// private final Map s1attrs = Collections.singletonMap("s1attr", "s1val"); -// -// private final Map servers = -// Collections.singletonMap("serverOne", new ServerConfigImpl("1111", "ws", null, s1attrs)); -// -// private final ExternalServerExposer serverExposer = -// new GatewayServerExposer<>( -// new SingleHostExternalServiceExposureStrategy("che-host"), -// (name, serviceUrl, path) -> -// Collections.singletonMap("hello", name + "#" + serviceUrl + "#" + path)); -// -// @Test -// public void testExposeServiceWithGatewayConfigmap() { -// KubernetesEnvironment k8sEnv = KubernetesEnvironment.builder().build(); -// serverExposer.expose(k8sEnv, machineName, serviceName, serverId, servicePort, servers); -// Map configMaps = k8sEnv.getConfigMaps(); -// -// assertTrue(configMaps.containsKey(serviceName + "-" + serverId)); -// -// ConfigMap serverConfigMap = configMaps.get("service-server"); -// -// Map serverConfigMapData = serverConfigMap.getData(); -// assertTrue(serverConfigMapData.containsKey("hello")); -// assertEquals( -// serverConfigMapData.get("hello"), -// "service-server#http://service.che.svc.cluster.local:1234#/service/server/"); -// assertEquals(serverConfigMap.getMetadata().getLabels(), GATEWAY_CONFIGMAP_LABELS); -// -// Map annotations = serverConfigMap.getMetadata().getAnnotations(); -// Annotations.Deserializer deserializer = Annotations.newDeserializer(annotations); -// assertEquals(deserializer.machineName(), machineName); -// -// Map exposedServers = deserializer.servers(); -// assertTrue(exposedServers.containsKey("serverOne")); -// -// ServerConfig s1 = exposedServers.get("serverOne"); -// assertEquals(s1.getAttributes(), s1attrs); -// assertEquals(s1.getPort(), "1111"); -// assertEquals(s1.getProtocol(), "ws"); -// assertEquals(s1.getPath(), "/service/server/"); -// } -// } +package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; + + +import io.fabric8.kubernetes.api.model.IntOrString; +import io.fabric8.kubernetes.api.model.ServicePort; +import java.util.Collections; +import java.util.List; +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.api.workspace.server.spi.environment.GatewayRouteConfig; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.testng.annotations.Test; + +public class GatewayServerExposerTest { + + private final String machineName = "machine"; + private final String serviceName = "service"; + private final String serverId = "server"; + private final ServicePort servicePort = + new ServicePort("portName", 1, 1, "http", new IntOrString(1234)); + + private final Map s1attrs = Collections.singletonMap("s1attr", "s1val"); + + private final Map servers = + Collections.singletonMap("serverOne", new ServerConfigImpl("1111", "ws", null, s1attrs)); + + private final ExternalServerExposer serverExposer = + new GatewayServerExposer<>(new SingleHostExternalServiceExposureStrategy("che-host")); + + @Test + public void testExposeServiceWithGatewayConfigmap() { + KubernetesEnvironment k8sEnv = KubernetesEnvironment.builder().build(); + serverExposer.expose(k8sEnv, machineName, serviceName, serverId, servicePort, servers); + List configMaps = k8sEnv.getGatewayRouteConfigs(); + + // TODO: assert created route configs + + // assertTrue(configMaps.containsKey(serviceName + "-" + serverId)); + // + // ConfigMap serverConfigMap = configMaps.get("service-server"); + // + // Map serverConfigMapData = serverConfigMap.getData(); + // assertTrue(serverConfigMapData.containsKey("hello")); + // assertEquals( + // serverConfigMapData.get("hello"), + // "service-server#http://service.che.svc.cluster.local:1234#/service/server/"); + // assertEquals(serverConfigMap.getMetadata().getLabels(), GATEWAY_CONFIGMAP_LABELS); + // + // Map annotations = serverConfigMap.getMetadata().getAnnotations(); + // Annotations.Deserializer deserializer = Annotations.newDeserializer(annotations); + // assertEquals(deserializer.machineName(), machineName); + // + // Map exposedServers = deserializer.servers(); + // assertTrue(exposedServers.containsKey("serverOne")); + // + // ServerConfig s1 = exposedServers.get("serverOne"); + // assertEquals(s1.getAttributes(), s1attrs); + // assertEquals(s1.getPort(), "1111"); + // assertEquals(s1.getProtocol(), "ws"); + // assertEquals(s1.getPath(), "/service/server/"); + } +} diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java index 157685109a1..0fcfd2299d6 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java @@ -9,55 +9,43 @@ * Contributors: * Red Hat, Inc. - initial API and implementation */ -/// * -// * 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.external; -// -// import static org.testng.Assert.*; -// -// import java.util.Map; -// import org.testng.annotations.Test; -// -// public class TraefikGatewayConfigGeneratorTest { -// private final GatewayRouteConfigGenerator gatewayConfigGenerator = -// new TraefikGatewayRouteConfigGenerator(); -// -// @Test -// public void testGenerateGatewayConfig() { -// String expectedConfig = -// "http:\n" -// + " routers:\n" -// + " external-server-1:\n" -// + " rule: \"PathPrefix(`/blabol-cesta`)\"\n" -// + " service: \"external-server-1\"\n" -// + " middlewares:\n" -// + " - \"external-server-1\"\n" -// + " priority: 100\n" -// + " services:\n" -// + " external-server-1:\n" -// + " loadBalancer:\n" -// + " servers:\n" -// + " - url: \"http://service-url:1234\"\n" -// + " middlewares:\n" -// + " external-server-1:\n" -// + " stripPrefix:\n" -// + " prefixes:\n" -// + " - \"/blabol-cesta\""; -// -// Map generatedConfig = -// gatewayConfigGenerator.generate( -// "external-server-1", "http://service-url:1234", "/blabol-cesta"); -// -// assertTrue(generatedConfig.containsKey("external-server-1.yml")); -// assertEquals(generatedConfig.get("external-server-1.yml"), expectedConfig); -// } -// } +package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; + +import org.testng.annotations.Test; + +public class TraefikGatewayConfigGeneratorTest { + + private final GatewayRouteConfigGenerator gatewayConfigGenerator = + new TraefikGatewayRouteConfigGenerator("che-namespace"); + + @Test + public void testGenerateGatewayConfig() { + String expectedConfig = + "http:\n" + + " routers:\n" + + " external-server-1:\n" + + " rule: \"PathPrefix(`/blabol-cesta`)\"\n" + + " service: \"external-server-1\"\n" + + " middlewares:\n" + + " - \"external-server-1\"\n" + + " priority: 100\n" + + " services:\n" + + " external-server-1:\n" + + " loadBalancer:\n" + + " servers:\n" + + " - url: \"http://service-url:1234\"\n" + + " middlewares:\n" + + " external-server-1:\n" + + " stripPrefix:\n" + + " prefixes:\n" + + " - \"/blabol-cesta\""; + + // TODO: create GatewayCouteConfig for generator + // Map generatedConfig = + // gatewayConfigGenerator.generate( + // "external-server-1", "http://service-url:1234", "/blabol-cesta"); + // + // assertTrue(generatedConfig.containsKey("external-server-1.yml")); + // assertEquals(generatedConfig.get("external-server-1.yml"), expectedConfig); + } +} diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java index 8f8651e3b37..61c94d201de 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java @@ -24,7 +24,6 @@ import java.util.Set; import javax.inject.Inject; import javax.inject.Named; -import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.workspace.server.URLRewriter.NoOpURLRewriter; import org.eclipse.che.api.workspace.server.hc.ServersCheckerFactory; import org.eclipse.che.api.workspace.server.hc.probe.ProbeScheduler; @@ -40,7 +39,6 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.StartSynchronizerFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesMachineCache; 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.CheNamespace; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.WorkspaceVolumesStrategy; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.secret.SecretAsContainerResourceProvisioner; From cc9ed2932f2adccbab0cb64eac8842c38c8a12b3 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Wed, 12 Aug 2020 17:05:27 +0200 Subject: [PATCH 12/47] format Signed-off-by: Michal Vala --- .../kubernetes/server/external/GatewayServerExposerTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java index 30388bcdd21..071a792363a 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java @@ -11,7 +11,6 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; - import io.fabric8.kubernetes.api.model.IntOrString; import io.fabric8.kubernetes.api.model.ServicePort; import java.util.Collections; From cf5641544c86bd1d39a392bb97e5da25645c6152 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Wed, 12 Aug 2020 20:32:16 +0200 Subject: [PATCH 13/47] license headers Signed-off-by: Michal Vala --- .../GatewayRouteConfigGeneratorFactory.java | 11 +++++++++++ .../server/external/GatewayServerExposerTest.java | 14 +++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java index 74c3fcc2f8e..ef5e3e7b0f0 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java @@ -1,3 +1,14 @@ +/* + * 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.external; import javax.inject.Singleton; diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java index 071a792363a..7d1c78aea1a 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java @@ -1,13 +1,13 @@ /* - *Copyright(c)2012-2018Red Hat,Inc. - *This program and the accompanying materials are made - *available under the terms of the Eclipse Public License2.0 - *which is available at https://www.eclipse.org/legal/epl-2.0/ + * 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 + * SPDX-License-Identifier: EPL-2.0 * - *Contributors: - *Red Hat,Inc.-initial API and implementation + * Contributors: + * Red Hat, Inc. - initial API and implementation */ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; From 7b8497b9417830040dfd2375270e7331b5b621aa Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 13 Aug 2020 10:40:36 +0200 Subject: [PATCH 14/47] fix GatewayTlsProvisionerTest Signed-off-by: Michal Vala --- .../provision/GatewayTlsProvisionerTest.java | 45 +++++++------------ .../spi/environment/GatewayRouteConfig.java | 3 +- 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisionerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisionerTest.java index 0eabcf0e9db..b6fc389f44a 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisionerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisionerTest.java @@ -12,18 +12,17 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; import static org.mockito.Mockito.when; import static org.testng.Assert.*; import com.google.common.collect.ImmutableMap; -import io.fabric8.kubernetes.api.model.ConfigMap; -import io.fabric8.kubernetes.api.model.ConfigMapBuilder; -import java.util.HashMap; import java.util.Map; import org.eclipse.che.api.core.model.workspace.config.ServerConfig; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl; +import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructureException; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; @@ -48,35 +47,26 @@ public class GatewayTlsProvisionerTest { singletonMap("annotation-key", "annotation-value"); private final String machine = "machine"; - private final ConfigMap configMap = - new ConfigMapBuilder() - .withNewMetadata() - .withName("gatewayConfig") - .withAnnotations(annotations) - .endMetadata() - .build(); - @Test - public void provisionTlsForConfigMap() throws Exception { + public void provisionTlsForGatewayRouteConfig() throws Exception { // given - GatewayTlsProvisioner ingressTlsProvisioner = + GatewayRouteConfig routeConfig = + new GatewayRouteConfig("gate1", "svc1", "1234", "/hello", annotations); + GatewayTlsProvisioner gatewayTlsProvisioner = new GatewayTlsProvisioner<>(true); - configMap - .getMetadata() + routeConfig .getAnnotations() .putAll(Annotations.newSerializer().servers(servers).machineName(machine).annotations()); - Map configMaps = new HashMap<>(); - configMaps.put("cm", configMap); - when(k8sEnv.getConfigMaps()).thenReturn(configMaps); + when(k8sEnv.getGatewayRouteConfigs()).thenReturn(singletonList(routeConfig)); // when - ingressTlsProvisioner.provision(k8sEnv, runtimeIdentity); + gatewayTlsProvisioner.provision(k8sEnv, runtimeIdentity); // then Map servers = - Annotations.newDeserializer(configMap.getMetadata().getAnnotations()).servers(); + Annotations.newDeserializer(routeConfig.getAnnotations()).servers(); assertEquals(servers.get("http-server").getProtocol(), "https"); assertEquals(servers.get("ws-server").getProtocol(), "wss"); } @@ -84,24 +74,23 @@ public void provisionTlsForConfigMap() throws Exception { @Test public void shouldNotChangeProtocolWhenTlsDisabled() throws KubernetesInfrastructureException { // given - GatewayTlsProvisioner ingressTlsProvisioner = + GatewayRouteConfig routeConfig = + new GatewayRouteConfig("gate1", "svc1", "1234", "/hello", annotations); + GatewayTlsProvisioner gatewayTlsProvisioner = new GatewayTlsProvisioner<>(false); - configMap - .getMetadata() + routeConfig .getAnnotations() .putAll(Annotations.newSerializer().servers(servers).machineName(machine).annotations()); - Map configMaps = new HashMap<>(); - configMaps.put("cm", configMap); - when(k8sEnv.getConfigMaps()).thenReturn(configMaps); + when(k8sEnv.getGatewayRouteConfigs()).thenReturn(singletonList(routeConfig)); // when - ingressTlsProvisioner.provision(k8sEnv, runtimeIdentity); + gatewayTlsProvisioner.provision(k8sEnv, runtimeIdentity); // then Map servers = - Annotations.newDeserializer(configMap.getMetadata().getAnnotations()).servers(); + Annotations.newDeserializer(routeConfig.getAnnotations()).servers(); assertEquals(servers.get("http-server").getProtocol(), "http"); assertEquals(servers.get("ws-server").getProtocol(), "ws"); } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java index 83769d03958..c2dedc0a2de 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java @@ -11,6 +11,7 @@ */ package org.eclipse.che.api.workspace.server.spi.environment; +import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.StringJoiner; @@ -32,7 +33,7 @@ public GatewayRouteConfig( this.serviceName = serviceName; this.servicePort = servicePort; this.routePath = routePath; - this.annotations = annotations; + this.annotations = new HashMap<>(annotations); } @Override From 3fc252413a702880643af5fb7dba4f47e041126b Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 13 Aug 2020 11:19:10 +0200 Subject: [PATCH 15/47] test GatewayRouterResolver Signed-off-by: Michal Vala --- .../kubernetes/GatewayRouterResolver.java | 9 ++- .../kubernetes/GatewayRouterResolverTest.java | 80 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolverTest.java diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolver.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolver.java index c6d24c3b901..f1cc2983b8a 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolver.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolver.java @@ -49,6 +49,13 @@ public GatewayRouterResolver(GatewayRouteConfigGeneratorFactory configGeneratorF this.configGeneratorFactory = configGeneratorFactory; } + /** + * Resolves {@link GatewayRouteConfig}s from given {@link InternalEnvironment} into {@link + * ConfigMap}s. Data for the resulting configmaps are generated with {@link + * GatewayRouteConfigGenerator}, provided by {@link GatewayRouteConfigGeneratorFactory}. + * + * @return configmaps created from GatewayRouteConfigs and other environment info + */ public List resolve(RuntimeIdentity id, InternalEnvironment internalEnvironment) throws InfrastructureException { if (internalEnvironment.getGatewayRouteConfigs().isEmpty()) { @@ -64,7 +71,7 @@ public List resolve(RuntimeIdentity id, InternalEnvironment internalE ConfigMapBuilder configMapBuilder = new ConfigMapBuilder() .withNewMetadata() - .withName(id.getWorkspaceId() + routeConfig.getName()) + .withName(id.getWorkspaceId() + "-" + routeConfig.getName()) .withLabels(GATEWAY_CONFIGMAP_LABELS) .withAnnotations(routeConfig.getAnnotations()) .endMetadata() diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolverTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolverTest.java new file mode 100644 index 00000000000..4f258be90f7 --- /dev/null +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolverTest.java @@ -0,0 +1,80 @@ +package org.eclipse.che.workspace.infrastructure.kubernetes; + +import static org.eclipse.che.workspace.infrastructure.kubernetes.GatewayRouterResolver.GATEWAY_CONFIGMAP_LABELS; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; +import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGenerator; +import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGeneratorFactory; +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 GatewayRouterResolverTest { + + private static final String NAMESPACE = "che"; + private static final String WS_ID = "ws-1"; + + @Mock private GatewayRouteConfigGeneratorFactory configGeneratorFactory; + @Mock private GatewayRouteConfigGenerator configGenerator; + @Mock private RuntimeIdentity runtimeIdentity; + @Mock private InternalEnvironment internalEnvironment; + + private GatewayRouterResolver gatewayRouterResolver; + + @BeforeMethod + public void setUp() throws InfrastructureException { + lenient().when(configGeneratorFactory.create(NAMESPACE)).thenReturn(configGenerator); + lenient().when(configGenerator.generate()).thenReturn(Collections.singletonMap("one", "two")); + lenient().when(runtimeIdentity.getInfrastructureNamespace()).thenReturn(NAMESPACE); + lenient().when(runtimeIdentity.getWorkspaceId()).thenReturn(WS_ID); + gatewayRouterResolver = new GatewayRouterResolver(configGeneratorFactory); + } + + @Test + public void testRouteConfigsAreResolvedToConfigMaps() throws InfrastructureException { + List configs = + Arrays.asList( + new GatewayRouteConfig("g1", "s1", "1", "/1", Collections.singletonMap("a1", "v1")), + new GatewayRouteConfig("g2", "s2", "2", "/2", Collections.singletonMap("a2", "v2"))); + when(internalEnvironment.getGatewayRouteConfigs()).thenReturn(configs); + + List configMaps = + gatewayRouterResolver.resolve(runtimeIdentity, internalEnvironment); + + assertEquals(configMaps.size(), 2); + verify(configGenerator, times(2)).generate(); + configMaps.forEach( + cm -> { + assertEquals(cm.getMetadata().getLabels(), GATEWAY_CONFIGMAP_LABELS); + assertTrue(cm.getMetadata().getName().startsWith(WS_ID)); + assertEquals(cm.getMetadata().getAnnotations().size(), 1); + }); + configs.forEach(c -> verify(configGenerator).addRouteConfig(c)); + } + + @Test + public void testNoRouteConfigsReturnsNoConfigMaps() throws InfrastructureException { + when(internalEnvironment.getGatewayRouteConfigs()).thenReturn(Collections.emptyList()); + + List configMaps = + gatewayRouterResolver.resolve(runtimeIdentity, internalEnvironment); + + assertTrue(configMaps.isEmpty()); + } +} From 067b3b0a67b5dac33cc1f7f39f343d6f0ecd7ec9 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 13 Aug 2020 11:25:25 +0200 Subject: [PATCH 16/47] test cheNamespace cleanup Signed-off-by: Michal Vala --- .../kubernetes/KubernetesInternalRuntimeTest.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java index 00e2538b430..8f36acd02c4 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java @@ -431,6 +431,7 @@ public void startsKubernetesEnvironment() throws Exception { verify(secrets).create(any()); verify(configMaps).create(any()); verify(namespace).cleanUp(); + verify(cheNamespace).cleanUp(WORKSPACE_ID); verify(namespace.deployments(), times(1)).watchEvents(any()); verify(eventService, times(4)).publish(any()); verifyOrderedEventsChains( @@ -447,8 +448,9 @@ public void testCleanupHappensFirst() throws InfrastructureException { internalRuntime.start(emptyMap()); InOrder cleanupInOrderExecutionVerification = - Mockito.inOrder(namespace, deployments, toolingProvisioner); + Mockito.inOrder(namespace, cheNamespace, deployments, toolingProvisioner); cleanupInOrderExecutionVerification.verify(namespace).cleanUp(); + cleanupInOrderExecutionVerification.verify(cheNamespace).cleanUp(WORKSPACE_ID); cleanupInOrderExecutionVerification .verify(toolingProvisioner) .provision(any(), any(), any(), any()); @@ -652,6 +654,7 @@ public void throwsInternalInfrastructureExceptionWhenRuntimeErrorOccurs() throws internalRuntime.start(emptyMap()); } catch (Exception rethrow) { verify(namespace, times(2)).cleanUp(); + verify(cheNamespace, times(2)).cleanUp(WORKSPACE_ID); verify(namespace, never()).services(); verify(namespace, never()).ingresses(); throw rethrow; @@ -731,6 +734,7 @@ public void stopsKubernetesEnvironment() throws Exception { verify(runtimeHangingDetector).stopTracking(IDENTITY); verify(namespace).cleanUp(); + verify(cheNamespace).cleanUp(WORKSPACE_ID); } @Test(expectedExceptions = InfrastructureException.class) @@ -740,6 +744,14 @@ public void throwsInfrastructureExceptionWhenKubernetesNamespaceCleanupFailed() internalRuntime.internalStop(emptyMap()); } + @Test(expectedExceptions = InfrastructureException.class) + public void throwsInfrastructureExceptionWhenKubernetesCheNamespaceCleanupFailed() + throws Exception { + doThrow(InfrastructureException.class).when(cheNamespace).cleanUp(WORKSPACE_ID); + + internalRuntime.internalStop(emptyMap()); + } + @Test public void testRepublishContainerOutputAsMachineLogEvents() throws Exception { final MachineLogsPublisher logsPublisher = From 97e3de302191fdc520464f1df20c5a0bed5b7822 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 13 Aug 2020 13:21:44 +0200 Subject: [PATCH 17/47] test creating configmaps from gateway configs in KubernetesInternalRuntime Signed-off-by: Michal Vala --- .../KubernetesInternalRuntimeTest.java | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java index 8f36acd02c4..50be4c4fcd0 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java @@ -52,6 +52,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.ContainerPort; import io.fabric8.kubernetes.api.model.ContainerPortBuilder; @@ -75,6 +76,7 @@ import io.opentracing.Tracer; import java.text.ParseException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -213,7 +215,7 @@ public class KubernetesInternalRuntimeTest { @Mock private RuntimeHangingDetector runtimeHangingDetector; @Mock private KubernetesPreviewUrlCommandProvisioner previewUrlCommandProvisioner; @Mock private SecretAsContainerResourceProvisioner secretAsContainerResourceProvisioner; - @Mock private GatewayRouterResolver gatewayRouterProvisioner; + @Mock private GatewayRouterResolver gatewayRouterResolver; private KubernetesServerResolverFactory serverResolverFactory; @Mock @@ -288,7 +290,7 @@ public void setup() throws Exception { previewUrlCommandProvisioner, secretAsContainerResourceProvisioner, serverResolverFactory, - gatewayRouterProvisioner, + gatewayRouterResolver, cheNamespace, tracer, context, @@ -1126,6 +1128,44 @@ WORKSPACE_POD_NAME, mockDeployment(singletonList(mockContainer(CONTAINER_NAME_1) new HashSet<>(asList(CONTAINER_NAME_1, "injectedContainer"))); } + @Test + public void testGatewayRouteConfigsAreCreatedAsConfigmapsInCheNamespace() + throws InfrastructureException { + // given + ConfigMap cmRoute1 = + new ConfigMapBuilder().withNewMetadata().withName("route1").endMetadata().build(); + ConfigMap cmRoute2 = + new ConfigMapBuilder().withNewMetadata().withName("route2").endMetadata().build(); + + when(gatewayRouterResolver.resolve(internalRuntime.getContext().getIdentity(), k8sEnv)) + .thenReturn(Arrays.asList(cmRoute1, cmRoute2)); + + // when + internalRuntime.start(emptyMap()); + + // then + verify(gatewayRouterResolver).resolve(internalRuntime.getContext().getIdentity(), k8sEnv); + verify(cheNamespace).createConfigMap(cmRoute1, WORKSPACE_ID); + verify(cheNamespace).createConfigMap(cmRoute2, WORKSPACE_ID); + verify(cheNamespace).cleanUp(WORKSPACE_ID); + } + + @Test + public void dontCreateAnythingInCheNamespaceWhenNoGatewayConfigs() + throws InfrastructureException { + // given + when(gatewayRouterResolver.resolve(internalRuntime.getContext().getIdentity(), k8sEnv)) + .thenReturn(emptyList()); + + // when + internalRuntime.start(emptyMap()); + + // then + verify(gatewayRouterResolver).resolve(internalRuntime.getContext().getIdentity(), k8sEnv); + verify(cheNamespace, never()).createConfigMap(any(), any()); + verify(cheNamespace).cleanUp(WORKSPACE_ID); + } + private static MachineStatusEvent newEvent(String machineName, MachineStatus status) { return newDto(MachineStatusEvent.class) .withIdentity(DtoConverter.asDto(IDENTITY)) From de5520c279a4b5f44dace7c2b9db5bc7d6695dfa Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 13 Aug 2020 15:47:46 +0200 Subject: [PATCH 18/47] CheNamespace and CheInstallationLocation tests, refactors Signed-off-by: Michal Vala --- .../CheKubernetesClientFactory.java | 55 ++++++ .../kubernetes/KubernetesInternalRuntime.java | 7 +- .../environment/CheInstallationLocation.java | 12 +- .../kubernetes/namespace/CheNamespace.java | 141 +++++++------- .../KubernetesInternalRuntimeTest.java | 9 +- .../CheInstallationLocationTest.java | 32 ++++ .../namespace/CheNamespaceTest.java | 179 ++++++++++++++++++ 7 files changed, 347 insertions(+), 88 deletions(-) create mode 100644 infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheKubernetesClientFactory.java create mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocationTest.java create mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespaceTest.java diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheKubernetesClientFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheKubernetesClientFactory.java new file mode 100644 index 00000000000..d391aa18e20 --- /dev/null +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheKubernetesClientFactory.java @@ -0,0 +1,55 @@ +package org.eclipse.che.workspace.infrastructure.kubernetes; + +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.KubernetesClient; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; +import okhttp3.EventListener; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.commons.annotation.Nullable; + +@Singleton +public class CheKubernetesClientFactory extends KubernetesClientFactory { + + @Inject + public CheKubernetesClientFactory( + @Nullable @Named("che.infra.kubernetes.master_url") String masterUrl, + @Nullable @Named("che.infra.kubernetes.trust_certs") Boolean doTrustCerts, + @Named("che.infra.kubernetes.client.http.async_requests.max") int maxConcurrentRequests, + @Named("che.infra.kubernetes.client.http.async_requests.max_per_host") + int maxConcurrentRequestsPerHost, + @Named("che.infra.kubernetes.client.http.connection_pool.max_idle") int maxIdleConnections, + @Named("che.infra.kubernetes.client.http.connection_pool.keep_alive_min") + int connectionPoolKeepAlive, + EventListener eventListener) { + super( + masterUrl, + doTrustCerts, + maxConcurrentRequests, + maxConcurrentRequestsPerHost, + maxIdleConnections, + connectionPoolKeepAlive, + eventListener); + } + + /** @param workspaceId ignored */ + @Override + public KubernetesClient create(String workspaceId) throws InfrastructureException { + return create(); + } + + /** + * creates an instance of {@link KubernetesClient} that is meant to be used on Che installation + * namespace + */ + @Override + public KubernetesClient create() throws InfrastructureException { + return super.create(); + } + + @Override + protected Config buildConfig(Config config, String workspaceId) { + return config; + } +} diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java index acdbd74fee2..9e694498610 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java @@ -704,10 +704,9 @@ protected List createConfigMaps(KubernetesEnvironment env, RuntimeIde for (ConfigMap configMap : env.getConfigMaps().values()) { createdConfigMaps.add(namespace.configMaps().create(configMap)); } - for (ConfigMap routeConfigMap : gatewayRouterResolver.resolve(identity, env)) { - createdConfigMaps.add( - cheNamespace.createConfigMap(routeConfigMap, identity.getWorkspaceId())); - } + createdConfigMaps.addAll( + cheNamespace.createConfigMaps(gatewayRouterResolver.resolve(identity, env), identity)); + return createdConfigMaps; } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java index 087a983fdf9..683e54339e3 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java @@ -11,12 +11,11 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.environment; +import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * This class checks the KUBERNETES_NAMESPACE and POD_NAMESPACE environment variables to determine @@ -27,9 +26,6 @@ */ @Singleton public class CheInstallationLocation { - - private static final Logger LOG = LoggerFactory.getLogger(CheInstallationLocation.class); - @Inject(optional = true) @Named("env.KUBERNETES_NAMESPACE") private String kubernetesNamespace; @@ -38,6 +34,12 @@ public class CheInstallationLocation { @Named("env.POD_NAMESPACE") private String podNamespace; + @VisibleForTesting + CheInstallationLocation(String kubernetesNamespace, String podNamespace) { + this.kubernetesNamespace = kubernetesNamespace; + this.podNamespace = podNamespace; + } + /** * @return The name of the namespace where Che is installed or null if both {@code * KUBERNETES_NAMESPACE} and {@code POD_NAMESPACE} environment variables are not set diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java index 30b6e7f435a..72f1fd90b4f 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java @@ -15,73 +15,109 @@ import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.putLabel; import io.fabric8.kubernetes.api.model.ConfigMap; -import io.fabric8.kubernetes.client.Config; -import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientException; +import java.util.ArrayList; +import java.util.List; import javax.inject.Inject; -import javax.inject.Named; import javax.inject.Singleton; -import okhttp3.EventListener; -import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; -import org.eclipse.che.api.core.model.workspace.Workspace; import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; -import org.eclipse.che.api.workspace.server.WorkspaceManager; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +import org.eclipse.che.api.workspace.server.WorkspaceRuntimes; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; -import org.eclipse.che.commons.annotation.Nullable; -import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; +import org.eclipse.che.api.workspace.server.spi.InternalRuntime; +import org.eclipse.che.workspace.infrastructure.kubernetes.CheKubernetesClientFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructureException; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.CheInstallationLocation; +/** + * This singleton bean can be used to create K8S object in Che installation namespaces. These + * objects are related to particular workspace, but for some reason has to be created in Che + * namespace. + */ @Singleton public class CheNamespace { private final String cheNamespaceName; private final CheKubernetesClientFactory clientFactory; - private final WorkspaceManager workspaceManager; + private final WorkspaceRuntimes workspaceRuntimes; @Inject public CheNamespace( CheInstallationLocation installationLocation, CheKubernetesClientFactory clientFactory, - WorkspaceManager workspaceManager) + WorkspaceRuntimes workspaceRuntimes) throws InfrastructureException { this.cheNamespaceName = installationLocation.getInstallationLocationNamespace(); this.clientFactory = clientFactory; - this.workspaceManager = workspaceManager; + this.workspaceRuntimes = workspaceRuntimes; } - public ConfigMap createConfigMap(ConfigMap configMap, String workspaceId) + /** + * Creates given {@link ConfigMap}s in Che installation namespace labeled with `workspaceId` from + * given `identity`. + * + *

`workspaceId` from given `identity` must be valid workspace ID, that is in {@link + * WorkspaceStatus#STARTING} state. Otherwise, {@link InfrastructureException} is thrown. + * + * @param configMaps to create + * @param identity to validate and label configmaps + * @return created {@link ConfigMap}s + * @throws InfrastructureException when something goes wrong + */ + public List createConfigMaps(List configMaps, RuntimeIdentity identity) throws InfrastructureException { - validate(workspaceId); + if (configMaps.isEmpty()) { + return configMaps; + } + validate(identity, WorkspaceStatus.STARTING); - putLabel(configMap, CHE_WORKSPACE_ID_LABEL, workspaceId); - try { - return clientFactory.create().configMaps().inNamespace(cheNamespaceName).create(configMap); - } catch (KubernetesClientException e) { - throw new KubernetesInfrastructureException(e); + List createdConfigMaps = new ArrayList<>(); + for (ConfigMap cm : configMaps) { + putLabel(cm, CHE_WORKSPACE_ID_LABEL, identity.getWorkspaceId()); + createdConfigMaps.add( + clientFactory.create().configMaps().inNamespace(cheNamespaceName).create(cm)); } + return createdConfigMaps; } - private void validate(String workspaceId) throws InfrastructureException { - if (cheNamespaceName == null) { - throw new InfrastructureException("Unable to determine Che installation location"); + /** + * Cleanup all objects related to given `workspaceId` in Che installation namespace. + * + * @param workspaceId to delete objects + * @throws InfrastructureException when workspaceId is null or something bad happen during + * removing the objects + */ + public void cleanUp(String workspaceId) throws InfrastructureException { + if (workspaceId == null) { + throw new InfrastructureException("workspaceId to cleanup can't be null"); } + cleanUpConfigMaps(workspaceId); + } + /** + * Checks whether we have valid `workspaceId` and `owner` of existing workspace. + * + * @param identity to get `workspaceId` and `owner` to check + * @throws InfrastructureException when `workspaceId` is not valid workspace, is not in {@link + * WorkspaceStatus#STARTING} state, is `null`, or owner does not match. + */ + private void validate(RuntimeIdentity identity, WorkspaceStatus expectedStatus) + throws InfrastructureException { try { - Workspace ws = workspaceManager.getWorkspace(workspaceId); - if (ws.getStatus() != WorkspaceStatus.STARTING) { - throw new InfrastructureException("only for starting workspace"); + InternalRuntime runtime = workspaceRuntimes.getInternalRuntime(identity.getWorkspaceId()); + if (!identity.getOwnerId().equals(runtime.getOwner())) { + throw new InfrastructureException("Given owner does not match workspace's actual owner."); + } + + if (runtime.getStatus() != expectedStatus) { + throw new InfrastructureException("Can create objects only for starting workspaces."); } - } catch (NotFoundException | ServerException e) { + } catch (ServerException e) { throw new InfrastructureException(e); } } - public void cleanUp(String workspaceId) throws InfrastructureException { - cleanUpConfigMaps(workspaceId); - } - private void cleanUpConfigMaps(String workspaceId) throws InfrastructureException { try { clientFactory @@ -95,49 +131,4 @@ private void cleanUpConfigMaps(String workspaceId) throws InfrastructureExceptio throw new KubernetesInfrastructureException(e); } } - - @Singleton - private static class CheKubernetesClientFactory extends KubernetesClientFactory { - - @Inject - public CheKubernetesClientFactory( - @Nullable @Named("che.infra.kubernetes.master_url") String masterUrl, - @Nullable @Named("che.infra.kubernetes.trust_certs") Boolean doTrustCerts, - @Named("che.infra.kubernetes.client.http.async_requests.max") int maxConcurrentRequests, - @Named("che.infra.kubernetes.client.http.async_requests.max_per_host") - int maxConcurrentRequestsPerHost, - @Named("che.infra.kubernetes.client.http.connection_pool.max_idle") int maxIdleConnections, - @Named("che.infra.kubernetes.client.http.connection_pool.keep_alive_min") - int connectionPoolKeepAlive, - EventListener eventListener) { - super( - masterUrl, - doTrustCerts, - maxConcurrentRequests, - maxConcurrentRequestsPerHost, - maxIdleConnections, - connectionPoolKeepAlive, - eventListener); - } - - /** @param workspaceId ignored */ - @Override - public KubernetesClient create(String workspaceId) throws InfrastructureException { - return create(); - } - - /** - * creates an instance of {@link KubernetesClient} that is meant to be used on Che installation - * namespace - */ - @Override - public KubernetesClient create() throws InfrastructureException { - return super.create(); - } - - @Override - protected Config buildConfig(Config config, String workspaceId) { - return config; - } - } } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java index 50be4c4fcd0..c8ce748188d 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java @@ -1137,16 +1137,17 @@ public void testGatewayRouteConfigsAreCreatedAsConfigmapsInCheNamespace() ConfigMap cmRoute2 = new ConfigMapBuilder().withNewMetadata().withName("route2").endMetadata().build(); + List configMaps = Arrays.asList(cmRoute1, cmRoute2); + when(gatewayRouterResolver.resolve(internalRuntime.getContext().getIdentity(), k8sEnv)) - .thenReturn(Arrays.asList(cmRoute1, cmRoute2)); + .thenReturn(configMaps); // when internalRuntime.start(emptyMap()); // then verify(gatewayRouterResolver).resolve(internalRuntime.getContext().getIdentity(), k8sEnv); - verify(cheNamespace).createConfigMap(cmRoute1, WORKSPACE_ID); - verify(cheNamespace).createConfigMap(cmRoute2, WORKSPACE_ID); + verify(cheNamespace).createConfigMaps(configMaps, internalRuntime.getContext().getIdentity()); verify(cheNamespace).cleanUp(WORKSPACE_ID); } @@ -1162,7 +1163,7 @@ public void dontCreateAnythingInCheNamespaceWhenNoGatewayConfigs() // then verify(gatewayRouterResolver).resolve(internalRuntime.getContext().getIdentity(), k8sEnv); - verify(cheNamespace, never()).createConfigMap(any(), any()); + verify(cheNamespace).createConfigMaps(emptyList(), internalRuntime.getContext().getIdentity()); verify(cheNamespace).cleanUp(WORKSPACE_ID); } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocationTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocationTest.java new file mode 100644 index 00000000000..feb6c4ee094 --- /dev/null +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocationTest.java @@ -0,0 +1,32 @@ +package org.eclipse.che.workspace.infrastructure.kubernetes.environment; + +import static org.testng.Assert.*; + +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.testng.annotations.Test; + +public class CheInstallationLocationTest { + @Test + public void returnKubernetesNamespaceWhenBothSet() throws InfrastructureException { + CheInstallationLocation cheInstallationLocation = new CheInstallationLocation("kube", "pod"); + assertEquals(cheInstallationLocation.getInstallationLocationNamespace(), "kube"); + } + + @Test + public void returnKubernetesNamespaceWhenItsOnlySet() throws InfrastructureException { + CheInstallationLocation cheInstallationLocation = new CheInstallationLocation("kube", null); + assertEquals(cheInstallationLocation.getInstallationLocationNamespace(), "kube"); + } + + @Test + public void returnPodNamespaceWhenKubernetesNamespaceNotSet() throws InfrastructureException { + CheInstallationLocation cheInstallationLocation = new CheInstallationLocation(null, "pod"); + assertEquals(cheInstallationLocation.getInstallationLocationNamespace(), "pod"); + } + + @Test(expectedExceptions = InfrastructureException.class) + public void throwExceptionWhenNoneSet() throws InfrastructureException { + CheInstallationLocation cheInstallationLocation = new CheInstallationLocation(null, null); + cheInstallationLocation.getInstallationLocationNamespace(); + } +} diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespaceTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespaceTest.java new file mode 100644 index 00000000000..b446ba22198 --- /dev/null +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespaceTest.java @@ -0,0 +1,179 @@ +package org.eclipse.che.workspace.infrastructure.kubernetes.namespace; + +import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_WORKSPACE_ID_LABEL; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.*; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.ConfigMapList; +import io.fabric8.kubernetes.api.model.DoneableConfigMap; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.dsl.MixedOperation; +import io.fabric8.kubernetes.client.dsl.Resource; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +import org.eclipse.che.api.workspace.server.WorkspaceRuntimes; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.InternalRuntime; +import org.eclipse.che.workspace.infrastructure.kubernetes.CheKubernetesClientFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.CheInstallationLocation; +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 CheNamespaceTest { + + private static final String WORKSPACE_ID = "ws-id"; + private static final String OWNER_ID = "owner-id"; + private static final String CHE_NAMESPACE = "che"; + + private CheNamespace cheNamespace; + + @Mock private CheInstallationLocation cheInstallationLocation; + @Mock private CheKubernetesClientFactory clientFactory; + @Mock private WorkspaceRuntimes workspaceRuntimes; + @Mock private RuntimeIdentity identity; + @Mock private KubernetesClient kubeClient; + + @Mock + private MixedOperation< + ConfigMap, ConfigMapList, DoneableConfigMap, Resource> + kubeConfigMaps; + + @Mock + private MixedOperation< + ConfigMap, ConfigMapList, DoneableConfigMap, Resource> + kubeConfigMapsInNamespace; + + @Mock + private MixedOperation< + ConfigMap, ConfigMapList, DoneableConfigMap, Resource> + kubeConfigMapsWithLabel; + + @Mock + private MixedOperation< + ConfigMap, ConfigMapList, DoneableConfigMap, Resource> + kubeConfigMapsWithPropagationPolicy; + + @Mock private InternalRuntime internalRuntime; + + @BeforeMethod + public void setUp() throws InfrastructureException, ServerException { + when(cheInstallationLocation.getInstallationLocationNamespace()).thenReturn(CHE_NAMESPACE); + cheNamespace = new CheNamespace(cheInstallationLocation, clientFactory, workspaceRuntimes); + lenient().when(identity.getWorkspaceId()).thenReturn(WORKSPACE_ID); + lenient().when(identity.getOwnerId()).thenReturn(OWNER_ID); + lenient().when(workspaceRuntimes.getInternalRuntime(WORKSPACE_ID)).thenReturn(internalRuntime); + } + + @Test + public void testCreateConfigMaps() throws InfrastructureException { + // given + when(internalRuntime.getOwner()).thenReturn(OWNER_ID); + when(internalRuntime.getStatus()).thenReturn(WorkspaceStatus.STARTING); + + ConfigMap cm1 = new ConfigMapBuilder().withNewMetadata().withName("cm1").endMetadata().build(); + ConfigMap cm2 = new ConfigMapBuilder().withNewMetadata().withName("cm2").endMetadata().build(); + + when(clientFactory.create()).thenReturn(kubeClient); + when(kubeClient.configMaps()).thenReturn(kubeConfigMaps); + when(kubeConfigMaps.inNamespace(CHE_NAMESPACE)).thenReturn(kubeConfigMapsInNamespace); + when(kubeConfigMapsInNamespace.create(any(ConfigMap.class))).thenReturn(cm1).thenReturn(cm2); + + List configMapsToCreate = Arrays.asList(cm1, cm2); + + // when + List createdConfigMaps = cheNamespace.createConfigMaps(configMapsToCreate, identity); + + // then + assertEquals(createdConfigMaps.size(), 2); + createdConfigMaps.forEach( + cm -> assertEquals(cm.getMetadata().getLabels().get(CHE_WORKSPACE_ID_LABEL), WORKSPACE_ID)); + } + + @Test(expectedExceptions = InfrastructureException.class) + public void testCreateConfigmapFailsWhenNoWorkspaceIdFoundInRuntimes() + throws InfrastructureException, ServerException { + // given + when(workspaceRuntimes.getInternalRuntime(WORKSPACE_ID)).thenThrow(ServerException.class); + when(internalRuntime.getOwner()).thenReturn(OWNER_ID); + when(internalRuntime.getStatus()).thenReturn(WorkspaceStatus.STARTING); + + ConfigMap cm1 = new ConfigMapBuilder().withNewMetadata().withName("cm1").endMetadata().build(); + + // when + cheNamespace.createConfigMaps(Collections.singletonList(cm1), identity); + } + + @Test(expectedExceptions = InfrastructureException.class) + public void testCreateConfigmapFailsWhenOwnerDontMatch() throws InfrastructureException { + // given + when(internalRuntime.getOwner()).thenReturn("nope"); + when(internalRuntime.getStatus()).thenReturn(WorkspaceStatus.STARTING); + + ConfigMap cm1 = new ConfigMapBuilder().withNewMetadata().withName("cm1").endMetadata().build(); + + // when + cheNamespace.createConfigMaps(Collections.singletonList(cm1), identity); + } + + @Test(expectedExceptions = InfrastructureException.class) + public void testCreateConfigmapFailsWhenWorkspaceStatusIsNotStarting() + throws InfrastructureException { + // given + when(internalRuntime.getOwner()).thenReturn(OWNER_ID); + when(internalRuntime.getStatus()).thenReturn(WorkspaceStatus.RUNNING); + + ConfigMap cm1 = new ConfigMapBuilder().withNewMetadata().withName("cm1").endMetadata().build(); + + // when + cheNamespace.createConfigMaps(Collections.singletonList(cm1), identity); + } + + @Test + public void testCreateEmptyReturnEmpty() throws InfrastructureException { + assertTrue(cheNamespace.createConfigMaps(Collections.emptyList(), identity).isEmpty()); + } + + @Test(expectedExceptions = InfrastructureException.class) + public void throwExceptionWhenCheInstallationLocationFails() throws InfrastructureException { + when(cheInstallationLocation.getInstallationLocationNamespace()) + .thenThrow(InfrastructureException.class); + + new CheNamespace(cheInstallationLocation, clientFactory, workspaceRuntimes); + } + + @Test(expectedExceptions = InfrastructureException.class) + public void cleanupThrowExceptionWhenWorkspaceIdIsNull() throws InfrastructureException { + cheNamespace.cleanUp(null); + } + + @Test + public void testCleanup() throws InfrastructureException { + // given + when(clientFactory.create()).thenReturn(kubeClient); + when(kubeClient.configMaps()).thenReturn(kubeConfigMaps); + when(kubeConfigMaps.inNamespace(CHE_NAMESPACE)).thenReturn(kubeConfigMapsInNamespace); + when(kubeConfigMapsInNamespace.withLabel(CHE_WORKSPACE_ID_LABEL, WORKSPACE_ID)) + .thenReturn(kubeConfigMapsWithLabel); + when(kubeConfigMapsWithLabel.withPropagationPolicy("Background")) + .thenReturn(kubeConfigMapsWithPropagationPolicy); + + // when + cheNamespace.cleanUp(WORKSPACE_ID); + + // then + verify(kubeConfigMapsWithPropagationPolicy).delete(); + } +} From 31e8fa0b4a5e4c1e790cfb7cb77303bdeb2e0bb3 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 13 Aug 2020 16:00:40 +0200 Subject: [PATCH 19/47] format, license headers, javadocs, Signed-off-by: Michal Vala --- .../kubernetes/CheKubernetesClientFactory.java | 11 +++++++++++ .../external/GatewayRouteConfigGeneratorFactory.java | 4 ++++ .../kubernetes/GatewayRouterResolverTest.java | 11 +++++++++++ .../environment/CheInstallationLocationTest.java | 11 +++++++++++ .../kubernetes/namespace/CheNamespaceTest.java | 11 +++++++++++ 5 files changed, 48 insertions(+) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheKubernetesClientFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheKubernetesClientFactory.java index d391aa18e20..6e016f69f11 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheKubernetesClientFactory.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheKubernetesClientFactory.java @@ -1,3 +1,14 @@ +/* + * 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 io.fabric8.kubernetes.client.Config; diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java index ef5e3e7b0f0..d396c747c40 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java @@ -13,6 +13,10 @@ import javax.inject.Singleton; +/** + * This Factory provides {@link GatewayRouteConfigGenerator} instances, so implementation using + * these can stay Gateway technology agnostic. + */ @Singleton public class GatewayRouteConfigGeneratorFactory { diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolverTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolverTest.java index 4f258be90f7..94f84e1a8d3 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolverTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolverTest.java @@ -1,3 +1,14 @@ +/* + * 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.eclipse.che.workspace.infrastructure.kubernetes.GatewayRouterResolver.GATEWAY_CONFIGMAP_LABELS; diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocationTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocationTest.java index feb6c4ee094..b84de63bc15 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocationTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocationTest.java @@ -1,3 +1,14 @@ +/* + * 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.environment; import static org.testng.Assert.*; diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespaceTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespaceTest.java index b446ba22198..0affacc81b5 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespaceTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespaceTest.java @@ -1,3 +1,14 @@ +/* + * 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.namespace; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_WORKSPACE_ID_LABEL; From 4035eb3fc0cd00190197d5fdb352ecca9fdd3b04 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 13 Aug 2020 16:00:54 +0200 Subject: [PATCH 20/47] test generating traefik configuration Signed-off-by: Michal Vala --- .../TraefikGatewayConfigGeneratorTest.java | 51 ------------- ...raefikGatewayRouteConfigGeneratorTest.java | 72 +++++++++++++++++++ 2 files changed, 72 insertions(+), 51 deletions(-) delete mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java create mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java deleted file mode 100644 index 0fcfd2299d6..00000000000 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayConfigGeneratorTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.external; - -import org.testng.annotations.Test; - -public class TraefikGatewayConfigGeneratorTest { - - private final GatewayRouteConfigGenerator gatewayConfigGenerator = - new TraefikGatewayRouteConfigGenerator("che-namespace"); - - @Test - public void testGenerateGatewayConfig() { - String expectedConfig = - "http:\n" - + " routers:\n" - + " external-server-1:\n" - + " rule: \"PathPrefix(`/blabol-cesta`)\"\n" - + " service: \"external-server-1\"\n" - + " middlewares:\n" - + " - \"external-server-1\"\n" - + " priority: 100\n" - + " services:\n" - + " external-server-1:\n" - + " loadBalancer:\n" - + " servers:\n" - + " - url: \"http://service-url:1234\"\n" - + " middlewares:\n" - + " external-server-1:\n" - + " stripPrefix:\n" - + " prefixes:\n" - + " - \"/blabol-cesta\""; - - // TODO: create GatewayCouteConfig for generator - // Map generatedConfig = - // gatewayConfigGenerator.generate( - // "external-server-1", "http://service-url:1234", "/blabol-cesta"); - // - // assertTrue(generatedConfig.containsKey("external-server-1.yml")); - // assertEquals(generatedConfig.get("external-server-1.yml"), expectedConfig); - } -} diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java new file mode 100644 index 00000000000..348f21159ac --- /dev/null +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java @@ -0,0 +1,72 @@ +/* + * 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.external; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.util.Collections; +import java.util.Map; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; +import org.testng.annotations.Test; + +public class TraefikGatewayRouteConfigGeneratorTest { + + private final GatewayRouteConfigGenerator gatewayConfigGenerator = + new TraefikGatewayRouteConfigGenerator("che-namespace"); + + @Test + public void testGenerateGatewayConfig() throws InfrastructureException { + String expectedConfig = + "http:\n" + + " routers:\n" + + " external-server-1:\n" + + " rule: \"PathPrefix(`/blabol-cesta`)\"\n" + + " service: \"external-server-1\"\n" + + " middlewares:\n" + + " - \"external-server-1\"\n" + + " priority: 100\n" + + " services:\n" + + " external-server-1:\n" + + " loadBalancer:\n" + + " servers:\n" + + " - url: \"http://service-url.che-namespace.svc.cluster.local:1234\"\n" + + " middlewares:\n" + + " external-server-1:\n" + + " stripPrefix:\n" + + " prefixes:\n" + + " - \"/blabol-cesta\""; + + GatewayRouteConfig routeConfig = + new GatewayRouteConfig( + "external-server-1", "service-url", "1234", "/blabol-cesta", Collections.emptyMap()); + gatewayConfigGenerator.addRouteConfig(routeConfig); + Map generatedConfig = gatewayConfigGenerator.generate(); + + assertTrue(generatedConfig.containsKey("external-server-1.yml")); + assertEquals(generatedConfig.get("external-server-1.yml"), expectedConfig); + } + + @Test + public void testMultipleRouteConfigsAreGeneratedAsMultipleMapEntries() + throws InfrastructureException { + GatewayRouteConfig c1 = new GatewayRouteConfig("c1", "", "", "", Collections.emptyMap()); + GatewayRouteConfig c2 = new GatewayRouteConfig("c2", "", "", "", Collections.emptyMap()); + gatewayConfigGenerator.addRouteConfig(c1); + gatewayConfigGenerator.addRouteConfig(c2); + Map generatedConfig = gatewayConfigGenerator.generate(); + + assertTrue(generatedConfig.containsKey("c1.yml")); + assertTrue(generatedConfig.containsKey("c2.yml")); + } +} From f42a4b230f05e11f4d4cfe9a0de570d47caafb0e Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 13 Aug 2020 16:06:40 +0200 Subject: [PATCH 21/47] javadocs GatewayRouteConfig Signed-off-by: Michal Vala --- .../server/spi/environment/GatewayRouteConfig.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java index c2dedc0a2de..2e431a5dec4 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java @@ -16,7 +16,18 @@ import java.util.Objects; import java.util.StringJoiner; +/** + * Data object that holds all needed info for configuring individual gateway routes. + * + *

It's used in case of gateway based single-host + * (`che.infra.kubernetes.server_strategy=default-host=single-host` AND + * `che.infra.kubernetes.single_host.workspace.exposure=gateway`). + * + *

Instances of {@link GatewayRouteConfig} are later transformed into gateway-specific + * configuration and into Kubernetes objects needed to properly configure the Gateway. + */ public class GatewayRouteConfig { + private final String name; private final String serviceName; private final String servicePort; From 1e163fbf455397a8b3d711822cbce80fe8251889 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 13 Aug 2020 16:25:16 +0200 Subject: [PATCH 22/47] javadocs Signed-off-by: Michal Vala --- .../infrastructure/kubernetes/CheKubernetesClientFactory.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheKubernetesClientFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheKubernetesClientFactory.java index 6e016f69f11..260966f52d3 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheKubernetesClientFactory.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheKubernetesClientFactory.java @@ -20,6 +20,10 @@ import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.commons.annotation.Nullable; +/** + * This {@link KubernetesClientFactory} is used to access Che installation namespace. It always + * provides client with default {@link Config}. + */ @Singleton public class CheKubernetesClientFactory extends KubernetesClientFactory { From a563b3462ec1609ef97b37fe0108627376a7c15e Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Mon, 17 Aug 2020 10:34:49 +0200 Subject: [PATCH 23/47] fix CheInstallationLocation test Signed-off-by: Michal Vala --- .../environment/CheInstallationLocation.java | 11 ++--------- .../environment/CheInstallationLocationTest.java | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java index 683e54339e3..339a49547e4 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocation.java @@ -11,7 +11,6 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.environment; -import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; @@ -28,17 +27,11 @@ public class CheInstallationLocation { @Inject(optional = true) @Named("env.KUBERNETES_NAMESPACE") - private String kubernetesNamespace; + String kubernetesNamespace; @Inject(optional = true) @Named("env.POD_NAMESPACE") - private String podNamespace; - - @VisibleForTesting - CheInstallationLocation(String kubernetesNamespace, String podNamespace) { - this.kubernetesNamespace = kubernetesNamespace; - this.podNamespace = podNamespace; - } + String podNamespace; /** * @return The name of the namespace where Che is installed or null if both {@code diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocationTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocationTest.java index b84de63bc15..479b8a89617 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocationTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/CheInstallationLocationTest.java @@ -19,25 +19,33 @@ public class CheInstallationLocationTest { @Test public void returnKubernetesNamespaceWhenBothSet() throws InfrastructureException { - CheInstallationLocation cheInstallationLocation = new CheInstallationLocation("kube", "pod"); + CheInstallationLocation cheInstallationLocation = new CheInstallationLocation(); + cheInstallationLocation.kubernetesNamespace = "kube"; + cheInstallationLocation.podNamespace = "pod"; assertEquals(cheInstallationLocation.getInstallationLocationNamespace(), "kube"); } @Test public void returnKubernetesNamespaceWhenItsOnlySet() throws InfrastructureException { - CheInstallationLocation cheInstallationLocation = new CheInstallationLocation("kube", null); + CheInstallationLocation cheInstallationLocation = new CheInstallationLocation(); + cheInstallationLocation.kubernetesNamespace = "kube"; + cheInstallationLocation.podNamespace = null; assertEquals(cheInstallationLocation.getInstallationLocationNamespace(), "kube"); } @Test public void returnPodNamespaceWhenKubernetesNamespaceNotSet() throws InfrastructureException { - CheInstallationLocation cheInstallationLocation = new CheInstallationLocation(null, "pod"); + CheInstallationLocation cheInstallationLocation = new CheInstallationLocation(); + cheInstallationLocation.kubernetesNamespace = null; + cheInstallationLocation.podNamespace = "pod"; assertEquals(cheInstallationLocation.getInstallationLocationNamespace(), "pod"); } @Test(expectedExceptions = InfrastructureException.class) public void throwExceptionWhenNoneSet() throws InfrastructureException { - CheInstallationLocation cheInstallationLocation = new CheInstallationLocation(null, null); + CheInstallationLocation cheInstallationLocation = new CheInstallationLocation(); + cheInstallationLocation.kubernetesNamespace = null; + cheInstallationLocation.podNamespace = null; cheInstallationLocation.getInstallationLocationNamespace(); } } From 721495fb39e21a5c417785af4360a73111b046fa Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Mon, 17 Aug 2020 10:35:37 +0200 Subject: [PATCH 24/47] resolve servers only for configmaps that has machinename annotation Signed-off-by: Michal Vala --- .../kubernetes/server/resolver/ConfigMapServerResolver.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/resolver/ConfigMapServerResolver.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/resolver/ConfigMapServerResolver.java index f662d63e74d..dc75e024d7e 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/resolver/ConfigMapServerResolver.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/resolver/ConfigMapServerResolver.java @@ -37,7 +37,9 @@ public ConfigMapServerResolver( for (ConfigMap configMap : configMaps) { String machineName = Annotations.newDeserializer(configMap.getMetadata().getAnnotations()).machineName(); - this.configMaps.put(machineName, configMap); + if (machineName != null) { + this.configMaps.put(machineName, configMap); + } } } From 62e2314025e06b1e1438317f1dde0144bbffc052 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Tue, 18 Aug 2020 09:44:34 +0200 Subject: [PATCH 25/47] add X-Forwarded-Proto header to traefik config Signed-off-by: Michal Vala --- .../provision/GatewayTlsProvisioner.java | 26 +++++--- .../kubernetes/provision/TlsProvisioner.java | 6 +- .../server/external/GatewayServerExposer.java | 33 ++++------ .../TraefikGatewayRouteConfigGenerator.java | 25 +++++-- .../kubernetes/GatewayRouterResolverTest.java | 6 +- .../provision/GatewayTlsProvisionerTest.java | 66 +++++++++++-------- ...raefikGatewayRouteConfigGeneratorTest.java | 18 +++-- .../spi/environment/GatewayRouteConfig.java | 15 ++++- .../spi/environment/InternalEnvironment.java | 5 +- 9 files changed, 126 insertions(+), 74 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java index 42cfc53c1a6..0cdeb90fe18 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java @@ -19,9 +19,9 @@ import javax.inject.Singleton; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; -import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructureException; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; /** @@ -39,8 +39,7 @@ public GatewayTlsProvisioner(@Named("che.infra.kubernetes.tls_enabled") boolean } @Override - public void provision(T k8sEnv, RuntimeIdentity identity) - throws KubernetesInfrastructureException { + public void provision(T k8sEnv, RuntimeIdentity identity) throws InfrastructureException { if (!isTlsEnabled) { return; } @@ -50,19 +49,26 @@ public void provision(T k8sEnv, RuntimeIdentity identity) } } - private void useSecureProtocolForGatewayServers(GatewayRouteConfig routeConfig) { + private void useSecureProtocolForGatewayServers(GatewayRouteConfig routeConfig) + throws InfrastructureException { Map servers = Annotations.newDeserializer(routeConfig.getAnnotations()).servers(); if (servers.isEmpty()) { return; } - - servers.values().forEach(s -> s.setProtocol(getSecureProtocol(s.getProtocol()))); - - Map annotations = Annotations.newSerializer().servers(servers).annotations(); - if (!annotations.isEmpty() && routeConfig.getAnnotations() != null) { - routeConfig.getAnnotations().putAll(annotations); + if (servers.size() != 1) { + throw new InfrastructureException( + "Expected exactly 1 server in GatewayRouteConfig [" + routeConfig.toString() + "]"); } + String scKey = servers.keySet().stream().findFirst().get(); + ServerConfigImpl serverConfig = servers.get(scKey); + String protocol = getSecureProtocol(serverConfig.getProtocol()); + routeConfig.setProtocol(protocol); + + serverConfig.setProtocol(protocol); + routeConfig + .getAnnotations() + .putAll(Annotations.newSerializer().server(scKey, serverConfig).annotations()); } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/TlsProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/TlsProvisioner.java index d9449431e48..d0b3c77c284 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/TlsProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/TlsProvisioner.java @@ -12,7 +12,7 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; -import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructureException; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; /** @@ -27,9 +27,9 @@ public interface TlsProvisioner { * If TLS enabled, updates protocol to secure one and ensures that underlying exposure objects are * properly configured. * - * @throws KubernetesInfrastructureException in case of any infrastructure failure + * @throws InfrastructureException in case of any infrastructure failure */ - void provision(T k8sEnv, RuntimeIdentity identity) throws KubernetesInfrastructureException; + void provision(T k8sEnv, RuntimeIdentity identity) throws InfrastructureException; /** * Returns the secure version of the provided protocol or the same protocol if the conversion is diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java index cf89772fd04..858203b3091 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java @@ -13,7 +13,6 @@ import io.fabric8.kubernetes.api.model.IntOrString; import io.fabric8.kubernetes.api.model.ServicePort; -import java.util.HashMap; import java.util.Map; import javax.inject.Inject; import org.eclipse.che.api.core.model.workspace.config.ServerConfig; @@ -65,8 +64,11 @@ public void expose( serverId = servicePort.getName(); } - k8sEnv.addGatewayRouteConfig( - createGatewayRouteConfig(machineName, serviceName, serverId, servicePort, externalServers)); + for (String esKey : externalServers.keySet()) { + k8sEnv.addGatewayRouteConfig( + createGatewayRouteConfig( + machineName, serviceName, serverId, servicePort, esKey, externalServers.get(esKey))); + } } private GatewayRouteConfig createGatewayRouteConfig( @@ -74,13 +76,19 @@ private GatewayRouteConfig createGatewayRouteConfig( String serviceName, String serverId, ServicePort servicePort, - Map serversConfigs) { + String scRef, + ServerConfig serverConfig) { final String serverName = KubernetesServerExposer.makeServerNameValidForDns(serverId); final String name = createName(serviceName, serverName); final String path = ensureDontEndsWithSlash(strategy.getExternalPath(serviceName, serverName)); - final Map annotations = createAnnotations(serversConfigs, path, machineName); + final String protocol = serverConfig.getProtocol(); + final Map annotations = + Annotations.newSerializer() + .server(scRef, new ServerConfigImpl(serverConfig).withPath(path)) + .machineName(machineName) + .annotations(); return new GatewayRouteConfig( - name, serviceName, getTargetPort(servicePort.getTargetPort()), path, annotations); + name, serviceName, getTargetPort(servicePort.getTargetPort()), path, protocol, annotations); } private String ensureDontEndsWithSlash(String path) { @@ -96,17 +104,4 @@ private String getTargetPort(IntOrString targetPort) { ? targetPort.getIntVal().toString() : targetPort.getStrVal(); } - - private Map createAnnotations( - Map serversConfigs, String path, String machineName) { - Map configsWithPaths = new HashMap<>(); - for (String scKey : serversConfigs.keySet()) { - configsWithPaths.put(scKey, new ServerConfigImpl(serversConfigs.get(scKey)).withPath(path)); - } - - return Annotations.newSerializer() - .servers(configsWithPaths) - .machineName(machineName) - .annotations(); - } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java index 33243aae0af..4a39b0658f9 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java @@ -77,7 +77,8 @@ public Map generate() throws InfrastructureException { generate( routeConfig.getName(), createServiceUrl(routeConfig.getServiceName(), routeConfig.getServicePort()), - routeConfig.getRoutePath()); + routeConfig.getRoutePath(), + routeConfig.getProtocol()); cmData.put(routeConfig.getName() + ".yml", traefikRouteConfig); } return cmData; @@ -91,7 +92,7 @@ public Map generate() throws InfrastructureException { * @param path path to route and strip * @return traefik service route config */ - private String generate(String name, String serviceUrl, String path) + private String generate(String name, String serviceUrl, String path, String protocol) throws InfrastructureException { StringWriter sw = new StringWriter(); try { @@ -109,7 +110,7 @@ private String generate(String name, String serviceUrl, String path) generateServices(generator, name, serviceUrl); generator.writeFieldName("middlewares"); - generateMiddlewares(generator, name, path); + generateMiddlewares(generator, name, path, protocol); generator.flush(); @@ -143,6 +144,7 @@ private void generateRouters(YAMLGenerator generator, String name, String path) generator.writeFieldName("middlewares"); generator.writeStartArray(); generator.writeString(name); + generator.writeString(name + "_headers"); generator.writeEndArray(); generator.writeFieldName("priority"); generator.writeNumber(100); @@ -189,8 +191,8 @@ private void generateServices(YAMLGenerator generator, String name, String servi * - "{path}" *

*/ - private void generateMiddlewares(YAMLGenerator generator, String name, String path) - throws IOException { + private void generateMiddlewares( + YAMLGenerator generator, String name, String path, String protocol) throws IOException { generator.writeStartObject(); generator.writeFieldName(name); generator.writeStartObject(); @@ -202,6 +204,19 @@ private void generateMiddlewares(YAMLGenerator generator, String name, String pa generator.writeEndArray(); generator.writeEndObject(); generator.writeEndObject(); + + generator.writeFieldName(name + "_headers"); + generator.writeStartObject(); + generator.writeFieldName("headers"); + generator.writeStartObject(); + generator.writeFieldName("customRequestHeaders"); + generator.writeStartObject(); + generator.writeFieldName("X-Forwarded-Proto"); + generator.writeString(protocol); + generator.writeEndObject(); + generator.writeEndObject(); + generator.writeEndObject(); + generator.writeEndObject(); } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolverTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolverTest.java index 94f84e1a8d3..a569b3a81b2 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolverTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolverTest.java @@ -61,8 +61,10 @@ public void setUp() throws InfrastructureException { public void testRouteConfigsAreResolvedToConfigMaps() throws InfrastructureException { List configs = Arrays.asList( - new GatewayRouteConfig("g1", "s1", "1", "/1", Collections.singletonMap("a1", "v1")), - new GatewayRouteConfig("g2", "s2", "2", "/2", Collections.singletonMap("a2", "v2"))); + new GatewayRouteConfig( + "g1", "s1", "1", "/1", "http", Collections.singletonMap("a1", "v1")), + new GatewayRouteConfig( + "g2", "s2", "2", "/2", "http", Collections.singletonMap("a2", "v2"))); when(internalEnvironment.getGatewayRouteConfigs()).thenReturn(configs); List configMaps = diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisionerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisionerTest.java index b6fc389f44a..77637f187f1 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisionerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisionerTest.java @@ -17,22 +17,23 @@ import static org.mockito.Mockito.when; import static org.testng.Assert.*; -import com.google.common.collect.ImmutableMap; +import java.util.HashMap; import java.util.Map; -import org.eclipse.che.api.core.model.workspace.config.ServerConfig; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; -import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructureException; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @Listeners(MockitoTestNGListener.class) public class GatewayTlsProvisionerTest { + public static final String WORKSPACE_ID = "workspace123"; @Mock private KubernetesEnvironment k8sEnv; @Mock private RuntimeIdentity runtimeIdentity; @@ -41,23 +42,21 @@ public class GatewayTlsProvisionerTest { new ServerConfigImpl("8080/tpc", "http", "/api", emptyMap()); private final ServerConfigImpl wsServer = new ServerConfigImpl("8080/tpc", "ws", "/ws", emptyMap()); - private final Map servers = - ImmutableMap.of("http-server", httpServer, "ws-server", wsServer); private final Map annotations = singletonMap("annotation-key", "annotation-value"); private final String machine = "machine"; - @Test - public void provisionTlsForGatewayRouteConfig() throws Exception { + @Test(dataProvider = "tlsProvisionData") + public void provisionTlsForGatewayRouteConfig( + ServerConfigImpl server, boolean tlsEnabled, String expectedProtocol) throws Exception { // given + Map composedAnnotations = new HashMap<>(annotations); + composedAnnotations.putAll( + Annotations.newSerializer().server("server", server).machineName(machine).annotations()); GatewayRouteConfig routeConfig = - new GatewayRouteConfig("gate1", "svc1", "1234", "/hello", annotations); + new GatewayRouteConfig("gate1", "svc1", "1234", "/hello", "http", composedAnnotations); GatewayTlsProvisioner gatewayTlsProvisioner = - new GatewayTlsProvisioner<>(true); - - routeConfig - .getAnnotations() - .putAll(Annotations.newSerializer().servers(servers).machineName(machine).annotations()); + new GatewayTlsProvisioner<>(tlsEnabled); when(k8sEnv.getGatewayRouteConfigs()).thenReturn(singletonList(routeConfig)); @@ -67,31 +66,40 @@ public void provisionTlsForGatewayRouteConfig() throws Exception { // then Map servers = Annotations.newDeserializer(routeConfig.getAnnotations()).servers(); - assertEquals(servers.get("http-server").getProtocol(), "https"); - assertEquals(servers.get("ws-server").getProtocol(), "wss"); + assertEquals(servers.get("server").getProtocol(), expectedProtocol); } - @Test - public void shouldNotChangeProtocolWhenTlsDisabled() throws KubernetesInfrastructureException { + @DataProvider + public Object[][] tlsProvisionData() { + return new Object[][] { + {httpServer, true, "https"}, + {httpServer, false, "http"}, + {wsServer, true, "wss"}, + {wsServer, false, "ws"}, + }; + } + + @Test(expectedExceptions = InfrastructureException.class) + public void throwExceptionWhenMultipleServersInGatewayRouteConfigAnnotations() + throws InfrastructureException { // given + Map composedAnnotations = new HashMap<>(annotations); + composedAnnotations.putAll( + Annotations.newSerializer() + .server("server1", httpServer) + .server("server2", wsServer) + .machineName(machine) + .annotations()); GatewayRouteConfig routeConfig = - new GatewayRouteConfig("gate1", "svc1", "1234", "/hello", annotations); - GatewayTlsProvisioner gatewayTlsProvisioner = - new GatewayTlsProvisioner<>(false); - - routeConfig - .getAnnotations() - .putAll(Annotations.newSerializer().servers(servers).machineName(machine).annotations()); + new GatewayRouteConfig("gate1", "svc1", "1234", "/hello", "http", composedAnnotations); when(k8sEnv.getGatewayRouteConfigs()).thenReturn(singletonList(routeConfig)); + GatewayTlsProvisioner gatewayTlsProvisioner = + new GatewayTlsProvisioner<>(true); // when gatewayTlsProvisioner.provision(k8sEnv, runtimeIdentity); - // then - Map servers = - Annotations.newDeserializer(routeConfig.getAnnotations()).servers(); - assertEquals(servers.get("http-server").getProtocol(), "http"); - assertEquals(servers.get("ws-server").getProtocol(), "ws"); + // then exception } } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java index 348f21159ac..77598640ac4 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java @@ -35,6 +35,7 @@ public void testGenerateGatewayConfig() throws InfrastructureException { + " service: \"external-server-1\"\n" + " middlewares:\n" + " - \"external-server-1\"\n" + + " - \"external-server-1_headers\"\n" + " priority: 100\n" + " services:\n" + " external-server-1:\n" @@ -45,11 +46,20 @@ public void testGenerateGatewayConfig() throws InfrastructureException { + " external-server-1:\n" + " stripPrefix:\n" + " prefixes:\n" - + " - \"/blabol-cesta\""; + + " - \"/blabol-cesta\"\n" + + " external-server-1_headers:\n" + + " headers:\n" + + " customRequestHeaders:\n" + + " X-Forwarded-Proto: \"http\""; GatewayRouteConfig routeConfig = new GatewayRouteConfig( - "external-server-1", "service-url", "1234", "/blabol-cesta", Collections.emptyMap()); + "external-server-1", + "service-url", + "1234", + "/blabol-cesta", + "http", + Collections.emptyMap()); gatewayConfigGenerator.addRouteConfig(routeConfig); Map generatedConfig = gatewayConfigGenerator.generate(); @@ -60,8 +70,8 @@ public void testGenerateGatewayConfig() throws InfrastructureException { @Test public void testMultipleRouteConfigsAreGeneratedAsMultipleMapEntries() throws InfrastructureException { - GatewayRouteConfig c1 = new GatewayRouteConfig("c1", "", "", "", Collections.emptyMap()); - GatewayRouteConfig c2 = new GatewayRouteConfig("c2", "", "", "", Collections.emptyMap()); + GatewayRouteConfig c1 = new GatewayRouteConfig("c1", "", "", "", "", Collections.emptyMap()); + GatewayRouteConfig c2 = new GatewayRouteConfig("c2", "", "", "", "", Collections.emptyMap()); gatewayConfigGenerator.addRouteConfig(c1); gatewayConfigGenerator.addRouteConfig(c2); Map generatedConfig = gatewayConfigGenerator.generate(); diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java index 2e431a5dec4..1654cd3bf2e 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java @@ -32,6 +32,7 @@ public class GatewayRouteConfig { private final String serviceName; private final String servicePort; private final String routePath; + private String protocol; private final Map annotations; public GatewayRouteConfig( @@ -39,11 +40,13 @@ public GatewayRouteConfig( String serviceName, String servicePort, String routePath, + String protocol, Map annotations) { this.name = name; this.serviceName = serviceName; this.servicePort = servicePort; this.routePath = routePath; + this.protocol = protocol; this.annotations = new HashMap<>(annotations); } @@ -54,6 +57,7 @@ public String toString() { .add("serviceName='" + serviceName + "'") .add("servicePort='" + servicePort + "'") .add("routePath='" + routePath + "'") + .add("protocol='" + protocol + "'") .add("annotations=" + annotations) .toString(); } @@ -71,12 +75,13 @@ public boolean equals(Object o) { && Objects.equals(serviceName, that.serviceName) && Objects.equals(servicePort, that.servicePort) && Objects.equals(routePath, that.routePath) + && Objects.equals(protocol, that.protocol) && Objects.equals(annotations, that.annotations); } @Override public int hashCode() { - return Objects.hash(name, serviceName, servicePort, routePath, annotations); + return Objects.hash(name, serviceName, servicePort, routePath, protocol, annotations); } public String getName() { @@ -98,4 +103,12 @@ public Map getAnnotations() { public String getServicePort() { return servicePort; } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironment.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironment.java index 8b6922ed2ef..291eba7bd50 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironment.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironment.java @@ -46,10 +46,11 @@ public abstract class InternalEnvironment { private Map attributes; private List commands; private DevfileImpl devfile; - private final List gatewayRouteConfigs = new ArrayList<>(); + private List gatewayRouteConfigs; protected InternalEnvironment() { this.warnings = new CopyOnWriteArrayList<>(); + this.gatewayRouteConfigs = new ArrayList<>(); } protected InternalEnvironment( @@ -61,6 +62,7 @@ protected InternalEnvironment( this.warnings.addAll(warnings); } this.type = recipe != null ? recipe.getType() : null; + this.gatewayRouteConfigs = new ArrayList<>(); } protected InternalEnvironment(InternalEnvironment internalEnvironment) { @@ -71,6 +73,7 @@ protected InternalEnvironment(InternalEnvironment internalEnvironment) { this.attributes = internalEnvironment.getAttributes(); this.commands = internalEnvironment.getCommands(); this.devfile = internalEnvironment.getDevfile(); + this.gatewayRouteConfigs = new ArrayList<>(internalEnvironment.getGatewayRouteConfigs()); } /** From 66b9d3ee560a2b87dbc80ecb4ffa6e98df92fa76 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Tue, 18 Aug 2020 13:55:48 +0200 Subject: [PATCH 26/47] refactor so KubernetesInternalRuntime only creates configmaps Signed-off-by: Michal Vala --- .../kubernetes/Annotations.java | 3 + .../kubernetes/GatewayRouterResolver.java | 85 ----------------- .../KubernetesEnvironmentProvisioner.java | 7 +- .../kubernetes/KubernetesInternalRuntime.java | 25 +++-- .../kubernetes/namespace/CheNamespace.java | 20 ++++ .../provision/GatewayRouterProvisioner.java | 54 +++++++++++ .../external/GatewayRouteConfigGenerator.java | 2 +- .../GatewayRouteConfigGeneratorFactory.java | 2 +- .../server/external/GatewayServerExposer.java | 4 + .../TraefikGatewayRouteConfigGenerator.java | 13 +-- .../kubernetes/GatewayRouterResolverTest.java | 93 ------------------- .../KubernetesEnvironmentProvisionerTest.java | 5 +- .../KubernetesInternalRuntimeTest.java | 22 ----- ...raefikGatewayRouteConfigGeneratorTest.java | 6 +- .../openshift/OpenShiftInternalRuntime.java | 3 - .../OpenShiftInternalRuntimeTest.java | 3 - .../spi/environment/InternalEnvironment.java | 2 +- 17 files changed, 120 insertions(+), 229 deletions(-) delete mode 100644 infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolver.java create mode 100644 infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java delete mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolverTest.java diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Annotations.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Annotations.java index 7977d0bd727..c05e26be59e 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Annotations.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Annotations.java @@ -41,6 +41,9 @@ public class Annotations { public static final String MACHINE_NAME_ANNOTATION = ANNOTATION_PREFIX + "machine.name"; + public static final String CREATE_IN_CHE_INSTALLATION_NAMESPACE = + ANNOTATION_PREFIX + "installation.namespace"; + /** Pattern that matches server annotations e.g. "org.eclipse.che.server.exec-agent.port". */ private static final Pattern SERVER_ANNOTATION_PATTERN = Pattern.compile("org\\.eclipse\\.che\\.server\\.(?[\\w-/]+)\\..+"); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolver.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolver.java deleted file mode 100644 index f1cc2983b8a..00000000000 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolver.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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 com.google.common.collect.ImmutableMap; -import io.fabric8.kubernetes.api.model.ConfigMap; -import io.fabric8.kubernetes.api.model.ConfigMapBuilder; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; -import org.eclipse.che.api.workspace.server.spi.InfrastructureException; -import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; -import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironment; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGenerator; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGeneratorFactory; - -/** - * Resolves {@link GatewayRouteConfig}s from {@link InternalEnvironment} into {@link ConfigMap}s. - * Created instance of {@link ConfigMap} is annotated with {@link - * GatewayRouterResolver#GATEWAY_CONFIGMAP_LABELS}, which are needed so Configbump tool can pick - * them up and provide them to the Gateway pod. - */ -@Singleton -public class GatewayRouterResolver { - - protected static final Map GATEWAY_CONFIGMAP_LABELS = - ImmutableMap.builder() - .put("app", "che") - .put("role", "gateway-config") - .build(); - - private final GatewayRouteConfigGeneratorFactory configGeneratorFactory; - - @Inject - public GatewayRouterResolver(GatewayRouteConfigGeneratorFactory configGeneratorFactory) { - this.configGeneratorFactory = configGeneratorFactory; - } - - /** - * Resolves {@link GatewayRouteConfig}s from given {@link InternalEnvironment} into {@link - * ConfigMap}s. Data for the resulting configmaps are generated with {@link - * GatewayRouteConfigGenerator}, provided by {@link GatewayRouteConfigGeneratorFactory}. - * - * @return configmaps created from GatewayRouteConfigs and other environment info - */ - public List resolve(RuntimeIdentity id, InternalEnvironment internalEnvironment) - throws InfrastructureException { - if (internalEnvironment.getGatewayRouteConfigs().isEmpty()) { - return Collections.emptyList(); - } - List routeConfigMaps = new ArrayList<>(); - - for (GatewayRouteConfig routeConfig : internalEnvironment.getGatewayRouteConfigs()) { - GatewayRouteConfigGenerator gatewayRouteConfigGenerator = - configGeneratorFactory.create(id.getInfrastructureNamespace()); - gatewayRouteConfigGenerator.addRouteConfig(routeConfig); - - ConfigMapBuilder configMapBuilder = - new ConfigMapBuilder() - .withNewMetadata() - .withName(id.getWorkspaceId() + "-" + routeConfig.getName()) - .withLabels(GATEWAY_CONFIGMAP_LABELS) - .withAnnotations(routeConfig.getAnnotations()) - .endMetadata() - .withData(gatewayRouteConfigGenerator.generate()); - - routeConfigMaps.add(configMapBuilder.build()); - } - - return routeConfigMaps; - } -} diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesEnvironmentProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesEnvironmentProvisioner.java index 98eabcc88dd..821657b8c0c 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesEnvironmentProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesEnvironmentProvisioner.java @@ -23,6 +23,7 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.provision.AsyncStoragePodInterceptor; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.AsyncStorageProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.CertificateProvisioner; +import org.eclipse.che.workspace.infrastructure.kubernetes.provision.GatewayRouterProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.GitConfigProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.ImagePullSecretProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.LogsVolumeMachineProvisioner; @@ -82,6 +83,7 @@ class KubernetesEnvironmentProvisionerImpl private final GitConfigProvisioner gitConfigProvisioner; private final PreviewUrlExposer previewUrlExposer; private final VcsSslCertificateProvisioner vcsSslCertificateProvisioner; + private final GatewayRouterProvisioner gatewayRouterProvisioner; @Inject public KubernetesEnvironmentProvisionerImpl( @@ -105,7 +107,8 @@ public KubernetesEnvironmentProvisionerImpl( SshKeysProvisioner sshKeysProvisioner, GitConfigProvisioner gitConfigProvisioner, PreviewUrlExposer previewUrlExposer, - VcsSslCertificateProvisioner vcsSslCertificateProvisioner) { + VcsSslCertificateProvisioner vcsSslCertificateProvisioner, + GatewayRouterProvisioner gatewayRouterProvisioner) { this.pvcEnabled = pvcEnabled; this.volumesStrategy = volumesStrategy; this.uniqueNamesProvisioner = uniqueNamesProvisioner; @@ -127,6 +130,7 @@ public KubernetesEnvironmentProvisionerImpl( this.vcsSslCertificateProvisioner = vcsSslCertificateProvisioner; this.gitConfigProvisioner = gitConfigProvisioner; this.previewUrlExposer = previewUrlExposer; + this.gatewayRouterProvisioner = gatewayRouterProvisioner; } @Traced @@ -168,6 +172,7 @@ public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity) sshKeysProvisioner.provision(k8sEnv, identity); vcsSslCertificateProvisioner.provision(k8sEnv, identity); gitConfigProvisioner.provision(k8sEnv, identity); + gatewayRouterProvisioner.provision(k8sEnv, identity); LOG.debug("Provisioning Kubernetes environment done for workspace '{}'", workspaceId); } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java index 9e694498610..c3bd1824a5e 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java @@ -11,9 +11,12 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes; +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; import static java.lang.String.format; import static java.util.Collections.emptyMap; import static java.util.stream.Collectors.toMap; +import static org.eclipse.che.workspace.infrastructure.kubernetes.Annotations.CREATE_IN_CHE_INSTALLATION_NAMESPACE; import static org.eclipse.che.workspace.infrastructure.kubernetes.util.TracingSpanConstants.CHECK_SERVERS; import static org.eclipse.che.workspace.infrastructure.kubernetes.util.TracingSpanConstants.WAIT_MACHINES_START; import static org.eclipse.che.workspace.infrastructure.kubernetes.util.TracingSpanConstants.WAIT_RUNNING_ASYNC; @@ -133,7 +136,6 @@ public class KubernetesInternalRuntime private final SecretAsContainerResourceProvisioner secretAsContainerResourceProvisioner; private final KubernetesServerResolverFactory serverResolverFactory; protected final CheNamespace cheNamespace; - protected final GatewayRouterResolver gatewayRouterResolver; protected final Tracer tracer; @Inject @@ -158,7 +160,6 @@ public KubernetesInternalRuntime( PreviewUrlCommandProvisioner previewUrlCommandProvisioner, SecretAsContainerResourceProvisioner secretAsContainerResourceProvisioner, KubernetesServerResolverFactory kubernetesServerResolverFactory, - GatewayRouterResolver gatewayRouterResolver, CheNamespace cheNamespace, Tracer tracer, @Assisted KubernetesRuntimeContext context, @@ -186,7 +187,6 @@ public KubernetesInternalRuntime( this.secretAsContainerResourceProvisioner = secretAsContainerResourceProvisioner; this.serverResolverFactory = kubernetesServerResolverFactory; this.tracer = tracer; - this.gatewayRouterResolver = gatewayRouterResolver; } @Override @@ -702,10 +702,23 @@ protected List createConfigMaps(KubernetesEnvironment env, RuntimeIde List createdConfigMaps = new ArrayList<>(); for (ConfigMap configMap : env.getConfigMaps().values()) { - createdConfigMaps.add(namespace.configMaps().create(configMap)); + Map annotations = configMap.getMetadata().getAnnotations(); + if (annotations == null + || annotations.isEmpty() + || FALSE + .toString() + .equals( + annotations.getOrDefault( + CREATE_IN_CHE_INSTALLATION_NAMESPACE, FALSE.toString()))) { + createdConfigMaps.add(namespace.configMaps().create(configMap)); + } else if (TRUE.toString() + .equals( + annotations.getOrDefault(CREATE_IN_CHE_INSTALLATION_NAMESPACE, FALSE.toString()))) { + createdConfigMaps.add(cheNamespace.createConfigMap(configMap, identity)); + } else { + throw new InfrastructureException("what?"); + } } - createdConfigMaps.addAll( - cheNamespace.createConfigMaps(gatewayRouterResolver.resolve(identity, env), identity)); return createdConfigMaps; } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java index 72f1fd90b4f..e2c80c128fa 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java @@ -53,6 +53,26 @@ public CheNamespace( this.workspaceRuntimes = workspaceRuntimes; } + /** + * Creates given {@link ConfigMap}s in Che installation namespace labeled with `workspaceId` from + * given `identity`. + * + *

`workspaceId` from given `identity` must be valid workspace ID, that is in {@link + * WorkspaceStatus#STARTING} state. Otherwise, {@link InfrastructureException} is thrown. + * + * @param configMaps to create + * @param identity to validate and label configmaps + * @return created {@link ConfigMap}s + * @throws InfrastructureException when something goes wrong + */ + public ConfigMap createConfigMap(ConfigMap configMap, RuntimeIdentity identity) + throws InfrastructureException { + validate(identity, WorkspaceStatus.STARTING); + + putLabel(configMap, CHE_WORKSPACE_ID_LABEL, identity.getWorkspaceId()); + return clientFactory.create().configMaps().inNamespace(cheNamespaceName).create(configMap); + } + /** * Creates given {@link ConfigMap}s in Che installation namespace labeled with `workspaceId` from * given `identity`. diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java new file mode 100644 index 00000000000..c1f2e0ab381 --- /dev/null +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java @@ -0,0 +1,54 @@ +package org.eclipse.che.workspace.infrastructure.kubernetes.provision; + +import com.google.common.collect.ImmutableMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import java.util.Map; +import javax.inject.Inject; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGenerator; +import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGeneratorFactory; + +public class GatewayRouterProvisioner implements ConfigurationProvisioner { + + protected static final Map GATEWAY_CONFIGMAP_LABELS = + ImmutableMap.builder() + .put("app", "che") + .put("role", "gateway-config") + .build(); + + private final GatewayRouteConfigGeneratorFactory configGeneratorFactory; + + @Inject + public GatewayRouterProvisioner(GatewayRouteConfigGeneratorFactory configGeneratorFactory) { + this.configGeneratorFactory = configGeneratorFactory; + } + + @Override + public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity) + throws InfrastructureException { + if (k8sEnv.getGatewayRouteConfigs().isEmpty()) { + return; + } + + for (GatewayRouteConfig routeConfig : k8sEnv.getGatewayRouteConfigs()) { + GatewayRouteConfigGenerator gatewayRouteConfigGenerator = + configGeneratorFactory.create(identity.getInfrastructureNamespace()); + gatewayRouteConfigGenerator.addRouteConfig(routeConfig); + + ConfigMapBuilder configMapBuilder = + new ConfigMapBuilder() + .withNewMetadata() + .withName(identity.getWorkspaceId() + "-" + routeConfig.getName()) + .withLabels(GATEWAY_CONFIGMAP_LABELS) + .withAnnotations(routeConfig.getAnnotations()) + .endMetadata() + .withData( + gatewayRouteConfigGenerator.generate(identity.getInfrastructureNamespace())); + + k8sEnv.getConfigMaps().put(routeConfig.getName(), configMapBuilder.build()); + } + } +} diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java index ccdf151d790..e03db308ed3 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java @@ -54,5 +54,5 @@ public interface GatewayRouteConfigGenerator { * * @return full content of configuration for the services */ - Map generate() throws InfrastructureException; + Map generate(String namespace) throws InfrastructureException; } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java index d396c747c40..9a5d6cd6aa0 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java @@ -21,6 +21,6 @@ public class GatewayRouteConfigGeneratorFactory { public GatewayRouteConfigGenerator create(String namespace) { - return new TraefikGatewayRouteConfigGenerator(namespace); + return new TraefikGatewayRouteConfigGenerator(); } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java index 858203b3091..7ce14adece0 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java @@ -11,6 +11,9 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; +import static java.lang.Boolean.TRUE; +import static org.eclipse.che.workspace.infrastructure.kubernetes.Annotations.CREATE_IN_CHE_INSTALLATION_NAMESPACE; + import io.fabric8.kubernetes.api.model.IntOrString; import io.fabric8.kubernetes.api.model.ServicePort; import java.util.Map; @@ -87,6 +90,7 @@ private GatewayRouteConfig createGatewayRouteConfig( .server(scRef, new ServerConfigImpl(serverConfig).withPath(path)) .machineName(machineName) .annotations(); + annotations.put(CREATE_IN_CHE_INSTALLATION_NAMESPACE, TRUE.toString()); return new GatewayRouteConfig( name, serviceName, getTargetPort(servicePort.getTargetPort()), path, protocol, annotations); } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java index 4a39b0658f9..48241ac6324 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java @@ -29,12 +29,6 @@ public class TraefikGatewayRouteConfigGenerator implements GatewayRouteConfigGen private final List routeConfigs = new ArrayList<>(); - private final String serviceNamespace; - - public TraefikGatewayRouteConfigGenerator(String serviceNamespace) { - this.serviceNamespace = serviceNamespace; - } - @Override public void addRouteConfig(GatewayRouteConfig routeConfig) { this.routeConfigs.add(routeConfig); @@ -70,13 +64,14 @@ public void addRouteConfig(GatewayRouteConfig routeConfig) { *

*/ @Override - public Map generate() throws InfrastructureException { + public Map generate(String namespace) throws InfrastructureException { Map cmData = new HashMap<>(); for (GatewayRouteConfig routeConfig : routeConfigs) { String traefikRouteConfig = generate( routeConfig.getName(), - createServiceUrl(routeConfig.getServiceName(), routeConfig.getServicePort()), + createServiceUrl( + routeConfig.getServiceName(), routeConfig.getServicePort(), namespace), routeConfig.getRoutePath(), routeConfig.getProtocol()); cmData.put(routeConfig.getName() + ".yml", traefikRouteConfig); @@ -220,7 +215,7 @@ private void generateMiddlewares( generator.writeEndObject(); } - private String createServiceUrl(String serviceName, String servicePort) { + private String createServiceUrl(String serviceName, String servicePort, String serviceNamespace) { return String.format( "http://%s.%s.svc.cluster.local:%s", serviceName, serviceNamespace, servicePort); } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolverTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolverTest.java deleted file mode 100644 index a569b3a81b2..00000000000 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/GatewayRouterResolverTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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.eclipse.che.workspace.infrastructure.kubernetes.GatewayRouterResolver.GATEWAY_CONFIGMAP_LABELS; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -import io.fabric8.kubernetes.api.model.ConfigMap; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; -import org.eclipse.che.api.workspace.server.spi.InfrastructureException; -import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; -import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironment; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGenerator; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGeneratorFactory; -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 GatewayRouterResolverTest { - - private static final String NAMESPACE = "che"; - private static final String WS_ID = "ws-1"; - - @Mock private GatewayRouteConfigGeneratorFactory configGeneratorFactory; - @Mock private GatewayRouteConfigGenerator configGenerator; - @Mock private RuntimeIdentity runtimeIdentity; - @Mock private InternalEnvironment internalEnvironment; - - private GatewayRouterResolver gatewayRouterResolver; - - @BeforeMethod - public void setUp() throws InfrastructureException { - lenient().when(configGeneratorFactory.create(NAMESPACE)).thenReturn(configGenerator); - lenient().when(configGenerator.generate()).thenReturn(Collections.singletonMap("one", "two")); - lenient().when(runtimeIdentity.getInfrastructureNamespace()).thenReturn(NAMESPACE); - lenient().when(runtimeIdentity.getWorkspaceId()).thenReturn(WS_ID); - gatewayRouterResolver = new GatewayRouterResolver(configGeneratorFactory); - } - - @Test - public void testRouteConfigsAreResolvedToConfigMaps() throws InfrastructureException { - List configs = - Arrays.asList( - new GatewayRouteConfig( - "g1", "s1", "1", "/1", "http", Collections.singletonMap("a1", "v1")), - new GatewayRouteConfig( - "g2", "s2", "2", "/2", "http", Collections.singletonMap("a2", "v2"))); - when(internalEnvironment.getGatewayRouteConfigs()).thenReturn(configs); - - List configMaps = - gatewayRouterResolver.resolve(runtimeIdentity, internalEnvironment); - - assertEquals(configMaps.size(), 2); - verify(configGenerator, times(2)).generate(); - configMaps.forEach( - cm -> { - assertEquals(cm.getMetadata().getLabels(), GATEWAY_CONFIGMAP_LABELS); - assertTrue(cm.getMetadata().getName().startsWith(WS_ID)); - assertEquals(cm.getMetadata().getAnnotations().size(), 1); - }); - configs.forEach(c -> verify(configGenerator).addRouteConfig(c)); - } - - @Test - public void testNoRouteConfigsReturnsNoConfigMaps() throws InfrastructureException { - when(internalEnvironment.getGatewayRouteConfigs()).thenReturn(Collections.emptyList()); - - List configMaps = - gatewayRouterResolver.resolve(runtimeIdentity, internalEnvironment); - - assertTrue(configMaps.isEmpty()); - } -} diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesEnvironmentProvisionerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesEnvironmentProvisionerTest.java index 9408678ef45..cc5430797d5 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesEnvironmentProvisionerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesEnvironmentProvisionerTest.java @@ -22,6 +22,7 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.provision.AsyncStoragePodInterceptor; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.AsyncStorageProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.CertificateProvisioner; +import org.eclipse.che.workspace.infrastructure.kubernetes.provision.GatewayRouterProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.GitConfigProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.ImagePullSecretProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.LogsVolumeMachineProvisioner; @@ -80,6 +81,7 @@ public class KubernetesEnvironmentProvisionerTest { @Mock private GitConfigProvisioner gitConfigProvisioner; @Mock private PreviewUrlExposer previewUrlExposer; @Mock private VcsSslCertificateProvisioner vcsSslCertificateProvisioner; + @Mock private GatewayRouterProvisioner gatewayRouterProvisioner; private KubernetesEnvironmentProvisioner k8sInfraProvisioner; @@ -111,7 +113,8 @@ public void setUp() { sshKeysProvisioner, gitConfigProvisioner, previewUrlExposer, - vcsSslCertificateProvisioner); + vcsSslCertificateProvisioner, + gatewayRouterProvisioner); provisionOrder = inOrder( logsVolumeMachineProvisioner, diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java index c8ce748188d..b87c5100cdf 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java @@ -215,7 +215,6 @@ public class KubernetesInternalRuntimeTest { @Mock private RuntimeHangingDetector runtimeHangingDetector; @Mock private KubernetesPreviewUrlCommandProvisioner previewUrlCommandProvisioner; @Mock private SecretAsContainerResourceProvisioner secretAsContainerResourceProvisioner; - @Mock private GatewayRouterResolver gatewayRouterResolver; private KubernetesServerResolverFactory serverResolverFactory; @Mock @@ -290,7 +289,6 @@ public void setup() throws Exception { previewUrlCommandProvisioner, secretAsContainerResourceProvisioner, serverResolverFactory, - gatewayRouterResolver, cheNamespace, tracer, context, @@ -1139,34 +1137,14 @@ public void testGatewayRouteConfigsAreCreatedAsConfigmapsInCheNamespace() List configMaps = Arrays.asList(cmRoute1, cmRoute2); - when(gatewayRouterResolver.resolve(internalRuntime.getContext().getIdentity(), k8sEnv)) - .thenReturn(configMaps); - // when internalRuntime.start(emptyMap()); // then - verify(gatewayRouterResolver).resolve(internalRuntime.getContext().getIdentity(), k8sEnv); verify(cheNamespace).createConfigMaps(configMaps, internalRuntime.getContext().getIdentity()); verify(cheNamespace).cleanUp(WORKSPACE_ID); } - @Test - public void dontCreateAnythingInCheNamespaceWhenNoGatewayConfigs() - throws InfrastructureException { - // given - when(gatewayRouterResolver.resolve(internalRuntime.getContext().getIdentity(), k8sEnv)) - .thenReturn(emptyList()); - - // when - internalRuntime.start(emptyMap()); - - // then - verify(gatewayRouterResolver).resolve(internalRuntime.getContext().getIdentity(), k8sEnv); - verify(cheNamespace).createConfigMaps(emptyList(), internalRuntime.getContext().getIdentity()); - verify(cheNamespace).cleanUp(WORKSPACE_ID); - } - private static MachineStatusEvent newEvent(String machineName, MachineStatus status) { return newDto(MachineStatusEvent.class) .withIdentity(DtoConverter.asDto(IDENTITY)) diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java index 77598640ac4..85ffbde82ea 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java @@ -23,7 +23,7 @@ public class TraefikGatewayRouteConfigGeneratorTest { private final GatewayRouteConfigGenerator gatewayConfigGenerator = - new TraefikGatewayRouteConfigGenerator("che-namespace"); + new TraefikGatewayRouteConfigGenerator(); @Test public void testGenerateGatewayConfig() throws InfrastructureException { @@ -61,7 +61,7 @@ public void testGenerateGatewayConfig() throws InfrastructureException { "http", Collections.emptyMap()); gatewayConfigGenerator.addRouteConfig(routeConfig); - Map generatedConfig = gatewayConfigGenerator.generate(); + Map generatedConfig = gatewayConfigGenerator.generate("che-namespace"); assertTrue(generatedConfig.containsKey("external-server-1.yml")); assertEquals(generatedConfig.get("external-server-1.yml"), expectedConfig); @@ -74,7 +74,7 @@ public void testMultipleRouteConfigsAreGeneratedAsMultipleMapEntries() GatewayRouteConfig c2 = new GatewayRouteConfig("c2", "", "", "", "", Collections.emptyMap()); gatewayConfigGenerator.addRouteConfig(c1); gatewayConfigGenerator.addRouteConfig(c2); - Map generatedConfig = gatewayConfigGenerator.generate(); + Map generatedConfig = gatewayConfigGenerator.generate("che-namespace"); assertTrue(generatedConfig.containsKey("c1.yml")); assertTrue(generatedConfig.containsKey("c2.yml")); diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java index 61c94d201de..883b7ac145b 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java @@ -32,7 +32,6 @@ import org.eclipse.che.api.workspace.server.spi.provision.InternalEnvironmentProvisioner; import org.eclipse.che.commons.annotation.Traced; import org.eclipse.che.commons.tracing.TracingTags; -import org.eclipse.che.workspace.infrastructure.kubernetes.GatewayRouterResolver; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInternalRuntime; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesRuntimeContext; import org.eclipse.che.workspace.infrastructure.kubernetes.RuntimeHangingDetector; @@ -85,7 +84,6 @@ public OpenShiftInternalRuntime( SecretAsContainerResourceProvisioner secretAsContainerResourceProvisioner, OpenShiftServerResolverFactory serverResolverFactory, - GatewayRouterResolver gatewayRouterProvisioner, CheNamespace cheNamespace, Tracer tracer, Openshift4TrustedCAProvisioner trustedCAProvisioner, @@ -112,7 +110,6 @@ public OpenShiftInternalRuntime( previewUrlCommandProvisioner, secretAsContainerResourceProvisioner, null, - gatewayRouterProvisioner, cheNamespace, tracer, context, diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntimeTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntimeTest.java index c6687762d6f..8603eeb31ca 100644 --- a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntimeTest.java +++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntimeTest.java @@ -66,7 +66,6 @@ import org.eclipse.che.api.workspace.server.spi.environment.InternalMachineConfig; import org.eclipse.che.api.workspace.server.spi.provision.InternalEnvironmentProvisioner; import org.eclipse.che.api.workspace.shared.dto.event.MachineStatusEvent; -import org.eclipse.che.workspace.infrastructure.kubernetes.GatewayRouterResolver; import org.eclipse.che.workspace.infrastructure.kubernetes.RuntimeHangingDetector; import org.eclipse.che.workspace.infrastructure.kubernetes.StartSynchronizer; import org.eclipse.che.workspace.infrastructure.kubernetes.StartSynchronizerFactory; @@ -150,7 +149,6 @@ public class OpenShiftInternalRuntimeTest { @Mock private OpenShiftPreviewUrlCommandProvisioner previewUrlCommandProvisioner; @Mock private SecretAsContainerResourceProvisioner secretAsContainerResourceProvisioner; @Mock private Openshift4TrustedCAProvisioner trustedCAProvisioner; - @Mock private GatewayRouterResolver gatewayRouterProvisioner; @Mock private CheNamespace cheNamespace; private OpenShiftServerResolverFactory serverResolverFactory; @@ -196,7 +194,6 @@ public void setup() throws Exception { previewUrlCommandProvisioner, secretAsContainerResourceProvisioner, serverResolverFactory, - gatewayRouterProvisioner, cheNamespace, tracer, trustedCAProvisioner, diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironment.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironment.java index 291eba7bd50..b5b84ff01af 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironment.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironment.java @@ -46,7 +46,7 @@ public abstract class InternalEnvironment { private Map attributes; private List commands; private DevfileImpl devfile; - private List gatewayRouteConfigs; + private final List gatewayRouteConfigs; protected InternalEnvironment() { this.warnings = new CopyOnWriteArrayList<>(); From 3cd20063aa05794d25b88dfe48cca40fbe170dc1 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Wed, 19 Aug 2020 11:15:50 +0200 Subject: [PATCH 27/47] get rid of GatewayRouteConfig Signed-off-by: Michal Vala --- .../model/workspace/config/ServerConfig.java | 3 + .../provision/GatewayRouterProvisioner.java | 67 +++++--- .../provision/GatewayTlsProvisioner.java | 18 +- .../external/GatewayRouteConfigGenerator.java | 15 +- .../server/external/GatewayServerExposer.java | 36 ++-- ...leHostExternalServiceExposureStrategy.java | 4 + .../TraefikGatewayRouteConfigGenerator.java | 47 +++--- .../GatewayRouterProvisionerTest.java | 34 ++++ .../provision/GatewayTlsProvisionerTest.java | 154 ++++++++---------- .../external/GatewayServerExposerTest.java | 4 +- ...raefikGatewayRouteConfigGeneratorTest.java | 114 ++++++------- .../spi/environment/GatewayRouteConfig.java | 114 ------------- .../spi/environment/InternalEnvironment.java | 12 -- 13 files changed, 271 insertions(+), 351 deletions(-) create mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisionerTest.java delete mode 100644 wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java 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 ca264acb7ea..6b8f228168c 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 @@ -77,6 +77,9 @@ public interface ServerConfig { */ String SERVER_NAME_ATTRIBUTE = "serverName"; + String SERVICE_NAME_ATTRIBUTE = "serviceName"; + String SERVICE_PORT_ATTRIBUTE = "servicePort"; + /** * Port used by server. * diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java index c1f2e0ab381..3d3b5fa23dd 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java @@ -1,19 +1,24 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; +import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.SERVICE_NAME_ATTRIBUTE; +import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.SERVICE_PORT_ATTRIBUTE; + import com.google.common.collect.ImmutableMap; -import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.ConfigMap; import java.util.Map; +import java.util.Map.Entry; import javax.inject.Inject; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; -import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; +import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGenerator; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGeneratorFactory; public class GatewayRouterProvisioner implements ConfigurationProvisioner { - protected static final Map GATEWAY_CONFIGMAP_LABELS = + public static final Map GATEWAY_CONFIGMAP_LABELS = ImmutableMap.builder() .put("app", "che") .put("role", "gateway-config") @@ -29,26 +34,46 @@ public GatewayRouterProvisioner(GatewayRouteConfigGeneratorFactory configGenerat @Override public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity) throws InfrastructureException { - if (k8sEnv.getGatewayRouteConfigs().isEmpty()) { - return; + for (Entry configMapEntry : k8sEnv.getConfigMaps().entrySet()) { + if (isGatewayConfig(configMapEntry.getValue())) { + + GatewayRouteConfigGenerator gatewayRouteConfigGenerator = + configGeneratorFactory.create(identity.getInfrastructureNamespace()); + gatewayRouteConfigGenerator + .addRouteConfig(configMapEntry.getKey(), configMapEntry.getValue()); + + Map servers = new Annotations.Deserializer( + configMapEntry.getValue().getMetadata().getAnnotations()).servers(); + if (servers.size() != 1) { + throw new InfrastructureException("expected 1"); + } + String scKey = servers.keySet().stream().findFirst().get(); + ServerConfigImpl server = servers.get(scKey); + + if (!server.getAttributes().containsKey(SERVICE_NAME_ATTRIBUTE) || + !server.getAttributes().containsKey(SERVICE_PORT_ATTRIBUTE)) { + throw new InfrastructureException("Need serviceName and servicePort"); + } + + final String serviceName = server.getAttributes().get(SERVICE_NAME_ATTRIBUTE); + final String servicePort = server.getAttributes().get(SERVICE_PORT_ATTRIBUTE); + + configMapEntry.getValue() + .setData(gatewayRouteConfigGenerator.generate(serviceName, servicePort, + identity.getInfrastructureNamespace())); + } } + } - for (GatewayRouteConfig routeConfig : k8sEnv.getGatewayRouteConfigs()) { - GatewayRouteConfigGenerator gatewayRouteConfigGenerator = - configGeneratorFactory.create(identity.getInfrastructureNamespace()); - gatewayRouteConfigGenerator.addRouteConfig(routeConfig); - - ConfigMapBuilder configMapBuilder = - new ConfigMapBuilder() - .withNewMetadata() - .withName(identity.getWorkspaceId() + "-" + routeConfig.getName()) - .withLabels(GATEWAY_CONFIGMAP_LABELS) - .withAnnotations(routeConfig.getAnnotations()) - .endMetadata() - .withData( - gatewayRouteConfigGenerator.generate(identity.getInfrastructureNamespace())); - - k8sEnv.getConfigMaps().put(routeConfig.getName(), configMapBuilder.build()); + public static boolean isGatewayConfig(ConfigMap configMap) { + Map labels = configMap.getMetadata().getLabels(); + for (Entry labelEntry : GATEWAY_CONFIGMAP_LABELS.entrySet()) { + if (labels == null || !labels.containsKey(labelEntry.getKey()) || !labels + .get(labelEntry.getKey()) + .equals(labelEntry.getValue())) { + return false; + } } + return true; } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java index 0cdeb90fe18..bfd6938e23a 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java @@ -13,6 +13,7 @@ import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.TlsProvisioner.getSecureProtocol; +import io.fabric8.kubernetes.api.model.ConfigMap; import java.util.Map; import javax.inject.Inject; import javax.inject.Named; @@ -20,7 +21,6 @@ import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; -import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; @@ -44,30 +44,30 @@ public void provision(T k8sEnv, RuntimeIdentity identity) throws InfrastructureE return; } - for (GatewayRouteConfig routeConfig : k8sEnv.getGatewayRouteConfigs()) { - useSecureProtocolForGatewayServers(routeConfig); + for (ConfigMap configMap : k8sEnv.getConfigMaps().values()) { + if (GatewayRouterProvisioner.isGatewayConfig(configMap)) { + useSecureProtocolForGatewayCm(configMap); + } } } - private void useSecureProtocolForGatewayServers(GatewayRouteConfig routeConfig) - throws InfrastructureException { + private void useSecureProtocolForGatewayCm(ConfigMap cm) throws InfrastructureException { Map servers = - Annotations.newDeserializer(routeConfig.getAnnotations()).servers(); + Annotations.newDeserializer(cm.getMetadata().getAnnotations()).servers(); if (servers.isEmpty()) { return; } if (servers.size() != 1) { throw new InfrastructureException( - "Expected exactly 1 server in GatewayRouteConfig [" + routeConfig.toString() + "]"); + "Expected exactly 1 server in Gateway ConfigMap [" + cm.toString() + "]"); } String scKey = servers.keySet().stream().findFirst().get(); ServerConfigImpl serverConfig = servers.get(scKey); String protocol = getSecureProtocol(serverConfig.getProtocol()); - routeConfig.setProtocol(protocol); serverConfig.setProtocol(protocol); - routeConfig + cm.getMetadata() .getAnnotations() .putAll(Annotations.newSerializer().server(scKey, serverConfig).annotations()); } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java index e03db308ed3..cfca51f2831 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java @@ -11,34 +11,25 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; +import io.fabric8.kubernetes.api.model.ConfigMap; import java.util.Map; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; -import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; /** * Generates config for external servers that we want to expose in the Gateway. * - *

Implementation must accept new {@link GatewayRouteConfig}s with {@link - * GatewayRouteConfigGenerator#addRouteConfig(GatewayRouteConfig)}. Then call to {@link - * GatewayRouteConfigGenerator#generate()} must generate gateway specific configuration for all - * added {@link GatewayRouteConfig}s. * *

Implementation provides configuration for specific Gateway technology (e.g., Traefik). */ public interface GatewayRouteConfigGenerator { /** - * Add {@link GatewayRouteConfig} to the generator so it can be generated later with {@link - * GatewayRouteConfigGenerator#generate()} - * * @param routeConfig config to add */ - void addRouteConfig(GatewayRouteConfig routeConfig); + void addRouteConfig(String name, ConfigMap routeConfig); /** * Generates content of configurations for services, defined earlier by added {@link - * GatewayRouteConfig}s with {@link - * GatewayRouteConfigGenerator#addRouteConfig(GatewayRouteConfig)}. Returned {@code Map} will be used as a value of ConfigMap and injected into Gateway pod. * *

Implementation must ensure that Gateway configured with returned content will route the @@ -54,5 +45,5 @@ public interface GatewayRouteConfigGenerator { * * @return full content of configuration for the services */ - Map generate(String namespace) throws InfrastructureException; + Map generate(String serviceName, String servicePort, String namespace) throws InfrastructureException; } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java index 7ce14adece0..2dd6210dbe2 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java @@ -12,18 +12,22 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; import static java.lang.Boolean.TRUE; +import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.SERVICE_NAME_ATTRIBUTE; +import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.SERVICE_PORT_ATTRIBUTE; import static org.eclipse.che.workspace.infrastructure.kubernetes.Annotations.CREATE_IN_CHE_INSTALLATION_NAMESPACE; +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.IntOrString; import io.fabric8.kubernetes.api.model.ServicePort; import java.util.Map; import javax.inject.Inject; 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.environment.GatewayRouteConfig; import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.provision.GatewayRouterProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.server.KubernetesServerExposer; /** @@ -68,31 +72,39 @@ public void expose( } for (String esKey : externalServers.keySet()) { - k8sEnv.addGatewayRouteConfig( - createGatewayRouteConfig( - machineName, serviceName, serverId, servicePort, esKey, externalServers.get(esKey))); + final String serverName = KubernetesServerExposer.makeServerNameValidForDns(serverId); + final String name = createName(serviceName, serverName); + k8sEnv.getConfigMaps().put(name, + createGatewayRouteConfigmap(name, machineName, serviceName, servicePort, serverName, esKey, + externalServers.get(esKey))); } } - private GatewayRouteConfig createGatewayRouteConfig( - String machineName, + private ConfigMap createGatewayRouteConfigmap(String name, String machineName, String serviceName, - String serverId, ServicePort servicePort, + String serverName, String scRef, ServerConfig serverConfig) { - final String serverName = KubernetesServerExposer.makeServerNameValidForDns(serverId); - final String name = createName(serviceName, serverName); + final String path = ensureDontEndsWithSlash(strategy.getExternalPath(serviceName, serverName)); - final String protocol = serverConfig.getProtocol(); + serverConfig.getAttributes().put(SERVICE_NAME_ATTRIBUTE, serviceName); + serverConfig.getAttributes().put(SERVICE_PORT_ATTRIBUTE, getTargetPort(servicePort.getTargetPort())); + final Map annotations = Annotations.newSerializer() .server(scRef, new ServerConfigImpl(serverConfig).withPath(path)) .machineName(machineName) .annotations(); annotations.put(CREATE_IN_CHE_INSTALLATION_NAMESPACE, TRUE.toString()); - return new GatewayRouteConfig( - name, serviceName, getTargetPort(servicePort.getTargetPort()), path, protocol, annotations); + + ConfigMapBuilder gatewayConfigMap = new ConfigMapBuilder() + .withNewMetadata() + .withName(name) + .withLabels(GatewayRouterProvisioner.GATEWAY_CONFIGMAP_LABELS) + .withAnnotations(annotations) + .endMetadata(); + return gatewayConfigMap.build(); } private String ensureDontEndsWithSlash(String path) { 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 69d7395684f..3888edf07d1 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 @@ -60,4 +60,8 @@ public String getExternalHost(String serviceName, String serverName) { public String getExternalPath(String serviceName, String serverName) { return "/" + serviceName + "/" + serverName; } + + public static String extractServiceNameFromExternalPath(String path) { + return path.substring(1).split("/")[0]; + } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java index 48241ac6324..ef53eb8f5f0 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java @@ -15,31 +15,27 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; +import io.fabric8.kubernetes.api.model.ConfigMap; import java.io.IOException; import java.io.StringWriter; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; -import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; +import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; /** Config generator for Traefik Gateway */ public class TraefikGatewayRouteConfigGenerator implements GatewayRouteConfigGenerator { - private final List routeConfigs = new ArrayList<>(); + private final Map routeConfigs = new HashMap<>(); @Override - public void addRouteConfig(GatewayRouteConfig routeConfig) { - this.routeConfigs.add(routeConfig); + public void addRouteConfig(String name, ConfigMap routeConfig) { + this.routeConfigs.put(name, routeConfig); } /** - * Generate Traefik configuration for all added {@link GatewayRouteConfig}s. - * - *

Each {@link GatewayRouteConfig} is translated into Traefik configuration under extra key in - * returned {@link Map} `{GatewayRouteConfig#name}.yml`. - * *

Content of single service configuration looks like this: * *

@@ -64,17 +60,24 @@ public void addRouteConfig(GatewayRouteConfig routeConfig) {
    * 
*/ @Override - public Map generate(String namespace) throws InfrastructureException { + public Map generate(String serviceName, String servicePort, String namespace) throws InfrastructureException { Map cmData = new HashMap<>(); - for (GatewayRouteConfig routeConfig : routeConfigs) { - String traefikRouteConfig = - generate( - routeConfig.getName(), - createServiceUrl( - routeConfig.getServiceName(), routeConfig.getServicePort(), namespace), - routeConfig.getRoutePath(), - routeConfig.getProtocol()); - cmData.put(routeConfig.getName() + ".yml", traefikRouteConfig); + for (Entry routeConfig : routeConfigs.entrySet()) { + Map servers = + new Annotations.Deserializer(routeConfig.getValue().getMetadata().getAnnotations()) + .servers(); + if (servers.size() != 1) { + throw new InfrastructureException( + "Expected exactly 1 server [" + routeConfig.getValue().toString() + "]"); + } + ServerConfigImpl server = servers.get(servers.keySet().stream().findFirst().get()); + + String traefikRouteConfig = generate( + routeConfig.getKey(), + createServiceUrl(serviceName, servicePort, namespace), + server.getPath(), + server.getProtocol()); + cmData.put(routeConfig.getKey() + ".yml", traefikRouteConfig); } return cmData; } @@ -215,7 +218,7 @@ private void generateMiddlewares( generator.writeEndObject(); } - private String createServiceUrl(String serviceName, String servicePort, String serviceNamespace) { + String createServiceUrl(String serviceName, String servicePort, String serviceNamespace) { return String.format( "http://%s.%s.svc.cluster.local:%s", serviceName, serviceNamespace, servicePort); } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisionerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisionerTest.java new file mode 100644 index 00000000000..d5f6e919b30 --- /dev/null +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisionerTest.java @@ -0,0 +1,34 @@ +package org.eclipse.che.workspace.infrastructure.kubernetes.provision; + +import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.GatewayRouterProvisioner.GATEWAY_CONFIGMAP_LABELS; +import static org.testng.Assert.*; + +import com.google.common.collect.ImmutableMap; +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import java.util.Collections; +import java.util.Map; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class GatewayRouterProvisionerTest { + @Test(dataProvider = "isGatewayConfigData") + public void testIsGatewayConfig(Map labels, boolean isGatewayConfigExpected) { + ConfigMap cm = new ConfigMapBuilder().withNewMetadata().withLabels(labels).endMetadata().build(); + assertEquals(GatewayRouterProvisioner.isGatewayConfig(cm), isGatewayConfigExpected); + } + + @DataProvider + public Object[][] isGatewayConfigData() { + return new Object[][] { + {GATEWAY_CONFIGMAP_LABELS, true}, + {ImmutableMap.builder().putAll(GATEWAY_CONFIGMAP_LABELS).put("other", "value").build(), true}, + {Collections.emptyMap(), false}, + {ImmutableMap.of("one", "two"), false}, + {ImmutableMap.of(), false}, + {ImmutableMap.of("app", "yes", "role", "no"), false}, + {ImmutableMap.of("app", GATEWAY_CONFIGMAP_LABELS.get("app"), "role", "no"), false}, + {ImmutableMap.of("app", "no", "role", GATEWAY_CONFIGMAP_LABELS.get("role")), false}, + }; + } +} diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisionerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisionerTest.java index 77637f187f1..68a18d04a6a 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisionerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisionerTest.java @@ -11,95 +11,77 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonList; -import static java.util.Collections.singletonMap; -import static org.mockito.Mockito.when; -import static org.testng.Assert.*; - -import java.util.HashMap; -import java.util.Map; -import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; -import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl; -import org.eclipse.che.api.workspace.server.spi.InfrastructureException; -import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; -import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; -import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; -import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; -import org.testng.annotations.Test; @Listeners(MockitoTestNGListener.class) public class GatewayTlsProvisionerTest { - - public static final String WORKSPACE_ID = "workspace123"; - @Mock private KubernetesEnvironment k8sEnv; - @Mock private RuntimeIdentity runtimeIdentity; - - private final ServerConfigImpl httpServer = - new ServerConfigImpl("8080/tpc", "http", "/api", emptyMap()); - private final ServerConfigImpl wsServer = - new ServerConfigImpl("8080/tpc", "ws", "/ws", emptyMap()); - private final Map annotations = - singletonMap("annotation-key", "annotation-value"); - private final String machine = "machine"; - - @Test(dataProvider = "tlsProvisionData") - public void provisionTlsForGatewayRouteConfig( - ServerConfigImpl server, boolean tlsEnabled, String expectedProtocol) throws Exception { - // given - Map composedAnnotations = new HashMap<>(annotations); - composedAnnotations.putAll( - Annotations.newSerializer().server("server", server).machineName(machine).annotations()); - GatewayRouteConfig routeConfig = - new GatewayRouteConfig("gate1", "svc1", "1234", "/hello", "http", composedAnnotations); - GatewayTlsProvisioner gatewayTlsProvisioner = - new GatewayTlsProvisioner<>(tlsEnabled); - - when(k8sEnv.getGatewayRouteConfigs()).thenReturn(singletonList(routeConfig)); - - // when - gatewayTlsProvisioner.provision(k8sEnv, runtimeIdentity); - - // then - Map servers = - Annotations.newDeserializer(routeConfig.getAnnotations()).servers(); - assertEquals(servers.get("server").getProtocol(), expectedProtocol); - } - - @DataProvider - public Object[][] tlsProvisionData() { - return new Object[][] { - {httpServer, true, "https"}, - {httpServer, false, "http"}, - {wsServer, true, "wss"}, - {wsServer, false, "ws"}, - }; - } - - @Test(expectedExceptions = InfrastructureException.class) - public void throwExceptionWhenMultipleServersInGatewayRouteConfigAnnotations() - throws InfrastructureException { - // given - Map composedAnnotations = new HashMap<>(annotations); - composedAnnotations.putAll( - Annotations.newSerializer() - .server("server1", httpServer) - .server("server2", wsServer) - .machineName(machine) - .annotations()); - GatewayRouteConfig routeConfig = - new GatewayRouteConfig("gate1", "svc1", "1234", "/hello", "http", composedAnnotations); - - when(k8sEnv.getGatewayRouteConfigs()).thenReturn(singletonList(routeConfig)); - GatewayTlsProvisioner gatewayTlsProvisioner = - new GatewayTlsProvisioner<>(true); - - // when - gatewayTlsProvisioner.provision(k8sEnv, runtimeIdentity); - - // then exception - } +// +// public static final String WORKSPACE_ID = "workspace123"; +// @Mock private KubernetesEnvironment k8sEnv; +// @Mock private RuntimeIdentity runtimeIdentity; +// +// private final ServerConfigImpl httpServer = +// new ServerConfigImpl("8080/tpc", "http", "/api", emptyMap()); +// private final ServerConfigImpl wsServer = +// new ServerConfigImpl("8080/tpc", "ws", "/ws", emptyMap()); +// private final Map annotations = +// singletonMap("annotation-key", "annotation-value"); +// private final String machine = "machine"; +// +// @Test(dataProvider = "tlsProvisionData") +// public void provisionTlsForGatewayRouteConfig( +// ServerConfigImpl server, boolean tlsEnabled, String expectedProtocol) throws Exception { +// // given +// Map composedAnnotations = new HashMap<>(annotations); +// composedAnnotations.putAll( +// Annotations.newSerializer().server("server", server).machineName(machine).annotations()); +// new GatewayRouteConfig("gate1", "svc1", "1234", "/hello", "http", composedAnnotations); +// GatewayTlsProvisioner gatewayTlsProvisioner = +// new GatewayTlsProvisioner<>(tlsEnabled); +// +// when(k8sEnv.getGatewayRouteConfigs()).thenReturn(singletonList(routeConfig)); +// +// // when +// gatewayTlsProvisioner.provision(k8sEnv, runtimeIdentity); +// +// // then +// Map servers = +// Annotations.newDeserializer(routeConfig.getAnnotations()).servers(); +// assertEquals(servers.get("server").getProtocol(), expectedProtocol); +// } +// +// @DataProvider +// public Object[][] tlsProvisionData() { +// return new Object[][] { +// {httpServer, true, "https"}, +// {httpServer, false, "http"}, +// {wsServer, true, "wss"}, +// {wsServer, false, "ws"}, +// }; +// } +// +// @Test(expectedExceptions = InfrastructureException.class) +// public void throwExceptionWhenMultipleServersInGatewayRouteConfigAnnotations() +// throws InfrastructureException { +// // given +// Map composedAnnotations = new HashMap<>(annotations); +// composedAnnotations.putAll( +// Annotations.newSerializer() +// .server("server1", httpServer) +// .server("server2", wsServer) +// .machineName(machine) +// .annotations()); +// GatewayRouteConfig routeConfig = +// new GatewayRouteConfig("gate1", "svc1", "1234", "/hello", "http", composedAnnotations); +// +// when(k8sEnv.getGatewayRouteConfigs()).thenReturn(singletonList(routeConfig)); +// GatewayTlsProvisioner gatewayTlsProvisioner = +// new GatewayTlsProvisioner<>(true); +// +// // when +// gatewayTlsProvisioner.provision(k8sEnv, runtimeIdentity); +// +// // then exception +// } } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java index 7d1c78aea1a..c6bd93c8b72 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java @@ -14,11 +14,9 @@ import io.fabric8.kubernetes.api.model.IntOrString; import io.fabric8.kubernetes.api.model.ServicePort; import java.util.Collections; -import java.util.List; 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.api.workspace.server.spi.environment.GatewayRouteConfig; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; import org.testng.annotations.Test; @@ -42,7 +40,7 @@ public class GatewayServerExposerTest { public void testExposeServiceWithGatewayConfigmap() { KubernetesEnvironment k8sEnv = KubernetesEnvironment.builder().build(); serverExposer.expose(k8sEnv, machineName, serviceName, serverId, servicePort, servers); - List configMaps = k8sEnv.getGatewayRouteConfigs(); +// List configMaps = k8sEnv.getGatewayRouteConfigs(); // TODO: assert created route configs diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java index 85ffbde82ea..f0378b7a5d1 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java @@ -14,69 +14,63 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; -import java.util.Collections; -import java.util.Map; -import org.eclipse.che.api.workspace.server.spi.InfrastructureException; -import org.eclipse.che.api.workspace.server.spi.environment.GatewayRouteConfig; -import org.testng.annotations.Test; - public class TraefikGatewayRouteConfigGeneratorTest { private final GatewayRouteConfigGenerator gatewayConfigGenerator = new TraefikGatewayRouteConfigGenerator(); - @Test - public void testGenerateGatewayConfig() throws InfrastructureException { - String expectedConfig = - "http:\n" - + " routers:\n" - + " external-server-1:\n" - + " rule: \"PathPrefix(`/blabol-cesta`)\"\n" - + " service: \"external-server-1\"\n" - + " middlewares:\n" - + " - \"external-server-1\"\n" - + " - \"external-server-1_headers\"\n" - + " priority: 100\n" - + " services:\n" - + " external-server-1:\n" - + " loadBalancer:\n" - + " servers:\n" - + " - url: \"http://service-url.che-namespace.svc.cluster.local:1234\"\n" - + " middlewares:\n" - + " external-server-1:\n" - + " stripPrefix:\n" - + " prefixes:\n" - + " - \"/blabol-cesta\"\n" - + " external-server-1_headers:\n" - + " headers:\n" - + " customRequestHeaders:\n" - + " X-Forwarded-Proto: \"http\""; - - GatewayRouteConfig routeConfig = - new GatewayRouteConfig( - "external-server-1", - "service-url", - "1234", - "/blabol-cesta", - "http", - Collections.emptyMap()); - gatewayConfigGenerator.addRouteConfig(routeConfig); - Map generatedConfig = gatewayConfigGenerator.generate("che-namespace"); - - assertTrue(generatedConfig.containsKey("external-server-1.yml")); - assertEquals(generatedConfig.get("external-server-1.yml"), expectedConfig); - } - - @Test - public void testMultipleRouteConfigsAreGeneratedAsMultipleMapEntries() - throws InfrastructureException { - GatewayRouteConfig c1 = new GatewayRouteConfig("c1", "", "", "", "", Collections.emptyMap()); - GatewayRouteConfig c2 = new GatewayRouteConfig("c2", "", "", "", "", Collections.emptyMap()); - gatewayConfigGenerator.addRouteConfig(c1); - gatewayConfigGenerator.addRouteConfig(c2); - Map generatedConfig = gatewayConfigGenerator.generate("che-namespace"); - - assertTrue(generatedConfig.containsKey("c1.yml")); - assertTrue(generatedConfig.containsKey("c2.yml")); - } +// @Test +// public void testGenerateGatewayConfig() throws InfrastructureException { +// String expectedConfig = +// "http:\n" +// + " routers:\n" +// + " external-server-1:\n" +// + " rule: \"PathPrefix(`/blabol-cesta`)\"\n" +// + " service: \"external-server-1\"\n" +// + " middlewares:\n" +// + " - \"external-server-1\"\n" +// + " - \"external-server-1_headers\"\n" +// + " priority: 100\n" +// + " services:\n" +// + " external-server-1:\n" +// + " loadBalancer:\n" +// + " servers:\n" +// + " - url: \"http://service-url.che-namespace.svc.cluster.local:1234\"\n" +// + " middlewares:\n" +// + " external-server-1:\n" +// + " stripPrefix:\n" +// + " prefixes:\n" +// + " - \"/blabol-cesta\"\n" +// + " external-server-1_headers:\n" +// + " headers:\n" +// + " customRequestHeaders:\n" +// + " X-Forwarded-Proto: \"http\""; +// +// GatewayRouteConfig routeConfig = +// new GatewayRouteConfig( +// "external-server-1", +// "service-url", +// "1234", +// "/blabol-cesta", +// "http", +// Collections.emptyMap()); +// gatewayConfigGenerator.addRouteConfig(routeConfig); +// Map generatedConfig = gatewayConfigGenerator.generate("che-namespace"); +// +// assertTrue(generatedConfig.containsKey("external-server-1.yml")); +// assertEquals(generatedConfig.get("external-server-1.yml"), expectedConfig); +// } +// +// @Test +// public void testMultipleRouteConfigsAreGeneratedAsMultipleMapEntries() +// throws InfrastructureException { +// GatewayRouteConfig c1 = new GatewayRouteConfig("c1", "", "", "", "", Collections.emptyMap()); +// GatewayRouteConfig c2 = new GatewayRouteConfig("c2", "", "", "", "", Collections.emptyMap()); +// gatewayConfigGenerator.addRouteConfig(c1); +// gatewayConfigGenerator.addRouteConfig(c2); +// Map generatedConfig = gatewayConfigGenerator.generate("che-namespace"); +// +// assertTrue(generatedConfig.containsKey("c1.yml")); +// assertTrue(generatedConfig.containsKey("c2.yml")); +// } } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java deleted file mode 100644 index 1654cd3bf2e..00000000000 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/GatewayRouteConfig.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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.api.workspace.server.spi.environment; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.StringJoiner; - -/** - * Data object that holds all needed info for configuring individual gateway routes. - * - *

It's used in case of gateway based single-host - * (`che.infra.kubernetes.server_strategy=default-host=single-host` AND - * `che.infra.kubernetes.single_host.workspace.exposure=gateway`). - * - *

Instances of {@link GatewayRouteConfig} are later transformed into gateway-specific - * configuration and into Kubernetes objects needed to properly configure the Gateway. - */ -public class GatewayRouteConfig { - - private final String name; - private final String serviceName; - private final String servicePort; - private final String routePath; - private String protocol; - private final Map annotations; - - public GatewayRouteConfig( - String name, - String serviceName, - String servicePort, - String routePath, - String protocol, - Map annotations) { - this.name = name; - this.serviceName = serviceName; - this.servicePort = servicePort; - this.routePath = routePath; - this.protocol = protocol; - this.annotations = new HashMap<>(annotations); - } - - @Override - public String toString() { - return new StringJoiner(", ", GatewayRouteConfig.class.getSimpleName() + "[", "]") - .add("name='" + name + "'") - .add("serviceName='" + serviceName + "'") - .add("servicePort='" + servicePort + "'") - .add("routePath='" + routePath + "'") - .add("protocol='" + protocol + "'") - .add("annotations=" + annotations) - .toString(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - GatewayRouteConfig that = (GatewayRouteConfig) o; - return Objects.equals(name, that.name) - && Objects.equals(serviceName, that.serviceName) - && Objects.equals(servicePort, that.servicePort) - && Objects.equals(routePath, that.routePath) - && Objects.equals(protocol, that.protocol) - && Objects.equals(annotations, that.annotations); - } - - @Override - public int hashCode() { - return Objects.hash(name, serviceName, servicePort, routePath, protocol, annotations); - } - - public String getName() { - return name; - } - - public String getServiceName() { - return serviceName; - } - - public String getRoutePath() { - return routePath; - } - - public Map getAnnotations() { - return annotations; - } - - public String getServicePort() { - return servicePort; - } - - public String getProtocol() { - return protocol; - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } -} diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironment.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironment.java index b5b84ff01af..80da8a1c4b0 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironment.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironment.java @@ -46,11 +46,9 @@ public abstract class InternalEnvironment { private Map attributes; private List commands; private DevfileImpl devfile; - private final List gatewayRouteConfigs; protected InternalEnvironment() { this.warnings = new CopyOnWriteArrayList<>(); - this.gatewayRouteConfigs = new ArrayList<>(); } protected InternalEnvironment( @@ -62,7 +60,6 @@ protected InternalEnvironment( this.warnings.addAll(warnings); } this.type = recipe != null ? recipe.getType() : null; - this.gatewayRouteConfigs = new ArrayList<>(); } protected InternalEnvironment(InternalEnvironment internalEnvironment) { @@ -73,7 +70,6 @@ protected InternalEnvironment(InternalEnvironment internalEnvironment) { this.attributes = internalEnvironment.getAttributes(); this.commands = internalEnvironment.getCommands(); this.devfile = internalEnvironment.getDevfile(); - this.gatewayRouteConfigs = new ArrayList<>(internalEnvironment.getGatewayRouteConfigs()); } /** @@ -196,12 +192,4 @@ public DevfileImpl getDevfile() { public void setDevfile(DevfileImpl devfile) { this.devfile = devfile; } - - public List getGatewayRouteConfigs() { - return gatewayRouteConfigs; - } - - public void addGatewayRouteConfig(GatewayRouteConfig gatewayRouteConfig) { - gatewayRouteConfigs.add(gatewayRouteConfig); - } } From 9508e6c3c095064d5d0a21134a3026ad5d60687e Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 06:59:20 +0200 Subject: [PATCH 28/47] javadocs and refactorings Signed-off-by: Michal Vala --- .../model/workspace/config/ServerConfig.java | 11 +++++ .../kubernetes/Annotations.java | 5 +++ .../kubernetes/KubernetesInternalRuntime.java | 41 +++++++++++++------ .../kubernetes/namespace/CheNamespace.java | 16 ++++---- 4 files changed, 52 insertions(+), 21 deletions(-) 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 6b8f228168c..d01f4ef36aa 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 @@ -77,7 +77,18 @@ public interface ServerConfig { */ String SERVER_NAME_ATTRIBUTE = "serverName"; + /** + * This attribute is used to remember name of the service for single-host gateway configuration. + * It's used internally only, so the attribute is removed from {@link ServerConfig}'s attributes + * before going outside. + */ String SERVICE_NAME_ATTRIBUTE = "serviceName"; + + /** + * This attribute is used to remember port of the service for single-host gateway configuration. + * It's used internally only, so the attribute is removed from {@link ServerConfig}'s attributes + * before going outside. + */ String SERVICE_PORT_ATTRIBUTE = "servicePort"; /** diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Annotations.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Annotations.java index c05e26be59e..5a89947566c 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Annotations.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Annotations.java @@ -41,6 +41,11 @@ public class Annotations { public static final String MACHINE_NAME_ANNOTATION = ANNOTATION_PREFIX + "machine.name"; + /** + * Object annotated with this set to `true` should be created in Che installation namespace. It's + * used only internally so it may be removed before actually creating k8s object, so it's not + * exposed. + */ public static final String CREATE_IN_CHE_INSTALLATION_NAMESPACE = ANNOTATION_PREFIX + "installation.namespace"; diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java index c3bd1824a5e..8d2403002c0 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java @@ -701,28 +701,43 @@ protected List createConfigMaps(KubernetesEnvironment env, RuntimeIde TracingTags.WORKSPACE_ID.set(identity.getWorkspaceId()); List createdConfigMaps = new ArrayList<>(); + + List cheNamespaceConfigMaps = new ArrayList<>(); for (ConfigMap configMap : env.getConfigMaps().values()) { Map annotations = configMap.getMetadata().getAnnotations(); - if (annotations == null - || annotations.isEmpty() - || FALSE - .toString() - .equals( - annotations.getOrDefault( - CREATE_IN_CHE_INSTALLATION_NAMESPACE, FALSE.toString()))) { - createdConfigMaps.add(namespace.configMaps().create(configMap)); - } else if (TRUE.toString() - .equals( - annotations.getOrDefault(CREATE_IN_CHE_INSTALLATION_NAMESPACE, FALSE.toString()))) { - createdConfigMaps.add(cheNamespace.createConfigMap(configMap, identity)); + if (shouldCreateInCheNamespace(annotations)) { + // we collect the che namespace configmaps into separate list + cheNamespaceConfigMaps.add(configMap); } else { - throw new InfrastructureException("what?"); + createdConfigMaps.add(namespace.configMaps().create(configMap)); } } + // create che namespace configmaps in one batch, because we're doing some extra checks inside + createdConfigMaps.addAll(cheNamespace.createConfigMaps(cheNamespaceConfigMaps, identity)); + return createdConfigMaps; } + /** + * Create in Che installation namespace only if there is {@link + * Annotations#CREATE_IN_CHE_INSTALLATION_NAMESPACE} annotation set exactly to `true`. In all + * other cases we create the object in Workspace's namespace. + * + * @param annotations object's annotations + * @return `true` if {@link Annotations#CREATE_IN_CHE_INSTALLATION_NAMESPACE} is set to `true`. + * False otherwise. + */ + private boolean shouldCreateInCheNamespace(Map annotations) { + if (annotations == null || annotations.isEmpty()) { + return false; + } + + return annotations + .getOrDefault(CREATE_IN_CHE_INSTALLATION_NAMESPACE, FALSE.toString()) + .equals(TRUE.toString()); + } + @Traced @SuppressWarnings("WeakerAccess") // package-private so that interception is possible List createServices(KubernetesEnvironment env, String workspaceId) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java index e2c80c128fa..21469d9990f 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java @@ -11,12 +11,14 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace; +import static org.eclipse.che.workspace.infrastructure.kubernetes.Annotations.CREATE_IN_CHE_INSTALLATION_NAMESPACE; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_WORKSPACE_ID_LABEL; import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.putLabel; import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.client.KubernetesClientException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; @@ -60,16 +62,16 @@ public CheNamespace( *

`workspaceId` from given `identity` must be valid workspace ID, that is in {@link * WorkspaceStatus#STARTING} state. Otherwise, {@link InfrastructureException} is thrown. * - * @param configMaps to create + * @param configMap to create * @param identity to validate and label configmaps * @return created {@link ConfigMap}s * @throws InfrastructureException when something goes wrong */ - public ConfigMap createConfigMap(ConfigMap configMap, RuntimeIdentity identity) + private ConfigMap createConfigMap(ConfigMap configMap, RuntimeIdentity identity) throws InfrastructureException { - validate(identity, WorkspaceStatus.STARTING); - putLabel(configMap, CHE_WORKSPACE_ID_LABEL, identity.getWorkspaceId()); + // remove this annotation, so it's not exposed in actual k8s object + configMap.getMetadata().getAnnotations().remove(CREATE_IN_CHE_INSTALLATION_NAMESPACE); return clientFactory.create().configMaps().inNamespace(cheNamespaceName).create(configMap); } @@ -88,15 +90,13 @@ public ConfigMap createConfigMap(ConfigMap configMap, RuntimeIdentity identity) public List createConfigMaps(List configMaps, RuntimeIdentity identity) throws InfrastructureException { if (configMaps.isEmpty()) { - return configMaps; + return Collections.emptyList(); } validate(identity, WorkspaceStatus.STARTING); List createdConfigMaps = new ArrayList<>(); for (ConfigMap cm : configMaps) { - putLabel(cm, CHE_WORKSPACE_ID_LABEL, identity.getWorkspaceId()); - createdConfigMaps.add( - clientFactory.create().configMaps().inNamespace(cheNamespaceName).create(cm)); + createdConfigMaps.add(createConfigMap(cm, identity)); } return createdConfigMaps; } From 5e6051d2490afd7024cd46c1a9fd8f5d82bd64d2 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 07:02:14 +0200 Subject: [PATCH 29/47] revert unnecessary change Signed-off-by: Michal Vala --- .../infrastructure/kubernetes/KubernetesRuntimeContext.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesRuntimeContext.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesRuntimeContext.java index dde6eefd172..c34350dbf0a 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesRuntimeContext.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesRuntimeContext.java @@ -16,6 +16,7 @@ import java.util.Optional; import javax.inject.Inject; import javax.inject.Named; +import org.eclipse.che.api.core.ValidationException; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.InternalInfrastructureException; @@ -46,7 +47,8 @@ public KubernetesRuntimeContext( KubernetesRuntimeStateCache runtimeStatuses, @Assisted T kubernetesEnvironment, @Assisted RuntimeIdentity identity, - @Assisted RuntimeInfrastructure infrastructure) { + @Assisted RuntimeInfrastructure infrastructure) + throws ValidationException, InfrastructureException { super(kubernetesEnvironment, identity, infrastructure); this.namespaceFactory = namespaceFactory; this.runtimeFactory = runtimeFactory; From e30d27967897fae45c86092f18a96a17677abb06 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 07:23:25 +0200 Subject: [PATCH 30/47] cleanup, refactor, javadocs of GatewayRouteProvisioner Signed-off-by: Michal Vala --- .../provision/GatewayRouterProvisioner.java | 68 +++++++++++++------ 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java index 3d3b5fa23dd..e75fb23af9b 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java @@ -2,6 +2,7 @@ import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.SERVICE_NAME_ATTRIBUTE; import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.SERVICE_PORT_ATTRIBUTE; +import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.isLabeled; import com.google.common.collect.ImmutableMap; import io.fabric8.kubernetes.api.model.ConfigMap; @@ -16,8 +17,15 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGenerator; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGeneratorFactory; +/** + * This provisioner finds {@link ConfigMap}s, that configures the single-host Gateway, generates + * Gateway configuration and puts it into their data. + * + *

It uses {@link GatewayRouteConfigGenerator} to generate the gateway configuration. + */ public class GatewayRouterProvisioner implements ConfigurationProvisioner { + /** Configmap labeled with these holds the configuration of single-host gateway route */ public static final Map GATEWAY_CONFIGMAP_LABELS = ImmutableMap.builder() .put("app", "che") @@ -36,41 +44,57 @@ public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity) throws InfrastructureException { for (Entry configMapEntry : k8sEnv.getConfigMaps().entrySet()) { if (isGatewayConfig(configMapEntry.getValue())) { + ConfigMap gatewayConfigMap = configMapEntry.getValue(); - GatewayRouteConfigGenerator gatewayRouteConfigGenerator = - configGeneratorFactory.create(identity.getInfrastructureNamespace()); - gatewayRouteConfigGenerator - .addRouteConfig(configMapEntry.getKey(), configMapEntry.getValue()); - - Map servers = new Annotations.Deserializer( - configMapEntry.getValue().getMetadata().getAnnotations()).servers(); + Map servers = + new Annotations.Deserializer(gatewayConfigMap.getMetadata().getAnnotations()).servers(); if (servers.size() != 1) { - throw new InfrastructureException("expected 1"); + throw new InfrastructureException( + "Expected only 1 server in gateway config ConfigMap's annotations."); } - String scKey = servers.keySet().stream().findFirst().get(); - ServerConfigImpl server = servers.get(scKey); + Entry serverConfigEntry = servers.entrySet().iterator().next(); + ServerConfigImpl server = serverConfigEntry.getValue(); - if (!server.getAttributes().containsKey(SERVICE_NAME_ATTRIBUTE) || - !server.getAttributes().containsKey(SERVICE_PORT_ATTRIBUTE)) { - throw new InfrastructureException("Need serviceName and servicePort"); + if (!server.getAttributes().containsKey(SERVICE_NAME_ATTRIBUTE) + || !server.getAttributes().containsKey(SERVICE_PORT_ATTRIBUTE)) { + throw new InfrastructureException( + "Expected `serviceName` and `servicePort` in gateway config ServerConfig attributes."); } - final String serviceName = server.getAttributes().get(SERVICE_NAME_ATTRIBUTE); - final String servicePort = server.getAttributes().get(SERVICE_PORT_ATTRIBUTE); + // We're now creating only 1 gateway route configuration per ConfigMap, so we need to create + // generator in each loop iteration. + GatewayRouteConfigGenerator gatewayRouteConfigGenerator = + configGeneratorFactory.create(identity.getInfrastructureNamespace()); + gatewayRouteConfigGenerator.addRouteConfig(configMapEntry.getKey(), gatewayConfigMap); + + Map gatewayConfiguration = + gatewayRouteConfigGenerator.generate(identity.getInfrastructureNamespace()); + gatewayConfigMap.setData(gatewayConfiguration); - configMapEntry.getValue() - .setData(gatewayRouteConfigGenerator.generate(serviceName, servicePort, - identity.getInfrastructureNamespace())); + // Configuration is now generated, so remove these internal attributes + server.getAttributes().remove(SERVICE_NAME_ATTRIBUTE); + server.getAttributes().remove(SERVICE_PORT_ATTRIBUTE); + gatewayConfigMap + .getMetadata() + .getAnnotations() + .putAll( + new Annotations.Serializer() + .server(serverConfigEntry.getKey(), server) + .annotations()); } } } + /** + * Check whether configmap is gateway route configuration. That is defined by {@link + * GatewayRouterProvisioner#GATEWAY_CONFIGMAP_LABELS} labels. + * + * @param configMap to check + * @return `true` if ConfigMap is gateway route configuration, `false` otherwise + */ public static boolean isGatewayConfig(ConfigMap configMap) { - Map labels = configMap.getMetadata().getLabels(); for (Entry labelEntry : GATEWAY_CONFIGMAP_LABELS.entrySet()) { - if (labels == null || !labels.containsKey(labelEntry.getKey()) || !labels - .get(labelEntry.getKey()) - .equals(labelEntry.getValue())) { + if (!isLabeled(configMap, labelEntry.getKey(), labelEntry.getValue())) { return false; } } From 8480ba9b22f83b8e8699a93d2d7ecdb6bb169a33 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 07:29:19 +0200 Subject: [PATCH 31/47] cleanup, better exception messages Signed-off-by: Michal Vala --- .../provision/GatewayRouterProvisioner.java | 8 ++++-- .../provision/GatewayTlsProvisioner.java | 27 ++++++++++++------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java index e75fb23af9b..830da2b2fc6 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java @@ -50,7 +50,9 @@ public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity) new Annotations.Deserializer(gatewayConfigMap.getMetadata().getAnnotations()).servers(); if (servers.size() != 1) { throw new InfrastructureException( - "Expected only 1 server in gateway config ConfigMap's annotations."); + "Expected only 1 server in gateway config ConfigMap's '" + + gatewayConfigMap.getMetadata().getName() + + "' annotations. This is a bug, please report."); } Entry serverConfigEntry = servers.entrySet().iterator().next(); ServerConfigImpl server = serverConfigEntry.getValue(); @@ -58,7 +60,9 @@ public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity) if (!server.getAttributes().containsKey(SERVICE_NAME_ATTRIBUTE) || !server.getAttributes().containsKey(SERVICE_PORT_ATTRIBUTE)) { throw new InfrastructureException( - "Expected `serviceName` and `servicePort` in gateway config ServerConfig attributes."); + "Expected `serviceName` and `servicePort` in gateway config ServerConfig attributes for gateway config Configmap '" + + gatewayConfigMap.getMetadata().getName() + + "'. This is a bug, please report."); } // We're now creating only 1 gateway route configuration per ConfigMap, so we need to create diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java index bfd6938e23a..882506f60a0 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisioner.java @@ -15,6 +15,7 @@ import io.fabric8.kubernetes.api.model.ConfigMap; import java.util.Map; +import java.util.Map.Entry; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; @@ -46,29 +47,35 @@ public void provision(T k8sEnv, RuntimeIdentity identity) throws InfrastructureE for (ConfigMap configMap : k8sEnv.getConfigMaps().values()) { if (GatewayRouterProvisioner.isGatewayConfig(configMap)) { - useSecureProtocolForGatewayCm(configMap); + useSecureProtocolForGatewayConfigMap(configMap); } } } - private void useSecureProtocolForGatewayCm(ConfigMap cm) throws InfrastructureException { + private void useSecureProtocolForGatewayConfigMap(ConfigMap configMap) + throws InfrastructureException { Map servers = - Annotations.newDeserializer(cm.getMetadata().getAnnotations()).servers(); + Annotations.newDeserializer(configMap.getMetadata().getAnnotations()).servers(); if (servers.isEmpty()) { return; } if (servers.size() != 1) { throw new InfrastructureException( - "Expected exactly 1 server in Gateway ConfigMap [" + cm.toString() + "]"); + "Expected exactly 1 server in Gateway configuration ConfigMap '" + + configMap.getMetadata().getName() + + "'. This is a bug, please report."); } - String scKey = servers.keySet().stream().findFirst().get(); - ServerConfigImpl serverConfig = servers.get(scKey); - String protocol = getSecureProtocol(serverConfig.getProtocol()); + Entry serverConfigEntry = servers.entrySet().iterator().next(); + ServerConfigImpl serverConfig = serverConfigEntry.getValue(); - serverConfig.setProtocol(protocol); - cm.getMetadata() + serverConfig.setProtocol(getSecureProtocol(serverConfig.getProtocol())); + configMap + .getMetadata() .getAnnotations() - .putAll(Annotations.newSerializer().server(scKey, serverConfig).annotations()); + .putAll( + Annotations.newSerializer() + .server(serverConfigEntry.getKey(), serverConfig) + .annotations()); } } From 183d58c7c2d0ae87ecf5950dfef2bc8448377446 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 12:40:55 +0200 Subject: [PATCH 32/47] javadocs and minor refactorings Signed-off-by: Michal Vala --- .../provision/GatewayRouterProvisioner.java | 3 +-- .../external/GatewayRouteConfigGenerator.java | 13 ++++++++++--- .../GatewayRouteConfigGeneratorFactory.java | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java index 830da2b2fc6..3d6175f9068 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java @@ -67,8 +67,7 @@ public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity) // We're now creating only 1 gateway route configuration per ConfigMap, so we need to create // generator in each loop iteration. - GatewayRouteConfigGenerator gatewayRouteConfigGenerator = - configGeneratorFactory.create(identity.getInfrastructureNamespace()); + GatewayRouteConfigGenerator gatewayRouteConfigGenerator = configGeneratorFactory.create(); gatewayRouteConfigGenerator.addRouteConfig(configMapEntry.getKey(), gatewayConfigMap); Map gatewayConfiguration = diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java index cfca51f2831..f5bae821c5b 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java @@ -18,18 +18,25 @@ /** * Generates config for external servers that we want to expose in the Gateway. * - * *

Implementation provides configuration for specific Gateway technology (e.g., Traefik). */ public interface GatewayRouteConfigGenerator { /** + * Add prepared {@link ConfigMap},that will hold gateway route configuration, to the generator. So + * it can be generated later with {@link GatewayRouteConfigGenerator#generate(String)}. + * + *

Provided {@link ConfigMap} must be properly labeled and must be annotated with {@link + * org.eclipse.che.api.core.model.workspace.config.ServerConfig} annotations. + * * @param routeConfig config to add + * @throws InfrastructureException when passed ConfigMap is not gateway configuration ConfigMap */ - void addRouteConfig(String name, ConfigMap routeConfig); + void addRouteConfig(String name, ConfigMap routeConfig) throws InfrastructureException; /** * Generates content of configurations for services, defined earlier by added {@link + * GatewayRouteConfigGenerator#addRouteConfig(String, ConfigMap)}. Returned {@code Map} will be used as a value of ConfigMap and injected into Gateway pod. * *

Implementation must ensure that Gateway configured with returned content will route the @@ -45,5 +52,5 @@ public interface GatewayRouteConfigGenerator { * * @return full content of configuration for the services */ - Map generate(String serviceName, String servicePort, String namespace) throws InfrastructureException; + Map generate(String namespace) throws InfrastructureException; } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java index 9a5d6cd6aa0..b68e3863c41 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGeneratorFactory.java @@ -20,7 +20,7 @@ @Singleton public class GatewayRouteConfigGeneratorFactory { - public GatewayRouteConfigGenerator create(String namespace) { + public GatewayRouteConfigGenerator create() { return new TraefikGatewayRouteConfigGenerator(); } } From 8d796ae74fb609c2d83f1868f2736d5d87b1b77c Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 13:10:44 +0200 Subject: [PATCH 33/47] javadocs and minor refactors Signed-off-by: Michal Vala --- .../external/GatewayRouteConfigGenerator.java | 3 +- .../server/external/GatewayServerExposer.java | 36 ++++-- ...leHostExternalServiceExposureStrategy.java | 4 - .../TraefikGatewayRouteConfigGenerator.java | 108 ++++++++++++------ 4 files changed, 101 insertions(+), 50 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java index f5bae821c5b..3c7732eca2b 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java @@ -37,7 +37,8 @@ public interface GatewayRouteConfigGenerator { /** * Generates content of configurations for services, defined earlier by added {@link * GatewayRouteConfigGenerator#addRouteConfig(String, ConfigMap)}. Returned {@code Map} will be used as a value of ConfigMap and injected into Gateway pod. + * String>} must be ready to be used as a {@link ConfigMap}'s data, which is further injected into + * Gateway pod. * *

Implementation must ensure that Gateway configured with returned content will route the * requests on {@code path} into {@code serviceUrl}. Also it must strip {@code path} from request diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java index 2dd6210dbe2..308e177d779 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java @@ -74,13 +74,24 @@ public void expose( for (String esKey : externalServers.keySet()) { final String serverName = KubernetesServerExposer.makeServerNameValidForDns(serverId); final String name = createName(serviceName, serverName); - k8sEnv.getConfigMaps().put(name, - createGatewayRouteConfigmap(name, machineName, serviceName, servicePort, serverName, esKey, - externalServers.get(esKey))); + k8sEnv + .getConfigMaps() + .put( + name, + createGatewayRouteConfigmap( + name, + machineName, + serviceName, + servicePort, + serverName, + esKey, + externalServers.get(esKey))); } } - private ConfigMap createGatewayRouteConfigmap(String name, String machineName, + private ConfigMap createGatewayRouteConfigmap( + String name, + String machineName, String serviceName, ServicePort servicePort, String serverName, @@ -89,7 +100,9 @@ private ConfigMap createGatewayRouteConfigmap(String name, String machineName, final String path = ensureDontEndsWithSlash(strategy.getExternalPath(serviceName, serverName)); serverConfig.getAttributes().put(SERVICE_NAME_ATTRIBUTE, serviceName); - serverConfig.getAttributes().put(SERVICE_PORT_ATTRIBUTE, getTargetPort(servicePort.getTargetPort())); + serverConfig + .getAttributes() + .put(SERVICE_PORT_ATTRIBUTE, getTargetPort(servicePort.getTargetPort())); final Map annotations = Annotations.newSerializer() @@ -98,12 +111,13 @@ private ConfigMap createGatewayRouteConfigmap(String name, String machineName, .annotations(); annotations.put(CREATE_IN_CHE_INSTALLATION_NAMESPACE, TRUE.toString()); - ConfigMapBuilder gatewayConfigMap = new ConfigMapBuilder() - .withNewMetadata() - .withName(name) - .withLabels(GatewayRouterProvisioner.GATEWAY_CONFIGMAP_LABELS) - .withAnnotations(annotations) - .endMetadata(); + ConfigMapBuilder gatewayConfigMap = + new ConfigMapBuilder() + .withNewMetadata() + .withName(name) + .withLabels(GatewayRouterProvisioner.GATEWAY_CONFIGMAP_LABELS) + .withAnnotations(annotations) + .endMetadata(); return gatewayConfigMap.build(); } 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 3888edf07d1..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 @@ -60,8 +60,4 @@ public String getExternalHost(String serviceName, String serverName) { public String getExternalPath(String serviceName, String serverName) { return "/" + serviceName + "/" + serverName; } - - public static String extractServiceNameFromExternalPath(String path) { - return path.substring(1).split("/")[0]; - } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java index ef53eb8f5f0..fd3e342ecbd 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGenerator.java @@ -12,6 +12,9 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; import static com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature.WRITE_DOC_START_MARKER; +import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.SERVICE_NAME_ATTRIBUTE; +import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.SERVICE_PORT_ATTRIBUTE; +import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.GatewayRouterProvisioner.isGatewayConfig; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; @@ -25,42 +28,68 @@ import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; -/** Config generator for Traefik Gateway */ +/** + * Config generator for Traefik Gateway. + * + *

Content of single service configuration looks like this: + * + *

+ * http:
+ *   routers:
+ *     {name}:
+ *       rule: "PathPrefix(`{path}`)"
+ *       service: {name}
+ *       middlewares:
+ *       - "{name}"
+ *       - "{name}_headers"
+ *       priority: 100
+ *   services:
+ *     {name}:
+ *       loadBalancer:
+ *         servers:
+ *         - url: '{serviceUrl}'
+ *   middlewares:
+ *     {name}:
+ *       stripPrefix:
+ *         prefixes:
+ *         - "{GatewayRouteConfig#routePath}"
+ *     {name}_headers:
+ *       customRequestHeaders:
+ *         X-Forwarded-Proto: "{protocol}"
+ * 
+ */ public class TraefikGatewayRouteConfigGenerator implements GatewayRouteConfigGenerator { + private static final String SERVICE_URL_FORMAT = "http://%s.%s.svc.cluster.local:%s"; + private final Map routeConfigs = new HashMap<>(); @Override - public void addRouteConfig(String name, ConfigMap routeConfig) { - this.routeConfigs.put(name, routeConfig); + public void addRouteConfig(String name, ConfigMap routeConfig) throws InfrastructureException { + if (isGatewayConfig(routeConfig)) { + this.routeConfigs.put(name, routeConfig); + } else { + throw new InfrastructureException( + "Not a gateway configuration ConfigMap '" + + routeConfig.getMetadata().getName() + + "'. This is a bug, please report."); + } } /** - *

Content of single service configuration looks like this: + * Generates configuration for all configs added by {@link + * TraefikGatewayRouteConfigGenerator#addRouteConfig(String, ConfigMap)} so far. It does not + * change them, so this method can be used repeatedly. * - *

-   * http:
-   *   routers:
-   *     {name}:
-   *       rule: "PathPrefix(`{GatewayRouteConfig#routePath}`)"
-   *       service: {GatewayRouteConfig#name}
-   *       middlewares:
-   *       - "{GatewayRouteConfig#name}"
-   *       priority: 100
-   *   services:
-   *     {name}:
-   *       loadBalancer:
-   *         servers:
-   *         - url: '{serviceUrl}'
-   *   middlewares:
-   *     {name}:
-   *       stripPrefix:
-   *         prefixes:
-   *         - "{GatewayRouteConfig#routePath}"
-   * 
+ *

Returned {@code Map} has keys created from {@code name} parameter of {@link + * TraefikGatewayRouteConfigGenerator#addRouteConfig(String, ConfigMap)} + '.yml' suffix. Values + * are full configuration for single gateway route. This map is suppose to be directly used as + * {@link ConfigMap}'s data. + * + * @return map with added routes configurations */ @Override - public Map generate(String serviceName, String servicePort, String namespace) throws InfrastructureException { + public Map generate(String namespace) throws InfrastructureException { Map cmData = new HashMap<>(); for (Entry routeConfig : routeConfigs.entrySet()) { Map servers = @@ -70,13 +99,16 @@ public Map generate(String serviceName, String servicePort, Stri throw new InfrastructureException( "Expected exactly 1 server [" + routeConfig.getValue().toString() + "]"); } - ServerConfigImpl server = servers.get(servers.keySet().stream().findFirst().get()); + ServerConfigImpl server = servers.get(servers.keySet().iterator().next()); + String serviceName = server.getAttributes().get(SERVICE_NAME_ATTRIBUTE); + String servicePort = server.getAttributes().get(SERVICE_PORT_ATTRIBUTE); - String traefikRouteConfig = generate( - routeConfig.getKey(), - createServiceUrl(serviceName, servicePort, namespace), - server.getPath(), - server.getProtocol()); + String traefikRouteConfig = + generate( + routeConfig.getKey(), + createServiceUrl(serviceName, servicePort, namespace), + server.getPath(), + server.getProtocol()); cmData.put(routeConfig.getKey() + ".yml", traefikRouteConfig); } return cmData; @@ -88,6 +120,7 @@ public Map generate(String serviceName, String servicePort, Stri * @param name name of the service * @param serviceUrl url of service we want to route to * @param path path to route and strip + * @param protocol protocol of the service to properly set the headers * @return traefik service route config */ private String generate(String name, String serviceUrl, String path, String protocol) @@ -110,6 +143,9 @@ private String generate(String name, String serviceUrl, String path, String prot generator.writeFieldName("middlewares"); generateMiddlewares(generator, name, path, protocol); + generator.writeEndObject(); + generator.writeEndObject(); + generator.flush(); return sw.toString(); @@ -127,6 +163,7 @@ private String generate(String name, String serviceUrl, String path, String prot * service: "{name}" * middlewares: * - "{name}" + * - "{name}_headers * priority: 100 * */ @@ -187,6 +224,10 @@ private void generateServices(YAMLGenerator generator, String name, String servi * stripPrefix: * prefixes: * - "{path}" + * {name}_headers: + * headers: + * customRequestHeaders: + * X-Forwarded-Proto: "{protocol}" * */ private void generateMiddlewares( @@ -218,8 +259,7 @@ private void generateMiddlewares( generator.writeEndObject(); } - String createServiceUrl(String serviceName, String servicePort, String serviceNamespace) { - return String.format( - "http://%s.%s.svc.cluster.local:%s", serviceName, serviceNamespace, servicePort); + private String createServiceUrl(String serviceName, String servicePort, String serviceNamespace) { + return String.format(SERVICE_URL_FORMAT, serviceName, serviceNamespace, servicePort); } } From d5cc15557820c8ba1ce1420bc22cc077c12bb185 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 13:13:36 +0200 Subject: [PATCH 34/47] remove singlehost from openshift for now Signed-off-by: Michal Vala --- .../openshift/OpenShiftInfraModule.java | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java index c78c950b5e4..9c167bf8c48 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java @@ -17,9 +17,6 @@ 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.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; @@ -71,12 +68,9 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.provision.server.ServersConverter; import org.eclipse.che.workspace.infrastructure.kubernetes.server.PreviewUrlExposer; import org.eclipse.che.workspace.infrastructure.kubernetes.server.WorkspaceExposureType; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.DefaultHostExternalServiceExposureStrategy; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServerExposer; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServiceExposureStrategy; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayServerExposer; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.IngressServiceExposureStrategyProvider; -import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.SingleHostExternalServiceExposureStrategy; import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposer; import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactoryProvider; @@ -255,17 +249,7 @@ protected void configure() { KubernetesDevfileBindings.addAllowedEnvironmentTypeUpgradeBindings( binder(), OpenShiftEnvironment.TYPE, KubernetesEnvironment.TYPE); - MapBinder ingressStrategies = - MapBinder.newMapBinder(binder(), String.class, ExternalServiceExposureStrategy.class); - ingressStrategies.addBinding(MULTI_HOST_STRATEGY).to(OpenShiftServerExposureStrategy.class); - ingressStrategies - .addBinding(SINGLE_HOST_STRATEGY) - .to(SingleHostExternalServiceExposureStrategy.class); - ingressStrategies - .addBinding(DEFAULT_HOST_STRATEGY) - .to(DefaultHostExternalServiceExposureStrategy.class); - bind(ExternalServiceExposureStrategy.class) - .toProvider(IngressServiceExposureStrategyProvider.class); + bind(ExternalServiceExposureStrategy.class).to(OpenShiftServerExposureStrategy.class); bind(CookiePathStrategy.class).to(OpenShiftCookiePathStrategy.class); bind(NonTlsDistributedClusterModeNotifier.class); bind(AsyncStorageProvisioner.class); From a82b8830e9ad470cdcf2da71a5608caa029b3797 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 13:18:29 +0200 Subject: [PATCH 35/47] verify that gatewayRouterProvisioner is called Signed-off-by: Michal Vala --- .../kubernetes/KubernetesEnvironmentProvisionerTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesEnvironmentProvisionerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesEnvironmentProvisionerTest.java index cc5430797d5..a5f88b6b082 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesEnvironmentProvisionerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesEnvironmentProvisionerTest.java @@ -132,7 +132,8 @@ public void setUp() { serviceAccountProvisioner, certificateProvisioner, gitConfigProvisioner, - previewUrlExposer); + previewUrlExposer, + gatewayRouterProvisioner); } @Test @@ -158,6 +159,7 @@ public void performsOrderedProvisioning() throws Exception { provisionOrder.verify(serviceAccountProvisioner).provision(eq(k8sEnv), eq(runtimeIdentity)); provisionOrder.verify(certificateProvisioner).provision(eq(k8sEnv), eq(runtimeIdentity)); provisionOrder.verify(gitConfigProvisioner).provision(eq(k8sEnv), eq(runtimeIdentity)); + provisionOrder.verify(gatewayRouterProvisioner).provision(eq(k8sEnv), eq(runtimeIdentity)); provisionOrder.verifyNoMoreInteractions(); } } From 60b626a77cc83c0e684c34a09e4147832189cec1 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 13:32:57 +0200 Subject: [PATCH 36/47] fix test checking proper configmaps are created in che namespace Signed-off-by: Michal Vala --- .../KubernetesInternalRuntimeTest.java | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java index b87c5100cdf..d02b19692c3 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java @@ -24,7 +24,9 @@ import static org.eclipse.che.api.workspace.shared.Constants.DEBUG_WORKSPACE_START; import static org.eclipse.che.api.workspace.shared.Constants.DEBUG_WORKSPACE_START_LOG_LIMIT_BYTES; import static org.eclipse.che.dto.server.DtoFactory.newDto; +import static org.eclipse.che.workspace.infrastructure.kubernetes.Annotations.CREATE_IN_CHE_INSTALLATION_NAMESPACE; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_ORIGINAL_NAME_LABEL; +import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.GatewayRouterProvisioner.GATEWAY_CONFIGMAP_LABELS; import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.MultiHostExternalServiceExposureStrategy.MULTI_HOST_STRATEGY; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; @@ -1131,17 +1133,37 @@ public void testGatewayRouteConfigsAreCreatedAsConfigmapsInCheNamespace() throws InfrastructureException { // given ConfigMap cmRoute1 = - new ConfigMapBuilder().withNewMetadata().withName("route1").endMetadata().build(); + new ConfigMapBuilder() + .withNewMetadata() + .withName("route1") + .withLabels(GATEWAY_CONFIGMAP_LABELS) + .withAnnotations(ImmutableMap.of(CREATE_IN_CHE_INSTALLATION_NAMESPACE, "true")) + .endMetadata() + .build(); ConfigMap cmRoute2 = + new ConfigMapBuilder() + .withNewMetadata() + .withName("route2") + .withLabels(GATEWAY_CONFIGMAP_LABELS) + .withAnnotations(ImmutableMap.of(CREATE_IN_CHE_INSTALLATION_NAMESPACE, "true")) + .endMetadata() + .build(); + ConfigMap cm3 = new ConfigMapBuilder().withNewMetadata().withName("route2").endMetadata().build(); - List configMaps = Arrays.asList(cmRoute1, cmRoute2); + Map configMaps = + ImmutableMap.of("route1", cmRoute1, "route2", cmRoute2, "cm3", cm3); + when(k8sEnv.getConfigMaps()).thenReturn(configMaps); + + List expectedCreatedCheNamespaceConfigmaps = Arrays.asList(cmRoute1, cmRoute2); // when internalRuntime.start(emptyMap()); // then - verify(cheNamespace).createConfigMaps(configMaps, internalRuntime.getContext().getIdentity()); + verify(cheNamespace) + .createConfigMaps( + expectedCreatedCheNamespaceConfigmaps, internalRuntime.getContext().getIdentity()); verify(cheNamespace).cleanUp(WORKSPACE_ID); } From e4db20482bce2f7556b8ab98dec28c48c1f2c1ba Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 14:53:43 +0200 Subject: [PATCH 37/47] CheNamespace checks configmaps for proper annotations + fix and add tests Signed-off-by: Michal Vala --- .../kubernetes/namespace/CheNamespace.java | 18 +++++ .../namespace/CheNamespaceTest.java | 72 ++++++++++++++++++- 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java index 21469d9990f..e22b643d3fa 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java @@ -11,6 +11,8 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace; +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; import static org.eclipse.che.workspace.infrastructure.kubernetes.Annotations.CREATE_IN_CHE_INSTALLATION_NAMESPACE; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_WORKSPACE_ID_LABEL; import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.putLabel; @@ -20,6 +22,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import javax.inject.Inject; import javax.inject.Singleton; import org.eclipse.che.api.core.ServerException; @@ -28,6 +31,7 @@ import org.eclipse.che.api.workspace.server.WorkspaceRuntimes; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.InternalRuntime; +import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; import org.eclipse.che.workspace.infrastructure.kubernetes.CheKubernetesClientFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructureException; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.CheInstallationLocation; @@ -70,6 +74,17 @@ public CheNamespace( private ConfigMap createConfigMap(ConfigMap configMap, RuntimeIdentity identity) throws InfrastructureException { putLabel(configMap, CHE_WORKSPACE_ID_LABEL, identity.getWorkspaceId()); + // check that ConfigMap is properly annotated to be created in Che installation namespace + Map annotations = configMap.getMetadata().getAnnotations(); + if (annotations == null + || !annotations + .getOrDefault(CREATE_IN_CHE_INSTALLATION_NAMESPACE, FALSE.toString()) + .equals(TRUE.toString())) { + throw new InfrastructureException( + String.format( + "ConfigMap '%s' to be created in Che installation namespace is not properly annotated with '%s=true'. This is a bug, please report.", + configMap.getMetadata().getName(), CREATE_IN_CHE_INSTALLATION_NAMESPACE)); + } // remove this annotation, so it's not exposed in actual k8s object configMap.getMetadata().getAnnotations().remove(CREATE_IN_CHE_INSTALLATION_NAMESPACE); return clientFactory.create().configMaps().inNamespace(cheNamespaceName).create(configMap); @@ -82,6 +97,9 @@ private ConfigMap createConfigMap(ConfigMap configMap, RuntimeIdentity identity) *

`workspaceId` from given `identity` must be valid workspace ID, that is in {@link * WorkspaceStatus#STARTING} state. Otherwise, {@link InfrastructureException} is thrown. * + *

all given {@code configMaps} must be annotated with {@link + * Annotations#CREATE_IN_CHE_INSTALLATION_NAMESPACE} set to 'true'. + * * @param configMaps to create * @param identity to validate and label configmaps * @return created {@link ConfigMap}s diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespaceTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespaceTest.java index 0affacc81b5..71ea3f38148 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespaceTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespaceTest.java @@ -11,6 +11,7 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace; +import static org.eclipse.che.workspace.infrastructure.kubernetes.Annotations.CREATE_IN_CHE_INSTALLATION_NAMESPACE; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_WORKSPACE_ID_LABEL; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; @@ -18,6 +19,7 @@ import static org.mockito.Mockito.when; import static org.testng.Assert.*; +import com.google.common.collect.ImmutableMap; import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.ConfigMapList; @@ -28,6 +30,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; @@ -93,9 +96,23 @@ public void testCreateConfigMaps() throws InfrastructureException { // given when(internalRuntime.getOwner()).thenReturn(OWNER_ID); when(internalRuntime.getStatus()).thenReturn(WorkspaceStatus.STARTING); - - ConfigMap cm1 = new ConfigMapBuilder().withNewMetadata().withName("cm1").endMetadata().build(); - ConfigMap cm2 = new ConfigMapBuilder().withNewMetadata().withName("cm2").endMetadata().build(); + Map cheNamespaceAnnotations = + ImmutableMap.of(CREATE_IN_CHE_INSTALLATION_NAMESPACE, "true"); + + ConfigMap cm1 = + new ConfigMapBuilder() + .withNewMetadata() + .withName("cm1") + .withAnnotations(cheNamespaceAnnotations) + .endMetadata() + .build(); + ConfigMap cm2 = + new ConfigMapBuilder() + .withNewMetadata() + .withName("cm2") + .withAnnotations(cheNamespaceAnnotations) + .endMetadata() + .build(); when(clientFactory.create()).thenReturn(kubeClient); when(kubeClient.configMaps()).thenReturn(kubeConfigMaps); @@ -113,6 +130,55 @@ public void testCreateConfigMaps() throws InfrastructureException { cm -> assertEquals(cm.getMetadata().getLabels().get(CHE_WORKSPACE_ID_LABEL), WORKSPACE_ID)); } + @Test(expectedExceptions = InfrastructureException.class) + public void failWhenTryToCreateCmWithoutAnnotation() throws InfrastructureException { + // given + when(internalRuntime.getOwner()).thenReturn(OWNER_ID); + when(internalRuntime.getStatus()).thenReturn(WorkspaceStatus.STARTING); + + ConfigMap cm1 = new ConfigMapBuilder().withNewMetadata().withName("cm1").endMetadata().build(); + + when(clientFactory.create()).thenReturn(kubeClient); + when(kubeClient.configMaps()).thenReturn(kubeConfigMaps); + when(kubeConfigMaps.inNamespace(CHE_NAMESPACE)).thenReturn(kubeConfigMapsInNamespace); + when(kubeConfigMapsInNamespace.create(any(ConfigMap.class))).thenReturn(cm1); + + List configMapsToCreate = Collections.singletonList(cm1); + + // when + cheNamespace.createConfigMaps(configMapsToCreate, identity); + + // then exception + } + + @Test(expectedExceptions = InfrastructureException.class) + public void failWhenTryToCreateCmWithWronglySetAnnotation() throws InfrastructureException { + // given + when(internalRuntime.getOwner()).thenReturn(OWNER_ID); + when(internalRuntime.getStatus()).thenReturn(WorkspaceStatus.STARTING); + + ConfigMap cm1 = + new ConfigMapBuilder() + .withNewMetadata() + .withName("cm1") + .withAnnotations( + Collections.singletonMap(CREATE_IN_CHE_INSTALLATION_NAMESPACE, "blabol")) + .endMetadata() + .build(); + + when(clientFactory.create()).thenReturn(kubeClient); + when(kubeClient.configMaps()).thenReturn(kubeConfigMaps); + when(kubeConfigMaps.inNamespace(CHE_NAMESPACE)).thenReturn(kubeConfigMapsInNamespace); + when(kubeConfigMapsInNamespace.create(any(ConfigMap.class))).thenReturn(cm1); + + List configMapsToCreate = Collections.singletonList(cm1); + + // when + cheNamespace.createConfigMaps(configMapsToCreate, identity); + + // then exception + } + @Test(expectedExceptions = InfrastructureException.class) public void testCreateConfigmapFailsWhenNoWorkspaceIdFoundInRuntimes() throws InfrastructureException, ServerException { From 49375aea83458299cd3586e893ea0703b4f3583e Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 15:35:00 +0200 Subject: [PATCH 38/47] test GatewayRouterProvisioner Signed-off-by: Michal Vala --- .../provision/GatewayRouterProvisioner.java | 2 +- .../GatewayRouterProvisionerTest.java | 175 +++++++++++++++++- 2 files changed, 166 insertions(+), 11 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java index 3d6175f9068..0b3438a6f3f 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java @@ -50,7 +50,7 @@ public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity) new Annotations.Deserializer(gatewayConfigMap.getMetadata().getAnnotations()).servers(); if (servers.size() != 1) { throw new InfrastructureException( - "Expected only 1 server in gateway config ConfigMap's '" + "Expected exactly 1 server in gateway config ConfigMap's '" + gatewayConfigMap.getMetadata().getName() + "' annotations. This is a bug, please report."); } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisionerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisionerTest.java index d5f6e919b30..e4e305561d1 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisionerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisionerTest.java @@ -1,34 +1,189 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; +import static java.util.Collections.emptyMap; +import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.SERVICE_NAME_ATTRIBUTE; +import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.SERVICE_PORT_ATTRIBUTE; import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.GatewayRouterProvisioner.GATEWAY_CONFIGMAP_LABELS; -import static org.testng.Assert.*; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; import com.google.common.collect.ImmutableMap; import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import java.util.Collections; import java.util.Map; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +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.server.external.GatewayRouteConfigGenerator; +import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.GatewayRouteConfigGeneratorFactory; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; +import org.testng.annotations.Listeners; import org.testng.annotations.Test; +@Listeners(MockitoTestNGListener.class) public class GatewayRouterProvisionerTest { + + private final String NAMESPACE = "nejmspejs"; + + @Mock private GatewayRouteConfigGeneratorFactory configGeneratorFactory; + @Mock private GatewayRouteConfigGenerator gatewayRouteConfigGenerator; + @Mock private KubernetesEnvironment env; + @Mock private RuntimeIdentity identity; + + private GatewayRouterProvisioner gatewayRouterProvisioner; + private final ServerConfigImpl serverConfigWithoutAttributes = + new ServerConfigImpl("1234", "http", "/hello/there", emptyMap()); + private final ServerConfigImpl serverConfig = + new ServerConfigImpl( + "1234", + "http", + "/hello/there", + ImmutableMap.of(SERVICE_NAME_ATTRIBUTE, "serviceName", SERVICE_PORT_ATTRIBUTE, "1111")); + + @BeforeMethod + public void setUp() { + lenient().when(configGeneratorFactory.create()).thenReturn(gatewayRouteConfigGenerator); + lenient().when(identity.getInfrastructureNamespace()).thenReturn(NAMESPACE); + + gatewayRouterProvisioner = new GatewayRouterProvisioner(configGeneratorFactory); + } + + @Test(expectedExceptions = InfrastructureException.class) + public void testFailWhenNoServersInConfigmapAnnotations() throws InfrastructureException { + // given + ConfigMap gatewayRouteConfigMap = + new ConfigMapBuilder() + .withNewMetadata() + .withName("route") + .withLabels(GATEWAY_CONFIGMAP_LABELS) + .endMetadata() + .build(); + when(env.getConfigMaps()).thenReturn(Collections.singletonMap("route", gatewayRouteConfigMap)); + + // when + gatewayRouterProvisioner.provision(env, identity); + + // then exception + } + + @Test(expectedExceptions = InfrastructureException.class) + public void testFailWhenMoreThanOneServerInConfigmapAnnotations() throws InfrastructureException { + // given + Map annotationsWith2Servers = + new Annotations.Serializer() + .server("s1", serverConfigWithoutAttributes) + .server("s2", serverConfigWithoutAttributes) + .annotations(); + + ConfigMap gatewayRouteConfigMap = + new ConfigMapBuilder() + .withNewMetadata() + .withName("route") + .withLabels(GATEWAY_CONFIGMAP_LABELS) + .withAnnotations(annotationsWith2Servers) + .endMetadata() + .build(); + when(env.getConfigMaps()).thenReturn(Collections.singletonMap("route", gatewayRouteConfigMap)); + + // when + gatewayRouterProvisioner.provision(env, identity); + + // then exception + } + + @Test(expectedExceptions = InfrastructureException.class) + public void testFailWhenServerHasNotAllNeededAttributes() throws InfrastructureException { + // given + Map annotationsWith2Servers = + new Annotations.Serializer().server("s1", serverConfigWithoutAttributes).annotations(); + + ConfigMap gatewayRouteConfigMap = + new ConfigMapBuilder() + .withNewMetadata() + .withName("route") + .withLabels(GATEWAY_CONFIGMAP_LABELS) + .withAnnotations(annotationsWith2Servers) + .endMetadata() + .build(); + when(env.getConfigMaps()).thenReturn(Collections.singletonMap("route", gatewayRouteConfigMap)); + + // when + gatewayRouterProvisioner.provision(env, identity); + + // then exception + } + + @Test + public void testProvision() throws InfrastructureException { + // given + Map annotationsWith2Servers = + new Annotations.Serializer().server("s1", serverConfig).annotations(); + + ConfigMap gatewayRouteConfigMap = + new ConfigMapBuilder() + .withNewMetadata() + .withName("route") + .withLabels(GATEWAY_CONFIGMAP_LABELS) + .withAnnotations(annotationsWith2Servers) + .endMetadata() + .build(); + when(env.getConfigMaps()).thenReturn(Collections.singletonMap("route", gatewayRouteConfigMap)); + Map expectedData = + Collections.singletonMap("data.yml", "this is for sure generated configuration"); + when(gatewayRouteConfigGenerator.generate(NAMESPACE)).thenReturn(expectedData); + + // when + gatewayRouterProvisioner.provision(env, identity); + + // then + verify(configGeneratorFactory).create(); + verify(gatewayRouteConfigGenerator).addRouteConfig("route", gatewayRouteConfigMap); + verify(gatewayRouteConfigGenerator).generate(NAMESPACE); + + Map serverConfigsAfterProvisioning = + new Annotations.Deserializer(gatewayRouteConfigMap.getMetadata().getAnnotations()) + .servers(); + assertEquals(serverConfigsAfterProvisioning.size(), 1); + ServerConfigImpl server = + serverConfigsAfterProvisioning.get( + serverConfigsAfterProvisioning.keySet().iterator().next()); + + // verify that provisioner removes the internal attributes + assertFalse(server.getAttributes().containsKey(SERVICE_NAME_ATTRIBUTE)); + assertFalse(server.getAttributes().containsKey(SERVICE_PORT_ATTRIBUTE)); + + // verify that provisioner included the data info configmap + Map actualData = gatewayRouteConfigMap.getData(); + assertEquals(actualData, expectedData); + } + @Test(dataProvider = "isGatewayConfigData") public void testIsGatewayConfig(Map labels, boolean isGatewayConfigExpected) { - ConfigMap cm = new ConfigMapBuilder().withNewMetadata().withLabels(labels).endMetadata().build(); + ConfigMap cm = + new ConfigMapBuilder().withNewMetadata().withLabels(labels).endMetadata().build(); assertEquals(GatewayRouterProvisioner.isGatewayConfig(cm), isGatewayConfigExpected); } @DataProvider public Object[][] isGatewayConfigData() { return new Object[][] { - {GATEWAY_CONFIGMAP_LABELS, true}, - {ImmutableMap.builder().putAll(GATEWAY_CONFIGMAP_LABELS).put("other", "value").build(), true}, - {Collections.emptyMap(), false}, - {ImmutableMap.of("one", "two"), false}, - {ImmutableMap.of(), false}, - {ImmutableMap.of("app", "yes", "role", "no"), false}, - {ImmutableMap.of("app", GATEWAY_CONFIGMAP_LABELS.get("app"), "role", "no"), false}, - {ImmutableMap.of("app", "no", "role", GATEWAY_CONFIGMAP_LABELS.get("role")), false}, + {GATEWAY_CONFIGMAP_LABELS, true}, + {ImmutableMap.builder().putAll(GATEWAY_CONFIGMAP_LABELS).put("other", "value").build(), true}, + {emptyMap(), false}, + {ImmutableMap.of("one", "two"), false}, + {ImmutableMap.of(), false}, + {ImmutableMap.of("app", "yes", "role", "no"), false}, + {ImmutableMap.of("app", GATEWAY_CONFIGMAP_LABELS.get("app"), "role", "no"), false}, + {ImmutableMap.of("app", "no", "role", GATEWAY_CONFIGMAP_LABELS.get("role")), false}, }; } } From 69a03fb7530f8ce9e8c686763b0ee9ffaa56a2e7 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 15:42:30 +0200 Subject: [PATCH 39/47] test GatewayTlcProvisioner Signed-off-by: Michal Vala --- .../provision/GatewayTlsProvisionerTest.java | 168 +++++++++++------- 1 file changed, 100 insertions(+), 68 deletions(-) diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisionerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisionerTest.java index 68a18d04a6a..302301ebb70 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisionerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayTlsProvisionerTest.java @@ -11,77 +11,109 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; +import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.GatewayRouterProvisioner.GATEWAY_CONFIGMAP_LABELS; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import java.util.HashMap; +import java.util.Map; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +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.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; +import org.testng.annotations.Test; @Listeners(MockitoTestNGListener.class) public class GatewayTlsProvisionerTest { -// -// public static final String WORKSPACE_ID = "workspace123"; -// @Mock private KubernetesEnvironment k8sEnv; -// @Mock private RuntimeIdentity runtimeIdentity; -// -// private final ServerConfigImpl httpServer = -// new ServerConfigImpl("8080/tpc", "http", "/api", emptyMap()); -// private final ServerConfigImpl wsServer = -// new ServerConfigImpl("8080/tpc", "ws", "/ws", emptyMap()); -// private final Map annotations = -// singletonMap("annotation-key", "annotation-value"); -// private final String machine = "machine"; -// -// @Test(dataProvider = "tlsProvisionData") -// public void provisionTlsForGatewayRouteConfig( -// ServerConfigImpl server, boolean tlsEnabled, String expectedProtocol) throws Exception { -// // given -// Map composedAnnotations = new HashMap<>(annotations); -// composedAnnotations.putAll( -// Annotations.newSerializer().server("server", server).machineName(machine).annotations()); -// new GatewayRouteConfig("gate1", "svc1", "1234", "/hello", "http", composedAnnotations); -// GatewayTlsProvisioner gatewayTlsProvisioner = -// new GatewayTlsProvisioner<>(tlsEnabled); -// -// when(k8sEnv.getGatewayRouteConfigs()).thenReturn(singletonList(routeConfig)); -// -// // when -// gatewayTlsProvisioner.provision(k8sEnv, runtimeIdentity); -// -// // then -// Map servers = -// Annotations.newDeserializer(routeConfig.getAnnotations()).servers(); -// assertEquals(servers.get("server").getProtocol(), expectedProtocol); -// } -// -// @DataProvider -// public Object[][] tlsProvisionData() { -// return new Object[][] { -// {httpServer, true, "https"}, -// {httpServer, false, "http"}, -// {wsServer, true, "wss"}, -// {wsServer, false, "ws"}, -// }; -// } -// -// @Test(expectedExceptions = InfrastructureException.class) -// public void throwExceptionWhenMultipleServersInGatewayRouteConfigAnnotations() -// throws InfrastructureException { -// // given -// Map composedAnnotations = new HashMap<>(annotations); -// composedAnnotations.putAll( -// Annotations.newSerializer() -// .server("server1", httpServer) -// .server("server2", wsServer) -// .machineName(machine) -// .annotations()); -// GatewayRouteConfig routeConfig = -// new GatewayRouteConfig("gate1", "svc1", "1234", "/hello", "http", composedAnnotations); -// -// when(k8sEnv.getGatewayRouteConfigs()).thenReturn(singletonList(routeConfig)); -// GatewayTlsProvisioner gatewayTlsProvisioner = -// new GatewayTlsProvisioner<>(true); -// -// // when -// gatewayTlsProvisioner.provision(k8sEnv, runtimeIdentity); -// -// // then exception -// } + + public static final String WORKSPACE_ID = "workspace123"; + @Mock private KubernetesEnvironment k8sEnv; + @Mock private RuntimeIdentity runtimeIdentity; + + private final ServerConfigImpl httpServer = + new ServerConfigImpl("8080/tpc", "http", "/api", emptyMap()); + private final ServerConfigImpl wsServer = + new ServerConfigImpl("8080/tpc", "ws", "/ws", emptyMap()); + private final Map annotations = + singletonMap("annotation-key", "annotation-value"); + private final String machine = "machine"; + + @Test(dataProvider = "tlsProvisionData") + public void provisionTlsForGatewayRouteConfigmaps( + ServerConfigImpl server, boolean tlsEnabled, String expectedProtocol) throws Exception { + // given + Map composedAnnotations = new HashMap<>(annotations); + composedAnnotations.putAll( + Annotations.newSerializer().server("server", server).machineName(machine).annotations()); + ConfigMap routeConfigMap = + new ConfigMapBuilder() + .withNewMetadata() + .withName("route") + .withLabels(GATEWAY_CONFIGMAP_LABELS) + .withAnnotations(composedAnnotations) + .endMetadata() + .build(); + + GatewayTlsProvisioner gatewayTlsProvisioner = + new GatewayTlsProvisioner<>(tlsEnabled); + + when(k8sEnv.getConfigMaps()).thenReturn(singletonMap("route", routeConfigMap)); + + // when + gatewayTlsProvisioner.provision(k8sEnv, runtimeIdentity); + + // then + Map servers = + Annotations.newDeserializer(routeConfigMap.getMetadata().getAnnotations()).servers(); + assertEquals(servers.get("server").getProtocol(), expectedProtocol); + } + + @DataProvider + public Object[][] tlsProvisionData() { + return new Object[][] { + {httpServer, true, "https"}, + {httpServer, false, "http"}, + {wsServer, true, "wss"}, + {wsServer, false, "ws"}, + }; + } + + @Test(expectedExceptions = InfrastructureException.class) + public void throwExceptionWhenMultipleServersInGatewayRouteConfigAnnotations() + throws InfrastructureException { + // given + Map composedAnnotations = new HashMap<>(annotations); + composedAnnotations.putAll( + Annotations.newSerializer() + .server("server1", httpServer) + .server("server2", wsServer) + .machineName(machine) + .annotations()); + ConfigMap routeConfigMap = + new ConfigMapBuilder() + .withNewMetadata() + .withName("route") + .withLabels(GATEWAY_CONFIGMAP_LABELS) + .withAnnotations(composedAnnotations) + .endMetadata() + .build(); + + when(k8sEnv.getConfigMaps()).thenReturn(singletonMap("route", routeConfigMap)); + GatewayTlsProvisioner gatewayTlsProvisioner = + new GatewayTlsProvisioner<>(true); + + // when + gatewayTlsProvisioner.provision(k8sEnv, runtimeIdentity); + + // then exception + } } From 28c8fbe4a2be7f3d515b124ef23044c90d2dc299 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 15:52:16 +0200 Subject: [PATCH 40/47] test GatewayServerExposer Signed-off-by: Michal Vala --- .../external/GatewayServerExposerTest.java | 59 +++++++++++-------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java index c6bd93c8b72..8b8f2139fde 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java @@ -11,12 +11,18 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; +import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.GatewayRouterProvisioner.GATEWAY_CONFIGMAP_LABELS; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.IntOrString; import io.fabric8.kubernetes.api.model.ServicePort; import java.util.Collections; 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.environment.KubernetesEnvironment; import org.testng.annotations.Test; @@ -38,34 +44,37 @@ public class GatewayServerExposerTest { @Test public void testExposeServiceWithGatewayConfigmap() { + // given KubernetesEnvironment k8sEnv = KubernetesEnvironment.builder().build(); + + // when serverExposer.expose(k8sEnv, machineName, serviceName, serverId, servicePort, servers); -// List configMaps = k8sEnv.getGatewayRouteConfigs(); - // TODO: assert created route configs + // then + Map configMaps = k8sEnv.getConfigMaps(); + assertTrue(configMaps.containsKey(serviceName + "-" + serverId)); + ConfigMap serverConfigMap = configMaps.get("service-server"); + + // data should be empty at this point + assertTrue(serverConfigMap.getData() == null || serverConfigMap.getData().isEmpty()); + + assertEquals(serverConfigMap.getMetadata().getLabels(), GATEWAY_CONFIGMAP_LABELS); + + Map annotations = serverConfigMap.getMetadata().getAnnotations(); + Annotations.Deserializer deserializer = Annotations.newDeserializer(annotations); + assertEquals(deserializer.machineName(), machineName); + + Map exposedServers = deserializer.servers(); + assertTrue(exposedServers.containsKey("serverOne")); - // assertTrue(configMaps.containsKey(serviceName + "-" + serverId)); - // - // ConfigMap serverConfigMap = configMaps.get("service-server"); - // - // Map serverConfigMapData = serverConfigMap.getData(); - // assertTrue(serverConfigMapData.containsKey("hello")); - // assertEquals( - // serverConfigMapData.get("hello"), - // "service-server#http://service.che.svc.cluster.local:1234#/service/server/"); - // assertEquals(serverConfigMap.getMetadata().getLabels(), GATEWAY_CONFIGMAP_LABELS); - // - // Map annotations = serverConfigMap.getMetadata().getAnnotations(); - // Annotations.Deserializer deserializer = Annotations.newDeserializer(annotations); - // assertEquals(deserializer.machineName(), machineName); - // - // Map exposedServers = deserializer.servers(); - // assertTrue(exposedServers.containsKey("serverOne")); - // - // ServerConfig s1 = exposedServers.get("serverOne"); - // assertEquals(s1.getAttributes(), s1attrs); - // assertEquals(s1.getPort(), "1111"); - // assertEquals(s1.getProtocol(), "ws"); - // assertEquals(s1.getPath(), "/service/server/"); + ServerConfig s1 = exposedServers.get("serverOne"); + assertEquals( + s1.getAttributes().get(s1attrs.keySet().iterator().next()), + s1attrs.values().iterator().next()); + assertEquals(s1.getAttributes().get(ServerConfigImpl.SERVICE_NAME_ATTRIBUTE), "service"); + assertEquals(s1.getAttributes().get(ServerConfigImpl.SERVICE_PORT_ATTRIBUTE), "1234"); + assertEquals(s1.getPort(), "1111"); + assertEquals(s1.getProtocol(), "ws"); + assertEquals(s1.getPath(), "/service/server"); } } From fe3a96c0d6fa9fef5e23a60d87754eeae0c346bb Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 16:14:16 +0200 Subject: [PATCH 41/47] test Traefik config generator Signed-off-by: Michal Vala --- ...raefikGatewayRouteConfigGeneratorTest.java | 185 ++++++++++++------ 1 file changed, 129 insertions(+), 56 deletions(-) diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java index f0378b7a5d1..7158a10ff1e 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/TraefikGatewayRouteConfigGeneratorTest.java @@ -11,66 +11,139 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.server.external; +import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.SERVICE_NAME_ATTRIBUTE; +import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.SERVICE_PORT_ATTRIBUTE; +import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.GatewayRouterProvisioner.GATEWAY_CONFIGMAP_LABELS; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; +import com.google.common.collect.ImmutableMap; +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import java.util.Map; +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.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + public class TraefikGatewayRouteConfigGeneratorTest { - private final GatewayRouteConfigGenerator gatewayConfigGenerator = - new TraefikGatewayRouteConfigGenerator(); + private GatewayRouteConfigGenerator gatewayConfigGenerator; + + @BeforeMethod + public void setUp() { + gatewayConfigGenerator = new TraefikGatewayRouteConfigGenerator(); + } + + @Test + public void testGenerateGatewayConfig() throws InfrastructureException { + String expectedConfig = + "http:\n" + + " routers:\n" + + " external-server-1:\n" + + " rule: \"PathPrefix(`/blabol-cesta`)\"\n" + + " service: \"external-server-1\"\n" + + " middlewares:\n" + + " - \"external-server-1\"\n" + + " - \"external-server-1_headers\"\n" + + " priority: 100\n" + + " services:\n" + + " external-server-1:\n" + + " loadBalancer:\n" + + " servers:\n" + + " - url: \"http://service-url.che-namespace.svc.cluster.local:1234\"\n" + + " middlewares:\n" + + " external-server-1:\n" + + " stripPrefix:\n" + + " prefixes:\n" + + " - \"/blabol-cesta\"\n" + + " external-server-1_headers:\n" + + " headers:\n" + + " customRequestHeaders:\n" + + " X-Forwarded-Proto: \"https\""; + + ServerConfigImpl serverConfig = + new ServerConfigImpl( + "123", + "https", + "/blabol-cesta", + ImmutableMap.of(SERVICE_NAME_ATTRIBUTE, "service-url", SERVICE_PORT_ATTRIBUTE, "1234")); + Map annotations = + new Annotations.Serializer().server("s1", serverConfig).annotations(); + ConfigMap routeConfig = + new ConfigMapBuilder() + .withNewMetadata() + .withName("route") + .withLabels(GATEWAY_CONFIGMAP_LABELS) + .withAnnotations(annotations) + .endMetadata() + .build(); + + gatewayConfigGenerator.addRouteConfig("external-server-1", routeConfig); + Map generatedConfig = gatewayConfigGenerator.generate("che-namespace"); + + assertTrue(generatedConfig.containsKey("external-server-1.yml")); + assertEquals(generatedConfig.get("external-server-1.yml"), expectedConfig); + } + + @Test + public void testMultipleRouteConfigsAreGeneratedAsMultipleMapEntries() + throws InfrastructureException { + ServerConfigImpl serverConfig = + new ServerConfigImpl( + "123", + "https", + "/blabol-cesta", + ImmutableMap.of(SERVICE_NAME_ATTRIBUTE, "service-url", SERVICE_PORT_ATTRIBUTE, "1234")); + Map annotations = + new Annotations.Serializer().server("s1", serverConfig).annotations(); + ConfigMap routeConfig = + new ConfigMapBuilder() + .withNewMetadata() + .withName("route") + .withLabels(GATEWAY_CONFIGMAP_LABELS) + .withAnnotations(annotations) + .endMetadata() + .build(); + gatewayConfigGenerator.addRouteConfig("c1", routeConfig); + gatewayConfigGenerator.addRouteConfig("c2", routeConfig); + Map generatedConfig = gatewayConfigGenerator.generate("che-namespace"); + + assertTrue(generatedConfig.containsKey("c1.yml")); + assertTrue(generatedConfig.containsKey("c2.yml")); + } + + @Test(expectedExceptions = InfrastructureException.class) + public void failWhenMultipleServersInConfigmapAnnotations() throws InfrastructureException { + ServerConfigImpl serverConfig = + new ServerConfigImpl( + "123", + "https", + "/blabol-cesta", + ImmutableMap.of(SERVICE_NAME_ATTRIBUTE, "service-url", SERVICE_PORT_ATTRIBUTE, "1234")); + Map annotations = + new Annotations.Serializer() + .server("s1", serverConfig) + .server("s2", serverConfig) + .annotations(); + ConfigMap routeConfig = + new ConfigMapBuilder() + .withNewMetadata() + .withName("route") + .withLabels(GATEWAY_CONFIGMAP_LABELS) + .withAnnotations(annotations) + .endMetadata() + .build(); + gatewayConfigGenerator.addRouteConfig("c1", routeConfig); + + gatewayConfigGenerator.generate("che-namespace"); + } -// @Test -// public void testGenerateGatewayConfig() throws InfrastructureException { -// String expectedConfig = -// "http:\n" -// + " routers:\n" -// + " external-server-1:\n" -// + " rule: \"PathPrefix(`/blabol-cesta`)\"\n" -// + " service: \"external-server-1\"\n" -// + " middlewares:\n" -// + " - \"external-server-1\"\n" -// + " - \"external-server-1_headers\"\n" -// + " priority: 100\n" -// + " services:\n" -// + " external-server-1:\n" -// + " loadBalancer:\n" -// + " servers:\n" -// + " - url: \"http://service-url.che-namespace.svc.cluster.local:1234\"\n" -// + " middlewares:\n" -// + " external-server-1:\n" -// + " stripPrefix:\n" -// + " prefixes:\n" -// + " - \"/blabol-cesta\"\n" -// + " external-server-1_headers:\n" -// + " headers:\n" -// + " customRequestHeaders:\n" -// + " X-Forwarded-Proto: \"http\""; -// -// GatewayRouteConfig routeConfig = -// new GatewayRouteConfig( -// "external-server-1", -// "service-url", -// "1234", -// "/blabol-cesta", -// "http", -// Collections.emptyMap()); -// gatewayConfigGenerator.addRouteConfig(routeConfig); -// Map generatedConfig = gatewayConfigGenerator.generate("che-namespace"); -// -// assertTrue(generatedConfig.containsKey("external-server-1.yml")); -// assertEquals(generatedConfig.get("external-server-1.yml"), expectedConfig); -// } -// -// @Test -// public void testMultipleRouteConfigsAreGeneratedAsMultipleMapEntries() -// throws InfrastructureException { -// GatewayRouteConfig c1 = new GatewayRouteConfig("c1", "", "", "", "", Collections.emptyMap()); -// GatewayRouteConfig c2 = new GatewayRouteConfig("c2", "", "", "", "", Collections.emptyMap()); -// gatewayConfigGenerator.addRouteConfig(c1); -// gatewayConfigGenerator.addRouteConfig(c2); -// Map generatedConfig = gatewayConfigGenerator.generate("che-namespace"); -// -// assertTrue(generatedConfig.containsKey("c1.yml")); -// assertTrue(generatedConfig.containsKey("c2.yml")); -// } + @Test(expectedExceptions = InfrastructureException.class) + public void failWhenAddConfigmapWithoutLabels() throws InfrastructureException { + ConfigMap routeConfig = + new ConfigMapBuilder().withNewMetadata().withName("route").endMetadata().build(); + gatewayConfigGenerator.addRouteConfig("c1", routeConfig); + } } From ee77b6b7a95ce6b8b35646bffdca0f321ffd3df9 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 16:15:17 +0200 Subject: [PATCH 42/47] revert unnecessary change Signed-off-by: Michal Vala --- .../openshift/multiuser/oauth/IdentityProviderConfigFactory.java | 1 - 1 file changed, 1 deletion(-) diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/multiuser/oauth/IdentityProviderConfigFactory.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/multiuser/oauth/IdentityProviderConfigFactory.java index 83f4e057ba8..2d741e44186 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/multiuser/oauth/IdentityProviderConfigFactory.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/multiuser/oauth/IdentityProviderConfigFactory.java @@ -118,7 +118,6 @@ public boolean isPersonalized() { * Builds the OpenShift {@link Config} object based on a default {@link Config} object and an * optional workspace Id. */ - @Override public Config buildConfig(Config defaultConfig, @Nullable String workspaceId) throws InfrastructureException { Subject subject = EnvironmentContext.getCurrent().getSubject(); From 83e4774a5d563b136b3a702daf41b874039f8201 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 16:56:13 +0200 Subject: [PATCH 43/47] license headers Signed-off-by: Michal Vala --- .../provision/GatewayRouterProvisioner.java | 11 +++++++++++ .../provision/GatewayRouterProvisionerTest.java | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java index 0b3438a6f3f..e3c6b2fea0e 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisioner.java @@ -1,3 +1,14 @@ +/* + * 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.provision; import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.SERVICE_NAME_ATTRIBUTE; diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisionerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisionerTest.java index e4e305561d1..c2200b0641c 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisionerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/GatewayRouterProvisionerTest.java @@ -1,3 +1,14 @@ +/* + * 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.provision; import static java.util.Collections.emptyMap; From c77a4ee031f29d93f19408372f8c4230f18b7b6a Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 17:09:12 +0200 Subject: [PATCH 44/47] fix NPE when checking object to create in che installation namespace Signed-off-by: Michal Vala --- .../kubernetes/KubernetesInternalRuntime.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java index 8d2403002c0..db31f46e9f4 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java @@ -25,6 +25,7 @@ import com.google.inject.assistedinject.Assisted; import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.Container; +import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodTemplateSpec; @@ -704,8 +705,7 @@ protected List createConfigMaps(KubernetesEnvironment env, RuntimeIde List cheNamespaceConfigMaps = new ArrayList<>(); for (ConfigMap configMap : env.getConfigMaps().values()) { - Map annotations = configMap.getMetadata().getAnnotations(); - if (shouldCreateInCheNamespace(annotations)) { + if (shouldCreateInCheNamespace(configMap)) { // we collect the che namespace configmaps into separate list cheNamespaceConfigMaps.add(configMap); } else { @@ -724,11 +724,15 @@ protected List createConfigMaps(KubernetesEnvironment env, RuntimeIde * Annotations#CREATE_IN_CHE_INSTALLATION_NAMESPACE} annotation set exactly to `true`. In all * other cases we create the object in Workspace's namespace. * - * @param annotations object's annotations + * @param k8sObject object to check * @return `true` if {@link Annotations#CREATE_IN_CHE_INSTALLATION_NAMESPACE} is set to `true`. * False otherwise. */ - private boolean shouldCreateInCheNamespace(Map annotations) { + private boolean shouldCreateInCheNamespace(HasMetadata k8sObject) { + if (k8sObject.getMetadata() == null) { + return false; + } + Map annotations = k8sObject.getMetadata().getAnnotations(); if (annotations == null || annotations.isEmpty()) { return false; } From 8f1c14ed60b5308ab4747726d4a35af7fb732099 Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Thu, 20 Aug 2020 17:38:12 +0200 Subject: [PATCH 45/47] javadocs Signed-off-by: Michal Vala --- .../kubernetes/server/external/GatewayRouteConfigGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java index 3c7732eca2b..5576cd7eafe 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayRouteConfigGenerator.java @@ -44,7 +44,7 @@ public interface GatewayRouteConfigGenerator { * requests on {@code path} into {@code serviceUrl}. Also it must strip {@code path} from request * url. * - *

Keys and Values of returned {@link Map} depends on gateway technology. e.g.: + *

Returned Map's Keys will be used as file names, Values as their content. e.g.: * *

    *   service1.yml: {config-content-for-service-1}

From 4d6337c137116c0cf5e591e8a29a2c2029c8b517 Mon Sep 17 00:00:00 2001
From: Michal Vala 
Date: Fri, 21 Aug 2020 14:49:15 +0200
Subject: [PATCH 46/47] rename CheKubernetesClientFactory ->
 CheServerKubernetesClientFactory and move method to check che namespace
 annotation into util class

Signed-off-by: Michal Vala 
---
 ... => CheServerKubernetesClientFactory.java} |  4 +--
 .../kubernetes/KubernetesInternalRuntime.java | 28 +-----------------
 .../kubernetes/namespace/CheNamespace.java    | 16 ++++------
 .../namespace/KubernetesObjectUtil.java       | 29 +++++++++++++++++++
 .../namespace/CheNamespaceTest.java           |  4 +--
 5 files changed, 39 insertions(+), 42 deletions(-)
 rename infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/{CheKubernetesClientFactory.java => CheServerKubernetesClientFactory.java} (94%)

diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheKubernetesClientFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheServerKubernetesClientFactory.java
similarity index 94%
rename from infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheKubernetesClientFactory.java
rename to infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheServerKubernetesClientFactory.java
index 260966f52d3..87171d29424 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheKubernetesClientFactory.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/CheServerKubernetesClientFactory.java
@@ -25,10 +25,10 @@
  * provides client with default {@link Config}.
  */
 @Singleton
-public class CheKubernetesClientFactory extends KubernetesClientFactory {
+public class CheServerKubernetesClientFactory extends KubernetesClientFactory {
 
   @Inject
-  public CheKubernetesClientFactory(
+  public CheServerKubernetesClientFactory(
       @Nullable @Named("che.infra.kubernetes.master_url") String masterUrl,
       @Nullable @Named("che.infra.kubernetes.trust_certs") Boolean doTrustCerts,
       @Named("che.infra.kubernetes.client.http.async_requests.max") int maxConcurrentRequests,
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java
index db31f46e9f4..87900aa5069 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java
@@ -11,12 +11,10 @@
  */
 package org.eclipse.che.workspace.infrastructure.kubernetes;
 
-import static java.lang.Boolean.FALSE;
-import static java.lang.Boolean.TRUE;
 import static java.lang.String.format;
 import static java.util.Collections.emptyMap;
 import static java.util.stream.Collectors.toMap;
-import static org.eclipse.che.workspace.infrastructure.kubernetes.Annotations.CREATE_IN_CHE_INSTALLATION_NAMESPACE;
+import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.shouldCreateInCheNamespace;
 import static org.eclipse.che.workspace.infrastructure.kubernetes.util.TracingSpanConstants.CHECK_SERVERS;
 import static org.eclipse.che.workspace.infrastructure.kubernetes.util.TracingSpanConstants.WAIT_MACHINES_START;
 import static org.eclipse.che.workspace.infrastructure.kubernetes.util.TracingSpanConstants.WAIT_RUNNING_ASYNC;
@@ -25,7 +23,6 @@
 import com.google.inject.assistedinject.Assisted;
 import io.fabric8.kubernetes.api.model.ConfigMap;
 import io.fabric8.kubernetes.api.model.Container;
-import io.fabric8.kubernetes.api.model.HasMetadata;
 import io.fabric8.kubernetes.api.model.ObjectMeta;
 import io.fabric8.kubernetes.api.model.Pod;
 import io.fabric8.kubernetes.api.model.PodTemplateSpec;
@@ -719,29 +716,6 @@ protected List createConfigMaps(KubernetesEnvironment env, RuntimeIde
     return createdConfigMaps;
   }
 
-  /**
-   * Create in Che installation namespace only if there is {@link
-   * Annotations#CREATE_IN_CHE_INSTALLATION_NAMESPACE} annotation set exactly to `true`. In all
-   * other cases we create the object in Workspace's namespace.
-   *
-   * @param k8sObject object to check
-   * @return `true` if {@link Annotations#CREATE_IN_CHE_INSTALLATION_NAMESPACE} is set to `true`.
-   *     False otherwise.
-   */
-  private boolean shouldCreateInCheNamespace(HasMetadata k8sObject) {
-    if (k8sObject.getMetadata() == null) {
-      return false;
-    }
-    Map annotations = k8sObject.getMetadata().getAnnotations();
-    if (annotations == null || annotations.isEmpty()) {
-      return false;
-    }
-
-    return annotations
-        .getOrDefault(CREATE_IN_CHE_INSTALLATION_NAMESPACE, FALSE.toString())
-        .equals(TRUE.toString());
-  }
-
   @Traced
   @SuppressWarnings("WeakerAccess") // package-private so that interception is possible
   List createServices(KubernetesEnvironment env, String workspaceId)
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java
index e22b643d3fa..ac889f8948d 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespace.java
@@ -11,18 +11,16 @@
  */
 package org.eclipse.che.workspace.infrastructure.kubernetes.namespace;
 
-import static java.lang.Boolean.FALSE;
-import static java.lang.Boolean.TRUE;
 import static org.eclipse.che.workspace.infrastructure.kubernetes.Annotations.CREATE_IN_CHE_INSTALLATION_NAMESPACE;
 import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_WORKSPACE_ID_LABEL;
 import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.putLabel;
+import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.shouldCreateInCheNamespace;
 
 import io.fabric8.kubernetes.api.model.ConfigMap;
 import io.fabric8.kubernetes.client.KubernetesClientException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import org.eclipse.che.api.core.ServerException;
@@ -32,7 +30,7 @@
 import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
 import org.eclipse.che.api.workspace.server.spi.InternalRuntime;
 import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations;
-import org.eclipse.che.workspace.infrastructure.kubernetes.CheKubernetesClientFactory;
+import org.eclipse.che.workspace.infrastructure.kubernetes.CheServerKubernetesClientFactory;
 import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInfrastructureException;
 import org.eclipse.che.workspace.infrastructure.kubernetes.environment.CheInstallationLocation;
 
@@ -45,13 +43,13 @@
 public class CheNamespace {
 
   private final String cheNamespaceName;
-  private final CheKubernetesClientFactory clientFactory;
+  private final CheServerKubernetesClientFactory clientFactory;
   private final WorkspaceRuntimes workspaceRuntimes;
 
   @Inject
   public CheNamespace(
       CheInstallationLocation installationLocation,
-      CheKubernetesClientFactory clientFactory,
+      CheServerKubernetesClientFactory clientFactory,
       WorkspaceRuntimes workspaceRuntimes)
       throws InfrastructureException {
     this.cheNamespaceName = installationLocation.getInstallationLocationNamespace();
@@ -75,11 +73,7 @@ private ConfigMap createConfigMap(ConfigMap configMap, RuntimeIdentity identity)
       throws InfrastructureException {
     putLabel(configMap, CHE_WORKSPACE_ID_LABEL, identity.getWorkspaceId());
     // check that ConfigMap is properly annotated to be created in Che installation namespace
-    Map annotations = configMap.getMetadata().getAnnotations();
-    if (annotations == null
-        || !annotations
-            .getOrDefault(CREATE_IN_CHE_INSTALLATION_NAMESPACE, FALSE.toString())
-            .equals(TRUE.toString())) {
+    if (!shouldCreateInCheNamespace(configMap)) {
       throw new InfrastructureException(
           String.format(
               "ConfigMap '%s' to be created in Che installation namespace is not properly annotated with '%s=true'. This is a bug, please report.",
diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesObjectUtil.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesObjectUtil.java
index 82d127ee51f..fb72a140f8c 100644
--- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesObjectUtil.java
+++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesObjectUtil.java
@@ -12,6 +12,9 @@
 package org.eclipse.che.workspace.infrastructure.kubernetes.namespace;
 
 import static com.google.common.base.Strings.isNullOrEmpty;
+import static java.lang.Boolean.FALSE;
+import static java.lang.Boolean.TRUE;
+import static org.eclipse.che.workspace.infrastructure.kubernetes.Annotations.CREATE_IN_CHE_INSTALLATION_NAMESPACE;
 
 import com.google.common.collect.ImmutableMap;
 import io.fabric8.kubernetes.api.model.HasMetadata;
@@ -33,6 +36,7 @@
 import io.fabric8.kubernetes.api.model.apps.DeploymentSpec;
 import java.util.HashMap;
 import java.util.Map;
+import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations;
 
 /**
  * Helps to work with Kubernetes objects.
@@ -224,4 +228,29 @@ public static Volume newVolume(String name, String pvcName) {
         new PersistentVolumeClaimVolumeSourceBuilder().withClaimName(pvcName).build();
     return new VolumeBuilder().withPersistentVolumeClaim(pvcs).withName(name).build();
   }
+
+  /**
+   * Checks the object if it is propetly annotated to be created in Che installation namespace.
+   *
+   * 

Create in Che installation namespace only if there is {@link + * Annotations#CREATE_IN_CHE_INSTALLATION_NAMESPACE} annotation set exactly to `true`. In all + * other cases we create the object in Workspace's namespace. + * + * @param k8sObject object to check + * @return `true` if {@link Annotations#CREATE_IN_CHE_INSTALLATION_NAMESPACE} is set to `true`. + * `false` otherwise. + */ + public static boolean shouldCreateInCheNamespace(HasMetadata k8sObject) { + if (k8sObject.getMetadata() == null) { + return false; + } + Map annotations = k8sObject.getMetadata().getAnnotations(); + if (annotations == null || annotations.isEmpty()) { + return false; + } + + return annotations + .getOrDefault(CREATE_IN_CHE_INSTALLATION_NAMESPACE, FALSE.toString()) + .equals(TRUE.toString()); + } } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespaceTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespaceTest.java index 71ea3f38148..7622ad4c6f1 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespaceTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/CheNamespaceTest.java @@ -37,7 +37,7 @@ import org.eclipse.che.api.workspace.server.WorkspaceRuntimes; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.InternalRuntime; -import org.eclipse.che.workspace.infrastructure.kubernetes.CheKubernetesClientFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.CheServerKubernetesClientFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.CheInstallationLocation; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; @@ -55,7 +55,7 @@ public class CheNamespaceTest { private CheNamespace cheNamespace; @Mock private CheInstallationLocation cheInstallationLocation; - @Mock private CheKubernetesClientFactory clientFactory; + @Mock private CheServerKubernetesClientFactory clientFactory; @Mock private WorkspaceRuntimes workspaceRuntimes; @Mock private RuntimeIdentity identity; @Mock private KubernetesClient kubeClient; From ec1201d50a7eabc934c52a1e966bfc84024a62ce Mon Sep 17 00:00:00 2001 From: Michal Vala Date: Fri, 21 Aug 2020 20:30:08 +0200 Subject: [PATCH 47/47] expose paths with ending slash Signed-off-by: Michal Vala --- .../kubernetes/server/external/GatewayServerExposer.java | 6 +++--- .../server/external/GatewayServerExposerTest.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java index 308e177d779..60b1387eb79 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposer.java @@ -98,7 +98,7 @@ private ConfigMap createGatewayRouteConfigmap( String scRef, ServerConfig serverConfig) { - final String path = ensureDontEndsWithSlash(strategy.getExternalPath(serviceName, serverName)); + final String path = ensureEndsWithSlash(strategy.getExternalPath(serviceName, serverName)); serverConfig.getAttributes().put(SERVICE_NAME_ATTRIBUTE, serviceName); serverConfig .getAttributes() @@ -121,8 +121,8 @@ private ConfigMap createGatewayRouteConfigmap( return gatewayConfigMap.build(); } - private String ensureDontEndsWithSlash(String path) { - return path.endsWith("/") ? path.substring(0, path.length() - 1) : path; + private String ensureEndsWithSlash(String path) { + return path.endsWith("/") ? path : path + '/'; } private String createName(String serviceName, String serverName) { diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java index 8b8f2139fde..c50b08106a8 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/external/GatewayServerExposerTest.java @@ -75,6 +75,6 @@ public void testExposeServiceWithGatewayConfigmap() { assertEquals(s1.getAttributes().get(ServerConfigImpl.SERVICE_PORT_ATTRIBUTE), "1234"); assertEquals(s1.getPort(), "1111"); assertEquals(s1.getProtocol(), "ws"); - assertEquals(s1.getPath(), "/service/server"); + assertEquals(s1.getPath(), "/service/server/"); } }