Support storage classes on Kubernetes infra. (#12818)

Signed-off-by: Masaki Muranaka <monaka@monami-ya.com>
7.20.x
Masaki Muranaka 2019-03-21 15:43:49 +09:00 committed by Sergii Leshchenko
parent 7bf96a8c81
commit b765a5ffb0
8 changed files with 80 additions and 13 deletions

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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,

View File

@ -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();

View File

@ -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