Support `endpoints` for components of type kubernetes/openshift (#16529)
* prepare devfile for k8s/openshift endpoints Signed-off-by: Michal Vala <mvala@redhat.com> * include endpoints for k8s components Signed-off-by: Michal Vala <mvala@redhat.com> make it possible to have public and discoverable k8s component endpoints Signed-off-by: Michal Vala <mvala@redhat.com> test k8s/openshift devfile endpoint validation with attributes Signed-off-by: Michal Vala <mvala@redhat.com> code cleanup, util class to avoid duplicate logic, more tests, remove unused code, ... Signed-off-by: Michal Vala <mvala@redhat.com> * update test devfile for kubernetes endpoint Signed-off-by: Michal Vala <mvala@redhat.com> * import cleanup Signed-off-by: Michal Vala <mvala@redhat.com> * remove unused dependency Signed-off-by: Michal Vala <mvala@redhat.com> * fix missing license headers Signed-off-by: Michal Vala <mvala@redhat.com> * Revert "remove unused dependency" This reverts commit eeb250b60f122ffcb7c70b47180b98147db726d7. * endpoints extractor for k8s and dockerimage components Signed-off-by: Michal Vala <mvala@redhat.com> * k8s/openshift components refactored one more time Signed-off-by: Michal Vala <mvala@redhat.com> * rename extractor->converter Signed-off-by: Michal Vala <mvala@redhat.com> * prepare devfile for k8s/openshift endpoints Signed-off-by: Michal Vala <mvala@redhat.com> * include endpoints for k8s components Signed-off-by: Michal Vala <mvala@redhat.com> make it possible to have public and discoverable k8s component endpoints Signed-off-by: Michal Vala <mvala@redhat.com> test k8s/openshift devfile endpoint validation with attributes Signed-off-by: Michal Vala <mvala@redhat.com> code cleanup, util class to avoid duplicate logic, more tests, remove unused code, ... Signed-off-by: Michal Vala <mvala@redhat.com> * update test devfile for kubernetes endpoint Signed-off-by: Michal Vala <mvala@redhat.com> * import cleanup Signed-off-by: Michal Vala <mvala@redhat.com> * remove unused dependency Signed-off-by: Michal Vala <mvala@redhat.com> * fix missing license headers Signed-off-by: Michal Vala <mvala@redhat.com> * Revert "remove unused dependency" This reverts commit eeb250b60f122ffcb7c70b47180b98147db726d7. * endpoints extractor for k8s and dockerimage components Signed-off-by: Michal Vala <mvala@redhat.com> * k8s/openshift components refactored one more time Signed-off-by: Michal Vala <mvala@redhat.com> * rename extractor->converter Signed-off-by: Michal Vala <mvala@redhat.com> * docs, tests Signed-off-by: Michal Vala <mvala@redhat.com> * add label param to create service method, fix tests Signed-off-by: Michal Vala <mvala@redhat.com> * format, license, Openshift applier fix Signed-off-by: Michal Vala <mvala@redhat.com> * cleanup Signed-off-by: Michal Vala <mvala@redhat.com> * move service creation for discoverable endpoints to later phase, together with all services Signed-off-by: Michal Vala <mvala@redhat.com> * format, cleanup Signed-off-by: Michal Vala <mvala@redhat.com> * tests Signed-off-by: Michal Vala <mvala@redhat.com> * tests, comments Signed-off-by: Michal Vala <mvala@redhat.com> * fix tests Signed-off-by: Michal Vala <mvala@redhat.com> * javadoc and clean the serverconfig from serverName attribute Signed-off-by: Michal Vala <mvala@redhat.com>7.20.x
parent
eb9a2ab9b6
commit
7a6c83b19f
|
|
@ -17,6 +17,7 @@ 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.devfile.Endpoint;
|
||||
import org.eclipse.che.api.core.model.workspace.runtime.Server;
|
||||
import org.eclipse.che.commons.annotation.Nullable;
|
||||
|
||||
|
|
@ -62,6 +63,20 @@ public interface ServerConfig {
|
|||
*/
|
||||
String UNIQUE_SERVER_ATTRIBUTE = "unique";
|
||||
|
||||
/**
|
||||
* {@link ServerConfig} and {@link Server} attribute name which can identify endpoint as
|
||||
* discoverable(i.e. it is accessible by its name from workspace's containers). Attribute value
|
||||
* {@code true} makes a endpoint discoverable, any other value or lack of the attribute makes the
|
||||
* server non-discoverable.
|
||||
*/
|
||||
String DISCOVERABLE_SERVER_ATTRIBUTE = "discoverable";
|
||||
|
||||
/**
|
||||
* This attribute is used to remember {@link Endpoint#getName()} inside {@link ServerConfig} for
|
||||
* internal use.
|
||||
*/
|
||||
String SERVER_NAME_ATTRIBUTE = "serverName";
|
||||
|
||||
/**
|
||||
* Port used by server.
|
||||
*
|
||||
|
|
@ -156,6 +171,16 @@ public interface ServerConfig {
|
|||
attributes.put(UNIQUE_SERVER_ATTRIBUTE, Boolean.toString(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the attributes configure the server to be discoverable.
|
||||
*
|
||||
* @param attributes the attributes with additional server configuration
|
||||
* @see #DISCOVERABLE_SERVER_ATTRIBUTE
|
||||
*/
|
||||
static boolean isDiscoverable(Map<String, String> attributes) {
|
||||
return AttributesEvaluator.booleanAttr(attributes, DISCOVERABLE_SERVER_ATTRIBUTE, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the attributes configure the server to be authenticated using JWT cookies. A
|
||||
* null value means that the attributes don't require any particular authentication.
|
||||
|
|
@ -229,6 +254,11 @@ public interface ServerConfig {
|
|||
default List<String> getUnsecuredPaths() {
|
||||
return getUnsecuredPaths(getAttributes());
|
||||
}
|
||||
|
||||
/** @see #isDiscoverable(Map) */
|
||||
default boolean isDiscoverable() {
|
||||
return isDiscoverable(getAttributes());
|
||||
}
|
||||
}
|
||||
|
||||
// helper class for the default methods in the above interface
|
||||
|
|
|
|||
|
|
@ -14,12 +14,9 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.devfile;
|
|||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.eclipse.che.api.core.model.workspace.config.Command.MACHINE_NAME_ATTRIBUTE;
|
||||
import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.DEVFILE_COMPONENT_ALIAS_ATTRIBUTE;
|
||||
import static org.eclipse.che.api.workspace.server.devfile.Constants.DISCOVERABLE_ENDPOINT_ATTRIBUTE;
|
||||
import static org.eclipse.che.api.workspace.server.devfile.Constants.DOCKERIMAGE_COMPONENT_TYPE;
|
||||
import static org.eclipse.che.api.workspace.server.devfile.Constants.PUBLIC_ENDPOINT_ATTRIBUTE;
|
||||
import static org.eclipse.che.api.workspace.shared.Constants.PROJECTS_VOLUME_NAME;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
|
@ -28,19 +25,13 @@ import io.fabric8.kubernetes.api.model.Container;
|
|||
import io.fabric8.kubernetes.api.model.ContainerBuilder;
|
||||
import io.fabric8.kubernetes.api.model.EnvVar;
|
||||
import io.fabric8.kubernetes.api.model.HasMetadata;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.ServiceBuilder;
|
||||
import io.fabric8.kubernetes.api.model.ServicePort;
|
||||
import io.fabric8.kubernetes.api.model.ServicePortBuilder;
|
||||
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import org.eclipse.che.api.core.model.workspace.config.ServerConfig;
|
||||
import org.eclipse.che.api.core.model.workspace.devfile.Endpoint;
|
||||
import org.eclipse.che.api.workspace.server.devfile.Constants;
|
||||
import org.eclipse.che.api.workspace.server.devfile.FileContentProvider;
|
||||
|
|
@ -120,10 +111,37 @@ public class DockerimageComponentToWorkspaceApplier implements ComponentToWorksp
|
|||
String machineName =
|
||||
componentAlias == null ? toMachineName(dockerimageComponent.getImage()) : componentAlias;
|
||||
|
||||
MachineConfigImpl machineConfig = createMachineConfig(dockerimageComponent, componentAlias);
|
||||
List<HasMetadata> componentObjects = createComponentObjects(dockerimageComponent, machineName);
|
||||
|
||||
k8sEnvProvisioner.provision(
|
||||
workspaceConfig,
|
||||
KubernetesEnvironment.TYPE,
|
||||
componentObjects,
|
||||
ImmutableMap.of(machineName, machineConfig));
|
||||
|
||||
workspaceConfig
|
||||
.getCommands()
|
||||
.stream()
|
||||
.filter(
|
||||
c ->
|
||||
componentAlias != null
|
||||
&& componentAlias.equals(
|
||||
c.getAttributes().get(Constants.COMPONENT_ALIAS_COMMAND_ATTRIBUTE)))
|
||||
.forEach(c -> c.getAttributes().put(MACHINE_NAME_ATTRIBUTE, machineName));
|
||||
}
|
||||
|
||||
private MachineConfigImpl createMachineConfig(
|
||||
ComponentImpl dockerimageComponent, String componentAlias) {
|
||||
MachineConfigImpl machineConfig = new MachineConfigImpl();
|
||||
dockerimageComponent
|
||||
.getEndpoints()
|
||||
.forEach(e -> machineConfig.getServers().put(e.getName(), toServerConfig(e)));
|
||||
machineConfig
|
||||
.getServers()
|
||||
.putAll(
|
||||
dockerimageComponent
|
||||
.getEndpoints()
|
||||
.stream()
|
||||
.collect(
|
||||
Collectors.toMap(Endpoint::getName, ServerConfigImpl::createFromEndpoint)));
|
||||
|
||||
dockerimageComponent
|
||||
.getVolumes()
|
||||
|
|
@ -143,6 +161,11 @@ public class DockerimageComponentToWorkspaceApplier implements ComponentToWorksp
|
|||
machineConfig.getAttributes().put(DEVFILE_COMPONENT_ALIAS_ATTRIBUTE, componentAlias);
|
||||
}
|
||||
|
||||
return machineConfig;
|
||||
}
|
||||
|
||||
private List<HasMetadata> createComponentObjects(
|
||||
ComponentImpl dockerimageComponent, String machineName) {
|
||||
List<HasMetadata> componentObjects = new ArrayList<>();
|
||||
Deployment deployment =
|
||||
buildDeployment(
|
||||
|
|
@ -160,27 +183,7 @@ public class DockerimageComponentToWorkspaceApplier implements ComponentToWorksp
|
|||
dockerimageComponent.getArgs());
|
||||
componentObjects.add(deployment);
|
||||
|
||||
dockerimageComponent
|
||||
.getEndpoints()
|
||||
.stream()
|
||||
.filter(e -> "true".equals(e.getAttributes().get(DISCOVERABLE_ENDPOINT_ATTRIBUTE)))
|
||||
.forEach(e -> componentObjects.add(createService(deployment, e)));
|
||||
|
||||
k8sEnvProvisioner.provision(
|
||||
workspaceConfig,
|
||||
KubernetesEnvironment.TYPE,
|
||||
componentObjects,
|
||||
ImmutableMap.of(machineName, machineConfig));
|
||||
|
||||
workspaceConfig
|
||||
.getCommands()
|
||||
.stream()
|
||||
.filter(
|
||||
c ->
|
||||
componentAlias != null
|
||||
&& componentAlias.equals(
|
||||
c.getAttributes().get(Constants.COMPONENT_ALIAS_COMMAND_ATTRIBUTE)))
|
||||
.forEach(c -> c.getAttributes().put(MACHINE_NAME_ATTRIBUTE, machineName));
|
||||
return componentObjects;
|
||||
}
|
||||
|
||||
private Deployment buildDeployment(
|
||||
|
|
@ -232,45 +235,6 @@ public class DockerimageComponentToWorkspaceApplier implements ComponentToWorksp
|
|||
.build();
|
||||
}
|
||||
|
||||
private ServerConfigImpl toServerConfig(Endpoint endpoint) {
|
||||
HashMap<String, String> attributes = new HashMap<>(endpoint.getAttributes());
|
||||
|
||||
String protocol = attributes.remove("protocol");
|
||||
if (isNullOrEmpty(protocol)) {
|
||||
protocol = "http";
|
||||
}
|
||||
|
||||
String path = attributes.remove("path");
|
||||
|
||||
String isPublic = attributes.remove(PUBLIC_ENDPOINT_ATTRIBUTE);
|
||||
if ("false".equals(isPublic)) {
|
||||
ServerConfig.setInternal(attributes, true);
|
||||
}
|
||||
|
||||
return new ServerConfigImpl(Integer.toString(endpoint.getPort()), protocol, path, attributes);
|
||||
}
|
||||
|
||||
private Service createService(Deployment deployment, Endpoint endpoint) {
|
||||
ServicePort servicePort =
|
||||
new ServicePortBuilder()
|
||||
.withPort(endpoint.getPort())
|
||||
.withProtocol("TCP")
|
||||
.withNewTargetPort(endpoint.getPort())
|
||||
.build();
|
||||
return new ServiceBuilder()
|
||||
.withNewMetadata()
|
||||
.withName(endpoint.getName())
|
||||
.endMetadata()
|
||||
.withNewSpec()
|
||||
.withSelector(
|
||||
ImmutableMap.of(
|
||||
CHE_COMPONENT_NAME_LABEL,
|
||||
deployment.getSpec().getTemplate().getMetadata().getName()))
|
||||
.withPorts(singletonList(servicePort))
|
||||
.endSpec()
|
||||
.build();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static String toMachineName(String imageName) throws DevfileException {
|
||||
if (imageName.isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -39,11 +39,13 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import org.eclipse.che.api.core.model.workspace.WorkspaceConfig;
|
||||
import org.eclipse.che.api.core.model.workspace.config.Command;
|
||||
import org.eclipse.che.api.core.model.workspace.devfile.Component;
|
||||
import org.eclipse.che.api.core.model.workspace.devfile.Endpoint;
|
||||
import org.eclipse.che.api.core.model.workspace.devfile.Entrypoint;
|
||||
import org.eclipse.che.api.workspace.server.devfile.Constants;
|
||||
import org.eclipse.che.api.workspace.server.devfile.DevfileRecipeFormatException;
|
||||
|
|
@ -51,6 +53,7 @@ import org.eclipse.che.api.workspace.server.devfile.FileContentProvider;
|
|||
import org.eclipse.che.api.workspace.server.devfile.convert.component.ComponentToWorkspaceApplier;
|
||||
import org.eclipse.che.api.workspace.server.devfile.exception.DevfileException;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.MachineConfigImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.VolumeImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.devfile.ComponentImpl;
|
||||
|
|
@ -152,15 +155,10 @@ public class KubernetesComponentToWorkspaceApplier implements ComponentToWorkspa
|
|||
|
||||
String componentContent = retrieveContent(k8sComponent, contentProvider);
|
||||
|
||||
List<HasMetadata> componentObjects =
|
||||
new ArrayList<>(unmarshalComponentObjects(k8sComponent, componentContent));
|
||||
|
||||
if (!k8sComponent.getSelector().isEmpty()) {
|
||||
componentObjects = SelectorFilter.filter(componentObjects, k8sComponent.getSelector());
|
||||
}
|
||||
final List<HasMetadata> componentObjects =
|
||||
prepareComponentObjects(k8sComponent, componentContent);
|
||||
|
||||
List<PodData> podsData = getPodDatas(componentObjects);
|
||||
|
||||
podsData
|
||||
.stream()
|
||||
.flatMap(e -> e.getSpec().getContainers().stream())
|
||||
|
|
@ -174,15 +172,29 @@ public class KubernetesComponentToWorkspaceApplier implements ComponentToWorkspa
|
|||
podsData.forEach(p -> envVars.apply(p, k8sComponent.getEnv()));
|
||||
}
|
||||
|
||||
applyEntrypoints(k8sComponent.getEntrypoints(), componentObjects);
|
||||
|
||||
Map<String, MachineConfigImpl> machineConfigs = prepareMachineConfigs(podsData, k8sComponent);
|
||||
|
||||
linkCommandsToMachineName(workspaceConfig, k8sComponent, machineConfigs.keySet());
|
||||
|
||||
k8sEnvProvisioner.provision(workspaceConfig, environmentType, componentObjects, machineConfigs);
|
||||
}
|
||||
|
||||
private List<HasMetadata> prepareComponentObjects(Component k8sComponent, String componentContent)
|
||||
throws DevfileRecipeFormatException {
|
||||
final List<HasMetadata> componentObjects;
|
||||
|
||||
if (!k8sComponent.getSelector().isEmpty()) {
|
||||
componentObjects =
|
||||
SelectorFilter.filter(
|
||||
new ArrayList<>(unmarshalComponentObjects(k8sComponent, componentContent)),
|
||||
k8sComponent.getSelector());
|
||||
} else {
|
||||
componentObjects = new ArrayList<>(unmarshalComponentObjects(k8sComponent, componentContent));
|
||||
}
|
||||
|
||||
applyEntrypoints(k8sComponent.getEntrypoints(), componentObjects);
|
||||
return componentObjects;
|
||||
}
|
||||
|
||||
private void applyProjectsVolumes(List<PodData> podsData, List<HasMetadata> componentObjects) {
|
||||
if (componentObjects
|
||||
.stream()
|
||||
|
|
@ -236,12 +248,25 @@ public class KubernetesComponentToWorkspaceApplier implements ComponentToWorkspa
|
|||
config.getAttributes().put(DEVFILE_COMPONENT_ALIAS_ATTRIBUTE, component.getAlias());
|
||||
}
|
||||
provisionVolumes(component, container, config);
|
||||
provisionEndpoints(component, config);
|
||||
|
||||
machineConfigs.put(machineName, config);
|
||||
}
|
||||
}
|
||||
return machineConfigs;
|
||||
}
|
||||
|
||||
private void provisionEndpoints(Component component, MachineConfigImpl config) {
|
||||
config
|
||||
.getServers()
|
||||
.putAll(
|
||||
component
|
||||
.getEndpoints()
|
||||
.stream()
|
||||
.collect(
|
||||
Collectors.toMap(Endpoint::getName, ServerConfigImpl::createFromEndpoint)));
|
||||
}
|
||||
|
||||
private void provisionVolumes(
|
||||
ComponentImpl component, Container container, MachineConfigImpl config)
|
||||
throws DevfileException {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.server;
|
|||
|
||||
import static java.lang.Integer.parseInt;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.SERVER_NAME_ATTRIBUTE;
|
||||
import static org.eclipse.che.commons.lang.NameGenerator.generate;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_ORIGINAL_NAME_LABEL;
|
||||
|
||||
|
|
@ -25,6 +26,7 @@ import io.fabric8.kubernetes.api.model.ServicePort;
|
|||
import io.fabric8.kubernetes.api.model.ServicePortBuilder;
|
||||
import io.fabric8.kubernetes.api.model.extensions.Ingress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
|
@ -39,6 +41,8 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.provision.Configurati
|
|||
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.UniqueNamesProvisioner;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServerExposer;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Helps to modify {@link KubernetesEnvironment} to make servers that are configured by {@link
|
||||
|
|
@ -98,6 +102,8 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureS
|
|||
*/
|
||||
public class KubernetesServerExposer<T extends KubernetesEnvironment> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(KubernetesServerExposer.class);
|
||||
|
||||
public static final int SERVER_UNIQUE_PART_SIZE = 8;
|
||||
public static final String SERVER_PREFIX = "server";
|
||||
|
||||
|
|
@ -178,11 +184,45 @@ public class KubernetesServerExposer<T extends KubernetesEnvironment> {
|
|||
splitServersAndPortsByExposureType(
|
||||
servers, internalServers, externalServers, secureServers, unsecuredPorts, securedPorts);
|
||||
|
||||
provisionServicesForDiscoverableServers(servers);
|
||||
|
||||
exposeNonSecureServers(internalServers, externalServers, unsecuredPorts);
|
||||
|
||||
exposeSecureServers(secureServers, securedPorts);
|
||||
}
|
||||
|
||||
// TODO: this creates discoverable services as an extra services. Service for same {@link
|
||||
// ServerConfig} is also created later in in {@link #exposeNonSecureServers(Map, Map, Map)} or
|
||||
// {@link #exposeSecureServers(Map, Map)} as a non-discoverable one. This was added during
|
||||
// working on adding endpoints for kubernetes/openshift components, to keep behavior consistent.
|
||||
// However, this logic is probably broken and should be changed.
|
||||
/**
|
||||
* Creates services with defined names for discoverable {@link ServerConfig}s. The name is taken
|
||||
* from {@link ServerConfig}'s attributes under {@link ServerConfig#SERVER_NAME_ATTRIBUTE} and
|
||||
* must be set, otherwise service won't be created.
|
||||
*/
|
||||
private void provisionServicesForDiscoverableServers(
|
||||
Map<String, ? extends ServerConfig> servers) {
|
||||
for (String serverName : servers.keySet()) {
|
||||
ServerConfig server = servers.get(serverName);
|
||||
if (server.getAttributes().containsKey(SERVER_NAME_ATTRIBUTE)) {
|
||||
// remove the name from attributes so we don't send it to the client
|
||||
String endpointName = server.getAttributes().remove(SERVER_NAME_ATTRIBUTE);
|
||||
if (server.isDiscoverable()) {
|
||||
Service service =
|
||||
new ServerServiceBuilder()
|
||||
.withName(endpointName)
|
||||
.withMachineName(machineName)
|
||||
.withSelectorEntry(CHE_ORIGINAL_NAME_LABEL, pod.getMetadata().getName())
|
||||
.withPorts(Collections.singletonList(getServicePort(server)))
|
||||
.withServers(Collections.singletonMap(serverName, server))
|
||||
.build();
|
||||
k8sEnv.getServices().put(service.getMetadata().getName(), service);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void splitServersAndPortsByExposureType(
|
||||
Map<String, ? extends ServerConfig> servers,
|
||||
Map<String, ServerConfig> internalServers,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.devfile;
|
|||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.DEVFILE_COMPONENT_ALIAS_ATTRIBUTE;
|
||||
import static org.eclipse.che.api.workspace.server.devfile.Constants.DISCOVERABLE_ENDPOINT_ATTRIBUTE;
|
||||
import static org.eclipse.che.api.workspace.server.devfile.Constants.DOCKERIMAGE_COMPONENT_TYPE;
|
||||
import static org.eclipse.che.api.workspace.server.devfile.Constants.PUBLIC_ENDPOINT_ATTRIBUTE;
|
||||
import static org.eclipse.che.api.workspace.shared.Constants.PROJECTS_VOLUME_NAME;
|
||||
|
|
@ -31,12 +30,9 @@ import com.google.common.collect.ImmutableMap;
|
|||
import io.fabric8.kubernetes.api.model.Container;
|
||||
import io.fabric8.kubernetes.api.model.EnvVar;
|
||||
import io.fabric8.kubernetes.api.model.HasMetadata;
|
||||
import io.fabric8.kubernetes.api.model.IntOrString;
|
||||
import io.fabric8.kubernetes.api.model.ObjectMeta;
|
||||
import io.fabric8.kubernetes.api.model.PodTemplateSpec;
|
||||
import io.fabric8.kubernetes.api.model.Quantity;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.ServicePort;
|
||||
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
|
@ -352,7 +348,6 @@ public class DockerimageComponentToWorkspaceApplierTest {
|
|||
assertEquals(serverConfig.getPath(), "/ls");
|
||||
assertEquals(serverConfig.getPort(), "4923");
|
||||
Map<String, String> attributes = serverConfig.getAttributes();
|
||||
assertEquals(attributes.size(), 2);
|
||||
assertEquals(attributes.get(ServerConfig.INTERNAL_SERVER_ATTRIBUTE), "true");
|
||||
assertEquals(attributes.get("secure"), "false");
|
||||
}
|
||||
|
|
@ -373,7 +368,7 @@ public class DockerimageComponentToWorkspaceApplierTest {
|
|||
"false",
|
||||
"secure",
|
||||
"false",
|
||||
DISCOVERABLE_ENDPOINT_ATTRIBUTE,
|
||||
"discoverable",
|
||||
"true"));
|
||||
ComponentImpl dockerimageComponent = new ComponentImpl();
|
||||
dockerimageComponent.setAlias("jdk");
|
||||
|
|
@ -394,22 +389,12 @@ public class DockerimageComponentToWorkspaceApplierTest {
|
|||
machinesCaptor.capture());
|
||||
|
||||
List<HasMetadata> objects = objectsCaptor.getValue();
|
||||
assertEquals(objects.size(), 2);
|
||||
assertEquals(objects.size(), 1);
|
||||
assertTrue(objects.get(0) instanceof Deployment);
|
||||
Deployment deployment = (Deployment) objects.get(0);
|
||||
assertEquals(
|
||||
deployment.getSpec().getTemplate().getMetadata().getLabels().get(CHE_COMPONENT_NAME_LABEL),
|
||||
"jdk");
|
||||
|
||||
assertTrue(objects.get(1) instanceof Service);
|
||||
Service service = (Service) objects.get(1);
|
||||
assertEquals(service.getMetadata().getName(), "jdk-ls");
|
||||
assertEquals(service.getSpec().getSelector(), ImmutableMap.of(CHE_COMPONENT_NAME_LABEL, "jdk"));
|
||||
List<ServicePort> ports = service.getSpec().getPorts();
|
||||
assertEquals(ports.size(), 1);
|
||||
ServicePort port = ports.get(0);
|
||||
assertEquals(port.getPort(), Integer.valueOf(4923));
|
||||
assertEquals(port.getTargetPort(), new IntOrString(4923));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.devfile;
|
|||
|
||||
import static io.fabric8.kubernetes.client.utils.Serialization.unmarshal;
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.eclipse.che.api.core.model.workspace.config.Command.MACHINE_NAME_ATTRIBUTE;
|
||||
|
|
@ -32,6 +33,7 @@ import static org.testng.Assert.assertEquals;
|
|||
import static org.testng.Assert.assertNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.fabric8.kubernetes.api.model.Container;
|
||||
import io.fabric8.kubernetes.api.model.HasMetadata;
|
||||
import io.fabric8.kubernetes.api.model.KubernetesList;
|
||||
|
|
@ -51,11 +53,14 @@ import org.eclipse.che.api.workspace.server.devfile.URLFileContentProvider;
|
|||
import org.eclipse.che.api.workspace.server.devfile.exception.DevfileException;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.CommandImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.MachineConfigImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.devfile.ComponentImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.devfile.EndpointImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.devfile.EntrypointImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.devfile.EnvImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.devfile.VolumeImpl;
|
||||
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
|
||||
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.KubernetesRecipeParser;
|
||||
|
|
@ -556,7 +561,6 @@ public class KubernetesComponentToWorkspaceApplierTest {
|
|||
k8sBasedComponents);
|
||||
String yamlRecipeContent = getResource("devfile/petclinic.yaml");
|
||||
doReturn(toK8SList(yamlRecipeContent).getItems()).when(k8sRecipeParser).parse(anyString());
|
||||
List<String> command = asList("teh", "command");
|
||||
ComponentImpl component = new ComponentImpl();
|
||||
component.setType(KUBERNETES_COMPONENT_TYPE);
|
||||
component.setReference(REFERENCE_FILENAME);
|
||||
|
|
@ -583,6 +587,105 @@ public class KubernetesComponentToWorkspaceApplierTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldProvisionEndpointsToAllMachines()
|
||||
throws IOException, ValidationException, InfrastructureException, DevfileException {
|
||||
// given
|
||||
String endpointName = "petclinic-endpoint";
|
||||
Integer endpointPort = 8081;
|
||||
|
||||
String yamlRecipeContent = getResource("devfile/petclinicPods.yaml");
|
||||
doReturn(toK8SList(yamlRecipeContent).getItems()).when(k8sRecipeParser).parse(anyString());
|
||||
|
||||
ComponentImpl component = new ComponentImpl();
|
||||
component.setType(KUBERNETES_COMPONENT_TYPE);
|
||||
component.setReference(REFERENCE_FILENAME);
|
||||
component.setAlias(COMPONENT_NAME);
|
||||
component.setEndpoints(singletonList(new EndpointImpl(endpointName, endpointPort, emptyMap())));
|
||||
|
||||
// when
|
||||
applier.apply(workspaceConfig, component, s -> yamlRecipeContent);
|
||||
|
||||
// then
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentCaptor<Map<String, MachineConfigImpl>> objectsCaptor =
|
||||
ArgumentCaptor.forClass(Map.class);
|
||||
verify(k8sEnvProvisioner).provision(any(), any(), any(), objectsCaptor.capture());
|
||||
Map<String, MachineConfigImpl> configs = objectsCaptor.getValue();
|
||||
assertEquals(configs.size(), 3);
|
||||
configs
|
||||
.values()
|
||||
.forEach(
|
||||
machineConfig -> {
|
||||
Map<String, ServerConfigImpl> serverConfigs = machineConfig.getServers();
|
||||
assertEquals(serverConfigs.size(), 1);
|
||||
assertTrue(serverConfigs.containsKey(endpointName));
|
||||
assertEquals(serverConfigs.get(endpointName).getPort(), endpointPort.toString());
|
||||
assertNull(serverConfigs.get(endpointName).getPath());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldProvisionEndpointWithAttributes()
|
||||
throws IOException, ValidationException, InfrastructureException, DevfileException {
|
||||
// given
|
||||
String endpointName = "petclinic-endpoint";
|
||||
Integer endpointPort = 8081;
|
||||
String endpointProtocol = "tcp";
|
||||
String endpointPath = "path";
|
||||
String endpointPublic = "false";
|
||||
String endpointSecure = "false";
|
||||
|
||||
String yamlRecipeContent = getResource("devfile/petclinicPods.yaml");
|
||||
doReturn(toK8SList(yamlRecipeContent).getItems()).when(k8sRecipeParser).parse(anyString());
|
||||
|
||||
ComponentImpl component = new ComponentImpl();
|
||||
component.setType(KUBERNETES_COMPONENT_TYPE);
|
||||
component.setReference(REFERENCE_FILENAME);
|
||||
component.setAlias(COMPONENT_NAME);
|
||||
component.setEndpoints(
|
||||
singletonList(
|
||||
new EndpointImpl(
|
||||
endpointName,
|
||||
endpointPort,
|
||||
ImmutableMap.of(
|
||||
"protocol",
|
||||
endpointProtocol,
|
||||
"path",
|
||||
endpointPath,
|
||||
"public",
|
||||
endpointPublic,
|
||||
"secure",
|
||||
endpointSecure))));
|
||||
|
||||
// when
|
||||
applier.apply(workspaceConfig, component, s -> yamlRecipeContent);
|
||||
|
||||
// then
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentCaptor<Map<String, MachineConfigImpl>> objectsCaptor =
|
||||
ArgumentCaptor.forClass(Map.class);
|
||||
verify(k8sEnvProvisioner).provision(any(), any(), any(), objectsCaptor.capture());
|
||||
Map<String, MachineConfigImpl> configs = objectsCaptor.getValue();
|
||||
assertEquals(configs.size(), 3);
|
||||
configs
|
||||
.values()
|
||||
.forEach(
|
||||
machineConfig -> {
|
||||
Map<String, ServerConfigImpl> serverConfigs = machineConfig.getServers();
|
||||
assertEquals(serverConfigs.size(), 1);
|
||||
assertTrue(serverConfigs.containsKey(endpointName));
|
||||
assertEquals(serverConfigs.get(endpointName).getPort(), endpointPort.toString());
|
||||
assertEquals(serverConfigs.get(endpointName).getPath(), endpointPath);
|
||||
assertEquals(serverConfigs.get(endpointName).getProtocol(), endpointProtocol);
|
||||
assertEquals(
|
||||
serverConfigs.get(endpointName).isSecure(), Boolean.parseBoolean(endpointSecure));
|
||||
assertEquals(
|
||||
serverConfigs.get(endpointName).isInternal(),
|
||||
!Boolean.parseBoolean(endpointPublic));
|
||||
});
|
||||
}
|
||||
|
||||
private KubernetesList toK8SList(String content) {
|
||||
return unmarshal(content, KubernetesList.class);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.server;
|
|||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.DISCOVERABLE_SERVER_ATTRIBUTE;
|
||||
import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.SERVER_NAME_ATTRIBUTE;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.KubernetesServerExposer.SERVER_PREFIX;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.KubernetesServerExposer.SERVER_UNIQUE_PART_SIZE;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
|
|
@ -20,6 +22,7 @@ import static org.mockito.ArgumentMatchers.eq;
|
|||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
|
|
@ -396,6 +399,43 @@ public class KubernetesServerExposerTest {
|
|||
"ws-server", new ServerConfigImpl(wsServerConfig).withAttributes(ATTRIBUTES_MAP)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateExtraServiceForDiscoverableServerConfig() throws InfrastructureException {
|
||||
// given
|
||||
ServerConfigImpl httpServerConfig =
|
||||
new ServerConfigImpl(
|
||||
"8080/tcp",
|
||||
"http",
|
||||
"/api",
|
||||
ImmutableMap.of(SERVER_NAME_ATTRIBUTE, "hello", DISCOVERABLE_SERVER_ATTRIBUTE, "true"));
|
||||
Map<String, ServerConfigImpl> serversToExpose =
|
||||
ImmutableMap.of("http-server", httpServerConfig);
|
||||
|
||||
// when
|
||||
serverExposer.expose(serversToExpose);
|
||||
|
||||
assertEquals(kubernetesEnvironment.getServices().size(), 2);
|
||||
assertTrue(kubernetesEnvironment.getServices().containsKey("hello"));
|
||||
assertEquals(kubernetesEnvironment.getServices().get("hello").getMetadata().getName(), "hello");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDiscoverableServerConfigWithoutNameAttributeIsNotProvisioned()
|
||||
throws InfrastructureException {
|
||||
// given
|
||||
ServerConfigImpl httpServerConfig =
|
||||
new ServerConfigImpl(
|
||||
"8080/tcp", "http", "/api", ImmutableMap.of(DISCOVERABLE_SERVER_ATTRIBUTE, "true"));
|
||||
Map<String, ServerConfigImpl> serversToExpose =
|
||||
ImmutableMap.of("http-server", httpServerConfig);
|
||||
|
||||
// when
|
||||
serverExposer.expose(serversToExpose);
|
||||
|
||||
assertEquals(kubernetesEnvironment.getServices().size(), 1);
|
||||
assertFalse(kubernetesEnvironment.getServices().containsKey("hello"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private void assertThatExternalServerIsExposed(
|
||||
String machineName,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: List
|
||||
items:
|
||||
- apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: petclinic
|
||||
labels:
|
||||
app.kubernetes.io/name: petclinic
|
||||
app.kubernetes.io/component: webapp
|
||||
app.kubernetes.io/part-of: petclinic
|
||||
spec:
|
||||
containers:
|
||||
- name: server
|
||||
image: mariolet/petclinic
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: TCP
|
||||
resources:
|
||||
limits:
|
||||
memory: 512Mi
|
||||
- apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: mysql
|
||||
labels:
|
||||
app.kubernetes.io/name: mysql
|
||||
app.kubernetes.io/component: database
|
||||
app.kubernetes.io/part-of: petclinic
|
||||
spec:
|
||||
containers:
|
||||
- name: mysql
|
||||
image: centos/mysql-57-centos7
|
||||
env:
|
||||
- name: MYSQL_USER
|
||||
value: petclinic
|
||||
- name: MYSQL_PASSWORD
|
||||
value: petclinic
|
||||
- name: MYSQL_ROOT_PASSWORD
|
||||
value: petclinic
|
||||
- name: MYSQL_DATABASE
|
||||
value: petclinic
|
||||
ports:
|
||||
- containerPort: 3306
|
||||
protocol: TCP
|
||||
resources:
|
||||
limits:
|
||||
memory: 512Mi
|
||||
- apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: withoutLabels
|
||||
spec:
|
||||
containers:
|
||||
- name: server
|
||||
imagePullPolicy: Always
|
||||
image: test/petclinic
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: TCP
|
||||
resources:
|
||||
limits:
|
||||
memory: 512Mi
|
||||
|
|
@ -11,6 +11,9 @@
|
|||
*/
|
||||
package org.eclipse.che.api.workspace.server.model.impl;
|
||||
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static org.eclipse.che.api.workspace.server.devfile.Constants.PUBLIC_ENDPOINT_ATTRIBUTE;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
|
@ -25,6 +28,7 @@ import javax.persistence.JoinColumn;
|
|||
import javax.persistence.MapKeyColumn;
|
||||
import javax.persistence.Table;
|
||||
import org.eclipse.che.api.core.model.workspace.config.ServerConfig;
|
||||
import org.eclipse.che.api.core.model.workspace.devfile.Endpoint;
|
||||
|
||||
/** @author Alexander Garagatyi */
|
||||
@Entity(name = "ServerConf")
|
||||
|
|
@ -175,4 +179,23 @@ public class ServerConfigImpl implements ServerConfig {
|
|||
+ attributes
|
||||
+ '}';
|
||||
}
|
||||
|
||||
public static ServerConfigImpl createFromEndpoint(Endpoint endpoint) {
|
||||
HashMap<String, String> attributes = new HashMap<>(endpoint.getAttributes());
|
||||
attributes.put(SERVER_NAME_ATTRIBUTE, endpoint.getName());
|
||||
|
||||
String protocol = attributes.remove("protocol");
|
||||
if (isNullOrEmpty(protocol)) {
|
||||
protocol = "http";
|
||||
}
|
||||
|
||||
String path = attributes.remove("path");
|
||||
|
||||
String isPublic = attributes.remove(PUBLIC_ENDPOINT_ATTRIBUTE);
|
||||
if ("false".equals(isPublic)) {
|
||||
ServerConfig.setInternal(attributes, true);
|
||||
}
|
||||
|
||||
return new ServerConfigImpl(Integer.toString(endpoint.getPort()), protocol, path, attributes);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -388,6 +388,7 @@
|
|||
"mountSources": {},
|
||||
"volumes": {},
|
||||
"env": {},
|
||||
"endpoints": {},
|
||||
"reference": {
|
||||
"description": "Describes absolute or devfile-relative location of Kubernetes list yaml file. Applicable only for 'kubernetes' and 'openshift' type components",
|
||||
"type": "string",
|
||||
|
|
@ -478,6 +479,7 @@
|
|||
"cpuLimit": {},
|
||||
"cpuRequest": {},
|
||||
"volumes": {},
|
||||
"endpoints": {},
|
||||
"memoryLimit": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
@ -524,56 +526,6 @@
|
|||
"examples": [
|
||||
"['-R', '-f']"
|
||||
]
|
||||
},
|
||||
"endpoints": {
|
||||
"type": "array",
|
||||
"description": "Describes dockerimage component endpoints",
|
||||
"items": {
|
||||
"name": "object",
|
||||
"description": "Describes dockerimage component endpoint",
|
||||
"required": [
|
||||
"name",
|
||||
"port"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "The Endpoint Name",
|
||||
"description": "The Endpoint name"
|
||||
},
|
||||
"port": {
|
||||
"type": "integer",
|
||||
"title": "The Endpoint Port",
|
||||
"description": "The container port that should be used as endpoint"
|
||||
},
|
||||
"attributes": {
|
||||
"type": "object",
|
||||
"public": {
|
||||
"type": "boolean",
|
||||
"description": "Identifies endpoint as workspace internally or externally accessible.",
|
||||
"default": "true"
|
||||
},
|
||||
"secure": {
|
||||
"type": "boolean",
|
||||
"description": "Identifies server as secure or non-secure. Requests to secure servers will be authenticated and must contain machine token",
|
||||
"default": "false"
|
||||
},
|
||||
"discoverable": {
|
||||
"type": "boolean",
|
||||
"description": "Identifies endpoint as accessible by its name.",
|
||||
"default": "false"
|
||||
},
|
||||
"protocol": {
|
||||
"type": "boolean",
|
||||
"description": "Defines protocol that should be used for communication with endpoint. Is used for endpoint URL evaluation"
|
||||
},
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"javaType": "java.util.Map<String, String>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -698,6 +650,56 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"endpoints": {
|
||||
"type": "array",
|
||||
"description": "Describes dockerimage component endpoints",
|
||||
"items": {
|
||||
"name": "object",
|
||||
"description": "Describes dockerimage component endpoint",
|
||||
"required": [
|
||||
"name",
|
||||
"port"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "The Endpoint Name",
|
||||
"description": "The Endpoint name"
|
||||
},
|
||||
"port": {
|
||||
"type": "integer",
|
||||
"title": "The Endpoint Port",
|
||||
"description": "The container port that should be used as endpoint"
|
||||
},
|
||||
"attributes": {
|
||||
"type": "object",
|
||||
"public": {
|
||||
"type": "boolean",
|
||||
"description": "Identifies endpoint as workspace internally or externally accessible.",
|
||||
"default": "true"
|
||||
},
|
||||
"secure": {
|
||||
"type": "boolean",
|
||||
"description": "Identifies server as secure or non-secure. Requests to secure servers will be authenticated and must contain machine token",
|
||||
"default": "false"
|
||||
},
|
||||
"discoverable": {
|
||||
"type": "boolean",
|
||||
"description": "Identifies endpoint as accessible by its name.",
|
||||
"default": "false"
|
||||
},
|
||||
"protocol": {
|
||||
"type": "boolean",
|
||||
"description": "Defines protocol that should be used for communication with endpoint. Is used for endpoint URL evaluation"
|
||||
},
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"javaType": "java.util.Map<String, String>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ public class DevfileSchemaValidatorTest {
|
|||
"kubernetes_openshift_component/devfile_openshift_component_reference_and_content_as_block.yaml"
|
||||
},
|
||||
{"kubernetes_openshift_component/devfile_k8s_openshift_component_with_env.yaml"},
|
||||
{"kubernetes_openshift_component/devfile_k8s_openshift_component_with_endpoints.yaml"},
|
||||
{"kubernetes_openshift_component/devfile_openshift_component_content_without_reference.yaml"},
|
||||
{
|
||||
"kubernetes_openshift_component/devfile_kubernetes_component_content_without_reference.yaml"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* 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.model.impl;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.INTERNAL_SERVER_ATTRIBUTE;
|
||||
import static org.eclipse.che.api.core.model.workspace.config.ServerConfig.SERVER_NAME_ATTRIBUTE;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.util.Map;
|
||||
import org.eclipse.che.api.core.model.workspace.config.ServerConfig;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.devfile.EndpointImpl;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
public class ServerConfigImplTest {
|
||||
|
||||
@Test
|
||||
public void testStoreEndpointNameIntoAttributes() {
|
||||
ServerConfig serverConfig =
|
||||
ServerConfigImpl.createFromEndpoint(new EndpointImpl("blabol", 123, emptyMap()));
|
||||
|
||||
assertEquals(serverConfig.getAttributes().get(SERVER_NAME_ATTRIBUTE), "blabol");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFromEndpointMinimalEndpointShouldTranslateToHttpProtocol() {
|
||||
ServerConfig serverConfig =
|
||||
ServerConfigImpl.createFromEndpoint(new EndpointImpl("name", 123, emptyMap()));
|
||||
|
||||
assertEquals(serverConfig.getProtocol(), "http");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFromEndpointMinimalEndpointShouldTranslateToNullPath() {
|
||||
ServerConfig serverConfig =
|
||||
ServerConfigImpl.createFromEndpoint(new EndpointImpl("name", 123, emptyMap()));
|
||||
|
||||
assertNull(serverConfig.getPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFromEndpointCustomAttributesShouldPreserveInAttributes() {
|
||||
Map<String, String> customAttributes = ImmutableMap.of("k1", "v1", "k2", "v2");
|
||||
ServerConfig serverConfig =
|
||||
ServerConfigImpl.createFromEndpoint(new EndpointImpl("name", 123, customAttributes));
|
||||
|
||||
assertEquals(serverConfig.getAttributes().get("k1"), "v1");
|
||||
assertEquals(serverConfig.getAttributes().get("k2"), "v2");
|
||||
assertEquals(serverConfig.getAttributes().size(), 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFromEndpointTranslatePath() {
|
||||
ServerConfig serverConfig =
|
||||
ServerConfigImpl.createFromEndpoint(
|
||||
new EndpointImpl("name", 123, singletonMap("path", "hello")));
|
||||
|
||||
assertEquals(serverConfig.getPath(), "hello");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFromEndpointTranslateProtocol() {
|
||||
ServerConfig serverConfig =
|
||||
ServerConfigImpl.createFromEndpoint(
|
||||
new EndpointImpl("name", 123, singletonMap("protocol", "hello")));
|
||||
|
||||
assertEquals(serverConfig.getProtocol(), "hello");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFromEndpointTranslatePublicTrue() {
|
||||
ServerConfig serverConfig =
|
||||
ServerConfigImpl.createFromEndpoint(
|
||||
new EndpointImpl("name", 123, singletonMap("public", "true")));
|
||||
|
||||
assertFalse(serverConfig.isInternal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFromEndpointTranslatePublicWhatever() {
|
||||
ServerConfig serverConfig =
|
||||
ServerConfigImpl.createFromEndpoint(
|
||||
new EndpointImpl("name", 123, singletonMap("public", "whatever")));
|
||||
|
||||
assertFalse(serverConfig.isInternal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFromEndpointTranslatePublicFalse() {
|
||||
ServerConfig serverConfig =
|
||||
ServerConfigImpl.createFromEndpoint(
|
||||
new EndpointImpl("name", 123, singletonMap("public", "false")));
|
||||
|
||||
assertFalse(serverConfig.getAttributes().isEmpty());
|
||||
assertEquals(
|
||||
serverConfig.getAttributes().get(INTERNAL_SERVER_ATTRIBUTE), Boolean.TRUE.toString());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
---
|
||||
apiVersion: 1.0.0
|
||||
metadata:
|
||||
name: petclinic-dev-environment
|
||||
components:
|
||||
- alias: mysql
|
||||
type: openshift
|
||||
reference: petclinic.yaml
|
||||
endpoints:
|
||||
- name: test-endpoint-os
|
||||
port: 1234
|
||||
attributes:
|
||||
protocol: http
|
||||
secure: 'true'
|
||||
public: 'true'
|
||||
discoverable: 'false'
|
||||
- alias: web-app
|
||||
type: kubernetes
|
||||
reference: petclinic.yaml
|
||||
endpoints:
|
||||
- name: test-endpoint-k8s
|
||||
port: 4321
|
||||
attributes:
|
||||
protocol: http
|
||||
secure: 'true'
|
||||
public: 'true'
|
||||
discoverable: 'false'
|
||||
Loading…
Reference in New Issue