diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties index 819a00a7f5..072ee04623 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties @@ -100,6 +100,12 @@ che.workspace.default_memory_limit_mb=1024 # RAM limit default for each sidecar that has no RAM settings in Che plugin configuration. che.workspace.sidecar.default_memory_limit_mb=128 +# Define image pulling strategy for sidecars. +# Possible values are: Always, Never, IfNotPresent. Any other value +# will be interpreted as unspecified policy (Always if :latest tag is specified, +# or IfNotPresent otherwise.) +che.workspace.sidecar.image_pull_policy=Always + # RAM request default for each machine that has no explicit RAM settings in environment. # this amount will be allocated on workspace container creation # this property might not be supported by all infrastructure implementations: diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/K8sContainerResolver.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/K8sContainerResolver.java index f3ee4a1754..d6a2ea9740 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/K8sContainerResolver.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/K8sContainerResolver.java @@ -40,11 +40,16 @@ public class K8sContainerResolver { static final int MAX_CONTAINER_NAME_LENGTH = 63; // K8S container name limit private final String pluginName; + private final String imagePullPolicy; private final CheContainer cheContainer; private final List containerEndpoints; public K8sContainerResolver( - String pluginName, CheContainer container, List containerEndpoints) { + String pluginName, + String imagePullPolicy, + CheContainer container, + List containerEndpoints) { + this.imagePullPolicy = imagePullPolicy; this.cheContainer = container; this.pluginName = pluginName; this.containerEndpoints = containerEndpoints; @@ -58,6 +63,7 @@ public class K8sContainerResolver { Container container = new ContainerBuilder() .withImage(cheContainer.getImage()) + .withImagePullPolicy(imagePullPolicy) .withName(buildContainerName(pluginName, cheContainer.getName())) .withEnv(toK8sEnv(cheContainer.getEnv())) .withPorts(getContainerPorts()) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/K8sContainerResolverBuilder.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/K8sContainerResolverBuilder.java index 1555ae60d6..b956a4b305 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/K8sContainerResolverBuilder.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/K8sContainerResolverBuilder.java @@ -22,6 +22,7 @@ import org.eclipse.che.api.workspace.server.wsplugins.model.ChePluginEndpoint; public class K8sContainerResolverBuilder { private String pluginName; + private String imagePullPolicy; private CheContainer container; private List pluginEndpoints; @@ -40,13 +41,18 @@ public class K8sContainerResolverBuilder { return this; } + public K8sContainerResolverBuilder setImagePullPolicy(String imagePullPolicy) { + this.imagePullPolicy = imagePullPolicy; + return this; + } + public K8sContainerResolver build() { if (container == null || pluginEndpoints == null) { throw new IllegalStateException(); } List containerEndpoints = getContainerEndpoints(container.getPorts(), pluginEndpoints); - return new K8sContainerResolver(pluginName, container, containerEndpoints); + return new K8sContainerResolver(pluginName, imagePullPolicy, container, containerEndpoints); } private List getContainerEndpoints( diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java index cce98e06aa..46f01eaa50 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java @@ -14,14 +14,17 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins; import static org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactoryProvider.SECURE_EXPOSER_IMPL_PROPERTY; import com.google.common.annotations.Beta; +import com.google.common.collect.Sets; import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.Service; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; import javax.inject.Inject; import javax.inject.Named; +import javax.inject.Singleton; 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; @@ -38,17 +41,24 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.environment.Kubernete * @author Oleksander Garagatyi */ @Beta +@Singleton public class KubernetesPluginsToolingApplier implements ChePluginsApplier { + private static final Set validImagePullPolicies = + Sets.newHashSet("Always", "Never", "IfNotPresent"); private final String defaultSidecarMemoryLimitBytes; + private final String sidecarImagePullPolicy; private final boolean isAuthEnabled; @Inject public KubernetesPluginsToolingApplier( + @Named("che.workspace.sidecar.image_pull_policy") String sidecarImagePullPolicy, @Named("che.workspace.sidecar.default_memory_limit_mb") long defaultSidecarMemoryLimitMB, @Named("che.agents.auth_enabled") boolean isAuthEnabled) { this.defaultSidecarMemoryLimitBytes = String.valueOf(defaultSidecarMemoryLimitMB * 1024 * 1024); this.isAuthEnabled = isAuthEnabled; + this.sidecarImagePullPolicy = + validImagePullPolicies.contains(sidecarImagePullPolicy) ? sidecarImagePullPolicy : null; } @Override @@ -98,6 +108,7 @@ public class KubernetesPluginsToolingApplier implements ChePluginsApplier { K8sContainerResolver k8sContainerResolver = new K8sContainerResolverBuilder() .setContainer(container) + .setImagePullPolicy(sidecarImagePullPolicy) .setPluginName(chePlugin.getName()) .setPluginEndpoints(chePlugin.getEndpoints()) .build(); diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/K8sContainerResolverTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/K8sContainerResolverTest.java index 688daf8d21..3d25ecdf1f 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/K8sContainerResolverTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/K8sContainerResolverTest.java @@ -47,7 +47,7 @@ public class K8sContainerResolverTest { public void setUp() { cheContainer = new CheContainer(); endpoints = new ArrayList<>(); - resolver = new K8sContainerResolver(PLUGIN_NAME, cheContainer, endpoints); + resolver = new K8sContainerResolver(PLUGIN_NAME, "Always", cheContainer, endpoints); } @Test diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplierTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplierTest.java index 13f31871c2..f98e453e54 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplierTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplierTest.java @@ -68,6 +68,7 @@ import org.testng.annotations.Test; @Listeners(MockitoTestNGListener.class) public class KubernetesPluginsToolingApplierTest { private static final String TEST_IMAGE = "testImage/test:test"; + private static final String TEST_IMAGE_POLICY = "IfNotPresent"; private static final String ENV_VAR = "PLUGINS_ENV_VAR"; private static final String ENV_VAR_VALUE = "PLUGINS_ENV_VAR_VALUE"; private static final String POD_NAME = "pod12"; @@ -88,7 +89,7 @@ public class KubernetesPluginsToolingApplierTest { @BeforeMethod public void setUp() { - applier = new KubernetesPluginsToolingApplier(MEMORY_LIMIT_MB, false); + applier = new KubernetesPluginsToolingApplier(TEST_IMAGE_POLICY, MEMORY_LIMIT_MB, false); Map machines = new HashMap<>(); List containers = new ArrayList<>(); @@ -365,7 +366,7 @@ public class KubernetesPluginsToolingApplierTest { @Test public void shouldSetJWTServerExposerAttributeIfAuthEnabled() throws Exception { - applier = new KubernetesPluginsToolingApplier(MEMORY_LIMIT_MB, true); + applier = new KubernetesPluginsToolingApplier(TEST_IMAGE_POLICY, MEMORY_LIMIT_MB, true); applier.apply(internalEnvironment, singletonList(createChePlugin())); @@ -375,7 +376,7 @@ public class KubernetesPluginsToolingApplierTest { @Test public void shouldNotSetJWTServerExposerAttributeIfAuthEnabledButAttributeIsPresent() throws Exception { - applier = new KubernetesPluginsToolingApplier(MEMORY_LIMIT_MB, true); + applier = new KubernetesPluginsToolingApplier(TEST_IMAGE_POLICY, MEMORY_LIMIT_MB, true); internalEnvironment.getAttributes().put(SECURE_EXPOSER_IMPL_PROPERTY, "somethingElse"); applier.apply(internalEnvironment, singletonList(createChePlugin())); @@ -384,6 +385,43 @@ public class KubernetesPluginsToolingApplierTest { internalEnvironment.getAttributes().get(SECURE_EXPOSER_IMPL_PROPERTY), "somethingElse"); } + @Test + public void shouldSetSpecifiedImagePullPolicy() throws Exception { + applier = new KubernetesPluginsToolingApplier(TEST_IMAGE_POLICY, MEMORY_LIMIT_MB, true); + + applier.apply(internalEnvironment, singletonList(createChePlugin())); + + assertEquals( + internalEnvironment + .getPods() + .values() + .iterator() + .next() + .getSpec() + .getContainers() + .get(1) + .getImagePullPolicy(), + TEST_IMAGE_POLICY); + } + + @Test + public void shouldSetNullImagePullPolicyIfValueIsNotStandard() throws Exception { + applier = new KubernetesPluginsToolingApplier("None", MEMORY_LIMIT_MB, true); + + applier.apply(internalEnvironment, singletonList(createChePlugin())); + + assertNull( + internalEnvironment + .getPods() + .values() + .iterator() + .next() + .getSpec() + .getContainers() + .get(1) + .getImagePullPolicy()); + } + @Test public void shouldNotSetJWTServerExposerAttributeIfAuthDisabled() throws Exception { applier.apply(internalEnvironment, singletonList(createChePlugin()));