Add LiveTest to cover loginPort (SSH) customization in Docker.
Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/3260fa58 Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/3260fa58 Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/3260fa58 Branch: refs/heads/master Commit: 3260fa5803048fe189a297cbd031fa1b97473438 Parents: f0fc31e Author: Josef Cacek <[email protected]> Authored: Tue Oct 20 18:54:58 2015 +0200 Committer: Ignasi Barrera <[email protected]> Committed: Wed Oct 21 16:10:29 2015 +0200 ---------------------------------------------------------------------- .../docker/compute/SshToCustomPortLiveTest.java | 224 +++++++++++++++++++ 1 file changed, 224 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds/blob/3260fa58/apis/docker/src/test/java/org/jclouds/docker/compute/SshToCustomPortLiveTest.java ---------------------------------------------------------------------- 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 new file mode 100644 index 0000000..62e1e5e --- /dev/null +++ b/apis/docker/src/test/java/org/jclouds/docker/compute/SshToCustomPortLiveTest.java @@ -0,0 +1,224 @@ +/* + * 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.compute; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.jclouds.compute.options.TemplateOptions.Builder.runAsRoot; +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; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest; +import org.jclouds.docker.DockerApi; +import org.jclouds.docker.compute.functions.LoginPortForContainer; +import org.jclouds.docker.compute.options.DockerTemplateOptions; +import org.jclouds.docker.domain.Container; +import org.jclouds.docker.domain.Image; +import org.jclouds.docker.domain.ImageSummary; +import org.jclouds.docker.options.BuildOptions; +import org.jclouds.sshj.config.SshjSshClientModule; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.inject.AbstractModule; +import com.google.inject.Module; + +/** + * This class tests configuring custom SSH port for Docker images. + */ +@Test(groups = "live", testName = "SshToCustomPortLiveTest", singleThreaded = true) +public class SshToCustomPortLiveTest extends BaseComputeServiceContextLiveTest { + + private static final int SSH_PORT = 8822; + private static final String IMAGE_REPOSITORY = "jclouds/testrepo"; + private static final String IMAGE_TAG_1 = "testtag"; + private static final String IMAGE_TAG_2 = "second"; + + private Image image; + + public SshToCustomPortLiveTest() { + provider = "docker"; + } + + /** + * Asserts that the new image exists and tags were created successfully in + * the test preparation phase ({@link #setupContext()} method). + */ + @Test + public void testImageCreated() { + assertNotNull(image); + + final String imageId = image.id(); + assertNotNull(imageId); + + List<ImageSummary> listImages = api().getImageApi().listImages(); + assertNotNull(listImages); + ImageSummary testImage = Iterables.find(listImages, new Predicate<ImageSummary>() { + @Override + public boolean apply(ImageSummary input) { + return imageId.equals(input.id()); + } + }); + + assertEquals(testImage.repoTags().size(), 2, "Unexpected number of tags on the image."); + assertThat(testImage.repoTags()).contains(toTag(IMAGE_REPOSITORY, IMAGE_TAG_1), + toTag(IMAGE_REPOSITORY, IMAGE_TAG_2)); + } + + /** + * Start a node from the newly created image. The dropbear SSH server running + * on custom port ( {@value #SSH_PORT}). The Docker networkMode used is + * "host". Execute a command through the SSH connection and check the result. + * Destroy the node when finished. + * + * @throws RunNodesException + */ + @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"); + + final Template template = view.getComputeService().templateBuilder().imageId(image.id()).options(options).build(); + + String nodeId = null; + try { + NodeMetadata node = Iterables + .getOnlyElement(view.getComputeService().createNodesInGroup("ssh-test", 1, template)); + + nodeId = node.getId(); + ExecResponse response = view.getComputeService().runScriptOnNode(nodeId, "echo hello", + runAsRoot(false).wrapInInitScript(false)); + assertThat(response.getOutput().trim()).endsWith("hello"); + } finally { + if (nodeId != null) + view.getComputeService().destroyNode(nodeId); + } + } + + /** + * Build a new image with 2 tags on it in the test preparation phase. + * + * @see org.jclouds.apis.BaseContextLiveTest#setupContext() + */ + @Override + @BeforeClass(groups = { "integration", "live" }) + public void setupContext() { + super.setupContext(); + + final String tag = toTag(IMAGE_REPOSITORY, IMAGE_TAG_1); + BuildOptions options = BuildOptions.Builder.tag(tag).verbose(false).nocache(false); + InputStream buildImageStream; + try { + buildImageStream = api().getMiscApi().build(BaseDockerApiLiveTest.tarredDockerfile(), options); + consumeStreamSilently(buildImageStream); + } catch (IOException e) { + throw new RuntimeException("Error occured during building Docker image.", e); + } + image = api().getImageApi().inspectImage(tag); + api().getImageApi().tagImage(image.id(), IMAGE_REPOSITORY, IMAGE_TAG_2, true); + } + + /** + * After the test remove created image (with all tags). + * + * @see #setupContext() + */ + @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))); + } + + /** + * Configure used modules. A custom {@link LoginPortForContainer} binding is + * added among logging and SSH module. + * + * @see org.jclouds.compute.internal.BaseGenericComputeServiceContextLiveTest#setupModules() + */ + @Override + protected Iterable<Module> setupModules() { + return ImmutableSet.<Module> of(getLoggingModule(), new SshjSshClientModule(), new AbstractModule() { + @Override + protected void configure() { + bind(LoginPortForContainer.class).toInstance(new LoginPortForContainer() { + @Override + public Optional<Integer> apply(Container input) { + return Optional.of(SSH_PORT); + } + }); + } + }); + } + + /** + * Return DockerApi for current Context. + * + * @return + */ + private DockerApi api() { + 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. + * + * @param repo + * @param tag + * @return + */ + private static String toTag(String repo, String tag) { + return repo + (tag != null ? ":" + tag : ""); + } +}
