package org.arquillian.cube.docker.impl.docker.compose;
import static org.arquillian.cube.docker.impl.util.YamlUtil.asBoolean;
import static org.arquillian.cube.docker.impl.util.YamlUtil.asInt;
import static org.arquillian.cube.docker.impl.util.YamlUtil.asListOfString;
import static org.arquillian.cube.docker.impl.util.YamlUtil.asLong;
import static org.arquillian.cube.docker.impl.util.YamlUtil.asMap;
import static org.arquillian.cube.docker.impl.util.YamlUtil.asMapOfStrings;
import static org.arquillian.cube.docker.impl.util.YamlUtil.asString;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.arquillian.cube.docker.impl.client.config.BuildImage;
import org.arquillian.cube.docker.impl.client.config.CubeContainer;
import org.arquillian.cube.docker.impl.client.config.Device;
import org.arquillian.cube.docker.impl.client.config.ExposedPort;
import org.arquillian.cube.docker.impl.client.config.Image;
import org.arquillian.cube.docker.impl.client.config.Link;
import org.arquillian.cube.docker.impl.client.config.PortBinding;
import org.arquillian.cube.docker.impl.client.config.RestartPolicy;
import org.yaml.snakeyaml.Yaml;
public class ContainerBuilder {
private static final String IMAGE = "image";
private static final String BUILD = "build";
private static final String COMMAND = "command";
private static final String LINKS = "links";
private static final String EXTERNAL_LINKS = "external_links";
private static final String LABELS = "labels";
private static final String LOG_DRIVER = "log_driver";
private static final String SECURITY_OPT = "security_opt";
private static final String DOCKERFILE= "dockerfile";
private static final String READ_ONLY = "read_only";
private static final String EXTENDS = "extends";
private static final String PORTS = "ports";
private static final String EXPOSE = "expose";
private static final String VOLUMES = "volumes";
private static final String VOLUMES_FROM = "volumes_from";
private static final String ENVIRONMENT = "environment";
private static final String ENV_FILE = "env_file";
private static final String NET = "net";
private static final String DNS = "dns";
private static final String CAP_ADD = "cap_add";
private static final String CAP_DROP = "cap_drop";
private static final String DNS_SEARCH = "dns_search";
private static final String WORKING_DIR = "working_dir";
private static final String ENTRYPOINT = "entrypoint";
private static final String PID = "pid";
private static final String USER = "user";
private static final String HOSTNAME = "hostname";
private static final String DOMAINNAME = "domainname";
private static final String MEM_LIMIT = "mem_limit";
private static final String MEM_SWAP_LIMIT = "memswap_limit";
private static final String SHM_SIZE = "shm_size";
private static final String PRIVILEGED = "privileged";
private static final String RESTART = "restart";
private static final String STDIN_OPEN = "stdin_open";
private static final String TTY = "tty";
private static final String CPU_SHARES = "cpu_shares";
private static final String CPU_SET = "cpuset";
private static final String CPU_QUOTA = "cpu_quota";
private static final String EXTRA_HOSTS = "extra_hosts";
private static final String DEVICES = "devices";
private static final String CONTAINERNAME = "container_name";
private static final String DEPENDS_ON = "depends_on";
private static final String CONTEXT = "context";
private static final String NETWORKS = "networks";
private static List<String> AVAILABLE_COMMANDS = Arrays.asList(IMAGE, BUILD, COMMAND, LINKS, EXTERNAL_LINKS, DOCKERFILE,
EXTENDS, PORTS, EXPOSE, VOLUMES, VOLUMES_FROM, ENVIRONMENT, ENV_FILE, NET, DNS, CAP_ADD, CAP_DROP,
DNS_SEARCH, WORKING_DIR, ENTRYPOINT, USER, HOSTNAME, MEM_LIMIT, PRIVILEGED, RESTART, STDIN_OPEN, TTY,
CPU_SET, CPU_SHARES, CPU_QUOTA, EXTRA_HOSTS, DEVICES, CONTAINERNAME, DEPENDS_ON, MEM_SWAP_LIMIT, SHM_SIZE, NETWORKS);
private static final Logger log = Logger.getLogger(ContainerBuilder.class.getName());
private Random random = new Random();
private CubeContainer configuration;
private Path dockerComposeRootLocation;
GitOperations gitOperations;
public ContainerBuilder(Path dockerComposeRootLocation) {
this(dockerComposeRootLocation, new CubeContainer());
}
protected ContainerBuilder(Path dockerComposeRootLocation, CubeContainer configuration) {
this.dockerComposeRootLocation = dockerComposeRootLocation;
this.configuration = configuration;
}
public CubeContainer build(Map<String, Object> dockerComposeContainerDefinition) {
return build(dockerComposeContainerDefinition, null);
}
@SuppressWarnings("unchecked")
public CubeContainer build(Map<String, Object> dockerComposeContainerDefinition, String version) {
if(dockerComposeContainerDefinition.containsKey(EXTENDS)) {
Map<String, Object> extendsDefinition = asMap(dockerComposeContainerDefinition, EXTENDS);
this.extend(Paths.get(asString(extendsDefinition, "file")), asString(extendsDefinition, "service"));
}
if (dockerComposeContainerDefinition.containsKey(IMAGE)) {
this.addImage(asString(dockerComposeContainerDefinition, IMAGE));
}
if (dockerComposeContainerDefinition.containsKey(BUILD)) {
if (DockerComposeConverter.DOCKER_COMPOSE_VERSION_2_VALUE.equals(version)) {
Object o = dockerComposeContainerDefinition.get(BUILD);
if (o instanceof String) {
String dockerfile = dockerComposeContainerDefinition.containsKey(DOCKERFILE) ? asString(dockerComposeContainerDefinition, DOCKERFILE) : null;
this.addBuild(asString(dockerComposeContainerDefinition, BUILD), dockerfile);
} else if (o instanceof Map) {
Map<String, Object> buildDefinition = asMap(dockerComposeContainerDefinition, BUILD);
String context = buildDefinition.containsKey(CONTEXT) ? asString(buildDefinition, CONTEXT) : null;
final String dockerfile = buildDefinition.containsKey(DOCKERFILE) ? asString(buildDefinition, DOCKERFILE) : null;
if (context != null) {
File directory = new File(context);
if (directory.isDirectory()) {
this.addBuild(asString(buildDefinition, CONTEXT),
dockerfile);
} else {
// Make GitOperations lazy because it will help for testing purposes and to avoid instantiate JGit classes when Git is not required-
// In this way, if you don't need Git, you don't need to add jgit dependency
if (gitOperations == null) {
log.log(Level.INFO, String.format("Starting cloning git repository %s defined in docker-compose", context));
GitOperations gitOperations = new GitOperations();
File clonedDirectory = gitOperations.cloneRepo(context);
log.log(Level.INFO, String.format("Finished cloning git repository %s defined in docker-compose", context));
this.addBuild(clonedDirectory.getParentFile().getAbsolutePath(), dockerfile);
}
}
} else {
log.log(Level.WARNING, "build configuration is provided as object but no context definition is found.");
}
}
} else {
String dockerfile = dockerComposeContainerDefinition.containsKey(DOCKERFILE) ? asString(dockerComposeContainerDefinition, DOCKERFILE) : null;
this.addBuild(asString(dockerComposeContainerDefinition, BUILD), dockerfile);
}
}
if (dockerComposeContainerDefinition.containsKey(COMMAND)) {
if (dockerComposeContainerDefinition.get(COMMAND) instanceof List) {
this.addCommands(asListOfString(dockerComposeContainerDefinition, COMMAND));
} else {
this.addCommand(asString(dockerComposeContainerDefinition, COMMAND));
}
}
if (dockerComposeContainerDefinition.containsKey(DEPENDS_ON)) {
this.addDependsOn(asListOfString(dockerComposeContainerDefinition, DEPENDS_ON));
}
if (dockerComposeContainerDefinition.containsKey(LINKS)) {
this.addLinks(asListOfString(dockerComposeContainerDefinition, LINKS));
}
if (dockerComposeContainerDefinition.containsKey(EXTERNAL_LINKS)) {
this.addLinks(asListOfString(dockerComposeContainerDefinition, EXTERNAL_LINKS));
}
if (dockerComposeContainerDefinition.containsKey(PORTS)) {
this.addPorts(asListOfString(dockerComposeContainerDefinition, PORTS));
}
if (dockerComposeContainerDefinition.containsKey(EXPOSE)) {
this.addExpose(asListOfString(dockerComposeContainerDefinition, EXPOSE));
}
if (dockerComposeContainerDefinition.containsKey(VOLUMES)) {
this.addVolumes(asListOfString(dockerComposeContainerDefinition, VOLUMES));
this.addBinds(asListOfString(dockerComposeContainerDefinition, VOLUMES));
}
if(dockerComposeContainerDefinition.containsKey(LABELS)) {
this.addLabels(asMapOfStrings(dockerComposeContainerDefinition, LABELS));
}
if (dockerComposeContainerDefinition.containsKey(VOLUMES_FROM)) {
this.addVolumesFrom(asListOfString(dockerComposeContainerDefinition, VOLUMES_FROM));
}
if (dockerComposeContainerDefinition.containsKey(ENVIRONMENT)) {
this.addEnvironment(asListOfString(dockerComposeContainerDefinition, ENVIRONMENT));
}
if (dockerComposeContainerDefinition.containsKey(ENV_FILE)) {
if(dockerComposeContainerDefinition.get(ENV_FILE) instanceof List) {
this.addEnvFile(asListOfString(dockerComposeContainerDefinition, ENV_FILE));
} else {
this.addEnvFile(Arrays.asList(asString(dockerComposeContainerDefinition, ENV_FILE)));
}
}
if (dockerComposeContainerDefinition.containsKey(NET)) {
this.addNet(asString(dockerComposeContainerDefinition, NET));
}
if (dockerComposeContainerDefinition.containsKey(EXTRA_HOSTS)) {
this.addExtraHosts(asListOfString(dockerComposeContainerDefinition, EXTRA_HOSTS));
}
if (dockerComposeContainerDefinition.containsKey(DNS)) {
Object dns = dockerComposeContainerDefinition.get(DNS);
if (dns instanceof List) {
this.addDns((List<String>) dns);
} else {
this.addDns((String) dns);
}
}
if (dockerComposeContainerDefinition.containsKey(CAP_ADD)) {
this.addCapAdd(asListOfString(dockerComposeContainerDefinition, CAP_ADD));
}
if (dockerComposeContainerDefinition.containsKey(CAP_DROP)) {
this.addCapDrop(asListOfString(dockerComposeContainerDefinition, CAP_DROP));
}
if (dockerComposeContainerDefinition.containsKey(DNS_SEARCH)) {
Object dns = dockerComposeContainerDefinition.get(DNS_SEARCH);
if (dns instanceof List) {
this.addDnsSearch((List<String>) dns);
} else {
this.addDnsSearch((String) dns);
}
}
if (dockerComposeContainerDefinition.containsKey(WORKING_DIR)) {
this.addWorkingDir(asString(dockerComposeContainerDefinition, WORKING_DIR));
}
if (dockerComposeContainerDefinition.containsKey(ENTRYPOINT)) {
this.addEntrypoint(asString(dockerComposeContainerDefinition, ENTRYPOINT));
}
if (dockerComposeContainerDefinition.containsKey(USER)) {
this.addUser(asString(dockerComposeContainerDefinition, USER));
}
if (dockerComposeContainerDefinition.containsKey(HOSTNAME)) {
this.addHostname(asString(dockerComposeContainerDefinition, HOSTNAME));
}
if (dockerComposeContainerDefinition.containsKey(MEM_LIMIT)) {
this.addMemLimit(asLong(dockerComposeContainerDefinition, MEM_LIMIT));
}
if (dockerComposeContainerDefinition.containsKey(MEM_SWAP_LIMIT)) {
this.addMemSwapLimit(asLong(dockerComposeContainerDefinition, MEM_SWAP_LIMIT));
}
if (dockerComposeContainerDefinition.containsKey(SHM_SIZE)) {
this.addShmSize(asLong(dockerComposeContainerDefinition, SHM_SIZE));
}
if (dockerComposeContainerDefinition.containsKey(PRIVILEGED)) {
this.addPrivileged(asBoolean(dockerComposeContainerDefinition, PRIVILEGED));
}
if (dockerComposeContainerDefinition.containsKey(RESTART)) {
this.addRestart(asString(dockerComposeContainerDefinition, RESTART));
}
if (dockerComposeContainerDefinition.containsKey(STDIN_OPEN)) {
this.addStdinOpen(asBoolean(dockerComposeContainerDefinition, STDIN_OPEN));
}
if (dockerComposeContainerDefinition.containsKey(TTY)) {
this.addTty(asBoolean(dockerComposeContainerDefinition, TTY));
}
if (dockerComposeContainerDefinition.containsKey(CPU_SHARES)) {
this.addCpuShares(asInt(dockerComposeContainerDefinition, CPU_SHARES));
}
if (dockerComposeContainerDefinition.containsKey(CPU_SET)) {
this.addCpuSet(asString(dockerComposeContainerDefinition, CPU_SET));
}
if (dockerComposeContainerDefinition.containsKey(CPU_QUOTA)) {
this.addCpuQuota(asInt(dockerComposeContainerDefinition, CPU_QUOTA));
}
if (dockerComposeContainerDefinition.containsKey(DEVICES)) {
this.addDevices(asListOfString(dockerComposeContainerDefinition, DEVICES));
}
if (dockerComposeContainerDefinition.containsKey(DOMAINNAME)) {
this.addDomainName(asString(dockerComposeContainerDefinition, DOMAINNAME));
}
if (dockerComposeContainerDefinition.containsKey(READ_ONLY)) {
this.addReadOnly(asBoolean(dockerComposeContainerDefinition, READ_ONLY));
}
if (dockerComposeContainerDefinition.containsKey(CONTAINERNAME)) {
this.addContainerName(asString(dockerComposeContainerDefinition, CONTAINERNAME));
}
if (dockerComposeContainerDefinition.containsKey(NETWORKS)) {
if (dockerComposeContainerDefinition.get(NETWORKS) instanceof ArrayList) {
this.addNetworks(asListOfString(dockerComposeContainerDefinition, NETWORKS));
} else {
Map<String, Object> networks = asMap(dockerComposeContainerDefinition, NETWORKS);
this.addNetworks(networks.keySet());
}
}
this.logUnsupportedOperations(dockerComposeContainerDefinition.keySet());
return this.build();
}
private ContainerBuilder addNetworks(Collection<String> networks) {
if (configuration.getNetworks() != null) {
configuration.getNetworks().addAll(networks);
} else {
configuration.setNetworks(new HashSet<>(networks));
}
return this;
}
private ContainerBuilder addShmSize(long shmSize) {
configuration.setShmSize(shmSize);
return this;
}
private ContainerBuilder addMemSwapLimit(long memSwapLimit) {
configuration.setMemorySwap(memSwapLimit);
return this;
}
private ContainerBuilder addDevices(Collection<String> devices) {
Collection<Device> devicesDefinition = new HashSet<Device>();
for (String device : devices) {
String[] deviceSplitted = device.split(":");
Device def = new Device();
switch(deviceSplitted.length) {
case 3: {
///dev/ttyUSB0:/dev/ttyUSB0:rw
def.setcGroupPermissions(deviceSplitted[2]);
}
case 2: {
///dev/ttyUSB0:/dev/ttyUSB0
def.setPathOnHost(deviceSplitted[0]);
def.setPathInContainer(deviceSplitted[1]);
break;
}
default: {
throw new IllegalArgumentException(String.format("Device definition %s is incorrect. It should follow the format <hostPath>:<containerPath>:(optional)<permissions>", device));
}
}
devicesDefinition.add(def);
}
configuration.setDevices(devicesDefinition);
return this;
}
public ContainerBuilder addExtraHosts(Collection<String> extraHosts) {
if (configuration.getExtraHosts() != null) {
Collection<String> oldExtraHosts = configuration.getExtraHosts();
oldExtraHosts.addAll(extraHosts);
} else {
configuration.setExtraHosts(new HashSet<String>(extraHosts));
}
return this;
}
public ContainerBuilder addImage(String image) {
configuration.setImage(Image.valueOf(image));
return this;
}
public ContainerBuilder addContainerName(String name) {
configuration.setContainerName(name);
return this;
}
public ContainerBuilder addReadOnly(boolean b) {
configuration.setReadonlyRootfs(b);
return this;
}
public ContainerBuilder addBuild(String buildPath, String dockerfile) {
//. directory is the root of the project, but docker-compose . means relative to docker-compose file, so we resolve the full path
//and to no add full path we relativize to docker-compose
Path buildPathPath = Paths.get(buildPath);
Path calculatedPath;
if (buildPathPath.isAbsolute()) {
calculatedPath = buildPathPath;
} else {
Path fullDirectory = this.dockerComposeRootLocation.resolve(buildPath);
calculatedPath = this.dockerComposeRootLocation.relativize(fullDirectory);
}
BuildImage buildImage = new BuildImage(calculatedPath.toString(), dockerfile, true, true);
configuration.setBuildImage(buildImage);
return this;
}
public ContainerBuilder addCommand(String command) {
addCommands(Arrays.asList(command.split("\\ ")));
return this;
}
public ContainerBuilder addCommands(Collection<String> commands) {
configuration.setCmd(commands);
return this;
}
public ContainerBuilder addDependsOn(Collection<String> dependsOn) {
Collection<String> listOfDependsOn = new HashSet<>();
for (String link : dependsOn) {
listOfDependsOn.add(link);
}
if (configuration.getDependsOn() != null) {
Collection<String> oldDependsOn = configuration.getDependsOn();
oldDependsOn.addAll(listOfDependsOn);
} else {
configuration.setDependsOn(listOfDependsOn);
}
return this;
}
public ContainerBuilder addLinks(Collection<String> links) {
Collection<Link> listOfLinks = new HashSet<Link>();
for (String link : links) {
listOfLinks.add(Link.valueOf(link));
}
if (configuration.getLinks() != null) {
Collection<Link> oldLinks = configuration.getLinks();
oldLinks.addAll(listOfLinks);
} else {
configuration.setLinks(listOfLinks);
}
return this;
}
public ContainerBuilder addPorts(Collection<String> ports) {
Collection<PortBinding> listOfPorts = new HashSet<>();
for (String port : ports) {
String[] elements = port.split(":");
switch (elements.length) {
case 1: {
//random host port
if (port.contains("-")) {
getExpandedPorts(port).stream()
.forEach(expandedPort -> listOfPorts.add(PortBinding.valueOf(getRandomPort() + "->" + expandedPort)));
} else {
listOfPorts.add(PortBinding.valueOf(getRandomPort() + "->" + elements[0]));
}
break;
}
case 2: {
//hostport:containerport
if (port.contains("-")) {
listOfPorts.addAll(addPairPortRange(elements[0], elements[1], null));
} else {
listOfPorts.add(PortBinding.valueOf(port.replaceAll(":", "->")));
}
break;
}
case 3: {
//host:hostport:containerport
if (port.contains("-")) {
listOfPorts.addAll(addPairPortRange(elements[1], elements[2], elements[0]));
} else {
listOfPorts.add(PortBinding.valueOf(elements[0] + ":" + elements[1] + "->" + elements[2]));
}
break;
}
}
}
if (configuration.getPortBindings() != null) {
Collection<PortBinding> oldPortBindings = configuration.getPortBindings();
oldPortBindings.addAll(listOfPorts);
} else {
configuration.setPortBindings(listOfPorts);
}
return this;
}
private Collection<PortBinding> addPairPortRange(String hostRangePorts, String containerRangePorts, String host) {
Collection<PortBinding> listOfPorts = new ArrayList<>();
final List<String> expandedHostPorts = getExpandedPorts(hostRangePorts);
final List<String> expandedContainerPorts = getExpandedPorts(containerRangePorts);
if (expandedContainerPorts.size() != expandedHostPorts.size()) {
throw new IllegalArgumentException("Port ranges from host and container side should contain same number of ports");
}
for (int i=0; i < expandedHostPorts.size(); i++) {
if (host == null) {
listOfPorts.add(PortBinding.valueOf(expandedHostPorts.get(i) + "->" + expandedContainerPorts.get(i)));
} else {
listOfPorts.add(PortBinding.valueOf(host + ":" + expandedHostPorts.get(i) + "->" + expandedContainerPorts.get(i)));
}
}
return listOfPorts;
}
private List<String> getExpandedPorts(String expression) {
String[] portRange = expression.split("-");
if (portRange.length != 2) {
throw new IllegalArgumentException("Expected Port Range expression but found " + expression);
}
int initialPort = Integer.parseInt(portRange[0].trim());
int endPort = Integer.parseInt(portRange[1].trim()) + 1;
return IntStream.range(initialPort, endPort).boxed()
.map(String::valueOf)
.collect(Collectors.toList());
}
public ContainerBuilder addExpose(Collection<String> exposes) {
Collection<ExposedPort> ports = new HashSet<ExposedPort>();
for(String exposed : exposes) {
ports.add(ExposedPort.valueOf(exposed));
}
if (configuration.getExposedPorts() != null) {
Collection<ExposedPort> oldExposedPorts = configuration.getExposedPorts();
oldExposedPorts.addAll(ports);
} else {
configuration.setExposedPorts(ports);
}
return this;
}
public ContainerBuilder addVolumes(Collection<String> volumes) {
if (configuration.getVolumes() != null) {
Collection<String> oldVolumes = configuration.getVolumes();
oldVolumes.addAll(volumes);
} else {
configuration.setVolumes(new HashSet<>(volumes));
}
return this;
}
public ContainerBuilder addBinds(Collection<String> volumes) {
if (configuration.getBinds() != null) {
Collection<String> oldBinds = configuration.getBinds();
oldBinds.addAll(volumes);
} else {
configuration.setBinds(new HashSet<>(volumes));
}
return this;
}
public ContainerBuilder addVolumesFrom(Collection<String> volumesFrom) {
if (configuration.getVolumesFrom() != null) {
Collection<String> oldVolumes = configuration.getVolumesFrom();
oldVolumes.addAll(volumesFrom);
} else {
configuration.setVolumesFrom(new HashSet<String>(volumesFrom));
}
return this;
}
public ContainerBuilder addLabels(Map<String, String> labels) {
//TODO now only support for array approach and not dictionary
if (configuration.getLabels() != null) {
Map<String, String> oldLabels = configuration.getLabels();
oldLabels.putAll(labels);
} else {
configuration.setLabels(labels);
}
return this;
}
public ContainerBuilder addEnvironment(Collection<String> environments) {
//TODO now only support for array approach
addEnvironment(getProperties(environments));
return this;
}
private void addEnvironment(Properties properties) {
if (configuration.getEnv() != null) {
Properties oldProperties = getProperties(configuration.getEnv());
oldProperties.putAll(properties);
configuration.setEnv(toEnvironment(oldProperties));
} else {
configuration.setEnv(toEnvironment(properties));
}
}
public ContainerBuilder addEnvFile(Collection<String> environmentPaths) {
for (String environmentPath : environmentPaths) {
try {
Properties properties = new Properties();
Path environmentLocation = Paths.get(environmentPath);
File environmentFile = this.dockerComposeRootLocation.resolve(environmentLocation).toFile();
FileInputStream inStream = new FileInputStream(environmentFile);
properties.load(inStream);
inStream.close();
addEnvironment(properties);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
return this;
}
public ContainerBuilder addNet(String net) {
configuration.setNetworkMode(net);
return this;
}
public ContainerBuilder addDns(String dns) {
configuration.setDns(Arrays.asList(dns));
return this;
}
public ContainerBuilder addDns(Collection<String> dns) {
if (configuration.getDns() != null) {
Collection<String> oldDns = configuration.getDns();
oldDns.addAll(dns);
} else {
configuration.setDns(new HashSet<String>(dns));
}
return this;
}
public ContainerBuilder addCapAdd(Collection<String> capAdds) {
if (configuration.getCapAdd() != null) {
Collection<String> oldCapAdd = configuration.getCapAdd();
oldCapAdd.addAll(capAdds);
} else {
configuration.setCapAdd(new HashSet<String>(capAdds));
}
return this;
}
public ContainerBuilder addCapDrop(Collection<String> capDrops) {
if (configuration.getCapDrop() != null) {
Collection<String> oldCapDrops = configuration.getCapDrop();
oldCapDrops.addAll(capDrops);
} else {
configuration.setCapDrop(new HashSet<String>(capDrops));
}
return this;
}
public ContainerBuilder addDnsSearch(String dnsSearch) {
configuration.setDnsSearch(Arrays.asList(dnsSearch));
return this;
}
public ContainerBuilder addDnsSearch(Collection<String> dnsSearch) {
if (configuration.getDnsSearch() != null) {
Collection<String> oldDnsSearch = configuration.getDnsSearch();
oldDnsSearch.addAll(dnsSearch);
} else {
configuration.setDnsSearch(new HashSet<String>(dnsSearch));
}
return this;
}
public ContainerBuilder addCpuShares(int cpuShares) {
configuration.setCpuShares(cpuShares);
return this;
}
private ContainerBuilder addCpuSet(String cpuSet) {
configuration.setCpuSet(cpuSet);
return this;
}
public ContainerBuilder addCpuQuota(int cpuQuota) {
configuration.setCpuQuota(cpuQuota);
return this;
}
public ContainerBuilder addTty(boolean tty) {
configuration.setTty(tty);
return this;
}
public ContainerBuilder addStdinOpen(boolean stdinOpen) {
configuration.setStdinOpen(stdinOpen);
return this;
}
public ContainerBuilder extend(Path location, String service) {
File extendLocation = this.dockerComposeRootLocation.resolve(location).toFile();
try(FileInputStream inputStream = new FileInputStream(extendLocation)) {
// resolve parameters
String content = DockerComposeEnvironmentVarResolver.replaceParameters(inputStream);
Map<String, Object> extendedDockerComposeFile = (Map<String, Object>) new Yaml().load(content);
Map<String, Object> serviceDockerComposeConfiguration = asMap(extendedDockerComposeFile, service);
ContainerBuilder containerBuilder = new ContainerBuilder(dockerComposeRootLocation, configuration);
configuration = containerBuilder.build(serviceDockerComposeConfiguration);
if(serviceDockerComposeConfiguration == null) {
throw new IllegalArgumentException(String.format("Service name %s is not present at %s", service, extendLocation.getAbsolutePath()));
}
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
return this;
}
public ContainerBuilder addRestart(String restart) {
RestartPolicy restartPolicy = new RestartPolicy();
if (restart.startsWith("on-failure")) {
String[] element = restart.split(":");
if (element.length == 1) {
restartPolicy.setName(restart);
restartPolicy.setMaximumRetryCount(0);
} else {
if (element.length == 2) {
restartPolicy.setName(element[0]);
restartPolicy.setMaximumRetryCount(Integer.parseInt(element[1]));
} else {
throw new IllegalArgumentException("on-failure restart should be on-failure or with optional retries on-failure:retries");
}
}
} else {
restartPolicy.setName(restart);
}
configuration.setRestartPolicy(restartPolicy);
return this;
}
public ContainerBuilder addPrivileged(boolean privileged) {
configuration.setPrivileged(privileged);
return this;
}
public ContainerBuilder addMemLimit(Long memLimit) {
configuration.setMemoryLimit(memLimit);
return this;
}
public ContainerBuilder addDomainName(String domainName) {
configuration.setDomainName(domainName);
return this;
}
public ContainerBuilder addHostname(String hostname) {
configuration.setHostName(hostname);
return this;
}
public ContainerBuilder addUser(String user) {
configuration.setUser(user);
return this;
}
public ContainerBuilder addEntrypoint(String entrypoint) {
configuration.setEntryPoint(Arrays.asList(entrypoint));
return this;
}
public ContainerBuilder addWorkingDir(String workingDir) {
configuration.setWorkingDir(workingDir);
return this;
}
public CubeContainer buildFromExtension() {
return this.configuration;
}
public CubeContainer build() {
return configuration;
}
private String getRandomPort() {
int shiftedRandomPort = random.nextInt(61000 - 32768);
return Integer.toString(shiftedRandomPort + 32768);
}
private Properties getProperties(Collection<String> properties) {
Properties allProperties = new Properties();
for (String property : properties) {
int keySeparator = property.indexOf("=");
allProperties.put(property.substring(0, keySeparator), property.substring(keySeparator + 1, property.length()));
}
return allProperties;
}
private Collection<String> toEnvironment(Properties properties) {
Collection<String> listOfEnvironment = new HashSet<String>();
Set<Entry<Object, Object>> entrySet = properties.entrySet();
for (Entry<Object, Object> entry : entrySet) {
listOfEnvironment.add(entry.getKey() + "=" + entry.getValue());
}
return listOfEnvironment;
}
private void logUnsupportedOperations(Set<String> keys) {
for (String key : keys) {
if(!AVAILABLE_COMMANDS.contains(key)) {
log.info(String.format("Key: %s is not implemented in Cube.", keys));
}
}
}
}