From f1531af7184f4f663c748c7bf04ca3058fdb9f1d Mon Sep 17 00:00:00 2001 From: Mark Collin Date: Thu, 18 Feb 2016 00:29:07 +0000 Subject: [PATCH] Fix #31 Write all exposed ports to a docker mappings file (defaults to ${project.build.directory}/docker-plugin/docker-mappings.properties) --- README.md | 8 +++ .../docker/maven/StartContainerMojo.java | 58 ++++++++++++++++--- .../docker/maven/StartContainerMojoTest.java | 39 ++++++++++--- 3 files changed, 89 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 4393829..d15f62c 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ pom.xml here: [pom.xml](https://github.com/wouterd/docker-maven-plugin/blob/mast at the end of the build even if the stop-containers goal is not executed (useful for preventing Ctrl+C causing dangling containers) --> false + mongo @@ -163,6 +164,13 @@ By default, all exposed ports are published on the host. The following two prope - docker.containers.[id].ports.[portname].host (f.ex 'docker.containers.id.app.ports.80/tcp.host') - docker.containers.[id].ports.[portname].port (f.ex 'docker.containers.id.app.ports.80/tcp.port') +All properties are also added to the file `${project.build.directory}/docker-plugin/docker-mappings.properties` so that you can easily load this properties file into your integration tests. +You can change the name or location of this file by modifying `` in the configuration block of the start-containers execution block. + + ${project.build.directory}/docker-plugin/docker-mappings.properties + +The location specified above is also exposed as a maven variable called `${docker.mappings.file}` + You can pass those project properties over to your integration test and use them to connect to your application. The plugin will connect to a docker instance over HTTP, linux socket support will be added after 1.0. It will look up diff --git a/src/main/java/net/wouterdanes/docker/maven/StartContainerMojo.java b/src/main/java/net/wouterdanes/docker/maven/StartContainerMojo.java index b0343fe..b3fcaf2 100644 --- a/src/main/java/net/wouterdanes/docker/maven/StartContainerMojo.java +++ b/src/main/java/net/wouterdanes/docker/maven/StartContainerMojo.java @@ -34,9 +34,15 @@ import org.apache.maven.project.MavenProject; import javax.inject.Inject; +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.nio.file.*; import java.util.*; import java.util.regex.Pattern; +import static java.nio.file.StandardOpenOption.APPEND; + /** * This class is responsible for starting docking containers in the pre-integration phase of the maven build. The goal * is called "start-containers" @@ -62,11 +68,15 @@ public StartContainerMojo(List containers) { @Parameter(defaultValue = "${mojoExecution}", readonly = true) private MojoExecution mojoExecution; + @Parameter(defaultValue = "${project.build.directory}/docker-plugin/docker-mappings.properties") + private File dockerMappingsFile; + @Override public void doExecute() throws MojoExecutionException, MojoFailureException { if (hasDuplicateIds() || hasInvalidLinks()) { return; } + generateMappingsFile(); DockerProvider provider = getDockerProvider(); for (ContainerStartConfiguration configuration : containers) { for (ContainerLink link : configuration.getLinks()) { @@ -84,6 +94,7 @@ public void doExecute() throws MojoExecutionException, MojoFailureException { String containerId = container.getId(); List exposedPorts = provider.getExposedPorts(containerId); exposePortsToProject(configuration, exposedPorts); + writeListOfPortsToFile(configuration, exposedPorts); getLog().info(String.format("Started container with id '%s'", containerId)); registerStartedContainer(configuration.getId(), container); } catch (DockerException e) { @@ -98,15 +109,14 @@ public void doExecute() throws MojoExecutionException, MojoFailureException { } } - /** Avoid dangling containers if the build is interrupted (e.g. via Ctrl+C) before the StopContainer mojo runs. */ - private void addShutdownHookToCleanUpContainers() - { + /** + * Avoid dangling containers if the build is interrupted (e.g. via Ctrl+C) before the StopContainer mojo runs. + */ + private void addShutdownHookToCleanUpContainers() { getLog().info("Started containers will be forcibly cleaned up when the build finishes"); - Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() - { + Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override - public void run() - { + public void run() { cleanUpStartedContainers(); } })); @@ -193,13 +203,39 @@ private boolean hasDuplicateIds() { private void exposePortsToProject(ContainerStartConfiguration configuration, List exposedPorts) { exposedPorts.parallelStream().forEach(port -> { - String prefix = String.format("docker.containers.%s.ports.%s.", - configuration.getId(), port.getContainerPort()); + String prefix = String.format("docker.containers.%s.ports.%s.", configuration.getId(), port.getContainerPort()); addPropertyToProject(prefix + "host", port.getHost()); addPropertyToProject(prefix + "port", String.valueOf(port.getExternalPort())); }); } + private void generateMappingsFile() throws MojoExecutionException { + try { + if (dockerMappingsFile.getParentFile() != null) { + Files.createDirectories(dockerMappingsFile.getParentFile().toPath()); + } + Files.createFile(dockerMappingsFile.toPath()); + addPropertyToProject("docker.mappings.file", dockerMappingsFile.getAbsolutePath()); + } catch (IOException e) { + throw new MojoExecutionException("Error generating docker mapping file: ", e); + } + } + + private void writeListOfPortsToFile(ContainerStartConfiguration configuration, List exposedPorts) throws MojoExecutionException { + try (BufferedWriter writer = Files.newBufferedWriter(dockerMappingsFile.toPath(), APPEND)) { + getLog().info(String.format("Writing properties for container '%s' to '%s'", configuration.getId(), dockerMappingsFile.getName())); + for (ExposedPort port : exposedPorts) { + String prefix = String.format("docker.containers.%s.ports.%s.", configuration.getId(), port.getContainerPort()); + writer.write(prefix + "host=" + port.getHost()); + writer.newLine(); + writer.write(prefix + "port=" + String.valueOf(port.getExternalPort())); + writer.newLine(); + } + } catch (IOException e) { + throw new MojoExecutionException("Error writing to docker mapping file: ", e); + } + } + private void replaceImageWithBuiltImageIdIfInternalId(ContainerStartConfiguration configuration) { Optional builtImage = getBuiltImageForStartId(configuration.getImage()); if (builtImage.isPresent()) { @@ -227,6 +263,10 @@ public void setMojoExecution(final MojoExecution mojoExecution) { this.mojoExecution = mojoExecution; } + public void setDockerMappingsFile(File dockerMappingsFile) { + this.dockerMappingsFile = dockerMappingsFile; + } + private void addPropertyToProject(String key, String value) { getLog().info(String.format("Setting property '%s' to '%s'", key, value)); project.getProperties().setProperty(key, value); diff --git a/src/test/java/net/wouterdanes/docker/maven/StartContainerMojoTest.java b/src/test/java/net/wouterdanes/docker/maven/StartContainerMojoTest.java index 68eb2ab..f1084cd 100644 --- a/src/test/java/net/wouterdanes/docker/maven/StartContainerMojoTest.java +++ b/src/test/java/net/wouterdanes/docker/maven/StartContainerMojoTest.java @@ -28,6 +28,7 @@ import org.apache.maven.plugin.MojoExecution; import org.apache.maven.project.MavenProject; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -35,7 +36,12 @@ import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.*; +import java.util.stream.Stream; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -45,6 +51,7 @@ public class StartContainerMojoTest { private static final String FAKE_PROVIDER_KEY = UUID.randomUUID().toString(); + private static final String DOCKER_MAPPINGS_FILE = System.getProperty("java.io.tmpdir") + File.separator + "docker-maven-plugin" + File.separator + "docker-mappings.properties"; private final MavenProject mavenProject = mock(MavenProject.class); private final MojoExecution mojoExecution = new MojoExecution(null, "start-containers", "some-id"); @@ -69,6 +76,7 @@ public void setUp() throws Exception { @After public void tearDown() throws Exception { DockerProviderSupplier.removeProvider(FAKE_PROVIDER_KEY); + Files.deleteIfExists(Paths.get(DOCKER_MAPPINGS_FILE)); } @Test @@ -285,8 +293,8 @@ public void testThatContainerWaitsForLinkedContainerToStart() throws Exception { final ContainerStartConfiguration parent = new ContainerStartConfiguration() .withId("parent") .withLink(new ContainerLink() - .toContainer("linked") - .withAlias("database") + .toContainer("linked") + .withAlias("database") ); when(FakeDockerProvider.instance.getLogs("linked")).thenReturn("", "", "there"); @@ -311,15 +319,15 @@ public Object answer(final InvocationOnMock invocation) throws Throwable { @Test public void testThatMojoStartsAContainerOnTheProviderWithEnvironmentVariables() throws Exception { - Map env = new HashMap<>(); - env.put("TEST_KEY", "test value"); - + Map env = new HashMap<>(); + env.put("TEST_KEY", "test value"); + ContainerStartConfiguration startConfiguration = new ContainerStartConfiguration() - .withEnv(env); + .withEnv(env); StartContainerMojo mojo = createMojo(startConfiguration); mojo.execute(); - + ArgumentCaptor captor = ArgumentCaptor.forClass(ContainerStartConfiguration.class); verify(FakeDockerProvider.instance).startContainer(captor.capture()); @@ -361,6 +369,22 @@ public void testThatConfiguredMacAddressGetsPassedToDocker() throws Exception { assertEquals("12:34:56:78:9a:bc", passedValue.getMacAddress()); } + @Test + public void testThatDockerMappingsFileIsCreated() throws Exception { + ContainerStartConfiguration startConfiguration = new ContainerStartConfiguration(); + StartContainerMojo mojo = createMojo(startConfiguration); + + File dockerMappingsFile = new File(DOCKER_MAPPINGS_FILE); + + assertEquals(dockerMappingsFile.exists(), false); + + mojo.execute(); + + verify(FakeDockerProvider.instance).startContainer(startConfiguration); + + assertEquals(dockerMappingsFile.exists(), true); + } + private StartContainerMojo createMojo(final ContainerStartConfiguration startConfiguration) { return createMojo(startConfiguration, FAKE_PROVIDER_KEY); } @@ -375,6 +399,7 @@ private StartContainerMojo createMojo(List startCon mojo.setProviderName(provider); mojo.setPluginContext(new HashMap()); mojo.setMojoExecution(mojoExecution); + mojo.setDockerMappingsFile(new File(DOCKER_MAPPINGS_FILE)); return mojo; }