diff --git a/assembly/assembly-main/src/assembly/bin/che.sh b/assembly/assembly-main/src/assembly/bin/che.sh index 4749a66904..773aabc158 100644 --- a/assembly/assembly-main/src/assembly/bin/che.sh +++ b/assembly/assembly-main/src/assembly/bin/che.sh @@ -433,6 +433,8 @@ get_docker_ready () { rm -rf ${CHE_HOME}/lib-copy/* mkdir -p ${CHE_HOME}/lib-copy cp -rf ${CHE_HOME}/lib/* ${CHE_HOME}/lib-copy + + export JAVA_OPTS="${JAVA_OPTS} -Dche.docker.che_host_network=bridge" fi } diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/codenvy/che.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/codenvy/che.properties index ff6961e16c..46d5a24e18 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/codenvy/che.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/codenvy/che.properties @@ -133,6 +133,11 @@ machine.docker.snapshot_use_registry=false # configured with size that equal to half of current machine memory, to disable swap set it to 0. machine.docker.memory_swap_multiplier=-1 +# Provides docker network where Che server is running. +# This allows to configure communication between Che server and Che workspaces. +# All workspace containers in Che will be added to this network to be able to connect to Che server. +docker.che_host_network=NULL + # URL path to api service. # Browser clients use this to initiate REST communications with workspace master api.endpoint=http://localhost:${SERVER_PORT}/wsmaster/api diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/compose/ComposeService.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/compose/ComposeService.java index 808de91fb9..546cb6d808 100644 --- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/compose/ComposeService.java +++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/compose/ComposeService.java @@ -131,4 +131,9 @@ public interface ComposeService { * Memory limit for the container of service, specified in bytes. */ Long getMemLimit(); + + /** + * List of networks that should be connected to service. + */ + List getNetworks(); } diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/CheInContainerNetworkProvider.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/CheInContainerNetworkProvider.java new file mode 100644 index 0000000000..5980f2a907 --- /dev/null +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/CheInContainerNetworkProvider.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * 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: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.plugin.docker.machine; + +import org.eclipse.che.commons.annotation.Nullable; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; +import java.util.Collections; +import java.util.Set; + +/** + * Provides network that all containers of workspaces in Che should join to properly communicate with Che server. + * + * @author Alexander Garagatyi + */ +@Singleton +public class CheInContainerNetworkProvider implements Provider> { + + private Set networks; + + @Inject + public CheInContainerNetworkProvider(@Nullable @Named("docker.che_host_network") String cheMasterNetwork) { + if (cheMasterNetwork == null) { + networks = Collections.emptySet(); + } else { + networks = Collections.singleton(cheMasterNetwork); + } + } + + @Override + public Set get() { + return networks; + } +} diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/ComposeMachineProviderImpl.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/ComposeMachineProviderImpl.java index 9b87198eab..5a7f99d669 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/ComposeMachineProviderImpl.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/ComposeMachineProviderImpl.java @@ -47,6 +47,7 @@ import org.eclipse.che.plugin.docker.client.json.ContainerConfig; import org.eclipse.che.plugin.docker.client.json.HostConfig; import org.eclipse.che.plugin.docker.client.json.PortBinding; import org.eclipse.che.plugin.docker.client.json.container.NetworkingConfig; +import org.eclipse.che.plugin.docker.client.json.network.ConnectContainer; import org.eclipse.che.plugin.docker.client.json.network.EndpointConfig; import org.eclipse.che.plugin.docker.client.json.network.NewNetwork; import org.eclipse.che.plugin.docker.client.params.BuildImageParams; @@ -58,6 +59,7 @@ import org.eclipse.che.plugin.docker.client.params.RemoveImageParams; import org.eclipse.che.plugin.docker.client.params.RemoveNetworkParams; import org.eclipse.che.plugin.docker.client.params.StartContainerParams; import org.eclipse.che.plugin.docker.client.params.TagParams; +import org.eclipse.che.plugin.docker.client.params.network.ConnectContainerToNetworkParams; import org.eclipse.che.plugin.docker.client.params.network.CreateNetworkParams; import org.eclipse.che.plugin.docker.machine.node.DockerNode; import org.eclipse.che.plugin.docker.machine.node.WorkspaceFolderPathProvider; @@ -123,6 +125,7 @@ public class ComposeMachineProviderImpl implements ComposeMachineInstanceProvide private final String projectFolderPath; private final boolean snapshotUseRegistry; private final double memorySwapMultiplier; + private final Set additionalNetworks; @Inject public ComposeMachineProviderImpl(DockerConnector docker, @@ -143,7 +146,8 @@ public class ComposeMachineProviderImpl implements ComposeMachineInstanceProvide @Named("machine.docker.dev_machine.machine_env") Set devMachineEnvVariables, @Named("machine.docker.machine_env") Set allMachinesEnvVariables, @Named("machine.docker.snapshot_use_registry") boolean snapshotUseRegistry, - @Named("machine.docker.memory_swap_multiplier") double memorySwapMultiplier) + @Named("machine.docker.memory_swap_multiplier") double memorySwapMultiplier, + @Named("machine.docker.networks") Set> additionalNetworks) throws IOException { this.docker = docker; this.dockerCredentials = dockerCredentials; @@ -155,7 +159,7 @@ public class ComposeMachineProviderImpl implements ComposeMachineInstanceProvide this.privilegeMode = privilegeMode; this.projectFolderPath = projectFolderPath; this.snapshotUseRegistry = snapshotUseRegistry; - // usecases: + // use-cases: // -1 enable unlimited swap // 0 disable swap // 0.5 enable swap with size equal to half of current memory size @@ -224,6 +228,10 @@ public class ComposeMachineProviderImpl implements ComposeMachineInstanceProvide this.allMachinesExtraHosts = ObjectArrays.concat(allMachinesExtraHosts.split(","), cheHostAlias); } + this.additionalNetworks = additionalNetworks.stream() + .flatMap(Set::stream) + .collect(Collectors.toSet()); + // TODO single point of failure in case of highly loaded system executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("MachineLogsStreamer-%d") .setDaemon(true) @@ -272,6 +280,9 @@ public class ComposeMachineProviderImpl implements ComposeMachineInstanceProvide networkName, service); + connectContainerToAdditionalNetworks(container, + service); + docker.startContainer(StartContainerParams.create(container)); readContainerLogsInSeparateThread(container, @@ -547,6 +558,16 @@ public class ComposeMachineProviderImpl implements ComposeMachineInstanceProvide composeService.getExpose().addAll(portsToExpose); composeService.getEnvironment().putAll(env); composeService.getVolumes().addAll(volumes); + composeService.getNetworks().addAll(additionalNetworks); + } + + private void connectContainerToAdditionalNetworks(String container, + ComposeServiceImpl service) throws IOException { + + for (String network : service.getNetworks()) { + docker.connectContainerToNetwork( + ConnectContainerToNetworkParams.create(network, new ConnectContainer().withContainer(container))); + } } private void readContainerLogsInSeparateThread(String container, diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerInstanceProvider.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerInstanceProvider.java index 00a7f6144f..d805cf9841 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerInstanceProvider.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerInstanceProvider.java @@ -10,12 +10,6 @@ *******************************************************************************/ package org.eclipse.che.plugin.docker.machine; -import com.google.common.base.MoreObjects; -import com.google.common.base.Strings; -import com.google.common.collect.Maps; -import com.google.common.collect.ObjectArrays; -import com.google.common.collect.Sets; -import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -23,72 +17,27 @@ import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.model.machine.Machine; import org.eclipse.che.api.core.model.machine.MachineConfig; import org.eclipse.che.api.core.model.machine.MachineSource; -import org.eclipse.che.api.core.model.machine.Recipe; -import org.eclipse.che.api.core.model.machine.ServerConf; -import org.eclipse.che.api.core.util.FileCleaner; import org.eclipse.che.api.core.util.LineConsumer; -import org.eclipse.che.api.core.util.SystemInfo; import org.eclipse.che.api.machine.server.exception.InvalidRecipeException; import org.eclipse.che.api.machine.server.exception.MachineException; import org.eclipse.che.api.machine.server.exception.SnapshotException; -import org.eclipse.che.api.machine.server.exception.SourceNotFoundException; import org.eclipse.che.api.machine.server.exception.UnsupportedRecipeException; import org.eclipse.che.api.machine.server.spi.Instance; import org.eclipse.che.api.machine.server.spi.InstanceProvider; -import org.eclipse.che.api.machine.server.util.RecipeRetriever; -import org.eclipse.che.commons.annotation.Nullable; -import org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.commons.lang.IoUtil; import org.eclipse.che.plugin.docker.client.DockerConnector; -import org.eclipse.che.plugin.docker.client.DockerConnectorConfiguration; -import org.eclipse.che.plugin.docker.client.DockerFileException; -import org.eclipse.che.plugin.docker.client.Dockerfile; -import org.eclipse.che.plugin.docker.client.DockerfileParser; -import org.eclipse.che.plugin.docker.client.ProgressLineFormatterImpl; -import org.eclipse.che.plugin.docker.client.ProgressMonitor; -import org.eclipse.che.plugin.docker.client.UserSpecificDockerRegistryCredentialsProvider; -import org.eclipse.che.plugin.docker.client.exception.ContainerNotFoundException; -import org.eclipse.che.plugin.docker.client.exception.ImageNotFoundException; -import org.eclipse.che.plugin.docker.client.json.ContainerConfig; -import org.eclipse.che.plugin.docker.client.json.HostConfig; -import org.eclipse.che.plugin.docker.client.params.BuildImageParams; -import org.eclipse.che.plugin.docker.client.params.CreateContainerParams; -import org.eclipse.che.plugin.docker.client.params.GetContainerLogsParams; -import org.eclipse.che.plugin.docker.client.params.PullParams; -import org.eclipse.che.plugin.docker.client.params.RemoveContainerParams; import org.eclipse.che.plugin.docker.client.params.RemoveImageParams; -import org.eclipse.che.plugin.docker.client.params.StartContainerParams; -import org.eclipse.che.plugin.docker.client.params.TagParams; -import org.eclipse.che.plugin.docker.machine.node.DockerNode; -import org.eclipse.che.plugin.docker.machine.node.WorkspaceFolderPathProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Named; import javax.ws.rs.core.UriBuilder; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; -import java.net.SocketTimeoutException; import java.net.URL; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import static com.google.common.base.Strings.isNullOrEmpty; -import static java.lang.String.format; -import static org.eclipse.che.plugin.docker.machine.DockerInstance.LATEST_TAG; /** * Docker implementation of {@link InstanceProvider} @@ -120,159 +69,14 @@ public class DockerInstanceProvider implements InstanceProvider { */ public static final String MACHINE_SNAPSHOT_PREFIX = "machine_snapshot_"; - public static final Pattern SNAPSHOT_LOCATION_PATTERN = Pattern.compile("(.+/)?" + MACHINE_SNAPSHOT_PREFIX + ".+"); - private final DockerConnector docker; - private final UserSpecificDockerRegistryCredentialsProvider dockerCredentials; - private final ExecutorService executor; - private final DockerInstanceStopDetector dockerInstanceStopDetector; - private final DockerContainerNameGenerator containerNameGenerator; - private final RecipeRetriever recipeRetriever; - private final WorkspaceFolderPathProvider workspaceFolderPathProvider; - private final boolean doForcePullOnBuild; - private final boolean privilegeMode; - private final Set supportedRecipeTypes; - private final DockerMachineFactory dockerMachineFactory; - private final Map> devMachinePortsToExpose; - private final Map> commonMachinePortsToExpose; - private final String[] devMachineSystemVolumes; - private final String[] commonMachineSystemVolumes; - private final Set devMachineEnvVariables; - private final Set commonMachineEnvVariables; - private final String[] allMachinesExtraHosts; - private final String projectFolderPath; private final boolean snapshotUseRegistry; - private final double memorySwapMultiplier; @Inject public DockerInstanceProvider(DockerConnector docker, - DockerConnectorConfiguration dockerConnectorConfiguration, - UserSpecificDockerRegistryCredentialsProvider dockerCredentials, - DockerMachineFactory dockerMachineFactory, - DockerInstanceStopDetector dockerInstanceStopDetector, - DockerContainerNameGenerator containerNameGenerator, - RecipeRetriever recipeRetriever, - @Named("machine.docker.dev_machine.machine_servers") Set devMachineServers, - @Named("machine.docker.machine_servers") Set allMachinesServers, - @Named("machine.docker.dev_machine.machine_volumes") Set devMachineSystemVolumes, - @Named("machine.docker.machine_volumes") Set allMachinesSystemVolumes, - @Nullable @Named("machine.docker.machine_extra_hosts") String allMachinesExtraHosts, - WorkspaceFolderPathProvider workspaceFolderPathProvider, - @Named("che.machine.projects.internal.storage") String projectFolderPath, - @Named("machine.docker.pull_image") boolean doForcePullOnBuild, - @Named("machine.docker.privilege_mode") boolean privilegeMode, - @Named("machine.docker.dev_machine.machine_env") Set devMachineEnvVariables, - @Named("machine.docker.machine_env") Set allMachinesEnvVariables, - @Named("machine.docker.snapshot_use_registry") boolean snapshotUseRegistry, - @Named("machine.docker.memory_swap_multiplier") double memorySwapMultiplier) throws IOException { + @Named("machine.docker.snapshot_use_registry") boolean snapshotUseRegistry) throws IOException { this.docker = docker; - this.dockerCredentials = dockerCredentials; - this.dockerMachineFactory = dockerMachineFactory; - this.dockerInstanceStopDetector = dockerInstanceStopDetector; - this.containerNameGenerator = containerNameGenerator; - this.recipeRetriever = recipeRetriever; - this.workspaceFolderPathProvider = workspaceFolderPathProvider; - this.doForcePullOnBuild = doForcePullOnBuild; - this.privilegeMode = privilegeMode; - this.supportedRecipeTypes = Sets.newHashSet(DOCKER_FILE_TYPE, DOCKER_IMAGE_TYPE); - this.projectFolderPath = projectFolderPath; this.snapshotUseRegistry = snapshotUseRegistry; - // usecases: - // -1 enable unlimited swap - // 0 disable swap - // 0.5 enable swap with size equal to half of current memory size - // 1 enable swap with size equal to current memory size - // - // according to docker docs field memorySwap should be equal to memory+swap - // we calculate this field as memorySwap=memory * (1+ multiplier) so we just add +1 to multiplier - this.memorySwapMultiplier = memorySwapMultiplier == -1 ? -1 : memorySwapMultiplier + 1; - - allMachinesSystemVolumes = removeEmptyAndNullValues(allMachinesSystemVolumes); - devMachineSystemVolumes = removeEmptyAndNullValues(devMachineSystemVolumes); - - Set volumes = new HashSet<>(); - devMachineSystemVolumes.forEach((volume) -> Arrays.asList(volume.split(";")).stream().forEach((entry) -> volumes.add(entry))); - devMachineSystemVolumes = volumes; - - if (SystemInfo.isWindows()) { - allMachinesSystemVolumes = escapePaths(allMachinesSystemVolumes); - devMachineSystemVolumes = escapePaths(devMachineSystemVolumes); - } - this.commonMachineSystemVolumes = allMachinesSystemVolumes.toArray(new String[allMachinesSystemVolumes.size()]); - final Set devMachineVolumes = Sets.newHashSetWithExpectedSize(allMachinesSystemVolumes.size() - + devMachineSystemVolumes.size()); - devMachineVolumes.addAll(allMachinesSystemVolumes); - devMachineVolumes.addAll(devMachineSystemVolumes); - this.devMachineSystemVolumes = devMachineVolumes.toArray(new String[devMachineVolumes.size()]); - - this.devMachinePortsToExpose = Maps.newHashMapWithExpectedSize(allMachinesServers.size() + devMachineServers.size()); - this.commonMachinePortsToExpose = Maps.newHashMapWithExpectedSize(allMachinesServers.size()); - for (ServerConf serverConf : devMachineServers) { - devMachinePortsToExpose.put(serverConf.getPort(), Collections.emptyMap()); - } - for (ServerConf serverConf : allMachinesServers) { - commonMachinePortsToExpose.put(serverConf.getPort(), Collections.emptyMap()); - devMachinePortsToExpose.put(serverConf.getPort(), Collections.emptyMap()); - } - - allMachinesEnvVariables = removeEmptyAndNullValues(allMachinesEnvVariables); - devMachineEnvVariables = removeEmptyAndNullValues(devMachineEnvVariables); - this.commonMachineEnvVariables = allMachinesEnvVariables; - final HashSet envVariablesForDevMachine = Sets.newHashSetWithExpectedSize(allMachinesEnvVariables.size() + - devMachineEnvVariables.size()); - envVariablesForDevMachine.addAll(allMachinesEnvVariables); - envVariablesForDevMachine.addAll(devMachineEnvVariables); - this.devMachineEnvVariables = envVariablesForDevMachine; - - // always add Che server to hosts list - String cheHost = dockerConnectorConfiguration.getDockerHostIp(); - String cheHostAlias = DockerInstanceRuntimeInfo.CHE_HOST.concat(":").concat(cheHost); - if (isNullOrEmpty(allMachinesExtraHosts)) { - this.allMachinesExtraHosts = new String[] {cheHostAlias}; - } else { - this.allMachinesExtraHosts = ObjectArrays.concat(allMachinesExtraHosts.split(","), cheHostAlias); - } - - executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("MachineLogsStreamer-%d") - .setDaemon(true) - .build()); - } - - /** - * Escape paths for Windows system with boot@docker according to rules given here : - * https://github.com/boot2docker/boot2docker/blob/master/README.md#virtualbox-guest-additions - * - * @param paths - * set of paths to escape - * @return set of escaped path - */ - protected Set escapePaths(Set paths) { - return paths.stream().map(this::escapePath).collect(Collectors.toSet()); - } - - /** - * Escape path for Windows system with boot@docker according to rules given here : - * https://github.com/boot2docker/boot2docker/blob/master/README.md#virtualbox-guest-additions - * - * @param path - * path to escape - * @return escaped path - */ - protected String escapePath(String path) { - String esc; - if (path.indexOf(":") == 1) { - //check and replace only occurrence of ":" after disk label on Windows host (e.g. C:/) - // but keep other occurrences it can be marker for docker mount volumes - // (e.g. /path/dir/from/host:/name/of/dir/in/container ) - esc = path.replaceFirst(":", "").replace('\\', '/'); - esc = Character.toLowerCase(esc.charAt(0)) + esc.substring(1); //letter of disk mark must be lower case - } else { - esc = path.replace('\\', '/'); - } - if (!esc.startsWith("/")) { - esc = "/" + esc; - } - return esc; } @Override @@ -282,7 +86,7 @@ public class DockerInstanceProvider implements InstanceProvider { @Override public Set getRecipeTypes() { - return supportedRecipeTypes; + return Collections.emptySet(); } /** @@ -305,144 +109,9 @@ public class DockerInstanceProvider implements InstanceProvider { */ @Override public Instance createInstance(Machine machine, - LineConsumer creationLogsOutput) throws UnsupportedRecipeException, - InvalidRecipeException, - SourceNotFoundException, - NotFoundException, + LineConsumer creationLogsOutput) throws NotFoundException, MachineException { - MachineConfig config = machine.getConfig(); - String sourceType = config.getSource().getType(); - - final String userName = EnvironmentContext.getCurrent().getSubject().getUserName(); - final String containerName = containerNameGenerator.generateContainerName(machine.getWorkspaceId(), - machine.getId(), - userName, - config.getName()); - final String imageName = "eclipse-che/" + containerName; - final ProgressLineFormatterImpl progressLineFormatter = new ProgressLineFormatterImpl(); - ProgressMonitor progressMonitor = currentProgressStatus -> { - try { - creationLogsOutput.writeLine(progressLineFormatter.format(currentProgressStatus)); - } catch (IOException e) { - LOG.error(e.getLocalizedMessage(), e); - } - }; - - if (DOCKER_FILE_TYPE.equals(sourceType)) { - buildImage(config, imageName, doForcePullOnBuild, progressMonitor); - } else if (DOCKER_IMAGE_TYPE.equals(sourceType)) { - pullImage(config, imageName, progressMonitor); - } else { - // not supported - throw new UnsupportedRecipeException("The type '" + sourceType + "' is not supported"); - } - - return createInstance(containerName, - machine, - imageName, - creationLogsOutput); - } - - protected void pullImage(MachineConfig machineConfig, - String machineImageName, - ProgressMonitor progressMonitor) throws NotFoundException, - MachineException, - SourceNotFoundException { - MachineSource source = machineConfig.getSource(); - if (isNullOrEmpty(source.getLocation())) { - throw new InvalidRecipeException( - format("The type '%s' needs to be used with a location, not with any other parameter. Found '%s'.", - source.getType(), - source)); - } - final DockerMachineSource dockerMachineSource = new DockerMachineSource(source); - if (dockerMachineSource.getRepository() == null) { - throw new MachineException( - format("Machine creation failed. Machine source is invalid. No repository is defined. Found %s.", - dockerMachineSource)); - } - - try { - boolean isSnapshot = SNAPSHOT_LOCATION_PATTERN.matcher(dockerMachineSource.getLocation()).matches(); - if (!isSnapshot || snapshotUseRegistry) { - PullParams pullParams = PullParams.create(dockerMachineSource.getRepository()) - .withTag(MoreObjects.firstNonNull(dockerMachineSource.getTag(), LATEST_TAG)) - .withRegistry(dockerMachineSource.getRegistry()) - .withAuthConfigs(dockerCredentials.getCredentials()); - docker.pull(pullParams, progressMonitor); - } - - final String fullNameOfPulledImage = dockerMachineSource.getLocation(false); - try { - // tag image with generated name to allow sysadmin recognize it - docker.tag(TagParams.create(fullNameOfPulledImage, machineImageName)); - } catch (ImageNotFoundException nfEx) { - throw new SourceNotFoundException(nfEx.getLocalizedMessage(), nfEx); - } - - // remove unneeded tag if restoring snapshot from registry - if (isSnapshot && snapshotUseRegistry){ - docker.removeImage(RemoveImageParams.create(fullNameOfPulledImage).withForce(false)); - } - } catch (IOException e) { - LOG.error(e.getLocalizedMessage(), e); - throw new MachineException("Can't create machine from image. Cause: " + e.getLocalizedMessage()); - } - } - - protected void buildImage(MachineConfig machineConfig, - String machineImageName, - boolean doForcePullOnBuild, - ProgressMonitor progressMonitor) - throws MachineException { - - Recipe recipe = recipeRetriever.getRecipe(machineConfig); - Dockerfile dockerfile = parseRecipe(recipe); - long memoryLimit = (long)machineConfig.getLimits().getRam() * 1024 * 1024; - - File workDir = null; - try { - // build docker image - workDir = Files.createTempDirectory(null).toFile(); - final File dockerfileFile = new File(workDir, "Dockerfile"); - dockerfile.writeDockerfile(dockerfileFile); - - docker.buildImage(BuildImageParams.create(dockerfileFile) - .withForceRemoveIntermediateContainers(true) - .withRepository(machineImageName) - .withAuthConfigs(dockerCredentials.getCredentials()) - .withDoForcePull(doForcePullOnBuild) - .withMemoryLimit(memoryLimit) - .withMemorySwapLimit(-1), - progressMonitor); - } catch (IOException e) { - throw new MachineException(e.getLocalizedMessage(), e); - } finally { - if (workDir != null) { - FileCleaner.addFile(workDir); - } - } - } - - public static Dockerfile parseRecipe(final Recipe recipe) throws InvalidRecipeException { - if (recipe.getScript() == null) { - throw new InvalidRecipeException("Unable build docker based machine, recipe isn't set or doesn't provide Dockerfile and " + - "no Dockerfile found in the list of files attached to this builder."); - } - try { - Dockerfile dockerfile = DockerfileParser.parse(recipe.getScript()); - if (dockerfile.getImages().isEmpty()) { - throw new InvalidRecipeException("Unable build docker based machine, Dockerfile found but it doesn't contain base image."); - } - if (dockerfile.getImages().size() > 1) { - throw new InvalidRecipeException( - "Unable build docker based machine, Dockerfile found but it contains more than one instruction 'FROM'."); - } - return dockerfile; - } catch (DockerFileException e) { - LOG.debug(e.getLocalizedMessage(), e); - throw new InvalidRecipeException("Unable build docker based machine. " + e.getMessage()); - } + throw new UnsupportedOperationException("This machine provider is deprecated."); } /** @@ -509,139 +178,4 @@ public class DockerInstanceProvider implements InstanceProvider { } } - private Instance createInstance(final String containerName, - final Machine machine, - final String imageName, - final LineConsumer outputConsumer) - throws MachineException { - String containerIdCopy = null; - try { - final Map> portsToExpose; - final String[] volumes; - final List env; - if (machine.getConfig().isDev()) { - portsToExpose = new HashMap<>(devMachinePortsToExpose); - - final String projectFolderVolume = format("%s:%s:Z", - workspaceFolderPathProvider.getPath(machine.getWorkspaceId()), - projectFolderPath); - volumes = ObjectArrays.concat(devMachineSystemVolumes, - SystemInfo.isWindows() ? escapePath(projectFolderVolume) : projectFolderVolume); - - env = new ArrayList<>(devMachineEnvVariables); - env.add(DockerInstanceRuntimeInfo.CHE_WORKSPACE_ID + '=' + machine.getWorkspaceId()); - env.add(DockerInstanceRuntimeInfo.USER_TOKEN + '=' + getUserToken(machine.getWorkspaceId())); - } else { - portsToExpose = new HashMap<>(commonMachinePortsToExpose); - volumes = commonMachineSystemVolumes; - env = new ArrayList<>(commonMachineEnvVariables); - } - - final long machineMemory = machine.getConfig().getLimits().getRam() * 1024L * 1024L; - final long machineMemorySwap = memorySwapMultiplier == -1 ? -1 : (long)(machineMemory * memorySwapMultiplier); - - machine.getConfig() - .getServers() - .stream() - .forEach(serverConf -> portsToExpose.put(serverConf.getPort(), Collections.emptyMap())); - - machine.getConfig() - .getEnvVariables() - .entrySet() - .stream() - .map(entry -> entry.getKey() + "=" + entry.getValue()) - .forEach(env::add); - - final HostConfig hostConfig = new HostConfig().withBinds(volumes) - .withExtraHosts(allMachinesExtraHosts) - .withPublishAllPorts(true) - .withMemorySwap(machineMemorySwap) - .withMemory(machineMemory) - .withPrivileged(privilegeMode); - final ContainerConfig config = new ContainerConfig().withImage(imageName) - .withExposedPorts(portsToExpose) - .withHostConfig(hostConfig) - .withEnv(env.toArray(new String[env.size()])); - - final String containerId = docker.createContainer(CreateContainerParams.create(config) - .withContainerName(containerName)) - .getId(); - containerIdCopy = containerId; - - docker.startContainer(StartContainerParams.create(containerId)); - - executor.execute(() -> { - long lastProcessedLogDate = 0; - boolean isContainerRunning = true; - while (isContainerRunning) { - try { - docker.getContainerLogs(GetContainerLogsParams.create(containerId) - .withFollow(true) - .withSince(lastProcessedLogDate), - new LogMessagePrinter(outputConsumer)); - isContainerRunning = false; - } catch (SocketTimeoutException ste) { - lastProcessedLogDate = System.currentTimeMillis() / 1000L; - // reconnect to container - } catch (ContainerNotFoundException e) { - isContainerRunning = false; - } catch (IOException e) { - LOG.error("Failed to get logs from machine {} backed by container {} with {} id", - machine, - containerName, - containerId); - } - } - }); - - final DockerNode node = dockerMachineFactory.createNode(machine.getWorkspaceId(), containerId); - if (machine.getConfig().isDev()) { - node.bindWorkspace(); - LOG.info("Machine with id '{}' backed by container '{}' has been deployed on node '{}'", - machine.getId(), containerId, node.getHost()); - } - - dockerInstanceStopDetector.startDetection(containerId, - machine.getId(), - machine.getWorkspaceId()); - - return dockerMachineFactory.createInstance(machine, - containerId, - imageName, - node, - outputConsumer); - } catch (IOException e) { - cleanUpContainer(containerIdCopy); - throw new MachineException(e.getLocalizedMessage(), e); - } catch (MachineException e) { - cleanUpContainer(containerIdCopy); - throw e; - } - } - - private void cleanUpContainer(@Nullable String containerId) { - try { - if (containerId != null) { - docker.removeContainer(RemoveContainerParams.create(containerId).withRemoveVolumes(true).withForce(true)); - } - } catch (Exception ex) { - LOG.error("Failed to remove docker container.", ex); - } - } - - // workspaceId parameter is required, because in case of separate storage for tokens - // you need to know exactly which workspace and which user to apply the token. - protected String getUserToken(String wsId) { - return EnvironmentContext.getCurrent().getSubject().getToken(); - } - - /** - * Returns set that contains all non empty and non nullable values from specified set - */ - protected Set removeEmptyAndNullValues(Set paths) { - return paths.stream() - .filter(path -> !Strings.isNullOrEmpty(path)) - .collect(Collectors.toSet()); - } - } diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerMachineModule.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerMachineModule.java index ece2924430..63b188228f 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerMachineModule.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerMachineModule.java @@ -11,11 +11,14 @@ package org.eclipse.che.plugin.docker.machine; import com.google.inject.AbstractModule; +import com.google.inject.TypeLiteral; import com.google.inject.multibindings.Multibinder; import com.google.inject.name.Names; import org.eclipse.che.api.core.model.machine.ServerConf; +import java.util.Set; + /** * Module for components that are needed for {@link DockerInstanceProvider} * @@ -50,5 +53,13 @@ public class DockerMachineModule extends AbstractModule { Multibinder machineVolumes = Multibinder.newSetBinder(binder(), String.class, Names.named("machine.docker.machine_volumes")); + + // Provides set of sets of strings instead of set of strings. + // This allows providers to return empty set as a value if no value should be added by provider. + // .permitDuplicates() is needed to allow different providers add empty sets. + Multibinder> networks = Multibinder.newSetBinder(binder(), + new TypeLiteral>() {}, + Names.named("machine.docker.networks")) + .permitDuplicates(); } } diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/local/LocalDockerModule.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/local/LocalDockerModule.java index eafb2bd11a..e4fec4e677 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/local/LocalDockerModule.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/local/LocalDockerModule.java @@ -11,6 +11,7 @@ package org.eclipse.che.plugin.docker.machine.local; import com.google.inject.AbstractModule; +import com.google.inject.TypeLiteral; import com.google.inject.assistedinject.FactoryModuleBuilder; import com.google.inject.multibindings.Multibinder; import com.google.inject.name.Names; @@ -23,6 +24,8 @@ import org.eclipse.che.plugin.docker.machine.DockerInstanceRuntimeInfo; import org.eclipse.che.plugin.docker.machine.DockerProcess; import org.eclipse.che.plugin.docker.machine.node.DockerNode; +import java.util.Set; + /** * The Module for Local Docker components * Note that LocalDockerNodeFactory requires machine.docker.local.project parameter pointed to @@ -66,5 +69,10 @@ public class LocalDockerModule extends AbstractModule { String.class, Names.named("machine.docker.dev_machine.machine_volumes")); devMachineVolumes.addBinding().toProvider(org.eclipse.che.plugin.docker.machine.local.provider.ExtraVolumeProvider.class); + + Multibinder> networks = Multibinder.newSetBinder(binder(), + new TypeLiteral>() {}, + Names.named("machine.docker.networks")); + networks.addBinding().toProvider(org.eclipse.che.plugin.docker.machine.CheInContainerNetworkProvider.class); } } diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/ComposeMachineProviderImplTest.java b/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/ComposeMachineProviderImplTest.java index c117969a66..82967bafe6 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/ComposeMachineProviderImplTest.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/ComposeMachineProviderImplTest.java @@ -58,6 +58,7 @@ import java.util.Set; import java.util.stream.Collectors; import static java.util.Arrays.asList; +import static java.util.Collections.emptySet; import static java.util.Collections.singletonMap; import static org.eclipse.che.plugin.docker.machine.DockerInstanceProvider.DOCKER_FILE_TYPE; import static org.eclipse.che.plugin.docker.machine.DockerInstanceProvider.MACHINE_SNAPSHOT_PREFIX; @@ -83,7 +84,6 @@ public class ComposeMachineProviderImplTest { private static final String MACHINE_NAME = "machineName"; private static final String USER_TOKEN = "userToken"; private static final String USER_NAME = "user"; - private static final int MEMORY_LIMIT_MB = 64; private static final boolean SNAPSHOT_USE_REGISTRY = true; private static final int MEMORY_SWAP_MULTIPLIER = 0; private static final String ENV_NAME = "env"; @@ -146,7 +146,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER)); + MEMORY_SWAP_MULTIPLIER, + emptySet())); EnvironmentContext envCont = new EnvironmentContext(); envCont.setSubject(new SubjectImpl(USER_NAME, "userId", USER_TOKEN, false)); @@ -335,7 +336,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER)); + MEMORY_SWAP_MULTIPLIER, + emptySet())); createInstanceFromRecipe(); @@ -515,7 +517,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - swapMultiplier)); + swapMultiplier, + emptySet())); // when createInstanceFromRecipe(memoryMB); @@ -573,7 +576,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); final boolean isDev = true; @@ -619,7 +623,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); final boolean isDev = false; @@ -672,7 +677,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); final boolean isDev = true; @@ -718,7 +724,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); final boolean isDev = false; @@ -758,7 +765,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); final boolean isDev = false; ComposeServiceImpl machine = createService(); @@ -801,7 +809,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); final boolean isDev = true; ComposeServiceImpl machine = createService(); @@ -844,7 +853,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); when(workspaceFolderPathProvider.getPath(anyString())).thenReturn(expectedHostPathOfProjects); @@ -884,7 +894,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); when(dockerNode.getProjectsFolder()).thenReturn("/tmp/projects"); @@ -933,7 +944,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); when(workspaceFolderPathProvider.getPath(anyString())).thenReturn(expectedHostPathOfProjects); final boolean isDev = true; @@ -980,7 +992,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); when(dockerNode.getProjectsFolder()).thenReturn(expectedHostPathOfProjects); @@ -1027,7 +1040,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); when(dockerNode.getProjectsFolder()).thenReturn(expectedHostPathOfProjects); @@ -1072,7 +1086,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); when(dockerNode.getProjectsFolder()).thenReturn(expectedHostPathOfProjects); final boolean isDev = true; @@ -1117,7 +1132,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); when(dockerNode.getProjectsFolder()).thenReturn(expectedHostPathOfProjects); @@ -1162,7 +1178,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); when(dockerNode.getProjectsFolder()).thenReturn(expectedHostPathOfProjects); final boolean isDev = false; @@ -1268,7 +1285,8 @@ public class ComposeMachineProviderImplTest { devEnv, commonEnv, SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); final boolean isDev = true; @@ -1305,7 +1323,8 @@ public class ComposeMachineProviderImplTest { devEnv, commonEnv, SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); final boolean isDev = false; @@ -1347,7 +1366,8 @@ public class ComposeMachineProviderImplTest { devEnv, commonEnv, SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); final boolean isDev = true; @@ -1385,7 +1405,8 @@ public class ComposeMachineProviderImplTest { devEnv, commonEnv, SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); final boolean isDev = false; @@ -1424,7 +1445,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); final boolean isDev = false; ComposeServiceImpl machine = createService(); @@ -1472,7 +1494,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); final boolean isDev = true; ComposeServiceImpl machine = createService(); @@ -1520,7 +1543,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); final boolean isDev = false; ComposeServiceImpl service = createService(); @@ -1568,7 +1592,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); + MEMORY_SWAP_MULTIPLIER, + emptySet()); final boolean isDev = true; ComposeServiceImpl machine = createService(); @@ -1700,7 +1725,8 @@ public class ComposeMachineProviderImplTest { Collections.emptySet(), Collections.emptySet(), snapshotUseRegistry, - MEMORY_SWAP_MULTIPLIER)); + MEMORY_SWAP_MULTIPLIER, + emptySet())); } public ComposeServiceImpl createService() { diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/DockerInstanceProviderTest.java b/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/DockerInstanceProviderTest.java deleted file mode 100644 index ab8d3d6471..0000000000 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/test/java/org/eclipse/che/plugin/docker/machine/DockerInstanceProviderTest.java +++ /dev/null @@ -1,2118 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * 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: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.plugin.docker.machine; - -import com.google.common.collect.Sets; - -import org.eclipse.che.api.core.NotFoundException; -import org.eclipse.che.api.core.model.machine.Machine; -import org.eclipse.che.api.core.model.machine.MachineConfig; -import org.eclipse.che.api.core.model.machine.MachineStatus; -import org.eclipse.che.api.core.model.machine.ServerConf; -import org.eclipse.che.api.core.util.LineConsumer; -import org.eclipse.che.api.machine.server.exception.InvalidRecipeException; -import org.eclipse.che.api.machine.server.exception.MachineException; -import org.eclipse.che.api.machine.server.model.impl.MachineLimitsImpl; -import org.eclipse.che.api.machine.server.model.impl.MachineConfigImpl; -import org.eclipse.che.api.machine.server.model.impl.MachineImpl; -import org.eclipse.che.api.machine.server.model.impl.MachineSourceImpl; -import org.eclipse.che.api.machine.server.model.impl.ServerConfImpl; -import org.eclipse.che.api.machine.server.recipe.RecipeImpl; -import org.eclipse.che.api.machine.server.util.RecipeRetriever; -import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.commons.subject.SubjectImpl; -import org.eclipse.che.plugin.docker.client.DockerConnector; -import org.eclipse.che.plugin.docker.client.DockerConnectorConfiguration; -import org.eclipse.che.plugin.docker.client.ProgressMonitor; -import org.eclipse.che.plugin.docker.client.UserSpecificDockerRegistryCredentialsProvider; -import org.eclipse.che.plugin.docker.client.json.ContainerCreated; -import org.eclipse.che.plugin.docker.client.json.ContainerInfo; -import org.eclipse.che.plugin.docker.client.json.ContainerState; -import org.eclipse.che.plugin.docker.client.params.CreateContainerParams; -import org.eclipse.che.plugin.docker.client.params.InspectContainerParams; -import org.eclipse.che.plugin.docker.client.params.BuildImageParams; -import org.eclipse.che.plugin.docker.client.params.PullParams; -import org.eclipse.che.plugin.docker.client.params.RemoveContainerParams; -import org.eclipse.che.plugin.docker.client.params.RemoveImageParams; -import org.eclipse.che.plugin.docker.client.params.StartContainerParams; -import org.eclipse.che.plugin.docker.client.params.TagParams; -import org.eclipse.che.plugin.docker.machine.node.DockerNode; -import org.eclipse.che.plugin.docker.machine.node.WorkspaceFolderPathProvider; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import static java.util.Arrays.asList; -import static org.eclipse.che.plugin.docker.machine.DockerInstanceProvider.DOCKER_FILE_TYPE; -import static org.eclipse.che.plugin.docker.machine.DockerInstanceProvider.DOCKER_IMAGE_TYPE; -import static org.eclipse.che.plugin.docker.machine.DockerInstanceProvider.MACHINE_SNAPSHOT_PREFIX; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; - -@Listeners(MockitoTestNGListener.class) -public class DockerInstanceProviderTest { - private static final String PROJECT_FOLDER_PATH = "/projects"; - private static final String CONTAINER_ID = "containerId"; - private static final String WORKSPACE_ID = "wsId"; - private static final String MACHINE_ID = "machineId"; - private static final String MACHINE_NAME = "machineName"; - private static final String USER_TOKEN = "userToken"; - private static final String USER_NAME = "user"; - private static final int MEMORY_LIMIT_MB = 64; - private static final boolean SNAPSHOT_USE_REGISTRY = true; - private static final int MEMORY_SWAP_MULTIPLIER = 0; - - @Mock - private DockerConnector dockerConnector; - - @Mock - private DockerConnectorConfiguration dockerConnectorConfiguration; - - @Mock - private DockerMachineFactory dockerMachineFactory; - - @Mock - private DockerInstanceStopDetector dockerInstanceStopDetector; - - @Mock - private DockerContainerNameGenerator containerNameGenerator; - - @Mock - private DockerNode dockerNode; - - @Mock - private WorkspaceFolderPathProvider workspaceFolderPathProvider; - - @Mock - private UserSpecificDockerRegistryCredentialsProvider credentialsReader; - - @Mock - private ContainerInfo containerInfo; - - @Mock - private ContainerState containerState; - - @Mock - private RecipeRetriever recipeRetriever; - - private DockerInstanceProvider dockerInstanceProvider; - - @BeforeMethod - public void setUp() throws Exception { - when(dockerConnectorConfiguration.getDockerHostIp()).thenReturn("123.123.123.123"); - - dockerInstanceProvider = spy(new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER)); - - EnvironmentContext envCont = new EnvironmentContext(); - envCont.setSubject(new SubjectImpl(USER_NAME, "userId", USER_TOKEN, false)); - EnvironmentContext.setCurrent(envCont); - - - when(recipeRetriever.getRecipe(any(MachineConfig.class))) - .thenReturn(new RecipeImpl().withType(DOCKER_FILE_TYPE).withScript("FROM codenvy")); - - when(dockerMachineFactory.createNode(anyString(), anyString())).thenReturn(dockerNode); - when(dockerConnector.createContainer(any(CreateContainerParams.class))) - .thenReturn(new ContainerCreated(CONTAINER_ID, new String[0])); - when(dockerConnector.inspectContainer(any(InspectContainerParams.class))).thenReturn(containerInfo); - when(containerInfo.getState()).thenReturn(containerState); - when(containerState.isRunning()).thenReturn(false); - } - - @AfterMethod - public void tearDown() throws Exception { - EnvironmentContext.reset(); - } - - @Test - public void shouldReturnTypeDocker() throws Exception { - assertEquals(dockerInstanceProvider.getType(), "docker"); - } - - @Test - public void shouldReturnRecipeTypesDockerfile() throws Exception { - assertEquals(dockerInstanceProvider.getRecipeTypes(), Sets.newHashSet(DOCKER_FILE_TYPE, DOCKER_IMAGE_TYPE)); - } - - // TODO add tests for instance snapshot removal - - @Test - public void shouldBuildDockerfileOnInstanceCreationFromRecipe() throws Exception { - String generatedContainerId = "genContainerId"; - doReturn(generatedContainerId).when(containerNameGenerator).generateContainerName(eq(WORKSPACE_ID), - eq(MACHINE_ID), - eq(USER_NAME), - eq(MACHINE_NAME)); - - - createInstanceFromRecipe(); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(BuildImageParams.class); - verify(dockerConnector).buildImage(argumentCaptor.capture(), - any(ProgressMonitor.class)); - BuildImageParams buildImageParams = argumentCaptor.getValue(); - assertEquals(buildImageParams.getRepository(), "eclipse-che/" + generatedContainerId); - assertEquals((long)buildImageParams.getMemoryLimit(), (long)MEMORY_LIMIT_MB * 1024 * 1024); - assertEquals((long)buildImageParams.getMemorySwapLimit(), (long)-1); - } - - @Test - public void shouldPullDockerImageOnInstanceCreationFromSnapshotFromRegistry() throws Exception { - String repo = MACHINE_SNAPSHOT_PREFIX + "repo"; - String tag = "latest"; - String registry = "localhost:1234"; - - createInstanceFromSnapshot(repo, tag, registry); - - PullParams pullParams = PullParams.create(repo).withRegistry(registry).withTag(tag); - - verify(dockerConnector).pull(eq(pullParams), any(ProgressMonitor.class)); - } - - @Test - public void shouldNotPullDockerImageOnInstanceCreationFromLocalSnapshot() throws Exception { - String repo = MACHINE_SNAPSHOT_PREFIX + "repo"; - String tag = "latest"; - String registry = "localhost:1234"; - dockerInstanceProvider = getDockerInstanceProvider(false); - - createInstanceFromSnapshot(repo, tag, registry); - - verify(dockerConnector, never()).pull(eq(PullParams.create(repo).withTag(tag)), any(ProgressMonitor.class)); - } - - @Test - public void shouldUseLocalImageOnInstanceCreationFromSnapshot() throws Exception { - final String repo = MACHINE_SNAPSHOT_PREFIX + "repo"; - final String tag = "latest"; - dockerInstanceProvider = getDockerInstanceProvider(false); - - MachineImpl machine = getMachineBuilder().build(); - final MachineSourceImpl machineSource = new DockerMachineSource(repo).withTag(tag); - machine.getConfig().setSource(machineSource); - - dockerInstanceProvider.createInstance(machine, - LineConsumer.DEV_NULL); - - verify(dockerConnector, never()).pull(any(PullParams.class), any(ProgressMonitor.class)); - } - - @Test - public void shouldRemoveLocalImageDuringRemovalOfSnapshot() throws Exception { - final String repo = MACHINE_SNAPSHOT_PREFIX + "repo"; - final String tag = "latest"; - final DockerMachineSource dockerMachineSource = new DockerMachineSource(repo).withTag(tag); - dockerInstanceProvider = getDockerInstanceProvider(false); - - dockerInstanceProvider.removeInstanceSnapshot(dockerMachineSource); - - verify(dockerConnector, times(1)).removeImage(RemoveImageParams.create(dockerMachineSource.getLocation(false))); - } - - @Test - public void shouldRemoveImageAfterRestoreFromSnapshotFromRegistry() throws Exception { - String repo = MACHINE_SNAPSHOT_PREFIX + "repo"; - String tag = "latest"; - - createInstanceFromSnapshot(repo, tag, null); - - verify(dockerConnector).removeImage(any(RemoveImageParams.class)); - } - - @Test - public void shouldNotRemoveImageAfterRestoreFromLocalSnapshot() throws Exception { - String repo = MACHINE_SNAPSHOT_PREFIX + "repo"; - String tag = "latest"; - dockerInstanceProvider = getDockerInstanceProvider(false); - - createInstanceFromSnapshot(repo, tag, null); - - verify(dockerConnector, never()).removeImage(any(RemoveImageParams.class)); - } - - @Test - public void shouldNotRemoveImageWhenCreatingInstanceFromLocalImage() throws Exception { - String repo = "repo1"; - String tag = "latest"; - DockerInstanceProvider dockerInstanceProvider = getDockerInstanceProvider(false); - MachineImpl machine = getMachineBuilder().build(); - machine.getConfig().setSource(new DockerMachineSource(repo).withTag(tag).withDigest("digest")); - - dockerInstanceProvider.createInstance(machine, LineConsumer.DEV_NULL); - - verify(dockerConnector, never()).removeImage(any(RemoveImageParams.class)); - } - - @Test - public void shouldReTagBuiltImageWithPredictableOnInstanceCreationFromRecipe() throws Exception { - String generatedContainerId = "genContainerId"; - doReturn(generatedContainerId).when(containerNameGenerator).generateContainerName(eq(WORKSPACE_ID), - eq(MACHINE_ID), - eq(USER_NAME), - eq(MACHINE_NAME)); - String repo = MACHINE_SNAPSHOT_PREFIX + "repo1"; - String tag = "tag1"; - String registry = "registry1"; - TagParams tagParams = TagParams.create(registry + "/" + repo + ":" + tag, "eclipse-che/" + generatedContainerId); - - createInstanceFromSnapshot(repo, tag, registry); - - verify(dockerConnector).tag(eq(tagParams)); - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(RemoveImageParams.class); - verify(dockerConnector).removeImage(argumentCaptor.capture()); - RemoveImageParams imageParams = argumentCaptor.getValue(); - assertEquals(imageParams.getImage(), registry + "/" + repo + ":" + tag); - assertFalse(imageParams.isForce()); - } - - @Test - public void shouldCreateContainerOnInstanceCreationFromRecipe() throws Exception { - String generatedContainerId = "genContainerId"; - doReturn(generatedContainerId).when(containerNameGenerator).generateContainerName(eq(WORKSPACE_ID), - eq(MACHINE_ID), - eq(USER_NAME), - eq(MACHINE_NAME)); - - - createInstanceFromRecipe(); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - assertEquals(argumentCaptor.getValue().getContainerConfig().getImage(), "eclipse-che/" + generatedContainerId); - } - - @Test - public void shouldStartContainerOnCreateInstanceFromRecipe() throws Exception { - createInstanceFromRecipe(); - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(StartContainerParams.class); - verify(dockerConnector).startContainer(argumentCaptor.capture()); - assertEquals(argumentCaptor.getValue().getContainer(), CONTAINER_ID); - } - - @Test - public void shouldCreateContainerOnInstanceCreationFromSnapshot() throws Exception { - String generatedContainerId = "genContainerId"; - doReturn(generatedContainerId).when(containerNameGenerator).generateContainerName(eq(WORKSPACE_ID), - eq(MACHINE_ID), - eq(USER_NAME), - eq(MACHINE_NAME)); - createInstanceFromSnapshot(); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - assertEquals(argumentCaptor.getValue().getContainerConfig().getImage(), "eclipse-che/" + generatedContainerId); - } - - @Test - public void shouldCreateContainerWithPrivilegeMode() throws Exception { - dockerInstanceProvider = spy(new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - true, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER)); - - createInstanceFromRecipe(); - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - assertTrue(argumentCaptor.getValue().getContainerConfig().getHostConfig().isPrivileged()); - } - - @Test(expectedExceptions = MachineException.class) - public void shouldRemoveContainerInCaseFailedBindWorkspaceOnCreateInstance() throws Exception { - doThrow(MachineException.class).when(dockerNode).bindWorkspace(); - final boolean isDev = true; - final String hostProjectsFolder = "/tmp/projects"; - when(dockerNode.getProjectsFolder()).thenReturn(hostProjectsFolder); - - createInstanceFromRecipe(isDev, WORKSPACE_ID); - - verify(dockerConnector).removeContainer(RemoveContainerParams.create(CONTAINER_ID).withRemoveVolumes(true).withForce(true)); - } - - @Test(expectedExceptions = MachineException.class) - public void shouldRemoveContainerInCaseFailedStartContainer() throws Exception { - doThrow(IOException.class).when(dockerConnector).startContainer(StartContainerParams.create(CONTAINER_ID)); - - createInstanceFromRecipe(false, WORKSPACE_ID); - - verify(dockerConnector).removeContainer(RemoveContainerParams.create(CONTAINER_ID).withRemoveVolumes(true).withForce(true)); - } - - @Test(expectedExceptions = MachineException.class) - public void shouldRemoveContainerInCaseFailedGetCreateNode() throws Exception { - doThrow(IOException.class).when(dockerMachineFactory).createNode(any(), any()); - - createInstanceFromRecipe(false, WORKSPACE_ID); - - verify(dockerConnector).removeContainer(RemoveContainerParams.create(CONTAINER_ID).withRemoveVolumes(true).withForce(true)); - } - - @Test(expectedExceptions = MachineException.class) - public void shouldRemoveContainerInCaseFailedCreateInstanceOnTheDockerMachineFactory() throws Exception { - doThrow(IOException.class).when(dockerMachineFactory).createInstance(any(), any(), any(), any(), any()); - - createInstanceFromRecipe(false, WORKSPACE_ID); - - verify(dockerConnector).removeContainer(RemoveContainerParams.create(CONTAINER_ID).withRemoveVolumes(true).withForce(true)); - } - - @Test - public void shouldStartContainerOnCreateInstanceFromSnapshot() throws Exception { - createInstanceFromSnapshot(); - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(StartContainerParams.class); - verify(dockerConnector).startContainer(argumentCaptor.capture()); - assertEquals(argumentCaptor.getValue().getContainer(), CONTAINER_ID); - } - - @Test - public void shouldCallCreationDockerInstanceWithFactoryOnCreateInstanceFromSnapshot() throws Exception { - String generatedContainerId = "genContainerId"; - doReturn(generatedContainerId).when(containerNameGenerator).generateContainerName(eq(WORKSPACE_ID), - eq(MACHINE_ID), - eq(USER_NAME), - eq(MACHINE_NAME)); - - final MachineSourceImpl machineSource = new MachineSourceImpl("type").setLocation("location"); - final MachineImpl machine = - new MachineImpl(new MachineConfigImpl(false, - MACHINE_NAME, - "machineType", - machineSource, - new MachineLimitsImpl(MEMORY_LIMIT_MB), - asList(new ServerConfImpl("ref1", "8080", "https", null), - new ServerConfImpl("ref2", "9090/udp", "someprotocol", null)), - Collections.singletonMap("key1", "value1")), - "machineId", - WORKSPACE_ID, - "envName", - USER_NAME, - MachineStatus.CREATING, - null); - - - createInstanceFromSnapshot(machine); - - - verify(dockerMachineFactory).createInstance(eq(machine), - eq(CONTAINER_ID), - eq("eclipse-che/" + generatedContainerId), - eq(dockerNode), - any(LineConsumer.class)); - } - - - - @Test - public void shouldCallCreationDockerInstanceWithFactoryOnCreateInstanceFromRecipe() throws Exception { - String generatedContainerId = "genContainerId"; - doReturn(generatedContainerId).when(containerNameGenerator).generateContainerName(eq(WORKSPACE_ID), - eq(MACHINE_ID), - eq(USER_NAME), - eq(MACHINE_NAME)); - - final MachineSourceImpl machineSource = new MachineSourceImpl(DOCKER_FILE_TYPE).setLocation("location"); - final MachineImpl machine = - new MachineImpl(new MachineConfigImpl(false, - MACHINE_NAME, - "machineType", - machineSource, - new MachineLimitsImpl(MEMORY_LIMIT_MB), - asList(new ServerConfImpl("ref1", "8080", "https", null), - new ServerConfImpl("ref2", "9090/udp", "someprotocol", null)), - Collections.singletonMap("key1", "value1")), - "machineId", - WORKSPACE_ID, - "envName", - USER_NAME, - MachineStatus.CREATING, - null); - - createInstanceFromRecipe(machine); - - - verify(dockerMachineFactory).createInstance(eq(machine), - eq(CONTAINER_ID), - eq("eclipse-che/" + generatedContainerId), - eq(dockerNode), - any(LineConsumer.class)); - } - - @Test - public void shouldBindWorkspaceOnDevInstanceCreationFromRecipe() throws Exception { - final boolean isDev = true; - final String hostProjectsFolder = "/tmp/projects"; - - when(dockerNode.getProjectsFolder()).thenReturn(hostProjectsFolder); - - createInstanceFromRecipe(isDev, WORKSPACE_ID); - - verify(dockerNode).bindWorkspace(); - } - - @Test - public void shouldBindWorkspaceOnDevInstanceCreationFromSnapshot() throws Exception { - final boolean isDev = true; - final String hostProjectsFolder = "/tmp/projects"; - - when(dockerNode.getProjectsFolder()).thenReturn(hostProjectsFolder); - - createInstanceFromSnapshot(isDev, WORKSPACE_ID); - - verify(dockerNode).bindWorkspace(); - } - - @Test - public void shouldNotBindWorkspaceOnNonDevInstanceCreationFromRecipe() throws Exception { - final boolean isDev = false; - - when(dockerNode.getProjectsFolder()).thenReturn("/tmp/projects"); - - createInstanceFromRecipe(isDev, WORKSPACE_ID); - - verify(dockerNode, never()).bindWorkspace(); - } - - @Test - public void shouldNotBindWorkspaceOnNonDevInstanceCreationFromSnapshot() throws Exception { - final boolean isDev = false; - - when(dockerNode.getProjectsFolder()).thenReturn("/tmp/projects"); - - createInstanceFromSnapshot(isDev, WORKSPACE_ID); - - verify(dockerNode, never()).bindWorkspace(); - } - - @Test - public void shouldSetMemorySizeInContainersOnInstanceCreationFromRecipe() throws Exception { - int memorySizeMB = 234; - - - createInstanceFromRecipe(memorySizeMB); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - verify(dockerConnector).startContainer(any(StartContainerParams.class)); - // docker accepts memory size in bytes - assertEquals(argumentCaptor.getValue().getContainerConfig().getHostConfig().getMemory(), memorySizeMB * 1024 * 1024); - } - - @Test - public void shouldSetMemorySizeInContainersOnInstanceCreationFromSnapshot() throws Exception { - int memorySizeMB = 234; - - - createInstanceFromSnapshot(memorySizeMB); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - verify(dockerConnector).startContainer(any(StartContainerParams.class)); - // docker accepts memory size in bytes - assertEquals(argumentCaptor.getValue().getContainerConfig().getHostConfig().getMemory(), memorySizeMB * 1024 * 1024); - } - - @Test(dataProvider = "swapTestProvider") - public void shouldBeAbleToSetCorrectSwapSize(double swapMultiplier, int memoryMB, long expectedSwapSize) throws Exception { - // given - dockerInstanceProvider = spy(new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - true, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - swapMultiplier)); - - // when - createInstanceFromRecipe(memoryMB); - - // then - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - assertEquals(argumentCaptor.getValue().getContainerConfig().getHostConfig().getMemorySwap(), expectedSwapSize); - } - - @DataProvider(name = "swapTestProvider") - public static Object[][] swapTestProvider() { - return new Object[][]{ - {-1, 1000, -1}, - {0, 1000, 1000L * 1024 * 1024}, - {0.7, 1000, (long)(1.7 * 1000 * 1024 * 1024)}, - {1, 1000, 2L * 1000 * 1024 * 1024}, - {2, 1000, 3L * 1000 * 1024 * 1024}, - {2.5, 1000, (long)(3.5 * 1000 * 1024 * 1024)} - }; - } - - @Test(expectedExceptions = InvalidRecipeException.class) - public void checkExceptionIfImageWithContent() throws Exception { - MachineImpl machine = getMachineBuilder().build(); - machine.getConfig().getSource().setContent("hello"); - machine.getConfig().getSource().setType(DOCKER_IMAGE_TYPE); - createInstanceFromRecipe(machine); - } - - @Test - public void shouldExposeCommonAndDevPortsToContainerOnDevInstanceCreationFromRecipe() throws Exception { - List expectedExposedPorts = new ArrayList<>(); - final Set commonServers = new HashSet<>(asList(new ServerConfImpl("reference1", "8080", "http", null), - new ServerConfImpl("reference2", "8081", "ftp", null))); - expectedExposedPorts.addAll(commonServers.stream() - .map(ServerConf::getPort) - .collect(Collectors.toList())); - - final Set devServers = new HashSet<>(asList(new ServerConfImpl("reference3", "8082", "https", null), - new ServerConfImpl("reference4", "8083", "sftp", null))); - expectedExposedPorts.addAll(devServers.stream() - .map(ServerConf::getPort) - .collect(Collectors.toList())); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - devServers, - commonServers, - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - final boolean isDev = true; - - - createInstanceFromRecipe(isDev); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - - assertTrue(new ArrayList<>(argumentCaptor.getValue() - .getContainerConfig() - .getExposedPorts() - .keySet()) - .containsAll(expectedExposedPorts)); - } - - @Test - public void shouldExposeOnlyCommonPortsToContainerOnNonDevInstanceCreationFromRecipe() throws Exception { - List expectedExposedPorts = new ArrayList<>(); - final Set commonServers = new HashSet<>(asList(new ServerConfImpl("reference1", "8080", "http", null), - new ServerConfImpl("reference2", "8081", "ftp", null))); - expectedExposedPorts.addAll(commonServers.stream() - .map(ServerConf::getPort) - .collect(Collectors.toList())); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - commonServers, - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - final boolean isDev = false; - - - createInstanceFromRecipe(isDev); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - - assertTrue(new ArrayList<>(argumentCaptor.getValue() - .getContainerConfig() - .getExposedPorts() - .keySet()) - .containsAll(expectedExposedPorts)); - } - - @Test - public void shouldExposeCommonAndDevPortsToContainerOnDevInstanceCreationFromSnapshot() throws Exception { - List expectedExposedPorts = new ArrayList<>(); - final Set commonServers = new HashSet<>(asList(new ServerConfImpl("reference1", "8080", "http", null), - new ServerConfImpl("reference2", "8081", "ftp", null))); - expectedExposedPorts.addAll(commonServers.stream() - .map(ServerConf::getPort) - .collect(Collectors.toList())); - - final Set devServers = new HashSet<>(asList(new ServerConfImpl("reference3", "8082", "https", null), - new ServerConfImpl("reference4", "8083", "sftp", null))); - expectedExposedPorts.addAll(devServers.stream() - .map(ServerConf::getPort) - .collect(Collectors.toList())); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - devServers, - commonServers, - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - final boolean isDev = true; - - - createInstanceFromSnapshot(isDev); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - - assertTrue(new ArrayList<>(argumentCaptor.getValue() - .getContainerConfig() - .getExposedPorts() - .keySet()) - .containsAll(expectedExposedPorts)); - } - - @Test - public void shouldExposeOnlyCommonPortsToContainerOnNonDevInstanceCreationFromSnapshot() throws Exception { - List expectedExposedPorts = new ArrayList<>(); - final Set commonServers = new HashSet<>(asList(new ServerConfImpl("reference1", "8080", "http", null), - new ServerConfImpl("reference2", "8081", "ftp", null))); - expectedExposedPorts.addAll(commonServers.stream() - .map(ServerConf::getPort) - .collect(Collectors.toList())); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - commonServers, - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - final boolean isDev = false; - - - createInstanceFromSnapshot(isDev); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - - assertTrue(new ArrayList<>(argumentCaptor.getValue() - .getContainerConfig() - .getExposedPorts() - .keySet()) - .containsAll(expectedExposedPorts)); - } - - @Test - public void shouldAddServersConfsPortsFromMachineConfigToExposedPortsOnNonDevInstanceCreationFromSnapshot() throws Exception { - // given - List expectedExposedPorts = new ArrayList<>(); - final List serversFromConf = asList(new ServerConfImpl("reference1", "8080", "http", null), - new ServerConfImpl("reference2", "8081", "ftp", null)); - expectedExposedPorts.addAll(serversFromConf.stream() - .map(ServerConf::getPort) - .collect(Collectors.toList())); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - final boolean isDev = false; - - // when - createInstanceFromSnapshot(getMachineBuilder().setConfig(getMachineConfigBuilder().setDev(isDev) - .setServers(serversFromConf) - .build()) - .build()); - - // then - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - - assertTrue(new ArrayList<>(argumentCaptor.getValue() - .getContainerConfig() - .getExposedPorts() - .keySet()) - .containsAll(expectedExposedPorts)); - } - - @Test - public void shouldAddServersConfsPortsFromMachineConfigToExposedPortsOnNonDevInstanceCreationFromRecipe() throws Exception { - // given - List expectedExposedPorts = new ArrayList<>(); - final List serversFromConf = asList(new ServerConfImpl("reference1", "8080", "http", null), - new ServerConfImpl("reference2", "8081", "ftp", null)); - expectedExposedPorts.addAll(serversFromConf.stream() - .map(ServerConf::getPort) - .collect(Collectors.toList())); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - final boolean isDev = false; - - // when - createInstanceFromRecipe(getMachineBuilder().setConfig(getMachineConfigBuilder().setDev(isDev) - .setServers(serversFromConf) - .build()) - .build()); - - // then - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - - assertTrue(new ArrayList<>(argumentCaptor.getValue() - .getContainerConfig() - .getExposedPorts() - .keySet()) - .containsAll(expectedExposedPorts)); - } - - @Test - public void shouldAddServersConfsPortsFromMachineConfigToExposedPortsOnDevInstanceCreationFromSnapshot() throws Exception { - // given - List expectedExposedPorts = new ArrayList<>(); - final List serversFromConf = asList(new ServerConfImpl("reference1", "8080", "http", null), - new ServerConfImpl("reference2", "8081", "ftp", null)); - expectedExposedPorts.addAll(serversFromConf.stream() - .map(ServerConf::getPort) - .collect(Collectors.toList())); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - final boolean isDev = true; - - // when - createInstanceFromSnapshot(getMachineBuilder().setConfig(getMachineConfigBuilder().setDev(isDev) - .setServers(serversFromConf) - .build()) - .build()); - - // then - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - - assertTrue(new ArrayList<>(argumentCaptor.getValue() - .getContainerConfig() - .getExposedPorts() - .keySet()) - .containsAll(expectedExposedPorts)); - } - - @Test - public void shouldAddServersConfsPortsFromMachineConfigToExposedPortsOnDevInstanceCreationFromRecipe() throws Exception { - // given - List expectedExposedPorts = new ArrayList<>(); - final List serversFromConf = asList(new ServerConfImpl("reference1", "8080", "http", null), - new ServerConfImpl("reference2", "8081", "ftp", null)); - expectedExposedPorts.addAll(serversFromConf.stream() - .map(ServerConf::getPort) - .collect(Collectors.toList())); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - final boolean isDev = true; - - // when - createInstanceFromRecipe(getMachineBuilder().setConfig(getMachineConfigBuilder().setDev(isDev) - .setServers(serversFromConf) - .build()) - .build()); - - // then - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - - assertTrue(new ArrayList<>(argumentCaptor.getValue() - .getContainerConfig() - .getExposedPorts() - .keySet()) - .containsAll(expectedExposedPorts)); - } - - @Test - public void shouldBindProjectsFSVolumeToContainerOnDevInstanceCreationFromRecipe() throws Exception { - final String expectedHostPathOfProjects = "/tmp/projects"; - String[] expectedVolumes = new String[] {expectedHostPathOfProjects + ":/projects:Z"}; - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - when(workspaceFolderPathProvider.getPath(anyString())).thenReturn(expectedHostPathOfProjects); - - final boolean isDev = true; - - - createInstanceFromRecipe(isDev); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - verify(dockerConnector).startContainer(any(StartContainerParams.class)); - - assertEquals(argumentCaptor.getValue().getContainerConfig().getHostConfig().getBinds(), expectedVolumes); - } - - @Test - public void shouldBindProjectsFSVolumeToContainerOnDevInstanceCreationFromSnapshot() throws Exception { - final String expectedHostPathOfProjects = "/tmp/projects"; - final String[] expectedVolumes = new String[] {expectedHostPathOfProjects + ":/projects:Z"}; - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - when(workspaceFolderPathProvider.getPath(anyString())).thenReturn(expectedHostPathOfProjects); - - final boolean isDev = true; - - - createInstanceFromSnapshot(isDev); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - verify(dockerConnector).startContainer(any(StartContainerParams.class)); - - assertEquals(argumentCaptor.getValue().getContainerConfig().getHostConfig().getBinds(), expectedVolumes); - } - - @Test - public void shouldNotBindProjectsFSVolumeToContainerOnNonDevInstanceCreationFromRecipe() throws Exception { - String[] expectedVolumes = new String[0]; - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - when(dockerNode.getProjectsFolder()).thenReturn("/tmp/projects"); - - final boolean isDev = false; - - - createInstanceFromRecipe(isDev); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - verify(dockerConnector).startContainer(any(StartContainerParams.class)); - - assertEquals(argumentCaptor.getValue().getContainerConfig().getHostConfig().getBinds(), expectedVolumes); - } - - @Test - public void shouldNotBindProjectsFSVolumeToContainerOnNonDevInstanceCreationFromSnapshot() throws Exception { - String[] expectedVolumes = new String[0]; - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - when(dockerNode.getProjectsFolder()).thenReturn("/tmp/projects"); - - final boolean isDev = false; - - - createInstanceFromSnapshot(isDev); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - verify(dockerConnector).startContainer(any(StartContainerParams.class)); - - assertEquals(argumentCaptor.getValue().getContainerConfig().getHostConfig().getBinds(), expectedVolumes); - } - - @Test - public void shouldBindCommonAndDevVolumesToContainerOnDevInstanceCreationFromRecipe() throws Exception { - final String expectedHostPathOfProjects = "/tmp/projects"; - Set devVolumes = new HashSet<>(asList("/etc:/tmp/etc:ro", "/some/thing:/home/some/thing")); - Set commonVolumes = new HashSet<>(asList("/some/thing/else:/home/some/thing/else", "/other/path:/home/other/path")); - - final ArrayList expectedVolumes = new ArrayList<>(); - expectedVolumes.addAll(devVolumes); - expectedVolumes.addAll(commonVolumes); - expectedVolumes.add(expectedHostPathOfProjects + ":/projects:Z"); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - devVolumes, - commonVolumes, - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - when(workspaceFolderPathProvider.getPath(anyString())).thenReturn(expectedHostPathOfProjects); - final boolean isDev = true; - - - createInstanceFromRecipe(isDev); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - verify(dockerConnector).startContainer(any(StartContainerParams.class)); - - final String[] actualBinds = argumentCaptor.getValue().getContainerConfig().getHostConfig().getBinds(); - assertEquals(actualBinds.length, expectedVolumes.size()); - assertEquals(new HashSet<>(asList(actualBinds)), new HashSet<>(expectedVolumes)); - } - - @Test - public void shouldBindCommonAndDevVolumesToContainerOnDevInstanceCreationFromSnapshot() throws Exception { - final String expectedHostPathOfProjects = "/tmp/projects"; - Set devVolumes = new HashSet<>(asList("/etc:/tmp/etc:ro", "/some/thing:/home/some/thing")); - Set commonVolumes = new HashSet<>(asList("/some/thing/else:/home/some/thing/else", "/other/path:/home/other/path")); - - final ArrayList expectedVolumes = new ArrayList<>(); - expectedVolumes.addAll(devVolumes); - expectedVolumes.addAll(commonVolumes); - expectedVolumes.add(expectedHostPathOfProjects + ":/projects:Z"); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - devVolumes, - commonVolumes, - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - when(workspaceFolderPathProvider.getPath(anyString())).thenReturn(expectedHostPathOfProjects); - - final boolean isDev = true; - - - createInstanceFromSnapshot(isDev); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - verify(dockerConnector).startContainer(any(StartContainerParams.class)); - - final String[] actualBinds = argumentCaptor.getValue().getContainerConfig().getHostConfig().getBinds(); - assertEquals(actualBinds.length, expectedVolumes.size()); - assertEquals(new HashSet<>(asList(actualBinds)), new HashSet<>(expectedVolumes)); - } - - @Test - public void shouldBindCommonVolumesOnlyToContainerOnNonDevInstanceCreationFromRecipe() throws Exception { - final String expectedHostPathOfProjects = "/tmp/projects"; - Set devVolumes = new HashSet<>(asList("/etc:/tmp/etc:ro", "/some/thing:/home/some/thing")); - Set commonVolumes = new HashSet<>(asList("/some/thing/else:/home/some/thing/else", "/other/path:/home/other/path")); - - final ArrayList expectedVolumes = new ArrayList<>(); - expectedVolumes.addAll(commonVolumes); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - devVolumes, - commonVolumes, - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - when(dockerNode.getProjectsFolder()).thenReturn(expectedHostPathOfProjects); - - final boolean isDev = false; - - - createInstanceFromRecipe(isDev); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - verify(dockerConnector).startContainer(any(StartContainerParams.class)); - - final String[] actualBinds = argumentCaptor.getValue().getContainerConfig().getHostConfig().getBinds(); - assertEquals(actualBinds.length, expectedVolumes.size()); - assertEquals(new HashSet<>(asList(actualBinds)), new HashSet<>(expectedVolumes)); - } - - @Test - public void shouldAddExtraHostOnDevInstanceCreationFromRecipe() throws Exception { - //given - final String expectedHostPathOfProjects = "/tmp/projects"; - Set devVolumes = new HashSet<>(asList("/etc:/tmp/etc:ro", "/some/thing:/home/some/thing")); - Set commonVolumes = new HashSet<>(asList("/some/thing/else:/home/some/thing/else", "/other/path:/home/other/path")); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - devVolumes, - commonVolumes, - "dev.box.com:192.168.0.1", - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - when(dockerNode.getProjectsFolder()).thenReturn(expectedHostPathOfProjects); - - final boolean isDev = true; - - //when - createInstanceFromRecipe(isDev); - - //then - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - verify(dockerConnector).startContainer(any(StartContainerParams.class)); - - final String[] extraHosts = argumentCaptor.getValue().getContainerConfig().getHostConfig().getExtraHosts(); - assertEquals(extraHosts.length, 2); - assertEquals(extraHosts[0], "dev.box.com:192.168.0.1"); - } - - @Test - public void shouldAddExtraHostOnDevInstanceCreationFromSnapshot() throws Exception { - //given - final String expectedHostPathOfProjects = "/tmp/projects"; - Set devVolumes = new HashSet<>(asList("/etc:/tmp/etc:ro", "/some/thing:/home/some/thing")); - Set commonVolumes = new HashSet<>(asList("/some/thing/else:/home/some/thing/else", "/other/path:/home/other/path")); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - devVolumes, - commonVolumes, - "dev.box.com:192.168.0.1,codenvy.com.com:185", - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - when(dockerNode.getProjectsFolder()).thenReturn(expectedHostPathOfProjects); - final boolean isDev = true; - - //when - createInstanceFromSnapshot(isDev); - //then - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - verify(dockerConnector).startContainer(any(StartContainerParams.class)); - - final String[] extraHosts = argumentCaptor.getValue().getContainerConfig().getHostConfig().getExtraHosts(); - assertEquals(extraHosts.length, 3); - assertEquals(extraHosts[0], "dev.box.com:192.168.0.1"); - assertEquals(extraHosts[1], "codenvy.com.com:185"); - } - - @Test - public void shouldAddExtraHostOnNonDevInstanceCreationFromRecipe() throws Exception { - //given - final String expectedHostPathOfProjects = "/tmp/projects"; - Set devVolumes = new HashSet<>(asList("/etc:/tmp/etc:ro", "/some/thing:/home/some/thing")); - Set commonVolumes = new HashSet<>(asList("/some/thing/else:/home/some/thing/else", "/other/path:/home/other/path")); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - devVolumes, - commonVolumes, - "dev.box.com:192.168.0.1", - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - when(dockerNode.getProjectsFolder()).thenReturn(expectedHostPathOfProjects); - - final boolean isDev = false; - - //when - createInstanceFromRecipe(isDev); - - //then - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - verify(dockerConnector).startContainer(any(StartContainerParams.class)); - - final String[] extraHosts = argumentCaptor.getValue().getContainerConfig().getHostConfig().getExtraHosts(); - assertEquals(extraHosts.length, 2); - assertEquals(extraHosts[0], "dev.box.com:192.168.0.1"); - } - - @Test - public void shouldAddExtraHostOnNonDevInstanceCreationFromSnapshot() throws Exception { - //given - final String expectedHostPathOfProjects = "/tmp/projects"; - Set devVolumes = new HashSet<>(asList("/etc:/tmp/etc:ro", "/some/thing:/home/some/thing")); - Set commonVolumes = new HashSet<>(asList("/some/thing/else:/home/some/thing/else", "/other/path:/home/other/path")); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - devVolumes, - commonVolumes, - "dev.box.com:192.168.0.1,codenvy.com.com:185", - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - when(dockerNode.getProjectsFolder()).thenReturn(expectedHostPathOfProjects); - final boolean isDev = false; - - //when - createInstanceFromSnapshot(isDev); - //then - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - verify(dockerConnector).startContainer(any(StartContainerParams.class)); - - final String[] extraHosts = argumentCaptor.getValue().getContainerConfig().getHostConfig().getExtraHosts(); - assertEquals(extraHosts.length, 3); - assertEquals(extraHosts[0], "dev.box.com:192.168.0.1"); - assertEquals(extraHosts[1], "codenvy.com.com:185"); - } - - @Test - public void shouldBindCommonVolumesOnlyToContainerOnNonDevInstanceCreationFromSnapshot() throws Exception { - final String expectedHostPathOfProjects = "/tmp/projects"; - Set devVolumes = new HashSet<>(asList("/etc:/tmp/etc:ro", "/some/thing:/home/some/thing")); - Set commonVolumes = new HashSet<>(asList("/some/thing/else:/home/some/thing/else", "/other/path:/home/other/path")); - - final ArrayList expectedVolumes = new ArrayList<>(); - expectedVolumes.addAll(commonVolumes); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - devVolumes, - commonVolumes, - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - when(dockerNode.getProjectsFolder()).thenReturn(expectedHostPathOfProjects); - - final boolean isDev = false; - - - createInstanceFromSnapshot(isDev); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - verify(dockerConnector).startContainer(any(StartContainerParams.class)); - - final String[] actualBinds = argumentCaptor.getValue().getContainerConfig().getHostConfig().getBinds(); - assertEquals(actualBinds.length, expectedVolumes.size()); - assertEquals(new HashSet<>(asList(actualBinds)), new HashSet<>(expectedVolumes)); - } - - @Test - public void shouldAddWorkspaceIdEnvVariableOnDevInstanceCreationFromRecipe() throws Exception { - String wsId = "myWs"; - createInstanceFromRecipe(true, wsId); - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - assertTrue(asList(argumentCaptor.getValue().getContainerConfig().getEnv()) - .contains(DockerInstanceRuntimeInfo.CHE_WORKSPACE_ID + "=" + wsId), - "Workspace Id variable is missing. Required " + DockerInstanceRuntimeInfo.CHE_WORKSPACE_ID + "=" + wsId + - ". Found " + Arrays.toString(argumentCaptor.getValue().getContainerConfig().getEnv())); - } - - @Test - public void shouldAddWorkspaceIdEnvVariableOnDevInstanceCreationFromSnapshot() throws Exception { - String wsId = "myWs"; - createInstanceFromSnapshot(true, wsId); - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - assertTrue(asList(argumentCaptor.getValue().getContainerConfig().getEnv()) - .contains(DockerInstanceRuntimeInfo.CHE_WORKSPACE_ID + "=" + wsId), - "Workspace Id variable is missing. Required " + DockerInstanceRuntimeInfo.CHE_WORKSPACE_ID + "=" + wsId + - ". Found " + Arrays.toString(argumentCaptor.getValue().getContainerConfig().getEnv())); - } - - @Test - public void shouldNotAddWorkspaceIdEnvVariableOnNonDevInstanceCreationFromRecipe() throws Exception { - String wsId = "myWs"; - createInstanceFromRecipe(false, wsId); - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - assertFalse(asList(argumentCaptor.getValue().getContainerConfig().getEnv()) - .contains(DockerInstanceRuntimeInfo.CHE_WORKSPACE_ID + "=" + wsId), - "Non dev machine should not contains " + DockerInstanceRuntimeInfo.CHE_WORKSPACE_ID); - } - - @Test - public void shouldNotAddWorkspaceIdEnvVariableOnNonDevInstanceCreationFromSnapshot() throws Exception { - String wsId = "myWs"; - createInstanceFromSnapshot(false, wsId); - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - assertFalse(asList(argumentCaptor.getValue().getContainerConfig().getEnv()) - .contains(DockerInstanceRuntimeInfo.CHE_WORKSPACE_ID + "=" + wsId), - "Non dev machine should not contains " + DockerInstanceRuntimeInfo.CHE_WORKSPACE_ID); - } - - /** - * E.g from https://github.com/boot2docker/boot2docker/blob/master/README.md#virtualbox-guest-additions - * - * Users should be /Users - * /Users should be /Users - * c/Users should be /c/Users - * /c/Users should be /c/Users - * c:/Users should be /c/Users - */ - @Test - public void shouldEscapePathForWindowsHost() { - assertEquals(dockerInstanceProvider.escapePath("Users"), "/Users"); - assertEquals(dockerInstanceProvider.escapePath("/Users"), "/Users"); - assertEquals(dockerInstanceProvider.escapePath("c/Users"), "/c/Users"); - assertEquals(dockerInstanceProvider.escapePath("/c/Users"), "/c/Users"); - assertEquals(dockerInstanceProvider.escapePath("c:/Users"), "/c/Users"); - assertEquals(dockerInstanceProvider.escapePath("C:/Users"), "/c/Users"); - - assertEquals(dockerInstanceProvider.escapePath("C:/Users/path/dir/from/host:/name/of/dir/in/container"), - "/c/Users/path/dir/from/host:/name/of/dir/in/container"); - } - - @Test - public void shouldAddCommonAndDevEnvVariablesToContainerOnDevInstanceCreationFromRecipe() throws Exception { - Set commonEnv = new HashSet<>(asList("ENV_VAR1=123", "ENV_VAR2=234")); - Set devEnv = new HashSet<>(asList("DEV_ENV_VAR1=345", "DEV_ENV_VAR2=456", "DEV_ENV_VAR3=567")); - Set expectedEnv = new HashSet<>(); - expectedEnv.addAll(commonEnv); - expectedEnv.addAll(devEnv); - expectedEnv.add(DockerInstanceRuntimeInfo.USER_TOKEN + "=" + USER_TOKEN); - expectedEnv.add(DockerInstanceRuntimeInfo.CHE_WORKSPACE_ID + "=" + WORKSPACE_ID); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - devEnv, - commonEnv, - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - final boolean isDev = true; - - - createInstanceFromRecipe(isDev); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - assertTrue(new HashSet<>(asList(argumentCaptor.getValue().getContainerConfig().getEnv())).containsAll(expectedEnv)); - } - - @Test - public void shouldNotAddDevEnvToCommonEnvVariablesToContainerOnNonDevInstanceCreationFromRecipe() throws Exception { - Set commonEnv = new HashSet<>(asList("ENV_VAR1=123", "ENV_VAR2=234")); - Set devEnv = new HashSet<>(asList("DEV_ENV_VAR1=345", "DEV_ENV_VAR2=456", "DEV_ENV_VAR3=567")); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - devEnv, - commonEnv, - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - final boolean isDev = false; - - - createInstanceFromRecipe(isDev); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - assertTrue(new HashSet<>(asList(argumentCaptor.getValue().getContainerConfig().getEnv())).containsAll(commonEnv)); - } - - @Test - public void shouldAddCommonAndDevEnvVariablesToContainerOnDevInstanceCreationFromSnapshot() throws Exception { - Set commonEnv = new HashSet<>(asList("ENV_VAR1=123", "ENV_VAR2=234")); - Set devEnv = new HashSet<>(asList("DEV_ENV_VAR1=345", "DEV_ENV_VAR2=456", "DEV_ENV_VAR3=567")); - Set expectedEnv = new HashSet<>(); - expectedEnv.addAll(commonEnv); - expectedEnv.addAll(devEnv); - expectedEnv.add(DockerInstanceRuntimeInfo.USER_TOKEN + "=" + USER_TOKEN); - expectedEnv.add(DockerInstanceRuntimeInfo.CHE_WORKSPACE_ID + "=" + WORKSPACE_ID); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - devEnv, - commonEnv, - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - final boolean isDev = true; - - - createInstanceFromSnapshot(isDev); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - assertTrue(new HashSet<>(asList(argumentCaptor.getValue().getContainerConfig().getEnv())).containsAll(expectedEnv)); - } - - @Test - public void shouldNotAddDevEnvToCommonEnvVariablesToContainerOnNonDevInstanceCreationFromSnapshot() throws Exception { - Set commonEnv = new HashSet<>(asList("ENV_VAR1=123", "ENV_VAR2=234")); - Set devEnv = new HashSet<>(asList("DEV_ENV_VAR1=345", "DEV_ENV_VAR2=456", "DEV_ENV_VAR3=567")); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - devEnv, - commonEnv, - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - final boolean isDev = false; - - - createInstanceFromSnapshot(isDev); - - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - assertTrue(new HashSet<>(asList(argumentCaptor.getValue().getContainerConfig().getEnv())).containsAll(commonEnv)); - } - - @Test - public void shouldAddEnvVarsFromMachineConfigToContainerOnNonDevInstanceCreationFromSnapshot() throws Exception { - // given - Map envVarsFromConfig = new HashMap<>(); - envVarsFromConfig.put("ENV_VAR1", "123"); - envVarsFromConfig.put("ENV_VAR2", "234"); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - final boolean isDev = false; - - // when - createInstanceFromSnapshot(getMachineBuilder().setConfig(getMachineConfigBuilder().setDev(isDev) - .setEnvVariables(envVarsFromConfig) - .build()) - .build()); - - // then - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - assertTrue(asList(argumentCaptor.getValue() - .getContainerConfig() - .getEnv()) - .containsAll(envVarsFromConfig.entrySet() - .stream() - .map(entry -> entry.getKey() + - "=" + - entry.getValue()) - .collect(Collectors.toList()))); - } - - @Test - public void shouldAddEnvVarsFromMachineConfigToContainerOnDevInstanceCreationFromSnapshot() throws Exception { - // given - Map envVarsFromConfig = new HashMap<>(); - envVarsFromConfig.put("ENV_VAR1", "123"); - envVarsFromConfig.put("ENV_VAR2", "234"); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - final boolean isDev = true; - - // when - createInstanceFromSnapshot(getMachineBuilder().setConfig(getMachineConfigBuilder().setDev(isDev) - .setEnvVariables(envVarsFromConfig) - .build()) - .build()); - - // then - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - assertTrue(asList(argumentCaptor.getValue() - .getContainerConfig() - .getEnv()) - .containsAll(envVarsFromConfig.entrySet() - .stream() - .map(entry -> entry.getKey() + - "=" + - entry.getValue()) - .collect(Collectors.toList()))); - } - - @Test - public void shouldAddEnvVarsFromMachineConfigToContainerOnNonDevInstanceCreationFromRecipe() throws Exception { - // given - Map envVarsFromConfig = new HashMap<>(); - envVarsFromConfig.put("ENV_VAR1", "123"); - envVarsFromConfig.put("ENV_VAR2", "234"); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - final boolean isDev = false; - - // when - createInstanceFromRecipe(getMachineBuilder().setConfig(getMachineConfigBuilder().setDev(isDev) - .setEnvVariables(envVarsFromConfig) - .build()) - .build()); - - // then - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - assertTrue(asList(argumentCaptor.getValue() - .getContainerConfig() - .getEnv()) - .containsAll(envVarsFromConfig.entrySet() - .stream() - .map(entry -> entry.getKey() + - "=" + - entry.getValue()) - .collect(Collectors.toList()))); - } - - @Test - public void shouldAddEnvVarsFromMachineConfigToContainerOnDevInstanceCreationFromRecipe() throws Exception { - // given - Map envVarsFromConfig = new HashMap<>(); - envVarsFromConfig.put("ENV_VAR1", "123"); - envVarsFromConfig.put("ENV_VAR2", "234"); - - dockerInstanceProvider = new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - SNAPSHOT_USE_REGISTRY, - MEMORY_SWAP_MULTIPLIER); - - final boolean isDev = true; - - // when - createInstanceFromRecipe(getMachineBuilder().setConfig(getMachineConfigBuilder().setDev(isDev) - .setEnvVariables(envVarsFromConfig) - .build()) - .build()); - - // then - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateContainerParams.class); - verify(dockerConnector).createContainer(argumentCaptor.capture()); - assertTrue(asList(argumentCaptor.getValue() - .getContainerConfig() - .getEnv()) - .containsAll(envVarsFromConfig.entrySet() - .stream() - .map(entry -> entry.getKey() + - "=" + - entry.getValue()) - .collect(Collectors.toList()))); - } - - private void createInstanceFromRecipe() throws Exception { - createInstanceFromRecipe(getMachineBuilder().build()); - } - - private void createInstanceFromRecipe(boolean isDev) throws Exception { - createInstanceFromRecipe(getMachineBuilder().setConfig(getMachineConfigBuilder().setDev(isDev) - .build()) - .build()); - } - - private void createInstanceFromRecipe(boolean isDev, String workspaceId) throws Exception { - createInstanceFromRecipe(getMachineBuilder().setConfig(getMachineConfigBuilder().setDev(isDev) - .build()) - .setWorkspaceId(workspaceId) - .build()); - } - - private void createInstanceFromRecipe(int memorySizeInMB) throws Exception { - createInstanceFromRecipe(getMachineBuilder().setConfig(getMachineConfigBuilder().setLimits(new MachineLimitsImpl(memorySizeInMB)) - .build()) - .build()); - } - - private void createInstanceFromSnapshot(String repo, String tag, String registry) throws NotFoundException, MachineException { - createInstanceFromSnapshot(getMachineBuilder().build(), new DockerMachineSource(repo).withTag(tag).withRegistry(registry).withDigest("digest")); - } - - private void createInstanceFromRecipe(Machine machine) throws Exception { - dockerInstanceProvider.createInstance(machine, - LineConsumer.DEV_NULL); - } - - private void createInstanceFromSnapshot() throws NotFoundException, MachineException { - createInstanceFromSnapshot(getMachineBuilder().build()); - } - - private void createInstanceFromSnapshot(int memorySizeInMB) throws NotFoundException, MachineException { - createInstanceFromSnapshot(getMachineBuilder().setConfig(getMachineConfigBuilder().setLimits(new MachineLimitsImpl(memorySizeInMB)) - .build()) - .build()); - } - - private void createInstanceFromSnapshot(boolean isDev) throws NotFoundException, MachineException { - createInstanceFromSnapshot(getMachineBuilder().setConfig(getMachineConfigBuilder().setDev(isDev) - .build()) - .build()); - } - - private void createInstanceFromSnapshot(boolean isDev, String workspaceId) throws NotFoundException, MachineException { - createInstanceFromSnapshot(getMachineBuilder().setConfig(getMachineConfigBuilder().setDev(isDev) - .build()) - .setWorkspaceId(workspaceId) - .build()); - } - - private void createInstanceFromSnapshot(MachineImpl machine) throws NotFoundException, MachineException { - DockerMachineSource machineSource = new DockerMachineSource("repo").withRegistry("registry").withDigest("digest"); - machine.getConfig().setSource(machineSource); - dockerInstanceProvider.createInstance(machine, - LineConsumer.DEV_NULL); - } - - private void createInstanceFromSnapshot(MachineImpl machine, DockerMachineSource dockerMachineSource) throws NotFoundException, - MachineException { - - machine.getConfig().setSource(dockerMachineSource); - dockerInstanceProvider.createInstance(machine, - LineConsumer.DEV_NULL); - } - - private MachineImpl.MachineImplBuilder getMachineBuilder() { - return MachineImpl.builder().fromMachine(new MachineImpl(getMachineConfigBuilder().build(), - MACHINE_ID, - WORKSPACE_ID, - "envName", - "userId", - MachineStatus.CREATING, - null)); - } - - private DockerInstanceProvider getDockerInstanceProvider(boolean snapshotUseRegistry) throws Exception { - return spy(new DockerInstanceProvider(dockerConnector, - dockerConnectorConfiguration, - credentialsReader, - dockerMachineFactory, - dockerInstanceStopDetector, - containerNameGenerator, - recipeRetriever, - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - null, - workspaceFolderPathProvider, - PROJECT_FOLDER_PATH, - false, - false, - Collections.emptySet(), - Collections.emptySet(), - snapshotUseRegistry, - MEMORY_SWAP_MULTIPLIER)); - } - - private MachineConfigImpl.MachineConfigImplBuilder getMachineConfigBuilder() { - return MachineConfigImpl.builder().fromConfig(new MachineConfigImpl(false, - MACHINE_NAME, - "machineType", - new MachineSourceImpl(DOCKER_FILE_TYPE).setContent("FROM codenvy"), - new MachineLimitsImpl(MEMORY_LIMIT_MB), - asList(new ServerConfImpl("ref1", - "8080", - "https", - null), - new ServerConfImpl("ref2", - "9090/udp", - "someprotocol", - null)), - Collections.singletonMap("key1", "value1"))); - } -} diff --git a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/compose/ComposeServiceDto.java b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/compose/ComposeServiceDto.java index 75e9e73f02..b3615b7e4c 100644 --- a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/compose/ComposeServiceDto.java +++ b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/compose/ComposeServiceDto.java @@ -79,4 +79,8 @@ public interface ComposeServiceDto extends ComposeService { void setMemLimit(Long memLimit); ComposeServiceDto withMemLimit(Long memLimit); + + void setNetworks(List networks); + + ComposeServiceDto withNetworks(List networks); } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/CheEnvironmentValidator.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/CheEnvironmentValidator.java index 154df26b5e..47252e817f 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/CheEnvironmentValidator.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/CheEnvironmentValidator.java @@ -238,6 +238,10 @@ public class CheEnvironmentValidator { checkArgument(service.getVolumes() == null || service.getVolumes().isEmpty(), "Volumes binding is forbidden but found in machine '%s' of environment '%s'", machineName, envName); + + checkArgument(service.getNetworks() == null || service.getNetworks().isEmpty(), + "Networks configuration is forbidden but found in machine '%s' of environment '%s'", + machineName, envName); } private void validateExtendedMachine(ExtendedMachine extendedMachine, String envName, String machineName) { diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/compose/model/ComposeServiceImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/compose/model/ComposeServiceImpl.java index 11be79e7ce..e386a132a7 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/compose/model/ComposeServiceImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/compose/model/ComposeServiceImpl.java @@ -42,6 +42,7 @@ public class ComposeServiceImpl implements ComposeService { @JsonProperty("mem_limit") private Long memLimit; private BuildContextImpl build; + private List networks; public ComposeServiceImpl() {} @@ -82,6 +83,9 @@ public class ComposeServiceImpl implements ComposeService { volumes = new ArrayList<>(service.getVolumes()); } memLimit = service.getMemLimit(); + if (service.getNetworks() != null) { + networks = new ArrayList<>(service.getNetworks()); + } } @Override @@ -311,13 +315,29 @@ public class ComposeServiceImpl implements ComposeService { return this; } + @Override + public List getNetworks() { + if (networks == null) { + networks = new ArrayList<>(); + } + return networks; + } + + public void setNetworks(List networks) { + this.networks = networks; + } + + public ComposeServiceImpl withNetworks(List networks) { + this.networks = networks; + return this; + } + @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof ComposeServiceImpl)) return false; ComposeServiceImpl service = (ComposeServiceImpl)o; return Objects.equals(containerName, service.containerName) && - Objects.equals(build, service.build) && Objects.equals(command, service.command) && Objects.equals(entrypoint, service.entrypoint) && Objects.equals(image, service.image) && @@ -329,7 +349,9 @@ public class ComposeServiceImpl implements ComposeService { Objects.equals(links, service.links) && Objects.equals(volumes, service.volumes) && Objects.equals(volumesFrom, service.volumesFrom) && - Objects.equals(memLimit, service.memLimit); + Objects.equals(memLimit, service.memLimit) && + Objects.equals(build, service.build) && + Objects.equals(networks, service.networks); } @Override @@ -347,14 +369,14 @@ public class ComposeServiceImpl implements ComposeService { links, volumes, volumesFrom, - memLimit); + memLimit, + networks); } @Override public String toString() { return "ComposeServiceImpl{" + "containerName='" + containerName + '\'' + - ", build='" + build + '\'' + ", command=" + command + ", entrypoint=" + entrypoint + ", image='" + image + '\'' + @@ -367,6 +389,8 @@ public class ComposeServiceImpl implements ComposeService { ", volumes=" + volumes + ", volumesFrom=" + volumesFrom + ", memLimit=" + memLimit + + ", build=" + build + + ", networks=" + networks + '}'; } } diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/environment/server/CheEnvironmentValidatorTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/environment/server/CheEnvironmentValidatorTest.java index 3a5fd47c5f..0a4fc432cb 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/environment/server/CheEnvironmentValidatorTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/environment/server/CheEnvironmentValidatorTest.java @@ -307,6 +307,25 @@ public class CheEnvironmentValidatorTest { service.setBuild(new BuildContextImpl()); data.add(asList(env, format("Field 'image' or 'build.context' is required in machine '%s' in environment 'env'", serviceEntry.getKey()))); + env = createComposeEnv(); + serviceEntry = getAnyService(env); + service = serviceEntry.getValue(); + service.setPorts(new ArrayList<>(singletonList("8080:8080"))); + data.add(asList(env, format("Ports binding is forbidden but found in machine '%s' of environment 'env'", serviceEntry.getKey()))); + + env = createComposeEnv(); + serviceEntry = getAnyService(env); + service = serviceEntry.getValue(); + service.setVolumes(new ArrayList<>(singletonList("volume"))); + data.add(asList(env, format("Volumes binding is forbidden but found in machine '%s' of environment 'env'", serviceEntry.getKey()))); + + env = createComposeEnv(); + serviceEntry = getAnyService(env); + service = serviceEntry.getValue(); + service.setNetworks(new ArrayList<>(singletonList("network1"))); + data.add(asList(env, format("Networks configuration is forbidden but found in machine '%s' of environment 'env'", serviceEntry.getKey()))); + + // TODO uncomment when internal representation of env will be separated from compose representation // env = createComposeEnv(); // serviceEntry = getAnyService(env); // service = serviceEntry.getValue();