add docker client

This commit is contained in:
tuna 2014-03-26 02:45:37 +07:00
parent cd4444cfec
commit cd8a4520b7
43 changed files with 5114 additions and 0 deletions

21
docker-java/.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
#Ignore Mac OS X DS Store
.DS_Store
*~
*.swp
.project
.settings
.classpath
# Ignore all build/dist directories
target
# Ignore InteliJ Idea project files
.idea
.idea/*
*.iml
*.iws
*.ipr
# Ignore all log files
*.log

202
docker-java/LICENSE Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

114
docker-java/README.md Normal file
View File

@ -0,0 +1,114 @@
# docker-java
Java API client for [Docker](http://docs.docker.io/ "Docker")
Supports a subset of the Docker Client API v1.8, Docker Server version 0.8.1
## Build with Maven
###### Prerequisites:
* Java 1.6+
* Maven 3.0.5
* Docker daemon running
Maven will run tests during build process. Tests are using localhost instance of Docker, make sure that
you have Docker running for tests to work or just turn off tests.
If you don't have Docker running locally, you can skip tests with -DskipTests flag set to true:
$ mvn clean install -DskipTests=true
By default Docker server is using UNIX sockets for communication with the Docker client, however docker-java
client uses TCP/IP to connect to the Docker server, so you will need to make sure that your Docker server is
listening on TCP port. To allow Docker server to use TCP add the following line to /etc/default/docker
DOCKER_OPTS="-H tcp://127.0.0.1:4243 -H unix:///var/run/docker.sock"
More details setting up docket server can be found in official documentation: http://docs.docker.io/en/latest/use/basics/
Now make sure that docker is up:
$ docker -H tcp://127.0.0.1:4243 version
Client version: 0.8.1
Go version (client): go1.2
Git commit (client): a1598d1
Server version: 0.8.1
Git commit (server): a1598d1
Go version (server): go1.2
Last stable version: 0.8.1
Run build with tests:
$ mvn clean install
## Docker-Java maven dependency:
<dependency>
<groupId>com.kpelykh</groupId>
<artifactId>docker-java</artifactId>
<version>0.8.1</version>
</dependency>
## Example code snippets:
DockerClient dockerClient = new DockerClient("http://localhost:4243");
###### Get Docker info:
Info info = dockerClient.info();
System.out.print(info);
###### Search Docker repository:
List<SearchItem> dockerSearch = dockerClient.search("busybox");
System.out.println("Search returned" + dockerSearch.toString());
###### Create new Docker container, wait for its start and stop it:
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.setImage("busybox");
containerConfig.setCmd(new String[] {"touch", "/test"});
ContainerCreateResponse container = dockerClient.createContainer(containerConfig);
dockerClient.startContainer(container.id);
dockerClient.waitContainer(container.id);
dockerClient.stopContainer(container.id);
##### Support for UNIX sockets:
Support for UNIX socket should appear in docker-java pretty soon. I'm working on its integration.
##### Docker Builder:
To use Docker Builder, as described on page http://docs.docker.io/en/latest/use/builder/,
user dockerClient.build(baseDir), where baseDir is a path to folder containing Dockerfile.
File baseDir = new File("~/kpelykh/docker/netcat");
ClientResponse response = dockerClient.build(baseDir);
StringWriter logwriter = new StringWriter();
try {
LineIterator itr = IOUtils.lineIterator(response.getEntityInputStream(), "UTF-8");
while (itr.hasNext()) {
String line = itr.next();
logwriter.write(line);
LOG.info(line);
}
} finally {
IOUtils.closeQuietly(response.getEntityInputStream());
}
For additional examples, please look at [DockerClientTest.java](https://github.com/kpelykh/docker-java/blob/master/src/test/java/com/kpelykh/docker/client/test/DockerClientTest.java "DockerClientTest.java")

292
docker-java/pom.xml Normal file
View File

@ -0,0 +1,292 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>com.kpelykh</groupId>
<artifactId>docker-java</artifactId>
<packaging>jar</packaging>
<version>0.8.2-SNAPSHOT</version>
<name>docker-java</name>
<url>https://github.com/kpelykh/docker-java</url>
<description>Java API Client for Docker</description>
<scm>
<connection>scm:git:git@github.com:kpelykh/docker-java.git</connection>
<url>git@github.com:kpelykh/docker-java.git</url>
<developerConnection>scm:git:git@github.com:kpelykh/docker-java.git</developerConnection>
<tag>HEAD</tag>
</scm>
<developers>
<developer>
<id>kpelykh</id>
<name>Konstantin Pelykh</name>
<email>kpelykh@gmail.com</email>
</developer>
</developers>
<properties>
<skipTests>true</skipTests>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jdk.debug>true</jdk.debug>
<jdk.optimize>false</jdk.optimize>
<jdk.source>1.6</jdk.source>
<jdk.target>1.6</jdk.target>
<version.slf4j>1.6.1</version.slf4j>
<jersey.version>1.18</jersey.version>
<jersey-apache-client4.version>1.9</jersey-apache-client4.version>
<httpclient.version>4.2.5</httpclient.version>
<commons-compress.version>1.5</commons-compress.version>
<commons-io.version>2.3</commons-io.version>
<commons-lang.version>2.6</commons-lang.version>
<slf4j-api.version>1.7.5</slf4j-api.version>
<jsr305.version>1.3.9</jsr305.version>
<jnr.unixsocket.version>0.3</jnr.unixsocket.version>
<!--test dependencies -->
<version.logback>1.0.1</version.logback>
<version.testng>5.12.1</version.testng>
<hamcrest.library.version>1.3</hamcrest.library.version>
<hamcrest.jpa-matchers>1.6</hamcrest.jpa-matchers>
<lambdaj.version>2.3.3</lambdaj.version>
<maven-jar-plugin.version>2.2</maven-jar-plugin.version>
<maven-compiler-plugin.version>2.3.1</maven-compiler-plugin.version>
<maven-release-plugin.version>2.3.1</maven-release-plugin.version>
<maven-surefire-plugin.version>2.8.1</maven-surefire-plugin.version>
<cobertura-maven-plugin.version>2.5.1</cobertura-maven-plugin.version>
<maven-antrun-plugin.version>1.7</maven-antrun-plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-multipart</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-apache-client4</artifactId>
<version>${jersey-apache-client4.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>${commons-compress.version}</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>${commons-lang.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-unixsocket</artifactId>
<version>${jnr.unixsocket.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j-api.version}</version>
</dependency>
<!-- /// Test /////////////////////////// -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${version.logback}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${version.logback}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${version.testng}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>${hamcrest.library.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.googlecode.lambdaj</groupId>
<artifactId>lambdaj</artifactId>
<version>${lambdaj.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.testinfected.hamcrest-matchers</groupId>
<artifactId>jpa-matchers</artifactId>
<version>${hamcrest.jpa-matchers}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>${maven-release-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${jdk.source}</source>
<target>${jdk.target}</target>
<encoding>ISO-8859-1</encoding>
<debug>${jdk.debug}</debug>
<optimize>${jdk.optimize}</optimize>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<skipTests>${skipTests}</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>${cobertura-maven-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>${maven-antrun-plugin.version}</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo>*******************************************************************</echo>
<echo>*******************************************************************</echo>
<echo>[project.name] : ${project.name}</echo>
<echo>[project.basedir] : ${project.basedir}</echo>
<echo>[project.version] : ${project.version}</echo>
<echo>[project.artifactId] ${project.artifactId}</echo>
<echo>[project.build.directory] ${project.build.directory}</echo>
<echo>[jdk.source] : ${jdk.source}</echo>
<echo>[jdk.target] : ${jdk.target}</echo>
<echo>[jdk.debug] : ${jdk.debug}</echo>
<echo>[jdk.optimize] : ${jdk.optimize}</echo>
<echo>[source encoding]: ${project.build.sourceEncoding}</echo>
<echo>[M2_HOME] : ${env.M2_HOME}</echo>
<echo>[LocalRepository] : ${settings.localRepository}</echo>
<echo>*******************************************************************</echo>
<echo>*******************************************************************</echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View File

@ -0,0 +1,443 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* 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 com.google.common.base;
import java.util.NoSuchElementException;
/**
* Simple static methods to be called at the start of your own methods to verify
* correct arguments and state. This allows constructs such as
* <pre>
* if (count <= 0) {
* throw new IllegalArgumentException("must be positive: " + count);
* }</pre>
*
* to be replaced with the more compact
* <pre>
* checkArgument(count > 0, "must be positive: %s", count);</pre>
*
* Note that the sense of the expression is inverted; with {@code Preconditions}
* you declare what you expect to be <i>true</i>, just as you do with an
* <a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html">
* {@code assert}</a> or a JUnit {@code assertTrue} call.
*
* <p><b>Warning:</b> only the {@code "%s"} specifier is recognized as a
* placeholder in these messages, not the full range of {@link
* String#format(String, Object[])} specifiers.
*
* <p>Take care not to confuse precondition checking with other similar types
* of checks! Precondition exceptions -- including those provided here, but also
* {@link IndexOutOfBoundsException}, {@link NoSuchElementException}, {@link
* UnsupportedOperationException} and others -- are used to signal that the
* <i>calling method</i> has made an error. This tells the caller that it should
* not have invoked the method when it did, with the arguments it did, or
* perhaps ever. Postcondition or other invariant failures should not throw
* these types of exceptions.
*
* <p>See the Guava User Guide on <a href=
* "http://code.google.com/p/guava-libraries/wiki/PreconditionsExplained">
* using {@code Preconditions}</a>.
*
* @author Kevin Bourrillion
* @since 2.0 (imported from Google Collections Library)
*/
public final class Preconditions {
private Preconditions() {}
/**
* Ensures the truth of an expression involving one or more parameters to the
* calling method.
*
* @param expression a boolean expression
* @throws IllegalArgumentException if {@code expression} is false
*/
public static void checkArgument(boolean expression) {
if (!expression) {
throw new IllegalArgumentException();
}
}
/**
* Ensures the truth of an expression involving one or more parameters to the
* calling method.
*
* @param expression a boolean expression
* @param errorMessage the exception message to use if the check fails; will
* be converted to a string using {@link String#valueOf(Object)}
* @throws IllegalArgumentException if {@code expression} is false
*/
public static void checkArgument(
boolean expression, Object errorMessage) {
if (!expression) {
throw new IllegalArgumentException(String.valueOf(errorMessage));
}
}
/**
* Ensures the truth of an expression involving one or more parameters to the
* calling method.
*
* @param expression a boolean expression
* @param errorMessageTemplate a template for the exception message should the
* check fail. The message is formed by replacing each {@code %s}
* placeholder in the template with an argument. These are matched by
* position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
* Unmatched arguments will be appended to the formatted message in square
* braces. Unmatched placeholders will be left as-is.
* @param errorMessageArgs the arguments to be substituted into the message
* template. Arguments are converted to strings using
* {@link String#valueOf(Object)}.
* @throws IllegalArgumentException if {@code expression} is false
* @throws NullPointerException if the check fails and either {@code
* errorMessageTemplate} or {@code errorMessageArgs} is null (don't let
* this happen)
*/
public static void checkArgument(boolean expression,
String errorMessageTemplate,
Object... errorMessageArgs) {
if (!expression) {
throw new IllegalArgumentException(
format(errorMessageTemplate, errorMessageArgs));
}
}
/**
* Ensures the truth of an expression involving the state of the calling
* instance, but not involving any parameters to the calling method.
*
* @param expression a boolean expression
* @throws IllegalStateException if {@code expression} is false
*/
public static void checkState(boolean expression) {
if (!expression) {
throw new IllegalStateException();
}
}
/**
* Ensures the truth of an expression involving the state of the calling
* instance, but not involving any parameters to the calling method.
*
* @param expression a boolean expression
* @param errorMessage the exception message to use if the check fails; will
* be converted to a string using {@link String#valueOf(Object)}
* @throws IllegalStateException if {@code expression} is false
*/
public static void checkState(
boolean expression, Object errorMessage) {
if (!expression) {
throw new IllegalStateException(String.valueOf(errorMessage));
}
}
/**
* Ensures the truth of an expression involving the state of the calling
* instance, but not involving any parameters to the calling method.
*
* @param expression a boolean expression
* @param errorMessageTemplate a template for the exception message should the
* check fail. The message is formed by replacing each {@code %s}
* placeholder in the template with an argument. These are matched by
* position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
* Unmatched arguments will be appended to the formatted message in square
* braces. Unmatched placeholders will be left as-is.
* @param errorMessageArgs the arguments to be substituted into the message
* template. Arguments are converted to strings using
* {@link String#valueOf(Object)}.
* @throws IllegalStateException if {@code expression} is false
* @throws NullPointerException if the check fails and either {@code
* errorMessageTemplate} or {@code errorMessageArgs} is null (don't let
* this happen)
*/
public static void checkState(boolean expression,
String errorMessageTemplate,
Object... errorMessageArgs) {
if (!expression) {
throw new IllegalStateException(
format(errorMessageTemplate, errorMessageArgs));
}
}
/**
* Ensures that an object reference passed as a parameter to the calling
* method is not null.
*
* @param reference an object reference
* @return the non-null reference that was validated
* @throws NullPointerException if {@code reference} is null
*/
public static <T> T checkNotNull(T reference) {
if (reference == null) {
throw new NullPointerException();
}
return reference;
}
/**
* Ensures that an object reference passed as a parameter to the calling
* method is not null.
*
* @param reference an object reference
* @param errorMessage the exception message to use if the check fails; will
* be converted to a string using {@link String#valueOf(Object)}
* @return the non-null reference that was validated
* @throws NullPointerException if {@code reference} is null
*/
public static <T> T checkNotNull(T reference, Object errorMessage) {
if (reference == null) {
throw new NullPointerException(String.valueOf(errorMessage));
}
return reference;
}
/**
* Ensures that an object reference passed as a parameter to the calling
* method is not null.
*
* @param reference an object reference
* @param errorMessageTemplate a template for the exception message should the
* check fail. The message is formed by replacing each {@code %s}
* placeholder in the template with an argument. These are matched by
* position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
* Unmatched arguments will be appended to the formatted message in square
* braces. Unmatched placeholders will be left as-is.
* @param errorMessageArgs the arguments to be substituted into the message
* template. Arguments are converted to strings using
* {@link String#valueOf(Object)}.
* @return the non-null reference that was validated
* @throws NullPointerException if {@code reference} is null
*/
public static <T> T checkNotNull(T reference,
String errorMessageTemplate,
Object... errorMessageArgs) {
if (reference == null) {
// If either of these parameters is null, the right thing happens anyway
throw new NullPointerException(
format(errorMessageTemplate, errorMessageArgs));
}
return reference;
}
/*
* All recent hotspots (as of 2009) *really* like to have the natural code
*
* if (guardExpression) {
* throw new BadException(messageExpression);
* }
*
* refactored so that messageExpression is moved to a separate
* String-returning method.
*
* if (guardExpression) {
* throw new BadException(badMsg(...));
* }
*
* The alternative natural refactorings into void or Exception-returning
* methods are much slower. This is a big deal - we're talking factors of
* 2-8 in microbenchmarks, not just 10-20%. (This is a hotspot optimizer
* bug, which should be fixed, but that's a separate, big project).
*
* The coding pattern above is heavily used in java.util, e.g. in ArrayList.
* There is a RangeCheckMicroBenchmark in the JDK that was used to test this.
*
* But the methods in this class want to throw different exceptions,
* depending on the args, so it appears that this pattern is not directly
* applicable. But we can use the ridiculous, devious trick of throwing an
* exception in the middle of the construction of another exception.
* Hotspot is fine with that.
*/
/**
* Ensures that {@code index} specifies a valid <i>element</i> in an array,
* list or string of size {@code size}. An element index may range from zero,
* inclusive, to {@code size}, exclusive.
*
* @param index a user-supplied index identifying an element of an array, list
* or string
* @param size the size of that array, list or string
* @return the value of {@code index}
* @throws IndexOutOfBoundsException if {@code index} is negative or is not
* less than {@code size}
* @throws IllegalArgumentException if {@code size} is negative
*/
public static int checkElementIndex(int index, int size) {
return checkElementIndex(index, size, "index");
}
/**
* Ensures that {@code index} specifies a valid <i>element</i> in an array,
* list or string of size {@code size}. An element index may range from zero,
* inclusive, to {@code size}, exclusive.
*
* @param index a user-supplied index identifying an element of an array, list
* or string
* @param size the size of that array, list or string
* @param desc the text to use to describe this index in an error message
* @return the value of {@code index}
* @throws IndexOutOfBoundsException if {@code index} is negative or is not
* less than {@code size}
* @throws IllegalArgumentException if {@code size} is negative
*/
public static int checkElementIndex(
int index, int size, String desc) {
// Carefully optimized for execution by hotspot (explanatory comment above)
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException(badElementIndex(index, size, desc));
}
return index;
}
private static String badElementIndex(int index, int size, String desc) {
if (index < 0) {
return format("%s (%s) must not be negative", desc, index);
} else if (size < 0) {
throw new IllegalArgumentException("negative size: " + size);
} else { // index >= size
return format("%s (%s) must be less than size (%s)", desc, index, size);
}
}
/**
* Ensures that {@code index} specifies a valid <i>position</i> in an array,
* list or string of size {@code size}. A position index may range from zero
* to {@code size}, inclusive.
*
* @param index a user-supplied index identifying a position in an array, list
* or string
* @param size the size of that array, list or string
* @return the value of {@code index}
* @throws IndexOutOfBoundsException if {@code index} is negative or is
* greater than {@code size}
* @throws IllegalArgumentException if {@code size} is negative
*/
public static int checkPositionIndex(int index, int size) {
return checkPositionIndex(index, size, "index");
}
/**
* Ensures that {@code index} specifies a valid <i>position</i> in an array,
* list or string of size {@code size}. A position index may range from zero
* to {@code size}, inclusive.
*
* @param index a user-supplied index identifying a position in an array, list
* or string
* @param size the size of that array, list or string
* @param desc the text to use to describe this index in an error message
* @return the value of {@code index}
* @throws IndexOutOfBoundsException if {@code index} is negative or is
* greater than {@code size}
* @throws IllegalArgumentException if {@code size} is negative
*/
public static int checkPositionIndex(
int index, int size, String desc) {
// Carefully optimized for execution by hotspot (explanatory comment above)
if (index < 0 || index > size) {
throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc));
}
return index;
}
private static String badPositionIndex(int index, int size, String desc) {
if (index < 0) {
return format("%s (%s) must not be negative", desc, index);
} else if (size < 0) {
throw new IllegalArgumentException("negative size: " + size);
} else { // index > size
return format("%s (%s) must not be greater than size (%s)",
desc, index, size);
}
}
/**
* Ensures that {@code start} and {@code end} specify a valid <i>positions</i>
* in an array, list or string of size {@code size}, and are in order. A
* position index may range from zero to {@code size}, inclusive.
*
* @param start a user-supplied index identifying a starting position in an
* array, list or string
* @param end a user-supplied index identifying a ending position in an array,
* list or string
* @param size the size of that array, list or string
* @throws IndexOutOfBoundsException if either index is negative or is
* greater than {@code size}, or if {@code end} is less than {@code start}
* @throws IllegalArgumentException if {@code size} is negative
*/
public static void checkPositionIndexes(int start, int end, int size) {
// Carefully optimized for execution by hotspot (explanatory comment above)
if (start < 0 || end < start || end > size) {
throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size));
}
}
private static String badPositionIndexes(int start, int end, int size) {
if (start < 0 || start > size) {
return badPositionIndex(start, size, "start index");
}
if (end < 0 || end > size) {
return badPositionIndex(end, size, "end index");
}
// end < start
return format("end index (%s) must not be less than start index (%s)",
end, start);
}
/**
* Substitutes each {@code %s} in {@code template} with an argument. These
* are matched by position - the first {@code %s} gets {@code args[0]}, etc.
* If there are more arguments than placeholders, the unmatched arguments will
* be appended to the end of the formatted message in square braces.
*
* @param template a non-null string containing 0 or more {@code %s}
* placeholders.
* @param args the arguments to be substituted into the message
* template. Arguments are converted to strings using
* {@link String#valueOf(Object)}. Arguments can be null.
*/
static String format(String template, Object... args) {
template = String.valueOf(template); // null -> "null"
// start substituting the arguments into the '%s' placeholders
StringBuilder builder = new StringBuilder(
template.length() + 16 * args.length);
int templateStart = 0;
int i = 0;
while (i < args.length) {
int placeholderStart = template.indexOf("%s", templateStart);
if (placeholderStart == -1) {
break;
}
builder.append(template.substring(templateStart, placeholderStart));
builder.append(args[i++]);
templateStart = placeholderStart + 2;
}
builder.append(template.substring(templateStart));
// if we run out of placeholders, append the extra args in square braces
if (i < args.length) {
builder.append(" [");
builder.append(args[i++]);
while (i < args.length) {
builder.append(", ");
builder.append(args[i++]);
}
builder.append(']');
}
return builder.toString();
}
}

View File

@ -0,0 +1,767 @@
package com.kpelykh.docker.client;
import com.google.common.base.Preconditions;
import com.kpelykh.docker.client.model.*;
import com.kpelykh.docker.client.utils.CompressArchiveUtil;
import com.kpelykh.docker.client.utils.JsonClientFilter;
import com.sun.jersey.api.client.*;
import com.sun.jersey.api.client.WebResource.Builder;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.client.filter.LoggingFilter;
import com.sun.jersey.api.json.JSONConfiguration;
import com.sun.jersey.client.apache4.ApacheHttpClient4;
import com.sun.jersey.client.apache4.ApacheHttpClient4Handler;
import com.sun.jersey.core.util.MultivaluedMapImpl;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
/**
*
* @author Konstantin Pelykh (kpelykh@gmail.com)
*
*/
public class DockerClient
{
private static final Logger LOGGER = LoggerFactory.getLogger(DockerClient.class);
private static DockerClient instance;
private Client client;
private String restEndpointUrl;
public DockerClient(String serverUrl) {
restEndpointUrl = serverUrl + "/v1.8";
ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", 4243, PlainSocketFactory.getSocketFactory()));
PoolingClientConnectionManager cm = new PoolingClientConnectionManager(schemeRegistry);
// Increase max total connection
cm.setMaxTotal(1000);
// Increase default max connection per route
cm.setDefaultMaxPerRoute(1000);
HttpClient httpClient = new DefaultHttpClient(cm);
client = new ApacheHttpClient4(new ApacheHttpClient4Handler(httpClient, null, false), clientConfig);
//Experimental support for unix sockets:
//client = new UnixSocketClient(clientConfig);
client.addFilter(new JsonClientFilter());
client.addFilter(new LoggingFilter());
}
/**
** MISC API
**
**/
public Info info() throws DockerException {
WebResource webResource = client.resource(restEndpointUrl + "/info");
try {
LOGGER.trace("GET: {}", webResource);
return webResource.accept(MediaType.APPLICATION_JSON).get(Info.class);
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error.", exception);
} else {
throw new DockerException(exception);
}
}
}
public Version version() throws DockerException {
WebResource webResource = client.resource(restEndpointUrl + "/version");
try {
LOGGER.trace("GET: {}", webResource);
return webResource.accept(MediaType.APPLICATION_JSON).get(Version.class);
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error.", exception);
} else {
throw new DockerException(exception);
}
}
}
/**
** IMAGE API
**
**/
public ClientResponse pull(String repository) throws DockerException {
return this.pull(repository, null, null);
}
public ClientResponse pull(String repository, String tag) throws DockerException {
return this.pull(repository, tag, null);
}
public ClientResponse pull(String repository, String tag, String registry) throws DockerException {
Preconditions.checkNotNull(repository, "Repository was not specified");
if (StringUtils.countMatches(repository, ":") == 1) {
String repositoryTag[] = StringUtils.split(repository);
repository = repositoryTag[0];
tag = repositoryTag[1];
}
MultivaluedMap<String,String> params = new MultivaluedMapImpl();
params.add("tag", tag);
params.add("fromImage", repository);
params.add("registry", registry);
WebResource webResource = client.resource(restEndpointUrl + "/images/create").queryParams(params);
try {
LOGGER.trace("POST: {}", webResource);
return webResource.accept(MediaType.APPLICATION_OCTET_STREAM_TYPE).post(ClientResponse.class);
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error.", exception);
} else {
throw new DockerException(exception);
}
}
}
/**
* Create an image by importing the given stream of a tar file.
*
* @param repository the repository to import to
* @param tag any tag for this image
* @param imageStream the InputStream of the tar file
* @return an {@link ImageCreateResponse} containing the id of the imported image
* @throws DockerException if the import fails for some reason.
*/
public ImageCreateResponse importImage(String repository, String tag, InputStream imageStream) throws DockerException {
Preconditions.checkNotNull(repository, "Repository was not specified");
Preconditions.checkNotNull(imageStream, "imageStream was not provided");
MultivaluedMap<String,String> params = new MultivaluedMapImpl();
params.add("repo", repository);
params.add("tag", tag);
params.add("fromSrc","-");
WebResource webResource = client.resource(restEndpointUrl + "/images/create").queryParams(params);
try {
LOGGER.trace("POST: {}", webResource);
return webResource.accept(MediaType.APPLICATION_OCTET_STREAM_TYPE).post(ImageCreateResponse.class,imageStream);
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error.", exception);
} else {
throw new DockerException(exception);
}
}
}
public List<SearchItem> search(String search) throws DockerException {
WebResource webResource = client.resource(restEndpointUrl + "/images/search").queryParam("term", search);
try {
return webResource.accept(MediaType.APPLICATION_JSON).get(new GenericType<List<SearchItem>>() {});
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error.", exception);
} else {
throw new DockerException(exception);
}
}
}
public void removeImage(String imageId) throws DockerException {
Preconditions.checkState(!StringUtils.isEmpty(imageId), "Image ID can't be empty");
try {
WebResource webResource = client.resource(restEndpointUrl + "/images/" + imageId);
LOGGER.trace("DELETE: {}", webResource);
webResource.delete();
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 204) {
//no error
LOGGER.trace("Successfully removed image " + imageId);
} else if (exception.getResponse().getStatus() == 404) {
LOGGER.warn("{} no such image", imageId);
} else if (exception.getResponse().getStatus() == 409) {
throw new DockerException("Conflict");
} else if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error.", exception);
} else {
throw new DockerException(exception);
}
}
}
public void removeImages(List<String> images) throws DockerException {
Preconditions.checkNotNull(images, "List of images can't be null");
for (String imageId : images) {
removeImage(imageId);
}
}
public String getVizImages() throws DockerException {
WebResource webResource = client.resource(restEndpointUrl + "/images/viz");
try {
LOGGER.trace("GET: {}", webResource);
String response = webResource.get(String.class);
LOGGER.trace("Response: {}", response);
return response;
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 400) {
throw new DockerException("bad parameter");
} else if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error", exception);
} else {
throw new DockerException(exception);
}
}
}
public List<Image> getImages() throws DockerException {
return this.getImages(null, false);
}
public List<Image> getImages(boolean allContainers) throws DockerException {
return this.getImages(null, allContainers);
}
public List<Image> getImages(String name) throws DockerException {
return this.getImages(name, false);
}
public List<Image> getImages(String name, boolean allImages) throws DockerException {
MultivaluedMap<String,String> params = new MultivaluedMapImpl();
params.add("filter", name);
params.add("all", allImages ? "1" : "0");
WebResource webResource = client.resource(restEndpointUrl + "/images/json").queryParams(params);
try {
LOGGER.trace("GET: {}", webResource);
List<Image> images = webResource.accept(MediaType.APPLICATION_JSON).get(new GenericType<List<Image>>() {});
LOGGER.trace("Response: {}", images);
return images;
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 400) {
throw new DockerException("bad parameter");
} else if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error", exception);
} else {
throw new DockerException();
}
}
}
public ImageInspectResponse inspectImage(String imageId) throws DockerException, NotFoundException {
WebResource webResource = client.resource(restEndpointUrl + String.format("/images/%s/json", imageId));
try {
LOGGER.trace("GET: {}", webResource);
return webResource.accept(MediaType.APPLICATION_JSON).get(ImageInspectResponse.class);
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 404) {
throw new NotFoundException(String.format("No such image %s", imageId));
} else if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error", exception);
} else {
throw new DockerException(exception);
}
}
}
/**
** CONTAINER API
**
**/
public List<Container> listContainers(boolean allContainers) {
return this.listContainers(allContainers, false, -1, false, null, null);
}
public List<Container> listContainers(boolean allContainers, boolean latest) {
return this.listContainers(allContainers, latest, -1, false, null, null);
}
public List<Container> listContainers(boolean allContainers, boolean latest, int limit) {
return this.listContainers(allContainers, latest, limit, false, null, null);
}
public List<Container> listContainers(boolean allContainers, boolean latest, int limit, boolean showSize) {
return this.listContainers(allContainers, latest, limit, showSize, null, null);
}
public List<Container> listContainers(boolean allContainers, boolean latest, int limit, boolean showSize, String since) {
return this.listContainers(allContainers, latest, limit, false, since, null);
}
public List<Container> listContainers(boolean allContainers, boolean latest, int limit, boolean showSize, String since, String before) {
MultivaluedMap<String,String> params = new MultivaluedMapImpl();
params.add("limit", latest ? "1" : String.valueOf(limit));
params.add("all", allContainers ? "1" : "0");
params.add("since", since);
params.add("before", before);
params.add("size", showSize ? "1" : "0");
WebResource webResource = client.resource(restEndpointUrl + "/containers/json").queryParams(params);
LOGGER.trace("GET: {}", webResource);
List<Container> containers = webResource.accept(MediaType.APPLICATION_JSON).get(new GenericType<List<Container>>() {});
LOGGER.trace("Response: {}", containers);
return containers;
}
public ContainerCreateResponse createContainer(ContainerConfig config) throws DockerException{
return createContainer(config, null);
}
public ContainerCreateResponse createContainer(ContainerConfig config,String name) throws DockerException, NotFoundException {
MultivaluedMap<String,String> params = new MultivaluedMapImpl();
if(name != null){
params.add("name", name);
}
WebResource webResource = client.resource(restEndpointUrl + "/containers/create").queryParams(params);
try {
LOGGER.trace("POST: {} ", webResource);
return webResource.accept(MediaType.APPLICATION_JSON)
.type(MediaType.APPLICATION_JSON)
.post(ContainerCreateResponse.class, config);
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 404) {
throw new NotFoundException(String.format("%s is an unrecognized image. Please pull the image first.", config.getImage()));
} else if (exception.getResponse().getStatus() == 406) {
throw new DockerException("impossible to attach (container not running)");
} else if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error", exception);
} else {
throw new DockerException(exception);
}
}
}
public void startContainer(String containerId) throws DockerException {
this.startContainer(containerId, null);
}
public void startContainer(String containerId, HostConfig hostConfig) throws DockerException, NotFoundException {
WebResource webResource = client.resource(restEndpointUrl + String.format("/containers/%s/start", containerId));
try {
LOGGER.trace("POST: {}", webResource);
Builder builder = webResource.accept(MediaType.TEXT_PLAIN);
if (hostConfig != null) {
builder.type(MediaType.APPLICATION_JSON).post(hostConfig);
} else {
builder.post((HostConfig) null);
}
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 404) {
throw new NotFoundException(String.format("No such container %s", containerId));
} else if (exception.getResponse().getStatus() == 204) {
//no error
LOGGER.trace("Successfully started container {}", containerId);
} else if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error", exception);
} else {
throw new DockerException(exception);
}
}
}
public ContainerInspectResponse inspectContainer(String containerId) throws DockerException, NotFoundException {
WebResource webResource = client.resource(restEndpointUrl + String.format("/containers/%s/json", containerId));
try {
LOGGER.trace("GET: {}", webResource);
return webResource.accept(MediaType.APPLICATION_JSON).get(ContainerInspectResponse.class);
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 404) {
throw new NotFoundException(String.format("No such container %s", containerId));
} else if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error", exception);
} else {
throw new DockerException(exception);
}
}
}
public void removeContainer(String container) throws DockerException {
this.removeContainer(container, false);
}
public void removeContainer(String containerId, boolean removeVolumes) throws DockerException {
Preconditions.checkState(!StringUtils.isEmpty(containerId), "Container ID can't be empty");
WebResource webResource = client.resource(restEndpointUrl + "/containers/" + containerId).queryParam("v", removeVolumes ? "1" : "0");
try {
LOGGER.trace("DELETE: {}", webResource);
String response = webResource.accept(MediaType.APPLICATION_JSON).delete(String.class);
LOGGER.trace("Response: {}", response);
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 204) {
//no error
LOGGER.trace("Successfully removed container " + containerId);
} else if (exception.getResponse().getStatus() == 400) {
throw new DockerException("bad parameter");
} else if (exception.getResponse().getStatus() == 404) {
// should really throw a NotFoundException instead of silently ignoring the problem
LOGGER.warn(String.format("%s is an unrecognized container.", containerId));
} else if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error", exception);
} else {
throw new DockerException(exception);
}
}
}
public void removeContainers(List<String> containers, boolean removeVolumes) throws DockerException {
Preconditions.checkNotNull(containers, "List of containers can't be null");
for (String containerId : containers) {
removeContainer(containerId, removeVolumes);
}
}
public int waitContainer(String containerId) throws DockerException, NotFoundException {
WebResource webResource = client.resource(restEndpointUrl + String.format("/containers/%s/wait", containerId));
try {
LOGGER.trace("POST: {}", webResource);
JSONObject jsonObject = webResource.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON).post(JSONObject.class);
return jsonObject.getInt("StatusCode");
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 404) {
throw new NotFoundException(String.format("No such container %s", containerId));
} else if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error", exception);
} else {
throw new DockerException(exception);
}
} catch (JSONException e) {
throw new DockerException(e);
}
}
public ClientResponse logContainer(String containerId) throws DockerException {
return logContainer(containerId, false);
}
public ClientResponse logContainerStream(String containerId) throws DockerException {
return logContainer(containerId, true);
}
private ClientResponse logContainer(String containerId, boolean stream) throws DockerException, NotFoundException {
MultivaluedMap<String,String> params = new MultivaluedMapImpl();
params.add("logs", "1");
params.add("stdout", "1");
params.add("stderr", "1");
if (stream) {
params.add("stream", "1"); // this parameter keeps stream open indefinitely
}
WebResource webResource = client.resource(restEndpointUrl + String.format("/containers/%s/attach", containerId))
.queryParams(params);
try {
LOGGER.trace("POST: {}", webResource);
return webResource.accept(MediaType.APPLICATION_OCTET_STREAM_TYPE).post(ClientResponse.class, params);
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 400) {
throw new DockerException("bad parameter");
} else if (exception.getResponse().getStatus() == 404) {
throw new NotFoundException(String.format("No such container %s", containerId));
} else if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error", exception);
} else {
throw new DockerException(exception);
}
}
}
public ClientResponse copyFile(String containerId, String resource) throws DockerException {
CopyConfig copyConfig = new CopyConfig();
copyConfig.setResource(resource);
WebResource webResource =
client.resource(restEndpointUrl + String.format("/containers/%s/copy", containerId));
try {
LOGGER.trace("POST: " + webResource.toString());
WebResource.Builder builder =
webResource.accept(MediaType.APPLICATION_OCTET_STREAM_TYPE).type("application/json");
return builder.post(ClientResponse.class, copyConfig.toString());
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 400) {
throw new DockerException("bad parameter");
} else if (exception.getResponse().getStatus() == 404) {
throw new DockerException(String.format("No such container %s", containerId));
} else if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error", exception);
} else {
throw new DockerException(exception);
}
}
}
public List<ChangeLog> containterDiff(String containerId) throws DockerException, NotFoundException {
WebResource webResource = client.resource(restEndpointUrl + String.format("/containers/%s/changes", containerId));
try {
LOGGER.trace("GET: {}", webResource);
return webResource.accept(MediaType.APPLICATION_JSON).get(new GenericType<List<ChangeLog>>() {});
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 404) {
throw new NotFoundException(String.format("No such container %s", containerId));
} else if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error", exception);
} else {
throw new DockerException(exception);
}
}
}
public void stopContainer(String containerId) throws DockerException {
this.stopContainer(containerId, 10);
}
public void stopContainer(String containerId, int timeout) throws DockerException {
WebResource webResource = client.resource(restEndpointUrl + String.format("/containers/%s/stop", containerId))
.queryParam("t", String.valueOf(timeout));
try {
LOGGER.trace("POST: {}", webResource);
webResource.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON).post();
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 404) {
LOGGER.warn("No such container {}", containerId);
} else if (exception.getResponse().getStatus() == 204) {
//no error
LOGGER.trace("Successfully stopped container {}", containerId);
} else if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error", exception);
} else {
throw new DockerException(exception);
}
}
}
public void kill(String containerId) throws DockerException {
WebResource webResource = client.resource(restEndpointUrl + String.format("/containers/%s/kill", containerId));
try {
LOGGER.trace("POST: {}", webResource);
webResource.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON).post();
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 404) {
LOGGER.warn("No such container {}", containerId);
} else if (exception.getResponse().getStatus() == 204) {
//no error
LOGGER.trace("Successfully killed container {}", containerId);
} else if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error", exception);
} else {
throw new DockerException(exception);
}
}
}
public void restart(String containerId, int timeout) throws DockerException, NotFoundException {
WebResource webResource = client.resource(restEndpointUrl + String.format("/containers/%s/restart", containerId));
try {
LOGGER.trace("POST: {}", webResource);
webResource.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON).post();
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 404) {
throw new NotFoundException(String.format("No such container %s", containerId));
} else if (exception.getResponse().getStatus() == 204) {
//no error
LOGGER.trace("Successfully restarted container {}", containerId);
} else if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error", exception);
} else {
throw new DockerException(exception);
}
}
}
public String commit(CommitConfig commitConfig) throws DockerException, NotFoundException {
Preconditions.checkNotNull(commitConfig.getContainer(), "Container ID was not specified");
MultivaluedMap<String,String> params = new MultivaluedMapImpl();
params.add("container", commitConfig.getContainer());
params.add("repo", commitConfig.getRepo());
params.add("tag", commitConfig.getTag());
params.add("m", commitConfig.getMessage());
params.add("author", commitConfig.getAuthor());
params.add("run", commitConfig.getRun());
WebResource webResource = client.resource(restEndpointUrl + "/commit").queryParams(params);
try {
LOGGER.trace("POST: {}", webResource);
JSONObject jsonObject = webResource.accept("application/vnd.docker.raw-stream").post(JSONObject.class, params);
return jsonObject.getString("Id");
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 404) {
throw new NotFoundException(String.format("No such container %s", commitConfig.getContainer()));
} else if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error", exception);
} else {
throw new DockerException(exception);
}
} catch (JSONException e) {
throw new DockerException(e);
}
}
public ClientResponse build(File dockerFolder) throws DockerException {
return this.build(dockerFolder, null);
}
public ClientResponse build(File dockerFolder, String tag) throws DockerException {
return this.build(dockerFolder, null, false);
}
public ClientResponse build(File dockerFolder, String tag, boolean noCache) throws DockerException {
Preconditions.checkNotNull(dockerFolder, "Folder is null");
Preconditions.checkArgument(dockerFolder.exists(), "Folder %s doesn't exist", dockerFolder);
Preconditions.checkState(new File(dockerFolder, "Dockerfile").exists(), "Dockerfile doesn't exist in " + dockerFolder);
//We need to use Jersey HttpClient here, since ApacheHttpClient4 will not add boundary filed to
//Content-Type: multipart/form-data; boundary=Boundary_1_372491238_1372806136625
MultivaluedMap<String,String> params = new MultivaluedMapImpl();
params.add("t", tag);
if(noCache) {
params.add("nocache", "true");
}
// ARCHIVE TAR
String archiveNameWithOutExtension = UUID.randomUUID().toString();
File dockerFolderTar = null;
File tmpDockerContextFolder = null;
try {
File dockerFile = new File(dockerFolder, "Dockerfile");
List<String> dockerFileContent = FileUtils.readLines(dockerFile);
if (dockerFileContent.size() <= 0) {
throw new DockerException(String.format("Dockerfile %s is empty", dockerFile));
}
//Create tmp docker context folder
tmpDockerContextFolder = new File(FileUtils.getTempDirectoryPath(), "docker-java-build" + archiveNameWithOutExtension);
FileUtils.copyFileToDirectory(dockerFile, tmpDockerContextFolder);
for (String cmd : dockerFileContent) {
if (StringUtils.startsWithIgnoreCase(cmd.trim(), "ADD ")) {
String addArgs[] = StringUtils.split(cmd, " \t");
if (addArgs.length != 3) {
throw new DockerException(String.format("Wrong format on line [%s]", cmd));
}
File src = new File(addArgs[1]);
if (!src.isAbsolute()) {
src = new File(dockerFolder, addArgs[1]).getCanonicalFile();
}
if (!src.exists()) {
throw new DockerException(String.format("Source file %s doesnt' exist", src));
}
if (src.isDirectory()) {
FileUtils.copyDirectory(src, tmpDockerContextFolder);
} else {
FileUtils.copyFileToDirectory(src, tmpDockerContextFolder);
}
}
}
dockerFolderTar = CompressArchiveUtil.archiveTARFiles(tmpDockerContextFolder, archiveNameWithOutExtension);
} catch (IOException ex) {
FileUtils.deleteQuietly(dockerFolderTar);
FileUtils.deleteQuietly(tmpDockerContextFolder);
throw new DockerException("Error occurred while preparing Docker context folder.", ex);
}
WebResource webResource = client.resource(restEndpointUrl + "/build").queryParams(params);
try {
LOGGER.trace("POST: {}", webResource);
return webResource
.type("application/tar")
.accept(MediaType.TEXT_PLAIN)
.post(ClientResponse.class, FileUtils.openInputStream(dockerFolderTar));
} catch (UniformInterfaceException exception) {
if (exception.getResponse().getStatus() == 500) {
throw new DockerException("Server error", exception);
} else {
throw new DockerException(exception);
}
} catch (IOException e) {
throw new DockerException(e);
} finally {
FileUtils.deleteQuietly(dockerFolderTar);
FileUtils.deleteQuietly(tmpDockerContextFolder);
}
}
}

View File

@ -0,0 +1,25 @@
package com.kpelykh.docker.client;
/**
*
* @author Konstantin Pelykh (kpelykh@gmail.com)
*
*/
public class DockerException extends Exception {
public DockerException() {
}
public DockerException(String message) {
super(message);
}
public DockerException(String message, Throwable cause) {
super(message, cause);
}
public DockerException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,20 @@
package com.kpelykh.docker.client;
/**
* Indicates that the given entity does not exist.
*
* @author Ryan Campbell ryan.campbell@gmail.com
*/
public class NotFoundException extends DockerException {
public NotFoundException() {
}
public NotFoundException(String message) {
super(message);
}
public NotFoundException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,12 @@
package com.kpelykh.docker.client;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.config.ClientConfig;
public class UnixSocketClient extends Client {
public UnixSocketClient(ClientConfig clientConfig) {
super(new UnixSocketClientHandler(), clientConfig);
}
}

View File

@ -0,0 +1,213 @@
package com.kpelykh.docker.client;
import com.sun.jersey.api.client.*;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.core.header.InBoundHeaders;
import com.sun.jersey.core.util.ReaderWriter;
import jnr.unixsocket.UnixSocketAddress;
import jnr.unixsocket.UnixSocketChannel;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpResponse;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.client.methods.*;
import org.apache.http.entity.AbstractHttpEntity;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.impl.DefaultHttpResponseFactory;
import org.apache.http.impl.io.DefaultHttpResponseParser;
import org.apache.http.impl.io.HttpRequestWriter;
import org.apache.http.message.BasicLineFormatter;
import org.apache.http.message.BasicLineParser;
import org.apache.http.params.BasicHttpParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.URI;
import java.nio.channels.Channels;
import java.util.ArrayList;
import java.util.List;
/**
* TODO: Make thread-safe.
*/
@NotThreadSafe
public class UnixSocketClientHandler extends RequestWriter implements ClientHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(UnixSocketClientHandler.class);
public static final int BUFFERSIZE = 1024;
public static final String DOCKER_SOCKET_PATH = "/var/run/docker.sock";
@Override
public ClientResponse handle(ClientRequest cr) throws ClientHandlerException {
try {
File path = new File(DOCKER_SOCKET_PATH);
UnixSocketAddress address = new UnixSocketAddress(path);
UnixSocketChannel channel = UnixSocketChannel.open(address);
OutputStream unixSocketChannelOutputStream = Channels.newOutputStream(channel);
final HttpUriRequest request = getUriHttpRequest(cr);
BasicHttpParams params = new BasicHttpParams();
UnixSocketSessionOutputBuffer outputBuffer = new UnixSocketSessionOutputBuffer();
outputBuffer.init(unixSocketChannelOutputStream, BUFFERSIZE, params);
HttpRequestWriter writer = new HttpRequestWriter(outputBuffer, new BasicLineFormatter(), params);
writer.write(request);
outputBuffer.flush();
UnixSocketSessionInputBuffer inputBuffer = new UnixSocketSessionInputBuffer();
inputBuffer.init(Channels.newInputStream(channel), BUFFERSIZE, params);
HttpResponse response = new DefaultHttpResponseParser(inputBuffer, new BasicLineParser(), new DefaultHttpResponseFactory(), params).parse();
LOGGER.trace(response.toString());
ClientResponse clientResponse = new ClientResponse(response.getStatusLine().getStatusCode(),
getInBoundHeaders(response),
new HttpClientResponseInputStream(response),
getMessageBodyWorkers());
clientResponse.bufferEntity();
clientResponse.close();
return clientResponse;
} catch (IOException e) {
e.printStackTrace();
} catch (HttpException e) {
e.printStackTrace();
}
return null;
}
private HttpUriRequest getUriHttpRequest(final ClientRequest cr) {
final String strMethod = cr.getMethod();
final URI uri = cr.getURI();
final HttpEntity entity = getHttpEntity(cr);
final HttpUriRequest request;
if (strMethod.equals("GET")) {
request = new HttpGet(uri);
} else if (strMethod.equals("POST")) {
request = new HttpPost(uri);
} else if (strMethod.equals("PUT")) {
request = new HttpPut(uri);
} else if (strMethod.equals("DELETE")) {
request = new HttpDelete(uri);
} else if (strMethod.equals("HEAD")) {
request = new HttpHead(uri);
} else if (strMethod.equals("OPTIONS")) {
request = new HttpOptions(uri);
} else {
request = new HttpEntityEnclosingRequestBase() {
@Override
public String getMethod() {
return strMethod;
}
@Override
public URI getURI() {
return uri;
}
};
}
if (entity != null && request instanceof HttpEntityEnclosingRequestBase) {
((HttpEntityEnclosingRequestBase) request).setEntity(entity);
} else if (entity != null) {
throw new ClientHandlerException("Adding entity to http method " + cr.getMethod() + " is not supported.");
}
return request;
}
private HttpEntity getHttpEntity(final ClientRequest cr) {
final Object entity = cr.getEntity();
if (entity == null)
return null;
final RequestEntityWriter requestEntityWriter = getRequestEntityWriter(cr);
try {
HttpEntity httpEntity = new AbstractHttpEntity() {
@Override
public boolean isRepeatable() {
return false;
}
@Override
public long getContentLength() {
return requestEntityWriter.getSize();
}
@Override
public InputStream getContent() throws IOException, IllegalStateException {
return null;
}
@Override
public void writeTo(OutputStream outputStream) throws IOException {
requestEntityWriter.writeRequestEntity(outputStream);
}
@Override
public boolean isStreaming() {
return false;
}
};
if (cr.getProperties().get(ClientConfig.PROPERTY_CHUNKED_ENCODING_SIZE) != null) {
// TODO return InputStreamEntity
return httpEntity;
} else {
return new BufferedHttpEntity(httpEntity);
}
} catch (Exception ex) {
// TODO warning/error?
}
return null;
}
private InBoundHeaders getInBoundHeaders(final HttpResponse response) {
final InBoundHeaders headers = new InBoundHeaders();
final Header[] respHeaders = response.getAllHeaders();
for (Header header : respHeaders) {
List<String> list = headers.get(header.getName());
if (list == null) {
list = new ArrayList<String>();
}
list.add(header.getValue());
headers.put(header.getName(), list);
}
return headers;
}
private static final class HttpClientResponseInputStream extends FilterInputStream {
HttpClientResponseInputStream(final HttpResponse response) throws IOException {
super(getInputStream(response));
}
@Override
public void close()
throws IOException {
super.close();
}
}
private static InputStream getInputStream(final HttpResponse response) throws IOException {
if (response.getEntity() == null) {
return new ByteArrayInputStream(new byte[0]);
} else {
final InputStream i = response.getEntity().getContent();
if (i.markSupported())
return i;
return new BufferedInputStream(i, ReaderWriter.BUFFER_SIZE);
}
}
}

View File

@ -0,0 +1,23 @@
package com.kpelykh.docker.client;
import org.apache.http.impl.io.AbstractSessionInputBuffer;
import org.apache.http.params.HttpParams;
import java.io.IOException;
import java.io.InputStream;
/**
*
*/
public class UnixSocketSessionInputBuffer extends AbstractSessionInputBuffer {
@Override
protected void init(InputStream instream, int buffersize, HttpParams params) {
super.init(instream, buffersize, params);
}
@Override
public boolean isDataAvailable(int timeout) throws IOException {
return true;
}
}

View File

@ -0,0 +1,17 @@
package com.kpelykh.docker.client;
import org.apache.http.impl.io.AbstractSessionOutputBuffer;
import org.apache.http.params.HttpParams;
import java.io.OutputStream;
/**
* {@link org.apache.http.impl.io.AbstractSessionOutputBuffer} implementation for UNIX sockets.
*/
public class UnixSocketSessionOutputBuffer extends AbstractSessionOutputBuffer {
@Override
protected void init(OutputStream outstream, int buffersize, HttpParams params) {
super.init(outstream, buffersize, params);
}
}

View File

@ -0,0 +1,93 @@
/**
* 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 com.kpelykh.docker.client.model;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;
import org.codehaus.jackson.map.annotate.JsonSerialize;
/**
* @author Kevin A. Archie <karchie@wustl.edu>
*
*/
@JsonSerialize(using=BoundHostVolumes.Serializer.class)
public class BoundHostVolumes {
private static final String[] STRING_ARRAY = new String[0];
private final String[] dests, binds;
/**
*
* @param specs Iterable of String binding specs, each of form "{host-path}:{container-patch}:[rw|ro]"
* @throws MalformedVolumeSpecException if any specs are null or empty
*/
public BoundHostVolumes(final Iterable<String> specs) {
final List<String> dests = new ArrayList<String>(), binds = new ArrayList<String>();
for (final String spec : specs) {
if (null == spec || "".equals(spec)) {
// skip empty spec lines
} else {
final String[] sspec = spec.split(":");
dests.add(sspec.length > 1 ? sspec[1] : sspec[0]);
binds.add(spec);
}
}
this.dests = dests.toArray(STRING_ARRAY);
this.binds = binds.toArray(STRING_ARRAY);
}
public String[] asBinds() {
return binds;
}
private BoundHostVolumes writeVolumes(final JsonGenerator jg) throws IOException {
jg.writeStartObject();
for (final String dest : dests) {
jg.writeObjectFieldStart(dest);
jg.writeEndObject();
}
jg.writeEndObject();
return this;
}
/**
* This is an ugly hack. We assume that the serializer only gets called when
* a containing ContainerConfig gets serialized, when POSTing to
* /containers/create . In that context, we pass only the container-path
* part (the key in the volumes map).
*
* @author Kevin A. Archie <karchie@wustl.edu>
*
*/
public static class Serializer extends JsonSerializer<BoundHostVolumes> {
/* (non-Javadoc)
* @see org.codehaus.jackson.map.JsonSerializer#serialize(java.lang.Object, org.codehaus.jackson.JsonGenerator, org.codehaus.jackson.map.SerializerProvider)
*/
@Override
public void serialize(final BoundHostVolumes volumes, final JsonGenerator jg, final SerializerProvider sp)
throws IOException {
volumes.writeVolumes(jg);
}
}
}

View File

@ -0,0 +1,33 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.annotate.JsonProperty;
/**
*
* @author Konstantin Pelykh (kpelykh@gmail.com)
*
*/
public class ChangeLog {
@JsonProperty("Path")
private String path;
@JsonProperty("Kind")
private int kind;
public String getPath() {
return path;
}
public int getKind() {
return kind;
}
@Override
public String toString() {
return "ChangeLog{" +
"path='" + path + '\'' +
", kind=" + kind +
'}';
}
}

View File

@ -0,0 +1,85 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.annotate.JsonProperty;
/**
*
* @author Konstantin Pelykh (kpelykh@gmail.com)
*
*/
public class CommitConfig {
@JsonProperty("container")
private String container;
@JsonProperty("repo")
private String repo;
@JsonProperty("tag")
private String tag;
@JsonProperty("m")
private String message;
//author (eg. John Hannibal Smith <hannibal@a-team.com>)
@JsonProperty("author")
private String author;
//config automatically applied when the image is run. (ex: {Cmd: [cat, /world], PortSpecs:[22]})
@JsonProperty("run")
private String run;
public String getContainer() {
return container;
}
public String getRepo() {
return repo;
}
public String getTag() {
return tag;
}
public String getMessage() {
return message;
}
public String getAuthor() {
return author;
}
public String getRun() {
return run;
}
public CommitConfig setRepo(String repo) {
this.repo = repo;
return this;
}
public CommitConfig setTag(String tag) {
this.tag = tag;
return this;
}
public CommitConfig setMessage(String message) {
this.message = message;
return this;
}
public CommitConfig setAuthor(String author) {
this.author = author;
return this;
}
public CommitConfig setRun(String run) {
this.run = run;
return this;
}
public CommitConfig(String container) {
this.container = container;
}
}

View File

@ -0,0 +1,140 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;
import java.util.Arrays;
/**
*
* @author Konstantin Pelykh (kpelykh@gmail.com)
*
*/
@JsonIgnoreProperties(ignoreUnknown=true)
public class Container {
@JsonProperty("Id")
private String id;
@JsonProperty("Command")
private String command;
@JsonProperty("Image")
private String image;
@JsonProperty("Created")
private long created;
@JsonProperty("Status")
private String status;
/* Example:
"Ports": {
"22/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "8022"
}
]
}
*/
@JsonProperty("Ports")
public Ports ports;
@JsonProperty("SizeRw")
private int size;
@JsonProperty("SizeRootFs")
private int sizeRootFs;
@JsonProperty("Names")
private String[] names;
public String getId() {
return id;
}
public String getCommand() {
return command;
}
public String getImage() {
return image;
}
public long getCreated() {
return created;
}
public String getStatus() {
return status;
}
public Ports getPorts() {
return ports;
}
public void setPorts(Ports ports) {
this.ports = ports;
}
public int getSize() {
return size;
}
public int getSizeRootFs() {
return sizeRootFs;
}
public String[] getNames() {
return names;
}
public void setId(String id) {
this.id = id;
}
public void setCommand(String command) {
this.command = command;
}
public void setImage(String image) {
this.image = image;
}
public void setCreated(long created) {
this.created = created;
}
public void setStatus(String status) {
this.status = status;
}
public void setSize(int size) {
this.size = size;
}
public void setSizeRootFs(int sizeRootFs) {
this.sizeRootFs = sizeRootFs;
}
public void setNames(String[] names) {
this.names = names;
}
@Override
public String toString() {
return "Container{" +
"id='" + id + '\'' +
", command='" + command + '\'' +
", image='" + image + '\'' +
", created=" + created +
", status='" + status + '\'' +
", ports=" + ports +
", size=" + size +
", sizeRootFs=" + sizeRootFs +
", names=" + Arrays.toString(names) +
'}';
}
}

View File

@ -0,0 +1,282 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.annotate.JsonProperty;
import java.util.Arrays;
import java.util.Map;
/**
*
* @author Konstantin Pelykh (kpelykh@gmail.com)
*
*/
public class ContainerConfig {
@JsonProperty("Hostname") private String hostName = "";
@JsonProperty("PortSpecs") private String[] portSpecs;
@JsonProperty("User") private String user = "";
@JsonProperty("Tty") private boolean tty = false;
@JsonProperty("OpenStdin") private boolean stdinOpen = false;
@JsonProperty("StdinOnce") private boolean stdInOnce = false;
@JsonProperty("Memory") private long memoryLimit = 0;
@JsonProperty("MemorySwap") private long memorySwap = 0;
@JsonProperty("CpuShares") private int cpuShares = 0;
@JsonProperty("AttachStdin") private boolean attachStdin = false;
@JsonProperty("AttachStdout") private boolean attachStdout = false;
@JsonProperty("AttachStderr") private boolean attachStderr = false;
@JsonProperty("Env") private String[] env;
@JsonProperty("Cmd") private String[] cmd;
@JsonProperty("Dns") private String[] dns;
@JsonProperty("Image") private String image;
@JsonProperty("Volumes") private BoundHostVolumes volumes;
@JsonProperty("VolumesFrom") private String volumesFrom = "";
@JsonProperty("Entrypoint") private String[] entrypoint = new String[]{};
@JsonProperty("NetworkDisabled") private boolean networkDisabled = false;
@JsonProperty("Privileged") private boolean privileged = false;
@JsonProperty("WorkingDir") private String workingDir = "";
@JsonProperty("Domainname") private String domainName = "";
// FIXME Is this the right type? -BJE
@JsonProperty("ExposedPorts") private Map<String, ?> exposedPorts;
@JsonProperty("OnBuild") private String[] onBuild;
public Map<String, ?> getExposedPorts() {
return exposedPorts;
}
public boolean isNetworkDisabled() {
return networkDisabled;
}
public String getDomainName() {
return domainName;
}
public String getWorkingDir() { return workingDir; }
public ContainerConfig setWorkingDir(String workingDir) {
this.workingDir = workingDir;
return this;
}
public boolean isPrivileged() {
return privileged;
}
public ContainerConfig setPrivileged(boolean privileged) {
this.privileged = privileged;
return this;
}
public String getHostName() {
return hostName;
}
public ContainerConfig setNetworkDisabled(boolean networkDisabled) {
this.networkDisabled = networkDisabled;
return this;
}
public ContainerConfig setHostName(String hostName) {
this.hostName = hostName;
return this;
}
public String[] getPortSpecs() {
return portSpecs;
}
public ContainerConfig setPortSpecs(String[] portSpecs) {
this.portSpecs = portSpecs;
return this;
}
public String getUser() {
return user;
}
public ContainerConfig setUser(String user) {
this.user = user;
return this;
}
public boolean isTty() {
return tty;
}
public ContainerConfig setTty(boolean tty) {
this.tty = tty;
return this;
}
public boolean isStdinOpen() {
return stdinOpen;
}
public ContainerConfig setStdinOpen(boolean stdinOpen) {
this.stdinOpen = stdinOpen;
return this;
}
public boolean isStdInOnce() {
return stdInOnce;
}
public ContainerConfig setStdInOnce(boolean stdInOnce) {
this.stdInOnce = stdInOnce;
return this;
}
public long getMemoryLimit() {
return memoryLimit;
}
public ContainerConfig setMemoryLimit(long memoryLimit) {
this.memoryLimit = memoryLimit;
return this;
}
public long getMemorySwap() {
return memorySwap;
}
public ContainerConfig setMemorySwap(long memorySwap) {
this.memorySwap = memorySwap;
return this;
}
public int getCpuShares() {
return cpuShares;
}
public ContainerConfig setCpuShares(int cpuShares) {
this.cpuShares = cpuShares;
return this;
}
public boolean isAttachStdin() {
return attachStdin;
}
public ContainerConfig setAttachStdin(boolean attachStdin) {
this.attachStdin = attachStdin;
return this;
}
public boolean isAttachStdout() {
return attachStdout;
}
public ContainerConfig setAttachStdout(boolean attachStdout) {
this.attachStdout = attachStdout;
return this;
}
public boolean isAttachStderr() {
return attachStderr;
}
public ContainerConfig setAttachStderr(boolean attachStderr) {
this.attachStderr = attachStderr;
return this;
}
public String[] getEnv() {
return env;
}
public ContainerConfig setEnv(String[] env) {
this.env = env;
return this;
}
public String[] getCmd() {
return cmd;
}
public ContainerConfig setCmd(String[] cmd) {
this.cmd = cmd;
return this;
}
public String[] getDns() {
return dns;
}
public ContainerConfig setDns(String[] dns) {
this.dns = dns;
return this;
}
public String getImage() {
return image;
}
public ContainerConfig setImage(String image) {
this.image = image;
return this;
}
public BoundHostVolumes getVolumes() {
return volumes;
}
public ContainerConfig setVolumes(BoundHostVolumes volumes) {
this.volumes = volumes;
return this;
}
public String getVolumesFrom() {
return volumesFrom;
}
public ContainerConfig setVolumesFrom(String volumesFrom) {
this.volumesFrom = volumesFrom;
return this;
}
public String[] getEntrypoint() {
return entrypoint;
}
public ContainerConfig setEntrypoint(String[] entrypoint) {
this.entrypoint = entrypoint;
return this;
}
public String[] getOnBuild() {
return onBuild;
}
public void setOnBuild(String[] onBuild) {
this.onBuild=onBuild;
}
@Override
public String toString() {
return "ContainerConfig{" +
"hostName='" + hostName + '\'' +
", portSpecs=" + Arrays.toString(portSpecs) +
", user='" + user + '\'' +
", tty=" + tty +
", stdinOpen=" + stdinOpen +
", stdInOnce=" + stdInOnce +
", memoryLimit=" + memoryLimit +
", memorySwap=" + memorySwap +
", cpuShares=" + cpuShares +
", attachStdin=" + attachStdin +
", attachStdout=" + attachStdout +
", attachStderr=" + attachStderr +
", env=" + Arrays.toString(env) +
", cmd=" + Arrays.toString(cmd) +
", dns=" + Arrays.toString(dns) +
", image='" + image + '\'' +
", volumes=" + volumes +
", volumesFrom='" + volumesFrom + '\'' +
", entrypoint=" + Arrays.toString(entrypoint) +
", networkDisabled=" + networkDisabled +
", privileged=" + privileged +
", workingDir='" + workingDir + '\'' +
", domainName='" + domainName + '\'' +
'}';
}
}

View File

@ -0,0 +1,43 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.annotate.JsonProperty;
import java.util.Arrays;
/**
*
* @author Konstantin Pelykh (kpelykh@gmail.com)
*
*/
public class ContainerCreateResponse {
@JsonProperty("Id")
private String id;
@JsonProperty("Warnings")
private String[] warnings;
public String getId() {
return id;
}
public String[] getWarnings() {
return warnings;
}
public void setId(String id) {
this.id = id;
}
public void setWarnings(String[] warnings) {
this.warnings = warnings;
}
@Override
public String toString() {
return "ContainerCreateResponse{" +
"id='" + id + '\'' +
", warnings=" + Arrays.toString(warnings) +
'}';
}
}

View File

@ -0,0 +1,247 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.annotate.JsonProperty;
import java.util.Arrays;
import java.util.Map;
/**
*
* @author Konstantin Pelykh (kpelykh@gmail.com)
*
*/
public class ContainerInspectResponse {
@JsonProperty("ID")
private String id;
@JsonProperty("Created")
private String created;
@JsonProperty("Path")
private String path;
@JsonProperty("Args")
private String[] args;
@JsonProperty("Config")
public ContainerConfig config;
@JsonProperty("State")
private ContainerState state;
@JsonProperty("Image")
private String image;
@JsonProperty("NetworkSettings")
private NetworkSettings networkSettings;
@JsonProperty("SysInitPath")
private String sysInitPath;
@JsonProperty("ResolvConfPath")
private String resolvConfPath;
@JsonProperty("Volumes")
private Map<String, String> volumes;
@JsonProperty("VolumesRW")
private Map<String, String> volumesRW;
@JsonProperty("HostnamePath")
private String hostnamePath;
@JsonProperty("HostsPath")
private String hostsPath;
@JsonProperty("Name")
private String name;
@JsonProperty("Driver")
private String driver;
@JsonProperty("HostConfig")
private HostConfig hostConfig;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCreated() {
return created;
}
public void setCreated(String created) {
this.created = created;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String[] getArgs() {
return args;
}
public void setArgs(String[] args) {
this.args = args;
}
public ContainerConfig getConfig() {
return config;
}
public void setConfig(ContainerConfig config) {
this.config = config;
}
public ContainerState getState() {
return state;
}
public void setState(ContainerState state) {
this.state = state;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public NetworkSettings getNetworkSettings() {
return networkSettings;
}
public void setNetworkSettings(NetworkSettings networkSettings) {
this.networkSettings = networkSettings;
}
public String getSysInitPath() {
return sysInitPath;
}
public void setSysInitPath(String sysInitPath) {
this.sysInitPath = sysInitPath;
}
public String getResolvConfPath() {
return resolvConfPath;
}
public void setResolvConfPath(String resolvConfPath) {
this.resolvConfPath = resolvConfPath;
}
public Map<String, String> getVolumes() {
return volumes;
}
public void setVolumes(Map<String, String> volumes) {
this.volumes = volumes;
}
public Map<String, String> getVolumesRW() {
return volumesRW;
}
public void setVolumesRW(Map<String, String> volumesRW) {
this.volumesRW = volumesRW;
}
public String getHostnamePath() {
return hostnamePath;
}
public void setHostnamePath(String hostnamePath) {
this.hostnamePath = hostnamePath;
}
public String getHostsPath() {
return hostsPath;
}
public void setHostsPath(String hostsPath) {
this.hostsPath = hostsPath;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public HostConfig getHostConfig() {
return hostConfig;
}
public void setHostConfig(HostConfig hostConfig) {
this.hostConfig = hostConfig;
}
public class NetworkSettings {
@JsonProperty("IPAddress") public String ipAddress;
@JsonProperty("IPPrefixLen") public int ipPrefixLen;
@JsonProperty("Gateway") public String gateway;
@JsonProperty("Bridge") public String bridge;
@JsonProperty("PortMapping") public Map<String,Map<String, String>> portMapping;
@JsonProperty("Ports") public Ports ports;
@Override
public String toString() {
return "NetworkSettings{" +
"ports=" + ports +
", portMapping=" + portMapping +
", bridge='" + bridge + '\'' +
", gateway='" + gateway + '\'' +
", ipPrefixLen=" + ipPrefixLen +
", ipAddress='" + ipAddress + '\'' +
'}';
}
}
public class ContainerState {
@JsonProperty("Running") public boolean running;
@JsonProperty("Pid") public int pid;
@JsonProperty("ExitCode") public int exitCode;
@JsonProperty("StartedAt") public String startedAt;
@JsonProperty("Ghost") public boolean ghost;
@JsonProperty("FinishedAt") private String finishedAt;
@Override
public String toString() {
return "ContainerState{" +
"running=" + running +
", pid=" + pid +
", exitCode=" + exitCode +
", startedAt='" + startedAt + '\'' +
", ghost=" + ghost +
", finishedAt='" + finishedAt + '\'' +
'}';
}
}
}

View File

@ -0,0 +1,61 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.annotate.JsonProperty;
/**
* Configuration object for copy command.
* @author Victor Lyuboslavsky
*/
public class CopyConfig {
@JsonProperty("HostPath")
private String hostPath;
@JsonProperty("Resource")
private String resource;
/**
* Constructor.
*/
public CopyConfig() {
hostPath = ".";
}
/**
* Retrieves the 'resource' variable.
* @return the 'resource' variable value
*/
public String getResource() {
return resource;
}
/**
* Sets the 'resource' variable.
* @param resource the new 'resource' variable value to set
*/
public void setResource(String resource) {
this.resource = resource;
}
/**
* Retrieves the 'hostPath' variable.
* @return the 'hostPath' variable value
*/
public String getHostPath() {
return hostPath;
}
/**
* Sets the 'hostPath' variable.
* @param hostPath the new 'hostPath' variable value to set
*/
public void setHostPath(String hostPath) {
this.hostPath = hostPath;
}
@Override
public String toString() {
return "{\"HostPath\":\"" + hostPath + "\", \"Resource\":\"" + resource + "\"}";
}
}

View File

@ -0,0 +1,31 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.annotate.JsonProperty;
/**
* Created by ben on 12/12/13.
*/
public class DriverStatus {
@JsonProperty("Root Dir")
private String rootDir;
@JsonProperty("Dirs")
private int dirs;
public String getRootDir() {
return rootDir;
}
public int getDirs() {
return dirs;
}
@Override
public String toString() {
return "DriverStatus{" +
"rootDir='" + rootDir + '\'' +
", dirs=" + dirs +
'}';
}
}

View File

@ -0,0 +1,148 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.annotate.JsonProperty;
import java.util.Arrays;
/**
*
* @author Konstantin Pelykh (kpelykh@gmail.com)
*
*/
public class HostConfig {
@JsonProperty("Binds")
private String[] binds;
@JsonProperty("ContainerIDFile")
private String containerIDFile;
@JsonProperty("LxcConf")
private LxcConf[] lxcConf;
@JsonProperty("Links")
private String[] links;
@JsonProperty("PortBindings")
private Ports portBindings;
@JsonProperty("Privileged")
private boolean privileged;
@JsonProperty("PublishAllPorts")
private boolean publishAllPorts;
public HostConfig() {
this.binds = null;
}
public String[] getBinds() {
return binds;
}
public void setBinds(String[] binds) {
this.binds = binds;
}
public void setBinds(final BoundHostVolumes volumes) {
setBinds(volumes.asBinds());
}
public String getContainerIDFile() {
return containerIDFile;
}
public void setContainerIDFile(String containerIDFile) {
this.containerIDFile = containerIDFile;
}
public LxcConf[] getLxcConf() {
return lxcConf;
}
public void setLxcConf(LxcConf[] lxcConf) {
this.lxcConf = lxcConf;
}
public String[] getLinks() {
return links;
}
public void setLinks(String[] links) {
this.links = links;
}
public Ports getPortBindings() {
return portBindings;
}
public void setPortBindings(Ports portBindings) {
this.portBindings = portBindings;
}
public boolean isPrivileged() {
return privileged;
}
public void setPrivileged(boolean privileged) {
this.privileged = privileged;
}
public boolean isPublishAllPorts() {
return publishAllPorts;
}
public void setPublishAllPorts(boolean publishAllPorts) {
this.publishAllPorts = publishAllPorts;
}
@Override
public String toString() {
return "HostConfig{" +
"binds=" + Arrays.toString(binds) +
", containerIDFile='" + containerIDFile + '\'' +
", lxcConf=" + Arrays.toString(lxcConf) +
", links=" + Arrays.toString(links) +
", portBindings=" + portBindings +
", privileged=" + privileged +
", publishAllPorts=" + publishAllPorts +
'}';
}
public class LxcConf {
@JsonProperty("Key")
public String key;
@JsonProperty("Value")
public String value;
public LxcConf(String key, String value) {
this.key = key;
this.value = value;
}
public LxcConf() {
}
public String getKey() {
return key;
}
public LxcConf setKey(String key) {
this.key = key;
return this;
}
public String getValue() {
return value;
}
public LxcConf setValue(String value) {
this.value = value;
return this;
}
}
}

View File

@ -0,0 +1,9 @@
package com.kpelykh.docker.client.model;
/**
* Created by ben on 12/12/13.
*/
public interface IBuilder<T> {
T build();
}

View File

@ -0,0 +1,116 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.annotate.JsonProperty;
import java.util.Arrays;
/**
*
* @author Konstantin Pelykh (kpelykh@gmail.com)
*
*/
public class Image {
@JsonProperty("Id")
private String id;
@JsonProperty("RepoTags")
private String[] repoTags;
@JsonProperty("Repository")
private String repository;
@JsonProperty("Tag")
private String tag;
@JsonProperty("ParentId")
private String parentId;
@JsonProperty("Created")
private long created;
@JsonProperty("Size")
private long size;
@JsonProperty("VirtualSize")
private long virtualSize;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String[] getRepoTags() {
return repoTags;
}
public void setRepoTags(String[] repoTags) {
this.repoTags = repoTags;
}
public String getRepository() {
return repository;
}
public void setRepository(String repository) {
this.repository = repository;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
public long getCreated() {
return created;
}
public void setCreated(long created) {
this.created = created;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public long getVirtualSize() {
return virtualSize;
}
public void setVirtualSize(long virtualSize) {
this.virtualSize = virtualSize;
}
@Override
public String toString() {
return "Image{" +
"virtualSize=" + virtualSize +
", id='" + id + '\'' +
", repoTags=" + Arrays.toString(repoTags) +
", repository='" + repository + '\'' +
", tag='" + tag + '\'' +
", parentId='" + parentId + '\'' +
", created=" + created +
", size=" + size +
'}';
}
}

View File

@ -0,0 +1,30 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.annotate.JsonProperty;
import java.util.Arrays;
/**
* Parse reponses from /images/create
*
* @author Ryan Campbell (ryan.campbell@gmail.com)
*
*/
public class ImageCreateResponse {
@JsonProperty("status")
private String id;
public String getId() {
return id;
}
@Override
public String toString() {
return "ContainerCreateResponse{" +
"id='" + id + '\'' +
'}';
}
}

View File

@ -0,0 +1,150 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.annotate.JsonProperty;
/**
*
* @author Konstantin Pelykh (kpelykh@gmail.com)
*
*/
public class ImageInspectResponse {
@JsonProperty("id")
private String id;
@JsonProperty("parent") private String parent;
@JsonProperty("created") private String created;
@JsonProperty("container") private String container;
@JsonProperty("container_config") private ContainerConfig containerConfig;
@JsonProperty("Size") private int size;
@JsonProperty("docker_version") private String dockerVersion;
@JsonProperty("config") private ContainerConfig config;
@JsonProperty("architecture") private String arch;
@JsonProperty("comment") private String comment;
@JsonProperty("author") private String author;
@JsonProperty("os") private String os;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getParent() {
return parent;
}
public void setParent(String parent) {
this.parent = parent;
}
public String getCreated() {
return created;
}
public void setCreated(String created) {
this.created = created;
}
public String getContainer() {
return container;
}
public void setContainer(String container) {
this.container = container;
}
public ContainerConfig getContainerConfig() {
return containerConfig;
}
public void setContainerConfig(ContainerConfig containerConfig) {
this.containerConfig = containerConfig;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public String getDockerVersion() {
return dockerVersion;
}
public void setDockerVersion(String dockerVersion) {
this.dockerVersion = dockerVersion;
}
public ContainerConfig getConfig() {
return config;
}
public void setConfig(ContainerConfig config) {
this.config = config;
}
public String getArch() {
return arch;
}
public void setArch(String arch) {
this.arch = arch;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getOs() {
return os;
}
public void setOs(String os) {
this.os = os;
}
@Override
public String toString() {
return "ImageInspectResponse{" +
"id='" + id + '\'' +
", parent='" + parent + '\'' +
", created='" + created + '\'' +
", container='" + container + '\'' +
", containerConfig=" + containerConfig +
", size=" + size +
", dockerVersion='" + dockerVersion + '\'' +
", config=" + config +
", arch='" + arch + '\'' +
", comment='" + comment + '\'' +
", author='" + author + '\'' +
", os='" + os + '\'' +
'}';
}
}

View File

@ -0,0 +1,225 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import java.util.List;
/**
*
* @author Konstantin Pelykh (kpelykh@gmail.com)
*
*/
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
public class Info {
@JsonProperty("Debug")
private boolean debug;
@JsonProperty("Containers")
private int containers;
@JsonProperty("Driver")
private String driver;
@JsonProperty("DriverStatus")
private List<Object> driverStatuses;
@JsonProperty("Images")
private int images;
@JsonProperty("IPv4Forwarding")
private String IPv4Forwarding;
@JsonProperty("IndexServerAddress")
private String IndexServerAddress;
@JsonProperty("InitPath")
private String initPath;
@JsonProperty("InitSha1")
private String initSha1;
@JsonProperty("KernelVersion")
private String kernelVersion;
@JsonProperty("LXCVersion")
private String lxcVersion;
@JsonProperty("MemoryLimit")
private boolean memoryLimit;
@JsonProperty("NEventsListener")
private long nEventListener;
@JsonProperty("NFd")
private int NFd;
@JsonProperty("NGoroutines")
private int NGoroutines;
@JsonProperty("SwapLimit")
private int swapLimit;
@JsonProperty("ExecutionDriver")
private String executionDriver;
public boolean isDebug() {
return debug;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
public int getContainers() {
return containers;
}
public void setContainers(int containers) {
this.containers = containers;
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public List<Object> getDriverStatuses() {
return driverStatuses;
}
public void setDriverStatuses(List<Object> driverStatuses) {
this.driverStatuses = driverStatuses;
}
public int getImages() {
return images;
}
public void setImages(int images) {
this.images = images;
}
public String getIPv4Forwarding() {
return IPv4Forwarding;
}
public void setIPv4Forwarding(String IPv4Forwarding) {
this.IPv4Forwarding = IPv4Forwarding;
}
public String getIndexServerAddress() {
return IndexServerAddress;
}
public void setIndexServerAddress(String indexServerAddress) {
IndexServerAddress = indexServerAddress;
}
public String getInitPath() {
return initPath;
}
public void setInitPath(String initPath) {
this.initPath = initPath;
}
public String getInitSha1() {
return initSha1;
}
public void setInitSha1(String initSha1) {
this.initSha1 = initSha1;
}
public String getKernelVersion() {
return kernelVersion;
}
public void setKernelVersion(String kernelVersion) {
this.kernelVersion = kernelVersion;
}
public String getLxcVersion() {
return lxcVersion;
}
public void setLxcVersion(String lxcVersion) {
this.lxcVersion = lxcVersion;
}
public boolean isMemoryLimit() {
return memoryLimit;
}
public void setMemoryLimit(boolean memoryLimit) {
this.memoryLimit = memoryLimit;
}
public long getnEventListener() {
return nEventListener;
}
public void setnEventListener(long nEventListener) {
this.nEventListener = nEventListener;
}
public int getNFd() {
return NFd;
}
public void setNFd(int NFd) {
this.NFd = NFd;
}
public int getNGoroutines() {
return NGoroutines;
}
public void setNGoroutines(int NGoroutines) {
this.NGoroutines = NGoroutines;
}
public int getSwapLimit() {
return swapLimit;
}
public void setSwapLimit(int swapLimit) {
this.swapLimit = swapLimit;
}
public String getExecutionDriver() {
return executionDriver;
}
public void setExecutionDriver(String executionDriver) {
this.executionDriver=executionDriver;
}
@Override
public String toString() {
return "Info{" +
"debug=" + debug +
", containers=" + containers +
", driver='" + driver + '\'' +
", driverStatuses=" + driverStatuses +
", images=" + images +
", IPv4Forwarding='" + IPv4Forwarding + '\'' +
", IndexServerAddress='" + IndexServerAddress + '\'' +
", initPath='" + initPath + '\'' +
", initSha1='" + initSha1 + '\'' +
", kernelVersion='" + kernelVersion + '\'' +
", lxcVersion='" + lxcVersion + '\'' +
", memoryLimit=" + memoryLimit +
", nEventListener=" + nEventListener +
", NFd=" + NFd +
", NGoroutines=" + NGoroutines +
", swapLimit=" + swapLimit +
'}';
}
}

View File

@ -0,0 +1,52 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.annotate.JsonProperty;
/**
* @author <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
*/
public class Port {
@JsonProperty("PrivatePort")
private long privatePort;
@JsonProperty("PublicPort")
private long publicPort;
@JsonProperty("Type")
private String type;
public long getPrivatePort() {
return privatePort;
}
public void setPrivatePort(long privatePort) {
this.privatePort = privatePort;
}
public long getPublicPort() {
return publicPort;
}
public void setPublicPort(long publicPort) {
this.publicPort = publicPort;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public String toString() {
return "Port{" +
"privatePort=" + privatePort +
", publicPort=" + publicPort +
", type='" + type + '\'' +
'}';
}
}

View File

@ -0,0 +1,131 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.*;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;
import org.codehaus.jackson.map.annotate.JsonDeserialize;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.node.NullNode;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Created by ben on 16/12/13.
*/
@JsonDeserialize(using=Ports.Deserializer.class)
@JsonSerialize(using=Ports.Serializer.class)
public class Ports {
private final Map<String, Port> ports = new HashMap<String, Port>();
public Ports() { }
public void addPort(Port port) {
ports.put(port.getPort(), port);
}
@Override
public String toString(){
return ports.toString();
}
public Map<String, Port> getAllPorts(){
return ports;
}
public static class Port{
private final String scheme;
private final String port;
private final String hostIp;
private final String hostPort;
public Port(String scheme_, String port_, String hostIp_, String hostPort_) {
scheme = scheme_;
port = port_;
hostIp = hostIp_;
hostPort = hostPort_;
}
public String getScheme() {
return scheme;
}
public String getPort() {
return port;
}
public String getHostIp() {
return hostIp;
}
public String getHostPort() {
return hostPort;
}
public static Port makePort(String full, String hostIp, String hostPort) {
if (full == null) return null;
String[] pieces = full.split("/");
return new Port(pieces[1], pieces[0], hostIp, hostPort);
}
@Override
public String toString() {
return "Port{" +
"scheme='" + scheme + '\'' +
", port='" + port + '\'' +
", hostIp='" + hostIp + '\'' +
", hostPort='" + hostPort + '\'' +
'}';
}
}
public static class Deserializer extends JsonDeserializer<Ports> {
@Override
public Ports deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
Ports out = new Ports();
ObjectCodec oc = jsonParser.getCodec();
JsonNode node = oc.readTree(jsonParser);
for (Iterator<Map.Entry<String, JsonNode>> it = node.getFields(); it.hasNext();) {
Map.Entry<String, JsonNode> field = it.next();
if (!field.getValue().equals(NullNode.getInstance())) {
String hostIp = field.getValue().get(0).get("HostIp").getTextValue();
String hostPort = field.getValue().get(0).get("HostPort").getTextValue();
out.addPort(Port.makePort(field.getKey(), hostIp, hostPort));
}
}
return out;
}
}
public static class Serializer extends JsonSerializer<Ports> {
@Override
public void serialize(Ports ports, JsonGenerator jsonGen,
SerializerProvider serProvider) throws IOException, JsonProcessingException {
jsonGen.writeStartObject();//{
for(String portKey : ports.getAllPorts().keySet()){
Port p = ports.getAllPorts().get(portKey);
jsonGen.writeFieldName(p.getPort() + "/" + p.getScheme());
jsonGen.writeStartArray();
jsonGen.writeStartObject();
jsonGen.writeStringField("HostIp", p.hostIp);
jsonGen.writeStringField("HostPort", p.hostPort);
jsonGen.writeEndObject();
jsonGen.writeEndArray();
}
jsonGen.writeEndObject();//}
}
}
}

View File

@ -0,0 +1,52 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.annotate.JsonProperty;
/**
*
* @author Konstantin Pelykh (kpelykh@gmail.com)
*
*/
public class SearchItem {
@JsonProperty("star_count")
private int starCount;
@JsonProperty("is_official")
private boolean isOfficial;
@JsonProperty("is_trusted")
private boolean isTrusted;
@JsonProperty("name")
private String name;
@JsonProperty("description")
private String description;
public int getStarCount() {
return starCount;
}
public boolean isOfficial() {
return isOfficial;
}
public boolean isTrusted() {
return isTrusted;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return "name='" + name + '\'' +
", description='" + description + '\'' + '}';
}
}

View File

@ -0,0 +1,91 @@
package com.kpelykh.docker.client.model;
import org.codehaus.jackson.annotate.JsonProperty;
/**
*
* @author Konstantin Pelykh (kpelykh@gmail.com)
*
*/
public class Version {
@JsonProperty("Version")
private String version;
@JsonProperty("GitCommit")
private String gitCommit;
@JsonProperty("GoVersion")
private String goVersion;
@JsonProperty("KernelVersion")
private String kernelVersion;
@JsonProperty("Arch")
private String arch;
@JsonProperty("Os")
private String operatingSystem;
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getGitCommit() {
return gitCommit;
}
public void setGitCommit(String gitCommit) {
this.gitCommit = gitCommit;
}
public String getGoVersion() {
return goVersion;
}
public void setGoVersion(String goVersion) {
this.goVersion = goVersion;
}
public String getKernelVersion() {
return kernelVersion;
}
public void setKernelVersion(String kernelVersion) {
this.kernelVersion = kernelVersion;
}
public String getArch() {
return arch;
}
public void setArch(String arch) {
this.arch = arch;
}
public String getOperatingSystem() {
return operatingSystem;
}
public void setOperatingSystem(String operatingSystem) {
this.operatingSystem = operatingSystem;
}
@Override
public String toString() {
return "Version{" +
"version='" + version + '\'' +
", gitCommit='" + gitCommit + '\'' +
", goVersion='" + goVersion + '\'' +
", kernelVersion='" + kernelVersion + '\'' +
", arch='" + arch + '\'' +
", operatingSystem='" + operatingSystem + '\'' +
'}';
}
}

View File

@ -0,0 +1,59 @@
package com.kpelykh.docker.client.utils;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.RegexFileFilter;
import org.apache.commons.lang.StringUtils;
import java.io.*;
import java.util.Collection;
import static org.apache.commons.io.filefilter.FileFilterUtils.*;
public class CompressArchiveUtil {
public static File archiveTARFiles(File baseDir, String archiveNameWithOutExtension) throws IOException {
File tarFile = null;
tarFile = new File(FileUtils.getTempDirectoryPath(), archiveNameWithOutExtension + ".tar");
Collection<File> files =
FileUtils.listFiles(
baseDir,
new RegexFileFilter("^(.*?)"),
and(directoryFileFilter(), notFileFilter(nameFileFilter(baseDir.getName()))));
byte[] buf = new byte[1024];
int len;
{
TarArchiveOutputStream tos = new TarArchiveOutputStream(new FileOutputStream(tarFile));
tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
for (File file : files) {
TarArchiveEntry tarEntry = new TarArchiveEntry(file);
tarEntry.setName(StringUtils.substringAfter(file.toString(), baseDir.getPath()));
tos.putArchiveEntry(tarEntry);
if (!file.isDirectory()) {
FileInputStream fin = new FileInputStream(file);
BufferedInputStream in = new BufferedInputStream(fin);
while ((len = in.read(buf)) != -1) {
tos.write(buf, 0, len);
}
in.close();
}
tos.closeArchiveEntry();
}
tos.close();
}
return tarFile;
}
}

View File

@ -0,0 +1,26 @@
package com.kpelykh.docker.client.utils;
import com.sun.jersey.api.client.ClientRequest;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.filter.ClientFilter;
/**
*
* @author Konstantin Pelykh (kpelykh@gmail.com)
*
*/
public class JsonClientFilter extends ClientFilter {
public ClientResponse handle(ClientRequest cr) {
// Call the next filter
ClientResponse resp = getNext().handle(cr);
String respContentType = resp.getHeaders().getFirst("Content-Type");
if (respContentType.startsWith("text/plain")) {
String newContentType = "application/json" + respContentType.substring(10);
resp.getHeaders().putSingle("Content-Type", newContentType);
}
return resp;
}
}

View File

@ -0,0 +1,791 @@
package com.kpelykh.docker.client.test;
import com.kpelykh.docker.client.DockerClient;
import com.kpelykh.docker.client.DockerException;
import com.kpelykh.docker.client.model.*;
import com.sun.jersey.api.client.ClientResponse;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.LineIterator;
import org.apache.commons.lang.StringUtils;
import org.hamcrest.Matcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.ITestResult;
import org.testng.annotations.*;
import java.io.*;
import java.lang.reflect.Method;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.List;
import static ch.lambdaj.Lambda.filter;
import static ch.lambdaj.Lambda.selectUnique;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.hasItem;
import static org.testinfected.hamcrest.jpa.HasFieldWithValue.hasField;
/**
* Unit test for DockerClient.
* @author Konstantin Pelykh (kpelykh@gmail.com)
*/
public class DockerClientTest extends Assert
{
public static final Logger LOG = LoggerFactory.getLogger(DockerClientTest.class);
private DockerClient dockerClient;
private List<String> tmpImgs = new ArrayList<String>();
private List<String> tmpContainers = new ArrayList<String>();
@BeforeTest
public void beforeTest() throws DockerException {
LOG.info("======================= BEFORETEST =======================");
String url = System.getProperty("docker.url", "http://192.168.1.188:5555");
LOG.info("Connecting to Docker server at " + url);
dockerClient = new DockerClient(url);
LOG.info("Creating image 'busybox'");
dockerClient.pull("busybox");
assertNotNull(dockerClient);
LOG.info("======================= END OF BEFORETEST =======================\n\n");
}
@AfterTest
public void afterTest() {
LOG.info("======================= END OF AFTERTEST =======================");
}
@BeforeMethod
public void beforeMethod(Method method) {
LOG.info(String.format("################################## STARTING %s ##################################", method.getName()));
}
@AfterMethod
public void afterMethod(ITestResult result) {
for (String container : tmpContainers) {
LOG.info("Cleaning up temporary container {}", container);
try {
dockerClient.stopContainer(container);
dockerClient.kill(container);
dockerClient.removeContainer(container);
} catch (DockerException ignore) {}
}
for (String image : tmpImgs) {
LOG.info("Cleaning up temporary image {}", image);
try {
dockerClient.removeImage(image);
} catch (DockerException ignore) {}
}
LOG.info("################################## END OF {} ##################################\n", result.getName());
}
/*
* #########################
* ## INFORMATION TESTS ##
* #########################
*/
@Test
public void testDockerVersion() throws DockerException {
Version version = dockerClient.version();
LOG.info(version.toString());
assertTrue(version.getGoVersion().length() > 0);
assertTrue(version.getVersion().length() > 0);
assertEquals(StringUtils.split(version.getVersion(), ".").length, 3);
}
@Test
public void testDockerInfo() throws DockerException {
Info dockerInfo = dockerClient.info();
LOG.info(dockerInfo.toString());
assertTrue(dockerInfo.toString().contains("containers"));
assertTrue(dockerInfo.toString().contains("images"));
assertTrue(dockerInfo.toString().contains("debug"));
assertTrue(dockerInfo.getContainers() > 0);
assertTrue(dockerInfo.getImages() > 0);
assertTrue(dockerInfo.getNFd() > 0);
assertTrue(dockerInfo.getNGoroutines() > 0);
assertTrue(dockerInfo.isMemoryLimit());
}
@Test
public void testDockerSearch() throws DockerException {
List<SearchItem> dockerSearch = dockerClient.search("busybox");
LOG.info("Search returned {}", dockerSearch.toString());
Matcher matcher = hasItem(hasField("name", equalTo("busybox")));
assertThat(dockerSearch, matcher);
assertThat(filter(hasField("name", is("busybox")), dockerSearch).size(), equalTo(1));
}
/*
* ###################
* ## LISTING TESTS ##
* ###################
*/
@Test
public void testImages() throws DockerException {
List<Image> images = dockerClient.getImages(true);
assertThat(images, notNullValue());
LOG.info("Images List: {}", images);
Info info = dockerClient.info();
assertThat(images.size(), equalTo(info.getImages()));
Image img = images.get(0);
assertThat(img.getCreated(), is(greaterThan(0L)) );
assertThat(img.getVirtualSize(), is(greaterThan(0L)) );
assertThat(img.getId(), not(isEmptyString()));
assertThat(img.getTag(), not(isEmptyString()));
assertThat(img.getRepository(), not(isEmptyString()));
}
@Test
public void testListContainers() throws DockerException {
List<Container> containers = dockerClient.listContainers(true);
assertThat(containers, notNullValue());
LOG.info("Container List: {}", containers);
int size = containers.size();
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.setImage("busybox");
containerConfig.setCmd(new String[]{"echo"});
ContainerCreateResponse container1 = dockerClient.createContainer(containerConfig);
assertThat(container1.getId(), not(isEmptyString()));
dockerClient.startContainer(container1.getId());
tmpContainers.add(container1.getId());
List containers2 = dockerClient.listContainers(true);
assertThat(size + 1, is(equalTo(containers2.size())));
Matcher matcher = hasItem(hasField("id", startsWith(container1.getId())));
assertThat(containers2, matcher);
List<Container> filteredContainers = filter(hasField("id", startsWith(container1.getId())), containers2);
assertThat(filteredContainers.size(), is(equalTo(1)));
Container container2 = filteredContainers.get(0);
assertThat(container2.getCommand(), not(isEmptyString()));
assertThat(container2.getImage(), equalTo("busybox:latest"));
}
/*
* #####################
* ## CONTAINER TESTS ##
* #####################
*/
@Test
public void testCreateContainer() throws DockerException {
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.setImage("busybox");
containerConfig.setCmd(new String[]{"true"});
ContainerCreateResponse container = dockerClient.createContainer(containerConfig);
LOG.info("Created container {}", container.toString());
assertThat(container.getId(), not(isEmptyString()));
tmpContainers.add(container.getId());
}
@Test
public void testStartContainer() throws DockerException {
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.setImage("busybox");
containerConfig.setCmd(new String[]{"true"});
ContainerCreateResponse container = dockerClient.createContainer(containerConfig);
LOG.info("Created container {}", container.toString());
assertThat(container.getId(), not(isEmptyString()));
boolean add = tmpContainers.add(container.getId());
dockerClient.startContainer(container.getId());
ContainerInspectResponse containerInspectResponse = dockerClient.inspectContainer(container.getId());
LOG.info("Container Inspect: {}", containerInspectResponse.toString());
assertThat(containerInspectResponse.config, is(notNullValue()));
assertThat(containerInspectResponse.getId(), not(isEmptyString()));
assertThat(containerInspectResponse.getId(), startsWith(container.getId()));
assertThat(containerInspectResponse.getImage(), not(isEmptyString()));
assertThat(containerInspectResponse.getState(), is(notNullValue()));
assertThat(containerInspectResponse.getState().running, is(true));
if (!containerInspectResponse.getState().running) {
assertThat(containerInspectResponse.getState().exitCode, is(equalTo(0)));
}
}
@Test
public void testWaitContainer() throws DockerException {
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.setImage("busybox");
containerConfig.setCmd(new String[]{"true"});
ContainerCreateResponse container = dockerClient.createContainer(containerConfig);
LOG.info("Created container: {}", container.toString());
assertThat(container.getId(), not(isEmptyString()));
tmpContainers.add(container.getId());
dockerClient.startContainer(container.getId());
int exitCode = dockerClient.waitContainer(container.getId());
LOG.info("Container exit code: {}", exitCode);
assertThat(exitCode, equalTo(0));
ContainerInspectResponse containerInspectResponse = dockerClient.inspectContainer(container.getId());
LOG.info("Container Inspect: {}", containerInspectResponse.toString());
assertThat(containerInspectResponse.getState().running, is(equalTo(false)));
assertThat(containerInspectResponse.getState().exitCode, is(equalTo(exitCode)));
}
@Test
public void testLogs() throws DockerException, IOException {
String snippet = "hello world";
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.setImage("busybox");
containerConfig.setCmd(new String[] {"/bin/echo", snippet});
ContainerCreateResponse container = dockerClient.createContainer(containerConfig);
LOG.info("Created container: {}", container.toString());
assertThat(container.getId(), not(isEmptyString()));
dockerClient.startContainer(container.getId());
tmpContainers.add(container.getId());
int exitCode = dockerClient.waitContainer(container.getId());
assertThat(exitCode, equalTo(0));
ClientResponse response = dockerClient.logContainer(container.getId());
StringWriter logwriter = new StringWriter();
try {
LineIterator itr = IOUtils.lineIterator(response.getEntityInputStream(), "UTF-8");
while (itr.hasNext()) {
String line = itr.next();
logwriter.write(line + (itr.hasNext() ? "\n" : ""));
LOG.info(line);
}
} finally {
IOUtils.closeQuietly(response.getEntityInputStream());
}
String fullLog = logwriter.toString();
LOG.info("Container log: {}", fullLog);
assertThat(fullLog, endsWith(snippet));
}
//This test doesn't work in Ubuntu 12.04 due to
//Error mounting '/dev/mapper/docker-8:5-...
//ref: https://github.com/dotcloud/docker/issues/4036
@Test
public void testDiff() throws DockerException {
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.setImage("busybox");
containerConfig.setCmd(new String[] {"touch", "/test"});
ContainerCreateResponse container = dockerClient.createContainer(containerConfig);
LOG.info("Created container: {}", container.toString());
assertThat(container.getId(), not(isEmptyString()));
dockerClient.startContainer(container.getId());
boolean add = tmpContainers.add(container.getId());
int exitCode = dockerClient.waitContainer(container.getId());
assertThat(exitCode, equalTo(0));
List filesystemDiff = dockerClient.containterDiff(container.getId());
LOG.info("Container DIFF: {}", filesystemDiff.toString());
assertThat(filesystemDiff.size(), equalTo(1));
ChangeLog testChangeLog = selectUnique(filesystemDiff, hasField("path", equalTo("/test")));
assertThat(testChangeLog, hasField("path", equalTo("/test")));
assertThat(testChangeLog, hasField("kind", equalTo(1)));
}
@Test
public void testStopContainer() throws DockerException {
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.setImage("busybox");
containerConfig.setCmd(new String[] {"sleep", "9999"});
ContainerCreateResponse container = dockerClient.createContainer(containerConfig);
LOG.info("Created container: {}", container.toString());
assertThat(container.getId(), not(isEmptyString()));
dockerClient.startContainer(container.getId());
tmpContainers.add(container.getId());
LOG.info("Stopping container: {}", container.getId());
dockerClient.stopContainer(container.getId(), 2);
ContainerInspectResponse containerInspectResponse = dockerClient.inspectContainer(container.getId());
LOG.info("Container Inspect: {}", containerInspectResponse.toString());
assertThat(containerInspectResponse.getState().running, is(equalTo(false)));
assertThat(containerInspectResponse.getState().exitCode, not(equalTo(0)));
}
@Test
public void testKillContainer() throws DockerException {
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.setImage("busybox");
containerConfig.setCmd(new String[] {"sleep", "9999"});
ContainerCreateResponse container = dockerClient.createContainer(containerConfig);
LOG.info("Created container: {}", container.toString());
assertThat(container.getId(), not(isEmptyString()));
dockerClient.startContainer(container.getId());
tmpContainers.add(container.getId());
LOG.info("Killing container: {}", container.getId());
dockerClient.kill(container.getId());
ContainerInspectResponse containerInspectResponse = dockerClient.inspectContainer(container.getId());
LOG.info("Container Inspect: {}", containerInspectResponse.toString());
assertThat(containerInspectResponse.getState().running, is(equalTo(false)));
assertThat(containerInspectResponse.getState().exitCode, not(equalTo(0)));
}
@Test
public void restartContainer() throws DockerException {
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.setImage("busybox");
containerConfig.setCmd(new String[] {"sleep", "9999"});
ContainerCreateResponse container = dockerClient.createContainer(containerConfig);
LOG.info("Created container: {}", container.toString());
assertThat(container.getId(), not(isEmptyString()));
dockerClient.startContainer(container.getId());
tmpContainers.add(container.getId());
ContainerInspectResponse containerInspectResponse = dockerClient.inspectContainer(container.getId());
LOG.info("Container Inspect: {}", containerInspectResponse.toString());
String startTime = containerInspectResponse.getState().startedAt;
dockerClient.restart(container.getId(), 2);
ContainerInspectResponse containerInspectResponse2 = dockerClient.inspectContainer(container.getId());
LOG.info("Container Inspect After Restart: {}", containerInspectResponse2.toString());
String startTime2 = containerInspectResponse2.getState().startedAt;
assertThat(startTime, not(equalTo(startTime2)));
assertThat(containerInspectResponse.getState().running, is(equalTo(true)));
dockerClient.kill(container.getId());
}
@Test
public void removeContainer() throws DockerException {
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.setImage("busybox");
containerConfig.setCmd(new String[] {"true"});
ContainerCreateResponse container = dockerClient.createContainer(containerConfig);
dockerClient.startContainer(container.getId());
dockerClient.waitContainer(container.getId());
tmpContainers.add(container.getId());
LOG.info("Removing container: {}", container.getId());
dockerClient.removeContainer(container.getId());
List containers2 = dockerClient.listContainers(true);
Matcher matcher = not(hasItem(hasField("id", startsWith(container.getId()))));
assertThat(containers2, matcher);
}
/*
* ##################
* ## IMAGES TESTS ##
* ##################
* */
@Test
public void testPullImage() throws DockerException, IOException {
String testImage = "centos";
LOG.info("Removing image: {}", testImage);
dockerClient.removeImage(testImage);
Info info = dockerClient.info();
LOG.info("Client info: {}", info.toString());
int imgCount= info.getImages();
LOG.info("Pulling image: {}", testImage);
ClientResponse response = dockerClient.pull(testImage);
StringWriter logwriter = new StringWriter();
try {
LineIterator itr = IOUtils.lineIterator(response.getEntityInputStream(), "UTF-8");
while (itr.hasNext()) {
String line = itr.next();
logwriter.write(line + "\n");
LOG.info(line);
}
} finally {
IOUtils.closeQuietly(response.getEntityInputStream());
}
String fullLog = logwriter.toString();
assertThat(fullLog, containsString("Download complete"));
tmpImgs.add(testImage);
info = dockerClient.info();
LOG.info("Client info after pull, {}", info.toString());
assertThat(imgCount, lessThan(info.getImages()));
ImageInspectResponse imageInspectResponse = dockerClient.inspectImage(testImage);
LOG.info("Image Inspect: {}", imageInspectResponse.toString());
assertThat(imageInspectResponse, notNullValue());
}
//This test doesn't work in Ubuntu 12.04 due to
//Error mounting '/dev/mapper/docker-8:5-...
//ref: https://github.com/dotcloud/docker/issues/4036
@Test
public void commitImage() throws DockerException {
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.setImage("busybox");
containerConfig.setCmd(new String[] {"touch", "/test"});
ContainerCreateResponse container = dockerClient.createContainer(containerConfig);
LOG.info("Created container: {}", container.toString());
assertThat(container.getId(), not(isEmptyString()));
dockerClient.startContainer(container.getId());
tmpContainers.add(container.getId());
LOG.info("Commiting container: {}", container.toString());
String imageId = dockerClient.commit(new CommitConfig(container.getId()));
tmpImgs.add(imageId);
ImageInspectResponse imageInspectResponse = dockerClient.inspectImage(imageId);
LOG.info("Image Inspect: {}", imageInspectResponse.toString());
assertThat(imageInspectResponse, hasField("container", startsWith(container.getId())));
assertThat(imageInspectResponse.getContainerConfig().getImage(), equalTo("busybox"));
ImageInspectResponse busyboxImg = dockerClient.inspectImage("busybox");
assertThat(imageInspectResponse.getParent(), equalTo(busyboxImg.getId()));
}
@Test
public void testRemoveImage() throws DockerException, InterruptedException {
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.setImage("busybox");
containerConfig.setCmd(new String[] {"touch", "/test"});
ContainerCreateResponse container = dockerClient.createContainer(containerConfig);
LOG.info("Created container: {}", container.toString());
assertThat(container.getId(), not(isEmptyString()));
dockerClient.startContainer(container.getId());
tmpContainers.add(container.getId());
LOG.info("Commiting container {}", container.toString());
String imageId = dockerClient.commit(new CommitConfig(container.getId()));
tmpImgs.add(imageId);
dockerClient.stopContainer(container.getId());
dockerClient.kill(container.getId());
dockerClient.removeContainer(container.getId());
tmpContainers.remove(container.getId());
LOG.info("Removing image: {}", imageId);
dockerClient.removeImage(imageId);
List containers = dockerClient.listContainers(true);
Matcher matcher = not(hasItem(hasField("id", startsWith(imageId))));
assertThat(containers, matcher);
}
/*
*
* ################
* ## MISC TESTS ##
* ################
*/
@Test
public void testRunShlex() throws DockerException {
String[] commands = new String[] {
"true",
"echo \"The Young Descendant of Tepes & Septette for the Dead Princess\"",
"echo -n 'The Young Descendant of Tepes & Septette for the Dead Princess'",
"/bin/sh -c echo Hello World",
"/bin/sh -c echo 'Hello World'",
"echo 'Night of Nights'",
"true && echo 'Night of Nights'"
};
for (String command : commands) {
LOG.info("Running command: [{}]", command);
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.setImage("busybox");
containerConfig.setCmd( commands );
ContainerCreateResponse container = dockerClient.createContainer(containerConfig);
dockerClient.startContainer(container.getId());
tmpContainers.add(container.getId());
int exitcode = dockerClient.waitContainer(container.getId());
assertThat(exitcode, equalTo(0));
}
}
@Test
public void testNginxDockerfileBuilder() throws DockerException, IOException {
File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("nginx").getFile());
ClientResponse response = dockerClient.build(baseDir);
StringWriter logwriter = new StringWriter();
try {
LineIterator itr = IOUtils.lineIterator(response.getEntityInputStream(), "UTF-8");
while (itr.hasNext()) {
String line = itr.next();
logwriter.write(line + "\n");
LOG.info(line);
}
} finally {
IOUtils.closeQuietly(response.getEntityInputStream());
}
String fullLog = logwriter.toString();
assertThat(fullLog, containsString("Successfully built"));
String imageId = StringUtils.substringBetween(fullLog, "Successfully built ", "\\n\"}").trim();
ImageInspectResponse imageInspectResponse = dockerClient.inspectImage(imageId);
assertThat(imageInspectResponse, not(nullValue()));
LOG.info("Image Inspect: {}", imageInspectResponse.toString());
tmpImgs.add(imageInspectResponse.getId());
assertThat(imageInspectResponse.getAuthor(), equalTo("Guillaume J. Charmes \"guillaume@dotcloud.com\""));
}
@Test
public void testDockerBuilderAddFile() throws DockerException, IOException {
File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testAddFile").getFile());
dockerfileBuild(baseDir, "Successfully executed testrun.sh");
}
@Test
public void testDockerBuilderAddFolder() throws DockerException, IOException {
File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testAddFolder").getFile());
dockerfileBuild(baseDir, "Successfully executed testAddFolder.sh");
}
@Test
public void testImportImageFromTar() throws DockerException, IOException {
InputStream tar = Thread.currentThread().getContextClassLoader().getResourceAsStream("testImportImageFromTar/empty.tar");
String imageId = dockerClient.importImage("empty", null, tar).getId();
assert imageId.contains(dockerClient.inspectImage("empty").getId());
}
@Test
public void testNetCatDockerfileBuilder() throws DockerException, IOException, InterruptedException {
File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("netcat").getFile());
ClientResponse response = dockerClient.build(baseDir);
StringWriter logwriter = new StringWriter();
try {
LineIterator itr = IOUtils.lineIterator(response.getEntityInputStream(), "UTF-8");
while (itr.hasNext()) {
String line = itr.next();
logwriter.write(line + "\n");
LOG.info(line);
}
} finally {
IOUtils.closeQuietly(response.getEntityInputStream());
}
String fullLog = logwriter.toString();
assertThat(fullLog, containsString("Successfully built"));
String imageId = StringUtils.substringBetween(fullLog, "Successfully built ", "\\n\"}").trim();
ImageInspectResponse imageInspectResponse = dockerClient.inspectImage(imageId);
assertThat(imageInspectResponse, not(nullValue()));
LOG.info("Image Inspect: {}", imageInspectResponse.toString());
tmpImgs.add(imageInspectResponse.getId());
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.setImage(imageInspectResponse.getId());
ContainerCreateResponse container = dockerClient.createContainer(containerConfig);
assertThat(container.getId(), not(isEmptyString()));
dockerClient.startContainer(container.getId());
tmpContainers.add(container.getId());
ContainerInspectResponse containerInspectResponse = dockerClient.inspectContainer(container.getId());
assertThat(containerInspectResponse.getId(), notNullValue());
assertThat(containerInspectResponse.getNetworkSettings().ports, notNullValue());
//No use as such if not running on the server
for(String portstr : containerInspectResponse.getNetworkSettings().ports.getAllPorts().keySet()){
Ports.Port p = containerInspectResponse.getNetworkSettings().ports.getAllPorts().get(portstr);
int port = Integer.valueOf(p.getHostPort());
LOG.info("Checking port {} is open", port);
assertThat(available(port), is(false));
}
dockerClient.stopContainer(container.getId(), 0);
}
// UTIL
/**
* Checks to see if a specific port is available.
*
* @param port the port to check for availability
*/
public static boolean available(int port) {
if (port < 1100 || port > 60000) {
throw new IllegalArgumentException("Invalid start port: " + port);
}
ServerSocket ss = null;
DatagramSocket ds = null;
try {
ss = new ServerSocket(port);
ss.setReuseAddress(true);
ds = new DatagramSocket(port);
ds.setReuseAddress(true);
return true;
} catch (IOException e) {
} finally {
if (ds != null) {
ds.close();
}
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
/* should not be thrown */
}
}
}
return false;
}
private void dockerfileBuild(File baseDir, String expectedText) throws DockerException, IOException {
//Build image
ClientResponse response = dockerClient.build(baseDir);
StringWriter logwriter = new StringWriter();
try {
LineIterator itr = IOUtils.lineIterator(response.getEntityInputStream(), "UTF-8");
while (itr.hasNext()) {
String line = itr.next();
logwriter.write(line + "\n");
LOG.info(line);
}
} finally {
IOUtils.closeQuietly(response.getEntityInputStream());
}
String fullLog = logwriter.toString();
assertThat(fullLog, containsString("Successfully built"));
String imageId = StringUtils.substringBetween(fullLog, "Successfully built ", "\\n\"}").trim();
//Create container based on image
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.setImage(imageId);
ContainerCreateResponse container = dockerClient.createContainer(containerConfig);
LOG.info("Created container: {}", container.toString());
assertThat(container.getId(), not(isEmptyString()));
dockerClient.startContainer(container.getId());
dockerClient.waitContainer(container.getId());
tmpContainers.add(container.getId());
//Log container
ClientResponse logResponse = dockerClient.logContainer(container.getId());
StringWriter logwriter2 = new StringWriter();
try {
LineIterator itr = IOUtils.lineIterator(logResponse.getEntityInputStream(), "UTF-8");
while (itr.hasNext()) {
String line = itr.next();
logwriter2.write(line + (itr.hasNext() ? "\n" : ""));
LOG.info(line);
}
} finally {
IOUtils.closeQuietly(logResponse.getEntityInputStream());
}
assertThat(logwriter2.toString(), endsWith(expectedText));
}
}

View File

@ -0,0 +1,16 @@
<configuration debug="true"> <!-- This will give you some valuable info about logback config upon runtime. Remove this for production. -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.kpelykh.docker.client" level="TRACE"/>
<logger name="com.kpelykh.docker.client.test" level="DEBUG"/>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,11 @@
# Firefox over VNC
#
# VERSION 0.3
FROM ubuntu
#install netcat
RUN apt-get install -y netcat
EXPOSE 6900
CMD ["nc", "-l", "6900"]

View File

@ -0,0 +1,12 @@
# Nginx
#
# VERSION 0.0.1
FROM ubuntu
MAINTAINER Guillaume J. Charmes "guillaume@dotcloud.com"
# make sure the package repository is up to date
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
RUN apt-get install -y inotify-tools nginx apache2 openssh-server

View File

@ -0,0 +1,9 @@
FROM ubuntu
# Copy testrun.sh files into the container
ADD ./testrun.sh /tmp/
run cp /tmp/testrun.sh /usr/local/bin/ && chmod +x /usr/local/bin/testrun.sh
CMD ["testrun.sh"]

View File

@ -0,0 +1,3 @@
#!/bin/sh
echo "Successfully executed testrun.sh"

View File

@ -0,0 +1,11 @@
FROM ubuntu
# Copy testrun.sh files into the container
ADD . /src/
run ls -la /src
run cp /src/folderA/testAddFolder.sh /usr/local/bin/ && chmod +x /usr/local/bin/testAddFolder.sh
CMD ["testAddFolder.sh"]

View File

@ -0,0 +1,3 @@
#!/bin/sh
echo "Successfully executed testAddFolder.sh"

View File

@ -427,6 +427,11 @@
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<dependency>
<groupId>com.kpelykh</groupId>
<artifactId>docker-java</artifactId>
<version>0.8.2-SNAPSHOT</version>
</dependency>
</dependencies>
<build>