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 e624e31100ed..0d8e65e1a65f 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 @@ -480,6 +480,12 @@ che.workspace.plugin_registry_url=https://che-plugin-registry.prod-preview.opens # In case Che plugins tooling is not needed value 'NULL' should be used che.workspace.devfile_registry_url=https://che-devfile-registry.prod-preview.openshift.io/ +# Defines a default behaviour if user does not configure persist volumes. +# Possible values: true or false +# In case of false - PersistentVolumeClaims are used by declared volumes by user and plugins. +# In case of true - emptyDir is used instead of PVCs. Note that data will be lost after workspace restart. +che.workspace.persist_volumes=false + # Configures in which way secure servers will be protected with authentication. # Suitable values: # - 'default': no additionally authentication system will be enabled. diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/CommonPVCStrategy.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/CommonPVCStrategy.java index 9b7d9e51dc5c..2a0eedd0c947 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/CommonPVCStrategy.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/CommonPVCStrategy.java @@ -143,7 +143,7 @@ protected PersistentVolumeClaim createCommonPVC(String workspaceId) { public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity) throws InfrastructureException { final String workspaceId = identity.getWorkspaceId(); - if (EphemeralWorkspaceUtility.isEphemeral(k8sEnv.getAttributes())) { + if (ephemeralWorkspaceAdapter.isEphemeral(k8sEnv.getAttributes())) { ephemeralWorkspaceAdapter.provision(k8sEnv, identity); return; } @@ -179,7 +179,7 @@ public void prepare(KubernetesEnvironment k8sEnv, RuntimeIdentity identity, long TracingTags.WORKSPACE_ID.set(workspaceId); - if (EphemeralWorkspaceUtility.isEphemeral(k8sEnv.getAttributes())) { + if (ephemeralWorkspaceAdapter.isEphemeral(k8sEnv.getAttributes())) { return; } @@ -227,7 +227,7 @@ public void prepare(KubernetesEnvironment k8sEnv, RuntimeIdentity identity, long @Override public void cleanup(Workspace workspace) throws InfrastructureException { - if (EphemeralWorkspaceUtility.isEphemeral(workspace)) { + if (ephemeralWorkspaceAdapter.isEphemeral(workspace)) { return; } String workspaceId = workspace.getId(); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/EphemeralWorkspaceAdapter.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/EphemeralWorkspaceAdapter.java index cb747b787ee4..4af05acb4156 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/EphemeralWorkspaceAdapter.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/EphemeralWorkspaceAdapter.java @@ -11,13 +11,19 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc; +import static org.eclipse.che.api.workspace.shared.Constants.CHE_WORKSPACE_PERSIST_VOLUMES_PROPERTY; +import static org.eclipse.che.api.workspace.shared.Constants.PERSIST_VOLUMES_ATTRIBUTE; + import io.fabric8.kubernetes.api.model.EmptyDirVolumeSource; import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; import io.fabric8.kubernetes.api.model.PodSpec; import java.util.HashMap; import java.util.Map; import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Singleton; +import org.eclipse.che.api.core.model.workspace.Workspace; +import org.eclipse.che.api.core.model.workspace.devfile.Devfile; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; @@ -44,11 +50,59 @@ public class EphemeralWorkspaceAdapter { private final PVCProvisioner pvcProvisioner; private final SubPathPrefixes subPathPrefixes; + private final boolean defaultPersistVolumes; @Inject - public EphemeralWorkspaceAdapter(PVCProvisioner pvcProvisioner, SubPathPrefixes subPathPrefixes) { + public EphemeralWorkspaceAdapter( + PVCProvisioner pvcProvisioner, + SubPathPrefixes subPathPrefixes, + @Named(CHE_WORKSPACE_PERSIST_VOLUMES_PROPERTY) boolean defaultPersistVolumes) { this.pvcProvisioner = pvcProvisioner; this.subPathPrefixes = subPathPrefixes; + this.defaultPersistVolumes = defaultPersistVolumes; + } + + /** + * @param workspaceAttributes workspace config or devfile attributes to check is ephemeral mode is + * enabled + * @return true if `persistVolumes` attribute exists and set to 'false'. In this case regardless + * of the PVC strategy, workspace volumes would be created as `emptyDir`. When a workspace Pod + * is removed for any reason, the data in the `emptyDir` volume is deleted forever + */ + public boolean isEphemeral(Map workspaceAttributes) { + String persistVolumes = workspaceAttributes.get(PERSIST_VOLUMES_ATTRIBUTE); + if (persistVolumes == null) { + return !defaultPersistVolumes; + } else { + return !"true".equals(persistVolumes); + } + } + + /** + * @param workspace workspace to check is ephemeral mode is enabled + * @return true if workspace config contains `persistVolumes` attribute which is set to false. In + * this case regardless of the PVC strategy, workspace volumes would be created as `emptyDir`. + * When a workspace Pod is removed for any reason, the data in the `emptyDir` volume is + * deleted forever + */ + public boolean isEphemeral(Workspace workspace) { + Devfile devfile = workspace.getDevfile(); + if (devfile != null) { + return isEphemeral(devfile.getAttributes()); + } + + return isEphemeral(workspace.getConfig().getAttributes()); + } + + /** + * Change workspace attributes such that future calls to {@link #isEphemeral(Map)} will return + * true. + * + * @param workspaceAttributes workspace config or devfile attributes to which ephemeral mode + * configuration should be provisioned + */ + public void makeEphemeral(Map workspaceAttributes) { + workspaceAttributes.put(PERSIST_VOLUMES_ATTRIBUTE, "false"); } public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/EphemeralWorkspaceUtility.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/EphemeralWorkspaceUtility.java deleted file mode 100644 index 977e5e77697d..000000000000 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/EphemeralWorkspaceUtility.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.workspace.infrastructure.kubernetes.namespace.pvc; - -import static org.eclipse.che.api.workspace.shared.Constants.PERSIST_VOLUMES_ATTRIBUTE; - -import java.util.Map; -import org.eclipse.che.api.core.model.workspace.Workspace; -import org.eclipse.che.api.core.model.workspace.devfile.Devfile; - -public class EphemeralWorkspaceUtility { - - /** - * @param workspaceAttributes workspace config or devfile attributes to check is ephemeral mode is - * enabled - * @return true if `persistVolumes` attribute exists and set to 'false'. In this case regardless - * of the PVC strategy, workspace volumes would be created as `emptyDir`. When a workspace Pod - * is removed for any reason, the data in the `emptyDir` volume is deleted forever - */ - public static boolean isEphemeral(Map workspaceAttributes) { - String persistVolumes = workspaceAttributes.get(PERSIST_VOLUMES_ATTRIBUTE); - return "false".equals(persistVolumes); - } - - /** - * @param workspace workspace to check is ephemeral mode is enabled - * @return true if workspace config contains `persistVolumes` attribute which is set to false. In - * this case regardless of the PVC strategy, workspace volumes would be created as `emptyDir`. - * When a workspace Pod is removed for any reason, the data in the `emptyDir` volume is - * deleted forever - */ - public static boolean isEphemeral(Workspace workspace) { - Devfile devfile = workspace.getDevfile(); - if (devfile != null) { - return isEphemeral(devfile.getAttributes()); - } - - return isEphemeral(workspace.getConfig().getAttributes()); - } - - /** - * Change workspace attributes such that future calls to {@link #isEphemeral(Map)} will return - * true. - * - * @param workspaceAttributes workspace config or devfile attributes to which ephemeral mode - * configuration should be provisioned - */ - public static void makeEphemeral(Map workspaceAttributes) { - workspaceAttributes.put(PERSIST_VOLUMES_ATTRIBUTE, "false"); - } -} diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PerWorkspacePVCStrategy.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PerWorkspacePVCStrategy.java index 26951b0e621b..e1ed4b8d82b4 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PerWorkspacePVCStrategy.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PerWorkspacePVCStrategy.java @@ -47,6 +47,7 @@ public class PerWorkspacePVCStrategy extends CommonPVCStrategy { private final String pvcAccessMode; private final String pvcQuantity; private final String pvcStorageClassName; + private final EphemeralWorkspaceAdapter ephemeralWorkspaceAdapter; @Inject public PerWorkspacePVCStrategy( @@ -80,6 +81,7 @@ public PerWorkspacePVCStrategy( this.pvcAccessMode = pvcAccessMode; this.pvcQuantity = pvcQuantity; this.pvcStorageClassName = pvcStorageClassName; + this.ephemeralWorkspaceAdapter = ephemeralWorkspaceAdapter; } @Override @@ -94,7 +96,7 @@ protected PersistentVolumeClaim createCommonPVC(String workspaceId) { @Override public void cleanup(Workspace workspace) throws InfrastructureException { - if (EphemeralWorkspaceUtility.isEphemeral(workspace)) { + if (ephemeralWorkspaceAdapter.isEphemeral(workspace)) { return; } final String workspaceId = workspace.getId(); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategy.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategy.java index 9464f852aeed..043b88bfd2a5 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategy.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategy.java @@ -101,7 +101,7 @@ public UniqueWorkspacePVCStrategy( public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity) throws InfrastructureException { final String workspaceId = identity.getWorkspaceId(); - if (EphemeralWorkspaceUtility.isEphemeral(k8sEnv.getAttributes())) { + if (ephemeralWorkspaceAdapter.isEphemeral(k8sEnv.getAttributes())) { ephemeralWorkspaceAdapter.provision(k8sEnv, identity); return; } @@ -133,7 +133,7 @@ public void prepare(KubernetesEnvironment k8sEnv, RuntimeIdentity identity, long TracingTags.WORKSPACE_ID.set(workspaceId); - if (EphemeralWorkspaceUtility.isEphemeral(k8sEnv.getAttributes())) { + if (ephemeralWorkspaceAdapter.isEphemeral(k8sEnv.getAttributes())) { return; } @@ -158,7 +158,7 @@ public void prepare(KubernetesEnvironment k8sEnv, RuntimeIdentity identity, long @Override public void cleanup(Workspace workspace) throws InfrastructureException { - if (EphemeralWorkspaceUtility.isEphemeral(workspace)) { + if (ephemeralWorkspaceAdapter.isEphemeral(workspace)) { return; } factory diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/PluginBrokerManager.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/PluginBrokerManager.java index 55abb59edd2c..1091017665de 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/PluginBrokerManager.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/PluginBrokerManager.java @@ -28,7 +28,7 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespace; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; -import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.EphemeralWorkspaceUtility; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.EphemeralWorkspaceAdapter; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.WorkspaceVolumesStrategy; import org.eclipse.che.workspace.infrastructure.kubernetes.util.RuntimeEventsPublisher; import org.eclipse.che.workspace.infrastructure.kubernetes.util.UnrecoverablePodEventListenerFactory; @@ -62,6 +62,7 @@ public class PluginBrokerManager { private final KubernetesEnvironmentProvisioner environmentProvisioner; private final UnrecoverablePodEventListenerFactory unrecoverablePodEventListenerFactory; private final RuntimeEventsPublisher runtimeEventsPublisher; + private final EphemeralWorkspaceAdapter ephemeralWorkspaceAdapter; private final Tracer tracer; @Inject @@ -75,6 +76,7 @@ public PluginBrokerManager( UnrecoverablePodEventListenerFactory unrecoverablePodEventListenerFactory, @Named("che.workspace.plugin_broker.wait_timeout_min") int pluginBrokerWaitingTimeout, RuntimeEventsPublisher runtimeEventsPublisher, + EphemeralWorkspaceAdapter ephemeralWorkspaceAdapter, Tracer tracer) { this.factory = factory; this.eventService = eventService; @@ -85,6 +87,7 @@ public PluginBrokerManager( this.pluginBrokerWaitingTimeout = pluginBrokerWaitingTimeout; this.unrecoverablePodEventListenerFactory = unrecoverablePodEventListenerFactory; this.runtimeEventsPublisher = runtimeEventsPublisher; + this.ephemeralWorkspaceAdapter = ephemeralWorkspaceAdapter; this.tracer = tracer; } @@ -109,7 +112,7 @@ public List getTooling( E brokerEnvironment = brokerEnvironmentFactory.createForMetadataBroker(pluginFQNs, identity); if (isEphemeral) { - EphemeralWorkspaceUtility.makeEphemeral(brokerEnvironment.getAttributes()); + ephemeralWorkspaceAdapter.makeEphemeral(brokerEnvironment.getAttributes()); } environmentProvisioner.provision(brokerEnvironment, identity); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/SidecarToolingProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/SidecarToolingProvisioner.java index b70f87e2b036..554927caa966 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/SidecarToolingProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/SidecarToolingProvisioner.java @@ -26,7 +26,7 @@ import org.eclipse.che.commons.annotation.Traced; import org.eclipse.che.workspace.infrastructure.kubernetes.StartSynchronizer; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; -import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.EphemeralWorkspaceUtility; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.EphemeralWorkspaceAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,17 +44,20 @@ public class SidecarToolingProvisioner { private final KubernetesArtifactsBrokerApplier artifactsBrokerApplier; private final PluginFQNParser pluginFQNParser; private final PluginBrokerManager pluginBrokerManager; + private final EphemeralWorkspaceAdapter ephemeralWorkspaceAdapter; @Inject public SidecarToolingProvisioner( Map workspaceNextAppliers, KubernetesArtifactsBrokerApplier artifactsBrokerApplier, PluginFQNParser pluginFQNParser, - PluginBrokerManager pluginBrokerManager) { + PluginBrokerManager pluginBrokerManager, + EphemeralWorkspaceAdapter ephemeralWorkspaceAdapter) { this.workspaceNextAppliers = ImmutableMap.copyOf(workspaceNextAppliers); this.artifactsBrokerApplier = artifactsBrokerApplier; this.pluginFQNParser = pluginFQNParser; this.pluginBrokerManager = pluginBrokerManager; + this.ephemeralWorkspaceAdapter = ephemeralWorkspaceAdapter; } @Traced @@ -75,7 +78,7 @@ public void provision( "Sidecar tooling configuration is not supported with environment type " + recipeType); } - boolean isEphemeral = EphemeralWorkspaceUtility.isEphemeral(environment.getAttributes()); + boolean isEphemeral = ephemeralWorkspaceAdapter.isEphemeral(environment.getAttributes()); List chePlugins = pluginBrokerManager.getTooling(identity, startSynchronizer, pluginFQNs, isEphemeral); diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/SidecarToolingProvisionerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/SidecarToolingProvisionerTest.java index a357a0c12552..8659e7dc13c1 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/SidecarToolingProvisionerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/SidecarToolingProvisionerTest.java @@ -27,7 +27,7 @@ import org.eclipse.che.api.workspace.server.wsplugins.PluginFQNParser; import org.eclipse.che.api.workspace.server.wsplugins.model.PluginFQN; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; -import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.EphemeralWorkspaceUtility; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.EphemeralWorkspaceAdapter; import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.KubernetesArtifactsBrokerApplier; import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.PluginBrokerManager; import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.SidecarToolingProvisioner; @@ -56,6 +56,7 @@ public class SidecarToolingProvisionerTest { @Mock private KubernetesEnvironment ephemeralEnvironment; @Mock private RuntimeIdentity runtimeId; @Mock private ChePluginsApplier chePluginsApplier; + @Mock private EphemeralWorkspaceAdapter ephemeralWorkspaceAdapter; private static Map environmentAttributesBase = ImmutableMap.of( @@ -71,7 +72,6 @@ public void setUp() throws Exception { Map workspaceNextAppliers = ImmutableMap.of(RECIPE_TYPE, chePluginsApplier); Map ephemeralEnvironmentAttributes = new HashMap<>(environmentAttributesBase); - EphemeralWorkspaceUtility.makeEphemeral(ephemeralEnvironmentAttributes); Map nonEphemeralEnvironmentAttributes = new HashMap<>(environmentAttributesBase); @@ -86,7 +86,11 @@ public void setUp() throws Exception { provisioner = new SidecarToolingProvisioner<>( - workspaceNextAppliers, artifactsBrokerApplier, pluginFQNParser, brokerManager); + workspaceNextAppliers, + artifactsBrokerApplier, + pluginFQNParser, + brokerManager, + ephemeralWorkspaceAdapter); } @Test diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/EphemeralWorkspaceAdapterTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/EphemeralWorkspaceAdapterTest.java index 5c133d16a052..01a1b039a6c1 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/EphemeralWorkspaceAdapterTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/EphemeralWorkspaceAdapterTest.java @@ -70,7 +70,8 @@ public class EphemeralWorkspaceAdapterTest { @BeforeMethod public void setup() throws Exception { - ephemeralWorkspaceAdapter = new EphemeralWorkspaceAdapter(pvcProvisioner, subPathPrefixes); + ephemeralWorkspaceAdapter = + new EphemeralWorkspaceAdapter(pvcProvisioner, subPathPrefixes, true); // ephemeral workspace configuration lenient().when(ephemeralWorkspace.getId()).thenReturn(EPHEMERAL_WORKSPACE_ID); @@ -93,8 +94,20 @@ public void setup() throws Exception { @Test public void testIsEphemeralWorkspace() throws Exception { - assertTrue(EphemeralWorkspaceUtility.isEphemeral(ephemeralWorkspace)); - assertFalse(EphemeralWorkspaceUtility.isEphemeral(nonEphemeralWorkspace)); + ephemeralWorkspaceAdapter = + new EphemeralWorkspaceAdapter(pvcProvisioner, subPathPrefixes, true); + + // a little tricky part since attribute indicates whether volumes are persisted while + // method indicates whether workspace is ephemeral + assertFalse( + ephemeralWorkspaceAdapter.isEphemeral(ImmutableMap.of(PERSIST_VOLUMES_ATTRIBUTE, "true"))); + assertTrue( + ephemeralWorkspaceAdapter.isEphemeral(ImmutableMap.of(PERSIST_VOLUMES_ATTRIBUTE, "false"))); + // any string value except true is propagated as false + assertTrue( + ephemeralWorkspaceAdapter.isEphemeral(ImmutableMap.of(PERSIST_VOLUMES_ATTRIBUTE, "any"))); + + assertFalse(ephemeralWorkspaceAdapter.isEphemeral(Collections.emptyMap())); } @Test diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PerWorkspacePVCStrategyTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PerWorkspacePVCStrategyTest.java index c364de6f6516..24bcb99f5f82 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PerWorkspacePVCStrategyTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PerWorkspacePVCStrategyTest.java @@ -12,7 +12,6 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc; import static java.lang.String.format; -import static org.eclipse.che.api.workspace.shared.Constants.PERSIST_VOLUMES_ATTRIBUTE; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_WORKSPACE_ID_LABEL; import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.CommonPVCStrategy.SUBPATHS_PROPERTY_FMT; import static org.mockito.ArgumentMatchers.any; @@ -22,14 +21,13 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNull; import com.google.common.collect.ImmutableMap; import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; import io.fabric8.kubernetes.api.model.PersistentVolumeClaimBuilder; -import java.util.HashMap; -import java.util.Map; import org.eclipse.che.api.core.model.workspace.Workspace; import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; @@ -195,8 +193,7 @@ public void shouldReturnNullStorageClassNameWhenStorageClassNameIsEmptyOrNull() } @Test - public void shouldDeletePVCsIfThereIsNoPersistAttributeInWorkspaceConfigWhenCleanupCalled() - throws Exception { + public void shouldDeletePVCsIfWorkspaceIsNotEphemeralWhenCleanupCalled() throws Exception { // given Workspace workspace = mock(Workspace.class); lenient().when(workspace.getId()).thenReturn(WORKSPACE_ID); @@ -204,19 +201,18 @@ public void shouldDeletePVCsIfThereIsNoPersistAttributeInWorkspaceConfigWhenClea WorkspaceConfig workspaceConfig = mock(WorkspaceConfig.class); lenient().when(workspace.getConfig()).thenReturn(workspaceConfig); - Map workspaceConfigAttributes = new HashMap<>(); - lenient().when(workspaceConfig.getAttributes()).thenReturn(workspaceConfigAttributes); + when(ephemeralWorkspaceAdapter.isEphemeral(any(Workspace.class))).thenReturn(false); // when strategy.cleanup(workspace); // then verify(pvcs).delete(ImmutableMap.of(CHE_WORKSPACE_ID_LABEL, WORKSPACE_ID)); + verify(ephemeralWorkspaceAdapter).isEphemeral(workspace); } @Test - public void shouldDeletePVCsIfPersistAttributeIsSetToTrueInWorkspaceConfigWhenCleanupCalled() - throws Exception { + public void shouldDoNothingIfWorkspaceIsEphemeralWhenCleanupCalled() throws Exception { // given Workspace workspace = mock(Workspace.class); lenient().when(workspace.getId()).thenReturn(WORKSPACE_ID); @@ -224,36 +220,14 @@ public void shouldDeletePVCsIfPersistAttributeIsSetToTrueInWorkspaceConfigWhenCl WorkspaceConfig workspaceConfig = mock(WorkspaceConfig.class); lenient().when(workspace.getConfig()).thenReturn(workspaceConfig); - Map workspaceConfigAttributes = new HashMap<>(); - lenient().when(workspaceConfig.getAttributes()).thenReturn(workspaceConfigAttributes); - workspaceConfigAttributes.put(PERSIST_VOLUMES_ATTRIBUTE, "true"); - - // when - strategy.cleanup(workspace); - - // then - verify(pvcs).delete(ImmutableMap.of(CHE_WORKSPACE_ID_LABEL, WORKSPACE_ID)); - } - - @Test - public void shouldDoNothingIfPersistAttributeIsSetToFalseInWorkspaceConfigWhenCleanupCalled() - throws Exception { - // given - Workspace workspace = mock(Workspace.class); - lenient().when(workspace.getId()).thenReturn(WORKSPACE_ID); - - WorkspaceConfig workspaceConfig = mock(WorkspaceConfig.class); - lenient().when(workspace.getConfig()).thenReturn(workspaceConfig); - - Map workspaceConfigAttributes = new HashMap<>(); - lenient().when(workspaceConfig.getAttributes()).thenReturn(workspaceConfigAttributes); - workspaceConfigAttributes.put(PERSIST_VOLUMES_ATTRIBUTE, "false"); + when(ephemeralWorkspaceAdapter.isEphemeral(any(Workspace.class))).thenReturn(true); // when strategy.cleanup(workspace); // then verify(pvcs, never()).delete(ImmutableMap.of(CHE_WORKSPACE_ID_LABEL, WORKSPACE_ID)); + verify(ephemeralWorkspaceAdapter).isEphemeral(workspace); } private static PersistentVolumeClaim newPVC(String name) { diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategyTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategyTest.java index 586c6c2b044c..8f86d0fbb086 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategyTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategyTest.java @@ -13,7 +13,6 @@ import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; -import static org.eclipse.che.api.workspace.shared.Constants.PERSIST_VOLUMES_ATTRIBUTE; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_WORKSPACE_ID_LABEL; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; @@ -192,8 +191,7 @@ public void throwsInfrastructureExceptionWhenFailedToCreatePVCs() throws Excepti } @Test - public void shouldDeletePVCsIfThereIsNoPersistAttributeInWorkspaceConfigWhenCleanupCalled() - throws Exception { + public void shouldDeletePVCsIfWorkspaceIsNotEphemeralWhenCleanupCalled() throws Exception { // given Workspace workspace = mock(Workspace.class); lenient().when(workspace.getId()).thenReturn(WORKSPACE_ID); @@ -201,40 +199,18 @@ public void shouldDeletePVCsIfThereIsNoPersistAttributeInWorkspaceConfigWhenClea WorkspaceConfig workspaceConfig = mock(WorkspaceConfig.class); lenient().when(workspace.getConfig()).thenReturn(workspaceConfig); - Map workspaceConfigAttributes = new HashMap<>(); - lenient().when(workspaceConfig.getAttributes()).thenReturn(workspaceConfigAttributes); - - // when - strategy.cleanup(workspace); - - // then - verify(pvcs).delete(ImmutableMap.of(CHE_WORKSPACE_ID_LABEL, WORKSPACE_ID)); - } - - @Test - public void shouldDeletePVCsIfPersistAttributeIsSetToTrueInWorkspaceConfigWhenCleanupCalled() - throws Exception { - // given - Workspace workspace = mock(Workspace.class); - lenient().when(workspace.getId()).thenReturn(WORKSPACE_ID); - - WorkspaceConfig workspaceConfig = mock(WorkspaceConfig.class); - lenient().when(workspace.getConfig()).thenReturn(workspaceConfig); - - Map workspaceConfigAttributes = new HashMap<>(); - lenient().when(workspaceConfig.getAttributes()).thenReturn(workspaceConfigAttributes); - workspaceConfigAttributes.put(PERSIST_VOLUMES_ATTRIBUTE, "true"); + when(ephemeralWorkspaceAdapter.isEphemeral(any(Workspace.class))).thenReturn(false); // when strategy.cleanup(workspace); // then verify(pvcs).delete(any()); + verify(ephemeralWorkspaceAdapter).isEphemeral(workspace); } @Test - public void shouldDoNothingIfPersistAttributeIsSetToFalseInWorkspaceConfigWhenCleanupCalled() - throws Exception { + public void shouldDoNothingIfWorkspaceIsEphemeralWhenCleanupCalled() throws Exception { // given Workspace workspace = mock(Workspace.class); lenient().when(workspace.getId()).thenReturn(WORKSPACE_ID); @@ -242,15 +218,14 @@ public void shouldDoNothingIfPersistAttributeIsSetToFalseInWorkspaceConfigWhenCl WorkspaceConfig workspaceConfig = mock(WorkspaceConfig.class); lenient().when(workspace.getConfig()).thenReturn(workspaceConfig); - Map workspaceConfigAttributes = new HashMap<>(); - lenient().when(workspaceConfig.getAttributes()).thenReturn(workspaceConfigAttributes); - workspaceConfigAttributes.put(PERSIST_VOLUMES_ATTRIBUTE, "false"); + when(ephemeralWorkspaceAdapter.isEphemeral(any(Workspace.class))).thenReturn(true); // when strategy.cleanup(workspace); // then verify(pvcs, never()).delete(any()); + verify(ephemeralWorkspaceAdapter).isEphemeral(workspace); } static PersistentVolumeClaim newPVC(String name) { diff --git a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/Constants.java b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/Constants.java index 664dd3685604..359d9eedae35 100644 --- a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/Constants.java +++ b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/Constants.java @@ -37,6 +37,20 @@ public final class Constants { public static final String CHE_WORKSPACE_AUTO_START = "che.workspace.auto_start"; + /** + * The configuration property that defined default value for persist volumes. Users are able to + * configure the values for their workspaces via Devfile attribute. + */ + public static final String CHE_WORKSPACE_PERSIST_VOLUMES_PROPERTY = + "che.workspace.persist_volumes"; + + /** + * The settings parameter that exposes value of {@link #CHE_WORKSPACE_PERSIST_VOLUMES_PROPERTY} to + * be consumed by clients. + */ + public static final String CHE_WORKSPACE_PERSIST_VOLUMES_SETTING = + "cheWorkspacesDefaultPersistVolumes"; + /** Property name for Che plugin registry url. */ public static final String CHE_WORKSPACE_PLUGIN_REGISTRY_URL_PROPERTY = "che.workspace.plugin_registry_url"; diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java index 13ad9a8410af..387323987dbf 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java @@ -21,6 +21,8 @@ import static org.eclipse.che.api.workspace.server.WorkspaceKeyValidator.validateKey; import static org.eclipse.che.api.workspace.shared.Constants.CHE_WORKSPACE_AUTO_START; import static org.eclipse.che.api.workspace.shared.Constants.CHE_WORKSPACE_DEVFILE_REGISTRY_URL_PROPERTY; +import static org.eclipse.che.api.workspace.shared.Constants.CHE_WORKSPACE_PERSIST_VOLUMES_PROPERTY; +import static org.eclipse.che.api.workspace.shared.Constants.CHE_WORKSPACE_PERSIST_VOLUMES_SETTING; import static org.eclipse.che.api.workspace.shared.Constants.CHE_WORKSPACE_PLUGIN_REGISTRY_URL_PROPERTY; import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_INFRASTRUCTURE_NAMESPACE_ATTRIBUTE; @@ -118,7 +120,7 @@ public WorkspaceService( WorkspaceLinksGenerator linksGenerator, @Named(CHE_WORKSPACE_PLUGIN_REGISTRY_URL_PROPERTY) @Nullable String pluginRegistryUrl, @Named(CHE_WORKSPACE_DEVFILE_REGISTRY_URL_PROPERTY) @Nullable String devfileRegistryUrl, - @Named("che.infra.kubernetes.pvc.enabled") boolean defaultPersistVolumes, + @Named(CHE_WORKSPACE_PERSIST_VOLUMES_PROPERTY) boolean defaultPersistVolumes, URLFetcher urlFetcher) { this.apiEndpoint = apiEndpoint; this.cheWorkspaceAutoStart = cheWorkspaceAutoStart; @@ -832,7 +834,7 @@ public Map getSettings() { settings.put("cheWorkspaceDevfileRegistryUrl", devfileRegistryUrl); } - settings.put("cheWorkspacesDefaultPersistVolumes", Boolean.toString(defaultPersistVolumes)); + settings.put(CHE_WORKSPACE_PERSIST_VOLUMES_SETTING, Boolean.toString(defaultPersistVolumes)); return settings.build(); }