/******************************************************************************* * Copyright (c) 2012-2016 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.plugin.docker.machine; import com.google.inject.assistedinject.Assisted; import org.eclipse.che.api.core.model.machine.MachineMetadata; import org.eclipse.che.api.core.model.machine.Server; import org.eclipse.che.api.machine.server.model.impl.ServerImpl; import org.eclipse.che.plugin.docker.client.json.ContainerInfo; import org.eclipse.che.plugin.docker.client.json.PortBinding; import javax.inject.Inject; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Docker implementation of {@link MachineMetadata} * * @author andrew00x * @author Alexander Garagatyi */ public class DockerInstanceMetadata implements MachineMetadata { /** * Env variable that points to root folder of projects in dev machine */ public static final String PROJECTS_ROOT_VARIABLE = "CHE_PROJECTS_ROOT"; /** * Env variable for dev machine that contains url of Che API */ public static final String API_ENDPOINT_URL_VARIABLE = "CHE_API_ENDPOINT"; /** * Environment variable that will be setup in developer machine will contain ID of a workspace for which this machine has been created */ public static final String CHE_WORKSPACE_ID = "CHE_WORKSPACE_ID"; /** * Default HOSTNAME that will be added in all docker containers that are started. This host will container the Docker host's ip * reachable inside the container. */ public static final String CHE_HOST = "che-host"; /** * Environment variable that will be setup in developer machine and contains user token. */ public static final String USER_TOKEN = "USER_TOKEN"; protected static final Pattern SERVICE_LABEL_PATTERN = Pattern.compile("che:server:(?<port>[0-9]+(/tcp|/udp)?):(?<servprop>ref|protocol)"); private final ContainerInfo info; private final String containerHost; @Inject public DockerInstanceMetadata(@Assisted ContainerInfo containerInfo, @Assisted String containerHost) { this.info = containerInfo; this.containerHost = containerHost; } @Override public Map<String, String> getProperties() { Map<String, String> md = new LinkedHashMap<>(); md.put("id", info.getId()); md.put("created", info.getCreated()); md.put("image", info.getImage()); md.put("path", info.getPath()); md.put("appArmorProfile", info.getAppArmorProfile()); md.put("driver", info.getDriver()); md.put("execDriver", info.getExecDriver()); md.put("hostnamePath", info.getHostnamePath()); md.put("hostsPath", info.getHostsPath()); md.put("mountLabel", info.getMountLabel()); md.put("name", info.getName()); md.put("processLabel", info.getProcessLabel()); md.put("volumesRW", String.valueOf(info.getVolumesRW())); md.put("resolvConfPath", info.getResolvConfPath()); md.put("args", Arrays.toString(info.getArgs())); md.put("volumes", String.valueOf(info.getVolumes())); md.put("restartCount", String.valueOf(info.getRestartCount())); md.put("logPath", String.valueOf(info.getLogPath())); md.put("config.domainName", info.getConfig().getDomainName()); md.put("config.hostname", info.getConfig().getHostname()); md.put("config.image", info.getConfig().getImage()); md.put("config.user", info.getConfig().getUser()); md.put("config.workingDir", info.getConfig().getWorkingDir()); md.put("config.cmd", Arrays.toString(info.getConfig().getCmd())); md.put("config.volumes", String.valueOf(info.getConfig().getVolumes())); md.put("config.cpuset", info.getConfig().getCpuset()); md.put("config.entrypoint", info.getConfig().getEntrypoint()); md.put("config.exposedPorts", String.valueOf(info.getConfig().getExposedPorts())); md.put("config.macAddress", info.getConfig().getMacAddress()); md.put("config.securityOpts", Arrays.toString(info.getConfig().getSecurityOpts())); md.put("config.cpuShares", Integer.toString(info.getConfig().getCpuShares())); md.put("config.env", Arrays.toString(info.getConfig().getEnv())); md.put("config.attachStderr", Boolean.toString(info.getConfig().isAttachStderr())); md.put("config.attachStdin", Boolean.toString(info.getConfig().isAttachStdin())); md.put("config.attachStdout", Boolean.toString(info.getConfig().isAttachStdout())); md.put("config.networkDisabled", Boolean.toString(info.getConfig().isNetworkDisabled())); md.put("config.openStdin", Boolean.toString(info.getConfig().isOpenStdin())); md.put("config.stdinOnce", Boolean.toString(info.getConfig().isStdinOnce())); md.put("config.tty", Boolean.toString(info.getConfig().isTty())); md.put("config.labels", String.valueOf(info.getConfig().getLabels())); md.put("state.startedAt", info.getState().getStartedAt()); md.put("state.exitCode", Integer.toString(info.getState().getExitCode())); md.put("state.pid", Integer.toString(info.getState().getPid())); md.put("state.running", Boolean.toString(info.getState().isRunning())); md.put("state.finishedAt", info.getState().getFinishedAt()); md.put("state.paused", Boolean.toString(info.getState().isPaused())); md.put("state.restarting", Boolean.toString(info.getState().isRestarting())); md.put("state.dead", String.valueOf(info.getState().isDead())); md.put("state.OOMKilled", String.valueOf(info.getState().isOOMKilled())); md.put("state.error", info.getState().getError()); md.put("network.bridge", info.getNetworkSettings().getBridge()); md.put("network.gateway", info.getNetworkSettings().getGateway()); md.put("network.ipAddress", info.getNetworkSettings().getIpAddress()); md.put("network.ipPrefixLen", Integer.toString(info.getNetworkSettings().getIpPrefixLen())); md.put("network.portMappings", Arrays.toString(info.getNetworkSettings().getPortMapping())); md.put("network.macAddress", info.getNetworkSettings().getMacAddress()); md.put("network.ports", String.valueOf(info.getNetworkSettings().getPorts())); md.put("network.linkLocalIPv6PrefixLen", String.valueOf(info.getNetworkSettings().getLinkLocalIPv6PrefixLen())); md.put("network.globalIPv6Address", info.getNetworkSettings().getGlobalIPv6Address()); md.put("network.globalIPv6PrefixLen", String.valueOf(info.getNetworkSettings().getGlobalIPv6PrefixLen())); md.put("network.iPv6Gateway", info.getNetworkSettings().getiPv6Gateway()); md.put("network.linkLocalIPv6Address", info.getNetworkSettings().getLinkLocalIPv6Address()); md.put("hostConfig.cgroupParent", info.getHostConfig().getCgroupParent()); md.put("hostConfig.containerIDFile", info.getHostConfig().getContainerIDFile()); md.put("hostConfig.cpusetCpus", info.getHostConfig().getCpusetCpus()); md.put("hostConfig.ipcMode", info.getHostConfig().getIpcMode()); md.put("hostConfig.memory", Long.toString(info.getHostConfig().getMemory())); md.put("hostConfig.networkMode", info.getHostConfig().getNetworkMode()); md.put("hostConfig.pidMode", info.getHostConfig().getPidMode()); md.put("hostConfig.binds", Arrays.toString(info.getHostConfig().getBinds())); md.put("hostConfig.capAdd", Arrays.toString(info.getHostConfig().getCapAdd())); md.put("hostConfig.capDrop", Arrays.toString(info.getHostConfig().getCapDrop())); md.put("hostConfig.cpuShares", String.valueOf(info.getHostConfig().getCpuShares())); md.put("hostConfig.devices", Arrays.toString(info.getHostConfig().getDevices())); md.put("hostConfig.dns", Arrays.toString(info.getHostConfig().getDns())); md.put("hostConfig.dnsSearch", Arrays.toString(info.getHostConfig().getDnsSearch())); md.put("hostConfig.extraHosts", Arrays.toString(info.getHostConfig().getExtraHosts())); md.put("hostConfig.links", Arrays.toString(info.getHostConfig().getLinks())); md.put("hostConfig.logConfig", String.valueOf(info.getHostConfig().getLogConfig())); md.put("hostConfig.lxcConf", Arrays.toString(info.getHostConfig().getLxcConf())); md.put("hostConfig.memorySwap", String.valueOf(info.getHostConfig().getMemorySwap())); md.put("hostConfig.portBindings", String.valueOf(info.getHostConfig().getPortBindings())); md.put("hostConfig.restartPolicy", String.valueOf(info.getHostConfig().getRestartPolicy())); md.put("hostConfig.ulimits", Arrays.toString(info.getHostConfig().getUlimits())); md.put("hostConfig.volumesFrom", Arrays.toString(info.getHostConfig().getVolumesFrom())); md.put("hostConfig.memory", Long.toString(info.getHostConfig().getMemory())); md.put("hostConfig.memorySwap", Long.toString(info.getHostConfig().getMemorySwap())); return md; } @Override public Map<String, String> getEnvVariables() { final Map<String, String> envVariables = new HashMap<>(); for (String envVariable : info.getConfig().getEnv()) { final String[] variableNameValue = envVariable.split("=", 2); envVariables.put(variableNameValue[0], variableNameValue[1]); } return envVariables; } @Override public String projectsRoot() { return getEnvVariables().get(PROJECTS_ROOT_VARIABLE); } @Override public Map<String, Server> getServers() { return addDefaultReferenceForServersWithoutReference( addRefAndUrlToServerFromImageLabels(getServersWithFilledPorts(containerHost, info.getNetworkSettings().getPorts()), info.getConfig().getLabels())); } private Map<String, Server> addDefaultReferenceForServersWithoutReference(Map<String, Server> servers) { // replace / if server port contains it. E.g. 5411/udp servers.entrySet() .stream() .filter(server -> server.getValue().getRef() == null) .forEach(server -> { // replace / if server port contains it. E.g. 5411/udp ((ServerImpl)server.getValue()).setRef("Server-" + server.getKey().replace("/", "-")); }); return servers; } protected HashMap<String, Server> getServersWithFilledPorts(final String host, final Map<String, List<PortBinding>> exposedPorts) { final HashMap<String, Server> servers = new LinkedHashMap<>(); for (Map.Entry<String, List<PortBinding>> portEntry : exposedPorts.entrySet()) { // in form 1234/tcp or 1234 String portOrPortUdp = portEntry.getKey(); // we are assigning ports automatically, so have 1 to 1 binding (at least per protocol) if (!portOrPortUdp.endsWith("/udp")) { // cut off /tcp if it presents portOrPortUdp = portOrPortUdp.split("/", 2)[0]; } final PortBinding portBinding = portEntry.getValue().get(0); servers.put(portOrPortUdp, new ServerImpl(null, host + ":" + portBinding.getHostPort(), null)); } return servers; } protected Map<String, Server> addRefAndUrlToServerFromImageLabels(final Map<String, Server> servers, final Map<String, String> labels) { for (Map.Entry<String, String> label : labels.entrySet()) { final Matcher matcher = SERVICE_LABEL_PATTERN.matcher(label.getKey()); if (matcher.matches()) { final String port = matcher.group("port"); if (servers.containsKey(port)) { final ServerImpl server = (ServerImpl)servers.get(port); if ("ref".equals(matcher.group("servprop"))) { server.setRef(label.getValue()); } else { // value is protocol server.setUrl(label.getValue() + "://" + server.getAddress()); } } } } return servers; } }