[JCLOUDS-1084] Docker live tests fixed and made more robust

This commit is contained in:
Josef Cacek 2016-02-19 12:33:24 +01:00 committed by Ignasi Barrera
parent b6e20822d8
commit 3f1fe271ed
8 changed files with 133 additions and 75 deletions

View File

@ -38,6 +38,7 @@
<test.docker.identity>${env.DOCKER_CERT_PATH}/cert.pem</test.docker.identity> <test.docker.identity>${env.DOCKER_CERT_PATH}/cert.pem</test.docker.identity>
<test.docker.credential>${env.DOCKER_CERT_PATH}/key.pem</test.docker.credential> <test.docker.credential>${env.DOCKER_CERT_PATH}/key.pem</test.docker.credential>
<test.docker.cacert.path>${env.DOCKER_CERT_PATH}/ca.pem</test.docker.cacert.path> <test.docker.cacert.path>${env.DOCKER_CERT_PATH}/ca.pem</test.docker.cacert.path>
<test.docker.endpoint>${env.DOCKER_HOST}</test.docker.endpoint>
<test.jclouds.trust-all-certs>false</test.jclouds.trust-all-certs> <test.jclouds.trust-all-certs>false</test.jclouds.trust-all-certs>
<jclouds.osgi.export>org.jclouds.docker*;version="${project.version}"</jclouds.osgi.export> <jclouds.osgi.export>org.jclouds.docker*;version="${project.version}"</jclouds.osgi.export>
<jclouds.osgi.import> <jclouds.osgi.import>
@ -151,7 +152,7 @@
</goals> </goals>
<configuration> <configuration>
<name>test.docker.endpoint</name> <name>test.docker.endpoint</name>
<value>${env.DOCKER_HOST}</value> <value>${test.docker.endpoint}</value>
<regex>tcp</regex> <regex>tcp</regex>
<replacement>https</replacement> <replacement>https</replacement>
<failIfNoMatch>false</failIfNoMatch> <failIfNoMatch>false</failIfNoMatch>

View File

@ -33,6 +33,7 @@ import org.jclouds.Constants;
import org.jclouds.apis.BaseApiLiveTest; import org.jclouds.apis.BaseApiLiveTest;
import org.jclouds.compute.config.ComputeServiceProperties; import org.jclouds.compute.config.ComputeServiceProperties;
import org.jclouds.docker.DockerApi; import org.jclouds.docker.DockerApi;
import org.jclouds.docker.internal.DockerTestUtils;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
import org.jclouds.io.Payloads; import org.jclouds.io.Payloads;
import org.jclouds.sshj.config.SshjSshClientModule; import org.jclouds.sshj.config.SshjSshClientModule;
@ -46,7 +47,7 @@ import com.google.inject.Module;
public class BaseDockerApiLiveTest extends BaseApiLiveTest<DockerApi> { public class BaseDockerApiLiveTest extends BaseApiLiveTest<DockerApi> {
protected static final String DEFAULT_IMAGE = "alpine"; 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); protected static final String ALPINE_IMAGE_TAG = String.format("%s:%s", DEFAULT_IMAGE, DEFAULT_TAG);
@ -54,6 +55,17 @@ public class BaseDockerApiLiveTest extends BaseApiLiveTest<DockerApi> {
provider = "docker"; provider = "docker";
} }
/**
* Removes Docker image if it's present on the Docker host.
*
* @param imageName
* image to be deleted (must be not-<code>null</code>)
* @see DockerTestUtils#removeImageIfExists(DockerApi, String)
*/
protected void removeImageIfExists(String imageName) {
DockerTestUtils.removeImageIfExists(api, imageName);
}
@Override @Override
protected Iterable<Module> setupModules() { protected Iterable<Module> setupModules() {
return ImmutableSet.<Module>of(getLoggingModule(), new SshjSshClientModule()); return ImmutableSet.<Module>of(getLoggingModule(), new SshjSshClientModule());

View File

@ -19,6 +19,7 @@ package org.jclouds.docker.compute;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNotNull;
import java.util.Properties; import java.util.Properties;
import java.util.Random; 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.Container;
import org.jclouds.docker.domain.Image; import org.jclouds.docker.domain.Image;
import org.jclouds.docker.options.CreateImageOptions; import org.jclouds.docker.options.CreateImageOptions;
import org.jclouds.docker.options.DeleteImageOptions;
import org.jclouds.sshj.config.SshjSshClientModule; 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.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -48,7 +48,7 @@ import com.google.inject.Module;
public class DockerComputeServiceAdapterLiveTest extends BaseDockerApiLiveTest { public class DockerComputeServiceAdapterLiveTest extends BaseDockerApiLiveTest {
private static final String SSHABLE_IMAGE = "kwart/alpine-ext"; 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 Image defaultImage;
private DockerComputeServiceAdapter adapter; private DockerComputeServiceAdapter adapter;
@ -68,6 +68,14 @@ public class DockerComputeServiceAdapterLiveTest extends BaseDockerApiLiveTest {
assertNotNull(defaultImage); assertNotNull(defaultImage);
} }
@AfterClass(alwaysRun = true)
protected void tearDown() {
if (guest != null) {
adapter.destroyNode(guest.getNode().id() + "");
}
super.tearDown();
}
@Override @Override
protected DockerApi create(Properties props, Iterable<Module> modules) { protected DockerApi create(Properties props, Iterable<Module> modules) {
Injector injector = newBuilder().modules(modules).overrides(props).buildInjector(); Injector injector = newBuilder().modules(modules).overrides(props).buildInjector();
@ -83,7 +91,7 @@ public class DockerComputeServiceAdapterLiveTest extends BaseDockerApiLiveTest {
Template template = templateBuilder.imageId(defaultImage.id()).build(); Template template = templateBuilder.imageId(defaultImage.id()).build();
DockerTemplateOptions options = template.getOptions().as(DockerTemplateOptions.class); 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); guest = adapter.createNodeWithGroupEncodedIntoName(group, name, template);
assertEquals(guest.getNodeId(), guest.getNode().id()); 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 @Override
protected Iterable<Module> setupModules() { protected Iterable<Module> setupModules() {
return ImmutableSet.<Module>of(getLoggingModule(), new SshjSshClientModule()); return ImmutableSet.<Module>of(getLoggingModule(), new SshjSshClientModule());

View File

@ -17,15 +17,15 @@
package org.jclouds.docker.compute; package org.jclouds.docker.compute;
import static org.assertj.core.api.Assertions.assertThat; 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.assertEquals;
import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNotNull;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List; import java.util.List;
import java.util.logging.Level;
import org.jclouds.compute.RunNodesException; import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.ExecResponse;
@ -104,8 +104,9 @@ public class SshToCustomPortLiveTest extends BaseComputeServiceContextLiveTest {
@Test(dependsOnMethods = "testImageCreated") @Test(dependsOnMethods = "testImageCreated")
public void testCustomPortSsh() throws RunNodesException { public void testCustomPortSsh() throws RunNodesException {
final DockerTemplateOptions options = DockerTemplateOptions.Builder final DockerTemplateOptions options = DockerTemplateOptions.Builder
.commands("/usr/sbin/dropbear", "-E", "-F", "-p", String.valueOf(SSH_PORT)).overrideLoginUser("root") .env("SSH_PORT=" + SSH_PORT, "ROOT_PASSWORD=screencast")
.overrideLoginPassword("screencast").blockOnPort(SSH_PORT, 30).networkMode("host"); .overrideLoginUser("root").overrideLoginPassword("screencast")
.blockOnPort(SSH_PORT, 30).networkMode("host");
final Template template = view.getComputeService().templateBuilder().imageId(image.id()).options(options).build(); 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)); .getOnlyElement(view.getComputeService().createNodesInGroup("ssh-test", 1, template));
nodeId = node.getId(); nodeId = node.getId();
ExecResponse response = view.getComputeService().runScriptOnNode(nodeId, "echo hello", ExecResponse response = view.getComputeService().runScriptOnNode(nodeId, "sh -c 'echo hello && sleep 0.2'", wrapInInitScript(false));
runAsRoot(false).wrapInInitScript(false));
assertThat(response.getOutput().trim()).endsWith("hello"); assertThat(response.getOutput().trim()).endsWith("hello");
} finally { } finally {
if (nodeId != null) if (nodeId != null)
@ -133,8 +133,11 @@ public class SshToCustomPortLiveTest extends BaseComputeServiceContextLiveTest {
@BeforeClass(groups = { "integration", "live" }) @BeforeClass(groups = { "integration", "live" })
public void setupContext() { public void setupContext() {
super.setupContext(); super.setupContext();
final String tag = toTag(IMAGE_REPOSITORY, IMAGE_TAG_1); 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); BuildOptions options = BuildOptions.Builder.tag(tag).verbose(false).nocache(false);
InputStream buildImageStream; InputStream buildImageStream;
try { try {
@ -154,8 +157,8 @@ public class SshToCustomPortLiveTest extends BaseComputeServiceContextLiveTest {
*/ */
@AfterClass(alwaysRun = true) @AfterClass(alwaysRun = true)
protected void tearDown() { protected void tearDown() {
consumeStreamSilently(api().getImageApi().deleteImage(toTag(IMAGE_REPOSITORY, IMAGE_TAG_1))); removeImageIfExists(api(), toTag(IMAGE_REPOSITORY, IMAGE_TAG_1));
consumeStreamSilently(api().getImageApi().deleteImage(toTag(IMAGE_REPOSITORY, IMAGE_TAG_2))); removeImageIfExists(api(), toTag(IMAGE_REPOSITORY, IMAGE_TAG_2));
} }
/** /**
@ -188,29 +191,6 @@ public class SshToCustomPortLiveTest extends BaseComputeServiceContextLiveTest {
return view.unwrapApi(DockerApi.class); 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. * 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) { private static String toTag(String repo, String tag) {
return repo + (tag != null ? ":" + tag : ""); return repo + (tag != null ? ":" + tag : "");
} }
} }

View File

@ -67,9 +67,6 @@ public class ContainerApiLiveTest extends BaseDockerApiLiveTest {
api.getContainerApi().removeContainer(container.id(), RemoveContainerOptions.Builder.force(true)); api.getContainerApi().removeContainer(container.id(), RemoveContainerOptions.Builder.force(true));
} }
} }
if (image != null) {
api.getImageApi().deleteImage(ALPINE_IMAGE_TAG);
}
} }
public void testCreateContainer() throws IOException, InterruptedException { public void testCreateContainer() throws IOException, InterruptedException {

View File

@ -51,6 +51,8 @@ import com.google.common.collect.Iterables;
@Test(groups = "live", testName = "MiscApiLiveTest", singleThreaded = true) @Test(groups = "live", testName = "MiscApiLiveTest", singleThreaded = true)
public class MiscApiLiveTest extends BaseDockerApiLiveTest { public class MiscApiLiveTest extends BaseDockerApiLiveTest {
private static final String IMAGE_TEST_TAG = "jclouds-test-test-build-image";
private static String imageId; private static String imageId;
private Container container = null; private Container container = null;
@ -105,14 +107,19 @@ public class MiscApiLiveTest extends BaseDockerApiLiveTest {
@Test @Test
public void testBuildImageFromDockerfile() throws IOException, InterruptedException, URISyntaxException { 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); InputStream buildImageStream = api().build(tarredDockerfile(), options);
String buildStream = consumeStream(buildImageStream); String buildStream = consumeStream(buildImageStream);
Iterable<String> splitted = Splitter.on("\n").split(buildStream.replace("\r", "").trim()); try {
String lastStreamedLine = Iterables.getLast(splitted).trim(); Iterable<String> splitted = Splitter.on("\n").split(buildStream.replace("\r", "").trim());
String rawImageId = Iterables.getLast(Splitter.on("Successfully built ").split(lastStreamedLine)); String lastStreamedLine = Iterables.getLast(splitted).trim();
imageId = rawImageId.substring(0, 11); String rawImageId = Iterables.getLast(Splitter.on("Successfully built ").split(lastStreamedLine));
assertNotNull(imageId); imageId = rawImageId.substring(0, 11);
assertNotNull(imageId);
} finally {
removeImageIfExists(IMAGE_TEST_TAG);
}
} }
@Test @Test
@ -168,7 +175,6 @@ public class MiscApiLiveTest extends BaseDockerApiLiveTest {
assertEquals(execInspect.exitCode(), 2); assertEquals(execInspect.exitCode(), 2);
} }
private MiscApi api() { private MiscApi api() {
return api.getMiscApi(); return api.getMiscApi();
} }

View File

@ -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-<code>null</code>)
* @param imageName
* image to be deleted (must be not-<code>null</code>)
*/
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));
}
}
}

View File

@ -16,19 +16,5 @@
# #
FROM alpine:3.2 FROM kwart/alpine-ext:3.3-ssh
MAINTAINER JClouds Dev <dev@jclouds.apache.org> MAINTAINER JClouds Dev <dev@jclouds.apache.org>
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"]