diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java index f3827fe247e..a8e8753d00e 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java @@ -14,7 +14,6 @@ import static java.lang.String.format; import static java.util.Collections.emptyMap; import static java.util.stream.Collectors.toMap; -import static org.eclipse.che.api.workspace.shared.Constants.DEBUG_WORKSPACE_START; import static org.eclipse.che.workspace.infrastructure.kubernetes.util.TracingSpanConstants.CHECK_SERVERS; import static org.eclipse.che.workspace.infrastructure.kubernetes.util.TracingSpanConstants.WAIT_MACHINES_START; import static org.eclipse.che.workspace.infrastructure.kubernetes.util.TracingSpanConstants.WAIT_RUNNING_ASYNC; @@ -213,7 +212,8 @@ protected void internalStart(Map startOptions) throws Infrastruc volumesStrategy.prepare( context.getEnvironment(), context.getIdentity(), - startSynchronizer.getStartTimeoutMillis()); + startSynchronizer.getStartTimeoutMillis(), + startOptions); startSynchronizer.checkFailure(); @@ -633,17 +633,10 @@ protected void listenEvents() throws InfrastructureException { private void watchLogsIfDebugEnabled(Map startOptions) throws InfrastructureException { - if (startOptions == null || startOptions.isEmpty()) { - LOG.debug( - "'startOptions' is null or empty so we won't watch the container logs for workspace '{}'", + if (LogWatcher.shouldWatchLogs(startOptions)) { + LOG.info( + "Debug workspace startup. Will watch the logs of '{}'", getContext().getIdentity().getWorkspaceId()); - return; - } - boolean shouldWatchContainerStartupLogs = - Boolean.parseBoolean( - startOptions.getOrDefault(DEBUG_WORKSPACE_START, Boolean.FALSE.toString())); - - if (shouldWatchContainerStartupLogs) { // get all the pods we care about Set podNames = machines diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/log/LogWatcher.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/log/LogWatcher.java index 409b15aaf6b..8a1c0779b84 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/log/LogWatcher.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/log/LogWatcher.java @@ -11,6 +11,7 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.log; +import static org.eclipse.che.api.workspace.shared.Constants.DEBUG_WORKSPACE_START; import static org.eclipse.che.api.workspace.shared.Constants.DEBUG_WORKSPACE_START_LOG_LIMIT_BYTES; import io.fabric8.kubernetes.client.KubernetesClient; @@ -198,4 +199,20 @@ public static long getLogLimitBytes(Map startOptions) { } } } + + /** + * Takes `startOptions` map and tells whether it's set so we should watch the logs. To return + * true, flag must be stored under {@link + * org.eclipse.che.api.workspace.shared.Constants#DEBUG_WORKSPACE_START} key. + * + * @param startOptions options where we'll try to find log watch flag + * @return true if we should watch the logs, false otherwise + */ + public static boolean shouldWatchLogs(Map startOptions) { + if (startOptions == null || startOptions.isEmpty()) { + return false; + } + return Boolean.parseBoolean( + startOptions.getOrDefault(DEBUG_WORKSPACE_START, Boolean.FALSE.toString())); + } } 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 b967d361e91..63437ea7678 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 @@ -172,7 +172,11 @@ public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity) @Override @Traced - public void prepare(KubernetesEnvironment k8sEnv, RuntimeIdentity identity, long timeoutMillis) + public void prepare( + KubernetesEnvironment k8sEnv, + RuntimeIdentity identity, + long timeoutMillis, + Map startOptions) throws InfrastructureException { String workspaceId = identity.getWorkspaceId(); @@ -215,10 +219,7 @@ public void prepare(KubernetesEnvironment k8sEnv, RuntimeIdentity identity, long commonPVC.getAdditionalProperties().remove(format(SUBPATHS_PROPERTY_FMT, workspaceId)); if (preCreateDirs && subpaths != null) { pvcSubPathHelper.createDirs( - workspaceId, - identity.getInfrastructureNamespace(), - commonPVC.getMetadata().getName(), - subpaths); + identity, workspaceId, commonPVC.getMetadata().getName(), startOptions, subpaths); } log.debug("Preparing PVC done for workspace '{}'", workspaceId); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCSubPathHelper.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCSubPathHelper.java index bf9081c42e1..bcf9e32bc6a 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCSubPathHelper.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCSubPathHelper.java @@ -25,6 +25,8 @@ import io.fabric8.kubernetes.api.model.PodBuilder; import io.fabric8.kubernetes.api.model.PodStatus; import java.util.Arrays; +import java.util.Collections; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -33,14 +35,19 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler; import org.eclipse.che.commons.lang.concurrent.ThreadLocalPropagateContext; import org.eclipse.che.commons.observability.ExecutorServiceWrapper; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesDeployments; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.log.LogWatchTimeouts; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.log.LogWatcher; +import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.log.PodLogToEventPublisher; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.SecurityContextProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.util.Containers; +import org.eclipse.che.workspace.infrastructure.kubernetes.util.RuntimeEventsPublisher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -78,6 +85,7 @@ public class PVCSubPathHelper { private final String jobMemoryLimit; private final KubernetesNamespaceFactory factory; private final ExecutorService executor; + private final RuntimeEventsPublisher eventsPublisher; private final SecurityContextProvisioner securityContextProvisioner; @@ -87,11 +95,13 @@ public class PVCSubPathHelper { @Named("che.infra.kubernetes.pvc.jobs.image") String jobImage, KubernetesNamespaceFactory factory, SecurityContextProvisioner securityContextProvisioner, - ExecutorServiceWrapper executorServiceWrapper) { + ExecutorServiceWrapper executorServiceWrapper, + RuntimeEventsPublisher eventPublisher) { this.jobMemoryLimit = jobMemoryLimit; this.jobImage = jobImage; this.factory = factory; this.securityContextProvisioner = securityContextProvisioner; + this.eventsPublisher = eventPublisher; this.executor = executorServiceWrapper.wrap( Executors.newFixedThreadPool( @@ -108,16 +118,20 @@ public class PVCSubPathHelper { * Performs create workspace directories job by given paths and waits until it finished. * * @param workspaceId workspace identifier - * @param namespace * @param dirs workspace directories to create */ - void createDirs(String workspaceId, String namespace, String pvcName, String... dirs) { + void createDirs( + RuntimeIdentity identity, + String workspaceId, + String pvcName, + Map startOptions, + String... dirs) { LOG.debug( "Preparing PVC `{}` for workspace `{}`. Directories to create: {}", pvcName, workspaceId, Arrays.toString(dirs)); - execute(workspaceId, namespace, pvcName, MKDIR_COMMAND_BASE, dirs); + execute(identity, workspaceId, pvcName, MKDIR_COMMAND_BASE, startOptions, dirs); } /** @@ -140,6 +154,24 @@ CompletableFuture removeDirsAsync( executor); } + @VisibleForTesting + void execute( + RuntimeIdentity identity, + String workspaceId, + String pvcName, + String[] commandBase, + Map startOptions, + String... arguments) { + execute( + identity, + workspaceId, + identity.getInfrastructureNamespace(), + pvcName, + commandBase, + startOptions, + arguments); + } + /** * Executes the job with the specified arguments. * @@ -154,6 +186,17 @@ void execute( String pvcName, String[] commandBase, String... arguments) { + execute(null, workspaceId, namespace, pvcName, commandBase, Collections.emptyMap(), arguments); + } + + private void execute( + RuntimeIdentity identity, + String workspaceId, + String namespace, + String pvcName, + String[] commandBase, + Map startOptions, + String... arguments) { final String jobName = commandBase[0]; final String podName = jobName + '-' + workspaceId; final String[] command = buildCommand(commandBase, arguments); @@ -164,6 +207,7 @@ void execute( try { deployments = factory.access(workspaceId, namespace).deployments(); deployments.create(pod); + watchLogsIfDebugEnabled(deployments, pod, identity, startOptions); final Pod finished = deployments.wait(podName, WAIT_POD_TIMEOUT_MIN, POD_PREDICATE::apply); PodStatus finishedStatus = finished.getStatus(); if (POD_PHASE_FAILED.equals(finishedStatus.getPhase())) { @@ -179,8 +223,10 @@ void execute( Arrays.toString(command), workspaceId, ex.getMessage()); + deployments.stopWatch(true); } finally { if (deployments != null) { + deployments.stopWatch(); try { deployments.delete(podName); } catch (InfrastructureException ignored) { @@ -189,6 +235,21 @@ void execute( } } + private void watchLogsIfDebugEnabled( + KubernetesDeployments deployment, + Pod pod, + RuntimeIdentity identity, + Map startOptions) + throws InfrastructureException { + if (LogWatcher.shouldWatchLogs(startOptions)) { + deployment.watchLogs( + new PodLogToEventPublisher(eventsPublisher, identity), + LogWatchTimeouts.AGGRESSIVE, + Collections.singleton(pod.getMetadata().getName()), + LogWatcher.getLogLimitBytes(startOptions)); + } + } + /** * Builds the command by given base and paths. * diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategy.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategy.java index 9464f852aee..29ed84f5bfe 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategy.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategy.java @@ -127,7 +127,11 @@ public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity) @Traced @Override - public void prepare(KubernetesEnvironment k8sEnv, RuntimeIdentity identity, long timeoutMillis) + public void prepare( + KubernetesEnvironment k8sEnv, + RuntimeIdentity identity, + long timeoutMillis, + Map startOptions) throws InfrastructureException { String workspaceId = identity.getWorkspaceId(); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/WorkspaceVolumesStrategy.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/WorkspaceVolumesStrategy.java index 1181dea56a0..2d04e365b10 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/WorkspaceVolumesStrategy.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/WorkspaceVolumesStrategy.java @@ -11,6 +11,7 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc; +import java.util.Map; import org.eclipse.che.api.core.model.workspace.Workspace; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; @@ -45,7 +46,11 @@ void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity) * @param timeoutMillis timeout in milliseconds * @throws InfrastructureException when any error while preparation occurs */ - void prepare(KubernetesEnvironment k8sEnv, RuntimeIdentity identity, long timeoutMillis) + void prepare( + KubernetesEnvironment k8sEnv, + RuntimeIdentity identity, + long timeoutMillis, + Map startOptions) throws InfrastructureException; /** diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/PluginBrokerManager.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/PluginBrokerManager.java index deae302a1d5..33a8705bbb9 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/PluginBrokerManager.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/PluginBrokerManager.java @@ -117,7 +117,7 @@ public List getTooling( ListenBrokerEvents listenBrokerEvents = getListenEventPhase(workspaceId, brokersResult); PrepareStorage prepareStorage = - getPrepareStoragePhase(identity, startSynchronizer, brokerEnvironment); + getPrepareStoragePhase(identity, startSynchronizer, brokerEnvironment, startOptions); WaitBrokerResult waitBrokerResult = getWaitBrokerPhase(workspaceId, brokersResult); DeployBroker deployBroker = getDeployBrokerPhase( @@ -134,9 +134,10 @@ private ListenBrokerEvents getListenEventPhase(String workspaceId, BrokersResult private PrepareStorage getPrepareStoragePhase( RuntimeIdentity identity, StartSynchronizer startSynchronizer, - KubernetesEnvironment brokerEnvironment) { + KubernetesEnvironment brokerEnvironment, + Map startOptions) { return new PrepareStorage( - identity, brokerEnvironment, volumesStrategy, startSynchronizer, tracer); + identity, brokerEnvironment, volumesStrategy, startSynchronizer, tracer, startOptions); } private DeployBroker getDeployBrokerPhase( diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/DeployBroker.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/DeployBroker.java index a1f967a6574..f36fd94c5d2 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/DeployBroker.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/DeployBroker.java @@ -12,7 +12,6 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases; import static java.lang.String.format; -import static org.eclipse.che.api.workspace.shared.Constants.DEBUG_WORKSPACE_START; import static org.eclipse.che.workspace.infrastructure.kubernetes.util.TracingSpanConstants.DEPLOY_BROKER_PHASE; import static org.slf4j.LoggerFactory.getLogger; @@ -157,17 +156,9 @@ public List execute() throws InfrastructureException { private void watchLogsIfDebugEnabled(Map startOptions, Pod pluginBrokerPod) throws InfrastructureException { - if (startOptions == null || startOptions.isEmpty()) { + if (LogWatcher.shouldWatchLogs(startOptions)) { LOG.debug( - "'startOptions' is null or empty so we won't watch the plugin broker pod logs for workspace '{}'", - runtimeId.getWorkspaceId()); - return; - } - boolean shouldWatchContainerStartupLogs = - Boolean.parseBoolean( - startOptions.getOrDefault(DEBUG_WORKSPACE_START, Boolean.FALSE.toString())); - - if (shouldWatchContainerStartupLogs) { + "Will watch the logs of plugin broker of workspace '{}'", runtimeId.getWorkspaceId()); namespace .deployments() .watchLogs( diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/PrepareStorage.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/PrepareStorage.java index c068a8869cb..a5dfc2e1a9f 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/PrepareStorage.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/PrepareStorage.java @@ -17,6 +17,7 @@ import io.opentracing.Span; import io.opentracing.Tracer; import java.util.List; +import java.util.Map; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.wsplugins.model.ChePlugin; @@ -40,18 +41,21 @@ public class PrepareStorage extends BrokerPhase { private final WorkspaceVolumesStrategy volumesStrategy; private final StartSynchronizer startSynchronizer; private final Tracer tracer; + private final Map startOptions; public PrepareStorage( RuntimeIdentity identity, KubernetesEnvironment brokerEnvironment, WorkspaceVolumesStrategy volumesStrategy, StartSynchronizer startSynchronizer, - Tracer tracer) { + Tracer tracer, + Map startOptions) { this.identity = identity; this.brokerEnvironment = brokerEnvironment; this.volumesStrategy = volumesStrategy; this.startSynchronizer = startSynchronizer; this.tracer = tracer; + this.startOptions = startOptions; } @Override @@ -61,7 +65,7 @@ public List execute() throws InfrastructureException { try { volumesStrategy.prepare( - brokerEnvironment, identity, startSynchronizer.getStartTimeoutMillis()); + brokerEnvironment, identity, startSynchronizer.getStartTimeoutMillis(), startOptions); } catch (InfrastructureException e) { TracingTags.setErrorStatus(tracingSpan, e); throw e; diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/log/LogWatcherTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/log/LogWatcherTest.java index 3cdb57a7c33..012d8e88661 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/log/LogWatcherTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/log/LogWatcherTest.java @@ -13,6 +13,7 @@ import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; +import static org.eclipse.che.api.workspace.shared.Constants.DEBUG_WORKSPACE_START; import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.log.LogWatcher.DEFAULT_LOG_LIMIT_BYTES; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.times; @@ -185,4 +186,24 @@ public Object[][] logLimitData() { public void testGettingLogLimitBytes(Map startOptions, long expectedLimit) { assertEquals(LogWatcher.getLogLimitBytes(startOptions), expectedLimit); } + + @DataProvider + public Object[][] shouldWatchLogsData() { + return new Object[][] { + {null, false}, + {emptyMap(), false}, + {singletonMap("bla", "bol"), false}, + {singletonMap(DEBUG_WORKSPACE_START, "blbost"), false}, + {singletonMap(DEBUG_WORKSPACE_START, "false"), false}, + {singletonMap(DEBUG_WORKSPACE_START, "true"), true}, + {ImmutableMap.of(DEBUG_WORKSPACE_START, "true", "bla", "bol"), true}, + {ImmutableMap.of(DEBUG_WORKSPACE_START, "tttt", "bla", "bol"), false}, + }; + } + + @Test(dataProvider = "shouldWatchLogsData") + public void testShouldWatchLogsFromStartOptions( + Map startOptions, boolean expected) { + assertEquals(LogWatcher.shouldWatchLogs(startOptions), expected); + } } 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 841a2288cf1..ea783ac9357 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 @@ -13,6 +13,7 @@ import static java.lang.String.format; import static java.util.Collections.emptyList; +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.namespace.pvc.CommonPVCStrategy.SUBPATHS_PROPERTY_FMT; import static org.mockito.ArgumentMatchers.any; @@ -198,14 +199,15 @@ public void testCreatesPVCsWithSubpathsOnPrepare() throws Exception { k8sEnv.getPersistentVolumeClaims().put(PVC_NAME, pvc); doNothing() .when(pvcSubPathHelper) - .createDirs(WORKSPACE_ID, NAMESPACE, PVC_NAME, WORKSPACE_SUBPATHS); + .createDirs(IDENTITY, WORKSPACE_ID, PVC_NAME, emptyMap(), WORKSPACE_SUBPATHS); - commonPVCStrategy.prepare(k8sEnv, IDENTITY, 100); + commonPVCStrategy.prepare(k8sEnv, IDENTITY, 100, emptyMap()); verify(pvcs).get(); verify(pvcs).create(pvc); verify(pvcs).waitBound(PVC_NAME, 100); - verify(pvcSubPathHelper).createDirs(WORKSPACE_ID, NAMESPACE, PVC_NAME, WORKSPACE_SUBPATHS); + verify(pvcSubPathHelper) + .createDirs(IDENTITY, WORKSPACE_ID, PVC_NAME, emptyMap(), WORKSPACE_SUBPATHS); } @Test @@ -230,14 +232,15 @@ public void testCreatesPVCsWithSubpathsOnPrepareIfWaitIsDisabled() throws Except k8sEnv.getPersistentVolumeClaims().put(PVC_NAME, pvc); doNothing() .when(pvcSubPathHelper) - .createDirs(WORKSPACE_ID, NAMESPACE, PVC_NAME, WORKSPACE_SUBPATHS); + .createDirs(IDENTITY, WORKSPACE_ID, PVC_NAME, emptyMap(), WORKSPACE_SUBPATHS); - commonPVCStrategy.prepare(k8sEnv, IDENTITY, 100); + commonPVCStrategy.prepare(k8sEnv, IDENTITY, 100, emptyMap()); verify(pvcs).get(); verify(pvcs).create(pvc); verify(pvcs, never()).waitBound(anyString(), anyLong()); - verify(pvcSubPathHelper).createDirs(WORKSPACE_ID, NAMESPACE, PVC_NAME, WORKSPACE_SUBPATHS); + verify(pvcSubPathHelper) + .createDirs(IDENTITY, WORKSPACE_ID, PVC_NAME, emptyMap(), WORKSPACE_SUBPATHS); } @Test( @@ -250,7 +253,7 @@ public void shouldThrowExceptionIfK8sEnvHasMoreThanOnePVCOnPreparing() throws Ex k8sEnv.getPersistentVolumeClaims().put("pvc1", pvc1); k8sEnv.getPersistentVolumeClaims().put("pvc2", pvc2); - commonPVCStrategy.prepare(k8sEnv, IDENTITY, 100); + commonPVCStrategy.prepare(k8sEnv, IDENTITY, 100, emptyMap()); } @Test(expectedExceptions = InfrastructureException.class) @@ -258,7 +261,7 @@ public void throwsInfrastructureExceptionWhenFailedToGetExistingPVCs() throws Ex k8sEnv.getPersistentVolumeClaims().put(PVC_NAME, mock(PersistentVolumeClaim.class)); doThrow(InfrastructureException.class).when(pvcs).get(); - commonPVCStrategy.prepare(k8sEnv, IDENTITY, 100); + commonPVCStrategy.prepare(k8sEnv, IDENTITY, 100, emptyMap()); } @Test(expectedExceptions = InfrastructureException.class) @@ -268,7 +271,7 @@ public void throwsInfrastructureExceptionWhenPVCCreationFailed() throws Exceptio when(pvcs.get()).thenReturn(emptyList()); doThrow(InfrastructureException.class).when(pvcs).create(any()); - commonPVCStrategy.prepare(k8sEnv, IDENTITY, 100); + commonPVCStrategy.prepare(k8sEnv, IDENTITY, 100, emptyMap()); } @Test diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCSubPathHelperTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCSubPathHelperTest.java index 94887179abe..1d2dd3cb47b 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCSubPathHelperTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCSubPathHelperTest.java @@ -12,7 +12,11 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc; import static com.google.common.collect.ImmutableMap.of; +import static java.lang.Boolean.TRUE; +import static java.util.Collections.emptyMap; import static java.util.stream.Collectors.toList; +import static org.eclipse.che.api.workspace.shared.Constants.DEBUG_WORKSPACE_START; +import static org.eclipse.che.api.workspace.shared.Constants.DEBUG_WORKSPACE_START_LOG_LIMIT_BYTES; import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.PVCSubPathHelper.JOB_MOUNT_PATH; import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.PVCSubPathHelper.MKDIR_COMMAND_BASE; import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.PVCSubPathHelper.POD_PHASE_FAILED; @@ -20,6 +24,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.lenient; @@ -28,6 +33,7 @@ import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; +import com.google.common.collect.ImmutableMap; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodStatus; import io.fabric8.kubernetes.api.model.Quantity; @@ -36,12 +42,14 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Stream; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.commons.observability.NoopExecutorServiceWrapper; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesDeployments; 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.provision.SecurityContextProvisioner; +import org.eclipse.che.workspace.infrastructure.kubernetes.util.RuntimeEventsPublisher; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; @@ -72,6 +80,8 @@ public class PVCSubPathHelperTest { @Mock private KubernetesDeployments osDeployments; @Mock private Pod pod; @Mock private PodStatus podStatus; + @Mock private RuntimeEventsPublisher eventsPublisher; + @Mock private RuntimeIdentity identity; @Captor private ArgumentCaptor podCaptor; @@ -85,7 +95,9 @@ public void setup() throws Exception { jobImage, k8sNamespaceFactory, securityContextProvisioner, - new NoopExecutorServiceWrapper()); + new NoopExecutorServiceWrapper(), + eventsPublisher); + lenient().when(identity.getInfrastructureNamespace()).thenReturn(NAMESPACE); lenient().when(k8sNamespaceFactory.access(WORKSPACE_ID, NAMESPACE)).thenReturn(k8sNamespace); lenient().when(k8sNamespace.deployments()).thenReturn(osDeployments); lenient().when(pod.getStatus()).thenReturn(podStatus); @@ -111,7 +123,8 @@ public void testBuildsCommandByGivenBaseAndPaths() throws Exception { public void testSuccessfullyCreatesWorkspaceDirs() throws Exception { when(podStatus.getPhase()).thenReturn(POD_PHASE_SUCCEEDED); - pvcSubPathHelper.createDirs(WORKSPACE_ID, NAMESPACE, PVC_NAME, WORKSPACE_ID + PROJECTS_PATH); + pvcSubPathHelper.createDirs( + identity, WORKSPACE_ID, PVC_NAME, emptyMap(), WORKSPACE_ID + PROJECTS_PATH); verify(osDeployments).create(podCaptor.capture()); final List actual = podCaptor.getValue().getSpec().getContainers().get(0).getCommand(); @@ -127,11 +140,27 @@ public void testSuccessfullyCreatesWorkspaceDirs() throws Exception { verify(securityContextProvisioner).provision(any()); } + @Test + public void testWatchLogsWhenCreatingWorkspaceDirs() throws InfrastructureException { + when(podStatus.getPhase()).thenReturn(POD_PHASE_SUCCEEDED); + + pvcSubPathHelper.createDirs( + identity, + WORKSPACE_ID, + PVC_NAME, + ImmutableMap.of( + DEBUG_WORKSPACE_START, TRUE.toString(), DEBUG_WORKSPACE_START_LOG_LIMIT_BYTES, "123"), + WORKSPACE_ID + PROJECTS_PATH); + + verify(osDeployments).watchLogs(any(), any(), any(), eq(123L)); + } + @Test public void testSetMemoryLimitAndRequest() throws Exception { when(podStatus.getPhase()).thenReturn(POD_PHASE_SUCCEEDED); - pvcSubPathHelper.createDirs(WORKSPACE_ID, NAMESPACE, PVC_NAME, WORKSPACE_ID + PROJECTS_PATH); + pvcSubPathHelper.createDirs( + identity, WORKSPACE_ID, PVC_NAME, emptyMap(), WORKSPACE_ID + PROJECTS_PATH); verify(osDeployments).create(podCaptor.capture()); ResourceRequirements actual = 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 c364de6f651..c831c31efdf 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PerWorkspacePVCStrategyTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PerWorkspacePVCStrategyTest.java @@ -12,6 +12,7 @@ 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; @@ -110,14 +111,14 @@ public void shouldPreparePerWorkspacePVCWithSubPaths() throws Exception { pvc.getAdditionalProperties().put(format(SUBPATHS_PROPERTY_FMT, WORKSPACE_ID), subPaths); // when - strategy.prepare(k8sEnv, IDENTITY, 100); + strategy.prepare(k8sEnv, IDENTITY, 100, emptyMap()); // then verify(pvcs).get(); verify(pvcs).create(pvc); verify(pvcs).waitBound(perWorkspacePVCName, 100); verify(pvcSubPathHelper) - .createDirs(WORKSPACE_ID, INFRA_NAMESPACE, perWorkspacePVCName, subPaths); + .createDirs(IDENTITY, WORKSPACE_ID, perWorkspacePVCName, emptyMap(), subPaths); } @Test @@ -147,14 +148,14 @@ public void shouldPreparePerWorkspacePVCWithSubPathsWhenWaitBoundIsDisabled() th pvc.getAdditionalProperties().put(format(SUBPATHS_PROPERTY_FMT, WORKSPACE_ID), subPaths); // when - strategy.prepare(k8sEnv, IDENTITY, 100); + strategy.prepare(k8sEnv, IDENTITY, 100, emptyMap()); // then verify(pvcs).get(); verify(pvcs).create(pvc); verify(pvcs, never()).waitBound(anyString(), anyLong()); verify(pvcSubPathHelper) - .createDirs(WORKSPACE_ID, INFRA_NAMESPACE, perWorkspacePVCName, subPaths); + .createDirs(IDENTITY, WORKSPACE_ID, perWorkspacePVCName, emptyMap(), subPaths); } @Test diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategyTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategyTest.java index 586c6c2b044..b7dd67a6ed2 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategyTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategyTest.java @@ -11,6 +11,7 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc; +import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; import static org.eclipse.che.api.workspace.shared.Constants.PERSIST_VOLUMES_ATTRIBUTE; @@ -152,7 +153,7 @@ public void testCreatesProvisionedPVCsOnPrepare() throws Exception { k8sEnv.getPersistentVolumeClaims().putAll(singletonMap(uniqueName, pvc)); doReturn(pvc).when(pvcs).create(any()); - strategy.prepare(k8sEnv, IDENTITY, 100); + strategy.prepare(k8sEnv, IDENTITY, 100, emptyMap()); verify(pvcs).createIfNotExist(any()); verify(pvcs).waitBound(uniqueName, 100); @@ -174,7 +175,7 @@ public void testCreatesProvisionedPVCsOnPrepareIfWaitIsDisabled() throws Excepti k8sEnv.getPersistentVolumeClaims().putAll(singletonMap(uniqueName, pvc)); doReturn(pvc).when(pvcs).create(any()); - strategy.prepare(k8sEnv, IDENTITY, 100); + strategy.prepare(k8sEnv, IDENTITY, 100, emptyMap()); verify(pvcs).createIfNotExist(any()); verify(pvcs, never()).waitBound(anyString(), anyLong()); @@ -188,7 +189,7 @@ public void throwsInfrastructureExceptionWhenFailedToCreatePVCs() throws Excepti k8sEnv.getPersistentVolumeClaims().put(PVC_NAME_PREFIX, pvc); doThrow(InfrastructureException.class).when(pvcs).createIfNotExist(any()); - strategy.prepare(k8sEnv, IDENTITY, 100); + strategy.prepare(k8sEnv, IDENTITY, 100, emptyMap()); } @Test