/** * Copyright 2015-2017 Linagora, Université Joseph Fourier, Floralis * * The present code is developed in the scope of the joint LINAGORA - * Université Joseph Fourier - Floralis research program and is designated * as a "Result" pursuant to the terms and conditions of the LINAGORA * - Université Joseph Fourier - Floralis research program. Each copyright * holder of Results enumerated here above fully & independently holds complete * ownership of the complete Intellectual Property rights applicable to the whole * of said Results, and may freely exploit it in any manner which does not infringe * the moral rights of the other copyright holders. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.roboconf.target.docker.internal; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.logging.Logger; import org.junit.Assert; import net.roboconf.core.model.beans.Instance; import net.roboconf.core.utils.ProgramUtils; import net.roboconf.core.utils.Utils; /** * @author Vincent Zurczak - Linagora * @author Pierre-Yves Gibello - Linagora * @author Pierre Bourret - Université Joseph Fourier */ public final class DockerTestUtils { public static final String DOCKER_TCP_PORT = "4243"; /** * The maximum time we allow the docker handler to take to configure a machine. * <p> * Installing packages may take a while... So this value is quite large! */ public static final long DOCKER_CONFIGURE_TIMEOUT = 150000L; /** * Private empty constructor. */ private DockerTestUtils() { // nothing } /** * Checks that Docker is installed and configures it if necessary. * @throws InterruptedException * @throws IOException */ public static void checkDockerIsInstalled() throws IOException, InterruptedException { Logger logger = Logger.getLogger( DockerTestUtils.class.getName()); List<String> command = Arrays.asList( "docker", "version" ); int exitCode = ProgramUtils.executeCommand( logger, command, null, null, null, null); if( exitCode != 0 ) throw new IOException( "Docker is not installed." ); checkOrUpdateDockerTcpConfig( logger ); } /** * Checks that Docker is configured to listen on the right TCP port. * <p> * If not, try to change Docker config and restart (may require root access). * </p> * * @param logger * @throws IOException * @throws InterruptedException */ private static void checkOrUpdateDockerTcpConfig( Logger logger ) throws IOException, InterruptedException { File dockerConf = new File( "/etc/default/docker" ); if( ! dockerConf.exists()) dockerConf = new File( "/etc/default/docker.io" ); if( ! dockerConf.exists() || ! dockerConf.canRead()) throw new IOException( "The docker configuration file could not be found or is not readable." ); // Look for the expected port in the configuration file BufferedReader reader = null; boolean ok = false; try { reader = new BufferedReader( new InputStreamReader( new FileInputStream( dockerConf ), "UTF-8" )); String line; while( ! ok && (line = reader.readLine()) != null) { if( line.indexOf("#") < 0 && line.indexOf("DOCKER_OPTS") >= 0 && (line.indexOf("-H=tcp:") > 0 || line.indexOf("-H tcp:") > 0) && line.indexOf( ":" + DOCKER_TCP_PORT ) > 0) ok = true; } } finally { Utils.closeQuietly( reader ); } // If not present, try to update the file if( ! ok ) { if( ! dockerConf.canWrite()) { logger.severe( "There is no TCP configuration for port " + DOCKER_TCP_PORT + " in " + dockerConf ); logger.info( "Update the file " + dockerConf + " with DOCKER_OPTS=\"-H tcp://localhost:" + DOCKER_TCP_PORT + " -H unix:///var/run/docker.sock\"" ); throw new IOException( "The Docker configuration is missing TCP configuration." ); } OutputStreamWriter writer = null; try { writer = new OutputStreamWriter( new FileOutputStream( dockerConf, true ),"UTF-8" ); writer.append("DOCKER_OPTS=\"-H tcp://localhost:" + DOCKER_TCP_PORT + " -H unix:///var/run/docker.sock\"\n"); } finally { Utils.closeQuietly( writer ); } List<String> command = Arrays.asList( "docker", "restart" ); int exitCode = ProgramUtils.executeCommand( logger, command, null, null, null, null); Assert.assertEquals( 0, exitCode ); } } /** * Wait until the Docker target updates its machine id, or the timeout expires... * @param machineId the current machine id. * @param instanceData the instance data to pull for updates. * @param timeOut the time period to wait before abandoning. * @return the updated Docker machine id, or {@code null} if the timeout has expired. * @throws InterruptedException if interrupted while waiting for update. */ public static String waitForMachineId( final String machineId, final Map<String, String> instanceData, long timeOut ) throws InterruptedException { long deadLine = System.currentTimeMillis() + timeOut; String containerId; do { containerId = instanceData.get(Instance.MACHINE_ID); if (containerId != null && !containerId.equals(machineId)) { break; } Thread.sleep(1000); } while (System.currentTimeMillis() < deadLine); return !machineId.equals(containerId) ? containerId : null; } }