fix: devfile endpoint with single-host exposure (#157)
Signed-off-by: Michal Vala <mvala@redhat.com>pull/154/head
parent
63d0ab9c89
commit
3a99240d2f
|
|
@ -17,7 +17,9 @@ import static java.lang.String.format;
|
|||
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.DOCKERIMAGE_COMPONENT_TYPE;
|
||||
import static org.eclipse.che.api.workspace.server.devfile.convert.component.ComponentToWorkspaceApplier.convertEndpointsIntoServers;
|
||||
import static org.eclipse.che.api.workspace.shared.Constants.PROJECTS_VOLUME_NAME;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.SingleHostExternalServiceExposureStrategy.SINGLE_HOST_STRATEGY;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
|
@ -32,13 +34,11 @@ 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.devfile.Endpoint;
|
||||
import org.eclipse.che.api.workspace.server.devfile.Constants;
|
||||
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;
|
||||
|
|
@ -65,15 +65,19 @@ public class DockerimageComponentToWorkspaceApplier implements ComponentToWorksp
|
|||
private final String projectFolderPath;
|
||||
private final String imagePullPolicy;
|
||||
private final KubernetesEnvironmentProvisioner k8sEnvProvisioner;
|
||||
private final String devfileEndpointsExposure;
|
||||
|
||||
@Inject
|
||||
public DockerimageComponentToWorkspaceApplier(
|
||||
@Named("che.workspace.projects.storage") String projectFolderPath,
|
||||
@Named("che.workspace.sidecar.image_pull_policy") String imagePullPolicy,
|
||||
@Named("che.infra.kubernetes.singlehost.workspace.devfile_endpoint_exposure")
|
||||
String devfileEndpointsExposure,
|
||||
KubernetesEnvironmentProvisioner k8sEnvProvisioner) {
|
||||
this.projectFolderPath = projectFolderPath;
|
||||
this.imagePullPolicy = imagePullPolicy;
|
||||
this.k8sEnvProvisioner = k8sEnvProvisioner;
|
||||
this.devfileEndpointsExposure = devfileEndpointsExposure;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -137,12 +141,9 @@ public class DockerimageComponentToWorkspaceApplier implements ComponentToWorksp
|
|||
machineConfig
|
||||
.getServers()
|
||||
.putAll(
|
||||
dockerimageComponent
|
||||
.getEndpoints()
|
||||
.stream()
|
||||
.collect(
|
||||
Collectors.toMap(
|
||||
Endpoint::getName, e -> ServerConfigImpl.createFromEndpoint(e, true))));
|
||||
convertEndpointsIntoServers(
|
||||
dockerimageComponent.getEndpoints(),
|
||||
!SINGLE_HOST_STRATEGY.equals(devfileEndpointsExposure)));
|
||||
|
||||
dockerimageComponent
|
||||
.getVolumes()
|
||||
|
|
|
|||
|
|
@ -18,12 +18,14 @@ import static java.util.stream.Collectors.toList;
|
|||
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.Components.getIdentifiableComponentName;
|
||||
import static org.eclipse.che.api.workspace.server.devfile.convert.component.ComponentToWorkspaceApplier.convertEndpointsIntoServers;
|
||||
import static org.eclipse.che.api.workspace.shared.Constants.PROJECTS_VOLUME_NAME;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.Names.machineName;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.devfile.KubernetesDevfileBindings.KUBERNETES_BASED_COMPONENTS_KEY_NAME;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.newPVC;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.newVolume;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.newVolumeMount;
|
||||
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.SingleHostExternalServiceExposureStrategy.SINGLE_HOST_STRATEGY;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.Container;
|
||||
import io.fabric8.kubernetes.api.model.HasMetadata;
|
||||
|
|
@ -39,14 +41,12 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
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;
|
||||
|
|
@ -54,7 +54,6 @@ 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;
|
||||
|
|
@ -80,6 +79,7 @@ public class KubernetesComponentToWorkspaceApplier implements ComponentToWorkspa
|
|||
private final String defaultPVCAccessMode;
|
||||
private final String pvcStorageClassName;
|
||||
private final EnvVars envVars;
|
||||
private final String devfileEndpointsExposure;
|
||||
|
||||
@Inject
|
||||
public KubernetesComponentToWorkspaceApplier(
|
||||
|
|
@ -91,6 +91,8 @@ public class KubernetesComponentToWorkspaceApplier implements ComponentToWorkspa
|
|||
@Named("che.infra.kubernetes.pvc.access_mode") String defaultPVCAccessMode,
|
||||
@Named("che.infra.kubernetes.pvc.storage_class_name") String pvcStorageClassName,
|
||||
@Named("che.workspace.sidecar.image_pull_policy") String imagePullPolicy,
|
||||
@Named("che.infra.kubernetes.singlehost.workspace.devfile_endpoint_exposure")
|
||||
String devfileEndpointsExposure,
|
||||
@Named(KUBERNETES_BASED_COMPONENTS_KEY_NAME) Set<String> kubernetesBasedComponentTypes) {
|
||||
this(
|
||||
objectsParser,
|
||||
|
|
@ -102,6 +104,7 @@ public class KubernetesComponentToWorkspaceApplier implements ComponentToWorkspa
|
|||
defaultPVCAccessMode,
|
||||
pvcStorageClassName,
|
||||
imagePullPolicy,
|
||||
devfileEndpointsExposure,
|
||||
kubernetesBasedComponentTypes);
|
||||
}
|
||||
|
||||
|
|
@ -115,6 +118,7 @@ public class KubernetesComponentToWorkspaceApplier implements ComponentToWorkspa
|
|||
String defaultPVCAccessMode,
|
||||
String pvcStorageClassName,
|
||||
String imagePullPolicy,
|
||||
String devfileEndpointsExposure,
|
||||
Set<String> kubernetesBasedComponentTypes) {
|
||||
this.objectsParser = objectsParser;
|
||||
this.k8sEnvProvisioner = k8sEnvProvisioner;
|
||||
|
|
@ -126,6 +130,7 @@ public class KubernetesComponentToWorkspaceApplier implements ComponentToWorkspa
|
|||
this.imagePullPolicy = imagePullPolicy;
|
||||
this.kubernetesBasedComponentTypes = kubernetesBasedComponentTypes;
|
||||
this.envVars = envVars;
|
||||
this.devfileEndpointsExposure = devfileEndpointsExposure;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -267,12 +272,8 @@ public class KubernetesComponentToWorkspaceApplier implements ComponentToWorkspa
|
|||
config
|
||||
.getServers()
|
||||
.putAll(
|
||||
component
|
||||
.getEndpoints()
|
||||
.stream()
|
||||
.collect(
|
||||
Collectors.toMap(
|
||||
Endpoint::getName, e -> ServerConfigImpl.createFromEndpoint(e, true))));
|
||||
convertEndpointsIntoServers(
|
||||
component.getEndpoints(), !SINGLE_HOST_STRATEGY.equals(devfileEndpointsExposure)));
|
||||
}
|
||||
|
||||
private void provisionVolumes(
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import static org.eclipse.che.api.workspace.server.devfile.Constants.DOCKERIMAGE
|
|||
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 static org.eclipse.che.workspace.infrastructure.kubernetes.devfile.DockerimageComponentToWorkspaceApplier.CHE_COMPONENT_NAME_LABEL;
|
||||
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 static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
|
@ -80,7 +82,7 @@ public class DockerimageComponentToWorkspaceApplierTest {
|
|||
public void setUp() throws Exception {
|
||||
dockerimageComponentApplier =
|
||||
new DockerimageComponentToWorkspaceApplier(
|
||||
PROJECTS_MOUNT_PATH, "Always", k8sEnvProvisioner);
|
||||
PROJECTS_MOUNT_PATH, "Always", MULTI_HOST_STRATEGY, k8sEnvProvisioner);
|
||||
workspaceConfig = new WorkspaceConfigImpl();
|
||||
}
|
||||
|
||||
|
|
@ -135,7 +137,8 @@ public class DockerimageComponentToWorkspaceApplierTest {
|
|||
dockerimageComponent.setImage("eclipse/ubuntu_jdk8:latest");
|
||||
dockerimageComponent.setMemoryLimit("1G");
|
||||
dockerimageComponentApplier =
|
||||
new DockerimageComponentToWorkspaceApplier(PROJECTS_MOUNT_PATH, "Never", k8sEnvProvisioner);
|
||||
new DockerimageComponentToWorkspaceApplier(
|
||||
PROJECTS_MOUNT_PATH, "Never", MULTI_HOST_STRATEGY, k8sEnvProvisioner);
|
||||
|
||||
// when
|
||||
dockerimageComponentApplier.apply(workspaceConfig, dockerimageComponent, null);
|
||||
|
|
@ -570,6 +573,79 @@ public class DockerimageComponentToWorkspaceApplierTest {
|
|||
assertEquals(container.getArgs(), args);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serverMustHaveRequireSubdomainWhenNonSinglehostDevfileExpose()
|
||||
throws DevfileException {
|
||||
dockerimageComponentApplier =
|
||||
new DockerimageComponentToWorkspaceApplier(
|
||||
PROJECTS_MOUNT_PATH, "Always", MULTI_HOST_STRATEGY, k8sEnvProvisioner);
|
||||
|
||||
// given
|
||||
EndpointImpl endpoint = new EndpointImpl("jdk-ls", 4923, emptyMap());
|
||||
ComponentImpl dockerimageComponent = new ComponentImpl();
|
||||
dockerimageComponent.setAlias("jdk");
|
||||
dockerimageComponent.setType(DOCKERIMAGE_COMPONENT_TYPE);
|
||||
dockerimageComponent.setImage("eclipse/ubuntu_jdk8:latest");
|
||||
dockerimageComponent.setMemoryLimit("100M");
|
||||
dockerimageComponent.setEndpoints(
|
||||
Arrays.asList(
|
||||
new EndpointImpl("e1", 1111, emptyMap()), new EndpointImpl("e2", 2222, emptyMap())));
|
||||
|
||||
// when
|
||||
dockerimageComponentApplier.apply(workspaceConfig, dockerimageComponent, null);
|
||||
|
||||
// then
|
||||
verify(k8sEnvProvisioner)
|
||||
.provision(
|
||||
eq(workspaceConfig),
|
||||
eq(KubernetesEnvironment.TYPE),
|
||||
objectsCaptor.capture(),
|
||||
machinesCaptor.capture());
|
||||
MachineConfigImpl machineConfig = machinesCaptor.getValue().get("jdk");
|
||||
assertNotNull(machineConfig);
|
||||
assertEquals(machineConfig.getServers().size(), 2);
|
||||
assertTrue(
|
||||
ServerConfig.isRequireSubdomain(machineConfig.getServers().get("e1").getAttributes()));
|
||||
assertTrue(
|
||||
ServerConfig.isRequireSubdomain(machineConfig.getServers().get("e2").getAttributes()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serverCantHaveRequireSubdomainWhenSinglehostDevfileExpose() throws DevfileException {
|
||||
dockerimageComponentApplier =
|
||||
new DockerimageComponentToWorkspaceApplier(
|
||||
PROJECTS_MOUNT_PATH, "Always", SINGLE_HOST_STRATEGY, k8sEnvProvisioner);
|
||||
|
||||
// given
|
||||
EndpointImpl endpoint = new EndpointImpl("jdk-ls", 4923, emptyMap());
|
||||
ComponentImpl dockerimageComponent = new ComponentImpl();
|
||||
dockerimageComponent.setAlias("jdk");
|
||||
dockerimageComponent.setType(DOCKERIMAGE_COMPONENT_TYPE);
|
||||
dockerimageComponent.setImage("eclipse/ubuntu_jdk8:latest");
|
||||
dockerimageComponent.setMemoryLimit("100M");
|
||||
dockerimageComponent.setEndpoints(
|
||||
Arrays.asList(
|
||||
new EndpointImpl("e1", 1111, emptyMap()), new EndpointImpl("e2", 2222, emptyMap())));
|
||||
|
||||
// when
|
||||
dockerimageComponentApplier.apply(workspaceConfig, dockerimageComponent, null);
|
||||
|
||||
// then
|
||||
verify(k8sEnvProvisioner)
|
||||
.provision(
|
||||
eq(workspaceConfig),
|
||||
eq(KubernetesEnvironment.TYPE),
|
||||
objectsCaptor.capture(),
|
||||
machinesCaptor.capture());
|
||||
MachineConfigImpl machineConfig = machinesCaptor.getValue().get("jdk");
|
||||
assertNotNull(machineConfig);
|
||||
assertEquals(machineConfig.getServers().size(), 2);
|
||||
assertFalse(
|
||||
ServerConfig.isRequireSubdomain(machineConfig.getServers().get("e1").getAttributes()));
|
||||
assertFalse(
|
||||
ServerConfig.isRequireSubdomain(machineConfig.getServers().get("e2").getAttributes()));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "imageNames")
|
||||
public void testGeneratesValidMachineNameFromImageName(String imageName)
|
||||
throws ValidationException, DevfileException {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import static org.eclipse.che.api.workspace.server.devfile.Constants.COMPONENT_A
|
|||
import static org.eclipse.che.api.workspace.server.devfile.Constants.KUBERNETES_COMPONENT_TYPE;
|
||||
import static org.eclipse.che.api.workspace.server.devfile.Constants.OPENSHIFT_COMPONENT_TYPE;
|
||||
import static org.eclipse.che.api.workspace.shared.Constants.PROJECTS_VOLUME_NAME;
|
||||
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 static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyMap;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
|
|
@ -31,6 +33,7 @@ import static org.mockito.Mockito.doReturn;
|
|||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
|
|
@ -43,6 +46,7 @@ import io.fabric8.kubernetes.api.model.Pod;
|
|||
import io.fabric8.kubernetes.api.model.PodBuilder;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
|
@ -51,6 +55,7 @@ import java.util.Set;
|
|||
import java.util.stream.Stream;
|
||||
import org.eclipse.che.api.core.ValidationException;
|
||||
import org.eclipse.che.api.core.model.workspace.config.MachineConfig;
|
||||
import org.eclipse.che.api.core.model.workspace.config.ServerConfig;
|
||||
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;
|
||||
|
|
@ -110,6 +115,7 @@ public class KubernetesComponentToWorkspaceApplierTest {
|
|||
"ReadWriteOnce",
|
||||
"",
|
||||
"Always",
|
||||
MULTI_HOST_STRATEGY,
|
||||
k8sBasedComponents);
|
||||
|
||||
workspaceConfig = new WorkspaceConfigImpl();
|
||||
|
|
@ -560,6 +566,7 @@ public class KubernetesComponentToWorkspaceApplierTest {
|
|||
"ReadWriteOnce",
|
||||
"",
|
||||
"Never",
|
||||
MULTI_HOST_STRATEGY,
|
||||
k8sBasedComponents);
|
||||
String yamlRecipeContent = getResource("devfile/petclinic.yaml");
|
||||
doReturn(toK8SList(yamlRecipeContent).getItems()).when(k8sRecipeParser).parse(anyString());
|
||||
|
|
@ -693,6 +700,110 @@ public class KubernetesComponentToWorkspaceApplierTest {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serverCantHaveRequireSubdomainWhenSinglehostDevfileExpose()
|
||||
throws DevfileException, IOException, ValidationException, InfrastructureException {
|
||||
applier =
|
||||
new KubernetesComponentToWorkspaceApplier(
|
||||
k8sRecipeParser,
|
||||
k8sEnvProvisioner,
|
||||
envVars,
|
||||
PROJECT_MOUNT_PATH,
|
||||
"1Gi",
|
||||
"ReadWriteOnce",
|
||||
"",
|
||||
"Always",
|
||||
SINGLE_HOST_STRATEGY,
|
||||
k8sBasedComponents);
|
||||
|
||||
String yamlRecipeContent = getResource("devfile/petclinic.yaml");
|
||||
doReturn(toK8SList(yamlRecipeContent).getItems()).when(k8sRecipeParser).parse(anyString());
|
||||
|
||||
// given
|
||||
ComponentImpl component = new ComponentImpl();
|
||||
component.setType(KUBERNETES_COMPONENT_TYPE);
|
||||
component.setReference(REFERENCE_FILENAME);
|
||||
component.setAlias(COMPONENT_NAME);
|
||||
component.setEndpoints(
|
||||
Arrays.asList(
|
||||
new EndpointImpl("e1", 1111, emptyMap()), new EndpointImpl("e2", 2222, 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> machineConfigs = objectsCaptor.getValue();
|
||||
assertEquals(machineConfigs.size(), 4);
|
||||
machineConfigs
|
||||
.values()
|
||||
.forEach(
|
||||
machineConfig -> {
|
||||
assertEquals(machineConfig.getServers().size(), 2);
|
||||
assertFalse(
|
||||
ServerConfig.isRequireSubdomain(
|
||||
machineConfig.getServers().get("e1").getAttributes()));
|
||||
assertFalse(
|
||||
ServerConfig.isRequireSubdomain(
|
||||
machineConfig.getServers().get("e2").getAttributes()));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serverMustHaveRequireSubdomainWhenNonSinglehostDevfileExpose()
|
||||
throws DevfileException, IOException, ValidationException, InfrastructureException {
|
||||
applier =
|
||||
new KubernetesComponentToWorkspaceApplier(
|
||||
k8sRecipeParser,
|
||||
k8sEnvProvisioner,
|
||||
envVars,
|
||||
PROJECT_MOUNT_PATH,
|
||||
"1Gi",
|
||||
"ReadWriteOnce",
|
||||
"",
|
||||
"Always",
|
||||
MULTI_HOST_STRATEGY,
|
||||
k8sBasedComponents);
|
||||
|
||||
String yamlRecipeContent = getResource("devfile/petclinic.yaml");
|
||||
doReturn(toK8SList(yamlRecipeContent).getItems()).when(k8sRecipeParser).parse(anyString());
|
||||
|
||||
// given
|
||||
ComponentImpl component = new ComponentImpl();
|
||||
component.setType(KUBERNETES_COMPONENT_TYPE);
|
||||
component.setReference(REFERENCE_FILENAME);
|
||||
component.setAlias(COMPONENT_NAME);
|
||||
component.setEndpoints(
|
||||
Arrays.asList(
|
||||
new EndpointImpl("e1", 1111, emptyMap()), new EndpointImpl("e2", 2222, 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> machineConfigs = objectsCaptor.getValue();
|
||||
assertEquals(machineConfigs.size(), 4);
|
||||
machineConfigs
|
||||
.values()
|
||||
.forEach(
|
||||
machineConfig -> {
|
||||
assertEquals(machineConfig.getServers().size(), 2);
|
||||
assertTrue(
|
||||
ServerConfig.isRequireSubdomain(
|
||||
machineConfig.getServers().get("e1").getAttributes()));
|
||||
assertTrue(
|
||||
ServerConfig.isRequireSubdomain(
|
||||
machineConfig.getServers().get("e2").getAttributes()));
|
||||
});
|
||||
}
|
||||
|
||||
private KubernetesList toK8SList(String content) {
|
||||
return unmarshal(content, KubernetesList.class);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ public class OpenshiftComponentToWorkspaceApplier extends KubernetesComponentToW
|
|||
@Named("che.infra.kubernetes.pvc.access_mode") String defaultPVCAccessMode,
|
||||
@Named("che.infra.kubernetes.pvc.storage_class_name") String pvcStorageClassName,
|
||||
@Named("che.workspace.sidecar.image_pull_policy") String imagePullPolicy,
|
||||
@Named("che.infra.kubernetes.singlehost.workspace.devfile_endpoint_exposure")
|
||||
String devfileEndpointsExposure,
|
||||
@Named(KUBERNETES_BASED_COMPONENTS_KEY_NAME) Set<String> kubernetesBasedComponentTypes) {
|
||||
super(
|
||||
objectsParser,
|
||||
|
|
@ -44,6 +46,7 @@ public class OpenshiftComponentToWorkspaceApplier extends KubernetesComponentToW
|
|||
defaultPVCAccessMode,
|
||||
pvcStorageClassName,
|
||||
imagePullPolicy,
|
||||
devfileEndpointsExposure,
|
||||
kubernetesBasedComponentTypes);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,27 +11,47 @@
|
|||
*/
|
||||
package org.eclipse.che.workspace.infrastructure.openshift.devfile;
|
||||
|
||||
import static io.fabric8.kubernetes.client.utils.Serialization.unmarshal;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static org.eclipse.che.api.workspace.server.devfile.Constants.KUBERNETES_COMPONENT_TYPE;
|
||||
import static org.eclipse.che.api.workspace.server.devfile.Constants.OPENSHIFT_COMPONENT_TYPE;
|
||||
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 static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.KubernetesList;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.eclipse.che.api.core.ValidationException;
|
||||
import org.eclipse.che.api.core.model.workspace.config.ServerConfig;
|
||||
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.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.spi.InfrastructureException;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.devfile.KubernetesComponentToWorkspaceApplier;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.devfile.KubernetesEnvironmentProvisioner;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesRecipeParser;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.util.EnvVars;
|
||||
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.testng.MockitoTestNGListener;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Listeners;
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.reporters.Files;
|
||||
|
||||
@Listeners(MockitoTestNGListener.class)
|
||||
public class OpenshiftComponentToWorkspaceApplierTest {
|
||||
|
|
@ -59,6 +79,7 @@ public class OpenshiftComponentToWorkspaceApplierTest {
|
|||
"ReadWriteOnce",
|
||||
"",
|
||||
"Always",
|
||||
MULTI_HOST_STRATEGY,
|
||||
k8sBasedComponents);
|
||||
|
||||
workspaceConfig = new WorkspaceConfigImpl();
|
||||
|
|
@ -81,4 +102,120 @@ public class OpenshiftComponentToWorkspaceApplierTest {
|
|||
verify(k8sEnvProvisioner)
|
||||
.provision(workspaceConfig, OpenShiftEnvironment.TYPE, emptyList(), emptyMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serverCantHaveRequireSubdomainWhenSinglehostDevfileExpose()
|
||||
throws DevfileException, IOException, ValidationException, InfrastructureException {
|
||||
Set<String> openshiftBasedComponents = new HashSet<>();
|
||||
openshiftBasedComponents.add(OPENSHIFT_COMPONENT_TYPE);
|
||||
applier =
|
||||
new OpenshiftComponentToWorkspaceApplier(
|
||||
k8sRecipeParser,
|
||||
k8sEnvProvisioner,
|
||||
envVars,
|
||||
"/projects",
|
||||
"1Gi",
|
||||
"ReadWriteOnce",
|
||||
"",
|
||||
"Always",
|
||||
SINGLE_HOST_STRATEGY,
|
||||
openshiftBasedComponents);
|
||||
|
||||
String yamlRecipeContent = getResource("devfile/petclinic.yaml");
|
||||
doReturn(toK8SList(yamlRecipeContent).getItems()).when(k8sRecipeParser).parse(anyString());
|
||||
|
||||
// given
|
||||
ComponentImpl component = new ComponentImpl();
|
||||
component.setType(OPENSHIFT_COMPONENT_TYPE);
|
||||
component.setReference(REFERENCE_FILENAME);
|
||||
component.setAlias(COMPONENT_NAME);
|
||||
component.setEndpoints(
|
||||
Arrays.asList(
|
||||
new EndpointImpl("e1", 1111, emptyMap()), new EndpointImpl("e2", 2222, 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> machineConfigs = objectsCaptor.getValue();
|
||||
assertEquals(machineConfigs.size(), 4);
|
||||
machineConfigs
|
||||
.values()
|
||||
.forEach(
|
||||
machineConfig -> {
|
||||
assertEquals(machineConfig.getServers().size(), 2);
|
||||
assertFalse(
|
||||
ServerConfig.isRequireSubdomain(
|
||||
machineConfig.getServers().get("e1").getAttributes()));
|
||||
assertFalse(
|
||||
ServerConfig.isRequireSubdomain(
|
||||
machineConfig.getServers().get("e2").getAttributes()));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serverMustHaveRequireSubdomainWhenNonSinglehostDevfileExpose()
|
||||
throws DevfileException, IOException, ValidationException, InfrastructureException {
|
||||
Set<String> openshiftBasedComponents = new HashSet<>();
|
||||
openshiftBasedComponents.add(OPENSHIFT_COMPONENT_TYPE);
|
||||
applier =
|
||||
new OpenshiftComponentToWorkspaceApplier(
|
||||
k8sRecipeParser,
|
||||
k8sEnvProvisioner,
|
||||
envVars,
|
||||
"/projects",
|
||||
"1Gi",
|
||||
"ReadWriteOnce",
|
||||
"",
|
||||
"Always",
|
||||
MULTI_HOST_STRATEGY,
|
||||
openshiftBasedComponents);
|
||||
|
||||
String yamlRecipeContent = getResource("devfile/petclinic.yaml");
|
||||
doReturn(toK8SList(yamlRecipeContent).getItems()).when(k8sRecipeParser).parse(anyString());
|
||||
|
||||
// given
|
||||
ComponentImpl component = new ComponentImpl();
|
||||
component.setType(OPENSHIFT_COMPONENT_TYPE);
|
||||
component.setReference(REFERENCE_FILENAME);
|
||||
component.setAlias(COMPONENT_NAME);
|
||||
component.setEndpoints(
|
||||
Arrays.asList(
|
||||
new EndpointImpl("e1", 1111, emptyMap()), new EndpointImpl("e2", 2222, 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> machineConfigs = objectsCaptor.getValue();
|
||||
assertEquals(machineConfigs.size(), 4);
|
||||
machineConfigs
|
||||
.values()
|
||||
.forEach(
|
||||
machineConfig -> {
|
||||
assertEquals(machineConfig.getServers().size(), 2);
|
||||
assertTrue(
|
||||
ServerConfig.isRequireSubdomain(
|
||||
machineConfig.getServers().get("e1").getAttributes()));
|
||||
assertTrue(
|
||||
ServerConfig.isRequireSubdomain(
|
||||
machineConfig.getServers().get("e2").getAttributes()));
|
||||
});
|
||||
}
|
||||
|
||||
private KubernetesList toK8SList(String content) {
|
||||
return unmarshal(content, KubernetesList.class);
|
||||
}
|
||||
|
||||
private String getResource(String resourceName) throws IOException {
|
||||
return Files.readFile(getClass().getClassLoader().getResourceAsStream(resourceName));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,131 @@
|
|||
#
|
||||
# Copyright (c) 2012-2021 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:
|
||||
initContainers:
|
||||
- command:
|
||||
- "echo foo:bar"
|
||||
image: "openjdk:11-jre-openjdk9"
|
||||
name: "init"
|
||||
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
|
||||
volumeMounts:
|
||||
- name: foo_volume
|
||||
mountPath: /foo/bar
|
||||
- kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: mysql
|
||||
labels:
|
||||
app.kubernetes.io/name: mysql
|
||||
app.kubernetes.io/component: database
|
||||
app.kubernetes.io/part-of: petclinic
|
||||
spec:
|
||||
ports:
|
||||
- name: mysql
|
||||
port: 3306
|
||||
targetPort: 3360
|
||||
selector:
|
||||
app.kubernetes.io/name: mysql
|
||||
app.kubernetes.io/component: database
|
||||
app.kubernetes.io/part-of: petclinic
|
||||
- kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: petclinic
|
||||
labels:
|
||||
app.kubernetes.io/name: petclinic
|
||||
app.kubernetes.io/component: webapp
|
||||
app.kubernetes.io/part-of: petclinic
|
||||
spec:
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: petclinic
|
||||
component: webapp
|
||||
- kind: Route
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: petclinic
|
||||
labels:
|
||||
app.kubernetes.io/name: petclinic
|
||||
app.kubernetes.io/component: webapp
|
||||
app.kubernetes.io/part-of: petclinic
|
||||
spec:
|
||||
to:
|
||||
kind: Service
|
||||
name: petclinic
|
||||
port:
|
||||
targetPort: web
|
||||
|
|
@ -11,8 +11,14 @@
|
|||
*/
|
||||
package org.eclipse.che.api.workspace.server.devfile.convert.component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
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.FileContentProvider;
|
||||
import org.eclipse.che.api.workspace.server.devfile.exception.DevfileException;
|
||||
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;
|
||||
|
||||
|
|
@ -41,4 +47,18 @@ public interface ComponentToWorkspaceApplier {
|
|||
ComponentImpl component,
|
||||
FileContentProvider contentProvider)
|
||||
throws DevfileException;
|
||||
|
||||
static Map<String, ServerConfigImpl> convertEndpointsIntoServers(
|
||||
List<? extends Endpoint> endpoints, boolean requireSubdomain) {
|
||||
return endpoints
|
||||
.stream()
|
||||
.collect(
|
||||
Collectors.toMap(
|
||||
Endpoint::getName,
|
||||
e -> {
|
||||
var cfg = ServerConfigImpl.createFromEndpoint(e);
|
||||
ServerConfig.setRequireSubdomain(cfg.getAttributes(), requireSubdomain);
|
||||
return cfg;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ public class ServerConfigImpl implements ServerConfig {
|
|||
+ '}';
|
||||
}
|
||||
|
||||
public static ServerConfigImpl createFromEndpoint(Endpoint endpoint, boolean devfileEndpoint) {
|
||||
public static ServerConfigImpl createFromEndpoint(Endpoint endpoint) {
|
||||
HashMap<String, String> attributes = new HashMap<>(endpoint.getAttributes());
|
||||
attributes.put(SERVER_NAME_ATTRIBUTE, endpoint.getName());
|
||||
|
||||
|
|
@ -196,12 +196,6 @@ public class ServerConfigImpl implements ServerConfig {
|
|||
ServerConfig.setInternal(attributes, true);
|
||||
}
|
||||
|
||||
ServerConfig.setRequireSubdomain(attributes, devfileEndpoint);
|
||||
|
||||
return new ServerConfigImpl(Integer.toString(endpoint.getPort()), protocol, path, attributes);
|
||||
}
|
||||
|
||||
public static ServerConfigImpl createFromEndpoint(Endpoint endpoint) {
|
||||
return createFromEndpoint(endpoint, false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,23 +109,6 @@ public class ServerConfigImplTest {
|
|||
serverConfig.getAttributes().get(INTERNAL_SERVER_ATTRIBUTE), Boolean.TRUE.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFromEndpointDevfileEndpointAttributeSet() {
|
||||
ServerConfig serverConfig =
|
||||
ServerConfigImpl.createFromEndpoint(new EndpointImpl("name", 123, new HashMap<>()), true);
|
||||
|
||||
assertTrue(serverConfig.getAttributes().containsKey(REQUIRE_SUBDOMAIN));
|
||||
assertTrue(Boolean.parseBoolean(serverConfig.getAttributes().get(REQUIRE_SUBDOMAIN)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFromEndpointDevfileEndpointAttributeNotSet() {
|
||||
ServerConfig serverConfig =
|
||||
ServerConfigImpl.createFromEndpoint(new EndpointImpl("name", 123, new HashMap<>()), false);
|
||||
|
||||
assertFalse(serverConfig.getAttributes().containsKey(REQUIRE_SUBDOMAIN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFromEndpointDevfileEndpointAttributeNotSetWhenDefault() {
|
||||
ServerConfig serverConfig =
|
||||
|
|
|
|||
Loading…
Reference in New Issue