From 3f1fe271ed8c59eb136d94bc4cd199f2da60befd Mon Sep 17 00:00:00 2001 From: Josef Cacek Date: Fri, 19 Feb 2016 12:33:24 +0100 Subject: [PATCH] [JCLOUDS-1084] Docker live tests fixed and made more robust --- apis/docker/pom.xml | 3 +- .../docker/compute/BaseDockerApiLiveTest.java | 14 +++- .../DockerComputeServiceAdapterLiveTest.java | 27 +++---- .../compute/SshToCustomPortLiveTest.java | 47 ++++------- .../docker/features/ContainerApiLiveTest.java | 3 - .../docker/features/MiscApiLiveTest.java | 20 +++-- .../docker/internal/DockerTestUtils.java | 78 +++++++++++++++++++ apis/docker/src/test/resources/Dockerfile | 16 +--- 8 files changed, 133 insertions(+), 75 deletions(-) create mode 100644 apis/docker/src/test/java/org/jclouds/docker/internal/DockerTestUtils.java diff --git a/apis/docker/pom.xml b/apis/docker/pom.xml index 39009fa89d..8bbb98c037 100644 --- a/apis/docker/pom.xml +++ b/apis/docker/pom.xml @@ -38,6 +38,7 @@ ${env.DOCKER_CERT_PATH}/cert.pem ${env.DOCKER_CERT_PATH}/key.pem ${env.DOCKER_CERT_PATH}/ca.pem + ${env.DOCKER_HOST} false org.jclouds.docker*;version="${project.version}" @@ -151,7 +152,7 @@ test.docker.endpoint - ${env.DOCKER_HOST} + ${test.docker.endpoint} tcp https false diff --git a/apis/docker/src/test/java/org/jclouds/docker/compute/BaseDockerApiLiveTest.java b/apis/docker/src/test/java/org/jclouds/docker/compute/BaseDockerApiLiveTest.java index eab76ba8ec..81324ef8bb 100644 --- a/apis/docker/src/test/java/org/jclouds/docker/compute/BaseDockerApiLiveTest.java +++ b/apis/docker/src/test/java/org/jclouds/docker/compute/BaseDockerApiLiveTest.java @@ -33,6 +33,7 @@ import org.jclouds.Constants; import org.jclouds.apis.BaseApiLiveTest; import org.jclouds.compute.config.ComputeServiceProperties; import org.jclouds.docker.DockerApi; +import org.jclouds.docker.internal.DockerTestUtils; import org.jclouds.io.Payload; import org.jclouds.io.Payloads; import org.jclouds.sshj.config.SshjSshClientModule; @@ -46,7 +47,7 @@ import com.google.inject.Module; public class BaseDockerApiLiveTest extends BaseApiLiveTest { protected static final String DEFAULT_IMAGE = "alpine"; - protected static final String DEFAULT_TAG = "3.2"; + protected static final String DEFAULT_TAG = "3.3"; protected static final String ALPINE_IMAGE_TAG = String.format("%s:%s", DEFAULT_IMAGE, DEFAULT_TAG); @@ -54,6 +55,17 @@ public class BaseDockerApiLiveTest extends BaseApiLiveTest { provider = "docker"; } + /** + * Removes Docker image if it's present on the Docker host. + * + * @param imageName + * image to be deleted (must be not-null) + * @see DockerTestUtils#removeImageIfExists(DockerApi, String) + */ + protected void removeImageIfExists(String imageName) { + DockerTestUtils.removeImageIfExists(api, imageName); + } + @Override protected Iterable setupModules() { return ImmutableSet.of(getLoggingModule(), new SshjSshClientModule()); diff --git a/apis/docker/src/test/java/org/jclouds/docker/compute/DockerComputeServiceAdapterLiveTest.java b/apis/docker/src/test/java/org/jclouds/docker/compute/DockerComputeServiceAdapterLiveTest.java index faad0ac51e..022177691f 100644 --- a/apis/docker/src/test/java/org/jclouds/docker/compute/DockerComputeServiceAdapterLiveTest.java +++ b/apis/docker/src/test/java/org/jclouds/docker/compute/DockerComputeServiceAdapterLiveTest.java @@ -19,6 +19,7 @@ package org.jclouds.docker.compute; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; + import java.util.Properties; import java.util.Random; @@ -32,9 +33,8 @@ import org.jclouds.docker.compute.strategy.DockerComputeServiceAdapter; import org.jclouds.docker.domain.Container; import org.jclouds.docker.domain.Image; import org.jclouds.docker.options.CreateImageOptions; -import org.jclouds.docker.options.DeleteImageOptions; import org.jclouds.sshj.config.SshjSshClientModule; -import org.testng.annotations.AfterGroups; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -48,7 +48,7 @@ import com.google.inject.Module; public class DockerComputeServiceAdapterLiveTest extends BaseDockerApiLiveTest { private static final String SSHABLE_IMAGE = "kwart/alpine-ext"; - private static final String SSHABLE_IMAGE_TAG = "3.2-ssh"; + private static final String SSHABLE_IMAGE_TAG = "3.3-ssh"; private Image defaultImage; private DockerComputeServiceAdapter adapter; @@ -68,6 +68,14 @@ public class DockerComputeServiceAdapterLiveTest extends BaseDockerApiLiveTest { assertNotNull(defaultImage); } + @AfterClass(alwaysRun = true) + protected void tearDown() { + if (guest != null) { + adapter.destroyNode(guest.getNode().id() + ""); + } + super.tearDown(); + } + @Override protected DockerApi create(Properties props, Iterable modules) { Injector injector = newBuilder().modules(modules).overrides(props).buildInjector(); @@ -83,7 +91,7 @@ public class DockerComputeServiceAdapterLiveTest extends BaseDockerApiLiveTest { Template template = templateBuilder.imageId(defaultImage.id()).build(); DockerTemplateOptions options = template.getOptions().as(DockerTemplateOptions.class); - options.env(ImmutableList.of("ROOT_PASS=password")); + options.env(ImmutableList.of("ROOT_PASSWORD=password")); guest = adapter.createNodeWithGroupEncodedIntoName(group, name, template); assertEquals(guest.getNodeId(), guest.getNode().id()); } @@ -97,17 +105,6 @@ public class DockerComputeServiceAdapterLiveTest extends BaseDockerApiLiveTest { } } - @AfterGroups(groups = "live") - protected void tearDown() { - if (guest != null) { - adapter.destroyNode(guest.getNode().id() + ""); - } - if (defaultImage != null) { - api.getImageApi().deleteImage(defaultImage.id(), DeleteImageOptions.Builder.force(true)); - } - super.tearDown(); - } - @Override protected Iterable setupModules() { return ImmutableSet.of(getLoggingModule(), new SshjSshClientModule()); diff --git a/apis/docker/src/test/java/org/jclouds/docker/compute/SshToCustomPortLiveTest.java b/apis/docker/src/test/java/org/jclouds/docker/compute/SshToCustomPortLiveTest.java index 62e1e5e848..cb35173c87 100644 --- a/apis/docker/src/test/java/org/jclouds/docker/compute/SshToCustomPortLiveTest.java +++ b/apis/docker/src/test/java/org/jclouds/docker/compute/SshToCustomPortLiveTest.java @@ -17,15 +17,15 @@ package org.jclouds.docker.compute; import static org.assertj.core.api.Assertions.assertThat; -import static org.jclouds.compute.options.TemplateOptions.Builder.runAsRoot; +import static org.jclouds.compute.options.RunScriptOptions.Builder.wrapInInitScript; +import static org.jclouds.docker.internal.DockerTestUtils.consumeStreamSilently; +import static org.jclouds.docker.internal.DockerTestUtils.removeImageIfExists; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.util.List; -import java.util.logging.Level; import org.jclouds.compute.RunNodesException; import org.jclouds.compute.domain.ExecResponse; @@ -104,8 +104,9 @@ public class SshToCustomPortLiveTest extends BaseComputeServiceContextLiveTest { @Test(dependsOnMethods = "testImageCreated") public void testCustomPortSsh() throws RunNodesException { final DockerTemplateOptions options = DockerTemplateOptions.Builder - .commands("/usr/sbin/dropbear", "-E", "-F", "-p", String.valueOf(SSH_PORT)).overrideLoginUser("root") - .overrideLoginPassword("screencast").blockOnPort(SSH_PORT, 30).networkMode("host"); + .env("SSH_PORT=" + SSH_PORT, "ROOT_PASSWORD=screencast") + .overrideLoginUser("root").overrideLoginPassword("screencast") + .blockOnPort(SSH_PORT, 30).networkMode("host"); final Template template = view.getComputeService().templateBuilder().imageId(image.id()).options(options).build(); @@ -115,8 +116,7 @@ public class SshToCustomPortLiveTest extends BaseComputeServiceContextLiveTest { .getOnlyElement(view.getComputeService().createNodesInGroup("ssh-test", 1, template)); nodeId = node.getId(); - ExecResponse response = view.getComputeService().runScriptOnNode(nodeId, "echo hello", - runAsRoot(false).wrapInInitScript(false)); + ExecResponse response = view.getComputeService().runScriptOnNode(nodeId, "sh -c 'echo hello && sleep 0.2'", wrapInInitScript(false)); assertThat(response.getOutput().trim()).endsWith("hello"); } finally { if (nodeId != null) @@ -133,8 +133,11 @@ public class SshToCustomPortLiveTest extends BaseComputeServiceContextLiveTest { @BeforeClass(groups = { "integration", "live" }) public void setupContext() { super.setupContext(); - final String tag = toTag(IMAGE_REPOSITORY, IMAGE_TAG_1); + + removeImageIfExists(api(), tag); + removeImageIfExists(api(), toTag(IMAGE_REPOSITORY, IMAGE_TAG_2)); + BuildOptions options = BuildOptions.Builder.tag(tag).verbose(false).nocache(false); InputStream buildImageStream; try { @@ -154,8 +157,8 @@ public class SshToCustomPortLiveTest extends BaseComputeServiceContextLiveTest { */ @AfterClass(alwaysRun = true) protected void tearDown() { - consumeStreamSilently(api().getImageApi().deleteImage(toTag(IMAGE_REPOSITORY, IMAGE_TAG_1))); - consumeStreamSilently(api().getImageApi().deleteImage(toTag(IMAGE_REPOSITORY, IMAGE_TAG_2))); + removeImageIfExists(api(), toTag(IMAGE_REPOSITORY, IMAGE_TAG_1)); + removeImageIfExists(api(), toTag(IMAGE_REPOSITORY, IMAGE_TAG_2)); } /** @@ -188,29 +191,6 @@ public class SshToCustomPortLiveTest extends BaseComputeServiceContextLiveTest { return view.unwrapApi(DockerApi.class); } - /** - * Read all data from given InputStream and throw away all the bits. - * - * @param is - */ - private static void consumeStreamSilently(InputStream is) { - char[] tmpBuff = new char[8 * 1024]; - // throw everything away - InputStreamReader isr = new InputStreamReader(is); - - try { - try { - while (isr.read(tmpBuff) > -1) { - // empty - } - } finally { - isr.close(); - } - } catch (IOException e) { - java.util.logging.Logger.getAnonymousLogger().log(Level.WARNING, "Error ocured during reading InputStream.", e); - } - } - /** * Concatenate repository and tag name (if provided) in Docker format. * @@ -221,4 +201,5 @@ public class SshToCustomPortLiveTest extends BaseComputeServiceContextLiveTest { private static String toTag(String repo, String tag) { return repo + (tag != null ? ":" + tag : ""); } + } diff --git a/apis/docker/src/test/java/org/jclouds/docker/features/ContainerApiLiveTest.java b/apis/docker/src/test/java/org/jclouds/docker/features/ContainerApiLiveTest.java index 295eb5b915..1b23b07b83 100644 --- a/apis/docker/src/test/java/org/jclouds/docker/features/ContainerApiLiveTest.java +++ b/apis/docker/src/test/java/org/jclouds/docker/features/ContainerApiLiveTest.java @@ -67,9 +67,6 @@ public class ContainerApiLiveTest extends BaseDockerApiLiveTest { api.getContainerApi().removeContainer(container.id(), RemoveContainerOptions.Builder.force(true)); } } - if (image != null) { - api.getImageApi().deleteImage(ALPINE_IMAGE_TAG); - } } public void testCreateContainer() throws IOException, InterruptedException { diff --git a/apis/docker/src/test/java/org/jclouds/docker/features/MiscApiLiveTest.java b/apis/docker/src/test/java/org/jclouds/docker/features/MiscApiLiveTest.java index 95b749bd7d..c9c69dc7ef 100644 --- a/apis/docker/src/test/java/org/jclouds/docker/features/MiscApiLiveTest.java +++ b/apis/docker/src/test/java/org/jclouds/docker/features/MiscApiLiveTest.java @@ -51,6 +51,8 @@ import com.google.common.collect.Iterables; @Test(groups = "live", testName = "MiscApiLiveTest", singleThreaded = true) public class MiscApiLiveTest extends BaseDockerApiLiveTest { + private static final String IMAGE_TEST_TAG = "jclouds-test-test-build-image"; + private static String imageId; private Container container = null; @@ -105,14 +107,19 @@ public class MiscApiLiveTest extends BaseDockerApiLiveTest { @Test public void testBuildImageFromDockerfile() throws IOException, InterruptedException, URISyntaxException { - BuildOptions options = BuildOptions.Builder.tag("jclouds-test-test-build-image").verbose(false).nocache(false); + removeImageIfExists(IMAGE_TEST_TAG); + BuildOptions options = BuildOptions.Builder.tag(IMAGE_TEST_TAG).verbose(false).nocache(true); InputStream buildImageStream = api().build(tarredDockerfile(), options); String buildStream = consumeStream(buildImageStream); - Iterable splitted = Splitter.on("\n").split(buildStream.replace("\r", "").trim()); - String lastStreamedLine = Iterables.getLast(splitted).trim(); - String rawImageId = Iterables.getLast(Splitter.on("Successfully built ").split(lastStreamedLine)); - imageId = rawImageId.substring(0, 11); - assertNotNull(imageId); + try { + Iterable splitted = Splitter.on("\n").split(buildStream.replace("\r", "").trim()); + String lastStreamedLine = Iterables.getLast(splitted).trim(); + String rawImageId = Iterables.getLast(Splitter.on("Successfully built ").split(lastStreamedLine)); + imageId = rawImageId.substring(0, 11); + assertNotNull(imageId); + } finally { + removeImageIfExists(IMAGE_TEST_TAG); + } } @Test @@ -168,7 +175,6 @@ public class MiscApiLiveTest extends BaseDockerApiLiveTest { assertEquals(execInspect.exitCode(), 2); } - private MiscApi api() { return api.getMiscApi(); } diff --git a/apis/docker/src/test/java/org/jclouds/docker/internal/DockerTestUtils.java b/apis/docker/src/test/java/org/jclouds/docker/internal/DockerTestUtils.java new file mode 100644 index 0000000000..102684af93 --- /dev/null +++ b/apis/docker/src/test/java/org/jclouds/docker/internal/DockerTestUtils.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.jclouds.docker.internal; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.logging.Level; + +import org.jclouds.docker.DockerApi; +import org.jclouds.docker.features.ImageApi; + +import com.google.common.base.Preconditions; + +/** + * Utility methods shared by Docker tests. + */ +public class DockerTestUtils { + + /** + * Read all data from given {@link InputStream} and throw away all the bits. + * If an {@link IOException} occurs, it's not propagated to user. The given InputStream is closed after the read. + * + * @param is InputStream instance (may be null) + */ + public static void consumeStreamSilently(InputStream is) { + if (is == null) { + return; + } + char[] tmpBuff = new char[8 * 1024]; + // throw everything away + InputStreamReader isr = new InputStreamReader(is); + try { + try { + while (isr.read(tmpBuff) > -1) { + // empty + } + } finally { + isr.close(); + } + } catch (IOException e) { + java.util.logging.Logger.getAnonymousLogger().log(Level.WARNING, "Error ocured during reading InputStream.", e); + } + } + + /** + * Removes Docker image if it's present on the Docker host. Docker Image API + * is used to inspect and remove image (({@link ImageApi#deleteImage(String)} + * method). + * + * @param dockerApi + * DockerApi instance (must be not-null) + * @param imageName + * image to be deleted (must be not-null) + */ + public static void removeImageIfExists(DockerApi dockerApi, String imageName) { + Preconditions.checkNotNull(dockerApi, "DockerApi instance has to be provided"); + Preconditions.checkNotNull(imageName, "Docker image name has to be provided"); + final ImageApi imageApi = dockerApi.getImageApi(); + if (null != imageApi.inspectImage(imageName)) { + consumeStreamSilently(imageApi.deleteImage(imageName)); + } + } +} diff --git a/apis/docker/src/test/resources/Dockerfile b/apis/docker/src/test/resources/Dockerfile index f375d33e25..0cedc5e20a 100644 --- a/apis/docker/src/test/resources/Dockerfile +++ b/apis/docker/src/test/resources/Dockerfile @@ -16,19 +16,5 @@ # -FROM alpine:3.2 +FROM kwart/alpine-ext:3.3-ssh MAINTAINER JClouds Dev - -ENV DROPBEAR_CONF=/etc/dropbear - -RUN apk add --update dropbear \ - && mkdir -p ${DROPBEAR_CONF} \ - && dropbearkey -t dss -f ${DROPBEAR_CONF}/dropbear_dss_host_key \ - && dropbearkey -t rsa -f ${DROPBEAR_CONF}/dropbear_rsa_host_key -s 2048 \ - && dropbearkey -t ecdsa -f ${DROPBEAR_CONF}/dropbear_ecdsa_host_key - -RUN echo 'root:screencast' | chpasswd - -EXPOSE 22 - -CMD ["/usr/sbin/dropbear", "-E", "-F"]