package org.arquillian.cube.docker.impl.util; import java.util.Collection; import java.util.Map; import java.util.Set; import org.arquillian.cube.docker.impl.client.CubeDockerConfiguration; import org.arquillian.cube.docker.impl.client.config.CubeContainer; import org.arquillian.cube.docker.impl.client.config.DockerCompositions; import org.arquillian.cube.docker.impl.client.config.PortBinding; /** * Utility class that helps on autoresolution of binding ports in case of running Arquillian as client mode and not using * enrichments for getting the host/bind port of exposed one. * <p> * Usually this class is used by extensions that needs autoresolution. */ public class SinglePortBindResolver { private static final int NO_PORT = -1; private SinglePortBindResolver() { super(); } /** * Method that tries to resolve a bind port for a given exposed port. * * @param cubeDockerConfiguration * where all docker configuration is exposed * @param exposedPort * used to find the binding port * @param excludedContainers * where binding port search is ignored * * @return binding port */ public static int resolveBindPort(CubeDockerConfiguration cubeDockerConfiguration, int exposedPort, String... excludedContainers) { final PortBindInfo portBinding = resolvePortBindPort(cubeDockerConfiguration, exposedPort, excludedContainers); if (portBinding == null) { return exposedPort; } return portBinding.getBindPort(); } /** * Method that tries to resolve a bind port for a given exposed port. * * @param cubeDockerConfiguration * where all docker configuration is exposed * @param exposedPort * used to find the binding port * @param excludedContainers * where binding port search is ignored * * @return binding port or null if couldn't be found */ public static PortBindInfo resolvePortBindPort(CubeDockerConfiguration cubeDockerConfiguration, int exposedPort, String... excludedContainers) { final DockerCompositions dockerContainersContent = cubeDockerConfiguration.getDockerContainersContent(); final Set<Map.Entry<String, CubeContainer>> containers = dockerContainersContent.getContainers().entrySet(); // user specified an exposed port PortBindInfo portBindInfo = null; for (Map.Entry<String, CubeContainer> cubeContainerEntry : containers) { // need to skip vnc and selenium container if (shouldBeIgnored(cubeContainerEntry.getKey(), excludedContainers)) { continue; } final CubeContainer cubeContainer = cubeContainerEntry.getValue(); final Collection<PortBinding> portBindings = cubeContainer.getPortBindings(); if (portBindings != null) { for (PortBinding portBinding : portBindings) { if (portBinding.getExposedPort().getExposed() == exposedPort) { if (noPreviousBindPortFound(portBindInfo)) { int bindPort = portBinding.getBound(); portBindInfo = new PortBindInfo( portBinding.getExposedPort().getExposed(), bindPort, cubeContainerEntry.getKey()); } else { throw new IllegalArgumentException( String.format("More than one docker container with port binding having exposed port %s.", exposedPort)); } } } } if (noPreviousBindPortFound(portBindInfo)) { return null; } } return portBindInfo; } /** * Method that tries to resolve a bind port by searching if there is only one binding port across all running * containers * * @param cubeDockerConfiguration * where all docker configuration is exposed * @param excludedContainers * where binding port search is ignored * * @return binding port */ public static int resolveBindPort(CubeDockerConfiguration cubeDockerConfiguration, String... excludedContainers) { final PortBindInfo portBinding = resolvePortBindPort(cubeDockerConfiguration, excludedContainers); if (portBinding == null) { throw new IllegalArgumentException("There isn't any bind port."); } return portBinding.getBindPort(); } /** * Method that tries to resolve a bind port by searching if there is only one binding port across all running * containers * * @param cubeDockerConfiguration * where all docker configuration is exposed * @param excludedContainers * where binding port search is ignored * * @return binding port */ public static PortBindInfo resolvePortBindPort(CubeDockerConfiguration cubeDockerConfiguration, String... excludedContainers) { final DockerCompositions dockerContainersContent = cubeDockerConfiguration.getDockerContainersContent(); final Set<Map.Entry<String, CubeContainer>> containers = dockerContainersContent.getContainers().entrySet(); //if no port, we check if there is only one cube with one bind port and if not, return default one PortBindInfo portBindInfo = null; for (Map.Entry<String, CubeContainer> cubeContainerEntry : containers) { // need to skip excluded containers if (shouldBeIgnored(cubeContainerEntry.getKey(), excludedContainers)) { continue; } final CubeContainer cubeContainer = cubeContainerEntry.getValue(); if (hasMoreThanOneBindPort(cubeContainer)) { throw new IllegalArgumentException("No port was specified and a container has more than one bind port."); } if (hasOnlyOneBindPort(cubeContainer)) { if (noPreviousBindPortFound(portBindInfo)) { final PortBinding portBinding = cubeContainer.getPortBindings() .iterator().next(); int bindPort = portBinding.getBound(); int exposedPort = portBinding.getExposedPort().getExposed(); portBindInfo = new PortBindInfo(exposedPort, bindPort, cubeContainerEntry.getKey()); } else { throw new IllegalArgumentException( "No port was specified and in all containers there are more than one bind port."); } } } if (noPreviousBindPortFound(portBindInfo)) { throw new IllegalArgumentException("There isn't any bind port."); } return portBindInfo; } private static boolean shouldBeIgnored(String containerId, String... excludedContainers) { for (String excludedContainer : excludedContainers) { if (excludedContainer.equals(containerId)) { return true; } } return false; } private static boolean noPreviousBindPortFound(PortBindInfo bindPort) { return bindPort == null; } private static boolean hasOnlyOneBindPort(CubeContainer cubeContainer) { final Collection<PortBinding> portBindings = cubeContainer.getPortBindings(); if (portBindings == null) { return false; } return portBindings.size() == 1; } private static boolean hasMoreThanOneBindPort(CubeContainer cubeContainer) { final Collection<PortBinding> portBindings = cubeContainer.getPortBindings(); if (portBindings == null) { return false; } return portBindings.size() > 1; } public static class PortBindInfo { private int bindPort; private int exposedPort; private String containerName; public PortBindInfo(int exposedPort, int bindPort, String containerName) { this.exposedPort = exposedPort; this.bindPort = bindPort; this.containerName = containerName; } public int getBindPort() { return bindPort; } public int getExposedPort() { return exposedPort; } public String getContainerName() { return containerName; } } }