From cd1301d1150e3af8d4d42baf063617381e1713b3 Mon Sep 17 00:00:00 2001 From: Oleksandr Garagatyi Date: Mon, 23 Oct 2017 16:02:08 +0300 Subject: [PATCH] CHE-6124: Do not publish exposed ports in Docker machines Publish port in Docker machines only in case there is a server in the workspace config that represents the port. Refactor OpenShift infrastructure code. Refactor Docker infrastructure code. Add constant of memory attribute and reuse it everywhere it is hardcoded. Add constant for installer environment attribute and reuse it everywhere it is hardcoded. Add machine memory attribute validation to workspace validation. Move provisioning of servers, environment variables from infrastructure implementations to runtime SPI abstract level. Signed-off-by: Oleksandr Garagatyi --- .../model/workspace/config/MachineConfig.java | 8 + .../cli/tests/cmd_backup_restore_tests.bats | 2 +- .../src/api/wsmaster/workspace/workspace.ts | 8 +- .../internal/action/impl/get-ssh-action.ts | 2 +- .../action/impl/workspace-ssh-action.ts | 2 +- dockerfiles/lib/src/internal/dir/che-dir.ts | 2 +- infrastructures/docker/infrastructure/pom.xml | 4 - .../docker/DockerMachineStarter.java | 11 +- .../docker/environment/EnvironmentParser.java | 44 +---- .../environment/EnvironmentValidator.java | 18 -- .../LocalCheInfrastructureProvisioner.java | 68 ++++--- .../docker/local/LocalDockerModule.java | 2 +- ...lInstallersBinariesVolumeProvisioner.java} | 13 +- .../provisioner/env/EnvVarsConverter.java | 42 ++++ .../installer/InstallerConfigApplier.java | 140 -------------- .../InstallersConfigProvisioner.java | 45 ----- ...ner.java => RuntimeLabelsProvisioner.java} | 11 +- .../memory/MemoryAttributeConverter.java | 49 +++++ .../provisioner/server/ServersConverter.java | 57 ++++++ .../docker/server/mapping/ServersMapper.java | 2 +- .../environment/EnvironmentParserTest.java | 66 ------- .../environment/EnvironmentValidatorTest.java | 24 +-- ...LocalCheInfrastructureProvisionerTest.java | 57 ++++-- .../installer/InstallerConfigApplierTest.java | 127 ------------ infrastructures/openshift/pom.xml | 4 - .../OpenShiftInfrastructureProvisioner.java | 29 ++- .../OpenShiftEnvironmentParser.java | 74 +------ .../provision/env/EnvVarsConverter.java | 56 ++++++ .../installer/InstallerConfigProvisioner.java | 87 ++------- .../labels/PodNameLabelProvisioner.java | 53 ++++++ .../restartpolicy/RestartPolicyRewriter.java | 56 ++++++ .../provision/server/ServersConverter.java | 57 ++++++ ...penShiftInfrastructureProvisionerTest.java | 39 +++- .../OpenShiftEnvironmentParserTest.java | 35 ---- .../InstallerConfigProvisionerTest.java | 180 +++--------------- .../RestartPolicyRewriterTest.java | 99 ++++++++++ plugins/plugin-urlfactory/pom.xml | 4 + .../urlfactory/URLFactoryBuilderTest.java | 7 +- .../client/TestWorkspaceServiceClient.java | 3 +- .../server/builder/FactoryBuilderTest.java | 3 +- .../api/installer/shared/model/Installer.java | 9 + .../workspace/server/WorkspaceValidator.java | 23 ++- .../adapter/WorkspaceConfigJsonAdapter.java | 3 +- .../server/spi/InternalMachineConfig.java | 47 +++-- .../WorkspaceConfigJsonAdapterTest.java | 5 +- .../server/WorkspaceManagerTest.java | 3 +- .../server/WorkspaceServiceTest.java | 3 +- .../server/WorkspaceValidatorTest.java | 29 ++- .../server/stack/StackLoaderTest.java | 3 +- 49 files changed, 825 insertions(+), 890 deletions(-) rename infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/installer/{LocalInstallersConfigProvisioner.java => LocalInstallersBinariesVolumeProvisioner.java} (73%) create mode 100644 infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/env/EnvVarsConverter.java delete mode 100644 infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/installer/InstallerConfigApplier.java delete mode 100644 infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/installer/InstallersConfigProvisioner.java rename infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/labels/{LabelsProvisioner.java => RuntimeLabelsProvisioner.java} (80%) create mode 100644 infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/memory/MemoryAttributeConverter.java create mode 100644 infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/server/ServersConverter.java delete mode 100644 infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/installer/InstallerConfigApplierTest.java create mode 100644 infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/env/EnvVarsConverter.java create mode 100644 infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/labels/PodNameLabelProvisioner.java create mode 100644 infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/restartpolicy/RestartPolicyRewriter.java create mode 100644 infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/server/ServersConverter.java create mode 100644 infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/restartpolicy/RestartPolicyRewriterTest.java diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/MachineConfig.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/MachineConfig.java index b0212d87da..162377c7de 100644 --- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/MachineConfig.java +++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/MachineConfig.java @@ -19,6 +19,14 @@ import java.util.Map; * @author Alexander Garagatyi */ public interface MachineConfig { + + /** + * Name of the attribute from {@link #getAttributes()} which if present sets memory limit of the + * machine in bytes. If memory limit is set in environment specific recipe this attribute should + * override value from recipe. + */ + String MEMORY_LIMIT_ATTRIBUTE = "memoryLimitBytes"; + /** * Returns configured installers. * diff --git a/dockerfiles/cli/tests/cmd_backup_restore_tests.bats b/dockerfiles/cli/tests/cmd_backup_restore_tests.bats index 596d6523f4..c455a02f8b 100644 --- a/dockerfiles/cli/tests/cmd_backup_restore_tests.bats +++ b/dockerfiles/cli/tests/cmd_backup_restore_tests.bats @@ -90,7 +90,7 @@ teardown() { check_che_state #create a workspace - ws_create=$(curl 'http://'${ip_address}':8080/api/workspace?namespace=che&attribute=stackId:java-default' -H 'Content-Type: application/json;charset=UTF-8' -H 'Accept: application/json, text/plain, */*' --data-binary '{"defaultEnv":"wksp-1p0b","environments":{"wksp-1p0b":{"recipe":{"location":"eclipse/ubuntu_jdk8","type":"dockerimage"},"machines":{"dev-machine":{"servers":{},"agents":["org.eclipse.che.exec","org.eclipse.che.terminal","org.eclipse.che.ws-agent","org.eclipse.che.ssh"],"attributes":{"memoryLimitBytes":"2147483648"}}}}},"projects":[],"commands":[{"commandLine":"mvn clean install -f ${current.project.path}","name":"build","type":"mvn","attributes":{"goal":"Build","previewUrl":""}}],"name":"backup-restore","links":[]}' --compressed) + ws_create=$(curl 'http://'${ip_address}':8080/api/workspace?namespace=che&attribute=stackId:java-default' -H 'Content-Type: application/json;charset=UTF-8' -H 'Accept: application/json, text/plain, */*' --data-binary '{"defaultEnv":"wksp-1p0b","environments":{"wksp-1p0b":{"recipe":{"location":"eclipse/ubuntu_jdk8","type":"dockerimage"},"machines":{"dev-machine":{"servers":{},"installers":["org.eclipse.che.exec","org.eclipse.che.terminal","org.eclipse.che.ws-agent","org.eclipse.che.ssh"],"attributes":{"memoryLimitBytes":"2147483648"}}}}},"projects":[],"commands":[{"commandLine":"mvn clean install -f ${current.project.path}","name":"build","type":"mvn","attributes":{"goal":"Build","previewUrl":""}}],"name":"backup-restore","links":[]}' --compressed) [[ "$ws_create" == *"created"* ]] [[ "$ws_create" == *"STOPPED"* ]] #stop che diff --git a/dockerfiles/lib/src/api/wsmaster/workspace/workspace.ts b/dockerfiles/lib/src/api/wsmaster/workspace/workspace.ts index 278ef61bfe..ce97b6aec3 100644 --- a/dockerfiles/lib/src/api/wsmaster/workspace/workspace.ts +++ b/dockerfiles/lib/src/api/wsmaster/workspace/workspace.ts @@ -63,10 +63,10 @@ export class Workspace { */ getWorkspaceConfigDto(createWorkspaceConfig:CreateWorkspaceConfig) : org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto { let devMachine : org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDto = new org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDtoImpl(); - devMachine.getAgents().push("org.eclipse.che.exec"); - devMachine.getAgents().push("org.eclipse.che.terminal"); - devMachine.getAgents().push("org.eclipse.che.ws-agent"); - devMachine.getAgents().push("org.eclipse.che.ssh"); + devMachine.getInstallers().push("org.eclipse.che.exec"); + devMachine.getInstallers().push("org.eclipse.che.terminal"); + devMachine.getInstallers().push("org.eclipse.che.ws-agent"); + devMachine.getInstallers().push("org.eclipse.che.ssh"); devMachine.getAttributes().set("memoryLimitBytes", "2147483648"); let defaultEnvironment : org.eclipse.che.api.workspace.shared.dto.EnvironmentDto = new org.eclipse.che.api.workspace.shared.dto.EnvironmentDtoImpl(); diff --git a/dockerfiles/lib/src/internal/action/impl/get-ssh-action.ts b/dockerfiles/lib/src/internal/action/impl/get-ssh-action.ts index 365fe40128..7adb51907f 100644 --- a/dockerfiles/lib/src/internal/action/impl/get-ssh-action.ts +++ b/dockerfiles/lib/src/internal/action/impl/get-ssh-action.ts @@ -69,7 +69,7 @@ export class GetSshDataAction { // Check ssh agent is there let defaultEnv:string = workspaceDto.getConfig().getDefaultEnv(); - let agents:Array = workspaceDto.getConfig().getEnvironments().get(defaultEnv).getMachines().get("dev-machine").getAgents(); + let agents:Array = workspaceDto.getConfig().getEnvironments().get(defaultEnv).getMachines().get("dev-machine").getInstallers(); if (agents.indexOf('org.eclipse.che.ssh') === -1) { return Promise.reject("The SSH agent (org.eclipse.che.ssh) has been disabled for this workspace.") diff --git a/dockerfiles/lib/src/internal/action/impl/workspace-ssh-action.ts b/dockerfiles/lib/src/internal/action/impl/workspace-ssh-action.ts index f66f70d2f9..570ba7fac0 100644 --- a/dockerfiles/lib/src/internal/action/impl/workspace-ssh-action.ts +++ b/dockerfiles/lib/src/internal/action/impl/workspace-ssh-action.ts @@ -87,7 +87,7 @@ export class WorkspaceSshAction { throw new Error("Unable to find a machine named " + this.machineName + " in the workspace '" + this.workspaceName) } - let agents:Array = machineConfig.getAgents(); + let agents:Array = machineConfig.getInstallers(); if (agents.indexOf('org.eclipse.che.ssh') === -1) { return Promise.reject("The SSH agent (org.eclipse.che.ssh) has been disabled for this workspace.") diff --git a/dockerfiles/lib/src/internal/dir/che-dir.ts b/dockerfiles/lib/src/internal/dir/che-dir.ts index cd45b05224..95d16f3fb4 100644 --- a/dockerfiles/lib/src/internal/dir/che-dir.ts +++ b/dockerfiles/lib/src/internal/dir/che-dir.ts @@ -830,7 +830,7 @@ setupSSHKeys(workspaceDto: org.eclipse.che.api.workspace.shared.dto.WorkspaceDto // Check ssh agent is there let defaultEnv : string = workspaceDto.getConfig().getDefaultEnv(); - let agents : Array = workspaceDto.getConfig().getEnvironments().get(defaultEnv).getMachines().get("dev-machine").getAgents(); + let agents : Array = workspaceDto.getConfig().getEnvironments().get(defaultEnv).getMachines().get("dev-machine").getInstallers(); if (agents.indexOf('org.eclipse.che.ssh') === - 1) { return Promise.reject("The SSH agent (org.eclipse.che.ssh) has been disabled for this workspace.") diff --git a/infrastructures/docker/infrastructure/pom.xml b/infrastructures/docker/infrastructure/pom.xml index 8b16923f2f..0182ce4521 100644 --- a/infrastructures/docker/infrastructure/pom.xml +++ b/infrastructures/docker/infrastructure/pom.xml @@ -86,10 +86,6 @@ org.eclipse.che.core che-core-api-installer - - org.eclipse.che.core - che-core-api-installer-shared - org.eclipse.che.core che-core-api-model diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/DockerMachineStarter.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/DockerMachineStarter.java index c28611ec8b..ee6d989957 100644 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/DockerMachineStarter.java +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/DockerMachineStarter.java @@ -463,8 +463,6 @@ public class DockerMachineStarter { hostConfig.setBinds(bindMountVolumes.toArray(new String[bindMountVolumes.size()])); config.setVolumes(nonBindMountVolumes); - config.getHostConfig().withPublishAllPorts(true); - setNonExitingContainerCommandIfNeeded(config); return docker @@ -479,12 +477,15 @@ public class DockerMachineStarter { Map portsBindings = Maps.newHashMapWithExpectedSize(portsSpecs.size()); for (String portSpec : portsSpecs) { String[] portMapping = portSpec.split(":"); - if (portMapping.length != 2) { + if (portMapping.length == 1) { + portsBindings.put(portMapping[0], new PortBinding[] {new PortBinding()}); + } else if (portMapping.length == 2) { + portsBindings.put( + portMapping[0], new PortBinding[] {new PortBinding().withHostPort(portMapping[1])}); + } else { throw new InternalInfrastructureException( format("Invalid port specification '%s' found machine '%s'", portsSpecs, machineName)); } - portsBindings.put( - portMapping[0], new PortBinding[] {new PortBinding().withHostPort(portMapping[1])}); } return portsBindings; } diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/EnvironmentParser.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/EnvironmentParser.java index a5b163d000..3c0ddb23ce 100644 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/EnvironmentParser.java +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/EnvironmentParser.java @@ -16,11 +16,9 @@ import static org.eclipse.che.workspace.infrastructure.docker.ArgumentsValidator import com.google.common.base.Joiner; import java.util.Map; -import java.util.stream.Collectors; import javax.inject.Inject; import org.eclipse.che.api.core.ValidationException; import org.eclipse.che.api.core.model.workspace.config.Environment; -import org.eclipse.che.api.core.model.workspace.config.ServerConfig; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.InternalEnvironment; import org.eclipse.che.api.workspace.server.spi.InternalEnvironment.InternalRecipe; @@ -75,41 +73,19 @@ public class EnvironmentParser { InternalMachineConfig machineConfig = environment.getMachines().get(entry.getKey()); if (machineConfig != null) { - normalizeMachine(entry.getKey(), entry.getValue(), machineConfig); + entry + .getValue() + .setExpose( + entry + .getValue() + .getExpose() + .stream() + .map(expose -> expose.contains("/") ? expose : expose + "/tcp") + .distinct() + .collect(toList())); } } return dockerEnvironment; } - - private void normalizeMachine( - String name, DockerContainerConfig container, InternalMachineConfig machineConfig) - throws ValidationException { - if (machineConfig.getAttributes().containsKey("memoryLimitBytes")) { - try { - container.setMemLimit( - Long.parseLong(machineConfig.getAttributes().get("memoryLimitBytes"))); - } catch (NumberFormatException e) { - throw new ValidationException( - format("Value of attribute 'memoryLimitBytes' of machine '%s' is illegal", name)); - } - } - container.setExpose( - container - .getExpose() - .stream() - .map(expose -> expose.contains("/") ? expose : expose + "/tcp") - .collect(toList())); - for (ServerConfig serverConfig : machineConfig.getServers().values()) { - String normalizedPort = - serverConfig.getPort().contains("/") - ? serverConfig.getPort() - : serverConfig.getPort() + "/tcp"; - - container.getExpose().add(normalizedPort); - } - container.setExpose(container.getExpose().stream().distinct().collect(Collectors.toList())); - - container.getEnvironment().putAll(machineConfig.getEnv()); - } } diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/EnvironmentValidator.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/EnvironmentValidator.java index 15d0eb67df..3635af3618 100644 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/EnvironmentValidator.java +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/environment/EnvironmentValidator.java @@ -11,7 +11,6 @@ package org.eclipse.che.workspace.infrastructure.docker.environment; import static com.google.common.base.Strings.isNullOrEmpty; -import static java.lang.String.format; import static java.util.stream.Collectors.toList; import static org.eclipse.che.workspace.infrastructure.docker.ArgumentsValidator.checkArgument; @@ -233,23 +232,6 @@ public class EnvironmentValidator { private void validateExtendedMachine(InternalMachineConfig machineConfig, String machineName) throws ValidationException { - if (machineConfig.getAttributes() != null - && machineConfig.getAttributes().get("memoryLimitBytes") != null) { - - try { - long memoryLimitBytes = - Long.parseLong(machineConfig.getAttributes().get("memoryLimitBytes")); - checkArgument( - memoryLimitBytes > 0, - "Value of attribute 'memoryLimitBytes' of machine '%s' in environment is illegal", - machineName); - } catch (NumberFormatException e) { - throw new ValidationException( - format( - "Value of attribute 'memoryLimitBytes' of machine '%s' in environment is illegal", - machineName)); - } - } if (machineConfig.getServers() != null) { for (Map.Entry serverEntry : diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/LocalCheInfrastructureProvisioner.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/LocalCheInfrastructureProvisioner.java index 34069c5956..99d63fefff 100644 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/LocalCheInfrastructureProvisioner.java +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/LocalCheInfrastructureProvisioner.java @@ -17,12 +17,15 @@ import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.InternalEnvironment; import org.eclipse.che.workspace.infrastructure.docker.InfrastructureProvisioner; import org.eclipse.che.workspace.infrastructure.docker.local.dod.DockerApiHostEnvVariableProvisioner; -import org.eclipse.che.workspace.infrastructure.docker.local.installer.LocalInstallersConfigProvisioner; +import org.eclipse.che.workspace.infrastructure.docker.local.installer.LocalInstallersBinariesVolumeProvisioner; import org.eclipse.che.workspace.infrastructure.docker.local.installer.WsAgentServerConfigProvisioner; import org.eclipse.che.workspace.infrastructure.docker.local.projects.ProjectsVolumeProvisioner; import org.eclipse.che.workspace.infrastructure.docker.model.DockerEnvironment; import org.eclipse.che.workspace.infrastructure.docker.provisioner.ContainerSystemSettingsProvisionersApplier; -import org.eclipse.che.workspace.infrastructure.docker.provisioner.labels.LabelsProvisioner; +import org.eclipse.che.workspace.infrastructure.docker.provisioner.env.EnvVarsConverter; +import org.eclipse.che.workspace.infrastructure.docker.provisioner.labels.RuntimeLabelsProvisioner; +import org.eclipse.che.workspace.infrastructure.docker.provisioner.memory.MemoryAttributeConverter; +import org.eclipse.che.workspace.infrastructure.docker.provisioner.server.ServersConverter; import org.eclipse.che.workspace.infrastructure.docker.provisioner.server.ToolingServersEnvVarsProvisioner; import org.eclipse.che.workspace.infrastructure.docker.provisioner.snapshot.ExcludeFoldersFromSnapshotProvisioner; @@ -34,34 +37,44 @@ import org.eclipse.che.workspace.infrastructure.docker.provisioner.snapshot.Excl */ @Singleton public class LocalCheInfrastructureProvisioner implements InfrastructureProvisioner { - private final ContainerSystemSettingsProvisionersApplier settingsProvisioners; - private final ExcludeFoldersFromSnapshotProvisioner snapshotProvisioner; + + private final ContainerSystemSettingsProvisionersApplier dockerSettingsProvisioners; + private final ExcludeFoldersFromSnapshotProvisioner snapshotVolumeProvisioner; private final ProjectsVolumeProvisioner projectsVolumeProvisioner; - private final LocalInstallersConfigProvisioner installerConfigProvisioner; - private final LabelsProvisioner labelsProvisioner; + private final LocalInstallersBinariesVolumeProvisioner installersBinariesVolumeProvisioner; + private final RuntimeLabelsProvisioner runtimeLabelsProvisioner; private final DockerApiHostEnvVariableProvisioner dockerApiEnvProvisioner; - private final ToolingServersEnvVarsProvisioner toolingServersEnvVarsProvisioner; + private final ToolingServersEnvVarsProvisioner agentsServersEnvVarsProvisioner; private final WsAgentServerConfigProvisioner wsAgentServerConfigProvisioner; + private final ServersConverter serversConverter; + private final EnvVarsConverter envVarsConverter; + private final MemoryAttributeConverter memoryAttributeConverter; @Inject public LocalCheInfrastructureProvisioner( - ContainerSystemSettingsProvisionersApplier settingsProvisioners, - ExcludeFoldersFromSnapshotProvisioner snapshotProvisioner, + ContainerSystemSettingsProvisionersApplier dockerSettingsProvisioners, + ExcludeFoldersFromSnapshotProvisioner snapshotVolumeProvisioner, ProjectsVolumeProvisioner projectsVolumeProvisioner, - LocalInstallersConfigProvisioner installerConfigProvisioner, - LabelsProvisioner labelsProvisioner, + LocalInstallersBinariesVolumeProvisioner installersBinariesVolumeProvisioner, + RuntimeLabelsProvisioner runtimeLabelsProvisioner, DockerApiHostEnvVariableProvisioner dockerApiEnvProvisioner, - ToolingServersEnvVarsProvisioner toolingServersEnvVarsProvisioner, - WsAgentServerConfigProvisioner wsAgentServerConfigProvisioner) { + ToolingServersEnvVarsProvisioner agentsServersEnvVarsProvisioner, + WsAgentServerConfigProvisioner wsAgentServerConfigProvisioner, + ServersConverter serversConverter, + EnvVarsConverter envVarsConverter, + MemoryAttributeConverter memoryAttributeConverter) { - this.settingsProvisioners = settingsProvisioners; - this.snapshotProvisioner = snapshotProvisioner; + this.dockerSettingsProvisioners = dockerSettingsProvisioners; + this.snapshotVolumeProvisioner = snapshotVolumeProvisioner; this.projectsVolumeProvisioner = projectsVolumeProvisioner; - this.installerConfigProvisioner = installerConfigProvisioner; - this.labelsProvisioner = labelsProvisioner; + this.installersBinariesVolumeProvisioner = installersBinariesVolumeProvisioner; + this.runtimeLabelsProvisioner = runtimeLabelsProvisioner; this.dockerApiEnvProvisioner = dockerApiEnvProvisioner; - this.toolingServersEnvVarsProvisioner = toolingServersEnvVarsProvisioner; + this.agentsServersEnvVarsProvisioner = agentsServersEnvVarsProvisioner; this.wsAgentServerConfigProvisioner = wsAgentServerConfigProvisioner; + this.serversConverter = serversConverter; + this.envVarsConverter = envVarsConverter; + this.memoryAttributeConverter = memoryAttributeConverter; } @Override @@ -69,13 +82,20 @@ public class LocalCheInfrastructureProvisioner implements InfrastructureProvisio InternalEnvironment envConfig, DockerEnvironment internalEnv, RuntimeIdentity identity) throws InfrastructureException { - snapshotProvisioner.provision(envConfig, internalEnv, identity); - installerConfigProvisioner.provision(envConfig, internalEnv, identity); + // 1 stage - add Che business logic items to Che model env + // 2 stage - converting Che model env to docker env + serversConverter.provision(envConfig, internalEnv, identity); + envVarsConverter.provision(envConfig, internalEnv, identity); + memoryAttributeConverter.provision(envConfig, internalEnv, identity); + // 3 stage - add docker env items + runtimeLabelsProvisioner.provision(envConfig, internalEnv, identity); + snapshotVolumeProvisioner.provision(envConfig, internalEnv, identity); + installersBinariesVolumeProvisioner.provision(envConfig, internalEnv, identity); projectsVolumeProvisioner.provision(envConfig, internalEnv, identity); - settingsProvisioners.provision(envConfig, internalEnv, identity); - labelsProvisioner.provision(envConfig, internalEnv, identity); - dockerApiEnvProvisioner.provision(envConfig, internalEnv, identity); - toolingServersEnvVarsProvisioner.provision(envConfig, internalEnv, identity); wsAgentServerConfigProvisioner.provision(envConfig, internalEnv, identity); + dockerSettingsProvisioners.provision(envConfig, internalEnv, identity); + dockerApiEnvProvisioner.provision(envConfig, internalEnv, identity); + // TODO move to abstract code + agentsServersEnvVarsProvisioner.provision(envConfig, internalEnv, identity); } } diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/LocalDockerModule.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/LocalDockerModule.java index c781a4100a..01edf2714f 100644 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/LocalDockerModule.java +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/LocalDockerModule.java @@ -10,7 +10,7 @@ */ package org.eclipse.che.workspace.infrastructure.docker.local; -import static org.eclipse.che.workspace.infrastructure.docker.local.installer.LocalInstallersConfigProvisioner.LOCAL_INSTALLERS_PROVISIONERS; +import static org.eclipse.che.workspace.infrastructure.docker.local.installer.LocalInstallersBinariesVolumeProvisioner.LOCAL_INSTALLERS_PROVISIONERS; import com.google.inject.AbstractModule; import com.google.inject.multibindings.Multibinder; diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/installer/LocalInstallersConfigProvisioner.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/installer/LocalInstallersBinariesVolumeProvisioner.java similarity index 73% rename from infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/installer/LocalInstallersConfigProvisioner.java rename to infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/installer/LocalInstallersBinariesVolumeProvisioner.java index 37c858b93e..3a82de8b55 100644 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/installer/LocalInstallersConfigProvisioner.java +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/installer/LocalInstallersBinariesVolumeProvisioner.java @@ -18,27 +18,23 @@ import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.InternalEnvironment; import org.eclipse.che.workspace.infrastructure.docker.model.DockerEnvironment; import org.eclipse.che.workspace.infrastructure.docker.provisioner.ConfigurationProvisioner; -import org.eclipse.che.workspace.infrastructure.docker.provisioner.installer.InstallerConfigApplier; -import org.eclipse.che.workspace.infrastructure.docker.provisioner.installer.InstallersConfigProvisioner; /** - * Provisions an environment with configuration and binaries that comes from installers of machines - * in the environment. + * Provisions an environment with binaries that comes from installers of machines in the + * environment. * * @author Alexander Garagatyi */ -public class LocalInstallersConfigProvisioner extends InstallersConfigProvisioner { +public class LocalInstallersBinariesVolumeProvisioner implements ConfigurationProvisioner { public static final String LOCAL_INSTALLERS_PROVISIONERS = "infrastructure.docker.local_installers_provisioners"; private final Set localInstallerProvisioners; @Inject - public LocalInstallersConfigProvisioner( - InstallerConfigApplier installerConfigApplier, + public LocalInstallersBinariesVolumeProvisioner( @Named(LOCAL_INSTALLERS_PROVISIONERS) Set localInstallerProvisioners) { - super(installerConfigApplier); this.localInstallerProvisioners = localInstallerProvisioners; } @@ -47,7 +43,6 @@ public class LocalInstallersConfigProvisioner extends InstallersConfigProvisione InternalEnvironment envConfig, DockerEnvironment internalEnv, RuntimeIdentity identity) throws InfrastructureException { - super.provision(envConfig, internalEnv, identity); for (ConfigurationProvisioner infrastructureProvisioner : localInstallerProvisioners) { infrastructureProvisioner.provision(envConfig, internalEnv, identity); } diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/env/EnvVarsConverter.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/env/EnvVarsConverter.java new file mode 100644 index 0000000000..51bed910fd --- /dev/null +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/env/EnvVarsConverter.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012-2017 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.workspace.infrastructure.docker.provisioner.env; + +import org.eclipse.che.api.core.model.workspace.config.MachineConfig; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.InternalEnvironment; +import org.eclipse.che.workspace.infrastructure.docker.InfrastructureProvisioner; +import org.eclipse.che.workspace.infrastructure.docker.model.DockerEnvironment; + +/** + * Converts environment variables in {@link MachineConfig} to Docker environment variables. + * + * @author Alexander Garagatyi + */ +public class EnvVarsConverter implements InfrastructureProvisioner { + + @Override + public void provision( + InternalEnvironment environment, DockerEnvironment internalEnv, RuntimeIdentity identity) + throws InfrastructureException { + + environment + .getMachines() + .forEach( + (machineName, machineConfig) -> + internalEnv + .getContainers() + .get(machineName) + .getEnvironment() + .putAll(machineConfig.getEnv())); + } +} diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/installer/InstallerConfigApplier.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/installer/InstallerConfigApplier.java deleted file mode 100644 index 30eee27475..0000000000 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/installer/InstallerConfigApplier.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2012-2017 Red Hat, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.workspace.infrastructure.docker.provisioner.installer; - -import static com.google.common.base.Strings.isNullOrEmpty; -import static java.lang.String.format; -import static org.eclipse.che.workspace.infrastructure.docker.provisioner.installer.InstallerConfigApplier.PROPERTIES.ENVIRONMENT; -import static org.slf4j.LoggerFactory.getLogger; - -import java.util.HashMap; -import java.util.Map; -import org.eclipse.che.api.core.model.workspace.config.ServerConfig; -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.spi.InternalEnvironment; -import org.eclipse.che.api.workspace.server.spi.InternalMachineConfig; -import org.eclipse.che.commons.annotation.Nullable; -import org.eclipse.che.workspace.infrastructure.docker.Labels; -import org.eclipse.che.workspace.infrastructure.docker.model.DockerContainerConfig; -import org.eclipse.che.workspace.infrastructure.docker.model.DockerEnvironment; -import org.slf4j.Logger; - -/** - * Applies docker specific properties of the installers to {@link DockerContainerConfig} or {@link - * DockerEnvironment}. Dependencies between installers are respected. This class must be called - * before machines represented by {@link DockerContainerConfig} is started, otherwise changing - * configuration has no effect.
The list of supported properties are: - *
  • environment The {@code environment} property contains command separated environment variables - * to set respecting the following format: "name=value". - * - * @author Anatolii Bazko - * @author Alexander Garagatyi - * @see Installer#getProperties() - * @see DockerContainerConfig#getEnvironment() - * @see DockerContainerConfig#getPorts() - * @see DockerContainerConfig#getLabels() - */ -public class InstallerConfigApplier { - private static final Logger LOG = getLogger(InstallerConfigApplier.class); - - /** - * Applies docker specific properties to an environment of machines. - * - * @param envConfig environment config with the list of installers that should be injected into - * machine - * @param dockerEnvironment affected environment of machines - * @throws InstallerException if any error occurs - */ - public void apply(InternalEnvironment envConfig, DockerEnvironment dockerEnvironment) - throws InstallerException { - for (Map.Entry machineEntry : - envConfig.getMachines().entrySet()) { - String machineName = machineEntry.getKey(); - InternalMachineConfig machineConf = machineEntry.getValue(); - DockerContainerConfig dockerContainer = dockerEnvironment.getContainers().get(machineName); - - apply(machineConf, dockerContainer); - } - } - - /** - * Applies docker specific properties to a machine. - * - * @param machineConf machine config with the list of installer that should be injected into - * machine - * @param machine affected machine - * @throws InstallerException if any error occurs - */ - public void apply(@Nullable InternalMachineConfig machineConf, DockerContainerConfig machine) - throws InstallerException { - if (machineConf != null) { - for (Installer installer : machineConf.getInstallers()) { - addEnv(machine, installer.getProperties()); - addExposedPorts(machine, installer.getServers()); - addLabels(machine, installer.getServers()); - } - } - } - - private void addLabels( - DockerContainerConfig container, Map servers) { - container.getLabels().putAll(Labels.newSerializer().servers(servers).labels()); - } - - private void addEnv(DockerContainerConfig container, Map properties) { - String environment = properties.get(ENVIRONMENT.toString()); - if (isNullOrEmpty(environment)) { - return; - } - - Map newEnv = new HashMap<>(); - if (container.getEnvironment() != null) { - newEnv.putAll(container.getEnvironment()); - } - - for (String env : environment.split(",")) { - String[] items = env.split("="); - if (items.length != 2) { - LOG.warn(format("Illegal environment variable '%s' format", env)); - continue; - } - String var = items[0]; - String name = items[1]; - - newEnv.put(var, name); - } - - container.setEnvironment(newEnv); - } - - private void addExposedPorts( - DockerContainerConfig container, Map servers) { - for (ServerConfig server : servers.values()) { - container.getExpose().add(server.getPort()); - } - } - - public enum PROPERTIES { - ENVIRONMENT("environment"); - - private final String value; - - PROPERTIES(String value) { - this.value = value; - } - - @Override - public String toString() { - return value; - } - } -} diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/installer/InstallersConfigProvisioner.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/installer/InstallersConfigProvisioner.java deleted file mode 100644 index d0295d87ed..0000000000 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/installer/InstallersConfigProvisioner.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2012-2017 Red Hat, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.workspace.infrastructure.docker.provisioner.installer; - -import javax.inject.Inject; -import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; -import org.eclipse.che.api.installer.server.exception.InstallerException; -import org.eclipse.che.api.workspace.server.spi.InfrastructureException; -import org.eclipse.che.api.workspace.server.spi.InternalEnvironment; -import org.eclipse.che.workspace.infrastructure.docker.model.DockerEnvironment; -import org.eclipse.che.workspace.infrastructure.docker.provisioner.ConfigurationProvisioner; - -/** - * Provisions an environment with configuration that comes from installers of machines in the - * environment. - * - * @author Alexander Garagatyi - */ -public class InstallersConfigProvisioner implements ConfigurationProvisioner { - private final InstallerConfigApplier installerConfigApplier; - - @Inject - public InstallersConfigProvisioner(InstallerConfigApplier installerConfigApplier) { - this.installerConfigApplier = installerConfigApplier; - } - - @Override - public void provision( - InternalEnvironment envConfig, DockerEnvironment internalEnv, RuntimeIdentity identity) - throws InfrastructureException { - try { - installerConfigApplier.apply(envConfig, internalEnv); - } catch (InstallerException e) { - throw new InfrastructureException(e.getLocalizedMessage(), e); - } - } -} diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/labels/LabelsProvisioner.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/labels/RuntimeLabelsProvisioner.java similarity index 80% rename from infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/labels/LabelsProvisioner.java rename to infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/labels/RuntimeLabelsProvisioner.java index 263b4c0c9c..6948937c66 100644 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/labels/LabelsProvisioner.java +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/labels/RuntimeLabelsProvisioner.java @@ -21,11 +21,11 @@ import org.eclipse.che.workspace.infrastructure.docker.model.DockerEnvironment; import org.eclipse.che.workspace.infrastructure.docker.provisioner.ConfigurationProvisioner; /** - * Provision labels related to workspace configuration to docker environment. + * Provision labels related to workspace runtime to docker environment. * * @author Alexander Garagatyi */ -public class LabelsProvisioner implements ConfigurationProvisioner { +public class RuntimeLabelsProvisioner implements ConfigurationProvisioner { @Override public void provision( InternalEnvironment envConfig, DockerEnvironment internalEnv, RuntimeIdentity identity) @@ -36,12 +36,7 @@ public class LabelsProvisioner implements ConfigurationProvisioner { DockerContainerConfig container = internalEnv.getContainers().get(name); container .getLabels() - .putAll( - Labels.newSerializer() - .machineName(name) - .runtimeId(identity) - .servers(entry.getValue().getServers()) - .labels()); + .putAll(Labels.newSerializer().machineName(name).runtimeId(identity).labels()); } } } diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/memory/MemoryAttributeConverter.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/memory/MemoryAttributeConverter.java new file mode 100644 index 0000000000..c124e138d2 --- /dev/null +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/memory/MemoryAttributeConverter.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012-2017 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.workspace.infrastructure.docker.provisioner.memory; + +import static java.lang.String.format; + +import java.util.Map.Entry; +import org.eclipse.che.api.core.model.workspace.config.MachineConfig; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.InternalEnvironment; +import org.eclipse.che.api.workspace.server.spi.InternalMachineConfig; +import org.eclipse.che.workspace.infrastructure.docker.InfrastructureProvisioner; +import org.eclipse.che.workspace.infrastructure.docker.model.DockerEnvironment; + +/** @author Alexander Garagatyi */ +public class MemoryAttributeConverter implements InfrastructureProvisioner { + + @Override + public void provision( + InternalEnvironment environment, DockerEnvironment internalEnv, RuntimeIdentity identity) + throws InfrastructureException { + + for (Entry machineEntry : + environment.getMachines().entrySet()) { + String machineName = machineEntry.getKey(); + InternalMachineConfig machineConfig = machineEntry.getValue(); + + String memory = machineConfig.getAttributes().get(MachineConfig.MEMORY_LIMIT_ATTRIBUTE); + if (memory != null) { + try { + internalEnv.getContainers().get(machineName).setMemLimit(Long.parseLong(memory)); + } catch (NumberFormatException e) { + throw new InfrastructureException( + format( + "Value of attribute 'memoryLimitBytes' of machine '%s' is illegal", machineName)); + } + } + } + } +} diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/server/ServersConverter.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/server/ServersConverter.java new file mode 100644 index 0000000000..27805cd47d --- /dev/null +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/server/ServersConverter.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012-2017 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.workspace.infrastructure.docker.provisioner.server; + +import org.eclipse.che.api.core.model.workspace.config.ServerConfig; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +import org.eclipse.che.api.core.model.workspace.runtime.Server; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.InternalEnvironment; +import org.eclipse.che.workspace.infrastructure.docker.InfrastructureProvisioner; +import org.eclipse.che.workspace.infrastructure.docker.Labels; +import org.eclipse.che.workspace.infrastructure.docker.model.DockerContainerConfig; +import org.eclipse.che.workspace.infrastructure.docker.model.DockerEnvironment; + +/** + * Converts {@link ServerConfig} to Docker related objects to add a server into Docker runtime. + * + *

    Adds ports mapping, exposes, labels to Docker container config to be able to evaluate {@link + * Server}. + * + * @author Alexander Garagatyi + */ +public class ServersConverter implements InfrastructureProvisioner { + + @Override + public void provision( + InternalEnvironment environment, DockerEnvironment internalEnv, RuntimeIdentity identity) + throws InfrastructureException { + + environment + .getMachines() + .forEach( + (machineName, machineConfig) -> { + DockerContainerConfig container = internalEnv.getContainers().get(machineName); + + container + .getLabels() + .putAll(Labels.newSerializer().servers(machineConfig.getServers()).labels()); + + machineConfig + .getServers() + .forEach( + (key, value) -> { + container.getPorts().add(value.getPort()); + container.getExpose().add(value.getPort()); + }); + }); + } +} diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/server/mapping/ServersMapper.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/server/mapping/ServersMapper.java index 0c5b94770d..9d2a75ddd1 100644 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/server/mapping/ServersMapper.java +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/server/mapping/ServersMapper.java @@ -108,7 +108,7 @@ public class ServersMapper { ports .entrySet() .stream() - .filter(entry -> entry.getValue().size() == 1) + .filter(entry -> entry.getValue() != null && entry.getValue().size() == 1) .map(entry -> toContainerPort(entry.getKey(), entry.getValue().get(0))) .toArray(ContainerPort[]::new), configs); diff --git a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/environment/EnvironmentParserTest.java b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/environment/EnvironmentParserTest.java index a2094387ec..91aabc8a69 100644 --- a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/environment/EnvironmentParserTest.java +++ b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/environment/EnvironmentParserTest.java @@ -18,11 +18,9 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertEqualsNoOrder; import com.google.common.collect.ImmutableMap; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -133,70 +131,6 @@ public class EnvironmentParserTest { verify(envParser).parse(environment); } - @Test - public void shouldOverrideMemoryLimitFromExtendedMachineInAnEnv() throws Exception { - // given - Map machines = - ImmutableMap.of( - "machine1", mockMachine(singletonMap("memoryLimitBytes", "101010")), - "machine2", mockMachine()); - when(environment.getMachines()).thenReturn(machines); - - DockerEnvironment dockerEnv = new DockerEnvironment(); - dockerEnv.getContainers().put("machine1", new DockerContainerConfig()); - dockerEnv.getContainers().put("machine2", new DockerContainerConfig()); - when(envParser.parse(environment)).thenReturn(dockerEnv); - - DockerEnvironment expected = new DockerEnvironment(); - expected.getContainers().put("machine1", new DockerContainerConfig().setMemLimit(101010L)); - expected.getContainers().put("machine2", new DockerContainerConfig()); - - // when - DockerEnvironment actual = parser.parse(environment); - - // then - assertEquals(actual, expected); - } - - @Test( - expectedExceptions = ValidationException.class, - expectedExceptionsMessageRegExp = - "Value of attribute 'memoryLimitBytes' of machine '.*' is illegal" - ) - public void shouldThrowExceptionInCaseFailedParseMemoryLimit() throws Exception { - // given - when(machine.getAttributes()).thenReturn(singletonMap("memoryLimitBytes", "AF")); - - // when - parser.parse(environment); - } - - @Test(dataProvider = "environmentWithServersProvider") - public void shouldAddExposesFromExtendedMachineServers( - InternalMachineConfig machineConfig, - DockerContainerConfig parsedContainer, - List expectedExposes) - throws Exception { - - // given - when(environment.getMachines()).thenReturn(singletonMap(DEFAULT_MACHINE_NAME, machineConfig)); - when(dockerEnv.getContainers()).thenReturn(singletonMap(DEFAULT_MACHINE_NAME, parsedContainer)); - - // when - DockerEnvironment actual = parser.parse(environment); - - // then - // prevent failures because of reordered entries of expose field - assertEquals(actual.getContainers().size(), 1); - assertEqualsNoOrder( - actual.getContainers().get(DEFAULT_MACHINE_NAME).getExpose().toArray(), - expectedExposes.toArray(), - String.format( - "Arrays are not equal. Actual: '%s'. Expected: '%s'", - Arrays.toString(actual.getContainers().get(DEFAULT_MACHINE_NAME).getExpose().toArray()), - Arrays.toString(expectedExposes.toArray()))); - } - @DataProvider(name = "environmentWithServersProvider") public static Object[][] environmentWithServersProvider() { // Format of result array: diff --git a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/environment/EnvironmentValidatorTest.java b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/environment/EnvironmentValidatorTest.java index 13338af241..f53855e4f5 100644 --- a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/environment/EnvironmentValidatorTest.java +++ b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/environment/EnvironmentValidatorTest.java @@ -15,6 +15,7 @@ import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; +import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -81,7 +82,7 @@ public class EnvironmentValidatorTest { when(machineConfig.getServers()) .thenReturn(singletonMap(Constants.SERVER_WS_AGENT_HTTP_REFERENCE, server)); Map attributes = - ImmutableMap.of("testKey", "value", "memoryLimitBytes", "1000000000"); + ImmutableMap.of("testKey", "value", MEMORY_LIMIT_ATTRIBUTE, "1000000000"); when(machineConfig.getAttributes()).thenReturn(attributes); when(container.getExpose()).thenReturn(asList("8090", "9090/tcp", "7070/udp")); when(container.getLinks()).thenReturn(singletonList(machine2Name + ":alias1")); @@ -277,27 +278,6 @@ public class EnvironmentValidatorTest { environmentValidator.validate(environment, dockerEnvironment); } - @Test( - expectedExceptions = ValidationException.class, - expectedExceptionsMessageRegExp = - "Value of attribute 'memoryLimitBytes' of machine '.*' in environment is illegal", - dataProvider = "memoryAttributeValue" - ) - public void shouldFailIfMemoryAttributeIsIllegal(String memoryAttributeValue) throws Exception { - // given - Map attributes = - ImmutableMap.of("testKey", "value", "memoryLimitBytes", memoryAttributeValue); - when(machineConfig.getAttributes()).thenReturn(attributes); - - // when - environmentValidator.validate(environment, dockerEnvironment); - } - - @DataProvider(name = "memoryAttributeValue") - public static Object[][] memoryAttributeValue() { - return new Object[][] {{"aa"}, {""}, {"!"}, {"156a"}, {"0"}, {"-1"}}; - } - @Test( expectedExceptions = ValidationException.class, expectedExceptionsMessageRegExp = diff --git a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/LocalCheInfrastructureProvisionerTest.java b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/LocalCheInfrastructureProvisionerTest.java index 7e0cf3a696..74b6855fc9 100644 --- a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/LocalCheInfrastructureProvisionerTest.java +++ b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/LocalCheInfrastructureProvisionerTest.java @@ -15,16 +15,18 @@ import static org.mockito.ArgumentMatchers.eq; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.workspace.server.spi.InternalEnvironment; import org.eclipse.che.workspace.infrastructure.docker.local.dod.DockerApiHostEnvVariableProvisioner; -import org.eclipse.che.workspace.infrastructure.docker.local.installer.LocalInstallersConfigProvisioner; +import org.eclipse.che.workspace.infrastructure.docker.local.installer.LocalInstallersBinariesVolumeProvisioner; import org.eclipse.che.workspace.infrastructure.docker.local.installer.WsAgentServerConfigProvisioner; import org.eclipse.che.workspace.infrastructure.docker.local.projects.ProjectsVolumeProvisioner; import org.eclipse.che.workspace.infrastructure.docker.model.DockerEnvironment; import org.eclipse.che.workspace.infrastructure.docker.provisioner.ContainerSystemSettingsProvisionersApplier; -import org.eclipse.che.workspace.infrastructure.docker.provisioner.labels.LabelsProvisioner; +import org.eclipse.che.workspace.infrastructure.docker.provisioner.env.EnvVarsConverter; +import org.eclipse.che.workspace.infrastructure.docker.provisioner.labels.RuntimeLabelsProvisioner; +import org.eclipse.che.workspace.infrastructure.docker.provisioner.memory.MemoryAttributeConverter; +import org.eclipse.che.workspace.infrastructure.docker.provisioner.server.ServersConverter; import org.eclipse.che.workspace.infrastructure.docker.provisioner.server.ToolingServersEnvVarsProvisioner; import org.eclipse.che.workspace.infrastructure.docker.provisioner.snapshot.ExcludeFoldersFromSnapshotProvisioner; import org.mockito.InOrder; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.testng.MockitoTestNGListener; @@ -35,23 +37,42 @@ import org.testng.annotations.Test; /** @author Alexander Garagatyi */ @Listeners(MockitoTestNGListener.class) public class LocalCheInfrastructureProvisionerTest { + @Mock private ContainerSystemSettingsProvisionersApplier settingsProvisioners; @Mock private ExcludeFoldersFromSnapshotProvisioner snapshotProvisioner; @Mock private ProjectsVolumeProvisioner projectsVolumeProvisioner; - @Mock private LocalInstallersConfigProvisioner installerConfigProvisioner; - @Mock private LabelsProvisioner labelsProvisioner; + @Mock private LocalInstallersBinariesVolumeProvisioner installerConfigProvisioner; + @Mock private RuntimeLabelsProvisioner labelsProvisioner; @Mock private DockerApiHostEnvVariableProvisioner dockerApiEnvProvisioner; @Mock private ToolingServersEnvVarsProvisioner toolingServersEnvVarsProvisioner; @Mock private InternalEnvironment environment; @Mock private DockerEnvironment dockerEnvironment; @Mock private RuntimeIdentity runtimeIdentity; @Mock private WsAgentServerConfigProvisioner wsAgentServerConfigProvisioner; - @InjectMocks private LocalCheInfrastructureProvisioner provisioner; + @Mock private ServersConverter serversConverter; + @Mock private EnvVarsConverter envVarsConverter; + @Mock private MemoryAttributeConverter memoryAttributeConverter; + + private LocalCheInfrastructureProvisioner provisioner; private Object[] allInnerProvisioners; @BeforeMethod public void setUp() throws Exception { + provisioner = + new LocalCheInfrastructureProvisioner( + settingsProvisioners, + snapshotProvisioner, + projectsVolumeProvisioner, + installerConfigProvisioner, + labelsProvisioner, + dockerApiEnvProvisioner, + toolingServersEnvVarsProvisioner, + wsAgentServerConfigProvisioner, + serversConverter, + envVarsConverter, + memoryAttributeConverter); + allInnerProvisioners = new Object[] { settingsProvisioners, @@ -61,7 +82,10 @@ public class LocalCheInfrastructureProvisionerTest { labelsProvisioner, dockerApiEnvProvisioner, toolingServersEnvVarsProvisioner, - wsAgentServerConfigProvisioner + wsAgentServerConfigProvisioner, + serversConverter, + envVarsConverter, + memoryAttributeConverter }; } @@ -72,6 +96,18 @@ public class LocalCheInfrastructureProvisionerTest { // then InOrder inOrder = Mockito.inOrder((Object[]) allInnerProvisioners); + inOrder + .verify(serversConverter) + .provision(eq(environment), eq(dockerEnvironment), eq(runtimeIdentity)); + inOrder + .verify(envVarsConverter) + .provision(eq(environment), eq(dockerEnvironment), eq(runtimeIdentity)); + inOrder + .verify(memoryAttributeConverter) + .provision(eq(environment), eq(dockerEnvironment), eq(runtimeIdentity)); + inOrder + .verify(labelsProvisioner) + .provision(eq(environment), eq(dockerEnvironment), eq(runtimeIdentity)); inOrder .verify(snapshotProvisioner) .provision(eq(environment), eq(dockerEnvironment), eq(runtimeIdentity)); @@ -82,10 +118,10 @@ public class LocalCheInfrastructureProvisionerTest { .verify(projectsVolumeProvisioner) .provision(eq(environment), eq(dockerEnvironment), eq(runtimeIdentity)); inOrder - .verify(settingsProvisioners) + .verify(wsAgentServerConfigProvisioner) .provision(eq(environment), eq(dockerEnvironment), eq(runtimeIdentity)); inOrder - .verify(labelsProvisioner) + .verify(settingsProvisioners) .provision(eq(environment), eq(dockerEnvironment), eq(runtimeIdentity)); inOrder .verify(dockerApiEnvProvisioner) @@ -93,9 +129,6 @@ public class LocalCheInfrastructureProvisionerTest { inOrder .verify(toolingServersEnvVarsProvisioner) .provision(eq(environment), eq(dockerEnvironment), eq(runtimeIdentity)); - inOrder - .verify(wsAgentServerConfigProvisioner) - .provision(eq(environment), eq(dockerEnvironment), eq(runtimeIdentity)); inOrder.verifyNoMoreInteractions(); } } diff --git a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/installer/InstallerConfigApplierTest.java b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/installer/InstallerConfigApplierTest.java deleted file mode 100644 index 8810881034..0000000000 --- a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/provisioner/installer/InstallerConfigApplierTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2012-2017 Red Hat, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.workspace.infrastructure.docker.provisioner.installer; - -import static java.util.Arrays.asList; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonList; -import static java.util.Collections.singletonMap; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -import java.util.List; -import java.util.Map; -import org.eclipse.che.api.core.model.workspace.config.ServerConfig; -import org.eclipse.che.api.installer.server.model.impl.InstallerImpl; -import org.eclipse.che.api.workspace.server.spi.InternalMachineConfig; -import org.eclipse.che.workspace.infrastructure.docker.model.DockerContainerConfig; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -/** @author Anatolii Bazko */ -@Listeners(value = {MockitoTestNGListener.class}) -public class InstallerConfigApplierTest { - @Mock private InstallerImpl installer1; - @Mock private InstallerImpl installer2; - @Mock private InstallerImpl installer3; - - private InstallerConfigApplier installerConfigApplier; - - @BeforeMethod - public void setUp() throws Exception { - installerConfigApplier = new InstallerConfigApplier(); - - when(installer1.getScript()).thenReturn("script1"); - when(installer1.getDependencies()).thenReturn(singletonList("installer3")); - - when(installer2.getScript()).thenReturn("script2"); - when(installer2.getDependencies()).thenReturn(singletonList("installer2")); - - when(installer3.getScript()).thenReturn("script3"); - } - - @Test - public void shouldAddLabels() throws Exception { - final ServerConfig serverConf1 = mock(ServerConfig.class); - when(serverConf1.getPort()).thenReturn("1111/udp"); - when(serverConf1.getProtocol()).thenReturn("http"); - when(serverConf1.getPath()).thenReturn("b"); - - when(installer1.getServers()).thenAnswer(invocation -> singletonMap("a", serverConf1)); - DockerContainerConfig containerConf = new DockerContainerConfig(); - InternalMachineConfig machineConfig = mock(InternalMachineConfig.class); - when(machineConfig.getInstallers()).thenReturn(singletonList(installer1)); - - installerConfigApplier.apply(machineConfig, containerConf); - - Map labels = containerConf.getLabels(); - assertEquals(labels.size(), 3); - assertEquals(labels.get("org.eclipse.che.server.a.port"), "1111/udp"); - assertEquals(labels.get("org.eclipse.che.server.a.protocol"), "http"); - assertEquals(labels.get("org.eclipse.che.server.a.path"), "b"); - } - - @Test - public void shouldAddExposedPorts() throws Exception { - final ServerConfig serverConf1 = mock(ServerConfig.class); - final ServerConfig serverConfig = mock(ServerConfig.class); - when(serverConf1.getPort()).thenReturn("1111/udp"); - when(serverConfig.getPort()).thenReturn("2222/tcp"); - - when(installer1.getServers()).thenAnswer(invocation -> singletonMap("a", serverConf1)); - when(installer2.getServers()).thenAnswer(invocation -> singletonMap("b", serverConfig)); - when(installer3.getServers()).thenReturn(emptyMap()); - DockerContainerConfig containerConf = new DockerContainerConfig(); - InternalMachineConfig machineConfig = mock(InternalMachineConfig.class); - when(machineConfig.getInstallers()).thenReturn(asList(installer1, installer2, installer3)); - - installerConfigApplier.apply(machineConfig, containerConf); - - List exposedPorts = containerConf.getExpose(); - assertTrue(exposedPorts.contains("1111/udp")); - assertTrue(exposedPorts.contains("2222/tcp")); - } - - @Test - public void shouldAddEnvVariables() throws Exception { - when(installer1.getProperties()).thenReturn(singletonMap("environment", "p1=v1,p2=v2")); - when(installer2.getProperties()).thenReturn(singletonMap("environment", "p3=v3")); - DockerContainerConfig containerConf = new DockerContainerConfig(); - InternalMachineConfig machineConfig = mock(InternalMachineConfig.class); - when(machineConfig.getInstallers()).thenReturn(asList(installer1, installer2)); - - installerConfigApplier.apply(machineConfig, containerConf); - - Map env = containerConf.getEnvironment(); - assertEquals(env.size(), 3); - assertEquals(env.get("p1"), "v1"); - assertEquals(env.get("p2"), "v2"); - assertEquals(env.get("p3"), "v3"); - } - - @Test - public void shouldIgnoreEnvironmentIfIllegalFormat() throws Exception { - when(installer1.getProperties()).thenReturn(singletonMap("environment", "p1")); - DockerContainerConfig containerConf = new DockerContainerConfig(); - InternalMachineConfig machineConfig = mock(InternalMachineConfig.class); - when(machineConfig.getInstallers()).thenReturn(singletonList(installer1)); - - installerConfigApplier.apply(machineConfig, containerConf); - - Map env = containerConf.getEnvironment(); - assertEquals(env.size(), 0); - } -} diff --git a/infrastructures/openshift/pom.xml b/infrastructures/openshift/pom.xml index e7d06e583d..c40b770e3a 100644 --- a/infrastructures/openshift/pom.xml +++ b/infrastructures/openshift/pom.xml @@ -74,10 +74,6 @@ org.eclipse.che.core che-core-api-installer - - org.eclipse.che.core - che-core-api-installer-shared - org.eclipse.che.core che-core-api-model diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructureProvisioner.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructureProvisioner.java index 2ff93fb995..6f289843b0 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructureProvisioner.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructureProvisioner.java @@ -17,8 +17,12 @@ import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.InternalEnvironment; import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment; import org.eclipse.che.workspace.infrastructure.openshift.provision.UniqueNamesProvisioner; +import org.eclipse.che.workspace.infrastructure.openshift.provision.env.EnvVarsConverter; import org.eclipse.che.workspace.infrastructure.openshift.provision.installer.InstallerConfigProvisioner; +import org.eclipse.che.workspace.infrastructure.openshift.provision.labels.PodNameLabelProvisioner; +import org.eclipse.che.workspace.infrastructure.openshift.provision.restartpolicy.RestartPolicyRewriter; import org.eclipse.che.workspace.infrastructure.openshift.provision.route.TlsRouteProvisioner; +import org.eclipse.che.workspace.infrastructure.openshift.provision.server.ServersConverter; import org.eclipse.che.workspace.infrastructure.openshift.provision.volume.PersistentVolumeClaimProvisioner; /** @@ -26,33 +30,54 @@ import org.eclipse.che.workspace.infrastructure.openshift.provision.volume.Persi * the desired order, which corresponds to the needs of the OpenShift infrastructure. * * @author Anton Korneta + * @author Alexander Garagatyi */ @Singleton public class OpenShiftInfrastructureProvisioner { - private final InstallerConfigProvisioner installerConfigProvisioner; private final PersistentVolumeClaimProvisioner persistentVolumeClaimProvisioner; private final UniqueNamesProvisioner uniqueNamesProvisioner; private final TlsRouteProvisioner tlsRouteProvisioner; + private final ServersConverter serversConverter; + private final EnvVarsConverter envVarsConverter; + private final RestartPolicyRewriter restartPolicyRewriter; + private final PodNameLabelProvisioner podNameLabelProvisioner; @Inject public OpenShiftInfrastructureProvisioner( InstallerConfigProvisioner installerConfigProvisioner, PersistentVolumeClaimProvisioner projectVolumeProvisioner, UniqueNamesProvisioner uniqueNamesProvisioner, - TlsRouteProvisioner tlsRouteProvisioner) { + TlsRouteProvisioner tlsRouteProvisioner, + ServersConverter serversConverter, + EnvVarsConverter envVarsConverter, + RestartPolicyRewriter restartPolicyRewriter, + PodNameLabelProvisioner podNameLabelProvisioner) { this.installerConfigProvisioner = installerConfigProvisioner; this.persistentVolumeClaimProvisioner = projectVolumeProvisioner; this.uniqueNamesProvisioner = uniqueNamesProvisioner; this.tlsRouteProvisioner = tlsRouteProvisioner; + this.serversConverter = serversConverter; + this.envVarsConverter = envVarsConverter; + this.restartPolicyRewriter = restartPolicyRewriter; + this.podNameLabelProvisioner = podNameLabelProvisioner; } public void provision( InternalEnvironment environment, OpenShiftEnvironment osEnv, RuntimeIdentity identity) throws InfrastructureException { + // 1 stage - add Che business logic items to Che model env installerConfigProvisioner.provision(environment, osEnv, identity); + // 2 stage - converting Che model env to OpenShift env + serversConverter.provision(environment, osEnv, identity); + envVarsConverter.provision(environment, osEnv, identity); + // 3 stage - add OpenShift env items + podNameLabelProvisioner.provision(environment, osEnv, identity); + restartPolicyRewriter.provision(environment, osEnv, identity); persistentVolumeClaimProvisioner.provision(environment, osEnv, identity); uniqueNamesProvisioner.provision(environment, osEnv, identity); tlsRouteProvisioner.provision(environment, osEnv, identity); } + + // TODO memory attribute provisioner } diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentParser.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentParser.java index 4e600c5577..9bb3aa761c 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentParser.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentParser.java @@ -11,34 +11,25 @@ package org.eclipse.che.workspace.infrastructure.openshift.environment; import static java.lang.String.format; -import static org.eclipse.che.workspace.infrastructure.openshift.Constants.CHE_POD_NAME_LABEL; -import io.fabric8.kubernetes.api.model.Container; -import io.fabric8.kubernetes.api.model.EnvVar; import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.KubernetesList; -import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; import io.fabric8.kubernetes.api.model.Pod; -import io.fabric8.kubernetes.api.model.PodSpec; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.openshift.api.model.DeploymentConfig; import io.fabric8.openshift.api.model.Route; import io.fabric8.openshift.client.OpenShiftClient; import java.io.ByteArrayInputStream; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.Map.Entry; import javax.inject.Inject; import org.eclipse.che.api.core.ValidationException; 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.InternalEnvironment; import org.eclipse.che.api.workspace.server.spi.InternalEnvironment.InternalRecipe; -import org.eclipse.che.api.workspace.server.spi.InternalMachineConfig; import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftClientFactory; -import org.eclipse.che.workspace.infrastructure.openshift.ServerExposer; import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment.Builder; /** @@ -64,8 +55,6 @@ public class OpenShiftEnvironmentParser { static final String PVC_IGNORED_WARNING_MESSAGE = "Persistent volume claims specified in OpenShift recipe are ignored."; - static final String DEFAULT_RESTART_POLICY = "Never"; - private final OpenShiftClientFactory clientFactory; @Inject @@ -144,63 +133,7 @@ public class OpenShiftEnvironmentParser { new WarningImpl(PVC_IGNORED_WARNING_CODE, PVC_IGNORED_WARNING_MESSAGE)); } - OpenShiftEnvironment openShiftEnv = openShiftEnvBuilder.build(); - - normalizeEnvironment(openShiftEnv, environment); - - return openShiftEnv; - } - - private void normalizeEnvironment( - OpenShiftEnvironment openShiftEnvironment, InternalEnvironment environment) - throws ValidationException { - for (Pod podConfig : openShiftEnvironment.getPods().values()) { - final String podName = podConfig.getMetadata().getName(); - getLabels(podConfig).put(CHE_POD_NAME_LABEL, podName); - final PodSpec podSpec = podConfig.getSpec(); - rewriteRestartPolicy(podSpec, podName, environment); - for (Container containerConfig : podSpec.getContainers()) { - String machineName = podName + '/' + containerConfig.getName(); - InternalMachineConfig machineConfig = environment.getMachines().get(machineName); - if (machineConfig != null && !machineConfig.getServers().isEmpty()) { - ServerExposer serverExposer = - new ServerExposer(machineName, containerConfig, openShiftEnvironment); - serverExposer.expose(machineConfig.getServers()); - - for (Entry envEntry : machineConfig.getEnv().entrySet()) { - putEnv(containerConfig.getEnv(), envEntry.getKey(), envEntry.getValue()); - } - } - } - } - } - - private Map getLabels(Pod pod) { - ObjectMeta metadata = pod.getMetadata(); - if (metadata == null) { - metadata = new ObjectMeta(); - pod.setMetadata(metadata); - } - - Map labels = metadata.getLabels(); - if (labels == null) { - labels = new HashMap<>(); - metadata.setLabels(labels); - } - return labels; - } - - private void rewriteRestartPolicy(PodSpec podSpec, String podName, InternalEnvironment env) { - final String restartPolicy = podSpec.getRestartPolicy(); - - if (restartPolicy != null && !DEFAULT_RESTART_POLICY.equalsIgnoreCase(restartPolicy)) { - final String warnMsg = - format( - "Restart policy '%s' for pod '%s' is rewritten with %s", - restartPolicy, podName, DEFAULT_RESTART_POLICY); - env.addWarning(new WarningImpl(101, warnMsg)); - } - podSpec.setRestartPolicy(DEFAULT_RESTART_POLICY); + return openShiftEnvBuilder.build(); } private void checkNotNull(Object object, String errorMessage) throws ValidationException { @@ -208,9 +141,4 @@ public class OpenShiftEnvironmentParser { throw new ValidationException(errorMessage); } } - - private void putEnv(List envs, String key, String value) { - envs.removeIf(env -> key.equals(env.getName())); - envs.add(new EnvVar(key, value, null)); - } } diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/env/EnvVarsConverter.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/env/EnvVarsConverter.java new file mode 100644 index 0000000000..91c58b5b6c --- /dev/null +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/env/EnvVarsConverter.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012-2017 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.workspace.infrastructure.openshift.provision.env; + +import io.fabric8.kubernetes.api.model.Container; +import io.fabric8.kubernetes.api.model.EnvVar; +import io.fabric8.kubernetes.api.model.Pod; +import javax.inject.Singleton; +import org.eclipse.che.api.core.model.workspace.config.MachineConfig; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.InternalEnvironment; +import org.eclipse.che.api.workspace.server.spi.InternalMachineConfig; +import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment; +import org.eclipse.che.workspace.infrastructure.openshift.provision.ConfigurationProvisioner; + +/** + * Converts environment variables in {@link MachineConfig} to OpenShift environment variables. + * + * @author Alexander Garagatyi + */ +@Singleton +public class EnvVarsConverter implements ConfigurationProvisioner { + @Override + public void provision( + InternalEnvironment environment, OpenShiftEnvironment osEnv, RuntimeIdentity identity) + throws InfrastructureException { + + for (Pod pod : osEnv.getPods().values()) { + String podName = pod.getMetadata().getName(); + for (Container container : pod.getSpec().getContainers()) { + String containerName = container.getName(); + String machineName = podName + "/" + containerName; + InternalMachineConfig machineConf = environment.getMachines().get(machineName); + + if (machineConf != null) { + machineConf + .getEnv() + .forEach( + (key, value) -> { + container.getEnv().removeIf(env -> key.equals(env.getName())); + container.getEnv().add(new EnvVar(key, value, null)); + }); + } + } + } + } +} diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/installer/InstallerConfigProvisioner.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/installer/InstallerConfigProvisioner.java index b8b76d90b1..eda7809f4e 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/installer/InstallerConfigProvisioner.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/installer/InstallerConfigProvisioner.java @@ -10,19 +10,11 @@ */ package org.eclipse.che.workspace.infrastructure.openshift.provision.installer; -import static com.google.common.base.Strings.isNullOrEmpty; -import static java.lang.String.format; -import static org.slf4j.LoggerFactory.getLogger; - -import io.fabric8.kubernetes.api.model.Container; -import io.fabric8.kubernetes.api.model.EnvVar; -import io.fabric8.kubernetes.api.model.Pod; -import java.util.List; -import java.util.Map; +import java.util.Map.Entry; import javax.inject.Inject; import javax.inject.Named; +import org.eclipse.che.api.core.model.workspace.config.MachineConfig; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; -import org.eclipse.che.api.installer.shared.model.Installer; import org.eclipse.che.api.workspace.server.WsAgentMachineFinderUtil; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.InternalEnvironment; @@ -30,30 +22,15 @@ import org.eclipse.che.api.workspace.server.spi.InternalMachineConfig; import org.eclipse.che.api.workspace.server.token.MachineTokenProvider; import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment; import org.eclipse.che.workspace.infrastructure.openshift.provision.ConfigurationProvisioner; -import org.slf4j.Logger; /** - * Applies OpenShift specific properties of the installers to {@link OpenShiftEnvironment}. - * - *

    This class must be called before OpenShift environment is started, otherwise changing - * configuration has no effect. - * - *

    This class performs following changes to environment:
    - * - adds environment variable to {@link Container containers} that are required by installers or - * agents.
    - * - adds environment variables which are specified in properties of installer configuration. The - * environment property contains environment variables in the following format: - * "env1=value1,env2=value2,...";
    - * - performs all required changes that are needed for exposing installers' servers. + * Adds environment variable to {@link MachineConfig} that are required by installers or agents. * * @author Sergii Leshchenko + * @author Alexander Garagatyi */ public class InstallerConfigProvisioner implements ConfigurationProvisioner { - private static final Logger LOG = getLogger(InstallerConfigProvisioner.class); - - private static final String ENVIRONMENT_PROPERTY = "environment"; - private final MachineTokenProvider machineTokenProvider; private final String cheServerEndpoint; @@ -73,56 +50,20 @@ public class InstallerConfigProvisioner implements ConfigurationProvisioner { WsAgentMachineFinderUtil.getWsAgentServerMachine(environment) .orElseThrow(() -> new InfrastructureException("Machine with wsagent not found")); - for (Pod pod : osEnv.getPods().values()) { - String podName = pod.getMetadata().getName(); - for (Container container : pod.getSpec().getContainers()) { - String containerName = container.getName(); - String machineName = podName + "/" + containerName; - InternalMachineConfig machineConf = environment.getMachines().get(machineName); + for (Entry machineEntry : environment.getMachines().entrySet()) { + InternalMachineConfig config = machineEntry.getValue(); - for (Installer installer : machineConf.getInstallers()) { - provisionEnv(container, installer.getProperties()); - } + // CHE_API is used by installers for agent binary downloading + config.getEnv().put("CHE_API", cheServerEndpoint); - // CHE_API is used by installers for agent binary downloading - putEnv(container.getEnv(), "CHE_API", cheServerEndpoint); + config.getEnv().put("USER_TOKEN", machineTokenProvider.getToken(identity.getWorkspaceId())); - putEnv( - container.getEnv(), - "USER_TOKEN", - machineTokenProvider.getToken(identity.getWorkspaceId())); - - // TODO incorrect place for env variable addition. workspace ID is needed for wsagent - // server, not installer - // WORKSPACE_ID is required only by workspace agent - if (devMachineName.equals(machineName)) { - putEnv(container.getEnv(), "CHE_WORKSPACE_ID", identity.getWorkspaceId()); - } + // TODO incorrect place for env variable addition. workspace ID is needed for wsagent + // server, not installer + // WORKSPACE_ID is required only by workspace agent + if (devMachineName.equals(machineEntry.getKey())) { + config.getEnv().put("CHE_WORKSPACE_ID", identity.getWorkspaceId()); } } } - - private void putEnv(List envs, String key, String value) { - envs.removeIf(env -> key.equals(env.getName())); - envs.add(new EnvVar(key, value, null)); - } - - private void provisionEnv(Container container, Map properties) { - String environment = properties.get(ENVIRONMENT_PROPERTY); - if (isNullOrEmpty(environment)) { - return; - } - - for (String env : environment.split(",")) { - String[] items = env.split("="); - if (items.length != 2) { - LOG.warn(format("Illegal environment variable '%s' format", env)); - continue; - } - String name = items[0]; - String value = items[1]; - - container.getEnv().add(new EnvVar(name, value, null)); - } - } } diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/labels/PodNameLabelProvisioner.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/labels/PodNameLabelProvisioner.java new file mode 100644 index 0000000000..4758d90d47 --- /dev/null +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/labels/PodNameLabelProvisioner.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2012-2017 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.workspace.infrastructure.openshift.provision.labels; + +import static org.eclipse.che.workspace.infrastructure.openshift.Constants.CHE_POD_NAME_LABEL; + +import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.kubernetes.api.model.Pod; +import java.util.HashMap; +import java.util.Map; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.InternalEnvironment; +import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment; +import org.eclipse.che.workspace.infrastructure.openshift.provision.ConfigurationProvisioner; + +/** @author Alexander Garagatyi */ +public class PodNameLabelProvisioner implements ConfigurationProvisioner { + + @Override + public void provision( + InternalEnvironment environment, OpenShiftEnvironment osEnv, RuntimeIdentity identity) + throws InfrastructureException { + + for (Pod podConfig : osEnv.getPods().values()) { + final String podName = podConfig.getMetadata().getName(); + getLabels(podConfig).put(CHE_POD_NAME_LABEL, podName); + } + } + + private Map getLabels(Pod pod) { + ObjectMeta metadata = pod.getMetadata(); + if (metadata == null) { + metadata = new ObjectMeta(); + pod.setMetadata(metadata); + } + + Map labels = metadata.getLabels(); + if (labels == null) { + labels = new HashMap<>(); + metadata.setLabels(labels); + } + return labels; + } +} diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/restartpolicy/RestartPolicyRewriter.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/restartpolicy/RestartPolicyRewriter.java new file mode 100644 index 0000000000..95c3cd9c94 --- /dev/null +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/restartpolicy/RestartPolicyRewriter.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012-2017 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.workspace.infrastructure.openshift.provision.restartpolicy; + +import static java.lang.String.format; + +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodSpec; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +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.InternalEnvironment; +import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment; +import org.eclipse.che.workspace.infrastructure.openshift.provision.ConfigurationProvisioner; + +/** + * Rewrites restart policy to supported one - 'Never'. + * + * @author Alexander Garagatyi + */ +public class RestartPolicyRewriter implements ConfigurationProvisioner { + static final String DEFAULT_RESTART_POLICY = "Never"; + + @Override + public void provision( + InternalEnvironment environment, OpenShiftEnvironment osEnv, RuntimeIdentity identity) + throws InfrastructureException { + + for (Pod podConfig : osEnv.getPods().values()) { + final String podName = podConfig.getMetadata().getName(); + final PodSpec podSpec = podConfig.getSpec(); + rewriteRestartPolicy(podSpec, podName, environment); + } + } + + private void rewriteRestartPolicy(PodSpec podSpec, String podName, InternalEnvironment env) { + final String restartPolicy = podSpec.getRestartPolicy(); + + if (restartPolicy != null && !DEFAULT_RESTART_POLICY.equalsIgnoreCase(restartPolicy)) { + final String warnMsg = + format( + "Restart policy '%s' for pod '%s' is rewritten with %s", + restartPolicy, podName, DEFAULT_RESTART_POLICY); + env.addWarning(new WarningImpl(101, warnMsg)); + } + podSpec.setRestartPolicy(DEFAULT_RESTART_POLICY); + } +} diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/server/ServersConverter.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/server/ServersConverter.java new file mode 100644 index 0000000000..c6517c6569 --- /dev/null +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/provision/server/ServersConverter.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012-2017 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.workspace.infrastructure.openshift.provision.server; + +import io.fabric8.kubernetes.api.model.Container; +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodSpec; +import java.util.Map; +import javax.inject.Singleton; +import org.eclipse.che.api.core.model.workspace.config.ServerConfig; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.InternalEnvironment; +import org.eclipse.che.api.workspace.server.spi.InternalMachineConfig; +import org.eclipse.che.workspace.infrastructure.openshift.ServerExposer; +import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment; +import org.eclipse.che.workspace.infrastructure.openshift.provision.ConfigurationProvisioner; + +/** + * Converts {@link ServerConfig} to OpenShift related objects to add a server into OpenShift + * runtime. + * + *

    Adds OpenShift objects by calling {@link ServerExposer#expose(Map)} on each machine with + * servers. + * + * @author Alexander Garagatyi + */ +@Singleton +public class ServersConverter implements ConfigurationProvisioner { + + @Override + public void provision( + InternalEnvironment environment, OpenShiftEnvironment osEnv, RuntimeIdentity identity) + throws InfrastructureException { + + for (Pod podConfig : osEnv.getPods().values()) { + final String podName = podConfig.getMetadata().getName(); + final PodSpec podSpec = podConfig.getSpec(); + for (Container containerConfig : podSpec.getContainers()) { + String machineName = podName + '/' + containerConfig.getName(); + InternalMachineConfig machineConfig = environment.getMachines().get(machineName); + if (machineConfig != null && !machineConfig.getServers().isEmpty()) { + ServerExposer serverExposer = new ServerExposer(machineName, containerConfig, osEnv); + serverExposer.expose(machineConfig.getServers()); + } + } + } + } +} diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructureProvisionerTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructureProvisionerTest.java index ce25520ac9..3bef232faa 100644 --- a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructureProvisionerTest.java +++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfrastructureProvisionerTest.java @@ -17,8 +17,12 @@ import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.workspace.server.spi.InternalEnvironment; import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment; import org.eclipse.che.workspace.infrastructure.openshift.provision.UniqueNamesProvisioner; +import org.eclipse.che.workspace.infrastructure.openshift.provision.env.EnvVarsConverter; import org.eclipse.che.workspace.infrastructure.openshift.provision.installer.InstallerConfigProvisioner; +import org.eclipse.che.workspace.infrastructure.openshift.provision.labels.PodNameLabelProvisioner; +import org.eclipse.che.workspace.infrastructure.openshift.provision.restartpolicy.RestartPolicyRewriter; import org.eclipse.che.workspace.infrastructure.openshift.provision.route.TlsRouteProvisioner; +import org.eclipse.che.workspace.infrastructure.openshift.provision.server.ServersConverter; import org.eclipse.che.workspace.infrastructure.openshift.provision.volume.PersistentVolumeClaimProvisioner; import org.mockito.InOrder; import org.mockito.Mock; @@ -42,6 +46,10 @@ public class OpenShiftInfrastructureProvisionerTest { @Mock private OpenShiftEnvironment osEnv; @Mock private RuntimeIdentity runtimeIdentity; @Mock private TlsRouteProvisioner tlsRouteProvisioner; + @Mock private EnvVarsConverter envVarsProvisioner; + @Mock private ServersConverter serversProvisioner; + @Mock private RestartPolicyRewriter restartPolicyRewriter; + @Mock private PodNameLabelProvisioner labelsProvisioner; private OpenShiftInfrastructureProvisioner osInfraProvisioner; @@ -51,9 +59,24 @@ public class OpenShiftInfrastructureProvisionerTest { public void setUp() { osInfraProvisioner = new OpenShiftInfrastructureProvisioner( - installerProvisioner, pvcProvisioner, uniqueNamesProvisioner, tlsRouteProvisioner); + installerProvisioner, + pvcProvisioner, + uniqueNamesProvisioner, + tlsRouteProvisioner, + serversProvisioner, + envVarsProvisioner, + restartPolicyRewriter, + labelsProvisioner); provisionOrder = - inOrder(installerProvisioner, pvcProvisioner, uniqueNamesProvisioner, tlsRouteProvisioner); + inOrder( + installerProvisioner, + pvcProvisioner, + uniqueNamesProvisioner, + tlsRouteProvisioner, + serversProvisioner, + envVarsProvisioner, + restartPolicyRewriter, + labelsProvisioner); } @Test @@ -63,6 +86,18 @@ public class OpenShiftInfrastructureProvisionerTest { provisionOrder .verify(installerProvisioner) .provision(eq(environment), eq(osEnv), eq(runtimeIdentity)); + provisionOrder + .verify(serversProvisioner) + .provision(eq(environment), eq(osEnv), eq(runtimeIdentity)); + provisionOrder + .verify(envVarsProvisioner) + .provision(eq(environment), eq(osEnv), eq(runtimeIdentity)); + provisionOrder + .verify(labelsProvisioner) + .provision(eq(environment), eq(osEnv), eq(runtimeIdentity)); + provisionOrder + .verify(restartPolicyRewriter) + .provision(eq(environment), eq(osEnv), eq(runtimeIdentity)); provisionOrder .verify(pvcProvisioner) .provision(eq(environment), eq(osEnv), eq(runtimeIdentity)); diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentParserTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentParserTest.java index a0a6ac7558..e58fab9089 100644 --- a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentParserTest.java +++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentParserTest.java @@ -10,10 +10,8 @@ */ package org.eclipse.che.workspace.infrastructure.openshift.environment; -import static java.lang.String.format; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; -import static org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironmentParser.DEFAULT_RESTART_POLICY; import static org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironmentParser.PVC_IGNORED_WARNING_CODE; import static org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironmentParser.PVC_IGNORED_WARNING_MESSAGE; import static org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironmentParser.ROUTES_IGNORED_WARNING_MESSAGE; @@ -26,17 +24,10 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; -import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.DoneableKubernetesList; import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.KubernetesList; -import io.fabric8.kubernetes.api.model.ObjectMeta; -import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; -import io.fabric8.kubernetes.api.model.Pod; -import io.fabric8.kubernetes.api.model.PodBuilder; -import io.fabric8.kubernetes.api.model.PodSpec; -import io.fabric8.kubernetes.api.model.PodSpecBuilder; import io.fabric8.kubernetes.client.dsl.KubernetesListMixedOperation; import io.fabric8.kubernetes.client.dsl.RecreateFromServerGettable; import io.fabric8.openshift.api.model.Route; @@ -64,8 +55,6 @@ import org.testng.annotations.Test; public class OpenShiftEnvironmentParserTest { private static final String YAML_RECIPE = "application/x-yaml"; - private static final String TEST_POD_NAME = "app"; - private static final String ALWAYS_RESTART_POLICY = "Always"; private OpenShiftEnvironmentParser osEnvironmentParser; @@ -95,23 +84,6 @@ public class OpenShiftEnvironmentParserTest { when(internalRecipe.getContent()).thenReturn("recipe content"); } - @Test - public void rewritesRestartPolicyWhenItsDifferentWithDefaultOne() throws Exception { - final List pods = singletonList(newPod(TEST_POD_NAME, ALWAYS_RESTART_POLICY)); - when(validatedObjects.getItems()).thenReturn(pods); - - final OpenShiftEnvironment parsed = osEnvironmentParser.parse(internalEnvironment); - - assertEquals( - parsed.getPods().get(TEST_POD_NAME).getSpec().getRestartPolicy(), DEFAULT_RESTART_POLICY); - verifyWarnings( - new WarningImpl( - 101, - format( - "Restart policy '%s' for pod '%s' is rewritten with %s", - ALWAYS_RESTART_POLICY, TEST_POD_NAME, DEFAULT_RESTART_POLICY))); - } - @Test public void ignoreRoutesWhenRecipeContainsThem() throws Exception { final List objects = asList(new Route(), new Route()); @@ -152,11 +124,4 @@ public class OpenShiftEnvironmentParserTest { verify(internalEnvironment, atLeastOnce()).addWarning(warningCaptor.capture()); return warningCaptor.getAllValues(); } - - private static Pod newPod(String podName, String restartPolicy, Container... containers) { - final ObjectMeta podMetadata = new ObjectMetaBuilder().withName(podName).build(); - final PodSpec podSpec = - new PodSpecBuilder().withRestartPolicy(restartPolicy).withContainers(containers).build(); - return new PodBuilder().withMetadata(podMetadata).withSpec(podSpec).build(); - } } diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/installer/InstallerConfigProvisionerTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/installer/InstallerConfigProvisionerTest.java index b25cb1e3ac..43aa1aea4f 100644 --- a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/installer/InstallerConfigProvisionerTest.java +++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/installer/InstallerConfigProvisionerTest.java @@ -11,6 +11,7 @@ package org.eclipse.che.workspace.infrastructure.openshift.provision.installer; import static java.lang.String.format; +import static java.util.Collections.singletonMap; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; @@ -18,21 +19,10 @@ import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; import com.google.common.collect.ImmutableMap; -import io.fabric8.kubernetes.api.model.Container; -import io.fabric8.kubernetes.api.model.EnvVar; -import io.fabric8.kubernetes.api.model.ObjectMeta; -import io.fabric8.kubernetes.api.model.Pod; -import io.fabric8.kubernetes.api.model.PodSpec; -import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.Optional; import org.eclipse.che.api.core.model.workspace.config.ServerConfig; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; -import org.eclipse.che.api.installer.server.model.impl.InstallerImpl; -import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl; import org.eclipse.che.api.workspace.server.spi.InternalEnvironment; import org.eclipse.che.api.workspace.server.spi.InternalMachineConfig; import org.eclipse.che.api.workspace.server.token.MachineTokenProvider; @@ -49,6 +39,7 @@ import org.testng.annotations.Test; * * @author Anton Korneta * @author Sergii Leshchenko + * @author Alexander Garagatyi */ @Listeners(MockitoTestNGListener.class) public class InstallerConfigProvisionerTest { @@ -57,6 +48,7 @@ public class InstallerConfigProvisionerTest { @Mock private MachineTokenProvider machineTokenProvider; @Mock private RuntimeIdentity runtimeIdentity; + @Mock protected OpenShiftEnvironment osEnvironment; private InstallerConfigProvisioner installerConfigProvisioner; @@ -68,68 +60,16 @@ public class InstallerConfigProvisionerTest { when(runtimeIdentity.getWorkspaceId()).thenReturn(WORKSPACE_ID); } - @Test - public void provisionWithEnvsFromInstallersAttributes() throws Exception { - // given - final Pod pod = new PodBuilder().setName("test").setContainers("machine").build(); - OpenShiftEnvironment osEnvironment = - OpenShiftEnvironment.builder() - .setPods(ImmutableMap.of(pod.getMetadata().getName(), pod)) - .build(); - - final Map machines = - ImmutableMap.of( - "test/machine", - new MachineConfigBuilder() - .setInstallers( - new InstallerImpl() - .withProperties(ImmutableMap.of("environment", "INSTALLER1=localhost")), - new InstallerImpl() - .withProperties(ImmutableMap.of("environment", "INSTALLER2=agent"))) - .setServer(Constants.SERVER_WS_AGENT_HTTP_REFERENCE, new ServerConfigImpl()) - .build()); - - InternalEnvironment environment = createEnvironment(machines); - - // when - installerConfigProvisioner.provision(environment, osEnvironment, runtimeIdentity); - - // then - Container container = pod.getSpec().getContainers().get(0); - List envs = container.getEnv(); - verifyContainsEnv(envs, "INSTALLER1", "localhost"); - verifyContainsEnv(envs, "INSTALLER2", "agent"); - } - @Test public void provisionWithAgentsRequiredEnvs() throws Exception { // given when(machineTokenProvider.getToken(WORKSPACE_ID)).thenReturn("superToken"); - final Pod podWithAgent = new PodBuilder().setName("pod1").setContainers("wsagent").build(); - - final Pod pod = new PodBuilder().setName("pod2").setContainers("machine").build(); - - OpenShiftEnvironment osEnvironment = - OpenShiftEnvironment.builder() - .setPods( - ImmutableMap.of( - podWithAgent.getMetadata().getName(), - podWithAgent, - pod.getMetadata().getName(), - pod)) - .build(); - + InternalMachineConfig machine1 = + createMachine(new HashMap<>(singletonMap("env1", "val1")), true); + InternalMachineConfig machine2 = createMachine(new HashMap<>(), false); final Map machines = - ImmutableMap.of( - "pod1/wsagent", - new MachineConfigBuilder() - .setServer(Constants.SERVER_WS_AGENT_HTTP_REFERENCE, new ServerConfigImpl()) - .build(), - "pod2/machine", - new MachineConfigBuilder() - .setServer(Constants.SERVER_TERMINAL_REFERENCE, new ServerConfigImpl()) - .build()); + ImmutableMap.of("pod1/wsagent", machine1, "pod2/machine", machine2); InternalEnvironment environment = createEnvironment(machines); @@ -137,17 +77,27 @@ public class InstallerConfigProvisionerTest { installerConfigProvisioner.provision(environment, osEnvironment, runtimeIdentity); // then - Container container = podWithAgent.getSpec().getContainers().get(0); - List envs = container.getEnv(); - verifyContainsEnv(envs, "CHE_API", CHE_SERVER_ENDPOINT); - verifyContainsEnv(envs, "USER_TOKEN", "superToken"); - verifyContainsEnv(envs, "CHE_WORKSPACE_ID", WORKSPACE_ID); + Map env = machine1.getEnv(); + verifyContainsEnv(env, "CHE_API", CHE_SERVER_ENDPOINT); + verifyContainsEnv(env, "USER_TOKEN", "superToken"); + verifyContainsEnv(env, "CHE_WORKSPACE_ID", WORKSPACE_ID); - Container container2 = pod.getSpec().getContainers().get(0); - List envs2 = container2.getEnv(); - verifyContainsEnv(envs2, "CHE_API", CHE_SERVER_ENDPOINT); - verifyContainsEnv(envs, "USER_TOKEN", "superToken"); - verifyDoesNotContainEnv(envs2, "CHE_WORKSPACE_ID"); + env = machine2.getEnv(); + verifyContainsEnv(env, "CHE_API", CHE_SERVER_ENDPOINT); + verifyContainsEnv(env, "USER_TOKEN", "superToken"); + assertFalse( + env.containsKey("CHE_WORKSPACE_ID"), "Environment variable '%s' found CHE_WORKSPACE_ID"); + } + + private InternalMachineConfig createMachine(Map env, boolean isDev) { + InternalMachineConfig machineConfig = mock(InternalMachineConfig.class); + when(machineConfig.getEnv()).thenReturn(env); + if (isDev) { + when(machineConfig.getServers()) + .thenReturn( + singletonMap(Constants.SERVER_WS_AGENT_HTTP_REFERENCE, mock(ServerConfig.class))); + } + return machineConfig; } private InternalEnvironment createEnvironment(Map machines) { @@ -156,18 +106,10 @@ public class InstallerConfigProvisionerTest { return environment; } - private void verifyDoesNotContainEnv(List envs, String name) { - Optional env = envs.stream().filter(e -> e.getName().equals(name)).findAny(); + private void verifyContainsEnv(Map env, String name, String expectedValue) { + assertTrue(env.containsKey(name), format("Expected environment variable '%s' not found", name)); - assertFalse(env.isPresent(), format("Environment variable '%s' found", name)); - } - - private void verifyContainsEnv(List envs, String name, String expectedValue) { - Optional env = envs.stream().filter(e -> e.getName().equals(name)).findAny(); - - assertTrue(env.isPresent(), format("Expected environment variable '%s' not found", name)); - - String actualValue = env.get().getValue(); + String actualValue = env.get(name); assertEquals( actualValue, expectedValue, @@ -175,66 +117,4 @@ public class InstallerConfigProvisionerTest { "Environment variable '%s' expected with " + "value '%s' but found with '%s'", name, expectedValue, actualValue)); } - - private static class MachineConfigBuilder { - - private List installers = new ArrayList<>(); - private Map servers = new HashMap<>(); - - MachineConfigBuilder setInstallers(InstallerImpl... installers) { - this.installers = Arrays.asList(installers); - return this; - } - - MachineConfigBuilder setServer(String name, ServerConfig server) { - this.servers.put(name, server); - return this; - } - - InternalMachineConfig build() { - final InternalMachineConfig machineConfig = mock(InternalMachineConfig.class); - when(machineConfig.getInstallers()).thenReturn(installers); - when(machineConfig.getServers()).thenReturn(servers); - return machineConfig; - } - } - - private static class PodBuilder { - - private String name; - private List containersNames; - - PodBuilder setName(String name) { - this.name = name; - return this; - } - - PodBuilder setContainers(String... names) { - this.containersNames = Arrays.asList(names); - return this; - } - - Pod build() { - final Pod pod = mock(Pod.class); - final ObjectMeta podMeta = mock(ObjectMeta.class); - when(pod.getMetadata()).thenReturn(podMeta); - when(podMeta.getName()).thenReturn(name); - - final PodSpec podSpec = mock(PodSpec.class); - when(pod.getSpec()).thenReturn(podSpec); - - final List containers = new ArrayList<>(); - for (String containerName : containersNames) { - final Container container = mock(Container.class); - when(container.getName()).thenReturn(containerName); - when(container.getEnv()).thenReturn(new ArrayList<>()); - - containers.add(container); - } - - when(podSpec.getContainers()).thenReturn(containers); - - return pod; - } - } } diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/restartpolicy/RestartPolicyRewriterTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/restartpolicy/RestartPolicyRewriterTest.java new file mode 100644 index 0000000000..a5bd5e71c1 --- /dev/null +++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/provision/restartpolicy/RestartPolicyRewriterTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2012-2017 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.workspace.infrastructure.openshift.provision.restartpolicy; + +import static java.lang.String.format; +import static java.util.Collections.singletonMap; +import static org.eclipse.che.workspace.infrastructure.openshift.provision.restartpolicy.RestartPolicyRewriter.DEFAULT_RESTART_POLICY; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import io.fabric8.kubernetes.api.model.Container; +import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodBuilder; +import io.fabric8.kubernetes.api.model.PodSpec; +import io.fabric8.kubernetes.api.model.PodSpecBuilder; +import java.util.Iterator; +import java.util.List; +import org.eclipse.che.api.core.model.workspace.Warning; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +import org.eclipse.che.api.workspace.server.model.impl.WarningImpl; +import org.eclipse.che.api.workspace.server.spi.InternalEnvironment; +import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +/** @author Alexander Garagatyi */ +@Listeners(MockitoTestNGListener.class) +public class RestartPolicyRewriterTest { + private static final String TEST_POD_NAME = "app"; + private static final String ALWAYS_RESTART_POLICY = "Always"; + + @Mock private InternalEnvironment environment; + @Mock private OpenShiftEnvironment osEnv; + @Mock private RuntimeIdentity runtimeIdentity; + @InjectMocks private RestartPolicyRewriter restartPolicyRewriter; + + @Captor private ArgumentCaptor warningCaptor; + + @Test + public void rewritesRestartPolicyWhenItsDifferentWithDefaultOne() throws Exception { + when(osEnv.getPods()) + .thenReturn(singletonMap(TEST_POD_NAME, newPod(TEST_POD_NAME, ALWAYS_RESTART_POLICY))); + + restartPolicyRewriter.provision(environment, osEnv, runtimeIdentity); + + assertEquals( + osEnv.getPods().get(TEST_POD_NAME).getSpec().getRestartPolicy(), DEFAULT_RESTART_POLICY); + verifyWarnings( + new WarningImpl( + 101, + format( + "Restart policy '%s' for pod '%s' is rewritten with %s", + ALWAYS_RESTART_POLICY, TEST_POD_NAME, DEFAULT_RESTART_POLICY))); + } + + private static Pod newPod(String podName, String restartPolicy, Container... containers) { + final ObjectMeta podMetadata = new ObjectMetaBuilder().withName(podName).build(); + final PodSpec podSpec = + new PodSpecBuilder().withRestartPolicy(restartPolicy).withContainers(containers).build(); + return new PodBuilder().withMetadata(podMetadata).withSpec(podSpec).build(); + } + + private void verifyWarnings(Warning... expectedWarnings) { + final Iterator actualWarnings = captureWarnings().iterator(); + for (Warning expected : expectedWarnings) { + if (!actualWarnings.hasNext()) { + fail("It is expected to receive environment warning"); + } + final Warning actual = actualWarnings.next(); + assertEquals(actual, expected); + } + if (actualWarnings.hasNext()) { + fail("No more warnings expected"); + } + } + + private List captureWarnings() { + verify(environment, atLeastOnce()).addWarning(warningCaptor.capture()); + return warningCaptor.getAllValues(); + } +} diff --git a/plugins/plugin-urlfactory/pom.xml b/plugins/plugin-urlfactory/pom.xml index e6a6a2b644..159dc7563d 100644 --- a/plugins/plugin-urlfactory/pom.xml +++ b/plugins/plugin-urlfactory/pom.xml @@ -70,6 +70,10 @@ org.eclipse.che.core che-core-api-factory-shared + + org.eclipse.che.core + che-core-api-model + org.eclipse.che.core che-core-api-workspace-shared diff --git a/plugins/plugin-urlfactory/src/test/java/org/eclipse/che/plugin/urlfactory/URLFactoryBuilderTest.java b/plugins/plugin-urlfactory/src/test/java/org/eclipse/che/plugin/urlfactory/URLFactoryBuilderTest.java index f038723c41..366c06f1e5 100644 --- a/plugins/plugin-urlfactory/src/test/java/org/eclipse/che/plugin/urlfactory/URLFactoryBuilderTest.java +++ b/plugins/plugin-urlfactory/src/test/java/org/eclipse/che/plugin/urlfactory/URLFactoryBuilderTest.java @@ -13,6 +13,7 @@ package org.eclipse.che.plugin.urlfactory; import static java.lang.Boolean.FALSE; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; +import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE; import static org.eclipse.che.dto.server.DtoFactory.newDto; import static org.eclipse.che.plugin.urlfactory.URLFactoryBuilder.DEFAULT_DOCKER_IMAGE; import static org.eclipse.che.plugin.urlfactory.URLFactoryBuilder.MACHINE_NAME; @@ -64,7 +65,7 @@ public class URLFactoryBuilderTest { MachineConfigDto machine = newDto(MachineConfigDto.class) .withInstallers(singletonList("org.eclipse.che.ws-agent")) - .withAttributes(singletonMap("memoryLimitBytes", MEMORY_LIMIT_BYTES)); + .withAttributes(singletonMap(MEMORY_LIMIT_ATTRIBUTE, MEMORY_LIMIT_BYTES)); // setup environment EnvironmentDto environmentDto = @@ -101,7 +102,7 @@ public class URLFactoryBuilderTest { MachineConfigDto machine = newDto(MachineConfigDto.class) .withInstallers(singletonList("org.eclipse.che.ws-agent")) - .withAttributes(singletonMap("memoryLimitBytes", MEMORY_LIMIT_BYTES)); + .withAttributes(singletonMap(MEMORY_LIMIT_ATTRIBUTE, MEMORY_LIMIT_BYTES)); // setup environment EnvironmentDto environmentDto = @@ -137,7 +138,7 @@ public class URLFactoryBuilderTest { MachineConfigDto machine = newDto(MachineConfigDto.class) .withInstallers(singletonList("org.eclipse.che.ws-agent")) - .withAttributes(singletonMap("memoryLimitBytes", MEMORY_LIMIT_BYTES)); + .withAttributes(singletonMap(MEMORY_LIMIT_ATTRIBUTE, MEMORY_LIMIT_BYTES)); // setup environment EnvironmentDto environmentDto = diff --git a/selenium/che-selenium-core/src/main/java/org/eclipse/che/selenium/core/client/TestWorkspaceServiceClient.java b/selenium/che-selenium-core/src/main/java/org/eclipse/che/selenium/core/client/TestWorkspaceServiceClient.java index 86018f500e..3cfe7ec30c 100644 --- a/selenium/che-selenium-core/src/main/java/org/eclipse/che/selenium/core/client/TestWorkspaceServiceClient.java +++ b/selenium/che-selenium-core/src/main/java/org/eclipse/che/selenium/core/client/TestWorkspaceServiceClient.java @@ -14,6 +14,7 @@ import static java.lang.String.format; import static java.lang.String.valueOf; import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.RUNNING; import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.STOPPED; +import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE; import static org.eclipse.che.api.workspace.server.WsAgentMachineFinderUtil.containsWsAgentServer; import com.google.inject.Inject; @@ -188,7 +189,7 @@ public class TestWorkspaceServiceClient { .forEach( m -> m.getAttributes() - .put("memoryLimitBytes", Long.toString(convertToByte(memory, memoryUnit)))); + .put(MEMORY_LIMIT_ATTRIBUTE, Long.toString(convertToByte(memory, memoryUnit)))); workspace.getEnvironments().remove("replaced_name"); workspace.getEnvironments().put(workspaceName, environment); workspace.setName(workspaceName); diff --git a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/builder/FactoryBuilderTest.java b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/builder/FactoryBuilderTest.java index fe14321182..a1ca562d67 100644 --- a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/builder/FactoryBuilderTest.java +++ b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/builder/FactoryBuilderTest.java @@ -14,6 +14,7 @@ import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; import static java.util.Objects.requireNonNull; +import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE; import static org.eclipse.che.dto.server.DtoFactory.newDto; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -191,7 +192,7 @@ public class FactoryBuilderTest { newDto(MachineConfigDto.class) .withInstallers(singletonList("org.eclipse.che.ws-agent")) .withAttributes( - singletonMap("memoryLimitBytes", "" + 512L * 1024L * 1024L)))); + singletonMap(MEMORY_LIMIT_ATTRIBUTE, "" + 512L * 1024L * 1024L)))); WorkspaceConfigDto workspaceConfig = dto.createDto(WorkspaceConfigDto.class) diff --git a/wsmaster/che-core-api-installer-shared/src/main/java/org/eclipse/che/api/installer/shared/model/Installer.java b/wsmaster/che-core-api-installer-shared/src/main/java/org/eclipse/che/api/installer/shared/model/Installer.java index 30cc53122c..bfedd4a709 100644 --- a/wsmaster/che-core-api-installer-shared/src/main/java/org/eclipse/che/api/installer/shared/model/Installer.java +++ b/wsmaster/che-core-api-installer-shared/src/main/java/org/eclipse/che/api/installer/shared/model/Installer.java @@ -18,9 +18,18 @@ import org.eclipse.che.api.core.model.workspace.config.ServerConfig; * An entity that might additionally injected into machine and brings functionality. * * @author Anatoliy Bazko + * @author Alexander Garagatyi */ public interface Installer { + /** + * Name of a property from {@link #getProperties()} that can contain environment variables that + * should be injected into machine. + * + *

    Example: { "environment" : "envVar1=value1,envVar2=value2" } + */ + String ENVIRONMENT_PROPERTY = "environment"; + /** Returns the id of the installer. */ String getId(); 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 05b5293352..75dc850a47 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 @@ -12,8 +12,10 @@ package org.eclipse.che.api.workspace.server; 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 java.util.Map; +import java.util.Map.Entry; import java.util.regex.Pattern; import javax.inject.Inject; import javax.inject.Singleton; @@ -24,6 +26,7 @@ import org.eclipse.che.api.core.model.workspace.Workspace; import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; import org.eclipse.che.api.core.model.workspace.config.Command; 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.workspace.server.spi.InfrastructureException; @@ -83,7 +86,11 @@ public class WorkspaceValidator { checkNotNull(recipe, "Environment recipe must not be null"); checkNotNull(recipe.getType(), "Environment recipe type must not be null"); - // TODO: spi: deal with exceptions + for (Entry machineEntry : + environment.getMachines().entrySet()) { + validateMachine(machineEntry.getKey(), machineEntry.getValue()); + } + try { runtimes.validate(environment); } catch (InfrastructureException e) { @@ -127,6 +134,20 @@ public class WorkspaceValidator { } } + private void validateMachine(String name, MachineConfig machine) throws ValidationException { + String memoryAttribute = machine.getAttributes().get(MEMORY_LIMIT_ATTRIBUTE); + if (memoryAttribute != null) { + try { + Long.parseLong(memoryAttribute); + } catch (NumberFormatException e) { + throw new ValidationException( + format( + "Value '%s' of attribute '%s' in machine '%s' is illegal", + memoryAttribute, MEMORY_LIMIT_ATTRIBUTE, name)); + } + } + } + /** * Checks that object reference is not null, throws {@link ValidationException} in the case of * null {@code object} with given {@code message}. diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/adapter/WorkspaceConfigJsonAdapter.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/adapter/WorkspaceConfigJsonAdapter.java index 47ad8ef6f3..89113ead33 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/adapter/WorkspaceConfigJsonAdapter.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/adapter/WorkspaceConfigJsonAdapter.java @@ -12,6 +12,7 @@ package org.eclipse.che.api.workspace.server.adapter; import static com.google.common.primitives.Ints.tryParse; import static java.lang.String.format; +import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -174,7 +175,7 @@ public class WorkspaceConfigJsonAdapter { envName)); } final JsonObject attributes = new JsonObject(); - attributes.addProperty("memoryLimitBytes", Long.toString(1024L * 1024L * ram)); + attributes.addProperty(MEMORY_LIMIT_ATTRIBUTE, Long.toString(1024L * 1024L * ram)); newMachine.add("attributes", attributes); } } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/InternalMachineConfig.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/InternalMachineConfig.java index 1f82cf978b..a188b8b656 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/InternalMachineConfig.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/InternalMachineConfig.java @@ -10,6 +10,7 @@ */ package org.eclipse.che.api.workspace.server.spi; +import static com.google.common.base.Strings.isNullOrEmpty; import static java.lang.String.format; import java.util.ArrayList; @@ -88,21 +89,43 @@ public class InternalMachineConfig { try { List sortedInstallers = installerRegistry.getOrderedInstallers(installersKeys); for (Installer installer : sortedInstallers) { - this.installers.add(new InstallerImpl(installer)); - for (Map.Entry serverEntry : - installer.getServers().entrySet()) { - if (servers.putIfAbsent(serverEntry.getKey(), serverEntry.getValue()) != null - && servers.get(serverEntry.getKey()).equals(serverEntry.getValue())) { - throw new InfrastructureException( - format( - "Installer '%s' contains server '%s' conflicting with machine configuration", - installer.getId(), serverEntry.getKey())); - } - } + applyInstaller(installer); } } catch (InstallerException e) { - // TODO installers has circular dependency or missing, what should we throw in that case? throw new InfrastructureException(e.getLocalizedMessage(), e); } } + + private void applyInstaller(Installer installer) throws InfrastructureException { + this.installers.add(new InstallerImpl(installer)); + for (Map.Entry serverEntry : + installer.getServers().entrySet()) { + if (servers.putIfAbsent(serverEntry.getKey(), serverEntry.getValue()) != null + && !servers.get(serverEntry.getKey()).equals(serverEntry.getValue())) { + throw new InfrastructureException( + format( + "Installer '%s' contains server '%s' conflicting with machine configuration", + installer.getId(), serverEntry.getKey())); + } + } + addEnvVars(installer); + } + + private void addEnvVars(Installer installer) { + String environment = installer.getProperties().get(Installer.ENVIRONMENT_PROPERTY); + if (isNullOrEmpty(environment)) { + return; + } + + for (String env : environment.split(",")) { + String[] items = env.split("="); + if (items.length != 2) { + // TODO add warning + // LOG.warn(format("Illegal environment variable '%s' format", env)); + continue; + } + + this.env.put(items[0], items[1]); + } + } } diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceConfigJsonAdapterTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceConfigJsonAdapterTest.java index b4d704d569..c637c0c05e 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceConfigJsonAdapterTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceConfigJsonAdapterTest.java @@ -10,6 +10,7 @@ */ package org.eclipse.che.api.workspace.server; +import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; @@ -85,8 +86,8 @@ public class WorkspaceConfigJsonAdapterTest { assertTrue( devMachineObj.get("attributes").isJsonObject(), "dev machine attributes is json object"); final JsonObject attributes = devMachineObj.getAsJsonObject("attributes"); - assertTrue(attributes.has("memoryLimitBytes"), "has memory limit"); - assertEquals(attributes.get("memoryLimitBytes").getAsString(), "2147483648"); + assertTrue(attributes.has(MEMORY_LIMIT_ATTRIBUTE), "has memory limit"); + assertEquals(attributes.get(MEMORY_LIMIT_ATTRIBUTE).getAsString(), "2147483648"); // check environment recipe assertTrue(environmentObj.has("recipe"), "environment contains recipe"); diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java index 61676878e4..020ed87570 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java @@ -18,6 +18,7 @@ import static java.util.Collections.singletonMap; import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.RUNNING; import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.STARTING; import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.STOPPED; +import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE; import static org.eclipse.che.api.workspace.server.WorkspaceManager.UPDATED_ATTRIBUTE_NAME; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyObject; @@ -557,7 +558,7 @@ public class WorkspaceManagerTest { singletonList("org.eclipse.che.ws-agent"), null, singletonMap("CHE_ENV", "value"), - singletonMap("memoryLimitBytes", "10000")); + singletonMap(MEMORY_LIMIT_ATTRIBUTE, "10000")); EnvironmentImpl environment = new EnvironmentImpl( new RecipeImpl("type", "contentType", "content", null), diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java index 09d8234bc4..e3ba9f0393 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java @@ -19,6 +19,7 @@ import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; import static java.util.stream.Collectors.toList; import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.STARTING; +import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE; import static org.eclipse.che.dto.server.DtoFactory.newDto; import static org.everrest.assured.JettyHttpServer.ADMIN_USER_NAME; import static org.everrest.assured.JettyHttpServer.ADMIN_USER_PASSWORD; @@ -917,7 +918,7 @@ public class WorkspaceServiceTest { singletonList("org.eclipse.che.ws-agent"), null, singletonMap("CHE_ENV", "value"), - singletonMap("memoryLimitBytes", "10000")); + singletonMap(MEMORY_LIMIT_ATTRIBUTE, "10000")); return DtoConverter.asDto( new EnvironmentImpl( 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 9de356e897..d2c44b29a9 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 @@ -12,6 +12,7 @@ package org.eclipse.che.api.workspace.server; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; +import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE; import static org.eclipse.che.dto.server.DtoFactory.newDto; import com.google.common.collect.ImmutableMap; @@ -20,6 +21,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.che.api.core.ValidationException; +import org.eclipse.che.api.core.model.workspace.config.MachineConfig; import org.eclipse.che.api.workspace.shared.dto.CommandDto; import org.eclipse.che.api.workspace.shared.dto.EnvironmentDto; import org.eclipse.che.api.workspace.shared.dto.MachineConfigDto; @@ -184,6 +186,27 @@ public class WorkspaceValidatorTest { wsValidator.validateConfig(config); } + @Test( + expectedExceptions = ValidationException.class, + expectedExceptionsMessageRegExp = + "Value '.*' of attribute '" + MEMORY_LIMIT_ATTRIBUTE + "' in machine '.*' is illegal", + dataProvider = "illegalMemoryAttributeValueProvider" + ) + public void shouldFailValidationIfMemoryMachineAttributeHasIllegalValue(String attributeValue) + throws Exception { + final WorkspaceConfigDto config = createConfig(); + EnvironmentDto env = config.getEnvironments().values().iterator().next(); + MachineConfigDto machine = env.getMachines().values().iterator().next(); + machine.getAttributes().put(MachineConfig.MEMORY_LIMIT_ATTRIBUTE, attributeValue); + + wsValidator.validateConfig(config); + } + + @DataProvider(name = "illegalMemoryAttributeValueProvider") + public static Object[][] illegalMemoryAttributeValueProvider() { + return new Object[][] {{"text"}, {""}, {"123MB"}, {"123GB"}, {"123KB"}}; + } + @Test( expectedExceptions = ValidationException.class, expectedExceptionsMessageRegExp = "Workspace ws-name contains command with null or empty name" @@ -221,17 +244,17 @@ public class WorkspaceValidatorTest { final WorkspaceConfigDto workspaceConfigDto = newDto(WorkspaceConfigDto.class).withName("ws-name").withDefaultEnv("dev-env"); - MachineConfigDto extendedMachine = + MachineConfigDto machineConfig = newDto(MachineConfigDto.class) .withInstallers(singletonList("org.eclipse.che.ws-agent")) .withServers( singletonMap( "ref1", newDto(ServerConfigDto.class).withPort("8080/tcp").withProtocol("https"))) - .withAttributes(singletonMap("memoryLimitBytes", "1000000")); + .withAttributes(new HashMap<>(singletonMap(MEMORY_LIMIT_ATTRIBUTE, "1000000"))); EnvironmentDto env = newDto(EnvironmentDto.class) - .withMachines(singletonMap("devmachine1", extendedMachine)) + .withMachines(singletonMap("devmachine1", machineConfig)) .withRecipe( newDto(RecipeDto.class) .withType("type") diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/stack/StackLoaderTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/stack/StackLoaderTest.java index 7b1ee30497..aa8647aa05 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/stack/StackLoaderTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/stack/StackLoaderTest.java @@ -11,6 +11,7 @@ package org.eclipse.che.api.workspace.server.stack; import static java.util.Collections.singletonMap; +import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE; import static org.eclipse.che.dto.server.DtoFactory.newDto; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; @@ -194,7 +195,7 @@ public class StackLoaderTest { newDto(MachineConfigDto.class) .withInstallers(Arrays.asList("agent1", "agent2")) .withServers(servers) - .withAttributes(singletonMap("memoryLimitBytes", "" + 512L * 1024L * 1024L))); + .withAttributes(singletonMap(MEMORY_LIMIT_ATTRIBUTE, "" + 512L * 1024L * 1024L))); EnvironmentDto environmentDto = newDto(EnvironmentDto.class).withRecipe(environmentRecipe).withMachines(machines);