Support storage classes on Kubernetes infra. (#12818)
Signed-off-by: Masaki Muranaka <monaka@monami-ya.com>7.20.x
parent
7bf96a8c81
commit
b765a5ffb0
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<PersistentVolumeClaimBuilder> 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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue