All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.fabric8.maven.docker.config.handler.compose.DockerComposeServiceWrapper Maven / Gradle / Ivy

There is a newer version: 0.45.0
Show newest version
package io.fabric8.maven.docker.config.handler.compose;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.fabric8.maven.docker.config.Arguments;
import io.fabric8.maven.docker.config.ImageConfiguration;
import io.fabric8.maven.docker.config.LogConfiguration;
import io.fabric8.maven.docker.config.NetworkConfig;
import io.fabric8.maven.docker.config.RestartPolicy;
import io.fabric8.maven.docker.config.RunVolumeConfiguration;
import io.fabric8.maven.docker.config.UlimitConfig;
import io.fabric8.maven.docker.util.VolumeBindingUtil;


class DockerComposeServiceWrapper {

    private final Map configuration;
    private final String name;
    private final File composeFile;
    private final ImageConfiguration enclosingImageConfig;
    private final File baseDir;

    DockerComposeServiceWrapper(String serviceName, File composeFile, Map serviceDefinition,
                                ImageConfiguration enclosingImageConfig, File baseDir) {
        this.name = serviceName;
        this.composeFile = composeFile;
        this.configuration = serviceDefinition;
        this.enclosingImageConfig = enclosingImageConfig;

        if (!baseDir.isAbsolute()) {
            throw new IllegalArgumentException(
                    "Expected the base directory '" + baseDir + "' to be an absolute path.");
        }
        this.baseDir = baseDir;
    }

    String getAlias() {
        // 'container_name' takes precidence
        String alias = asString("container_name");
        return (alias != null) ? alias : name;
    }

    String getImage() {
        return asString("image");
    }

    // ==================================================================================
    // Build config:

    boolean requiresBuild() {
        return asObject("build") != null;
    }

    String getBuildDir() {
        Object build = asObject("build");
        if (build == null) {
            return null;
        }
        if (build instanceof String) {
            return (String) build;
        }
        if (! (build instanceof Map)) {
            throwIllegalArgumentException("build:' must be either a String or a Map");
        }
        Map buildConfig = (Map) build;
        if (!buildConfig.containsKey("context")) {
            throwIllegalArgumentException("'build:' a context directory for a build must be specified");
        }
        return buildConfig.get("context");
    }

    String getDockerfile() {
        Object build = asObject("build");
        if (build instanceof Map) {
            return (String) ((Map) build).get("dockerfile");
        } else {
            return null;
        }
    }

    Map getBuildArgs() {
        Object build = asObject("build");
        if (build instanceof Map) {
            return (Map) ((Map) build).get("args");
        } else {
            return null;
        }
    }

    // ===================================================================================
    // Run config:

    List getCapAdd() {
        return asList("cap_add");
    }

    List getCapDrop() {
        return asList("cap_drop");
    }

    Arguments getCommand() {
        Object command = asObject("command");
        return command != null ? asArguments(command, "command") : null;
    }

    List getDependsOn() {
        return asList("depends_on");
    }

    List getDns() {
        return asList("dns");
    }

    List getDnsSearch() {
        return asList("dns_search");
    }

    List getTmpfs() {
        return asList("tmpfs");
    }

    Arguments getEntrypoint() {
        Object entrypoint = asObject("entrypoint");
        return entrypoint != null ? asArguments(entrypoint, "entrypoint") : null;
    }

    Map getEnvironment() {
        // TODO: load the env files from compose as given with env_file and add them all to the map
        return asMap("environment");
    }

    // external_links are added with "links"

    List getExtraHosts() {
        return asList("extra_hosts");
    }

    // image is added as top-level in image configuration

    Map getLabels() {
        return asMap("labels");
    }

    public List getLinks() {
        List ret = new ArrayList<>();
        ret.addAll(this.asList("links"));
        ret.addAll(this.asList("external_links"));
        return ret;
    }

    LogConfiguration getLogConfiguration() {
        Object logConfig = asObject("logging");
        if (logConfig == null) {
            return null;
        }
        if (!(logConfig instanceof Map)) {
            throwIllegalArgumentException("'logging' has to be a map and not " + logConfig.getClass());
        }
        Map config = (Map) logConfig;
        return new LogConfiguration.Builder()
            .logDriverName((String) config.get("driver"))
            .logDriverOpts((Map) config.get("options"))
            .build();
    }

    NetworkConfig getNetworkConfig() {
        String net = asString("network_mode");
        if (net != null) {
            return new NetworkConfig(net);
        }
        Object networks = asObject("networks");
        if (networks == null) {
            return null;
        }
        if (networks instanceof List) {
            List toJoin = (List) networks;
            if (toJoin.size() > 1) {
                throwIllegalArgumentException("'networks:' Only one custom network to join is supported currently");
            }
            return new NetworkConfig(NetworkConfig.Mode.custom, toJoin.get(0));
        } else if (networks instanceof Map) {
            Map toJoin = (Map) networks;
            if (toJoin.size() > 1) {
                throwIllegalArgumentException("'networks:' Only one custom network to join is supported currently");
            }
            String custom = toJoin.keySet().iterator().next();
            NetworkConfig ret = new NetworkConfig(NetworkConfig.Mode.custom, custom);
            Object aliases = toJoin.get(custom);
            if (aliases != null) {
                if (aliases instanceof List) {
                    for (String alias : (List) aliases) {
                        ret.addAlias(alias);
                    }
                } else if (aliases instanceof Map) {
                	Map> map = (Map>) aliases;
                    if (map.containsKey("aliases")) {
                        for (String alias : map.get("aliases")) {
                            ret.addAlias(alias);
                        }
                    } else {
                        throwIllegalArgumentException(
                                "'networks:' Aliases must be given as a map of strings. 'aliases' key not founded");
                    }
                } else {
                    throwIllegalArgumentException("'networks:' No aliases entry found in network config map");
                }
            }
            return ret;
        } else {
            throwIllegalArgumentException("'networks:' must beu either a list or a map");
            return null;
        }
    }

    List getPortMapping() {
        List fromYml = asList("ports");
        int size = fromYml.size();

        List ports = new ArrayList<>(size);
        for (int i = 0; i < size; i++) {
            String port = fromYml.get(i);
            if (port.contains(":")) {
                ports.add(port);
            }
            else {
                /*
                 * docker-compose allows just the port number which triggers a random port and the plugin does not, so construct a property
                 * name to mimic the required behavior. names will always based on position, and not the number of times we create the
                 * string.
                 */
                ports.add(String.format("%s_port_%s:%s", getAlias(), i + 1, port));
            }
        }
        return ports;
    }

    List getUlimits() {
        Object ulimits = asObject("ulimits");
        if (ulimits == null) {
            return null;
        }
        if (!(ulimits instanceof Map)) {
            throwIllegalArgumentException("'ulimits:' must be a map");
        }
        Map ulimitMap = (Map) ulimits;
        List ret = new ArrayList<>();
        for (String ulimit : ulimitMap.keySet()) {
            Object val = ulimitMap.get(ulimit);
            if (val instanceof Map) {
                Map valMap = (Map) val;
                Integer soft = valMap.get("soft");
                Integer hard = valMap.get("hard");
                ret.add(new UlimitConfig(ulimit, hard, soft));
            } else if (val instanceof Integer) {
                ret.add(new UlimitConfig(ulimit, (Integer) val, null));
            } else {
                throwIllegalArgumentException("'ulimits:' invalid limit value " + val + " (class : " + val.getClass() + ")");
            }
        }
        return ret;
    }

    RunVolumeConfiguration getVolumeConfig() {
        RunVolumeConfiguration.Builder builder = new RunVolumeConfiguration.Builder();
        List volumes = asList("volumes");
        boolean added = false;
        if (volumes.size() > 0) {
            builder.bind(volumes);
            added = true;
        }
        List volumesFrom = asList("volumes_from");
        if (volumesFrom.size() > 0) {
            builder.from(volumesFrom);
            added = true;
        }

        if (added) {
            RunVolumeConfiguration configuration = builder.build();
            VolumeBindingUtil.resolveRelativeVolumeBindings(baseDir, configuration);
            return configuration;
        }

        return null;
    }

    String getDomainname() {
        return asString("domainname");
    }

    String getHostname() {
        return asString("hostname");
    }

    Long getMemory() {
        return asLong("mem_limit");
    }

    Long getMemorySwap() {
        return asLong("memswap_limit");
    }

    Boolean getPrivileged() {
        return asBoolean("privileged");
    }

    RestartPolicy getRestartPolicy() {
        String restart = asString("restart");
        if (restart == null) {
            return null;
        }

        RestartPolicy.Builder builder = new RestartPolicy.Builder();
        if (restart.contains(":")) {
            String[] parts = restart.split(":", 2);
            builder.name(parts[0]).retry(Integer.valueOf(parts[1]));
        }
        else {
            builder.name(restart);
        }

        return builder.build();
    }

    Long getShmSize() {
        return asLong("shm_size");
    }

    String getUser() {
        return asString("user");
    }

    String getWorkingDir() {
        return asString("working_dir");
    }

    // ================================================================
    // Not used yet:

    public String getCGroupParent() {
        return asString("cgroup_parent");
    }

    public String getCpuSet() {
        return asString("cpuset");
    }

    public Long getCpuShares() {
        return asLong("cpu_shares");
    }

    public Long getCpusCount(){
        Double cpus = asDouble("cpus");
        return convertToNanoCpus(cpus);
    }

    public List getDevices() {
        return asList("devices");
    }

    // =======================================================================================================
    // Helper methods

    private Object asObject(String key) {
        return configuration.get(key);
    }

    private String asString(String key) {
        return String.class.cast(configuration.get(key));
    }

    private Long asLong(String key) {
        Long value = null;
        if (configuration.containsKey(key)) {
            value = Long.valueOf(configuration.get(key).toString());
        }
        return value;
    }

    private Boolean asBoolean(String key) {
        Boolean value = null;
        if (configuration.containsKey(key)) {
            value = Boolean.valueOf(configuration.get(key).toString());
        }
        return value;
    }

    private  List asList(String key) {
        if (configuration.containsKey(key)) {
            Object value = configuration.get(key);
            if (value instanceof String) {
                value = Arrays.asList(value);
            }

            return List.class.cast(value);
        }

        return Collections.emptyList();
    }

    private Map asMap(String key) {
        if (configuration.containsKey(key)) {
            Object value = configuration.get(key);
            if (value instanceof List) {
                value = convertToMap(List.class.cast(value));
            }
            return Map.class.cast(value);
        }

        return Collections.emptyMap();
    }

    private Double asDouble(String key){
        Double value = null;
        if (configuration.containsKey(key)) {
            value = Double.valueOf(configuration.get(key).toString());
        }
        return value;
    }

    private Arguments asArguments(Object command, String label) {
        if (command instanceof String) {
            return new Arguments((String) command);
        } else if (command instanceof List) {
            return new Arguments((List) command);
        } else {
            throwIllegalArgumentException(String.format("'%s' must be either String or List but not %s", label, command.getClass()));
            return null;
        }
    }

    private Map convertToMap(List list) {
        Map map = new HashMap<>(list.size());
        for (String entry : list) {
            String[] parts = entry.split("=", 2);
            map.put(parts[0], parts[1]);
        }
        return map;
    }

    private Long convertToNanoCpus(Double cpus){
        if(cpus == null){
            return null;
        }
        return (long)(cpus * 1000000000);
    }

    private void throwIllegalArgumentException(String msg) {
        throw new IllegalArgumentException(String.format("%s: %s - ", composeFile, name) + msg);
    }

}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy