remove che.infra.kubernetes.pvc.name and che.infra.kubernetes.pvc.quantity properties

Signed-off-by: Andrew Obuchowicz <aobuchow@redhat.com>
pull/344/head
Andrew Obuchowicz 2022-07-27 14:48:46 -04:00 committed by Ilya Buziuk
parent 97b7431bda
commit 18c12861a0
13 changed files with 18 additions and 1566 deletions

View File

@ -415,18 +415,13 @@ che.infra.kubernetes.pvc.strategy=common
# the {prod-short} Operator that this property has effect only if the `common` PVC strategy used.
che.infra.kubernetes.pvc.precreate_subpaths=true
# Defines the settings of PVC name for {prod-short} workspaces.
# Each PVC strategy supplies this value differently.
# See documentation for `che.infra.kubernetes.pvc.strategy` property
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 {prod-short} workspace.
# See: link:https://docs.openshift.com/container-platform/4.4/storage/understanding-persistent-storage.html[Understanding persistent storage]
che.infra.kubernetes.pvc.quantity=10Gi
# Pod that is launched when performing persistent volume claim maintenance jobs on OpenShift
che.infra.kubernetes.pvc.jobs.image=registry.access.redhat.com/ubi8-minimal:8.3-230

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2012-2021 Red Hat, Inc.
# Copyright (c) 2012-2022 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/
@ -20,8 +20,6 @@ che.infra.kubernetes.bootstrapper.server_check_period_sec=che.infra.openshift.bo
che.infra.kubernetes.pvc.enabled=che.infra.openshift.pvc.enabled
che.infra.kubernetes.pvc.strategy=che.infra.openshift.pvc.strategy
che.infra.kubernetes.pvc.precreate_subpaths=che.infra.openshift.pvc.precreate_subpaths
che.infra.kubernetes.pvc.name=che.infra.openshift.pvc.name
che.infra.kubernetes.pvc.quantity=che.infra.openshift.pvc.quantity
che.infra.kubernetes.pvc.jobs.image=che.infra.openshift.pvc.jobs.image
che.infra.kubernetes.pvc.jobs.memorylimit=che.infra.openshift.pvc.jobs.memorylimit
che.infra.kubernetes.pvc.access_mode=che.infra.openshift.pvc.access_mode

View File

@ -14,9 +14,6 @@ package org.eclipse.che.workspace.infrastructure.kubernetes;
import static com.google.inject.name.Names.named;
import static org.eclipse.che.api.workspace.server.devfile.Constants.DOCKERIMAGE_COMPONENT_TYPE;
import static org.eclipse.che.api.workspace.server.devfile.Constants.KUBERNETES_COMPONENT_TYPE;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.CommonPVCStrategy.COMMON_STRATEGY;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.PerWorkspacePVCStrategy.PER_WORKSPACE_STRATEGY;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.UniqueWorkspacePVCStrategy.UNIQUE_STRATEGY;
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.DefaultHostExternalServiceExposureStrategy.DEFAULT_HOST_STRATEGY;
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.MultiHostExternalServiceExposureStrategy.MULTI_HOST_STRATEGY;
import static org.eclipse.che.workspace.infrastructure.kubernetes.server.external.SingleHostExternalServiceExposureStrategy.SINGLE_HOST_STRATEGY;
@ -57,12 +54,7 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurato
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserPreferencesConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserProfileConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.WorkspaceServiceAccountConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.CommonPVCStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.PerWorkspacePVCStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.UniqueWorkspacePVCStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.WorkspacePVCCleaner;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.WorkspaceVolumeStrategyProvider;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.WorkspaceVolumesStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.AsyncStorageProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.GatewayTlsProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.IngressTlsProvisioner;
@ -160,13 +152,6 @@ public class KubernetesInfraModule extends AbstractModule {
bind(CheApiInternalEnvVarProvider.class).to(KubernetesCheApiInternalEnvVarProvider.class);
bind(CheApiExternalEnvVarProvider.class).to(KubernetesCheApiExternalEnvVarProvider.class);
MapBinder<String, WorkspaceVolumesStrategy> volumesStrategies =
MapBinder.newMapBinder(binder(), String.class, WorkspaceVolumesStrategy.class);
volumesStrategies.addBinding(COMMON_STRATEGY).to(CommonPVCStrategy.class);
volumesStrategies.addBinding(PER_WORKSPACE_STRATEGY).to(PerWorkspacePVCStrategy.class);
volumesStrategies.addBinding(UNIQUE_STRATEGY).to(UniqueWorkspacePVCStrategy.class);
bind(WorkspaceVolumesStrategy.class).toProvider(WorkspaceVolumeStrategyProvider.class);
Multibinder.newSetBinder(binder(), ServiceTermination.class)
.addBinding()
.to(KubernetesClientTermination.class);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* Copyright (c) 2012-2022 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/
@ -105,8 +105,6 @@ public class CommonPVCStrategy implements WorkspaceVolumesStrategy {
@Inject
public CommonPVCStrategy(
@Named("che.infra.kubernetes.pvc.name") String configuredPVCName,
@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,
@ -118,8 +116,8 @@ public class CommonPVCStrategy implements WorkspaceVolumesStrategy {
PodsVolumes podsVolumes,
SubPathPrefixes subpathPrefixes,
WorkspaceManager workspaceManager) {
this.configuredPVCName = configuredPVCName;
this.pvcQuantity = pvcQuantity;
this.configuredPVCName = "test";
this.pvcQuantity = "test";
this.pvcAccessMode = pvcAccessMode;
this.preCreateDirs = preCreateDirs;
this.pvcStorageClassName = pvcStorageClassName;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* Copyright (c) 2012-2022 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/
@ -55,13 +55,11 @@ public class PVCProvisioner {
@Inject
public 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.pvcNamePrefix = pvcNamePrefix;
this.pvcQuantity = pvcQuantity;
this.pvcNamePrefix = "TEST";
this.pvcQuantity = "test";
this.pvcAccessMode = pvcAccessMode;
this.pvcStorageClassName = pvcStorageClassName;
this.podsVolumes = podsVolumes;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* Copyright (c) 2012-2022 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/
@ -52,8 +52,6 @@ public class PerWorkspacePVCStrategy extends CommonPVCStrategy {
@Inject
public PerWorkspacePVCStrategy(
@Named("che.infra.kubernetes.pvc.name") String pvcName,
@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,
@ -66,8 +64,6 @@ public class PerWorkspacePVCStrategy extends CommonPVCStrategy {
SubPathPrefixes subpathPrefixes,
WorkspaceManager workspaceManager) {
super(
pvcName,
pvcQuantity,
pvcAccessMode,
preCreateDirs,
pvcStorageClassName,
@ -79,10 +75,10 @@ public class PerWorkspacePVCStrategy extends CommonPVCStrategy {
podsVolumes,
subpathPrefixes,
workspaceManager);
this.pvcNamePrefix = pvcName;
this.pvcNamePrefix = "TEST";
this.factory = factory;
this.pvcAccessMode = pvcAccessMode;
this.pvcQuantity = pvcQuantity;
this.pvcQuantity = "test";
this.pvcStorageClassName = pvcStorageClassName;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* Copyright (c) 2012-2022 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/
@ -127,20 +127,18 @@ public class AsyncStorageProvisioner {
@Inject
public AsyncStorageProvisioner(
@Named("che.workspace.sidecar.image_pull_policy") String sidecarImagePullPolicy,
@Named("che.infra.kubernetes.pvc.quantity") String pvcQuantity,
@Named("che.infra.kubernetes.async.storage.image") String asyncStorageImage,
@Named("che.infra.kubernetes.pvc.access_mode") String pvcAccessMode,
@Named("che.infra.kubernetes.pvc.strategy") String pvcStrategy,
@Named("che.infra.kubernetes.pvc.name") String pvcName,
@Named("che.infra.kubernetes.pvc.storage_class_name") String pvcStorageClassName,
SshManager sshManager,
KubernetesClientFactory kubernetesClientFactory) {
this.sidecarImagePullPolicy = sidecarImagePullPolicy;
this.pvcQuantity = pvcQuantity;
this.pvcQuantity = "test";
this.asyncStorageImage = asyncStorageImage;
this.pvcAccessMode = pvcAccessMode;
this.pvcStrategy = pvcStrategy;
this.pvcName = pvcName;
this.pvcName = "TEST";
this.pvcStorageClassName = pvcStorageClassName;
this.sshManager = sshManager;
this.kubernetesClientFactory = kubernetesClientFactory;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* Copyright (c) 2012-2022 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/
@ -40,10 +40,9 @@ public class ChePluginsVolumeApplier {
@Inject
public ChePluginsVolumeApplier(
@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) {
this.pvcQuantity = pvcQuantity;
this.pvcQuantity = "test";
this.pvcAccessMode = pvcAccessMode;
this.pvcStorageClassName = pvcStorageClassName;
}

View File

@ -1,468 +0,0 @@
/*
* Copyright (c) 2012-2021 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 java.lang.String.format;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static org.eclipse.che.api.user.server.UserManager.PERSONAL_ACCOUNT;
import static org.eclipse.che.api.workspace.shared.Constants.PERSIST_VOLUMES_ATTRIBUTE;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.CommonPVCStrategy.SUBPATHS_PROPERTY_FMT;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.lenient;
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.assertFalse;
import static org.testng.Assert.assertNotEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import io.fabric8.kubernetes.api.model.PersistentVolumeClaim;
import io.fabric8.kubernetes.api.model.PersistentVolumeClaimBuilder;
import io.fabric8.kubernetes.api.model.Quantity;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import org.eclipse.che.account.spi.AccountImpl;
import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.workspace.server.WorkspaceManager;
import org.eclipse.che.api.workspace.server.model.impl.RuntimeIdentityImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
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.KubernetesPersistentVolumeClaims;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Tests {@link CommonPVCStrategy}.
*
* @author Anton Korneta
* @author Sergii Leshchenko
*/
@Listeners(MockitoTestNGListener.class)
public class CommonPVCStrategyTest {
private static final String WORKSPACE_ID = "workspace123";
private static final String NAMESPACE = "infraNamespace";
private static final String PVC_NAME = "che-claim";
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"};
private static final RuntimeIdentity IDENTITY =
new RuntimeIdentityImpl(WORKSPACE_ID, "env1", "id1", NAMESPACE);
private KubernetesEnvironment k8sEnv;
@Mock private PVCSubPathHelper pvcSubPathHelper;
@Mock private KubernetesNamespaceFactory factory;
@Mock private KubernetesNamespace k8sNamespace;
@Mock private KubernetesPersistentVolumeClaims pvcs;
@Mock private EphemeralWorkspaceAdapter ephemeralWorkspaceAdapter;
@Mock private PVCProvisioner volumeConverter;
@Mock private PodsVolumes podsVolumes;
@Mock private SubPathPrefixes subpathPrefixes;
@Mock private WorkspaceManager workspaceManager;
private InOrder provisionOrder;
private CommonPVCStrategy commonPVCStrategy;
@BeforeMethod
public void setup() throws Exception {
commonPVCStrategy =
new CommonPVCStrategy(
PVC_NAME,
PVC_QUANTITY,
PVC_ACCESS_MODE,
true,
PVC_STORAGE_CLASS_NAME,
true,
pvcSubPathHelper,
factory,
ephemeralWorkspaceAdapter,
volumeConverter,
podsVolumes,
subpathPrefixes,
workspaceManager);
k8sEnv = KubernetesEnvironment.builder().build();
provisionOrder = inOrder(volumeConverter, subpathPrefixes, podsVolumes);
lenient().doNothing().when(pvcSubPathHelper).execute(any(), any(), any(), any());
lenient()
.doReturn(CompletableFuture.completedFuture(null))
.when(pvcSubPathHelper)
.removeDirsAsync(anyString(), anyString(), any(String.class));
lenient().when(factory.getOrCreate(IDENTITY)).thenReturn(k8sNamespace);
lenient().when(k8sNamespace.persistentVolumeClaims()).thenReturn(pvcs);
lenient().when(subpathPrefixes.getWorkspaceSubPath(WORKSPACE_ID)).thenReturn(WORKSPACE_ID);
}
@Test
public void testProvisionVolumesIntoKubernetesEnvironment() throws Exception {
// given
k8sEnv.getPersistentVolumeClaims().put("pvc1", newPVC("pvc1"));
k8sEnv.getPersistentVolumeClaims().put("pvc2", newPVC("pvc2"));
// when
commonPVCStrategy.provision(k8sEnv, IDENTITY);
// then
provisionOrder.verify(volumeConverter).convertCheVolumes(k8sEnv, WORKSPACE_ID);
provisionOrder.verify(subpathPrefixes).prefixVolumeMountsSubpaths(k8sEnv, WORKSPACE_ID);
provisionOrder.verify(podsVolumes).replacePVCVolumesWithCommon(k8sEnv.getPodsData(), PVC_NAME);
assertEquals(k8sEnv.getPersistentVolumeClaims().size(), 1);
PersistentVolumeClaim commonPVC = k8sEnv.getPersistentVolumeClaims().get(PVC_NAME);
assertNotNull(commonPVC);
assertEquals(commonPVC.getMetadata().getName(), PVC_NAME);
assertEquals(commonPVC.getSpec().getAccessModes(), Collections.singletonList(PVC_ACCESS_MODE));
assertEquals(
commonPVC.getSpec().getResources().getRequests().get("storage"),
new Quantity(PVC_QUANTITY));
}
@Test
public void testReplacePVCWhenItsAlreadyInKubernetesEnvironment() throws Exception {
PersistentVolumeClaim provisioned = newPVC(PVC_NAME);
k8sEnv.getPersistentVolumeClaims().put(PVC_NAME, provisioned);
commonPVCStrategy.provision(k8sEnv, IDENTITY);
assertNotEquals(k8sEnv.getPersistentVolumeClaims().get(PVC_NAME), provisioned);
}
@Test
public void testDoNotAddsSubpathsPropertyWhenPreCreationIsNotNeeded() throws Exception {
commonPVCStrategy =
new CommonPVCStrategy(
PVC_NAME,
PVC_QUANTITY,
PVC_ACCESS_MODE,
false,
PVC_STORAGE_CLASS_NAME,
true,
pvcSubPathHelper,
factory,
ephemeralWorkspaceAdapter,
volumeConverter,
podsVolumes,
subpathPrefixes,
workspaceManager);
commonPVCStrategy.provision(k8sEnv, IDENTITY);
final Map<String, PersistentVolumeClaim> actual = k8sEnv.getPersistentVolumeClaims();
assertFalse(actual.isEmpty());
assertTrue(actual.containsKey(PVC_NAME));
assertFalse(
actual
.get(PVC_NAME)
.getAdditionalProperties()
.containsKey(format(SUBPATHS_PROPERTY_FMT, WORKSPACE_ID)));
}
@Test
public void testCreatesPVCsWithSubpathsOnPrepare() throws Exception {
final PersistentVolumeClaim pvc = newPVC(PVC_NAME);
pvc.getAdditionalProperties()
.put(format(SUBPATHS_PROPERTY_FMT, WORKSPACE_ID), WORKSPACE_SUBPATHS);
k8sEnv.getPersistentVolumeClaims().put(PVC_NAME, pvc);
doNothing()
.when(pvcSubPathHelper)
.createDirs(IDENTITY, WORKSPACE_ID, PVC_NAME, emptyMap(), WORKSPACE_SUBPATHS);
commonPVCStrategy.prepare(k8sEnv, IDENTITY, 100, emptyMap());
verify(pvcs).get();
verify(pvcs).create(pvc);
verify(pvcs).waitBound(PVC_NAME, 100);
verify(pvcSubPathHelper)
.createDirs(IDENTITY, WORKSPACE_ID, PVC_NAME, emptyMap(), WORKSPACE_SUBPATHS);
}
@Test
public void testCreatesPVCsWithSubpathsOnPrepareIfWaitIsDisabled() throws Exception {
commonPVCStrategy =
new CommonPVCStrategy(
PVC_NAME,
PVC_QUANTITY,
PVC_ACCESS_MODE,
true,
PVC_STORAGE_CLASS_NAME,
false, // wait bound PVCs
pvcSubPathHelper,
factory,
ephemeralWorkspaceAdapter,
volumeConverter,
podsVolumes,
subpathPrefixes,
workspaceManager);
final PersistentVolumeClaim pvc = newPVC(PVC_NAME);
pvc.getAdditionalProperties()
.put(format(SUBPATHS_PROPERTY_FMT, WORKSPACE_ID), WORKSPACE_SUBPATHS);
k8sEnv.getPersistentVolumeClaims().put(PVC_NAME, pvc);
doNothing()
.when(pvcSubPathHelper)
.createDirs(IDENTITY, WORKSPACE_ID, PVC_NAME, emptyMap(), WORKSPACE_SUBPATHS);
commonPVCStrategy.prepare(k8sEnv, IDENTITY, 100, emptyMap());
verify(pvcs).get();
verify(pvcs).create(pvc);
verify(pvcs, never()).waitBound(anyString(), anyLong());
verify(pvcSubPathHelper)
.createDirs(IDENTITY, WORKSPACE_ID, PVC_NAME, emptyMap(), WORKSPACE_SUBPATHS);
}
@Test(
expectedExceptions = InfrastructureException.class,
expectedExceptionsMessageRegExp =
"The only one PVC MUST be present in common strategy while it contains: pvc1, pvc2\\.")
public void shouldThrowExceptionIfK8sEnvHasMoreThanOnePVCOnPreparing() throws Exception {
final PersistentVolumeClaim pvc1 = newPVC("pvc1");
final PersistentVolumeClaim pvc2 = newPVC("pvc2");
k8sEnv.getPersistentVolumeClaims().put("pvc1", pvc1);
k8sEnv.getPersistentVolumeClaims().put("pvc2", pvc2);
commonPVCStrategy.prepare(k8sEnv, IDENTITY, 100, emptyMap());
}
@Test(expectedExceptions = InfrastructureException.class)
public void throwsInfrastructureExceptionWhenFailedToGetExistingPVCs() throws Exception {
k8sEnv.getPersistentVolumeClaims().put(PVC_NAME, mock(PersistentVolumeClaim.class));
doThrow(InfrastructureException.class).when(pvcs).get();
commonPVCStrategy.prepare(k8sEnv, IDENTITY, 100, emptyMap());
}
@Test(expectedExceptions = InfrastructureException.class)
public void throwsInfrastructureExceptionWhenPVCCreationFailed() throws Exception {
final PersistentVolumeClaim claim = newPVC(PVC_NAME);
k8sEnv.getPersistentVolumeClaims().put(PVC_NAME, claim);
when(pvcs.get()).thenReturn(emptyList());
doThrow(InfrastructureException.class).when(pvcs).create(any());
commonPVCStrategy.prepare(k8sEnv, IDENTITY, 100, emptyMap());
}
@Test
public void shouldDeletePVCsIfThereIsNoPersistAttributeInWorkspaceConfigWhenCleanupCalled()
throws Exception {
// given
WorkspaceImpl workspace = mock(WorkspaceImpl.class);
Page workspaces = mock(Page.class);
when(workspace.getId()).thenReturn(WORKSPACE_ID);
when(workspaceManager.getWorkspaces(anyString(), eq(false), anyInt(), anyLong()))
.thenReturn((workspaces));
when(workspaces.isEmpty()).thenReturn(false);
WorkspaceConfigImpl workspaceConfig = mock(WorkspaceConfigImpl.class);
when(workspace.getConfig()).thenReturn(workspaceConfig);
AccountImpl account = mock(AccountImpl.class);
when(account.getType()).thenReturn(PERSONAL_ACCOUNT);
when(account.getId()).thenReturn("id123");
when(workspace.getAccount()).thenReturn(account);
Map<String, String> workspaceConfigAttributes = new HashMap<>();
when(workspaceConfig.getAttributes()).thenReturn(workspaceConfigAttributes);
KubernetesNamespace ns = mock(KubernetesNamespace.class);
when(factory.get(eq(workspace))).thenReturn(ns);
when(ns.getName()).thenReturn("ns");
// when
commonPVCStrategy.cleanup(workspace);
// then
verify(pvcSubPathHelper).removeDirsAsync(WORKSPACE_ID, "ns", PVC_NAME, WORKSPACE_ID);
}
@Test
public void shouldDeletePVCsIfPersistAttributeIsSetToTrueInWorkspaceConfigWhenCleanupCalled()
throws Exception {
// given
WorkspaceImpl workspace = mock(WorkspaceImpl.class);
Page workspaces = mock(Page.class);
when(workspaceManager.getWorkspaces(anyString(), eq(false), anyInt(), anyLong()))
.thenReturn((workspaces));
when(workspaces.isEmpty()).thenReturn(false);
when(workspace.getId()).thenReturn(WORKSPACE_ID);
WorkspaceConfigImpl workspaceConfig = mock(WorkspaceConfigImpl.class);
when(workspace.getConfig()).thenReturn(workspaceConfig);
AccountImpl account = mock(AccountImpl.class);
when(account.getType()).thenReturn(PERSONAL_ACCOUNT);
when(account.getId()).thenReturn("id123");
when(workspace.getAccount()).thenReturn(account);
Map<String, String> workspaceConfigAttributes = new HashMap<>();
when(workspaceConfig.getAttributes()).thenReturn(workspaceConfigAttributes);
workspaceConfigAttributes.put(PERSIST_VOLUMES_ATTRIBUTE, "true");
KubernetesNamespace ns = mock(KubernetesNamespace.class);
when(factory.get(eq(workspace))).thenReturn(ns);
when(ns.getName()).thenReturn("ns");
// when
commonPVCStrategy.cleanup(workspace);
// then
verify(pvcSubPathHelper).removeDirsAsync(WORKSPACE_ID, "ns", PVC_NAME, WORKSPACE_ID);
}
@Test
public void shouldDeleteCommonPVCIfUserHasNoWorkspaces() throws Exception {
// given
WorkspaceImpl workspace = mock(WorkspaceImpl.class);
Page workspaces = mock(Page.class);
KubernetesPersistentVolumeClaims persistentVolumeClaims =
mock(KubernetesPersistentVolumeClaims.class);
when(workspaceManager.getWorkspaces(anyString(), eq(false), anyInt(), anyLong()))
.thenReturn((workspaces));
when(workspaces.isEmpty()).thenReturn(true);
AccountImpl account = mock(AccountImpl.class);
when(account.getType()).thenReturn(PERSONAL_ACCOUNT);
when(account.getId()).thenReturn("id123");
when(workspace.getAccount()).thenReturn(account);
KubernetesNamespace ns = mock(KubernetesNamespace.class);
when(factory.get(eq(workspace))).thenReturn(ns);
when(ns.persistentVolumeClaims()).thenReturn(persistentVolumeClaims);
// when
commonPVCStrategy.cleanup(workspace);
// then
verify(ns).persistentVolumeClaims();
verify(persistentVolumeClaims).delete(PVC_NAME);
verify(pvcSubPathHelper, never()).removeDirsAsync(WORKSPACE_ID, "ns", PVC_NAME, WORKSPACE_ID);
verify(workspace, never()).getConfig();
verify(workspace, never()).getDevfile();
}
@Test
public void shouldNotDeleteCommonPVCIfUserHasWorkspaces() throws Exception {
// given
WorkspaceImpl workspace = mock(WorkspaceImpl.class);
Page workspaces = mock(Page.class);
KubernetesPersistentVolumeClaims persistentVolumeClaims =
mock(KubernetesPersistentVolumeClaims.class);
when(workspaceManager.getWorkspaces(anyString(), eq(false), anyInt(), anyLong()))
.thenReturn((workspaces));
when(workspaces.isEmpty()).thenReturn(false);
when(workspace.getId()).thenReturn(WORKSPACE_ID);
WorkspaceConfigImpl workspaceConfig = mock(WorkspaceConfigImpl.class);
when(workspace.getConfig()).thenReturn(workspaceConfig);
AccountImpl account = mock(AccountImpl.class);
when(account.getType()).thenReturn(PERSONAL_ACCOUNT);
when(account.getId()).thenReturn("id123");
when(workspace.getAccount()).thenReturn(account);
Map<String, String> workspaceConfigAttributes = new HashMap<>();
when(workspaceConfig.getAttributes()).thenReturn(workspaceConfigAttributes);
workspaceConfigAttributes.put(PERSIST_VOLUMES_ATTRIBUTE, "true");
KubernetesNamespace ns = mock(KubernetesNamespace.class);
when(factory.get(eq(workspace))).thenReturn(ns);
when(ns.getName()).thenReturn("ns");
// when
commonPVCStrategy.cleanup(workspace);
// then
verify(ns, never()).persistentVolumeClaims();
verify(persistentVolumeClaims, never()).delete(PVC_NAME);
verify(pvcSubPathHelper).removeDirsAsync(WORKSPACE_ID, "ns", PVC_NAME, WORKSPACE_ID);
}
@Test
public void
shouldDoNothingIfPersistAttributeIsSetToFalseInWorkspaceConfigAndWorkspacesNotEmptyWhenCleanupCalled()
throws Exception {
// given
WorkspaceImpl workspace = mock(WorkspaceImpl.class);
Page workspaces = mock(Page.class);
KubernetesPersistentVolumeClaims persistentVolumeClaims =
mock(KubernetesPersistentVolumeClaims.class);
when(workspaceManager.getWorkspaces(anyString(), eq(false), anyInt(), anyLong()))
.thenReturn((workspaces));
when(workspaces.isEmpty()).thenReturn(false);
AccountImpl account = mock(AccountImpl.class);
when(account.getType()).thenReturn(PERSONAL_ACCOUNT);
when(account.getId()).thenReturn("id123");
when(workspace.getAccount()).thenReturn(account);
WorkspaceConfigImpl workspaceConfig = mock(WorkspaceConfigImpl.class);
when(workspace.getConfig()).thenReturn(workspaceConfig);
Map<String, String> workspaceConfigAttributes = new HashMap<>();
when(workspaceConfig.getAttributes()).thenReturn(workspaceConfigAttributes);
workspaceConfigAttributes.put(PERSIST_VOLUMES_ATTRIBUTE, "false");
// when
commonPVCStrategy.cleanup(workspace);
// then
verify(persistentVolumeClaims, never()).delete(PVC_NAME);
verify(pvcSubPathHelper, never()).removeDirsAsync(WORKSPACE_ID, "ns", PVC_NAME, WORKSPACE_ID);
}
private static PersistentVolumeClaim newPVC(String name) {
return new PersistentVolumeClaimBuilder()
.withNewMetadata()
.withName(name)
.endMetadata()
.withNewSpec()
.endSpec()
.build();
}
}

View File

@ -1,331 +0,0 @@
/*
* Copyright (c) 2012-2021 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.workspace.infrastructure.kubernetes.Constants.CHE_VOLUME_NAME_LABEL;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.TestObjects.newContainer;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.TestObjects.newPod;
import static org.mockito.Mockito.verify;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import com.google.common.collect.ImmutableMap;
import io.fabric8.kubernetes.api.model.Container;
import io.fabric8.kubernetes.api.model.PersistentVolumeClaim;
import io.fabric8.kubernetes.api.model.PersistentVolumeClaimBuilder;
import io.fabric8.kubernetes.api.model.PersistentVolumeClaimVolumeSourceBuilder;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.PodSpec;
import io.fabric8.kubernetes.api.model.VolumeBuilder;
import io.fabric8.kubernetes.api.model.VolumeMount;
import io.fabric8.kubernetes.api.model.VolumeMountBuilder;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.workspace.server.model.impl.RuntimeIdentityImpl;
import org.eclipse.che.api.workspace.server.model.impl.VolumeImpl;
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/** @author Sergii Leshchenko */
@Listeners(MockitoTestNGListener.class)
public class PVCProvisionerTest {
private static final String WORKSPACE_ID = "workspace123";
private static final String PVC_NAME_PREFIX = "che-claim";
private static final String POD_1_NAME = "main";
private static final String CONTAINER_1_NAME = "app";
private static final String CONTAINER_2_NAME = "db";
private static final String MACHINE_1_NAME = POD_1_NAME + '/' + CONTAINER_1_NAME;
private static final String MACHINE_2_NAME = POD_1_NAME + '/' + CONTAINER_2_NAME;
private static final String POD_2_NAME = "second";
private static final String CONTAINER_3_NAME = "app2";
private static final String MACHINE_3_NAME = POD_2_NAME + '/' + CONTAINER_3_NAME;
private static final String VOLUME_1_NAME = "vol1";
private static final String VOLUME_2_NAME = "vol2";
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", "infraNamespace");
private KubernetesEnvironment k8sEnv;
private Pod pod;
private Pod pod2;
@Mock private PodsVolumes podsVolumes;
private PVCProvisioner provisioner;
@BeforeMethod
public void setUp() {
provisioner =
new PVCProvisioner(
PVC_NAME_PREFIX, PVC_QUANTITY, PVC_ACCESS_MODE, PVC_STORAGE_CLASS_NAME, podsVolumes);
k8sEnv = KubernetesEnvironment.builder().build();
k8sEnv
.getMachines()
.put(
MACHINE_1_NAME,
TestObjects.newMachineConfig()
.withVolume(VOLUME_1_NAME, "/path")
.withVolume(VOLUME_2_NAME, "/path2")
.build());
k8sEnv
.getMachines()
.put(
MACHINE_2_NAME,
TestObjects.newMachineConfig().withVolume(VOLUME_2_NAME, "/path2").build());
k8sEnv
.getMachines()
.put(
MACHINE_3_NAME,
TestObjects.newMachineConfig().withVolume(VOLUME_1_NAME, "/path").build());
pod =
newPod(POD_1_NAME)
.withContainers(
newContainer(CONTAINER_1_NAME).build(), newContainer(CONTAINER_2_NAME).build())
.build();
pod2 = newPod(POD_2_NAME).withContainers(newContainer(CONTAINER_3_NAME).build()).build();
k8sEnv.addPod(pod);
k8sEnv.addPod(pod2);
}
@Test
public void testProvisionPVCsForEachVolumeWithUniqueName() throws Exception {
// given
k8sEnv.getPersistentVolumeClaims().clear();
// when
provisioner.convertCheVolumes(k8sEnv, WORKSPACE_ID);
// then
assertEquals(pod.getSpec().getVolumes().size(), 2);
assertEquals(pod.getSpec().getContainers().get(0).getVolumeMounts().size(), 2);
assertEquals(pod.getSpec().getContainers().get(1).getVolumeMounts().size(), 1);
assertEquals(pod2.getSpec().getVolumes().size(), 1);
assertEquals(pod2.getSpec().getContainers().get(0).getVolumeMounts().size(), 1);
assertEquals(k8sEnv.getPersistentVolumeClaims().size(), 2);
PersistentVolumeClaim pvcForVolume1 =
findPvc(VOLUME_1_NAME, k8sEnv.getPersistentVolumeClaims());
assertNotNull(pvcForVolume1);
assertTrue(pvcForVolume1.getMetadata().getName().startsWith(PVC_NAME_PREFIX));
PersistentVolumeClaim pvcForVolume2 =
findPvc(VOLUME_2_NAME, k8sEnv.getPersistentVolumeClaims());
assertNotNull(pvcForVolume2);
assertTrue(pvcForVolume2.getMetadata().getName().startsWith(PVC_NAME_PREFIX));
}
@Test
public void testMatchingUserDefinedPVCWithCheVolume() throws Exception {
// given
k8sEnv.getPersistentVolumeClaims().put("userDataPVC", newPVC("userDataPVC"));
pod.getSpec()
.getVolumes()
.add(
new VolumeBuilder()
.withName("userData")
.withPersistentVolumeClaim(
new PersistentVolumeClaimVolumeSourceBuilder()
.withClaimName("userDataPVC")
.build())
.build());
pod.getSpec()
.getContainers()
.get(0)
.getVolumeMounts()
.add(new VolumeMountBuilder().withName("userData").withSubPath("/home/user/data").build());
k8sEnv.getMachines().values().forEach(m -> m.getVolumes().clear());
k8sEnv
.getMachines()
.get(MACHINE_2_NAME)
.getVolumes()
.put("userDataPVC", new VolumeImpl().withPath("/"));
// when
provisioner.convertCheVolumes(k8sEnv, WORKSPACE_ID);
// then
assertEquals(k8sEnv.getPersistentVolumeClaims().size(), 1);
PersistentVolumeClaim pvcForUserData =
findPvc("userDataPVC", k8sEnv.getPersistentVolumeClaims());
assertNotNull(pvcForUserData);
assertEquals("userDataPVC", pvcForUserData.getMetadata().getName());
PodSpec podSpec = k8sEnv.getPodsData().get(POD_1_NAME).getSpec();
io.fabric8.kubernetes.api.model.Volume userPodVolume = podSpec.getVolumes().get(0);
assertEquals(
userPodVolume.getPersistentVolumeClaim().getClaimName(),
pvcForUserData.getMetadata().getName());
assertEquals(
podSpec.getVolumes().get(0).getPersistentVolumeClaim().getClaimName(),
pvcForUserData.getMetadata().getName());
// check container bound to user-defined PVC
Container container1 = podSpec.getContainers().get(0);
assertEquals(container1.getVolumeMounts().size(), 1);
VolumeMount volumeMount = container1.getVolumeMounts().get(0);
assertEquals(volumeMount.getName(), userPodVolume.getName());
// check container that is bound to Che Volume via Machine configuration
Container container2 = podSpec.getContainers().get(1);
VolumeMount cheVolumeMount2 = container2.getVolumeMounts().get(0);
assertEquals(cheVolumeMount2.getName(), userPodVolume.getName());
}
@Test
public void testDoNotProvisionPVCsWhenItIsAlreadyProvisionedForGivenVolumeAndWorkspace()
throws Exception {
final String pvcUniqueName1 = PVC_NAME_PREFIX + "-3121";
PersistentVolumeClaim pvc1 =
newPVC(pvcUniqueName1, ImmutableMap.of(CHE_VOLUME_NAME_LABEL, VOLUME_1_NAME));
pvc1.getAdditionalProperties().put("CHE_PROVISIONED", true);
final String pvcUniqueName2 = PVC_NAME_PREFIX + "-71333";
PersistentVolumeClaim pvc2 =
newPVC(pvcUniqueName2, ImmutableMap.of(CHE_VOLUME_NAME_LABEL, VOLUME_2_NAME));
pvc2.getAdditionalProperties().put("CHE_PROVISIONED", true);
k8sEnv.getPersistentVolumeClaims().put(pvc1.getMetadata().getName(), pvc1);
k8sEnv.getPersistentVolumeClaims().put(pvc2.getMetadata().getName(), pvc2);
provisioner.convertCheVolumes(k8sEnv, WORKSPACE_ID);
assertEquals(pod.getSpec().getVolumes().size(), 2);
assertEquals(pod.getSpec().getContainers().get(0).getVolumeMounts().size(), 2);
assertEquals(pod.getSpec().getContainers().get(1).getVolumeMounts().size(), 1);
assertEquals(pod2.getSpec().getVolumes().size(), 1);
assertEquals(pod2.getSpec().getContainers().get(0).getVolumeMounts().size(), 1);
assertEquals(k8sEnv.getPersistentVolumeClaims().size(), 2);
assertTrue(k8sEnv.getPersistentVolumeClaims().containsKey(pvcUniqueName1));
assertTrue(k8sEnv.getPersistentVolumeClaims().containsKey(pvcUniqueName2));
}
@Test
public void testProvisioningPVCsToK8sEnvironment() throws Exception {
// given
k8sEnv = KubernetesEnvironment.builder().build();
Map<String, PersistentVolumeClaim> toProvision = new HashMap<>();
toProvision.put("appStorage", newPVC("appStorage"));
Pod pod =
newPod(POD_1_NAME)
.withContainers(
newContainer(CONTAINER_1_NAME)
.withVolumeMount("appStorage", "/data", "data")
.withVolumeMount("appStorage", "/config", "config")
.build())
.withPVCVolume("appStorage", "appStorage")
.build();
k8sEnv.addPod(pod);
// when
provisioner.provision(k8sEnv, toProvision);
// then
assertEquals(k8sEnv.getPersistentVolumeClaims().size(), 1);
PersistentVolumeClaim pvcForUserData =
findPvc("appStorage", k8sEnv.getPersistentVolumeClaims());
assertNotNull(pvcForUserData);
assertTrue(pvcForUserData.getMetadata().getName().startsWith(PVC_NAME_PREFIX));
verify(podsVolumes)
.changePVCReferences(
k8sEnv.getPodsData().values(), "appStorage", pvcForUserData.getMetadata().getName());
}
@Test
public void testMatchEnvPVCsByVolumeNameWhenProvisioningPVCsToK8sEnvironment() throws Exception {
// given
k8sEnv = KubernetesEnvironment.builder().build();
k8sEnv
.getPersistentVolumeClaims()
.put(
"appStorage",
newPVC("pvc123123", ImmutableMap.of(CHE_VOLUME_NAME_LABEL, "appStorage")));
Map<String, PersistentVolumeClaim> toProvision = new HashMap<>();
toProvision.put("appStorage", newPVC("appStorage"));
Pod pod =
newPod(POD_1_NAME)
.withContainers(
newContainer(CONTAINER_1_NAME)
.withVolumeMount("appStorage", "/data", "data")
.withVolumeMount("appStorage", "/config", "config")
.build())
.withPVCVolume("appStorage", "appStorage")
.build();
k8sEnv.addPod(pod);
// when
provisioner.provision(k8sEnv, toProvision);
// then
assertEquals(k8sEnv.getPersistentVolumeClaims().size(), 1);
PersistentVolumeClaim pvcForUserData =
findPvc("appStorage", k8sEnv.getPersistentVolumeClaims());
assertNotNull(pvcForUserData);
assertEquals("pvc123123", pvcForUserData.getMetadata().getName());
verify(podsVolumes)
.changePVCReferences(k8sEnv.getPodsData().values(), "appStorage", "pvc123123");
}
private static PersistentVolumeClaim newPVC(String name) {
return newPVC(name, new HashMap<>());
}
private static PersistentVolumeClaim newPVC(String name, Map<String, String> labels) {
return new PersistentVolumeClaimBuilder()
.withNewMetadata()
.withName(name)
.withLabels(labels)
.endMetadata()
.withNewSpec()
.endSpec()
.build();
}
private PersistentVolumeClaim findPvc(
String volumeName, Map<String, PersistentVolumeClaim> claims) {
return claims.values().stream()
.filter(c -> volumeName.equals(c.getMetadata().getLabels().get(CHE_VOLUME_NAME_LABEL)))
.findAny()
.orElse(null);
}
}

View File

@ -1,274 +0,0 @@
/*
* Copyright (c) 2012-2021 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 java.lang.String.format;
import static java.util.Collections.emptyMap;
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;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.lenient;
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;
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;
import org.eclipse.che.api.workspace.server.WorkspaceManager;
import org.eclipse.che.api.workspace.server.model.impl.RuntimeIdentityImpl;
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.KubernetesPersistentVolumeClaims;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Tests {@link PerWorkspacePVCStrategy}
*
* @author Sergii Leshchenko
*/
@Listeners(MockitoTestNGListener.class)
public class PerWorkspacePVCStrategyTest {
private static final String WORKSPACE_ID = "workspace123";
private static final String INFRA_NAMESPACE = "infraNamespace";
private static final String PVC_NAME_PREFIX = "che-claim";
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 RuntimeIdentity IDENTITY =
new RuntimeIdentityImpl(WORKSPACE_ID, "userid", null, INFRA_NAMESPACE);
@Mock private PVCSubPathHelper pvcSubPathHelper;
@Mock private KubernetesNamespaceFactory factory;
@Mock private KubernetesNamespace k8sNamespace;
@Mock private KubernetesPersistentVolumeClaims pvcs;
@Mock private EphemeralWorkspaceAdapter ephemeralWorkspaceAdapter;
@Mock private PVCProvisioner volumeConverter;
@Mock private PodsVolumes podsVolumes;
@Mock private SubPathPrefixes subpathPrefixes;
@Mock private WorkspaceManager workspaceManager;
private PerWorkspacePVCStrategy strategy;
@BeforeMethod
public void setup() throws Exception {
strategy =
new PerWorkspacePVCStrategy(
PVC_NAME_PREFIX,
PVC_QUANTITY,
PVC_ACCESS_MODE,
true,
PVC_STORAGE_CLASS_NAME,
true,
pvcSubPathHelper,
factory,
ephemeralWorkspaceAdapter,
volumeConverter,
podsVolumes,
subpathPrefixes,
workspaceManager);
lenient().when(factory.getOrCreate(IDENTITY)).thenReturn(k8sNamespace);
lenient().when(factory.get(any(Workspace.class))).thenReturn(k8sNamespace);
lenient().when(k8sNamespace.persistentVolumeClaims()).thenReturn(pvcs);
}
@Test
public void shouldPreparePerWorkspacePVCWithSubPaths() throws Exception {
// given
final PersistentVolumeClaim pvc = newPVC(PVC_NAME_PREFIX + "-" + WORKSPACE_ID);
String perWorkspacePVCName = pvc.getMetadata().getName();
KubernetesEnvironment k8sEnv = KubernetesEnvironment.builder().build();
k8sEnv.getPersistentVolumeClaims().put(perWorkspacePVCName, pvc);
String[] subPaths = {"/projects", "/plugins"};
pvc.getAdditionalProperties().put(format(SUBPATHS_PROPERTY_FMT, WORKSPACE_ID), subPaths);
// when
strategy.prepare(k8sEnv, IDENTITY, 100, emptyMap());
// then
verify(pvcs).get();
verify(pvcs).create(pvc);
verify(pvcs).waitBound(perWorkspacePVCName, 100);
verify(pvcSubPathHelper)
.createDirs(IDENTITY, WORKSPACE_ID, perWorkspacePVCName, emptyMap(), subPaths);
}
@Test
public void shouldPreparePerWorkspacePVCWithSubPathsWhenWaitBoundIsDisabled() throws Exception {
// given
strategy =
new PerWorkspacePVCStrategy(
PVC_NAME_PREFIX,
PVC_QUANTITY,
PVC_ACCESS_MODE,
true,
PVC_STORAGE_CLASS_NAME,
false,
pvcSubPathHelper,
factory,
ephemeralWorkspaceAdapter,
volumeConverter,
podsVolumes,
subpathPrefixes,
workspaceManager);
final PersistentVolumeClaim pvc = newPVC(PVC_NAME_PREFIX + "-" + WORKSPACE_ID);
String perWorkspacePVCName = pvc.getMetadata().getName();
KubernetesEnvironment k8sEnv = KubernetesEnvironment.builder().build();
k8sEnv.getPersistentVolumeClaims().put(perWorkspacePVCName, pvc);
String[] subPaths = {"/projects", "/plugins"};
pvc.getAdditionalProperties().put(format(SUBPATHS_PROPERTY_FMT, WORKSPACE_ID), subPaths);
// when
strategy.prepare(k8sEnv, IDENTITY, 100, emptyMap());
// then
verify(pvcs).get();
verify(pvcs).create(pvc);
verify(pvcs, never()).waitBound(anyString(), anyLong());
verify(pvcSubPathHelper)
.createDirs(IDENTITY, WORKSPACE_ID, perWorkspacePVCName, emptyMap(), subPaths);
}
@Test
public void shouldReturnPVCPerWorkspace() throws Exception {
// when
PersistentVolumeClaim commonPVC = strategy.createCommonPVC(WORKSPACE_ID);
// 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,
true,
pvcSubPathHelper,
factory,
ephemeralWorkspaceAdapter,
volumeConverter,
podsVolumes,
subpathPrefixes,
workspaceManager);
final PersistentVolumeClaim commonPVC = strategy.createCommonPVC(WORKSPACE_ID);
assertNull(commonPVC.getSpec().getStorageClassName());
}
}
@Test
public void shouldDeletePVCsIfThereIsNoPersistAttributeInWorkspaceConfigWhenCleanupCalled()
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<String, String> 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<String, String> 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<String, String> workspaceConfigAttributes = new HashMap<>();
lenient().when(workspaceConfig.getAttributes()).thenReturn(workspaceConfigAttributes);
workspaceConfigAttributes.put(PERSIST_VOLUMES_ATTRIBUTE, "false");
// when
strategy.cleanup(workspace);
// then
verify(pvcs, never()).delete(ImmutableMap.of(CHE_WORKSPACE_ID_LABEL, WORKSPACE_ID));
}
private static PersistentVolumeClaim newPVC(String name) {
return new PersistentVolumeClaimBuilder()
.withNewMetadata()
.withName(name)
.endMetadata()
.withNewSpec()
.endSpec()
.build();
}
}

View File

@ -1,370 +0,0 @@
/*
* Copyright (c) 2012-2021 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.provision;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static java.util.UUID.randomUUID;
import static org.eclipse.che.api.workspace.shared.Constants.ASYNC_PERSIST_ATTRIBUTE;
import static org.eclipse.che.api.workspace.shared.Constants.PERSIST_VOLUMES_ATTRIBUTE;
import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.AsyncStorageProvisioner.ASYNC_STORAGE;
import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.AsyncStorageProvisioner.ASYNC_STORAGE_CONFIG;
import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.AsyncStorageProvisioner.SSH_KEY_NAME;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.fabric8.kubernetes.api.model.PersistentVolumeClaim;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.Watcher;
import io.fabric8.kubernetes.client.dsl.AppsAPIGroupDSL;
import io.fabric8.kubernetes.client.dsl.MixedOperation;
import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
import io.fabric8.kubernetes.client.dsl.PodResource;
import io.fabric8.kubernetes.client.dsl.Resource;
import io.fabric8.kubernetes.client.dsl.RollableScalableResource;
import io.fabric8.kubernetes.client.dsl.ServiceResource;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.ssh.server.SshManager;
import org.eclipse.che.api.ssh.server.model.impl.SshPairImpl;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory;
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
@Listeners(MockitoTestNGListener.class)
public class AsyncStorageProvisionerTest {
private static final String WORKSPACE_ID = UUID.randomUUID().toString();
private static final String NAMESPACE = UUID.randomUUID().toString();
private static final String CONFIGMAP_NAME = NAMESPACE + ASYNC_STORAGE_CONFIG;
private static final String VPC_NAME = UUID.randomUUID().toString();
private static final String USER = "user";
@Mock private KubernetesEnvironment kubernetesEnvironment;
@Mock private RuntimeIdentity identity;
@Mock private KubernetesClientFactory clientFactory;
@Mock private KubernetesClient kubernetesClient;
@Mock private SshManager sshManager;
@Mock private Resource<PersistentVolumeClaim> pvcResource;
@Mock private Resource<ConfigMap> mapResource;
@Mock private PodResource<Pod> podResource;
@Mock private RollableScalableResource<Deployment> deploymentResource;
@Mock private ServiceResource<Service> serviceResource;
@Mock private MixedOperation mixedOperationPvc;
@Mock private MixedOperation mixedOperationConfigMap;
@Mock private MixedOperation mixedOperationPod;
@Mock private MixedOperation mixedOperationDeployment;
@Mock private MixedOperation mixedOperationService;
@Mock private NonNamespaceOperation namespacePvcOperation;
@Mock private NonNamespaceOperation namespaceConfigMapOperation;
@Mock private NonNamespaceOperation namespacePodOperation;
@Mock private NonNamespaceOperation namespaceDeploymentOperation;
@Mock private NonNamespaceOperation namespaceServiceOperation;
@Mock private AppsAPIGroupDSL apps;
@Captor private ArgumentCaptor<Watcher<Pod>> watcherCaptor;
private Map<String, String> attributes;
private AsyncStorageProvisioner asyncStorageProvisioner;
private SshPairImpl sshPair;
@BeforeMethod
public void setUp() {
asyncStorageProvisioner =
new AsyncStorageProvisioner(
"Always",
"10Gi",
"org/image:tag",
"ReadWriteOnce",
"common",
VPC_NAME,
"storage",
sshManager,
clientFactory);
attributes = new HashMap<>(2);
attributes.put(ASYNC_PERSIST_ATTRIBUTE, "true");
attributes.put(PERSIST_VOLUMES_ATTRIBUTE, "false");
sshPair = new SshPairImpl(USER, "internal", SSH_KEY_NAME, "", "");
}
@Test(
expectedExceptions = InfrastructureException.class,
expectedExceptionsMessageRegExp =
"Workspace configuration not valid: Asynchronous storage available only for 'common' PVC strategy.*")
public void shouldThrowExceptionIfNotCommonStrategy() throws Exception {
AsyncStorageProvisioner asyncStorageProvisioner =
new AsyncStorageProvisioner(
"Always",
"10Gi",
"org/image:tag",
"ReadWriteOnce",
randomUUID().toString(),
VPC_NAME,
"storageClass",
sshManager,
clientFactory);
when(kubernetesEnvironment.getAttributes()).thenReturn(attributes);
asyncStorageProvisioner.provision(kubernetesEnvironment, identity);
verifyNoMoreInteractions(sshManager);
verifyNoMoreInteractions(clientFactory);
verifyNoMoreInteractions(identity);
}
@Test(
expectedExceptions = InfrastructureException.class,
expectedExceptionsMessageRegExp =
"Workspace configuration not valid: Asynchronous storage available only if 'persistVolumes' attribute set to false")
public void shouldThrowExceptionIfAsyncStorageForNotEphemeralWorkspace() throws Exception {
Map attributes = new HashMap<>(2);
attributes.put(ASYNC_PERSIST_ATTRIBUTE, "true");
attributes.put(PERSIST_VOLUMES_ATTRIBUTE, "true");
when(kubernetesEnvironment.getAttributes()).thenReturn(attributes);
asyncStorageProvisioner.provision(kubernetesEnvironment, identity);
verifyNoMoreInteractions(sshManager);
verifyNoMoreInteractions(clientFactory);
verifyNoMoreInteractions(identity);
}
@Test
public void shouldDoNothingIfNotSetAttribute() throws InfrastructureException {
when(kubernetesEnvironment.getAttributes()).thenReturn(emptyMap());
asyncStorageProvisioner.provision(kubernetesEnvironment, identity);
verifyNoMoreInteractions(sshManager);
verifyNoMoreInteractions(clientFactory);
verifyNoMoreInteractions(identity);
}
@Test
public void shouldDoNothingIfAttributesAsyncPersistOnly() throws InfrastructureException {
when(kubernetesEnvironment.getAttributes())
.thenReturn(singletonMap(PERSIST_VOLUMES_ATTRIBUTE, "false"));
asyncStorageProvisioner.provision(kubernetesEnvironment, identity);
verifyNoMoreInteractions(sshManager);
verifyNoMoreInteractions(clientFactory);
verifyNoMoreInteractions(identity);
}
@Test
public void shouldCreateAll() throws InfrastructureException, ServerException, ConflictException {
when(kubernetesEnvironment.getAttributes()).thenReturn(attributes);
when(clientFactory.create(anyString())).thenReturn(kubernetesClient);
when(identity.getWorkspaceId()).thenReturn(WORKSPACE_ID);
when(identity.getInfrastructureNamespace()).thenReturn(NAMESPACE);
when(identity.getOwnerId()).thenReturn(USER);
when(sshManager.getPairs(USER, "internal")).thenReturn(singletonList(sshPair));
when(kubernetesClient.persistentVolumeClaims()).thenReturn(mixedOperationPvc);
when(mixedOperationPvc.inNamespace(NAMESPACE)).thenReturn(namespacePvcOperation);
when(namespacePvcOperation.withName(VPC_NAME)).thenReturn(pvcResource);
when(pvcResource.get()).thenReturn(null);
when(kubernetesClient.configMaps()).thenReturn(mixedOperationConfigMap);
when(mixedOperationConfigMap.inNamespace(NAMESPACE)).thenReturn(namespaceConfigMapOperation);
when(namespaceConfigMapOperation.withName(anyString())).thenReturn(mapResource);
when(mapResource.get()).thenReturn(null);
when(kubernetesClient.apps()).thenReturn(apps);
when(apps.deployments()).thenReturn(mixedOperationDeployment);
when(mixedOperationDeployment.inNamespace(NAMESPACE)).thenReturn(namespaceDeploymentOperation);
when(namespaceDeploymentOperation.withName(ASYNC_STORAGE)).thenReturn(deploymentResource);
when(deploymentResource.get()).thenReturn(null);
when(kubernetesClient.services()).thenReturn(mixedOperationService);
when(mixedOperationService.inNamespace(NAMESPACE)).thenReturn(namespaceServiceOperation);
when(namespaceServiceOperation.withName(ASYNC_STORAGE)).thenReturn(serviceResource);
when(serviceResource.get()).thenReturn(null);
asyncStorageProvisioner.provision(kubernetesEnvironment, identity);
verify(identity, times(1)).getInfrastructureNamespace();
verify(identity, times(1)).getOwnerId();
verify(sshManager, times(1)).getPairs(USER, "internal");
verify(sshManager, never()).generatePair(USER, "internal", SSH_KEY_NAME);
verify(kubernetesClient.services().inNamespace(NAMESPACE), times(1)).create(any(Service.class));
verify(kubernetesClient.configMaps().inNamespace(NAMESPACE), times(1))
.create(any(ConfigMap.class));
verify(kubernetesClient.apps().deployments().inNamespace(NAMESPACE), times(1))
.create(any(Deployment.class));
verify(kubernetesClient.persistentVolumeClaims().inNamespace(NAMESPACE), times(1))
.create(any(PersistentVolumeClaim.class));
}
@Test
public void shouldNotCreateConfigMap()
throws InfrastructureException, ServerException, ConflictException {
when(kubernetesEnvironment.getAttributes()).thenReturn(attributes);
when(clientFactory.create(anyString())).thenReturn(kubernetesClient);
when(identity.getWorkspaceId()).thenReturn(WORKSPACE_ID);
when(identity.getInfrastructureNamespace()).thenReturn(NAMESPACE);
when(identity.getOwnerId()).thenReturn(USER);
when(kubernetesClient.persistentVolumeClaims()).thenReturn(mixedOperationPvc);
when(mixedOperationPvc.inNamespace(NAMESPACE)).thenReturn(namespacePvcOperation);
when(namespacePvcOperation.withName(VPC_NAME)).thenReturn(pvcResource);
when(pvcResource.get()).thenReturn(null);
when(kubernetesClient.configMaps()).thenReturn(mixedOperationConfigMap);
when(mixedOperationConfigMap.inNamespace(NAMESPACE)).thenReturn(namespaceConfigMapOperation);
when(namespaceConfigMapOperation.withName(CONFIGMAP_NAME)).thenReturn(mapResource);
ObjectMeta meta = new ObjectMeta();
meta.setName(CONFIGMAP_NAME);
ConfigMap configMap = new ConfigMap();
configMap.setMetadata(meta);
when(mapResource.get()).thenReturn(configMap);
when(kubernetesClient.apps()).thenReturn(apps);
when(apps.deployments()).thenReturn(mixedOperationDeployment);
when(mixedOperationDeployment.inNamespace(NAMESPACE)).thenReturn(namespaceDeploymentOperation);
when(namespaceDeploymentOperation.withName(ASYNC_STORAGE)).thenReturn(deploymentResource);
when(deploymentResource.get()).thenReturn(null);
when(kubernetesClient.services()).thenReturn(mixedOperationService);
when(mixedOperationService.inNamespace(NAMESPACE)).thenReturn(namespaceServiceOperation);
when(namespaceServiceOperation.withName(ASYNC_STORAGE)).thenReturn(serviceResource);
when(serviceResource.get()).thenReturn(null);
asyncStorageProvisioner.provision(kubernetesEnvironment, identity);
verify(identity, times(1)).getInfrastructureNamespace();
verify(identity, times(1)).getOwnerId();
verify(identity, times(1)).getWorkspaceId();
verify(sshManager, never()).getPairs(USER, "internal");
verify(sshManager, never()).generatePair(USER, "internal", SSH_KEY_NAME);
verify(kubernetesClient.services().inNamespace(NAMESPACE), times(1)).create(any(Service.class));
verify(kubernetesClient.configMaps().inNamespace(NAMESPACE), never())
.create(any(ConfigMap.class));
verify(kubernetesClient.apps().deployments().inNamespace(NAMESPACE), times(1))
.create(any(Deployment.class));
verify(kubernetesClient.persistentVolumeClaims().inNamespace(NAMESPACE), times(1))
.create(any(PersistentVolumeClaim.class));
}
@Test
public void shouldNotCreatePod()
throws InfrastructureException, ServerException, ConflictException {
when(kubernetesEnvironment.getAttributes()).thenReturn(attributes);
when(clientFactory.create(anyString())).thenReturn(kubernetesClient);
when(identity.getWorkspaceId()).thenReturn(WORKSPACE_ID);
when(identity.getInfrastructureNamespace()).thenReturn(NAMESPACE);
when(identity.getOwnerId()).thenReturn(USER);
when(sshManager.getPairs(USER, "internal")).thenReturn(singletonList(sshPair));
when(kubernetesClient.persistentVolumeClaims()).thenReturn(mixedOperationPvc);
when(mixedOperationPvc.inNamespace(NAMESPACE)).thenReturn(namespacePvcOperation);
when(namespacePvcOperation.withName(VPC_NAME)).thenReturn(pvcResource);
when(pvcResource.get()).thenReturn(null);
when(kubernetesClient.configMaps()).thenReturn(mixedOperationConfigMap);
when(mixedOperationConfigMap.inNamespace(NAMESPACE)).thenReturn(namespaceConfigMapOperation);
when(namespaceConfigMapOperation.withName(CONFIGMAP_NAME)).thenReturn(mapResource);
when(mapResource.get()).thenReturn(null);
when(kubernetesClient.pods()).thenReturn(mixedOperationPod);
when(mixedOperationPod.inNamespace(NAMESPACE)).thenReturn(namespacePodOperation);
when(kubernetesClient.apps()).thenReturn(apps);
when(apps.deployments()).thenReturn(mixedOperationDeployment);
when(mixedOperationDeployment.inNamespace(NAMESPACE)).thenReturn(namespaceDeploymentOperation);
when(namespaceDeploymentOperation.withName(ASYNC_STORAGE)).thenReturn(deploymentResource);
ObjectMeta meta = new ObjectMeta();
meta.setName(ASYNC_STORAGE);
Deployment deployment = new Deployment();
deployment.setMetadata(meta);
when(deploymentResource.get()).thenReturn(deployment);
when(kubernetesClient.services()).thenReturn(mixedOperationService);
when(mixedOperationService.inNamespace(NAMESPACE)).thenReturn(namespaceServiceOperation);
when(namespaceServiceOperation.withName(ASYNC_STORAGE)).thenReturn(serviceResource);
when(serviceResource.get()).thenReturn(null);
asyncStorageProvisioner.provision(kubernetesEnvironment, identity);
verify(identity, times(1)).getInfrastructureNamespace();
verify(identity, times(1)).getOwnerId();
verify(sshManager, times(1)).getPairs(USER, "internal");
verify(sshManager, never()).generatePair(USER, "internal", SSH_KEY_NAME);
verify(kubernetesClient.services().inNamespace(NAMESPACE), times(1)).create(any(Service.class));
verify(kubernetesClient.configMaps().inNamespace(NAMESPACE), times(1))
.create(any(ConfigMap.class));
verify(kubernetesClient.pods().inNamespace(NAMESPACE), never()).create(any(Pod.class));
verify(kubernetesClient.persistentVolumeClaims().inNamespace(NAMESPACE), times(1))
.create(any(PersistentVolumeClaim.class));
}
@Test
public void shouldNotCreateService()
throws InfrastructureException, ServerException, ConflictException {
when(kubernetesEnvironment.getAttributes()).thenReturn(attributes);
when(clientFactory.create(anyString())).thenReturn(kubernetesClient);
when(identity.getWorkspaceId()).thenReturn(WORKSPACE_ID);
when(identity.getInfrastructureNamespace()).thenReturn(NAMESPACE);
when(identity.getOwnerId()).thenReturn(USER);
when(sshManager.getPairs(USER, "internal")).thenReturn(singletonList(sshPair));
when(kubernetesClient.persistentVolumeClaims()).thenReturn(mixedOperationPvc);
when(mixedOperationPvc.inNamespace(NAMESPACE)).thenReturn(namespacePvcOperation);
when(namespacePvcOperation.withName(VPC_NAME)).thenReturn(pvcResource);
when(pvcResource.get()).thenReturn(null);
when(kubernetesClient.configMaps()).thenReturn(mixedOperationConfigMap);
when(mixedOperationConfigMap.inNamespace(NAMESPACE)).thenReturn(namespaceConfigMapOperation);
when(namespaceConfigMapOperation.withName(CONFIGMAP_NAME)).thenReturn(mapResource);
when(mapResource.get()).thenReturn(null);
when(kubernetesClient.apps()).thenReturn(apps);
when(apps.deployments()).thenReturn(mixedOperationDeployment);
when(mixedOperationDeployment.inNamespace(NAMESPACE)).thenReturn(namespaceDeploymentOperation);
when(namespaceDeploymentOperation.withName(ASYNC_STORAGE)).thenReturn(deploymentResource);
when(deploymentResource.get()).thenReturn(null);
when(kubernetesClient.services()).thenReturn(mixedOperationService);
when(mixedOperationService.inNamespace(NAMESPACE)).thenReturn(namespaceServiceOperation);
when(namespaceServiceOperation.withName(ASYNC_STORAGE)).thenReturn(serviceResource);
ObjectMeta meta = new ObjectMeta();
meta.setName(ASYNC_STORAGE);
Service service = new Service();
service.setMetadata(meta);
when(serviceResource.get()).thenReturn(service);
asyncStorageProvisioner.provision(kubernetesEnvironment, identity);
verify(identity, times(1)).getInfrastructureNamespace();
verify(identity, times(1)).getOwnerId();
verify(sshManager, times(1)).getPairs(USER, "internal");
verify(sshManager, never()).generatePair(USER, "internal", SSH_KEY_NAME);
verify(kubernetesClient.services().inNamespace(NAMESPACE), never()).create(any(Service.class));
verify(kubernetesClient.configMaps().inNamespace(NAMESPACE), times(1))
.create(any(ConfigMap.class));
verify(kubernetesClient.apps().deployments().inNamespace(NAMESPACE), times(1))
.create(any(Deployment.class));
verify(kubernetesClient.persistentVolumeClaims().inNamespace(NAMESPACE), times(1))
.create(any(PersistentVolumeClaim.class));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* Copyright (c) 2012-2022 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/
@ -525,78 +525,6 @@ public class KubernetesPluginsToolingApplierTest {
verifyContainers(nonUserContainers);
}
@Test
public void applyPluginContainerWithOneVolume() throws InfrastructureException {
lenient().when(podSpec.getContainers()).thenReturn(new ArrayList<>());
ChePlugin chePlugin = createChePlugin();
CheContainer cheContainer = chePlugin.getContainers().get(0);
applier.apply(runtimeIdentity, internalEnvironment, singletonList(chePlugin));
verifyPodAndContainersNumber(1);
Container container = getOneAndOnlyNonUserContainer(internalEnvironment);
verifyContainer(container);
verify(chePluginsVolumeApplier)
.applyVolumes(
any(PodData.class),
eq(container),
eq(cheContainer.getVolumes()),
eq(internalEnvironment));
}
@Test
public void applyPluginInitContainerWithOneVolume() throws InfrastructureException {
lenient().when(podSpec.getInitContainers()).thenReturn(new ArrayList<>());
ChePlugin chePlugin = createChePlugin();
CheContainer initContainer = createContainer();
chePlugin.setInitContainers(singletonList(initContainer));
applier.apply(runtimeIdentity, internalEnvironment, singletonList(chePlugin));
verifyPodAndInitContainersNumber(1);
Container toolingInitContainer = getOnlyOneInitContainerFromPod(internalEnvironment);
verifyContainer(toolingInitContainer);
verify(chePluginsVolumeApplier)
.applyVolumes(
any(PodData.class),
eq(toolingInitContainer),
eq(initContainer.getVolumes()),
eq(internalEnvironment));
}
@Test
public void addsMachinesWithVolumesToAllToolingContainer() throws Exception {
// given
ChePlugin chePluginWithNonDefaultVolume = createChePlugin();
String anotherVolumeName = VOLUME_NAME + "1";
String anotherVolumeMountPath = VOLUME_MOUNT_PATH + "/something";
List<Volume> volumes =
singletonList(new Volume().name(anotherVolumeName).mountPath(anotherVolumeMountPath));
CheContainer toolingContainer = chePluginWithNonDefaultVolume.getContainers().get(0);
toolingContainer.setVolumes(volumes);
ChePlugin chePlugin = createChePlugin();
// when
applier.apply(
runtimeIdentity, internalEnvironment, asList(chePlugin, chePluginWithNonDefaultVolume));
// then
Collection<InternalMachineConfig> machineConfigs = getNonUserMachines(internalEnvironment);
assertEquals(machineConfigs.size(), 2);
verify(chePluginsVolumeApplier)
.applyVolumes(
any(PodData.class),
any(Container.class),
eq(chePlugin.getContainers().get(0).getVolumes()),
eq(internalEnvironment));
}
@Test
public void addsMachineWithVolumeFromChePlugin() throws Exception {
// given