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 055592dbda..b7d26b3a1e 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 @@ -430,6 +430,10 @@ che.infra.kubernetes.pvc.precreate_subpaths=true # Defines the name of Persistent Volume Claim for che workspaces. che.infra.kubernetes.pvc.name=claim-che-workspace +# Defines the storage class of Persistent Volume Claim for the workspaces. +# Empty strings means "use default". +che.infra.kubernetes.pvc.storage_class_name= + # Defines the size of Persistent Volume Claim of che workspace. # Format described here: # https://docs.openshift.com/container-platform/latest/dev_guide/compute_resources.html#dev-compute-resources diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesObjectUtil.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesObjectUtil.java index 4d6b696499..931d9fc5f1 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesObjectUtil.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesObjectUtil.java @@ -11,11 +11,14 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace; +import static com.google.common.base.Strings.isNullOrEmpty; + import com.google.common.collect.ImmutableMap; import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; import io.fabric8.kubernetes.api.model.PersistentVolumeClaimBuilder; +import io.fabric8.kubernetes.api.model.PersistentVolumeClaimFluent.SpecNested; import io.fabric8.kubernetes.api.model.PersistentVolumeClaimVolumeSource; import io.fabric8.kubernetes.api.model.PersistentVolumeClaimVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.Quantity; @@ -109,12 +112,26 @@ public class KubernetesObjectUtil { * quantity. */ public static PersistentVolumeClaim newPVC(String name, String accessMode, String quantity) { - return new PersistentVolumeClaimBuilder() - .withNewMetadata() - .withName(name) - .endMetadata() - .withNewSpec() - .withAccessModes(accessMode) + return newPVC(name, accessMode, quantity, null); + } + + /** + * Returns new instance of {@link PersistentVolumeClaim} with specified name, accessMode, quantity + * and storageClassName. + */ + public static PersistentVolumeClaim newPVC( + String name, String accessMode, String quantity, String storageClassName) { + SpecNested specs = + new PersistentVolumeClaimBuilder() + .withNewMetadata() + .withName(name) + .endMetadata() + .withNewSpec() + .withAccessModes(accessMode); + if (!isNullOrEmpty(storageClassName)) { + specs.withStorageClassName(storageClassName); + } + return specs .withNewResources() .withRequests(ImmutableMap.of(STORAGE_PARAM, new Quantity(quantity))) .endResources() 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 d677cc856a..f1b111974d 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 @@ -88,6 +88,7 @@ public class CommonPVCStrategy implements WorkspaceVolumesStrategy { private final String pvcQuantity; private final String configuredPVCName; private final String pvcAccessMode; + private final String pvcStorageClassName; private final PVCSubPathHelper pvcSubPathHelper; private final KubernetesNamespaceFactory factory; private final EphemeralWorkspaceAdapter ephemeralWorkspaceAdapter; @@ -101,6 +102,7 @@ public class CommonPVCStrategy implements WorkspaceVolumesStrategy { @Named("che.infra.kubernetes.pvc.quantity") String pvcQuantity, @Named("che.infra.kubernetes.pvc.access_mode") String pvcAccessMode, @Named("che.infra.kubernetes.pvc.precreate_subpaths") boolean preCreateDirs, + @Named("che.infra.kubernetes.pvc.storage_class_name") String pvcStorageClassName, PVCSubPathHelper pvcSubPathHelper, KubernetesNamespaceFactory factory, EphemeralWorkspaceAdapter ephemeralWorkspaceAdapter, @@ -111,6 +113,7 @@ public class CommonPVCStrategy implements WorkspaceVolumesStrategy { this.pvcQuantity = pvcQuantity; this.pvcAccessMode = pvcAccessMode; this.preCreateDirs = preCreateDirs; + this.pvcStorageClassName = pvcStorageClassName; this.pvcSubPathHelper = pvcSubPathHelper; this.factory = factory; this.ephemeralWorkspaceAdapter = ephemeralWorkspaceAdapter; @@ -129,7 +132,7 @@ public class CommonPVCStrategy implements WorkspaceVolumesStrategy { * @return pvc that should be used for the specified runtime identity */ protected PersistentVolumeClaim createCommonPVC(String workspaceId) { - return newPVC(configuredPVCName, pvcAccessMode, pvcQuantity); + return newPVC(configuredPVCName, pvcAccessMode, pvcQuantity, pvcStorageClassName); } @Override diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCProvisioner.java index 285b23ce3c..d590787540 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCProvisioner.java @@ -48,8 +48,9 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.environment.Kubernete public class PVCProvisioner { private final String pvcNamePrefix; - private final String pvcAccessMode; private final String pvcQuantity; + private final String pvcAccessMode; + private final String pvcStorageClassName; private final PodsVolumes podsVolumes; @Inject @@ -57,10 +58,12 @@ public class PVCProvisioner { @Named("che.infra.kubernetes.pvc.name") String pvcNamePrefix, @Named("che.infra.kubernetes.pvc.quantity") String pvcQuantity, @Named("che.infra.kubernetes.pvc.access_mode") String pvcAccessMode, + @Named("che.infra.kubernetes.pvc.storage_class_name") String pvcStorageClassName, PodsVolumes podsVolumes) { - this.pvcAccessMode = pvcAccessMode; - this.pvcQuantity = pvcQuantity; this.pvcNamePrefix = pvcNamePrefix; + this.pvcQuantity = pvcQuantity; + this.pvcAccessMode = pvcAccessMode; + this.pvcStorageClassName = pvcStorageClassName; this.podsVolumes = podsVolumes; } @@ -181,7 +184,7 @@ public class PVCProvisioner { // when PVC is not found in environment then create new one else { final String uniqueName = Names.generateName(pvcNamePrefix); - pvc = newPVC(uniqueName, pvcAccessMode, pvcQuantity); + pvc = newPVC(uniqueName, pvcAccessMode, pvcQuantity, pvcStorageClassName); putLabel(pvc, CHE_WORKSPACE_ID_LABEL, workspaceId); putLabel(pvc, CHE_VOLUME_NAME_LABEL, volumeName); k8sEnv.getPersistentVolumeClaims().put(uniqueName, pvc); 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 dc04a9855c..2966d787e2 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 @@ -46,6 +46,7 @@ public class PerWorkspacePVCStrategy extends CommonPVCStrategy { private final String pvcNamePrefix; private final String pvcAccessMode; private final String pvcQuantity; + private final String pvcStorageClassName; @Inject public PerWorkspacePVCStrategy( @@ -53,6 +54,7 @@ public class PerWorkspacePVCStrategy extends CommonPVCStrategy { @Named("che.infra.kubernetes.pvc.quantity") String pvcQuantity, @Named("che.infra.kubernetes.pvc.access_mode") String pvcAccessMode, @Named("che.infra.kubernetes.pvc.precreate_subpaths") boolean preCreateDirs, + @Named("che.infra.kubernetes.pvc.storage_class_name") String pvcStorageClassName, PVCSubPathHelper pvcSubPathHelper, KubernetesNamespaceFactory factory, EphemeralWorkspaceAdapter ephemeralWorkspaceAdapter, @@ -64,6 +66,7 @@ public class PerWorkspacePVCStrategy extends CommonPVCStrategy { pvcQuantity, pvcAccessMode, preCreateDirs, + pvcStorageClassName, pvcSubPathHelper, factory, ephemeralWorkspaceAdapter, @@ -74,13 +77,15 @@ public class PerWorkspacePVCStrategy extends CommonPVCStrategy { this.factory = factory; this.pvcAccessMode = pvcAccessMode; this.pvcQuantity = pvcQuantity; + this.pvcStorageClassName = pvcStorageClassName; } @Override protected PersistentVolumeClaim createCommonPVC(String workspaceId) { String pvcName = pvcNamePrefix + '-' + workspaceId; - PersistentVolumeClaim perWorkspacePVC = newPVC(pvcName, pvcAccessMode, pvcQuantity); + PersistentVolumeClaim perWorkspacePVC = + newPVC(pvcName, pvcAccessMode, pvcQuantity, pvcStorageClassName); perWorkspacePVC.getMetadata().getLabels().put(CHE_WORKSPACE_ID_LABEL, workspaceId); return perWorkspacePVC; } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/CommonPVCStrategyTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/CommonPVCStrategyTest.java index 6b0d79525b..2130e6bd3d 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/CommonPVCStrategyTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/CommonPVCStrategyTest.java @@ -68,6 +68,7 @@ public class CommonPVCStrategyTest { private static final String PVC_QUANTITY = "10Gi"; private static final String PVC_ACCESS_MODE = "RWO"; + private static final String PVC_STORAGE_CLASS_NAME = "special"; private static final String[] WORKSPACE_SUBPATHS = {"/projects", "/logs"}; @@ -99,6 +100,7 @@ public class CommonPVCStrategyTest { PVC_QUANTITY, PVC_ACCESS_MODE, true, + PVC_STORAGE_CLASS_NAME, pvcSubPathHelper, factory, ephemeralWorkspaceAdapter, @@ -163,6 +165,7 @@ public class CommonPVCStrategyTest { PVC_QUANTITY, PVC_ACCESS_MODE, false, + PVC_STORAGE_CLASS_NAME, pvcSubPathHelper, factory, ephemeralWorkspaceAdapter, diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCProvisionerTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCProvisionerTest.java index d4b74a6a5e..b9663364c2 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCProvisionerTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCProvisionerTest.java @@ -63,6 +63,7 @@ public class PVCProvisionerTest { private static final String PVC_QUANTITY = "10Gi"; private static final String PVC_ACCESS_MODE = "RWO"; + private static final String PVC_STORAGE_CLASS_NAME = "default"; private static final RuntimeIdentity IDENTITY = new RuntimeIdentityImpl(WORKSPACE_ID, "env1", "id1"); @@ -77,7 +78,9 @@ public class PVCProvisionerTest { @BeforeMethod public void setUp() { - provisioner = new PVCProvisioner(PVC_NAME_PREFIX, PVC_QUANTITY, PVC_ACCESS_MODE, podsVolumes); + provisioner = + new PVCProvisioner( + PVC_NAME_PREFIX, PVC_QUANTITY, PVC_ACCESS_MODE, PVC_STORAGE_CLASS_NAME, podsVolumes); k8sEnv = KubernetesEnvironment.builder().build(); 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 eb54f19801..8f79046dd4 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 @@ -20,6 +20,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; 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; @@ -51,6 +52,7 @@ public class PerWorkspacePVCStrategyTest { private static final String PVC_QUANTITY = "10Gi"; private static final String PVC_ACCESS_MODE = "RWO"; + private static final String PVC_STORAGE_CLASS_NAME = "special"; @Mock private PVCSubPathHelper pvcSubPathHelper; @Mock private KubernetesNamespaceFactory factory; @@ -72,6 +74,7 @@ public class PerWorkspacePVCStrategyTest { PVC_QUANTITY, PVC_ACCESS_MODE, true, + PVC_STORAGE_CLASS_NAME, pvcSubPathHelper, factory, ephemeralWorkspaceAdapter, @@ -113,6 +116,32 @@ public class PerWorkspacePVCStrategyTest { // then assertEquals(commonPVC.getMetadata().getName(), PVC_NAME_PREFIX + "-" + WORKSPACE_ID); assertEquals(commonPVC.getMetadata().getLabels().get(CHE_WORKSPACE_ID_LABEL), WORKSPACE_ID); + assertEquals(commonPVC.getSpec().getStorageClassName(), PVC_STORAGE_CLASS_NAME); + } + + @Test + public void shouldReturnNullStorageClassNameWhenStorageClassNameIsEmptyOrNull() throws Exception { + String[] storageClassNames = {"", null}; + + for (String storageClassName : storageClassNames) { + final PerWorkspacePVCStrategy strategy = + new PerWorkspacePVCStrategy( + PVC_NAME_PREFIX, + PVC_QUANTITY, + PVC_ACCESS_MODE, + true, + storageClassName, + pvcSubPathHelper, + factory, + ephemeralWorkspaceAdapter, + volumeConverter, + podsVolumes, + subpathPrefixes); + + final PersistentVolumeClaim commonPVC = strategy.createCommonPVC(WORKSPACE_ID); + + assertNull(commonPVC.getSpec().getStorageClassName()); + } } @Test