Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

make single-host gateway configmap labels configurable #17775

Merged
merged 5 commits into from
Sep 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,11 @@ che.infra.kubernetes.server_strategy=multi-host
# Defines the way in which the workspace plugins and editors are exposed in the single-host mode.
# Supported exposures:
# - 'native': Exposes servers using k8s Ingresses. Works only on Kubernetes.
che.infra.kubernetes.single_host.workspace.exposure=native
# - 'gateway': Exposes servers using reverse-proxy gateway.
che.infra.kubernetes.singlehost.workspace.exposure=native

# Defines labels which will be set to ConfigMaps configuring single-host gateway.
che.infra.kubernetes.singlehost.gateway.configmap_labels=app=che,component=che-gateway-config

# Used to generate domain for a server in a workspace in case property `che.infra.kubernetes.server_strategy` is set to `multi-host`
che.infra.kubernetes.ingress.domain=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,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;
import java.util.Map;
import java.util.Map.Entry;
Expand All @@ -27,6 +25,7 @@
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.eclipse.che.workspace.infrastructure.kubernetes.util.GatewayConfigmapLabels;

/**
* This provisioner finds {@link ConfigMap}s, that configures the single-host Gateway, generates
Expand All @@ -36,25 +35,22 @@
*/
public class GatewayRouterProvisioner implements ConfigurationProvisioner<KubernetesEnvironment> {

/** Configmap labeled with these holds the configuration of single-host gateway route */
public static final Map<String, String> GATEWAY_CONFIGMAP_LABELS =
ImmutableMap.<String, String>builder()
.put("app", "che")
.put("role", "gateway-config")
.build();

private final GatewayRouteConfigGeneratorFactory configGeneratorFactory;
private final GatewayConfigmapLabels configmapLabels;

@Inject
public GatewayRouterProvisioner(GatewayRouteConfigGeneratorFactory configGeneratorFactory) {
public GatewayRouterProvisioner(
GatewayRouteConfigGeneratorFactory configGeneratorFactory,
GatewayConfigmapLabels configmapLabels) {
this.configGeneratorFactory = configGeneratorFactory;
this.configmapLabels = configmapLabels;
}

@Override
public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity)
throws InfrastructureException {
for (Entry<String, ConfigMap> configMapEntry : k8sEnv.getConfigMaps().entrySet()) {
if (isGatewayConfig(configMapEntry.getValue())) {
if (configmapLabels.isGatewayConfig(configMapEntry.getValue())) {
ConfigMap gatewayConfigMap = configMapEntry.getValue();

Map<String, ServerConfigImpl> servers =
Expand Down Expand Up @@ -98,20 +94,4 @@ public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity)
}
}
}

/**
* 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) {
for (Entry<String, String> labelEntry : GATEWAY_CONFIGMAP_LABELS.entrySet()) {
if (!isLabeled(configMap, labelEntry.getKey(), labelEntry.getValue())) {
return false;
}
}
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
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.util.GatewayConfigmapLabels;

/**
* Enables Transport Layer Security (TLS) for external server implemented with gateway ConfigMaps.
Expand All @@ -32,11 +33,15 @@
public class GatewayTlsProvisioner<T extends KubernetesEnvironment>
implements ConfigurationProvisioner<T>, TlsProvisioner<T> {

final boolean isTlsEnabled;
private final boolean isTlsEnabled;
private final GatewayConfigmapLabels configmapLabels;

@Inject
public GatewayTlsProvisioner(@Named("che.infra.kubernetes.tls_enabled") boolean isTlsEnabled) {
public GatewayTlsProvisioner(
@Named("che.infra.kubernetes.tls_enabled") boolean isTlsEnabled,
GatewayConfigmapLabels configmapLabels) {
this.isTlsEnabled = isTlsEnabled;
this.configmapLabels = configmapLabels;
}

@Override
Expand All @@ -46,7 +51,7 @@ public void provision(T k8sEnv, RuntimeIdentity identity) throws InfrastructureE
}

for (ConfigMap configMap : k8sEnv.getConfigMaps().values()) {
if (GatewayRouterProvisioner.isGatewayConfig(configMap)) {
if (configmapLabels.isGatewayConfig(configMap)) {
useSecureProtocolForGatewayConfigMap(configMap);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

/**
* Provides {@link TlsProvisioner} based on `che.infra.kubernetes.server_strategy` and
* `che.infra.kubernetes.single_host.workspace.exposure` properties.
* `che.infra.kubernetes.singlehost.workspace.exposure` properties.
*
* @param <T> type of environment
*/
Expand All @@ -30,7 +30,7 @@ public class TlsProvisionerProvider<T extends KubernetesEnvironment>
@Inject
public TlsProvisionerProvider(
@Named("che.infra.kubernetes.server_strategy") String exposureStrategy,
@Named("che.infra.kubernetes.single_host.workspace.exposure") String wsExposureType,
@Named("che.infra.kubernetes.singlehost.workspace.exposure") String wsExposureType,
Map<WorkspaceExposureType, TlsProvisioner<T>> mapping) {
super(
exposureStrategy,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public abstract class AbstractExposureStrategyAwareProvider<T> implements Provid
*/
protected AbstractExposureStrategyAwareProvider(
@Named("che.infra.kubernetes.server_strategy") String exposureStrategy,
@Named("che.infra.kubernetes.single_host.workspace.exposure") String wsExposureType,
@Named("che.infra.kubernetes.singlehost.workspace.exposure") String wsExposureType,
Map<WorkspaceExposureType, T> mapping,
String errorMessageTemplate) {
if (exposureStrategy.equals(SingleHostExternalServiceExposureStrategy.SINGLE_HOST_STRATEGY)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

/**
* Provides {@link ExternalServerExposer} based on `che.infra.kubernetes.server_strategy` and
* `che.infra.kubernetes.single_host.workspace.exposure` properties.
* `che.infra.kubernetes.singlehost.workspace.exposure` properties.
*
* @param <T> type of environment
*/
Expand All @@ -31,7 +31,7 @@ public class ExternalServerExposerProvider<T extends KubernetesEnvironment>
@Inject
public ExternalServerExposerProvider(
@Named("che.infra.kubernetes.server_strategy") String exposureStrategy,
@Named("che.infra.kubernetes.single_host.workspace.exposure") String exposureType,
@Named("che.infra.kubernetes.singlehost.workspace.exposure") String exposureType,
Map<WorkspaceExposureType, ExternalServerExposer<T>> exposers) {

super(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ 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)}.
*
* <p>Provided {@link ConfigMap} must be properly labeled and must be annotated with {@link
* org.eclipse.che.api.core.model.workspace.config.ServerConfig} annotations.
* <p>Provided {@link ConfigMap} must be annotated with {@link
* org.eclipse.che.api.core.model.workspace.config.ServerConfig} annotations. It's responsibility
* of the caller to ensure that. The {@link GatewayRouteConfigGenerator} fails on {@link
* GatewayRouteConfigGenerator#generate(String)} when invalid {@link ConfigMap}s are added to it.
*
* @param routeConfig config to add
* @throws InfrastructureException when passed ConfigMap is not gateway configuration ConfigMap
*/
void addRouteConfig(String name, ConfigMap routeConfig) throws InfrastructureException;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
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;
import org.eclipse.che.workspace.infrastructure.kubernetes.util.GatewayConfigmapLabels;

/**
* Uses gateway configured with ConfigMaps to expose servers.
Expand All @@ -39,10 +39,13 @@ public class GatewayServerExposer<T extends KubernetesEnvironment>
implements ExternalServerExposer<T> {

private final ExternalServiceExposureStrategy strategy;
private final GatewayConfigmapLabels configmapLabels;

@Inject
public GatewayServerExposer(ExternalServiceExposureStrategy strategy) {
public GatewayServerExposer(
ExternalServiceExposureStrategy strategy, GatewayConfigmapLabels configmapLabels) {
this.strategy = strategy;
this.configmapLabels = configmapLabels;
}

/**
Expand Down Expand Up @@ -115,7 +118,7 @@ private ConfigMap createGatewayRouteConfigmap(
new ConfigMapBuilder()
.withNewMetadata()
.withName(name)
.withLabels(GatewayRouterProvisioner.GATEWAY_CONFIGMAP_LABELS)
.withLabels(configmapLabels.getLabels())
.withAnnotations(annotations)
.endMetadata();
return gatewayConfigMap.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
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;
Expand Down Expand Up @@ -65,15 +64,8 @@ public class TraefikGatewayRouteConfigGenerator implements GatewayRouteConfigGen
private final Map<String, ConfigMap> routeConfigs = new HashMap<>();

@Override
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.");
}
public void addRouteConfig(String name, ConfigMap routeConfig) {
this.routeConfigs.put(name, routeConfig);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class AbstractServerResolverFactory<T> {

protected AbstractServerResolverFactory(
@Named("che.infra.kubernetes.server_strategy") String exposureStrategy,
@Named("che.infra.kubernetes.single_host.workspace.exposure") String wsExposureType,
@Named("che.infra.kubernetes.singlehost.workspace.exposure") String wsExposureType,
Map<WorkspaceExposureType, ResolverConstructor<T>> mapping,
String errorMessageTemplate) {
constructorProvider =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public KubernetesServerResolverFactory(
IngressPathTransformInverter pathTransformInverter,
@Named("che.host") String cheHost,
@Named("che.infra.kubernetes.server_strategy") String exposureStrategy,
@Named("che.infra.kubernetes.single_host.workspace.exposure") String wsExposureType) {
@Named("che.infra.kubernetes.singlehost.workspace.exposure") String wsExposureType) {

super(
exposureStrategy,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.util;

import static com.google.common.base.Strings.isNullOrEmpty;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.isLabeled;

import com.google.common.base.Splitter;
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;
import org.eclipse.che.inject.ConfigurationException;

/** Little utility bean helping with Gateway ConfigMaps labels. */
@Singleton
public class GatewayConfigmapLabels {

private final Map<String, String> labels;

@Inject
public GatewayConfigmapLabels(
@Named("che.infra.kubernetes.singlehost.gateway.configmap_labels") String labelsProperty) {
if (isNullOrEmpty(labelsProperty)) {
throw new ConfigurationException(
"for gateway single-host, 'che.infra.kubernetes.singlehost.gateway.configmap_labels' property must be defined");
}
try {
this.labels = Splitter.on(",").trimResults().withKeyValueSeparator("=").split(labelsProperty);
} catch (IllegalArgumentException iae) {
throw new ConfigurationException(
"'che.infra.kubernetes.singlehost.gateway.configmap_labels' is set to invalid value. It must be in format `name1=value1,name2=value2`. Check the documentation for further details.",
iae);
}
}

public Map<String, String> getLabels() {
return labels;
}

/**
* Check whether configmap is gateway route configuration. That is defined with labels provided by
* `che.infra.kubernetes.singlehost.gateway.configmap_labels` configuration property.
*
* @param configMap to check
* @return `true` if ConfigMap is gateway route configuration, `false` otherwise
*/
public boolean isGatewayConfig(ConfigMap configMap) {
for (Entry<String, String> labelEntry : labels.entrySet()) {
if (!isLabeled(configMap, labelEntry.getKey(), labelEntry.getValue())) {
return false;
}
}
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
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;
Expand Down Expand Up @@ -1136,15 +1135,13 @@ public void testGatewayRouteConfigsAreCreatedAsConfigmapsInCheNamespace()
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();
Expand Down
Loading