CHE-2331: add all containers to Che master docker network (#2392)
Signed-off-by: Alexander Garagatyi <agaragatyi@codenvy.com>6.19.x
parent
c64592af9b
commit
b2309ef345
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<String> getNetworks();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Set<String>> {
|
||||
|
||||
private Set<String> 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<String> get() {
|
||||
return networks;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String> additionalNetworks;
|
||||
|
||||
@Inject
|
||||
public ComposeMachineProviderImpl(DockerConnector docker,
|
||||
|
|
@ -143,7 +146,8 @@ public class ComposeMachineProviderImpl implements ComposeMachineInstanceProvide
|
|||
@Named("machine.docker.dev_machine.machine_env") Set<String> devMachineEnvVariables,
|
||||
@Named("machine.docker.machine_env") Set<String> 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<Set<String>> 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,
|
||||
|
|
|
|||
|
|
@ -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<String> supportedRecipeTypes;
|
||||
private final DockerMachineFactory dockerMachineFactory;
|
||||
private final Map<String, Map<String, String>> devMachinePortsToExpose;
|
||||
private final Map<String, Map<String, String>> commonMachinePortsToExpose;
|
||||
private final String[] devMachineSystemVolumes;
|
||||
private final String[] commonMachineSystemVolumes;
|
||||
private final Set<String> devMachineEnvVariables;
|
||||
private final Set<String> 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<ServerConf> devMachineServers,
|
||||
@Named("machine.docker.machine_servers") Set<ServerConf> allMachinesServers,
|
||||
@Named("machine.docker.dev_machine.machine_volumes") Set<String> devMachineSystemVolumes,
|
||||
@Named("machine.docker.machine_volumes") Set<String> 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<String> devMachineEnvVariables,
|
||||
@Named("machine.docker.machine_env") Set<String> 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<String> 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<String> 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<String> 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<String> escapePaths(Set<String> 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<String> 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<String, Map<String, String>> portsToExpose;
|
||||
final String[] volumes;
|
||||
final List<String> 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<String> removeEmptyAndNullValues(Set<String> paths) {
|
||||
return paths.stream()
|
||||
.filter(path -> !Strings.isNullOrEmpty(path))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<String> 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<Set<String>> networks = Multibinder.newSetBinder(binder(),
|
||||
new TypeLiteral<Set<String>>() {},
|
||||
Names.named("machine.docker.networks"))
|
||||
.permitDuplicates();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Set<String>> networks = Multibinder.newSetBinder(binder(),
|
||||
new TypeLiteral<Set<String>>() {},
|
||||
Names.named("machine.docker.networks"));
|
||||
networks.addBinding().toProvider(org.eclipse.che.plugin.docker.machine.CheInContainerNetworkProvider.class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -79,4 +79,8 @@ public interface ComposeServiceDto extends ComposeService {
|
|||
void setMemLimit(Long memLimit);
|
||||
|
||||
ComposeServiceDto withMemLimit(Long memLimit);
|
||||
|
||||
void setNetworks(List<String> networks);
|
||||
|
||||
ComposeServiceDto withNetworks(List<String> networks);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ public class ComposeServiceImpl implements ComposeService {
|
|||
@JsonProperty("mem_limit")
|
||||
private Long memLimit;
|
||||
private BuildContextImpl build;
|
||||
private List<String> 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<String> getNetworks() {
|
||||
if (networks == null) {
|
||||
networks = new ArrayList<>();
|
||||
}
|
||||
return networks;
|
||||
}
|
||||
|
||||
public void setNetworks(List<String> networks) {
|
||||
this.networks = networks;
|
||||
}
|
||||
|
||||
public ComposeServiceImpl withNetworks(List<String> 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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in New Issue