diff --git a/assembly/assembly-wsmaster-war/src/main/resources/META-INF/persistence.xml b/assembly/assembly-wsmaster-war/src/main/resources/META-INF/persistence.xml index 1a974886c7..03e25ae1a5 100644 --- a/assembly/assembly-wsmaster-war/src/main/resources/META-INF/persistence.xml +++ b/assembly/assembly-wsmaster-war/src/main/resources/META-INF/persistence.xml @@ -70,7 +70,6 @@ org.eclipse.che.multiuser.machine.authentication.server.signature.model.impl.SignatureKeyPairImpl org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState - org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState.RuntimeId org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesMachineImpl org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesMachineImpl.MachineId diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/Runtime.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/Runtime.java index f97da65599..dd82a4f5f6 100644 --- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/Runtime.java +++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/Runtime.java @@ -14,6 +14,7 @@ package org.eclipse.che.api.core.model.workspace; import java.util.List; import java.util.Map; import org.eclipse.che.api.core.model.workspace.runtime.Machine; +import org.eclipse.che.commons.annotation.Nullable; /** * Defines a contract for workspace runtime. @@ -34,6 +35,7 @@ public interface Runtime { * Returns an active environment name. The environment with such name must exist in {@link * WorkspaceConfig#getEnvironments()}. */ + @Nullable String getActiveEnv(); /** diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/WorkspaceConfig.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/WorkspaceConfig.java index b55fbefd39..0e99779e64 100644 --- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/WorkspaceConfig.java +++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/WorkspaceConfig.java @@ -37,6 +37,7 @@ public interface WorkspaceConfig { * Returns default environment name. It is mandatory, implementation should guarantee that * environment with returned name exists for current workspace config. */ + @Nullable String getDefaultEnv(); /** diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/runtime/RuntimeIdentity.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/runtime/RuntimeIdentity.java index ff0e136feb..921aa8a1fc 100644 --- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/runtime/RuntimeIdentity.java +++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/runtime/RuntimeIdentity.java @@ -11,10 +11,13 @@ */ package org.eclipse.che.api.core.model.workspace.runtime; +import org.eclipse.che.commons.annotation.Nullable; + /** @author gazarenkov */ public interface RuntimeIdentity { String getWorkspaceId(); + @Nullable String getEnvName(); String getOwnerId(); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/context/AppContextImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/context/AppContextImpl.java index 9bca18da4c..01e16a2b22 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/context/AppContextImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/context/AppContextImpl.java @@ -52,6 +52,7 @@ import org.eclipse.che.ide.api.selection.SelectionChangedHandler; import org.eclipse.che.ide.api.workspace.WorkspaceReadyEvent; import org.eclipse.che.ide.api.workspace.WsAgentServerUtil; import org.eclipse.che.ide.api.workspace.event.WorkspaceStoppedEvent; +import org.eclipse.che.ide.api.workspace.model.EnvironmentImpl; import org.eclipse.che.ide.api.workspace.model.ServerImpl; import org.eclipse.che.ide.api.workspace.model.VolumeImpl; import org.eclipse.che.ide.api.workspace.model.WorkspaceImpl; @@ -286,17 +287,16 @@ public class AppContextImpl wsAgentServerUtilProvider.get().getWsAgentServerMachine().get().getName(); String activeEnv = workspace.getRuntime().getActiveEnv(); - VolumeImpl vol = - workspace - .getConfig() - .getEnvironments() - .get(activeEnv) - .getMachines() - .get(machineName) - .getVolume("projects"); + EnvironmentImpl environment = workspace.getConfig().getEnvironments().get(activeEnv); + VolumeImpl vol = null; + if (environment != null) { + vol = environment.getMachines().get(machineName).getVolume("projects"); + } // if voulme exists return its path, otherwise use backward compatible path (/projects) - if (vol != null) projectsRoot = Path.valueOf(vol.getPath()); + if (vol != null) { + projectsRoot = Path.valueOf(vol.getPath()); + } } Log.debug( diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/processes/loading/WorkspaceLoadingTrackerImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/processes/loading/WorkspaceLoadingTrackerImpl.java index 4040038d07..ce90206409 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/processes/loading/WorkspaceLoadingTrackerImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/processes/loading/WorkspaceLoadingTrackerImpl.java @@ -162,6 +162,9 @@ public class WorkspaceLoadingTrackerImpl EnvironmentImpl defaultEnvironment = appContext.getWorkspace().getConfig().getEnvironments().get(defaultEnvironmentName); + if (defaultEnvironment == null) { + return; + } Map environmentMachines = defaultEnvironment.getMachines(); for (final String machineName : environmentMachines.keySet()) { MachineConfigImpl machineConfig = environmentMachines.get(machineName); @@ -178,8 +181,10 @@ public class WorkspaceLoadingTrackerImpl EnvironmentImpl defaultEnvironment = appContext.getWorkspace().getConfig().getEnvironments().get(defaultEnvironmentName); + if (defaultEnvironment == null) { + return; + } Map machines = defaultEnvironment.getMachines(); - for (final String machineName : machines.keySet()) { MachineConfigImpl machineConfig = machines.get(machineName); view.addMachine(machineName); @@ -219,6 +224,9 @@ public class WorkspaceLoadingTrackerImpl EnvironmentImpl defaultEnvironment = appContext.getWorkspace().getConfig().getEnvironments().get(defaultEnvironmentName); + if (defaultEnvironment == null) { + return; + } Map machines = defaultEnvironment.getMachines(); for (final String machineName : machines.keySet()) { MachineConfigImpl machineConfig = machines.get(machineName); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/processes/runtime/ContextBasedRuntimeInfoProvider.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/processes/runtime/ContextBasedRuntimeInfoProvider.java index 6d8d75e024..613ddebd7d 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/processes/runtime/ContextBasedRuntimeInfoProvider.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/processes/runtime/ContextBasedRuntimeInfoProvider.java @@ -57,6 +57,10 @@ public class ContextBasedRuntimeInfoProvider implements RuntimeInfoProvider { return emptyList(); } + if (workspace.getConfig().getDefaultEnv() == null) { + return emptyList(); + } + // map with servers where probably port is set MachineConfigImpl preConfiguredRuntime = workspace diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/WorkspaceServiceClient.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/WorkspaceServiceClient.java index 112148297a..18e9e0858e 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/WorkspaceServiceClient.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/WorkspaceServiceClient.java @@ -23,6 +23,7 @@ import org.eclipse.che.api.promises.client.Function; import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.api.workspace.shared.dto.CommandDto; import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; +import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.command.CommandImpl; import org.eclipse.che.ide.api.workspace.model.WorkspaceImpl; @@ -88,8 +89,11 @@ public class WorkspaceServiceClient { * @param envName the name of the workspace environment that should be used for start * @return a promise that resolves to the {@link WorkspaceImpl}, or rejects with an error */ - Promise startById(String id, String envName) { - String url = baseHttpUrl + "/" + id + "/runtime" + "?environment=" + envName; + Promise startById(String id, @Nullable String envName) { + String url = baseHttpUrl + "/" + id + "/runtime"; + if (envName != null) { + url += "?environment=" + envName; + } return asyncRequestFactory .createPostRequest(url, null) diff --git a/infrastructures/docker/environment/pom.xml b/infrastructures/docker/environment/pom.xml index 25efbf7fad..a50f5a443c 100644 --- a/infrastructures/docker/environment/pom.xml +++ b/infrastructures/docker/environment/pom.xml @@ -71,6 +71,10 @@ org.eclipse.che.core che-core-api-workspace + + org.eclipse.che.core + che-core-commons-annotations + org.eclipse.che.core che-core-commons-lang diff --git a/infrastructures/docker/environment/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/compose/ComposeEnvironmentFactory.java b/infrastructures/docker/environment/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/compose/ComposeEnvironmentFactory.java index 0a61322101..5e6e8d7317 100644 --- a/infrastructures/docker/environment/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/compose/ComposeEnvironmentFactory.java +++ b/infrastructures/docker/environment/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/compose/ComposeEnvironmentFactory.java @@ -11,7 +11,6 @@ */ package org.eclipse.che.workspace.infrastructure.docker.environment.compose; -import static com.google.common.base.Preconditions.checkNotNull; import static java.lang.String.format; import static java.util.stream.Collectors.joining; @@ -30,7 +29,13 @@ import org.eclipse.che.api.core.ValidationException; import org.eclipse.che.api.core.model.workspace.Warning; import org.eclipse.che.api.installer.server.InstallerRegistry; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; -import org.eclipse.che.api.workspace.server.spi.environment.*; +import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironmentFactory; +import org.eclipse.che.api.workspace.server.spi.environment.InternalMachineConfig; +import org.eclipse.che.api.workspace.server.spi.environment.InternalRecipe; +import org.eclipse.che.api.workspace.server.spi.environment.MachineConfigsValidator; +import org.eclipse.che.api.workspace.server.spi.environment.MemoryAttributeProvisioner; +import org.eclipse.che.api.workspace.server.spi.environment.RecipeRetriever; +import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.workspace.infrastructure.docker.environment.compose.model.ComposeRecipe; import org.eclipse.che.workspace.infrastructure.docker.environment.compose.model.ComposeService; @@ -63,8 +68,11 @@ public class ComposeEnvironmentFactory extends InternalEnvironmentFactory machines, List warnings) + @Nullable InternalRecipe recipe, + Map machines, + List warnings) throws InfrastructureException, ValidationException { + checkNotNull(recipe, "Null recipe is not supported by compose environment factory"); String contentType = recipe.getContentType(); checkNotNull(contentType, "Recipe content type should not be null"); diff --git a/infrastructures/docker/environment/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/dockerfile/DockerfileEnvironmentFactory.java b/infrastructures/docker/environment/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/dockerfile/DockerfileEnvironmentFactory.java index 74ae1e9746..5e6b87f85b 100644 --- a/infrastructures/docker/environment/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/dockerfile/DockerfileEnvironmentFactory.java +++ b/infrastructures/docker/environment/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/dockerfile/DockerfileEnvironmentFactory.java @@ -23,6 +23,7 @@ import org.eclipse.che.api.core.model.workspace.Warning; import org.eclipse.che.api.installer.server.InstallerRegistry; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.environment.*; +import org.eclipse.che.commons.annotation.Nullable; /** @author Sergii Leshchenko */ @Singleton @@ -43,8 +44,11 @@ public class DockerfileEnvironmentFactory @Override protected DockerfileEnvironment doCreate( - InternalRecipe recipe, Map machines, List warnings) + @Nullable InternalRecipe recipe, + Map machines, + List warnings) throws InfrastructureException, ValidationException { + checkNotNull(recipe, "Null recipe is not supported by docker file environment factory"); if (!DockerfileEnvironment.TYPE.equals(recipe.getType())) { throw new ValidationException( format( @@ -66,4 +70,12 @@ public class DockerfileEnvironmentFactory memoryProvisioner.provision(machineConfig, 0L, 0L); } } + + private static void checkNotNull( + Object object, String errorMessageTemplate, Object... errorMessageParams) + throws ValidationException { + if (object == null) { + throw new ValidationException(format(errorMessageTemplate, errorMessageParams)); + } + } } diff --git a/infrastructures/docker/environment/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/dockerimage/DockerImageEnvironmentFactory.java b/infrastructures/docker/environment/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/dockerimage/DockerImageEnvironmentFactory.java index 61c1bbc830..4649bcce3f 100644 --- a/infrastructures/docker/environment/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/dockerimage/DockerImageEnvironmentFactory.java +++ b/infrastructures/docker/environment/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/dockerimage/DockerImageEnvironmentFactory.java @@ -25,6 +25,7 @@ import org.eclipse.che.api.installer.server.InstallerRegistry; import org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.environment.*; +import org.eclipse.che.commons.annotation.Nullable; /** @author Sergii Leshchenko */ @Singleton @@ -46,6 +47,8 @@ public class DockerImageEnvironmentFactory @Override public DockerImageEnvironment create(Environment sourceEnv) throws InfrastructureException, ValidationException { + checkNotNull( + sourceEnv, "Null environment is not supported by docker image environment factory"); if (sourceEnv.getRecipe().getLocation() != null) { // move image from location to content EnvironmentImpl envCopy = new EnvironmentImpl(sourceEnv); @@ -58,8 +61,11 @@ public class DockerImageEnvironmentFactory @Override protected DockerImageEnvironment doCreate( - InternalRecipe recipe, Map machines, List warnings) + @Nullable InternalRecipe recipe, + Map machines, + List warnings) throws InfrastructureException, ValidationException { + checkNotNull(recipe, "Null recipe is not supported by docker image environment factory"); if (!DockerImageEnvironment.TYPE.equals(recipe.getType())) { throw new ValidationException( format( @@ -81,4 +87,12 @@ public class DockerImageEnvironmentFactory memoryProvisioner.provision(machineConfig, 0L, 0L); } } + + private static void checkNotNull( + Object object, String errorMessageTemplate, Object... errorMessageParams) + throws ValidationException { + if (object == null) { + throw new ValidationException(format(errorMessageTemplate, errorMessageParams)); + } + } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java index 96bbad2264..0c6b68c606 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java @@ -26,12 +26,14 @@ import com.google.inject.multibindings.Multibinder; import com.google.inject.name.Names; import java.util.Map; import org.eclipse.che.api.system.server.ServiceTermination; +import org.eclipse.che.api.workspace.server.NoEnvironmentFactory; import org.eclipse.che.api.workspace.server.spi.RuntimeInfrastructure; import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironmentFactory; import org.eclipse.che.api.workspace.server.spi.provision.env.CheApiExternalEnvVarProvider; import org.eclipse.che.api.workspace.server.spi.provision.env.CheApiInternalEnvVarProvider; import org.eclipse.che.api.workspace.server.spi.provision.env.EnvVarProvider; import org.eclipse.che.api.workspace.server.wsplugins.ChePluginsApplier; +import org.eclipse.che.api.workspace.shared.Constants; import org.eclipse.che.workspace.infrastructure.docker.environment.dockerimage.DockerImageEnvironment; import org.eclipse.che.workspace.infrastructure.docker.environment.dockerimage.DockerImageEnvironmentFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.bootstrapper.KubernetesBootstrapperFactory; @@ -73,6 +75,7 @@ public class KubernetesInfraModule extends AbstractModule { factories.addBinding(KubernetesEnvironment.TYPE).to(KubernetesEnvironmentFactory.class); factories.addBinding(DockerImageEnvironment.TYPE).to(DockerImageEnvironmentFactory.class); + factories.addBinding(Constants.NO_ENVIRONMENT_RECIPE_TYPE).to(NoEnvironmentFactory.class); bind(RuntimeInfrastructure.class).to(KubernetesInfrastructure.class); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfrastructure.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfrastructure.java index 6cd6f54e84..f928518511 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfrastructure.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfrastructure.java @@ -20,11 +20,13 @@ import javax.inject.Inject; import javax.inject.Singleton; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.core.notification.EventService; +import org.eclipse.che.api.workspace.server.NoEnvironmentFactory.NoEnvInternalEnvironment; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.InternalInfrastructureException; import org.eclipse.che.api.workspace.server.spi.RuntimeInfrastructure; import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironment; import org.eclipse.che.api.workspace.server.spi.provision.InternalEnvironmentProvisioner; +import org.eclipse.che.api.workspace.shared.Constants; import org.eclipse.che.workspace.infrastructure.docker.environment.dockerimage.DockerImageEnvironment; import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesRuntimeStateCache; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; @@ -49,7 +51,10 @@ public class KubernetesInfrastructure extends RuntimeInfrastructure { KubernetesRuntimeStateCache runtimeStatusesCache) { super( NAME, - ImmutableSet.of(KubernetesEnvironment.TYPE, DockerImageEnvironment.TYPE), + ImmutableSet.of( + KubernetesEnvironment.TYPE, + DockerImageEnvironment.TYPE, + Constants.NO_ENVIRONMENT_RECIPE_TYPE), eventService, internalEnvProvisioners); this.runtimeContextFactory = runtimeContextFactory; @@ -70,10 +75,14 @@ public class KubernetesInfrastructure extends RuntimeInfrastructure { private KubernetesEnvironment asKubernetesEnv(InternalEnvironment source) throws InfrastructureException { - if (source instanceof KubernetesEnvironment) { + if (source instanceof NoEnvInternalEnvironment) { + return KubernetesEnvironment.builder() + .setAttributes(source.getAttributes()) + .setWarnings(source.getWarnings()) + .build(); + } else if (source instanceof KubernetesEnvironment) { return (KubernetesEnvironment) source; - } - if (source instanceof DockerImageEnvironment) { + } else if (source instanceof DockerImageEnvironment) { return dockerImageEnvConverter.convert((DockerImageEnvironment) source); } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/jpa/JpaKubernetesRuntimeStateCache.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/jpa/JpaKubernetesRuntimeStateCache.java index 548eec43c9..3994ea8661 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/jpa/JpaKubernetesRuntimeStateCache.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/jpa/JpaKubernetesRuntimeStateCache.java @@ -24,7 +24,6 @@ import javax.inject.Provider; import javax.inject.Singleton; import javax.persistence.EntityExistsException; import javax.persistence.EntityManager; -import javax.persistence.NoResultException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; @@ -36,7 +35,6 @@ import org.eclipse.che.core.db.jpa.DuplicateKeyException; import org.eclipse.che.workspace.infrastructure.kubernetes.cache.BeforeKubernetesRuntimeStateRemovedEvent; import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesRuntimeStateCache; import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState; -import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState.RuntimeId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -109,7 +107,7 @@ public class JpaKubernetesRuntimeStateCache implements KubernetesRuntimeStateCac throws InfrastructureException { try { return Optional.ofNullable( - managerProvider.get().find(KubernetesRuntimeState.class, new RuntimeId(runtimeId))); + managerProvider.get().find(KubernetesRuntimeState.class, runtimeId.getWorkspaceId())); } catch (RuntimeException x) { throw new InfrastructureException(x.getMessage(), x); } @@ -152,15 +150,8 @@ public class JpaKubernetesRuntimeStateCache implements KubernetesRuntimeStateCac protected Optional find(String workspaceId) throws InfrastructureException { try { - KubernetesRuntimeState queried = - managerProvider - .get() - .createNamedQuery("KubernetesRuntime.getByWorkspaceId", KubernetesRuntimeState.class) - .setParameter("workspaceId", workspaceId) - .getSingleResult(); - return Optional.of(queried); - } catch (NoResultException e) { - return Optional.empty(); + return Optional.ofNullable( + managerProvider.get().find(KubernetesRuntimeState.class, workspaceId)); } catch (RuntimeException x) { throw new InfrastructureException(x.getMessage(), x); } @@ -171,7 +162,7 @@ public class JpaKubernetesRuntimeStateCache implements KubernetesRuntimeStateCac EntityManager em = managerProvider.get(); KubernetesRuntimeState runtime = - em.find(KubernetesRuntimeState.class, new RuntimeId(runtimeIdentity)); + em.find(KubernetesRuntimeState.class, runtimeIdentity.getWorkspaceId()); if (runtime != null) { eventService @@ -245,7 +236,7 @@ public class JpaKubernetesRuntimeStateCache implements KubernetesRuntimeStateCac k8sRuntimes.find(event.getWorkspace().getId()); if (k8sRuntimeStateOpt.isPresent()) { KubernetesRuntimeState existingK8sRuntimeState = k8sRuntimeStateOpt.get(); - RuntimeId runtimeId = existingK8sRuntimeState.getRuntimeId(); + RuntimeIdentity runtimeId = existingK8sRuntimeState.getRuntimeId(); // It is not normal case when non STOPPED workspace is going to be removed. // Need to log error to investigate why it may happen diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironmentFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironmentFactory.java index 1334af93b0..93cdcf8633 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironmentFactory.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironmentFactory.java @@ -36,6 +36,7 @@ import org.eclipse.che.api.installer.server.InstallerRegistry; import org.eclipse.che.api.workspace.server.model.impl.WarningImpl; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.environment.*; +import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.Names; import org.eclipse.che.workspace.infrastructure.kubernetes.util.Containers; @@ -85,10 +86,11 @@ public class KubernetesEnvironmentFactory @Override protected KubernetesEnvironment doCreate( - InternalRecipe recipe, + @Nullable InternalRecipe recipe, Map machines, List sourceWarnings) throws InfrastructureException, ValidationException { + checkNotNull(recipe, "Null recipe is not supported by kubernetes environment factory"); List warnings = new ArrayList<>(); if (sourceWarnings != null) { warnings.addAll(sourceWarnings); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/model/KubernetesRuntimeState.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/model/KubernetesRuntimeState.java index d59df1e103..466c46843d 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/model/KubernetesRuntimeState.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/model/KubernetesRuntimeState.java @@ -13,26 +13,31 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.model; import java.util.Objects; import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.persistence.EmbeddedId; import javax.persistence.Entity; +import javax.persistence.Id; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.Table; import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +import org.eclipse.che.api.workspace.server.model.impl.RuntimeIdentityImpl; /** @author Sergii Leshchenko */ @Entity(name = "KubernetesRuntime") @Table(name = "che_k8s_runtime") @NamedQueries({ - @NamedQuery(name = "KubernetesRuntime.getAll", query = "SELECT r FROM KubernetesRuntime r"), - @NamedQuery( - name = "KubernetesRuntime.getByWorkspaceId", - query = "SELECT r FROM KubernetesRuntime r WHERE r.runtimeId.workspaceId = :workspaceId") + @NamedQuery(name = "KubernetesRuntime.getAll", query = "SELECT r FROM KubernetesRuntime r") }) public class KubernetesRuntimeState { - @EmbeddedId private RuntimeId runtimeId; + @Id + @Column(name = "workspace_id") + private String workspaceId; + + @Column(name = "env_name") + private String envName; + + @Column(name = "owner_id") + private String ownerId; @Column(name = "namespace") private String namespace; @@ -44,11 +49,9 @@ public class KubernetesRuntimeState { public KubernetesRuntimeState( RuntimeIdentity runtimeIdentity, String namespace, WorkspaceStatus status) { - this.runtimeId = - new RuntimeId( - runtimeIdentity.getWorkspaceId(), - runtimeIdentity.getEnvName(), - runtimeIdentity.getOwnerId()); + this.envName = runtimeIdentity.getEnvName(); + this.workspaceId = runtimeIdentity.getWorkspaceId(); + this.ownerId = runtimeIdentity.getOwnerId(); this.namespace = namespace; this.status = status; } @@ -61,8 +64,8 @@ public class KubernetesRuntimeState { return namespace; } - public RuntimeId getRuntimeId() { - return runtimeId; + public RuntimeIdentity getRuntimeId() { + return new RuntimeIdentityImpl(workspaceId, envName, ownerId); } public WorkspaceStatus getStatus() { @@ -79,33 +82,38 @@ public class KubernetesRuntimeState { } @Override - public boolean equals(Object obj) { - if (this == obj) { + public boolean equals(Object o) { + if (this == o) { return true; } - if (!(obj instanceof KubernetesRuntimeState)) { + if (!(o instanceof KubernetesRuntimeState)) { return false; } - final KubernetesRuntimeState that = (KubernetesRuntimeState) obj; - return Objects.equals(runtimeId, that.runtimeId) - && Objects.equals(namespace, that.namespace) - && Objects.equals(status, that.status); + KubernetesRuntimeState that = (KubernetesRuntimeState) o; + return Objects.equals(workspaceId, that.workspaceId) + && Objects.equals(envName, that.envName) + && Objects.equals(ownerId, that.ownerId) + && Objects.equals(getNamespace(), that.getNamespace()) + && getStatus() == that.getStatus(); } @Override public int hashCode() { - int hash = 7; - hash = 31 * hash + Objects.hashCode(runtimeId); - hash = 31 * hash + Objects.hashCode(namespace); - hash = 31 * hash + Objects.hashCode(status); - return hash; + return Objects.hash(workspaceId, envName, ownerId, getNamespace(), getStatus()); } @Override public String toString() { return "KubernetesRuntimeState{" - + "runtimeId=" - + runtimeId + + "workspaceId='" + + workspaceId + + '\'' + + ", envName='" + + envName + + '\'' + + ", ownerId='" + + ownerId + + '\'' + ", namespace='" + namespace + '\'' @@ -113,82 +121,4 @@ public class KubernetesRuntimeState { + status + '}'; } - - @Embeddable - public static class RuntimeId implements RuntimeIdentity { - - @Column(name = "workspace_id") - private String workspaceId; - - @Column(name = "env_name") - private String envName; - - @Column(name = "owner_id") - private String ownerId; - - public RuntimeId() {} - - public RuntimeId(String workspaceId, String envName, String ownerId) { - this.workspaceId = workspaceId; - this.envName = envName; - this.ownerId = ownerId; - } - - public RuntimeId(RuntimeIdentity identity) { - this(identity.getWorkspaceId(), identity.getEnvName(), identity.getOwnerId()); - } - - @Override - public String getWorkspaceId() { - return workspaceId; - } - - @Override - public String getEnvName() { - return envName; - } - - @Override - public String getOwnerId() { - return ownerId; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof RuntimeId)) { - return false; - } - final RuntimeId that = (RuntimeId) obj; - return Objects.equals(workspaceId, that.workspaceId) - && Objects.equals(envName, that.envName) - && Objects.equals(ownerId, that.ownerId); - } - - @Override - public int hashCode() { - int hash = 7; - hash = 31 * hash + Objects.hashCode(workspaceId); - hash = 31 * hash + Objects.hashCode(envName); - hash = 31 * hash + Objects.hashCode(ownerId); - return hash; - } - - @Override - public String toString() { - return "RuntimeId{" - + "workspaceId='" - + workspaceId - + '\'' - + ", envName='" - + envName - + '\'' - + ", ownerId='" - + ownerId - + '\'' - + '}'; - } - } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java index 72cc51754e..6a300b28a9 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java @@ -19,6 +19,7 @@ import com.google.common.collect.Sets; import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.EnvVar; import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodBuilder; import io.fabric8.kubernetes.api.model.Service; import java.util.Collection; import java.util.List; @@ -49,6 +50,8 @@ public class KubernetesPluginsToolingApplier implements ChePluginsApplier { private static final Set validImagePullPolicies = Sets.newHashSet("Always", "Never", "IfNotPresent"); + private static final String CHE_WORKSPACE_POD = "che-workspace-pod"; + private final String defaultSidecarMemoryLimitBytes; private final String sidecarImagePullPolicy; private final boolean isAuthEnabled; @@ -74,9 +77,15 @@ public class KubernetesPluginsToolingApplier implements ChePluginsApplier { KubernetesEnvironment kubernetesEnvironment = (KubernetesEnvironment) internalEnvironment; Map pods = kubernetesEnvironment.getPods(); - if (pods.size() != 1) { - throw new InfrastructureException( - "Che plugins tooling configuration can be applied to a workspace with one pod only"); + switch (pods.size()) { + case 0: + addToolingPod(kubernetesEnvironment); + break; + case 1: + break; + default: + throw new InfrastructureException( + "Che plugins tooling configuration can be applied to a workspace with one pod only"); } Pod pod = pods.values().iterator().next(); @@ -94,6 +103,19 @@ public class KubernetesPluginsToolingApplier implements ChePluginsApplier { } } + private void addToolingPod(KubernetesEnvironment kubernetesEnvironment) { + Pod pod = + new PodBuilder() + .withNewMetadata() + .withName(CHE_WORKSPACE_POD) + .endMetadata() + .withNewSpec() + .endSpec() + .build(); + + kubernetesEnvironment.getPods().put(CHE_WORKSPACE_POD, pod); + } + private void populateWorkspaceEnvVars( ChePlugin chePlugin, KubernetesEnvironment kubernetesEnvironment) { diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/BrokerEnvironmentFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/BrokerEnvironmentFactory.java index bb9e41fbd9..6fadf9b2e4 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/BrokerEnvironmentFactory.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/BrokerEnvironmentFactory.java @@ -16,6 +16,7 @@ import static java.lang.String.format; import static java.util.Collections.singletonMap; import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import com.google.gson.Gson; @@ -166,7 +167,9 @@ public abstract class BrokerEnvironmentFactory "-runtime-id", String.format( "%s:%s:%s", - runtimeId.getWorkspaceId(), runtimeId.getEnvName(), runtimeId.getOwnerId())) + runtimeId.getWorkspaceId(), + MoreObjects.firstNonNull(runtimeId.getEnvName(), ""), + runtimeId.getOwnerId())) .withImagePullPolicy(brokerPullPolicy) .withVolumeMounts( new VolumeMount(CONF_FOLDER + "/", null, brokerVolumeName, true, null)) diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java index 070d0bf5f6..a2849fd94a 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java @@ -110,7 +110,6 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.environment.Kubernete import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesMachineImpl; import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesMachineImpl.MachineId; import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState; -import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState.RuntimeId; import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesServerImpl; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesConfigsMaps; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesDeployments; @@ -859,7 +858,7 @@ public class KubernetesInternalRuntimeTest { } private static class MapBasedRuntimeStateCache implements KubernetesRuntimeStateCache { - private Map runtimesStates = new HashMap<>(); + private Map runtimesStates = new HashMap<>(); @Override public Set getIdentities() throws InfrastructureException { @@ -874,14 +873,14 @@ public class KubernetesInternalRuntimeTest { @Override public void updateStatus(RuntimeIdentity runtimeId, WorkspaceStatus newStatus) throws InfrastructureException { - runtimesStates.get(new RuntimeId(runtimeId)).setStatus(newStatus); + runtimesStates.get(new RuntimeIdentityImpl(runtimeId)).setStatus(newStatus); } @Override public boolean updateStatus( RuntimeIdentity identity, Predicate predicate, WorkspaceStatus newStatus) throws InfrastructureException { - KubernetesRuntimeState state = runtimesStates.get(new RuntimeId(identity)); + KubernetesRuntimeState state = runtimesStates.get(new RuntimeIdentityImpl(identity)); if (predicate.test(state.getStatus())) { state.setStatus(newStatus); return true; @@ -891,18 +890,18 @@ public class KubernetesInternalRuntimeTest { @Override public WorkspaceStatus getStatus(RuntimeIdentity runtimeId) throws InfrastructureException { - return runtimesStates.get(new RuntimeId(runtimeId)).getStatus(); + return runtimesStates.get(new RuntimeIdentityImpl(runtimeId)).getStatus(); } @Override public Optional get(RuntimeIdentity runtimeId) throws InfrastructureException { - return Optional.ofNullable(runtimesStates.get(new RuntimeId(runtimeId))); + return Optional.ofNullable(runtimesStates.get(new RuntimeIdentityImpl(runtimeId))); } @Override public void remove(RuntimeIdentity runtimeId) throws InfrastructureException { - runtimesStates.remove(new RuntimeId(runtimeId)); + runtimesStates.remove(new RuntimeIdentityImpl(runtimeId)); } } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/jpa/JpaTckModule.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/jpa/JpaTckModule.java index 737d1c5e6e..76ee394a3c 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/jpa/JpaTckModule.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/jpa/JpaTckModule.java @@ -38,7 +38,6 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesRunti import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesMachineImpl; import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesMachineImpl.MachineId; import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState; -import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState.RuntimeId; import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesServerImpl; import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesServerImpl.ServerId; import org.h2.Driver; @@ -65,7 +64,6 @@ public class JpaTckModule extends TckModule { CommandImpl.class, AccountImpl.class, KubernetesRuntimeState.class, - RuntimeId.class, KubernetesMachineImpl.class, MachineId.class, KubernetesServerImpl.class, diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/KubernetesMachinesCacheTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/KubernetesMachinesCacheTest.java index 49e2428269..8bda90caee 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/KubernetesMachinesCacheTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/KubernetesMachinesCacheTest.java @@ -12,7 +12,10 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.cache.tck; import static java.util.Arrays.asList; -import static org.eclipse.che.workspace.infrastructure.kubernetes.cache.tck.TestObjects.*; +import static org.eclipse.che.workspace.infrastructure.kubernetes.cache.tck.TestObjects.createMachine; +import static org.eclipse.che.workspace.infrastructure.kubernetes.cache.tck.TestObjects.createRuntimeState; +import static org.eclipse.che.workspace.infrastructure.kubernetes.cache.tck.TestObjects.createServer; +import static org.eclipse.che.workspace.infrastructure.kubernetes.cache.tck.TestObjects.createWorkspace; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -23,6 +26,7 @@ import java.util.Optional; import javax.inject.Inject; import org.eclipse.che.account.spi.AccountImpl; import org.eclipse.che.api.core.model.workspace.runtime.MachineStatus; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.core.model.workspace.runtime.ServerStatus; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; @@ -32,7 +36,6 @@ import org.eclipse.che.commons.test.tck.repository.TckRepositoryException; import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesMachineCache; import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesMachineImpl; import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState; -import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState.RuntimeId; import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesServerImpl; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; @@ -150,7 +153,7 @@ public class KubernetesMachinesCacheTest { @Test public void shouldGetMachines() throws Exception { // given - RuntimeId runtimeId = runtimeStates[0].getRuntimeId(); + RuntimeIdentity runtimeId = runtimeStates[0].getRuntimeId(); // when machineCache.getMachines(runtimeId); @@ -165,7 +168,7 @@ public class KubernetesMachinesCacheTest { @Test public void shouldGetServer() throws Exception { // given - RuntimeId runtimeId = runtimeStates[0].getRuntimeId(); + RuntimeIdentity runtimeId = runtimeStates[0].getRuntimeId(); KubernetesMachineImpl machine = machines[0]; Entry serverToFetch = machine.getServers().entrySet().iterator().next(); @@ -183,7 +186,7 @@ public class KubernetesMachinesCacheTest { expectedExceptionsMessageRegExp = "Server with name 'non-existing' was not found") public void shouldThrowExceptionWhenServerWasNotFoundOnGetting() throws Exception { // given - RuntimeId runtimeId = runtimeStates[0].getRuntimeId(); + RuntimeIdentity runtimeId = runtimeStates[0].getRuntimeId(); KubernetesMachineImpl machine = machines[0]; // when @@ -193,7 +196,7 @@ public class KubernetesMachinesCacheTest { @Test public void shouldUpdateMachineStatusServerStatus() throws Exception { // given - RuntimeId runtimeId = runtimeStates[0].getRuntimeId(); + RuntimeIdentity runtimeId = runtimeStates[0].getRuntimeId(); // when machineCache.updateServerStatus( @@ -209,7 +212,7 @@ public class KubernetesMachinesCacheTest { expectedExceptionsMessageRegExp = "Server with name 'non-existing' was not found") public void shouldThrowExceptionWhenServerWasNotFoundOnStatusUpdating() throws Exception { // given - RuntimeId runtimeId = runtimeStates[0].getRuntimeId(); + RuntimeIdentity runtimeId = runtimeStates[0].getRuntimeId(); KubernetesMachineImpl machine = machines[0]; // when @@ -220,7 +223,7 @@ public class KubernetesMachinesCacheTest { @Test public void shouldUpdateMachineStatus() throws Exception { // given - RuntimeId runtimeId = runtimeStates[0].getRuntimeId(); + RuntimeIdentity runtimeId = runtimeStates[0].getRuntimeId(); KubernetesMachineImpl machine = machines[0]; String machineName = machine.getName(); @@ -243,7 +246,7 @@ public class KubernetesMachinesCacheTest { @Test public void shouldUpdateServerStatus() throws Exception { // given - RuntimeId runtimeId = runtimeStates[0].getRuntimeId(); + RuntimeIdentity runtimeId = runtimeStates[0].getRuntimeId(); // when machineCache.updateServerStatus( @@ -257,7 +260,7 @@ public class KubernetesMachinesCacheTest { @Test public void shouldRemoveMachines() throws Exception { // given - RuntimeId runtimeId = runtimeStates[0].getRuntimeId(); + RuntimeIdentity runtimeId = runtimeStates[0].getRuntimeId(); // when machineCache.remove(runtimeId); diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/KubernetesRuntimeStateCacheTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/KubernetesRuntimeStateCacheTest.java index b544003bb9..3b7ead0fdc 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/KubernetesRuntimeStateCacheTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/KubernetesRuntimeStateCacheTest.java @@ -25,6 +25,7 @@ import javax.inject.Inject; import org.eclipse.che.account.spi.AccountImpl; import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; 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.WorkspaceImpl; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.commons.test.tck.TckListener; @@ -32,7 +33,6 @@ import org.eclipse.che.commons.test.tck.repository.TckRepository; import org.eclipse.che.commons.test.tck.repository.TckRepositoryException; import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesRuntimeStateCache; import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState; -import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState.RuntimeId; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Listeners; @@ -140,7 +140,7 @@ public class KubernetesRuntimeStateCacheTest { public void shouldThrowExceptionWhenThereIsNotRuntimeStateWhileStatusRetrieving() throws Exception { // when - runtimesStatesCache.getStatus(new RuntimeId("non-existent-ws", "defEnv", "acc1")); + runtimesStatesCache.getStatus(new RuntimeIdentityImpl("non-existent-ws", "defEnv", "acc1")); } @Test(dependsOnMethods = "shouldReturnRuntimeStatus") @@ -203,7 +203,7 @@ public class KubernetesRuntimeStateCacheTest { throws Exception { // when runtimesStatesCache.updateStatus( - new RuntimeId("non-existent-ws", "defEnv", "acc1"), WorkspaceStatus.STOPPED); + new RuntimeIdentityImpl("non-existent-ws", "defEnv", "acc1"), WorkspaceStatus.STOPPED); } @Test( @@ -214,7 +214,7 @@ public class KubernetesRuntimeStateCacheTest { throws Exception { // when runtimesStatesCache.updateStatus( - new RuntimeId("non-existent-ws", "defEnv", "acc1"), + new RuntimeIdentityImpl("non-existent-ws", "defEnv", "acc1"), s -> s.equals(WorkspaceStatus.STOPPING), WorkspaceStatus.STOPPED); } @@ -255,7 +255,7 @@ public class KubernetesRuntimeStateCacheTest { public void shouldRemoveRuntimeState() throws Exception { // given KubernetesRuntimeState runtimeState = createRuntimeState(workspaces[0]); - RuntimeId toRemove = runtimeState.getRuntimeId(); + RuntimeIdentity toRemove = runtimeState.getRuntimeId(); // when runtimesStatesCache.remove(toRemove); @@ -268,7 +268,7 @@ public class KubernetesRuntimeStateCacheTest { public void shouldDoNothingIfStateIsAlreadyRemove() throws Exception { // given KubernetesRuntimeState runtimeState = createRuntimeState(workspaces[2]); - RuntimeId toRemove = runtimeState.getRuntimeId(); + RuntimeIdentity toRemove = runtimeState.getRuntimeId(); // when runtimesStatesCache.remove(toRemove); diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/TestObjects.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/TestObjects.java index fc57788188..cf356e33d1 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/TestObjects.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/TestObjects.java @@ -21,12 +21,12 @@ import org.eclipse.che.account.spi.AccountImpl; import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; import org.eclipse.che.api.core.model.workspace.runtime.MachineStatus; import org.eclipse.che.api.core.model.workspace.runtime.ServerStatus; +import org.eclipse.che.api.workspace.server.model.impl.RuntimeIdentityImpl; import org.eclipse.che.api.workspace.server.model.impl.ServerImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesMachineImpl; import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState; -import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState.RuntimeId; /** @author Sergii Leshchenko */ public class TestObjects { @@ -51,7 +51,7 @@ public class TestObjects { public static KubernetesRuntimeState createRuntimeState(WorkspaceImpl workspace) { return new KubernetesRuntimeState( - new RuntimeId(workspace.getId(), "defEnv", workspace.getAccount().getId()), + new RuntimeIdentityImpl(workspace.getId(), "defEnv", workspace.getAccount().getId()), generate("namespace", 5), WorkspaceStatus.RUNNING); } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplierTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplierTest.java index 51e3bc7621..db90ca5752 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplierTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplierTest.java @@ -21,9 +21,8 @@ import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMO import static org.eclipse.che.commons.lang.NameGenerator.generate; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_ORIGINAL_NAME_LABEL; import static org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactoryProvider.SECURE_EXPOSER_IMPL_PROPERTY; -import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNull; @@ -83,40 +82,29 @@ public class KubernetesPluginsToolingApplierTest { @Mock Pod pod; @Mock PodSpec podSpec; @Mock ObjectMeta meta; - @Mock KubernetesEnvironment internalEnvironment; @Mock Container userContainer; @Mock InternalMachineConfig userMachineConfig; - List containers; - KubernetesPluginsToolingApplier applier; + private KubernetesEnvironment internalEnvironment; + private List containers; + private KubernetesPluginsToolingApplier applier; @BeforeMethod public void setUp() { + internalEnvironment = spy(KubernetesEnvironment.builder().build()); applier = new KubernetesPluginsToolingApplier(TEST_IMAGE_POLICY, MEMORY_LIMIT_MB, false); Map machines = new HashMap<>(); containers = new ArrayList<>(); - Map services = new HashMap<>(); - containers.add(userContainer); machines.put(USER_MACHINE_NAME, userMachineConfig); - when(internalEnvironment.getPods()).thenReturn(of(POD_NAME, pod)); + internalEnvironment.getPods().put(POD_NAME, pod); when(pod.getSpec()).thenReturn(podSpec); when(podSpec.getContainers()).thenReturn(containers); when(pod.getMetadata()).thenReturn(meta); when(meta.getName()).thenReturn(POD_NAME); - when(internalEnvironment.getMachines()).thenReturn(machines); - lenient().when(internalEnvironment.getServices()).thenReturn(services); - Map attributes = new HashMap<>(); - when(internalEnvironment.getAttributes()).thenReturn(attributes); - } - - @Test - public void doesNothingIfChePluginsListIsEmpty() throws Exception { - applier.apply(internalEnvironment, emptyList()); - - verifyZeroInteractions(internalEnvironment); + internalEnvironment.getMachines().putAll(machines); } @Test( @@ -138,6 +126,17 @@ public class KubernetesPluginsToolingApplierTest { verifyContainer(toolingContainer); } + @Test + public void createsPodAndAddToolingIfNoPodIsPresent() throws Exception { + internalEnvironment.getPods().clear(); + + applier.apply(internalEnvironment, singletonList(createChePlugin())); + + verifyPodAndContainersNumber(1); + Container toolingContainer = getOneAndOnlyNonUserContainer(internalEnvironment); + verifyContainer(toolingContainer); + } + @Test public void canAddMultipleToolingContainersToAPodFromOnePlugin() throws Exception { applier.apply(internalEnvironment, singletonList(createChePluginWith2Containers())); diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java index 6a07ec6f2e..6b651d9b05 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java @@ -22,12 +22,14 @@ import com.google.inject.multibindings.MapBinder; import com.google.inject.multibindings.Multibinder; import com.google.inject.name.Names; import org.eclipse.che.api.system.server.ServiceTermination; +import org.eclipse.che.api.workspace.server.NoEnvironmentFactory; import org.eclipse.che.api.workspace.server.spi.RuntimeInfrastructure; import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironmentFactory; import org.eclipse.che.api.workspace.server.spi.provision.env.CheApiExternalEnvVarProvider; import org.eclipse.che.api.workspace.server.spi.provision.env.CheApiInternalEnvVarProvider; import org.eclipse.che.api.workspace.server.spi.provision.env.EnvVarProvider; import org.eclipse.che.api.workspace.server.wsplugins.ChePluginsApplier; +import org.eclipse.che.api.workspace.shared.Constants; import org.eclipse.che.workspace.infrastructure.docker.environment.dockerimage.DockerImageEnvironment; import org.eclipse.che.workspace.infrastructure.docker.environment.dockerimage.DockerImageEnvironmentFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientTermination; @@ -73,6 +75,7 @@ public class OpenShiftInfraModule extends AbstractModule { factories.addBinding(OpenShiftEnvironment.TYPE).to(OpenShiftEnvironmentFactory.class); factories.addBinding(KubernetesEnvironment.TYPE).to(KubernetesEnvironmentFactory.class); factories.addBinding(DockerImageEnvironment.TYPE).to(DockerImageEnvironmentFactory.class); + factories.addBinding(Constants.NO_ENVIRONMENT_RECIPE_TYPE).to(NoEnvironmentFactory.class); bind(RuntimeInfrastructure.class).to(OpenShiftInfrastructure.class); diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructure.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructure.java index 0f2a875439..22c2b39605 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructure.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructure.java @@ -20,11 +20,13 @@ import javax.inject.Inject; import javax.inject.Singleton; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.core.notification.EventService; +import org.eclipse.che.api.workspace.server.NoEnvironmentFactory.NoEnvInternalEnvironment; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.InternalInfrastructureException; import org.eclipse.che.api.workspace.server.spi.RuntimeInfrastructure; import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironment; import org.eclipse.che.api.workspace.server.spi.provision.InternalEnvironmentProvisioner; +import org.eclipse.che.api.workspace.shared.Constants; import org.eclipse.che.workspace.infrastructure.docker.environment.dockerimage.DockerImageEnvironment; import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesRuntimeStateCache; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; @@ -51,7 +53,10 @@ public class OpenShiftInfrastructure extends RuntimeInfrastructure { super( NAME, ImmutableSet.of( - OpenShiftEnvironment.TYPE, KubernetesEnvironment.TYPE, DockerImageEnvironment.TYPE), + OpenShiftEnvironment.TYPE, + KubernetesEnvironment.TYPE, + DockerImageEnvironment.TYPE, + Constants.NO_ENVIRONMENT_RECIPE_TYPE), eventService, internalEnvProvisioners); this.runtimeContextFactory = runtimeContextFactory; @@ -72,15 +77,16 @@ public class OpenShiftInfrastructure extends RuntimeInfrastructure { private OpenShiftEnvironment asOpenShiftEnv(InternalEnvironment source) throws InfrastructureException { - if (source instanceof OpenShiftEnvironment) { + if (source instanceof NoEnvInternalEnvironment) { + return OpenShiftEnvironment.builder() + .setAttributes(source.getAttributes()) + .setWarnings(source.getWarnings()) + .build(); + } else if (source instanceof OpenShiftEnvironment) { return (OpenShiftEnvironment) source; - } - - if (source instanceof KubernetesEnvironment) { + } else if (source instanceof KubernetesEnvironment) { return new OpenShiftEnvironment((KubernetesEnvironment) source); - } - - if (source instanceof DockerImageEnvironment) { + } else if (source instanceof DockerImageEnvironment) { KubernetesEnvironment k8sEnv = dockerImageEnvConverter.convert((DockerImageEnvironment) source); return new OpenShiftEnvironment(k8sEnv); diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironment.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironment.java index 3af1455273..0ba15fca00 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironment.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironment.java @@ -135,6 +135,12 @@ public class OpenShiftEnvironment extends KubernetesEnvironment { return this; } + @Override + public Builder setAttributes(Map attributes) { + this.attributes.putAll(attributes); + return this; + } + public Builder setRoutes(Map route) { this.routes.putAll(route); return this; diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentFactory.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentFactory.java index bdb01e59dc..2d872eabab 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentFactory.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentFactory.java @@ -37,6 +37,7 @@ import org.eclipse.che.api.installer.server.InstallerRegistry; import org.eclipse.che.api.workspace.server.model.impl.WarningImpl; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.environment.*; +import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.workspace.infrastructure.kubernetes.Names; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironmentValidator; import org.eclipse.che.workspace.infrastructure.kubernetes.util.Containers; @@ -86,10 +87,11 @@ public class OpenShiftEnvironmentFactory extends InternalEnvironmentFactory machines, List sourceWarnings) throws InfrastructureException, ValidationException { + checkNotNull(recipe, "Null recipe is not supported by openshift environment factory"); List warnings = new ArrayList<>(); if (sourceWarnings != null) { warnings.addAll(sourceWarnings); diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/EnvironmentRamCalculator.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/EnvironmentRamCalculator.java index bd1635c61b..a0cfca4c7e 100644 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/EnvironmentRamCalculator.java +++ b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/EnvironmentRamCalculator.java @@ -25,6 +25,7 @@ import org.eclipse.che.api.core.model.workspace.config.MachineConfig; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironment; import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironmentFactory; +import org.eclipse.che.commons.annotation.Nullable; /** * Helps to calculate amount of RAM defined in {@link Environment environment} @@ -46,7 +47,10 @@ public class EnvironmentRamCalculator { * Parses (and fetches if needed) recipe of environment and sums RAM size of all machines in * environment in megabytes. */ - public long calculate(Environment environment) throws ServerException { + public long calculate(@Nullable Environment environment) throws ServerException { + if (environment == null) { + return 0; + } try { return getInternalEnvironment(environment) .getMachines() diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RamResourceUsageTracker.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RamResourceUsageTracker.java index f3f44b4e2e..1bdad6b8ee 100644 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RamResourceUsageTracker.java +++ b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RamResourceUsageTracker.java @@ -77,7 +77,9 @@ public class RamResourceUsageTracker implements ResourceUsageTracker { .getConfig() .getEnvironments() .get(activeWorkspace.getRuntime().getActiveEnv()); - currentlyUsedRamMB += environmentRamCalculator.calculate(startingEnvironment); + if (startingEnvironment != null) { + currentlyUsedRamMB += environmentRamCalculator.calculate(startingEnvironment); + } } else { currentlyUsedRamMB += environmentRamCalculator.calculate(activeWorkspace.getRuntime()); } diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/workspace/LimitsCheckingWorkspaceManager.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/workspace/LimitsCheckingWorkspaceManager.java index ab403a434d..18841cce14 100644 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/workspace/LimitsCheckingWorkspaceManager.java +++ b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/workspace/LimitsCheckingWorkspaceManager.java @@ -157,6 +157,9 @@ public class LimitsCheckingWorkspaceManager extends WorkspaceManager { if (maxRamPerEnvMB < 0) { return; } + if (config.getEnvironments().isEmpty()) { + return; + } for (Map.Entry envEntry : config.getEnvironments().entrySet()) { Environment env = envEntry.getValue(); final long workspaceRam = environmentRamCalculator.calculate(env); @@ -181,6 +184,9 @@ public class LimitsCheckingWorkspaceManager extends WorkspaceManager { String accountId, String namespace, WorkspaceConfig config, @Nullable String envName) throws NotFoundException, ServerException, ConflictException { + if (config.getEnvironments().isEmpty()) { + return; + } final Environment environment = config.getEnvironments().get(firstNonNull(envName, config.getDefaultEnv())); final ResourceImpl ramToUse = diff --git a/selenium/che-selenium-core/src/main/java/org/eclipse/che/selenium/core/client/CheTestWorkspaceServiceClient.java b/selenium/che-selenium-core/src/main/java/org/eclipse/che/selenium/core/client/CheTestWorkspaceServiceClient.java index 5fa5831298..b40e526661 100644 --- a/selenium/che-selenium-core/src/main/java/org/eclipse/che/selenium/core/client/CheTestWorkspaceServiceClient.java +++ b/selenium/che-selenium-core/src/main/java/org/eclipse/che/selenium/core/client/CheTestWorkspaceServiceClient.java @@ -65,7 +65,6 @@ public class CheTestWorkspaceServiceClient extends AbstractTestWorkspaceServiceC workspace.getEnvironments().put(workspaceName, environment); workspace.setName(workspaceName); workspace.setDefaultEnv(workspaceName); - WorkspaceDto workspaceDto = requestFactory .fromUrl(getBaseUrl()) diff --git a/selenium/che-selenium-test/src/test/java/org/eclipse/che/selenium/gwt/CheckSimpleGwtAppTest.java b/selenium/che-selenium-test/src/test/java/org/eclipse/che/selenium/gwt/CheckSimpleGwtAppTest.java index 77fb0b3d01..1275985322 100644 --- a/selenium/che-selenium-test/src/test/java/org/eclipse/che/selenium/gwt/CheckSimpleGwtAppTest.java +++ b/selenium/che-selenium-test/src/test/java/org/eclipse/che/selenium/gwt/CheckSimpleGwtAppTest.java @@ -75,7 +75,6 @@ public class CheckSimpleGwtAppTest { WorkspaceConfigDto workspace = workspaceDtoDeserializer.deserializeWorkspaceTemplate(UBUNTU_JDK8); - workspace .getEnvironments() .get("replaced_name") diff --git a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/Constants.java b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/Constants.java index fe86edc1c6..1da44c0dbf 100644 --- a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/Constants.java +++ b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/Constants.java @@ -160,5 +160,7 @@ public final class Constants { public static final String SUPPORTED_RECIPE_TYPES = "supportedRecipeTypes"; + public static final String NO_ENVIRONMENT_RECIPE_TYPE = "no-environment"; + private Constants() {} } diff --git a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/WorkspaceConfigDto.java b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/WorkspaceConfigDto.java index 53c3f97de8..5741ceb849 100644 --- a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/WorkspaceConfigDto.java +++ b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/WorkspaceConfigDto.java @@ -35,7 +35,7 @@ public interface WorkspaceConfigDto extends WorkspaceConfig, Hyperlinks { void setName(String name); @Override - @FactoryParameter(obligation = MANDATORY) + @FactoryParameter(obligation = OPTIONAL) String getDefaultEnv(); void setDefaultEnv(String defaultEnvironment); @@ -67,7 +67,7 @@ public interface WorkspaceConfigDto extends WorkspaceConfig, Hyperlinks { WorkspaceConfigDto withProjects(List projects); @Override - @FactoryParameter(obligation = MANDATORY) + @FactoryParameter(obligation = OPTIONAL) Map getEnvironments(); void setEnvironments(Map environments); diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/NoEnvironmentFactory.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/NoEnvironmentFactory.java new file mode 100644 index 0000000000..8ce8fe8fd6 --- /dev/null +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/NoEnvironmentFactory.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012-2018 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.api.workspace.server; + +import java.util.List; +import java.util.Map; +import javax.inject.Inject; +import org.eclipse.che.api.core.model.workspace.Warning; +import org.eclipse.che.api.installer.server.InstallerRegistry; +import org.eclipse.che.api.workspace.server.spi.InternalInfrastructureException; +import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironment; +import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironmentFactory; +import org.eclipse.che.api.workspace.server.spi.environment.InternalMachineConfig; +import org.eclipse.che.api.workspace.server.spi.environment.InternalRecipe; +import org.eclipse.che.api.workspace.server.spi.environment.MachineConfigsValidator; +import org.eclipse.che.api.workspace.server.spi.environment.RecipeRetriever; +import org.eclipse.che.commons.annotation.Nullable; + +/** + * Fake environment factory for a case when sidecar-based workspace has no environment. + * + * @author Alexander Garagatyi + */ +public class NoEnvironmentFactory extends InternalEnvironmentFactory { + + @Inject + public NoEnvironmentFactory( + InstallerRegistry installerRegistry, + RecipeRetriever recipeRetriever, + MachineConfigsValidator machinesValidator) { + super(installerRegistry, recipeRetriever, machinesValidator); + } + + @Override + protected InternalEnvironment doCreate( + @Nullable InternalRecipe recipe, + Map machines, + List warnings) + throws InternalInfrastructureException { + if (recipe != null) { + throw new InternalInfrastructureException( + "No environment factory doesn't accept non-null workspace recipes"); + } + return new NoEnvInternalEnvironment(); + } + + public static class NoEnvInternalEnvironment extends InternalEnvironment {} +} diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/SidecarToolingWorkspaceUtil.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/SidecarToolingWorkspaceUtil.java new file mode 100644 index 0000000000..3cf852aafc --- /dev/null +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/SidecarToolingWorkspaceUtil.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012-2018 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.api.workspace.server; + +import com.google.common.base.Strings; +import java.util.Map; +import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; +import org.eclipse.che.api.workspace.shared.Constants; + +/** + * Util class to deal with sidecar based workspaces. + * + * @author Alexander Garagatyi + */ +public class SidecarToolingWorkspaceUtil { + + /** + * Checks whether provided workspace config attributes {@link WorkspaceConfig#getAttributes()} + * contains configuration of sidecars.
+ * This indicates whether this workspace is Che6 or Che7 compatible. + */ + public static boolean isSidecarBasedWorkspace(Map attributes) { + boolean hasPlugins = + !Strings.isNullOrEmpty( + attributes.getOrDefault(Constants.WORKSPACE_TOOLING_PLUGINS_ATTRIBUTE, null)); + boolean hasEditor = + !Strings.isNullOrEmpty( + attributes.getOrDefault(Constants.WORKSPACE_TOOLING_EDITOR_ATTRIBUTE, null)); + return hasPlugins || hasEditor; + } +} diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java index f4e06e66c9..fe6b64a158 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java @@ -11,7 +11,6 @@ */ package org.eclipse.che.api.workspace.server; -import static com.google.common.base.MoreObjects.firstNonNull; import static java.lang.String.format; import static java.lang.System.currentTimeMillis; import static java.util.Objects.requireNonNull; @@ -351,24 +350,11 @@ public class WorkspaceManager { } /** Asynchronously starts given workspace. */ - private void startAsync(WorkspaceImpl workspace, String envName, Map options) + private void startAsync( + WorkspaceImpl workspace, @Nullable String envName, Map options) throws ConflictException, NotFoundException, ServerException { - if (envName != null && !workspace.getConfig().getEnvironments().containsKey(envName)) { - throw new NotFoundException( - format( - "Workspace '%s:%s' doesn't contain environment '%s'", - workspace.getNamespace(), workspace.getConfig().getName(), envName)); - } + String env = getValidatedEnvironmentName(workspace, envName); workspace.getAttributes().put(UPDATED_ATTRIBUTE_NAME, Long.toString(currentTimeMillis())); - final String env = firstNonNull(envName, workspace.getConfig().getDefaultEnv()); - - // validate environment in advance - try { - runtimes.validate(workspace.getConfig().getEnvironments().get(env)); - } catch (InfrastructureException | ValidationException e) { - throw new ServerException(e); - } - workspaceDao.update(workspace); runtimes .startAsync(workspace, env, firstNonNull(options, Collections.emptyMap())) @@ -384,6 +370,45 @@ public class WorkspaceManager { }); } + private String getValidatedEnvironmentName(WorkspaceImpl workspace, @Nullable String envName) + throws NotFoundException, ServerException { + if (envName != null && !workspace.getConfig().getEnvironments().containsKey(envName)) { + throw new NotFoundException( + format( + "Workspace '%s:%s' doesn't contain environment '%s'", + workspace.getNamespace(), workspace.getConfig().getName(), envName)); + } + + envName = firstNonNull(envName, workspace.getConfig().getDefaultEnv()); + + if (envName == null + && SidecarToolingWorkspaceUtil.isSidecarBasedWorkspace( + workspace.getConfig().getAttributes())) { + // Sidecar-based workspaces are allowed not to have any environments + return null; + } + + // validate environment in advance + if (envName == null) { + throw new NotFoundException( + format( + "Workspace %s:%s can't use null environment", + workspace.getNamespace(), workspace.getConfig().getName())); + } + try { + runtimes.validate(workspace.getConfig().getEnvironments().get(envName)); + } catch (InfrastructureException | ValidationException e) { + throw new ServerException(e); + } + + return envName; + } + + /** Returns first non-null argument or null if both are null. */ + private T firstNonNull(T first, T second) { + return first != null ? first : second; + } + private void checkWorkspaceIsRunningOrStarting(WorkspaceImpl workspace) throws ConflictException { if (workspace.getStatus() != RUNNING && workspace.getStatus() != STARTING) { throw new ConflictException( diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java index 6caf03d815..8c5390fe89 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java @@ -70,7 +70,9 @@ import org.eclipse.che.api.workspace.server.spi.RuntimeStartInterruptedException import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironment; import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironmentFactory; +import org.eclipse.che.api.workspace.shared.Constants; import org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent; +import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.commons.lang.NameGenerator; import org.eclipse.che.commons.lang.concurrent.ThreadLocalPropagateContext; @@ -281,16 +283,19 @@ public class WorkspaceRuntimes { * @see WorkspaceStatus#RUNNING */ public CompletableFuture startAsync( - Workspace workspace, String envName, Map options) + Workspace workspace, @Nullable String envName, Map options) throws ConflictException, NotFoundException, ServerException { - final EnvironmentImpl environment = copyEnv(workspace, envName); final String workspaceId = workspace.getId(); - - requireNonNull(environment, "Environment should not be null " + workspaceId); - requireNonNull(environment.getRecipe(), "Recipe should not be null " + workspaceId); - requireNonNull( - environment.getRecipe().getType(), "Recipe type should not be null " + workspaceId); + // Sidecar-based workspaces allowed not to have environments + EnvironmentImpl environment = null; + if (envName != null) { + environment = copyEnv(workspace, envName); + requireNonNull(environment, "Environment should not be null " + workspaceId); + requireNonNull(environment.getRecipe(), "Recipe should not be null " + workspaceId); + requireNonNull( + environment.getRecipe().getType(), "Recipe type should not be null " + workspaceId); + } if (isStartRefused.get()) { throw new ConflictException( @@ -620,12 +625,15 @@ public class WorkspaceRuntimes { identity.getWorkspaceId(), identity.getEnvName())); } - Environment environment = workspace.getConfig().getEnvironments().get(identity.getEnvName()); - if (environment == null) { - throw new ServerException( - format( - "Environment configuration is missing for the runtime '%s:%s'. Runtime won't be recovered", - identity.getWorkspaceId(), identity.getEnvName())); + Environment environment = null; + if (identity.getEnvName() != null) { + environment = workspace.getConfig().getEnvironments().get(identity.getEnvName()); + if (environment == null) { + throw new ServerException( + format( + "Environment configuration is missing for the runtime '%s:%s'. Runtime won't be recovered", + identity.getWorkspaceId(), identity.getEnvName())); + } } InternalRuntime runtime; @@ -785,10 +793,16 @@ public class WorkspaceRuntimes { return environmentFactories.keySet(); } - private InternalEnvironment createInternalEnvironment( - Environment environment, Map workspaceConfigAttributes) + @VisibleForTesting + InternalEnvironment createInternalEnvironment( + @Nullable Environment environment, Map workspaceConfigAttributes) throws InfrastructureException, ValidationException, NotFoundException { - String recipeType = environment.getRecipe().getType(); + String recipeType; + if (environment == null) { + recipeType = Constants.NO_ENVIRONMENT_RECIPE_TYPE; + } else { + recipeType = environment.getRecipe().getType(); + } InternalEnvironmentFactory factory = environmentFactories.get(recipeType); if (factory == null) { throw new NotFoundException( diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceValidator.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceValidator.java index 09f7987901..347463f45b 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceValidator.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceValidator.java @@ -15,8 +15,8 @@ import static com.google.common.base.Strings.isNullOrEmpty; import static java.lang.String.format; import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE; import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_REQUEST_ATTRIBUTE; +import static org.eclipse.che.api.workspace.server.SidecarToolingWorkspaceUtil.isSidecarBasedWorkspace; -import com.google.common.base.Strings; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; @@ -31,7 +31,6 @@ import org.eclipse.che.api.core.model.workspace.config.Environment; import org.eclipse.che.api.core.model.workspace.config.MachineConfig; import org.eclipse.che.api.core.model.workspace.config.Recipe; import org.eclipse.che.api.core.model.workspace.config.Volume; -import org.eclipse.che.api.workspace.shared.Constants; /** * Validator for {@link Workspace}. @@ -69,24 +68,7 @@ public class WorkspaceValidator { + "latin letters, underscores, dots, dashes and must start and end only with digits, " + "latin letters or underscores"); - // environments - check(!isNullOrEmpty(config.getDefaultEnv()), "Workspace default environment name required"); - checkNotNull(config.getEnvironments(), "Workspace must contain at least one environment"); - check( - config.getEnvironments().containsKey(config.getDefaultEnv()), - "Workspace default environment configuration required"); - - for (Environment environment : config.getEnvironments().values()) { - checkNotNull(environment, "Environment must not be null"); - Recipe recipe = environment.getRecipe(); - checkNotNull(recipe, "Environment recipe must not be null"); - checkNotNull(recipe.getType(), "Environment recipe type must not be null"); - - for (Entry machineEntry : - environment.getMachines().entrySet()) { - validateMachine(machineEntry.getKey(), machineEntry.getValue()); - } - } + validateEnvironments(config); // commands for (Command command : config.getCommands()) { @@ -127,6 +109,34 @@ public class WorkspaceValidator { } } + private void validateEnvironments(WorkspaceConfig config) throws ValidationException { + boolean environmentIsNotSet = + (config.getEnvironments() == null || config.getEnvironments().isEmpty()) + && isNullOrEmpty(config.getDefaultEnv()); + boolean isSidecarWorkspace = isSidecarBasedWorkspace(config.getAttributes()); + if (environmentIsNotSet && isSidecarWorkspace) { + // sidecar based workspaces allowed not to have environment + return; + } + check(!isNullOrEmpty(config.getDefaultEnv()), "Workspace default environment name required"); + checkNotNull(config.getEnvironments(), "Workspace must contain at least one environment"); + check( + config.getEnvironments().containsKey(config.getDefaultEnv()), + "Workspace default environment configuration required"); + + for (Environment environment : config.getEnvironments().values()) { + checkNotNull(environment, "Environment must not be null"); + Recipe recipe = environment.getRecipe(); + checkNotNull(recipe, "Environment recipe must not be null"); + checkNotNull(recipe.getType(), "Environment recipe type must not be null"); + + for (Entry machineEntry : + environment.getMachines().entrySet()) { + validateMachine(machineEntry.getKey(), machineEntry.getValue()); + } + } + } + private void validateMachine(String machineName, MachineConfig machine) throws ValidationException { validateLongAttribute( @@ -189,13 +199,7 @@ public class WorkspaceValidator { .flatMap(machine -> machine.getInstallers().stream()) .findAny(); Map attributes = config.getAttributes(); - boolean hasPlugins = - !Strings.isNullOrEmpty( - attributes.getOrDefault(Constants.WORKSPACE_TOOLING_PLUGINS_ATTRIBUTE, null)); - boolean hasEditor = - !Strings.isNullOrEmpty( - attributes.getOrDefault(Constants.WORKSPACE_TOOLING_EDITOR_ATTRIBUTE, null)); - if ((hasPlugins || hasEditor) && installers.isPresent()) { + if (isSidecarBasedWorkspace(attributes) && installers.isPresent()) { throw new ValidationException("Workspace config cannot have both plugins and installers."); } } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/bootstrap/AbstractBootstrapper.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/bootstrap/AbstractBootstrapper.java index fe66430ddb..0a3a9a7228 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/bootstrap/AbstractBootstrapper.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/bootstrap/AbstractBootstrapper.java @@ -11,6 +11,7 @@ */ package org.eclipse.che.api.workspace.server.bootstrap; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -55,7 +56,7 @@ public abstract class AbstractBootstrapper { // check bootstrapper belongs to current runtime and machine RuntimeIdentityDto runtimeId = event.getRuntimeId(); if (event.getMachineName().equals(machineName) - && runtimeIdentity.getEnvName().equals(runtimeId.getEnvName()) + && Objects.equals(runtimeIdentity.getEnvName(), runtimeId.getEnvName()) && runtimeIdentity.getWorkspaceId().equals(runtimeId.getWorkspaceId())) { finishEventFuture.complete(event); diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/RuntimeIdentityImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/RuntimeIdentityImpl.java index 64e0016783..d629cea170 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/RuntimeIdentityImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/RuntimeIdentityImpl.java @@ -11,6 +11,7 @@ */ package org.eclipse.che.api.workspace.server.model.impl; +import java.util.Objects; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; /** @author gazarenkov */ @@ -20,6 +21,10 @@ public final class RuntimeIdentityImpl implements RuntimeIdentity { private final String envName; private final String ownerId; + public RuntimeIdentityImpl(RuntimeIdentity id) { + this(id.getWorkspaceId(), id.getEnvName(), id.getOwnerId()); + } + public RuntimeIdentityImpl(String workspaceId, String envName, String ownerId) { this.workspaceId = workspaceId; this.envName = envName; @@ -43,14 +48,16 @@ public final class RuntimeIdentityImpl implements RuntimeIdentity { @Override public int hashCode() { - return (workspaceId + envName).hashCode(); + return Objects.hash(workspaceId, envName, ownerId); } @Override public boolean equals(Object obj) { if (!(obj instanceof RuntimeIdentityImpl)) return false; RuntimeIdentityImpl other = (RuntimeIdentityImpl) obj; - return workspaceId.equals(other.workspaceId) && envName.equals(other.envName); + return workspaceId.equals(other.workspaceId) + && Objects.equals(envName, other.envName) + && Objects.equals(ownerId, other.ownerId); } @Override diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceConfigImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceConfigImpl.java index 1b92aa5399..2d1015e975 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceConfigImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceConfigImpl.java @@ -63,7 +63,7 @@ public class WorkspaceConfigImpl implements WorkspaceConfig { @Column(name = "description", columnDefinition = "TEXT") private String description; - @Column(name = "defaultenv", nullable = false) + @Column(name = "defaultenv", nullable = true) private String defaultEnv; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/InternalRuntime.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/InternalRuntime.java index c9ce43d85d..b67fedce68 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/InternalRuntime.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/InternalRuntime.java @@ -79,6 +79,7 @@ public abstract class InternalRuntime { } /** Returns name of the active environment. */ + @Nullable public String getActiveEnv() { return context.getIdentity().getEnvName(); } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironmentFactory.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironmentFactory.java index 6d59c718af..955151d42a 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironmentFactory.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironmentFactory.java @@ -28,6 +28,7 @@ import org.eclipse.che.api.installer.server.exception.InstallerException; import org.eclipse.che.api.installer.shared.model.Installer; import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.commons.annotation.Nullable; /** * Creates a valid instance of InternalEnvironment. @@ -78,36 +79,40 @@ public abstract class InternalEnvironmentFactory * @throws InfrastructureException if infrastructure specific error occurs * @throws ValidationException if validation fails */ - public T create(final Environment sourceEnv) throws InfrastructureException, ValidationException { + public T create(@Nullable final Environment sourceEnv) + throws InfrastructureException, ValidationException { Map machines = new HashMap<>(); List warnings = new ArrayList<>(); + InternalRecipe recipe = null; - InternalRecipe recipe = recipeRetriever.getRecipe(sourceEnv.getRecipe()); + if (sourceEnv != null) { + recipe = recipeRetriever.getRecipe(sourceEnv.getRecipe()); - for (Map.Entry machineEntry : - sourceEnv.getMachines().entrySet()) { - MachineConfig machineConfig = machineEntry.getValue(); + for (Map.Entry machineEntry : + sourceEnv.getMachines().entrySet()) { + MachineConfig machineConfig = machineEntry.getValue(); - List installers; - try { - installers = installerRegistry.getOrderedInstallers(machineConfig.getInstallers()); - } catch (InstallerException e) { - throw new InfrastructureException(e); + List installers; + try { + installers = installerRegistry.getOrderedInstallers(machineConfig.getInstallers()); + } catch (InstallerException e) { + throw new InfrastructureException(e); + } + + machines.put( + machineEntry.getKey(), + new InternalMachineConfig( + installers, + normalizeServers(machineConfig.getServers()), + machineConfig.getEnv(), + machineConfig.getAttributes(), + machineConfig.getVolumes())); } - machines.put( - machineEntry.getKey(), - new InternalMachineConfig( - installers, - normalizeServers(machineConfig.getServers()), - machineConfig.getEnv(), - machineConfig.getAttributes(), - machineConfig.getVolumes())); + machinesValidator.validate(machines); } - machinesValidator.validate(machines); - return doCreate(recipe, machines, warnings); } @@ -127,7 +132,9 @@ public abstract class InternalEnvironmentFactory * @throws ValidationException if validation fails */ protected abstract T doCreate( - InternalRecipe recipe, Map machines, List warnings) + @Nullable InternalRecipe recipe, + Map machines, + List warnings) throws InfrastructureException, ValidationException; @VisibleForTesting diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimesTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimesTest.java index 906ca3df01..855a4acd5b 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimesTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimesTest.java @@ -14,6 +14,7 @@ package org.eclipse.che.api.workspace.server; import static java.util.Collections.emptyMap; import static java.util.Collections.emptySet; import static org.eclipse.che.api.workspace.shared.Constants.ERROR_MESSAGE_ATTRIBUTE_NAME; +import static org.eclipse.che.api.workspace.shared.Constants.NO_ENVIRONMENT_RECIPE_TYPE; import static org.eclipse.che.api.workspace.shared.Constants.STOPPED_ABNORMALLY_ATTRIBUTE_NAME; import static org.eclipse.che.api.workspace.shared.Constants.STOPPED_ATTRIBUTE_NAME; import static org.mockito.ArgumentMatchers.any; @@ -119,6 +120,53 @@ public class WorkspaceRuntimesTest { lockService); } + @Test + public void internalEnvironmentCreationShouldRespectNoEnvironmentCase() throws Exception { + InternalEnvironmentFactory noEnvFactory = + mock(InternalEnvironmentFactory.class); + runtimes = + new WorkspaceRuntimes( + eventService, + ImmutableMap.of( + TEST_ENVIRONMENT_TYPE, testEnvFactory, NO_ENVIRONMENT_RECIPE_TYPE, noEnvFactory), + infrastructure, + sharedPool, + workspaceDao, + dbInitializer, + probeScheduler, + statuses, + lockService); + InternalEnvironment expectedEnvironment = mock(InternalEnvironment.class); + when(noEnvFactory.create(eq(null))).thenReturn(expectedEnvironment); + + InternalEnvironment actualEnvironment = runtimes.createInternalEnvironment(null, emptyMap()); + + assertEquals(actualEnvironment, expectedEnvironment); + } + + @Test( + expectedExceptions = NotFoundException.class, + expectedExceptionsMessageRegExp = + "InternalEnvironmentFactory is not configured for recipe type: 'not-supported-type'") + public void internalEnvironmentShouldThrowExceptionWhenNoEnvironmentFactoryFoundForRecipeType() + throws Exception { + EnvironmentImpl environment = new EnvironmentImpl(); + environment.setRecipe(new RecipeImpl("not-supported-type", "", "", null)); + runtimes.createInternalEnvironment(environment, emptyMap()); + } + + @Test( + expectedExceptions = NotFoundException.class, + expectedExceptionsMessageRegExp = + "InternalEnvironmentFactory is not configured for recipe type: '" + + NO_ENVIRONMENT_RECIPE_TYPE + + "'") + public void + internalEnvironmentShouldThrowExceptionWhenNoEnvironmentFactoryFoundForNoEnvironmentWorkspaceCase() + throws Exception { + runtimes.createInternalEnvironment(null, emptyMap()); + } + @Test public void runtimeIsRecovered() throws Exception { RuntimeIdentity identity = new RuntimeIdentityImpl("workspace123", "my-env", "myId"); diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceValidatorTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceValidatorTest.java index f018c762b0..7c2808b1a0 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceValidatorTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceValidatorTest.java @@ -143,7 +143,7 @@ public class WorkspaceValidatorTest { @Test( expectedExceptions = ValidationException.class, expectedExceptionsMessageRegExp = "Workspace default environment name required") - public void shouldFailValidationIfDefaultEnvNameIsNull() throws Exception { + public void shouldFailValidationOfChe6WSIfDefaultEnvNameIsNull() throws Exception { final WorkspaceConfigDto config = createConfig(); config.setDefaultEnv(null); @@ -153,13 +153,24 @@ public class WorkspaceValidatorTest { @Test( expectedExceptions = ValidationException.class, expectedExceptionsMessageRegExp = "Workspace default environment name required") - public void shouldFailValidationIfDefaultEnvNameIsEmpty() throws Exception { + public void shouldFailValidationOfChe6WSIfDefaultEnvNameIsEmpty() throws Exception { final WorkspaceConfigDto config = createConfig(); config.setDefaultEnv(""); wsValidator.validateConfig(config); } + @Test + public void shouldNotFailValidationOfChe7WSIfDefaultEnvNameIsNullAndNoEnvIsPresent() + throws Exception { + final WorkspaceConfigDto config = createConfig(); + config.setDefaultEnv(null); + config.getEnvironments().clear(); + config.getAttributes().put(Constants.WORKSPACE_TOOLING_EDITOR_ATTRIBUTE, "something"); + + wsValidator.validateConfig(config); + } + @Test( expectedExceptions = ValidationException.class, expectedExceptionsMessageRegExp = "Workspace default environment configuration required") @@ -370,7 +381,7 @@ public class WorkspaceValidatorTest { .withType("type") .withContent("content") .withContentType("content type")); - workspaceConfigDto.setEnvironments(singletonMap("dev-env", env)); + workspaceConfigDto.setEnvironments(new HashMap<>(singletonMap("dev-env", env))); List commandDtos = new ArrayList<>(); commandDtos.add( diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironmentFactoryTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironmentFactoryTest.java index 2888fa4bb6..2a685b713c 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironmentFactoryTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/environment/InternalEnvironmentFactoryTest.java @@ -155,6 +155,20 @@ public class InternalEnvironmentFactoryTest { assertEquals(createdEnv, expectedEnv); } + @Test + public void shouldPassNullRecipeIfEnvironmentIsNull() throws Exception { + // given + InternalEnvironment expectedEnv = mock(InternalEnvironment.class); + when(environmentFactory.doCreate(any(), any(), any())).thenReturn(expectedEnv); + + // when + InternalEnvironment createdEnv = environmentFactory.create(null); + + // then + assertEquals(createdEnv, expectedEnv); + verify(environmentFactory).doCreate(eq(null), any(), any()); + } + @Test public void normalizeServersProtocols() throws InfrastructureException { ServerConfigImpl serverWithoutProtocol = diff --git a/wsmaster/che-core-sql-schema/src/main/resources/che-schema/6.15.0/1__remove_not_null_constraint_from_env_name_fields.sql b/wsmaster/che-core-sql-schema/src/main/resources/che-schema/6.15.0/1__remove_not_null_constraint_from_env_name_fields.sql new file mode 100644 index 0000000000..fd4d4066ff --- /dev/null +++ b/wsmaster/che-core-sql-schema/src/main/resources/che-schema/6.15.0/1__remove_not_null_constraint_from_env_name_fields.sql @@ -0,0 +1,20 @@ +-- +-- Copyright (c) 2012-2018 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 +-- + +-- Allow null as defaultEnv field in workspace config +ALTER TABLE workspaceconfig ALTER COLUMN defaultenv DROP NOT NULL; + +ALTER TABLE che_k8s_runtime DROP PRIMARY KEY; +ALTER TABLE che_k8s_runtime ADD PRIMARY KEY (workspace_id); + +-- Allow null as env_name field in kubernetes runtime +ALTER TABLE che_k8s_runtime ALTER COLUMN env_name DROP NOT NULL; diff --git a/wsmaster/che-core-sql-schema/src/main/resources/che-schema/6.15.0/mysql/1__remove_not_null_constraint_from_env_name_fields.sql b/wsmaster/che-core-sql-schema/src/main/resources/che-schema/6.15.0/mysql/1__remove_not_null_constraint_from_env_name_fields.sql new file mode 100644 index 0000000000..557eedc41f --- /dev/null +++ b/wsmaster/che-core-sql-schema/src/main/resources/che-schema/6.15.0/mysql/1__remove_not_null_constraint_from_env_name_fields.sql @@ -0,0 +1,20 @@ +-- +-- Copyright (c) 2012-2018 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 +-- + +-- Allow null as defaultEnv field in workspace config +ALTER TABLE workspaceconfig MODIFY COLUMN defaultenv VARCHAR(255); + +ALTER TABLE che_k8s_runtime DROP PRIMARY KEY; +ALTER TABLE che_k8s_runtime ADD PRIMARY KEY (workspace_id); + +-- Allow null as env_name field in kubernetes runtime +ALTER TABLE che_k8s_runtime MODIFY COLUMN env_name VARCHAR(255); diff --git a/wsmaster/che-core-sql-schema/src/main/resources/che-schema/6.15.0/postgresql/1__remove_not_null_constraint_from_env_name_fields.sql b/wsmaster/che-core-sql-schema/src/main/resources/che-schema/6.15.0/postgresql/1__remove_not_null_constraint_from_env_name_fields.sql new file mode 100644 index 0000000000..b373d20778 --- /dev/null +++ b/wsmaster/che-core-sql-schema/src/main/resources/che-schema/6.15.0/postgresql/1__remove_not_null_constraint_from_env_name_fields.sql @@ -0,0 +1,20 @@ +-- +-- Copyright (c) 2012-2018 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 +-- + +-- Allow null as defaultEnv field in workspace config +ALTER TABLE workspaceconfig ALTER COLUMN defaultenv DROP NOT NULL; + +ALTER TABLE che_k8s_runtime DROP CONSTRAINT che_k8s_runtime_pkey; +ALTER TABLE che_k8s_runtime ADD PRIMARY KEY (workspace_id); + +-- Allow null as env_name field in kubernetes runtime +ALTER TABLE che_k8s_runtime ALTER COLUMN env_name DROP NOT NULL; diff --git a/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/CascadeRemovalTest.java b/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/CascadeRemovalTest.java index 21c30ab33b..09d01ec342 100644 --- a/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/CascadeRemovalTest.java +++ b/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/CascadeRemovalTest.java @@ -185,7 +185,6 @@ public class CascadeRemovalTest { SshPairImpl.class, VolumeImpl.class, KubernetesRuntimeState.class, - KubernetesRuntimeState.RuntimeId.class, KubernetesMachineImpl.class, KubernetesMachineImpl.MachineId.class, KubernetesServerImpl.class, diff --git a/wsmaster/integration-tests/mysql-tck/src/test/java/MySqlTckModule.java b/wsmaster/integration-tests/mysql-tck/src/test/java/MySqlTckModule.java index 7f1d0dd7b6..8a57877ad6 100644 --- a/wsmaster/integration-tests/mysql-tck/src/test/java/MySqlTckModule.java +++ b/wsmaster/integration-tests/mysql-tck/src/test/java/MySqlTckModule.java @@ -136,7 +136,6 @@ public class MySqlTckModule extends TckModule { SignatureKeyPairImpl.class, // k8s-runtimes KubernetesRuntimeState.class, - KubernetesRuntimeState.RuntimeId.class, KubernetesMachineImpl.class, KubernetesMachineImpl.MachineId.class, KubernetesServerImpl.class, diff --git a/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java b/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java index c207da1f9a..2e816b32b7 100644 --- a/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java +++ b/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java @@ -131,7 +131,6 @@ public class PostgreSqlTckModule extends TckModule { VolumeImpl.class, // k8s-runtimes KubernetesRuntimeState.class, - KubernetesRuntimeState.RuntimeId.class, KubernetesMachineImpl.class, KubernetesMachineImpl.MachineId.class, KubernetesServerImpl.class,