Provision environment variables for initContainers of chePlugin/cheEditor (#15508)

Signed-off-by: Sergii Leshchenko <sleshche@redhat.com>
7.20.x
Sergii Leshchenko 2020-02-05 11:08:20 +02:00 committed by GitHub
parent 45604b90ef
commit edb72c2ca0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 80 additions and 33 deletions

View File

@ -35,8 +35,8 @@ public class EnvVars {
* <p>If a container does not have the corresponding env - it will be provisioned, if it has - the
* value will be overridden.
*
* @param podData pod to apply env
* @param env env var to apply
* @param podData pod to supply env vars
* @param env env vars to apply
*/
public void apply(PodData podData, List<? extends Env> env) {
Stream.concat(
@ -45,7 +45,16 @@ public class EnvVars {
.forEach(c -> apply(c, env));
}
private void apply(Container container, List<? extends Env> toApply) {
/**
* Applies the specified env vars list to the specified containers.
*
* <p>If a container does not have the corresponding env - it will be provisioned, if it has - the
* value will be overridden.
*
* @param container pod to supply env vars
* @param toApply env vars to apply
*/
public void apply(Container container, List<? extends Env> toApply) {
List<EnvVar> targetEnv = container.getEnv();
if (targetEnv == null) {
targetEnv = new ArrayList<>();

View File

@ -55,6 +55,7 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.Names;
import org.eclipse.che.workspace.infrastructure.kubernetes.Warnings;
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.util.EnvVars;
/**
* Applies Che plugins tooling configuration to a kubernetes internal runtime object.
@ -75,6 +76,7 @@ public class KubernetesPluginsToolingApplier implements ChePluginsApplier {
private final boolean isAuthEnabled;
private final ProjectsRootEnvVariableProvider projectsRootEnvVariableProvider;
private final ChePluginsVolumeApplier chePluginsVolumeApplier;
private final EnvVars envVars;
@Inject
public KubernetesPluginsToolingApplier(
@ -82,13 +84,15 @@ public class KubernetesPluginsToolingApplier implements ChePluginsApplier {
@Named("che.workspace.sidecar.default_memory_limit_mb") long defaultSidecarMemoryLimitMB,
@Named("che.agents.auth_enabled") boolean isAuthEnabled,
ProjectsRootEnvVariableProvider projectsRootEnvVariableProvider,
ChePluginsVolumeApplier chePluginsVolumeApplier) {
ChePluginsVolumeApplier chePluginsVolumeApplier,
EnvVars envVars) {
this.defaultSidecarMemoryLimitBytes = String.valueOf(defaultSidecarMemoryLimitMB * 1024 * 1024);
this.isAuthEnabled = isAuthEnabled;
this.sidecarImagePullPolicy =
validImagePullPolicies.contains(sidecarImagePullPolicy) ? sidecarImagePullPolicy : null;
this.projectsRootEnvVariableProvider = projectsRootEnvVariableProvider;
this.chePluginsVolumeApplier = chePluginsVolumeApplier;
this.envVars = envVars;
}
@Override
@ -119,12 +123,6 @@ public class KubernetesPluginsToolingApplier implements ChePluginsApplier {
CommandsResolver commandsResolver = new CommandsResolver(k8sEnv);
for (ChePlugin chePlugin : chePlugins) {
for (CheContainer container : chePlugin.getInitContainers()) {
Container k8sInitContainer = toK8sContainer(container);
pod.getSpec().getInitContainers().add(k8sInitContainer);
chePluginsVolumeApplier.applyVolumes(pod, k8sInitContainer, container.getVolumes(), k8sEnv);
}
Map<String, ComponentImpl> devfilePlugins =
k8sEnv
.getDevfile()
@ -141,6 +139,13 @@ public class KubernetesPluginsToolingApplier implements ChePluginsApplier {
}
ComponentImpl pluginRelatedComponent = devfilePlugins.get(chePlugin.getId());
for (CheContainer container : chePlugin.getInitContainers()) {
Container k8sInitContainer = toK8sContainer(container);
envVars.apply(k8sInitContainer, pluginRelatedComponent.getEnv());
chePluginsVolumeApplier.applyVolumes(pod, k8sInitContainer, container.getVolumes(), k8sEnv);
pod.getSpec().getInitContainers().add(k8sInitContainer);
}
Collection<CommandImpl> pluginRelatedCommands = commandsResolver.resolve(chePlugin);
for (CheContainer container : chePlugin.getContainers()) {
@ -237,6 +242,7 @@ public class KubernetesPluginsToolingApplier implements ChePluginsApplier {
List<ChePluginEndpoint> containerEndpoints = k8sContainerResolver.getEndpoints();
Container k8sContainer = k8sContainerResolver.resolve();
envVars.apply(k8sContainer, pluginRelatedComponent.getEnv());
chePluginsVolumeApplier.applyVolumes(pod, k8sContainer, container.getVolumes(), k8sEnv);
String machineName = k8sContainer.getName();

View File

@ -13,6 +13,7 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins;
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.lang.String.format;
import static java.util.Collections.emptyMap;
import static java.util.stream.Collectors.toMap;
import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.DEVFILE_COMPONENT_ALIAS_ATTRIBUTE;
import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE;
@ -23,10 +24,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import org.eclipse.che.api.core.model.workspace.config.ServerConfig;
import org.eclipse.che.api.core.model.workspace.devfile.Component;
import org.eclipse.che.api.core.model.workspace.devfile.Env;
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.spi.InfrastructureException;
@ -67,7 +66,7 @@ public class MachineResolver {
InternalMachineConfig machineConfig =
new InternalMachineConfig(
toServers(containerEndpoints),
component.getEnv().stream().collect(Collectors.toMap(Env::getName, Env::getValue)),
emptyMap(),
resolveMachineAttributes(),
toWorkspaceVolumes(cheContainer));

View File

@ -30,6 +30,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
@ -63,6 +64,7 @@ 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.model.impl.devfile.ComponentImpl;
import org.eclipse.che.api.workspace.server.model.impl.devfile.DevfileImpl;
import org.eclipse.che.api.workspace.server.model.impl.devfile.EnvImpl;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironment;
import org.eclipse.che.api.workspace.server.spi.environment.InternalMachineConfig;
@ -79,6 +81,8 @@ import org.eclipse.che.commons.lang.Pair;
import org.eclipse.che.workspace.infrastructure.kubernetes.Warnings;
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.util.EnvVars;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
@ -108,6 +112,7 @@ public class KubernetesPluginsToolingApplierTest {
@Mock private RuntimeIdentity runtimeIdentity;
@Mock private ProjectsRootEnvVariableProvider projectsRootEnvVariableProvider;
@Mock private ChePluginsVolumeApplier chePluginsVolumeApplier;
@Mock private EnvVars envVars;
private KubernetesEnvironment internalEnvironment;
private KubernetesPluginsToolingApplier applier;
@ -122,7 +127,8 @@ public class KubernetesPluginsToolingApplierTest {
MEMORY_LIMIT_MB,
false,
projectsRootEnvVariableProvider,
chePluginsVolumeApplier);
chePluginsVolumeApplier,
envVars);
Map<String, InternalMachineConfig> machines = new HashMap<>();
List<Container> containers = new ArrayList<>();
@ -168,6 +174,33 @@ public class KubernetesPluginsToolingApplierTest {
validateContainerNameName(envCommand.getAttributes().get(MACHINE_NAME_ATTRIBUTE), "container");
}
@Test
public void shouldProvisionApplyEnvironmentVariableToContainersAndInitContainersOfPlugin()
throws Exception {
// given
CheContainer container = new CheContainer();
container.setName("container");
CheContainer initContainer = new CheContainer();
initContainer.setName("initContainer");
ChePlugin chePlugin =
createChePlugin(
"publisher/id/1.0.0", singletonList(container), singletonList(initContainer));
ComponentImpl component = internalEnvironment.getDevfile().getComponents().get(0);
component.getEnv().add(new EnvImpl("TEST", "VALUE"));
ArgumentCaptor<Container> containerArgumentCaptor = ArgumentCaptor.forClass(Container.class);
// when
applier.apply(runtimeIdentity, internalEnvironment, singletonList(chePlugin));
// then
verify(envVars, times(2)).apply(containerArgumentCaptor.capture(), eq(component.getEnv()));
List<Container> containers = containerArgumentCaptor.getAllValues();
// containers names are suffixed to provide uniqueness and converted to be k8s API compatible
assertTrue(containers.get(0).getName().startsWith("initcontainer"));
assertTrue(containers.get(1).getName().startsWith("container"));
}
@Test(
expectedExceptions = InfrastructureException.class,
expectedExceptionsMessageRegExp =
@ -758,7 +791,8 @@ public class KubernetesPluginsToolingApplierTest {
MEMORY_LIMIT_MB,
true,
projectsRootEnvVariableProvider,
chePluginsVolumeApplier);
chePluginsVolumeApplier,
envVars);
applier.apply(runtimeIdentity, internalEnvironment, singletonList(createChePlugin()));
@ -774,7 +808,8 @@ public class KubernetesPluginsToolingApplierTest {
MEMORY_LIMIT_MB,
true,
projectsRootEnvVariableProvider,
chePluginsVolumeApplier);
chePluginsVolumeApplier,
envVars);
internalEnvironment.getAttributes().put(SECURE_EXPOSER_IMPL_PROPERTY, "somethingElse");
applier.apply(runtimeIdentity, internalEnvironment, singletonList(createChePlugin()));
@ -791,7 +826,8 @@ public class KubernetesPluginsToolingApplierTest {
MEMORY_LIMIT_MB,
true,
projectsRootEnvVariableProvider,
chePluginsVolumeApplier);
chePluginsVolumeApplier,
envVars);
applier.apply(runtimeIdentity, internalEnvironment, singletonList(createChePlugin()));
@ -816,7 +852,8 @@ public class KubernetesPluginsToolingApplierTest {
MEMORY_LIMIT_MB,
true,
projectsRootEnvVariableProvider,
chePluginsVolumeApplier);
chePluginsVolumeApplier,
envVars);
applier.apply(runtimeIdentity, internalEnvironment, singletonList(createChePlugin()));
@ -844,17 +881,26 @@ public class KubernetesPluginsToolingApplierTest {
}
private ChePlugin createChePlugin(CheContainer... containers) {
return createChePlugin("publisher/" + NameGenerator.generate("name", 3) + "/0.0.1", containers);
return createChePlugin(
"publisher/" + NameGenerator.generate("name", 3) + "/0.0.1",
Arrays.asList(containers),
emptyList());
}
private ChePlugin createChePlugin(String id, CheContainer... containers) {
return createChePlugin(id, Arrays.asList(containers), emptyList());
}
private ChePlugin createChePlugin(
String id, List<CheContainer> containers, List<CheContainer> initContainers) {
String[] splittedId = id.split("/");
ChePlugin plugin = new ChePlugin();
plugin.setPublisher(splittedId[0]);
plugin.setName(splittedId[1]);
plugin.setVersion(splittedId[2]);
plugin.setId(id);
plugin.setContainers(Arrays.asList(containers));
plugin.setContainers(containers);
plugin.setInitContainers(initContainers);
internalEnvironment.getDevfile().getComponents().add(new ComponentImpl("chePlugin", id));
return plugin;

View File

@ -25,7 +25,6 @@ import org.eclipse.che.api.core.model.workspace.config.ServerConfig;
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.VolumeImpl;
import org.eclipse.che.api.workspace.server.model.impl.devfile.ComponentImpl;
import org.eclipse.che.api.workspace.server.model.impl.devfile.EnvImpl;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.api.workspace.server.spi.environment.InternalMachineConfig;
import org.eclipse.che.api.workspace.server.wsplugins.model.CheContainer;
@ -164,18 +163,6 @@ public class MachineResolverTest {
assertEquals(machineConfig.getAttributes().get(MEMORY_LIMIT_ATTRIBUTE), expectedMemLimit);
}
@Test
public void
shouldProvisionEnvironmentVarsIntoMachineConfigOfASidecarIfTheyAreSetInTheCorrespondingComponent()
throws InfrastructureException {
component.getEnv().add(new EnvImpl("test", "value"));
InternalMachineConfig machineConfig = resolver.resolve();
assertEquals(machineConfig.getEnv().size(), 1);
assertEquals(machineConfig.getEnv().get("test"), "value");
}
@Test
public void shouldNotSetMemLimitAttributeIfLimitIsInContainer() throws InfrastructureException {
Containers.addRamLimit(container, 123456789);