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

Ingress/Route per plugin endpoint #15432

Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
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 @@ -11,6 +11,11 @@
*/
package org.eclipse.che.api.core.model.workspace.config;

import static java.lang.String.join;
import static java.util.Collections.emptyList;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.eclipse.che.api.core.model.workspace.runtime.Server;
import org.eclipse.che.commons.annotation.Nullable;
Expand Down Expand Up @@ -51,6 +56,12 @@ public interface ServerConfig {
*/
String SECURE_SERVER_COOKIES_AUTH_ENABLED_ATTRIBUTE = "cookiesAuthEnabled";

/**
* {@link ServerConfig} and {@link Server} attribute name which sets the server as unique, meaning
* that, if exposed, it has its own endpoint even if it shares the same port with other servers.
*/
String UNIQUE_SERVER_ATTRIBUTE = "unique";

/**
* Port used by server.
*
Expand Down Expand Up @@ -87,4 +98,140 @@ public interface ServerConfig {

/** Attributes of the server */
Map<String, String> getAttributes();

/**
* Determines whether the attributes configure the server to be internal.
*
* @param attributes the attributes with additional server configuration
* @see #INTERNAL_SERVER_ATTRIBUTE
*/
static boolean isInternal(Map<String, String> attributes) {
return AttributesEvaluator.booleanAttr(attributes, INTERNAL_SERVER_ATTRIBUTE, false);
}

/**
* Sets the "internal" flag in the provided attributes to the provided value.
*
* @param attributes the attributes with the additional server configuration
*/
static void setInternal(Map<String, String> attributes, boolean value) {
metlos marked this conversation as resolved.
Show resolved Hide resolved
attributes.put(INTERNAL_SERVER_ATTRIBUTE, Boolean.toString(value));
}

/**
* Determines whether the attributes configure the server to be secure.
*
* @param attributes the attributes with additional server configuration
* @see #SECURE_SERVER_ATTRIBUTE
*/
static boolean isSecure(Map<String, String> attributes) {
return AttributesEvaluator.booleanAttr(attributes, SECURE_SERVER_ATTRIBUTE, false);
}

/**
* Sets the "secure" flag in the provided attributes to the provided value.
*
* @param attributes the attributes with the additional server configuration
*/
static void setSecure(Map<String, String> attributes, boolean value) {
attributes.put(SECURE_SERVER_ATTRIBUTE, Boolean.toString(value));
}

/**
* Determines whether the attributes configure the server to be unique.
*
* @param attributes the attributes with additional server configuration
* @see #UNIQUE_SERVER_ATTRIBUTE
*/
static boolean isUnique(Map<String, String> attributes) {
return AttributesEvaluator.booleanAttr(attributes, UNIQUE_SERVER_ATTRIBUTE, false);
}

/**
* Sets the "unique" flag in the provided attributes to the provided value.
*
* @param attributes the attributes with the additional server configuration
*/
static void setUnique(Map<String, String> attributes, boolean value) {
attributes.put(UNIQUE_SERVER_ATTRIBUTE, Boolean.toString(value));
}

/**
* Determines whether the attributes configure the server to be authenticated using JWT cookies.
*
* @param attributes the attributes with additional server configuration
* @see #SECURE_SERVER_COOKIES_AUTH_ENABLED_ATTRIBUTE
*/
static boolean isCookiesAuthEnabled(Map<String, String> attributes) {
return AttributesEvaluator.booleanAttr(
attributes, SECURE_SERVER_COOKIES_AUTH_ENABLED_ATTRIBUTE, false);
}

/**
* Sets the "cookiesAuthEnabled" flag in the provided attributes to the provided value.
*
* @param attributes the attributes with the additional server configuration
*/
static void setCookiesAuthEnabled(Map<String, String> attributes, boolean value) {
attributes.put(SECURE_SERVER_COOKIES_AUTH_ENABLED_ATTRIBUTE, Boolean.toString(value));
}

/**
* Finds the unsecured paths configuration in the provided attributes.s
*
* @param attributes the attributes with additional server configuration
* @see #UNSECURED_PATHS_ATTRIBUTE
*/
static List<String> getUnsecuredPaths(Map<String, String> attributes) {
if (attributes == null) {
return emptyList();
}

String paths = attributes.get(UNSECURED_PATHS_ATTRIBUTE);
if (paths == null) {
return emptyList();
}

return Arrays.asList(paths.split("\\s*,\\s*"));
}

static void setUnsecuredPaths(Map<String, String> attributes, List<String> value) {
attributes.put(UNSECURED_PATHS_ATTRIBUTE, join(",", value));
}

default boolean isInternal() {
return isInternal(getAttributes());
}

default boolean isSecure() {
return isSecure(getAttributes());
}

default boolean isUnique() {
return isUnique(getAttributes());
}

default boolean isCookiesAuthEnabled() {
return isCookiesAuthEnabled(getAttributes());
}

default List<String> getUnsecuredPaths() {
return getUnsecuredPaths(getAttributes());
}
}

// helper class for the default methods in the above interface
class AttributesEvaluator {
static boolean booleanAttr(Map<String, String> attrs, String name, boolean defaultValue) {
if (attrs == null) {
return defaultValue;
}

String attr = attrs.get(name);
if (attr == null) {
return defaultValue;
}

return Boolean.parseBoolean(attr);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ public interface Server {
/** @return the status */
ServerStatus getStatus();

/** Returns attributes of the server with some metadata */
/**
* Returns attributes of the server with some metadata. You can use static methods on {@link
* org.eclipse.che.api.core.model.workspace.config.ServerConfig} to evaluate attributes in this
* map easily.
*/
Map<String, String> getAttributes();
}
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ private ServerConfigImpl toServerConfig(Endpoint endpoint) {

String isPublic = attributes.remove(PUBLIC_ENDPOINT_ATTRIBUTE);
if ("false".equals(isPublic)) {
attributes.put(ServerConfig.INTERNAL_SERVER_ATTRIBUTE, "true");
ServerConfig.setInternal(attributes, true);
}

return new ServerConfigImpl(Integer.toString(endpoint.getPort()), protocol, path, attributes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

import static java.lang.Integer.parseInt;
import static java.util.stream.Collectors.toMap;
import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.INTERNAL_SERVER_ATTRIBUTE;
import static org.eclipse.che.commons.lang.NameGenerator.generate;
import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_ORIGINAL_NAME_LABEL;

Expand Down Expand Up @@ -143,13 +142,13 @@ public void expose(Map<String, ? extends ServerConfig> servers) throws Infrastru

servers.forEach(
(key, value) -> {
if ("true".equals(value.getAttributes().get(INTERNAL_SERVER_ATTRIBUTE))) {
if (value.isInternal()) {
// Server is internal. It doesn't make sense to make an it secure since
// it is available only within workspace servers
internalServers.put(key, value);
} else {
// Server is external. Check if it should be secure or not
if ("true".equals(value.getAttributes().get(ServerConfig.SECURE_SERVER_ATTRIBUTE))) {
if (value.isSecure()) {
secureServers.put(key, value);
} else {
externalServers.put(key, value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.KubernetesServerExposer.SERVER_PREFIX;
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.KubernetesServerExposer.SERVER_UNIQUE_PART_SIZE;

import com.google.common.collect.ImmutableMap;
import io.fabric8.kubernetes.api.model.IntOrString;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.ServicePort;
Expand All @@ -28,6 +29,7 @@
import javax.inject.Inject;
import javax.inject.Singleton;
import org.eclipse.che.api.workspace.server.model.impl.CommandImpl;
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
import org.eclipse.che.api.workspace.server.spi.InternalInfrastructureException;
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServerExposer;
Expand Down Expand Up @@ -78,24 +80,31 @@ public void expose(T env) throws InternalInfrastructureException {
null,
foundService.get().getMetadata().getName(),
servicePort,
Collections.emptyMap());
ImmutableMap.of(
command.getName(),
new ServerConfigImpl(
servicePort.getName(), "http", "/", Collections.emptyMap())));
skabashnyuk marked this conversation as resolved.
Show resolved Hide resolved
}
} else {
portsToProvision.add(createServicePort(port));
}
}

if (!portsToProvision.isEmpty()) {
String serverName = generate(SERVER_PREFIX, SERVER_UNIQUE_PART_SIZE) + "-previewUrl";
Service service =
new ServerServiceBuilder()
.withName(generate(SERVER_PREFIX, SERVER_UNIQUE_PART_SIZE) + "-previewUrl")
.withPorts(portsToProvision)
.build();
env.getServices().put(service.getMetadata().getName(), service);
new ServerServiceBuilder().withName(serverName).withPorts(portsToProvision).build();
env.getServices().put(serverName, service);
portsToProvision.forEach(
port ->
externalServerExposer.expose(
env, null, service.getMetadata().getName(), port, Collections.emptyMap()));
env,
null,
service.getMetadata().getName(),
port,
ImmutableMap.of(
serverName,
new ServerConfigImpl(port.getName(), "http", "/", Collections.emptyMap()))));
metlos marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.server.external;

import io.fabric8.kubernetes.api.model.ServicePort;

/**
* Provides a path-based strategy for exposing service ports outside the cluster using Ingress
* Ingresses will be created without an explicit host (defaulting to *).
Expand Down Expand Up @@ -45,12 +43,12 @@ public class DefaultHostExternalServiceExposureStrategy implements ExternalServi
public static final String DEFAULT_HOST_STRATEGY = "default-host";

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

@Override
public String getExternalPath(String serviceName, ServicePort servicePort) {
return "/" + serviceName + "/" + servicePort.getName();
public String getExternalPath(String serviceName, String serverName) {
return "/" + serviceName + "/" + serverName;
}
}
Loading