You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by na...@apache.org on 2014/07/07 11:52:10 UTC
[3/3] git commit: [JCLOUDS-500] Initial commit for docker
[JCLOUDS-500] Initial commit for docker
Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs/commit/9b124ee9
Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs/tree/9b124ee9
Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs/diff/9b124ee9
Branch: refs/heads/master
Commit: 9b124ee9f12e0392b6d2f083308297bfcca8ea79
Parents: 422ffe0
Author: Andrea Turli <an...@gmail.com>
Authored: Tue Jan 28 10:42:43 2014 +0100
Committer: Ignasi Barrera <na...@apache.org>
Committed: Mon Jul 7 11:48:24 2014 +0200
----------------------------------------------------------------------
docker/README.md | 48 ++
docker/pom.xml | 143 ++++++
.../main/java/org/jclouds/docker/DockerApi.java | 37 ++
.../org/jclouds/docker/DockerApiMetadata.java | 98 ++++
.../binders/BindInputStreamToRequest.java | 68 +++
.../DockerComputeServiceContextModule.java | 58 +++
.../functions/ContainerToNodeMetadata.java | 126 +++++
.../docker/compute/functions/ImageToImage.java | 98 ++++
.../docker/compute/functions/StateToStatus.java | 38 ++
.../compute/options/DockerTemplateOptions.java | 485 +++++++++++++++++++
.../strategy/DockerComputeServiceAdapter.java | 232 +++++++++
.../docker/config/DockerHttpApiModule.java | 40 ++
.../docker/config/DockerParserModule.java | 62 +++
.../jclouds/docker/config/DockerProperties.java | 26 +
.../java/org/jclouds/docker/domain/Config.java | 457 +++++++++++++++++
.../org/jclouds/docker/domain/Container.java | 389 +++++++++++++++
.../org/jclouds/docker/domain/ExposedPorts.java | 106 ++++
.../org/jclouds/docker/domain/HostConfig.java | 242 +++++++++
.../java/org/jclouds/docker/domain/Image.java | 239 +++++++++
.../jclouds/docker/domain/NetworkSettings.java | 175 +++++++
.../java/org/jclouds/docker/domain/Port.java | 88 ++++
.../java/org/jclouds/docker/domain/State.java | 166 +++++++
.../java/org/jclouds/docker/domain/Version.java | 166 +++++++
.../org/jclouds/docker/features/RemoteApi.java | 272 +++++++++++
.../docker/features/internal/Archives.java | 60 +++
.../docker/handlers/DockerErrorHandler.java | 106 ++++
.../jclouds/docker/options/BuildOptions.java | 71 +++
.../jclouds/docker/options/CommitOptions.java | 109 +++++
.../docker/options/CreateImageOptions.java | 95 ++++
.../docker/options/DeleteImageOptions.java | 44 ++
.../docker/options/ListContainerOptions.java | 97 ++++
.../docker/options/ListImageOptions.java | 43 ++
.../docker/options/RemoveContainerOptions.java | 55 +++
.../services/org.jclouds.apis.ApiMetadata | 1 +
.../jclouds/docker/DockerApiMetadataTest.java | 47 ++
.../binders/BindInputStreamToRequestTest.java | 66 +++
.../docker/compute/BaseDockerApiLiveTest.java | 91 ++++
.../DockerComputeServiceAdapterLiveTest.java | 95 ++++
.../compute/DockerComputeServiceLiveTest.java | 142 ++++++
.../functions/ContainerToNodeMetadataTest.java | 204 ++++++++
.../compute/functions/ImageToImageTest.java | 74 +++
.../compute/functions/StateToStatusTest.java | 81 ++++
.../options/DockerTemplateOptionsTest.java | 62 +++
.../docker/config/DockerParserModuleTest.java | 52 ++
.../docker/features/RemoteApiLiveTest.java | 121 +++++
.../docker/features/RemoteApiMockTest.java | 376 ++++++++++++++
.../docker/features/internal/ArchivesTest.java | 112 +++++
.../docker/internal/BaseDockerMockTest.java | 118 +++++
docker/src/test/resources/Dockerfile | 29 ++
.../src/test/resources/container-creation.json | 1 +
docker/src/test/resources/container.json | 81 ++++
docker/src/test/resources/containers.json | 20 +
docker/src/test/resources/logback.xml | 34 ++
dockerFile | 29 ++
pom.xml | 1 +
55 files changed, 6376 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9b124ee9/docker/README.md
----------------------------------------------------------------------
diff --git a/docker/README.md b/docker/README.md
new file mode 100644
index 0000000..1c4394a
--- /dev/null
+++ b/docker/README.md
@@ -0,0 +1,48 @@
+# Docker as a local cloud provider
+jclouds-docker is a local cloud provider modelled on [docker](http://www.docker.io). Similar to other jclouds supported
+providers, it supports the same portable abstractions offered by jclouds.
+
+##Setup
+
+Please follow these steps to configure your workstation for jclouds-docker:
+
+- install the latest Docker release (please visit https://docs.docker.com/installation/)
+
+#How it works
+
+
+ --------------- -------------
+ | Image(s) | | Node(s) |
+ --------------- -------------
+ --------- docker remote api ----------------------------------------
+ | jclouds | ---------------------------> | DOCKER_HOST |
+ --------- ----------------------------------------
+
+##Components
+
+- jclouds \- acts as a java client to access to docker features
+- DOCKER_HOST \- hosts Docker API, NB: jclouds-docker assumes that the latest Docker is installed
+- Image \- it is a docker image that can be started.
+- Node \- is a docker container
+
+## Assumptions
+
+- jclouds-docker assumes that the images specified using the template are ssh'able.
+
+--------------
+
+#Notes:
+- jclouds-docker is still at alpha stage please report any issues you find at [jclouds issues](https://issues.apache.org/jira/browse/JCLOUDS)
+- jclouds-docker has been tested on Mac OSX, it might work on Linux iff vbox is running and set up correctly. However, it has never been tried on Windows.
+
+--------------
+
+#Troubleshooting
+As jclouds docker support is quite new, issues may occasionally arise. Please follow these steps to get things going again:
+
+1. Remove all containers
+
+ `$ docker ps -a -q | xargs docker stop | xargs docker rm`
+2. remove all the images
+
+ `$ docker images -q | xargs docker rmi`
http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9b124ee9/docker/pom.xml
----------------------------------------------------------------------
diff --git a/docker/pom.xml b/docker/pom.xml
new file mode 100644
index 0000000..42b9d4d
--- /dev/null
+++ b/docker/pom.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.jclouds.labs</groupId>
+ <artifactId>jclouds-labs</artifactId>
+ <version>1.8.0-SNAPSHOT</version>
+ </parent>
+
+ <!-- TODO: when out of labs, switch to org.jclouds.provider -->
+ <groupId>org.apache.jclouds.labs</groupId>
+ <artifactId>docker</artifactId>
+ <name>jclouds docker API</name>
+ <description>ComputeService binding to the Docker API</description>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <test.docker.endpoint>https://localhost:4243</test.docker.endpoint>
+ <test.docker.api-version>1.10</test.docker.api-version>
+ <test.docker.identity>FIXME</test.docker.identity>
+ <test.docker.credential>FIXME</test.docker.credential>
+ <jclouds.osgi.export>org.jclouds.docker*;version="${project.version}"</jclouds.osgi.export>
+ <jclouds.osgi.import>
+ org.jclouds.compute.internal;version="${project.version}",
+ org.jclouds.rest.internal;version="${project.version}",
+ org.jclouds*;version="${project.version}",
+ *
+ </jclouds.osgi.import>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.jclouds</groupId>
+ <artifactId>jclouds-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds</groupId>
+ <artifactId>jclouds-compute</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-compress</artifactId>
+ <version>1.5</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.jclouds.driver</groupId>
+ <artifactId>jclouds-sshj</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds</groupId>
+ <artifactId>jclouds-core</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds</groupId>
+ <artifactId>jclouds-compute</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds.driver</groupId>
+ <artifactId>jclouds-slf4j</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.squareup.okhttp</groupId>
+ <artifactId>mockwebserver</artifactId>
+ <scope>test</scope>
+ <exclusions>
+ <!-- Already provided by jclouds-sshj -->
+ <exclusion>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>live</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>integration</id>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <systemPropertyVariables>
+ <test.docker.endpoint>${test.docker.endpoint}</test.docker.endpoint>
+ <test.docker.api-version>${test.docker.api-version}</test.docker.api-version>
+ <test.docker.credential>${test.docker.identity}</test.docker.credential>
+ <test.docker.credential>${test.docker.credential}</test.docker.credential>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+</project>
http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9b124ee9/docker/src/main/java/org/jclouds/docker/DockerApi.java
----------------------------------------------------------------------
diff --git a/docker/src/main/java/org/jclouds/docker/DockerApi.java b/docker/src/main/java/org/jclouds/docker/DockerApi.java
new file mode 100644
index 0000000..54bf5c9
--- /dev/null
+++ b/docker/src/main/java/org/jclouds/docker/DockerApi.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.docker;
+
+import org.jclouds.docker.features.RemoteApi;
+import org.jclouds.rest.annotations.Delegate;
+
+import java.io.Closeable;
+
+/**
+ * Provides synchronous access to Docker Remote API.
+ *
+ * @see <a href="https://docs.docker.com/reference/api/docker_remote_api/"></a>
+ */
+public interface DockerApi extends Closeable {
+
+ /**
+ * Provides synchronous access to Docker Remote API features.
+ */
+ @Delegate
+ RemoteApi getRemoteApi();
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9b124ee9/docker/src/main/java/org/jclouds/docker/DockerApiMetadata.java
----------------------------------------------------------------------
diff --git a/docker/src/main/java/org/jclouds/docker/DockerApiMetadata.java b/docker/src/main/java/org/jclouds/docker/DockerApiMetadata.java
new file mode 100644
index 0000000..b281eb7
--- /dev/null
+++ b/docker/src/main/java/org/jclouds/docker/DockerApiMetadata.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.docker;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+import org.jclouds.Constants;
+import org.jclouds.apis.ApiMetadata;
+import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.config.ComputeServiceProperties;
+import org.jclouds.docker.compute.config.DockerComputeServiceContextModule;
+import org.jclouds.docker.config.DockerHttpApiModule;
+import org.jclouds.docker.config.DockerParserModule;
+import org.jclouds.rest.internal.BaseHttpApiMetadata;
+
+import java.net.URI;
+import java.util.Properties;
+
+import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE;
+import static org.jclouds.reflect.Reflection2.typeToken;
+
+/**
+ * Implementation of {@link BaseHttpApiMetadata} for the Docker API
+ */
+public class DockerApiMetadata extends BaseHttpApiMetadata<DockerApi> {
+
+ @Override
+ public Builder toBuilder() {
+ return new Builder().fromApiMetadata(this);
+ }
+
+ public DockerApiMetadata() {
+ this(new Builder());
+ }
+
+ protected DockerApiMetadata(Builder builder) {
+ super(builder);
+ }
+
+ public static Properties defaultProperties() {
+ Properties properties = BaseHttpApiMetadata.defaultProperties();
+ properties.setProperty(Constants.PROPERTY_MAX_RETRIES, "15");
+ properties.setProperty("jclouds.ssh.retry-auth", "true");
+ properties.setProperty(Constants.PROPERTY_CONNECTION_TIMEOUT, "1200000"); // 15 minutes
+ properties.setProperty(ComputeServiceProperties.IMAGE_LOGIN_USER, "root:password");
+ properties.setProperty(TEMPLATE, "osFamily=UBUNTU,os64Bit=true,osVersionMatches=1[012].[01][04]");
+ return properties;
+ }
+
+ public static class Builder extends BaseHttpApiMetadata.Builder<DockerApi, Builder> {
+
+ protected Builder() {
+ super(DockerApi.class);
+ id("docker")
+ .name("Docker API")
+ .identityName("user")
+ .credentialName("password")
+ .documentation(URI.create("https://docs.docker.com/reference/api/docker_remote_api/"))
+ .version("1.12")
+ .defaultEndpoint("http://127.0.0.1:2375")
+ .defaultProperties(DockerApiMetadata.defaultProperties())
+ .view(typeToken(ComputeServiceContext.class))
+ .defaultModules(ImmutableSet.<Class<? extends Module>>of(
+ DockerHttpApiModule.class,
+ DockerParserModule.class,
+ DockerComputeServiceContextModule.class));
+ }
+
+ @Override
+ public DockerApiMetadata build() {
+ return new DockerApiMetadata(this);
+ }
+
+ @Override
+ protected Builder self() {
+ return this;
+ }
+
+ @Override
+ public Builder fromApiMetadata(ApiMetadata in) {
+ return this;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9b124ee9/docker/src/main/java/org/jclouds/docker/binders/BindInputStreamToRequest.java
----------------------------------------------------------------------
diff --git a/docker/src/main/java/org/jclouds/docker/binders/BindInputStreamToRequest.java b/docker/src/main/java/org/jclouds/docker/binders/BindInputStreamToRequest.java
new file mode 100644
index 0000000..855a2e5
--- /dev/null
+++ b/docker/src/main/java/org/jclouds/docker/binders/BindInputStreamToRequest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.docker.binders;
+
+import com.google.common.base.Throwables;
+import com.google.common.io.Files;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.docker.features.internal.Archives;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.io.Payload;
+import org.jclouds.io.Payloads;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.Binder;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+@Singleton
+public class BindInputStreamToRequest implements Binder {
+
+ @Resource
+ @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+ protected Logger logger = Logger.NULL;
+
+ @Override
+ public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+ checkArgument(checkNotNull(input, "input") instanceof File, "this binder is only valid for File!");
+ checkNotNull(request, "request");
+
+ File dockerFile = (File) input;
+ File tmpDir = Files.createTempDir();
+ final File targetFile = new File(tmpDir + File.separator + "Dockerfile");
+ try {
+ Files.copy(dockerFile, targetFile);
+ File archive = Archives.tar(tmpDir, File.createTempFile("archive", ".tar"));
+ FileInputStream data = new FileInputStream(archive);
+ Payload payload = Payloads.newInputStreamPayload(data);
+ payload.getContentMetadata().setContentLength(data.getChannel().size());
+ payload.getContentMetadata().setContentType("application/tar");
+ request.setPayload(payload);
+ } catch (IOException e) {
+ logger.error(e, "Couldn't create a tarball for %s", targetFile);
+ throw Throwables.propagate(e);
+ }
+ return request;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9b124ee9/docker/src/main/java/org/jclouds/docker/compute/config/DockerComputeServiceContextModule.java
----------------------------------------------------------------------
diff --git a/docker/src/main/java/org/jclouds/docker/compute/config/DockerComputeServiceContextModule.java b/docker/src/main/java/org/jclouds/docker/compute/config/DockerComputeServiceContextModule.java
new file mode 100644
index 0000000..b1cfee2
--- /dev/null
+++ b/docker/src/main/java/org/jclouds/docker/compute/config/DockerComputeServiceContextModule.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.docker.compute.config;
+
+import com.google.common.base.Function;
+import com.google.inject.TypeLiteral;
+import org.jclouds.compute.ComputeServiceAdapter;
+import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.docker.compute.functions.ContainerToNodeMetadata;
+import org.jclouds.docker.compute.functions.ImageToImage;
+import org.jclouds.docker.compute.functions.StateToStatus;
+import org.jclouds.docker.compute.options.DockerTemplateOptions;
+import org.jclouds.docker.compute.strategy.DockerComputeServiceAdapter;
+import org.jclouds.docker.domain.Container;
+import org.jclouds.docker.domain.Image;
+import org.jclouds.docker.domain.State;
+import org.jclouds.domain.Location;
+import org.jclouds.functions.IdentityFunction;
+
+public class DockerComputeServiceContextModule extends
+ ComputeServiceAdapterContextModule<Container, Hardware, Image, Location> {
+
+ @Override
+ protected void configure() {
+ super.configure();
+ bind(new TypeLiteral<ComputeServiceAdapter<Container, Hardware, Image, Location>>() {
+ }).to(DockerComputeServiceAdapter.class);
+ bind(new TypeLiteral<Function<Container, NodeMetadata>>() {
+ }).to(ContainerToNodeMetadata.class);
+ bind(new TypeLiteral<Function<Image, org.jclouds.compute.domain.Image>>() {
+ }).to(ImageToImage.class);
+ bind(new TypeLiteral<Function<Hardware, Hardware>>() {
+ }).to(Class.class.cast(IdentityFunction.class));
+ bind(new TypeLiteral<Function<Location, Location>>() {
+ }).to(Class.class.cast(IdentityFunction.class));
+ bind(new TypeLiteral<Function<State, NodeMetadata.Status>>() {
+ }).to(StateToStatus.class);
+ bind(TemplateOptions.class).to(DockerTemplateOptions.class);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9b124ee9/docker/src/main/java/org/jclouds/docker/compute/functions/ContainerToNodeMetadata.java
----------------------------------------------------------------------
diff --git a/docker/src/main/java/org/jclouds/docker/compute/functions/ContainerToNodeMetadata.java b/docker/src/main/java/org/jclouds/docker/compute/functions/ContainerToNodeMetadata.java
new file mode 100644
index 0000000..72c16af
--- /dev/null
+++ b/docker/src/main/java/org/jclouds/docker/compute/functions/ContainerToNodeMetadata.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.docker.compute.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+import org.jclouds.collect.Memoized;
+import org.jclouds.compute.domain.HardwareBuilder;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.NodeMetadataBuilder;
+import org.jclouds.compute.domain.Processor;
+import org.jclouds.compute.functions.GroupNamingConvention;
+import org.jclouds.docker.domain.Container;
+import org.jclouds.docker.domain.Port;
+import org.jclouds.docker.domain.State;
+import org.jclouds.domain.Location;
+import org.jclouds.providers.ProviderMetadata;
+
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.inject.Singleton;
+
+@Singleton
+public class ContainerToNodeMetadata implements Function<Container, NodeMetadata> {
+
+ private final ProviderMetadata providerMetadata;
+ private final Function<State, NodeMetadata.Status> toPortableStatus;
+ private final GroupNamingConvention nodeNamingConvention;
+ private final Supplier<Map<String, ? extends Image>> images;
+ private final Supplier<Set<? extends Location>> locations;
+
+ @Inject
+ public ContainerToNodeMetadata(ProviderMetadata providerMetadata, Function<State,
+ NodeMetadata.Status> toPortableStatus, GroupNamingConvention.Factory namingConvention,
+ Supplier<Map<String, ? extends Image>> images,
+ @Memoized Supplier<Set<? extends Location>> locations) {
+ this.providerMetadata = checkNotNull(providerMetadata, "providerMetadata");
+ this.toPortableStatus = checkNotNull(toPortableStatus, "toPortableStatus cannot be null");
+ this.nodeNamingConvention = checkNotNull(namingConvention, "namingConvention").createWithoutPrefix();
+ this.images = checkNotNull(images, "images cannot be null");
+ this.locations = checkNotNull(locations, "locations");
+ }
+
+ @Override
+ public NodeMetadata apply(Container container) {
+ String name = cleanUpName(container.getName());
+ String group = nodeNamingConvention.extractGroup(name);
+ NodeMetadataBuilder builder = new NodeMetadataBuilder();
+ builder.ids(container.getId())
+ .name(name)
+ .group(group)
+ .hostname(container.getContainerConfig().getHostname())
+ // TODO Set up hardware
+ .hardware(new HardwareBuilder()
+ .id("")
+ .ram(container.getContainerConfig().getMemory())
+ .processor(new Processor(container.getContainerConfig().getCpuShares(), container.getContainerConfig().getCpuShares()))
+ .build());
+ builder.status(toPortableStatus.apply(container.getState()));
+ builder.imageId(container.getImage());
+ builder.loginPort(getLoginPort(container));
+ builder.publicAddresses(getPublicIpAddresses());
+ builder.privateAddresses(getPrivateIpAddresses(container));
+ builder.location(Iterables.getOnlyElement(locations.get()));
+ Image image = images.get().get(container.getImage());
+ builder.imageId(image.getId());
+ builder.operatingSystem(image.getOperatingSystem());
+
+ return builder.build();
+ }
+
+ private String cleanUpName(String name) {
+ return name.startsWith("/") ? name.substring(1) : name;
+ }
+
+ private Iterable<String> getPrivateIpAddresses(Container container) {
+ if (container.getNetworkSettings() == null) return ImmutableList.of();
+ return ImmutableList.of(container.getNetworkSettings().getIpAddress());
+ }
+
+ private List<String> getPublicIpAddresses() {
+ String dockerIpAddress = URI.create(providerMetadata.getEndpoint()).getHost();
+ return ImmutableList.of(dockerIpAddress);
+ }
+
+ protected static int getLoginPort(Container container) {
+ if (container.getNetworkSettings() != null) {
+ Map<String, List<Map<String, String>>> ports = container.getNetworkSettings().getPorts();
+ if (ports != null) {
+ return Integer.parseInt(getOnlyElement(ports.get("22/tcp")).get("HostPort"));
+ }
+ // this is needed in case the container list is coming from listContainers
+ } else if (container.getPorts() != null) {
+ for (Port port : container.getPorts()) {
+ if (port.getPrivatePort() == 22) {
+ return port.getPublicPort();
+ }
+ }
+ }
+ throw new IllegalStateException("Cannot determine the login port for " + container.getId());
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9b124ee9/docker/src/main/java/org/jclouds/docker/compute/functions/ImageToImage.java
----------------------------------------------------------------------
diff --git a/docker/src/main/java/org/jclouds/docker/compute/functions/ImageToImage.java b/docker/src/main/java/org/jclouds/docker/compute/functions/ImageToImage.java
new file mode 100644
index 0000000..4e3358d
--- /dev/null
+++ b/docker/src/main/java/org/jclouds/docker/compute/functions/ImageToImage.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.docker.compute.functions;
+
+import com.google.common.base.Function;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Iterables;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.ImageBuilder;
+import org.jclouds.compute.domain.OperatingSystem;
+import org.jclouds.compute.domain.OsFamily;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.logging.Logger;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.get;
+
+public class ImageToImage implements Function<org.jclouds.docker.domain.Image, org.jclouds.compute.domain.Image> {
+
+ private static final String CENTOS = "centos";
+ private static final String UBUNTU = "ubuntu";
+
+ @Resource
+ @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+ protected Logger logger = Logger.NULL;
+
+ @Override
+ public Image apply(org.jclouds.docker.domain.Image from) {
+ checkNotNull(from, "image");
+ String description = checkNotNull(Iterables.getFirst(from.getRepoTags(), "image must have at least one repo tag"));
+
+ OsFamily osFamily = osFamily().apply(description);
+ String osVersion = parseVersion(description);
+
+ OperatingSystem os = OperatingSystem.builder()
+ .description(description)
+ .family(osFamily)
+ .version(osVersion)
+ .is64Bit(is64bit(from))
+ .build();
+
+ return new ImageBuilder()
+ .ids(from.getId())
+ .name(get(Splitter.on(":").split(description), 0))
+ .description(description)
+ .operatingSystem(os)
+ .status(Image.Status.AVAILABLE)
+ .build();
+ }
+
+ private boolean is64bit(org.jclouds.docker.domain.Image inspectedImage) {
+ if (inspectedImage.getArchitecture() == null) return true;
+ return inspectedImage.getArchitecture().matches("x86_64|amd64");
+ }
+
+ /**
+ * Parses the item description to determine the OSFamily
+ *
+ * @return the @see OsFamily or OsFamily.UNRECOGNIZED
+ */
+ private Function<String, OsFamily> osFamily() {
+ return new Function<String, OsFamily>() {
+
+ @Override
+ public OsFamily apply(final String description) {
+ if (description != null) {
+ if (description.contains(CENTOS)) return OsFamily.CENTOS;
+ else if (description.contains(UBUNTU)) return OsFamily.UBUNTU;
+ }
+ return OsFamily.UNRECOGNIZED;
+ }
+ };
+ }
+
+ private String parseVersion(String description) {
+ String version = get(Splitter.on(":").split(description), 1);
+ logger.debug("os version for item: %s is %s", description, version);
+ return version;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9b124ee9/docker/src/main/java/org/jclouds/docker/compute/functions/StateToStatus.java
----------------------------------------------------------------------
diff --git a/docker/src/main/java/org/jclouds/docker/compute/functions/StateToStatus.java b/docker/src/main/java/org/jclouds/docker/compute/functions/StateToStatus.java
new file mode 100644
index 0000000..2d87384
--- /dev/null
+++ b/docker/src/main/java/org/jclouds/docker/compute/functions/StateToStatus.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.docker.compute.functions;
+
+import javax.inject.Singleton;
+
+import org.jclouds.compute.domain.NodeMetadata.Status;
+import org.jclouds.docker.domain.State;
+
+import com.google.common.base.Function;
+
+/**
+ * Transforms an {@link org.jclouds.docker.domain.Container} to the jclouds portable model.
+ */
+@Singleton
+public class StateToStatus implements Function<State, Status> {
+
+ @Override
+ public Status apply(final State state) {
+ if (state == null) return Status.UNRECOGNIZED;
+ return state.isRunning() ? Status.RUNNING : Status.TERMINATED;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9b124ee9/docker/src/main/java/org/jclouds/docker/compute/options/DockerTemplateOptions.java
----------------------------------------------------------------------
diff --git a/docker/src/main/java/org/jclouds/docker/compute/options/DockerTemplateOptions.java b/docker/src/main/java/org/jclouds/docker/compute/options/DockerTemplateOptions.java
new file mode 100644
index 0000000..5e4669b
--- /dev/null
+++ b/docker/src/main/java/org/jclouds/docker/compute/options/DockerTemplateOptions.java
@@ -0,0 +1,485 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.docker.compute.options;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.scriptbuilder.domain.Statement;
+
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Contains options supported in the {@code ComputeService#runNode} operation on the
+ * "docker" provider. <h2>Usage</h2> The recommended way to instantiate a
+ * DockerTemplateOptions object is to statically import DockerTemplateOptions.* and invoke a static
+ * creation method followed by an instance mutator (if needed):
+ * <p/>
+ * <code>
+ * import static org.jclouds.docker.compute.options.DockerTemplateOptions.Builder.*;
+ * <p/>
+ * ComputeService api = // get connection
+ * templateBuilder.options(inboundPorts(22, 80, 8080, 443));
+ * Set<? extends NodeMetadata> set = api.createNodesInGroup(tag, 2, templateBuilder.build());
+ * <code>
+ */
+public class DockerTemplateOptions extends TemplateOptions implements Cloneable {
+
+ protected Optional<String> dns = Optional.absent();
+ protected Optional<String> hostname = Optional.absent();
+ protected Optional<Integer> memory = Optional.absent();
+ protected Optional<Integer> cpuShares = Optional.absent();
+ protected Optional<List<String>> commands = Optional.absent();
+ protected Optional<Map<String, String>> volumes = Optional.absent();
+
+ @Override
+ public DockerTemplateOptions clone() {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ copyTo(options);
+ return options;
+ }
+
+ @Override
+ public void copyTo(TemplateOptions to) {
+ super.copyTo(to);
+ if (to instanceof DockerTemplateOptions) {
+ DockerTemplateOptions eTo = DockerTemplateOptions.class.cast(to);
+ if (volumes.isPresent()) {
+ eTo.volumes(getVolumes().get());
+ }
+ if (hostname.isPresent()) {
+ eTo.hostname(hostname.get());
+ }
+ if (dns.isPresent()) {
+ eTo.dns(dns.get());
+ }
+ if (memory.isPresent()) {
+ eTo.memory(memory.get());
+ }
+ if (commands.isPresent()) {
+ eTo.commands(commands.get());
+ }
+ if (cpuShares.isPresent()) {
+ eTo.cpuShares(cpuShares.get());
+ }
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+ DockerTemplateOptions that = DockerTemplateOptions.class.cast(o);
+ return super.equals(that) && equal(this.volumes, that.volumes) &&
+ equal(this.hostname, that.hostname) &&
+ equal(this.dns, that.dns) &&
+ equal(this.memory, that.memory) &&
+ equal(this.commands, that.commands) &&
+ equal(this.cpuShares, that.cpuShares);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(super.hashCode(), volumes, hostname, dns, memory, commands, cpuShares);
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this)
+ .add("dns", dns)
+ .add("hostname", hostname)
+ .add("memory", memory)
+ .add("cpuShares", cpuShares)
+ .add("commands", commands)
+ .add("volumes", volumes)
+ .toString();
+ }
+
+ public static final DockerTemplateOptions NONE = new DockerTemplateOptions();
+
+ public DockerTemplateOptions volumes(Map<String, String> volumes) {
+ this.volumes = Optional.<Map<String, String>> of(ImmutableMap.copyOf(volumes));
+ return this;
+ }
+
+ public TemplateOptions dns(@Nullable String dns) {
+ this.dns = Optional.fromNullable(dns);
+ return this;
+ }
+
+ public TemplateOptions hostname(@Nullable String hostname) {
+ this.hostname = Optional.fromNullable(hostname);
+ return this;
+ }
+
+ public TemplateOptions memory(@Nullable Integer memory) {
+ this.memory = Optional.fromNullable(memory);
+ return this;
+ }
+
+ public TemplateOptions commands(Iterable<String> commands) {
+ for (String command : checkNotNull(commands, "commands"))
+ checkNotNull(command, "all commands must be non-empty");
+ this.commands = Optional.<List<String>> of(ImmutableList.copyOf(commands));
+ return this;
+ }
+
+ public TemplateOptions commands(String... commands) {
+ return commands(ImmutableList.copyOf(checkNotNull(commands, "commands")));
+ }
+
+ public TemplateOptions cpuShares(@Nullable Integer cpuShares) {
+ this.cpuShares = Optional.fromNullable(cpuShares);
+ return this;
+ }
+
+ public Optional<Map<String, String>> getVolumes() {
+ return volumes;
+ }
+
+ public Optional<String> getDns() { return dns; }
+
+ public Optional<String> getHostname() { return hostname; }
+
+ public Optional<Integer> getMemory() { return memory; }
+
+ public Optional<List<String>> getCommands() {
+ return commands;
+ }
+
+ public Optional<Integer> getCpuShares() { return cpuShares; }
+
+ public static class Builder {
+
+ /**
+ * @see DockerTemplateOptions#volumes(java.util.Map)
+ */
+ public static DockerTemplateOptions volumes(Map<String, String> volumes) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return DockerTemplateOptions.class.cast(options.volumes(volumes));
+ }
+
+ /**
+ * @see DockerTemplateOptions#dns(String)
+ */
+ public static DockerTemplateOptions dns(String dns) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return DockerTemplateOptions.class.cast(options.dns(dns));
+ }
+
+ /**
+ * @see DockerTemplateOptions#hostname(String)
+ */
+ public static DockerTemplateOptions hostname(String hostname) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return DockerTemplateOptions.class.cast(options.hostname(hostname));
+ }
+
+ /**
+ * @see DockerTemplateOptions#memory(int)
+ */
+ public static DockerTemplateOptions memory(int memory) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return DockerTemplateOptions.class.cast(options.memory(memory));
+ }
+
+ /**
+ * @see DockerTemplateOptions#commands(Iterable)
+ */
+ public static DockerTemplateOptions commands(String... commands) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return DockerTemplateOptions.class.cast(options.commands(commands));
+ }
+
+ public static DockerTemplateOptions commands(Iterable<String> commands) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return DockerTemplateOptions.class.cast(options.commands(commands));
+ }
+
+ /**
+ * @see DockerTemplateOptions#cpuShares(int)
+ */
+ public static DockerTemplateOptions cpuShares(int cpuShares) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return DockerTemplateOptions.class.cast(options.cpuShares(cpuShares));
+ }
+
+ // methods that only facilitate returning the correct object type
+
+ /**
+ * @see TemplateOptions#inboundPorts
+ */
+ public static DockerTemplateOptions inboundPorts(int... ports) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return DockerTemplateOptions.class.cast(options.inboundPorts(ports));
+ }
+
+ /**
+ * @see TemplateOptions#port
+ */
+ public static DockerTemplateOptions blockOnPort(int port, int seconds) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return DockerTemplateOptions.class.cast(options.blockOnPort(port, seconds));
+ }
+
+ /**
+ * @see TemplateOptions#installPrivateKey
+ */
+ public static DockerTemplateOptions installPrivateKey(String rsaKey) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return DockerTemplateOptions.class.cast(options.installPrivateKey(rsaKey));
+ }
+
+ /**
+ * @see TemplateOptions#authorizePublicKey
+ */
+ public static DockerTemplateOptions authorizePublicKey(String rsaKey) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return DockerTemplateOptions.class.cast(options.authorizePublicKey(rsaKey));
+ }
+
+ /**
+ * @see TemplateOptions#userMetadata
+ */
+ public static DockerTemplateOptions userMetadata(Map<String, String> userMetadata) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return DockerTemplateOptions.class.cast(options.userMetadata(userMetadata));
+ }
+
+ /**
+ * @see TemplateOptions#nodeNames(Iterable)
+ */
+ public static DockerTemplateOptions nodeNames(Iterable<String> nodeNames) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return DockerTemplateOptions.class.cast(options.nodeNames(nodeNames));
+ }
+
+ /**
+ * @see TemplateOptions#networks(Iterable)
+ */
+ public static DockerTemplateOptions networks(Iterable<String> networks) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return DockerTemplateOptions.class.cast(options.networks(networks));
+ }
+
+ /**
+ * @see TemplateOptions#overrideLoginUser
+ */
+ public static DockerTemplateOptions overrideLoginUser(String user) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return options.overrideLoginUser(user);
+ }
+
+ /**
+ * @see TemplateOptions#overrideLoginPassword
+ */
+ public static DockerTemplateOptions overrideLoginPassword(String password) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return options.overrideLoginPassword(password);
+ }
+
+ /**
+ * @see TemplateOptions#overrideLoginPrivateKey
+ */
+ public static DockerTemplateOptions overrideLoginPrivateKey(String privateKey) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return options.overrideLoginPrivateKey(privateKey);
+ }
+
+ /**
+ * @see TemplateOptions#overrideAuthenticateSudo
+ */
+ public static DockerTemplateOptions overrideAuthenticateSudo(boolean authenticateSudo) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return options.overrideAuthenticateSudo(authenticateSudo);
+ }
+
+ /**
+ * @see TemplateOptions#overrideLoginCredentials
+ */
+ public static DockerTemplateOptions overrideLoginCredentials(LoginCredentials credentials) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return options.overrideLoginCredentials(credentials);
+ }
+
+ /**
+ * @see TemplateOptions#blockUntilRunning
+ */
+ public static DockerTemplateOptions blockUntilRunning(boolean blockUntilRunning) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return options.blockUntilRunning(blockUntilRunning);
+ }
+
+ }
+
+ // methods that only facilitate returning the correct object type
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions blockOnPort(int port, int seconds) {
+ return DockerTemplateOptions.class.cast(super.blockOnPort(port, seconds));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions inboundPorts(int... ports) {
+ return DockerTemplateOptions.class.cast(super.inboundPorts(ports));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions authorizePublicKey(String publicKey) {
+ return DockerTemplateOptions.class.cast(super.authorizePublicKey(publicKey));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions installPrivateKey(String privateKey) {
+ return DockerTemplateOptions.class.cast(super.installPrivateKey(privateKey));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions blockUntilRunning(boolean blockUntilRunning) {
+ return DockerTemplateOptions.class.cast(super.blockUntilRunning(blockUntilRunning));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions dontAuthorizePublicKey() {
+ return DockerTemplateOptions.class.cast(super.dontAuthorizePublicKey());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions nameTask(String name) {
+ return DockerTemplateOptions.class.cast(super.nameTask(name));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions runAsRoot(boolean runAsRoot) {
+ return DockerTemplateOptions.class.cast(super.runAsRoot(runAsRoot));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions runScript(Statement script) {
+ return DockerTemplateOptions.class.cast(super.runScript(script));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions overrideLoginCredentials(LoginCredentials overridingCredentials) {
+ return DockerTemplateOptions.class.cast(super.overrideLoginCredentials(overridingCredentials));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions overrideLoginPassword(String password) {
+ return DockerTemplateOptions.class.cast(super.overrideLoginPassword(password));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions overrideLoginPrivateKey(String privateKey) {
+ return DockerTemplateOptions.class.cast(super.overrideLoginPrivateKey(privateKey));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions overrideLoginUser(String loginUser) {
+ return DockerTemplateOptions.class.cast(super.overrideLoginUser(loginUser));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions overrideAuthenticateSudo(boolean authenticateSudo) {
+ return DockerTemplateOptions.class.cast(super.overrideAuthenticateSudo(authenticateSudo));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions userMetadata(Map<String, String> userMetadata) {
+ return DockerTemplateOptions.class.cast(super.userMetadata(userMetadata));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions userMetadata(String key, String value) {
+ return DockerTemplateOptions.class.cast(super.userMetadata(key, value));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions nodeNames(Iterable<String> nodeNames) {
+ return DockerTemplateOptions.class.cast(super.nodeNames(nodeNames));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DockerTemplateOptions networks(Iterable<String> networks) {
+ return DockerTemplateOptions.class.cast(super.networks(networks));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9b124ee9/docker/src/main/java/org/jclouds/docker/compute/strategy/DockerComputeServiceAdapter.java
----------------------------------------------------------------------
diff --git a/docker/src/main/java/org/jclouds/docker/compute/strategy/DockerComputeServiceAdapter.java b/docker/src/main/java/org/jclouds/docker/compute/strategy/DockerComputeServiceAdapter.java
new file mode 100644
index 0000000..7bbead3
--- /dev/null
+++ b/docker/src/main/java/org/jclouds/docker/compute/strategy/DockerComputeServiceAdapter.java
@@ -0,0 +1,232 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.docker.compute.strategy;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.find;
+
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.compute.ComputeServiceAdapter;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.HardwareBuilder;
+import org.jclouds.compute.domain.Processor;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.docker.DockerApi;
+import org.jclouds.docker.compute.options.DockerTemplateOptions;
+import org.jclouds.docker.domain.Config;
+import org.jclouds.docker.domain.Container;
+import org.jclouds.docker.domain.HostConfig;
+import org.jclouds.docker.domain.Image;
+import org.jclouds.docker.options.ListContainerOptions;
+import org.jclouds.docker.options.RemoveContainerOptions;
+import org.jclouds.domain.Location;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.logging.Logger;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+/**
+ * defines the connection between the {@link org.jclouds.docker.DockerApi} implementation and
+ * the jclouds {@link org.jclouds.compute.ComputeService}
+ */
+@Singleton
+public class DockerComputeServiceAdapter implements
+ ComputeServiceAdapter<Container, Hardware, Image, Location> {
+
+ @Resource
+ @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+ protected Logger logger = Logger.NULL;
+
+ private final DockerApi api;
+
+ @Inject
+ public DockerComputeServiceAdapter(DockerApi api) {
+ this.api = checkNotNull(api, "api");
+ }
+
+ @Override
+ public NodeAndInitialCredentials<Container> createNodeWithGroupEncodedIntoName(String group, String name,
+ Template template) {
+ checkNotNull(template, "template was null");
+ checkNotNull(template.getOptions(), "template options was null");
+
+ String imageId = checkNotNull(template.getImage().getId(), "template image id must not be null");
+ String loginUser = template.getImage().getDefaultCredentials().getUser();
+ String loginUserPassword = template.getImage().getDefaultCredentials().getPassword();
+
+ DockerTemplateOptions templateOptions = DockerTemplateOptions.class.cast(template.getOptions());
+ int[] inboundPorts = templateOptions.getInboundPorts();
+
+ Map<String, Object> exposedPorts = Maps.newHashMap();
+ for (int inboundPort : inboundPorts) {
+ exposedPorts.put(inboundPort + "/tcp", Maps.newHashMap());
+ }
+
+ Config.Builder containerConfigBuilder = Config.builder()
+ .imageId(imageId)
+ .exposedPorts(exposedPorts);
+
+ if (templateOptions.getCommands().isPresent()) {
+ containerConfigBuilder.cmd(templateOptions.getCommands().get());
+ }
+
+ if (templateOptions.getMemory().isPresent()) {
+ containerConfigBuilder.memory(templateOptions.getMemory().get());
+ }
+
+ if (templateOptions.getCpuShares().isPresent()) {
+ containerConfigBuilder.cpuShares(templateOptions.getCpuShares().get());
+ }
+
+ if (templateOptions.getVolumes().isPresent()) {
+ Map<String, Object> volumes = Maps.newLinkedHashMap();
+ for (String containerDir : templateOptions.getVolumes().get().values()) {
+ volumes.put(containerDir, Maps.newHashMap());
+ }
+ containerConfigBuilder.volumes(volumes);
+ }
+ Config containerConfig = containerConfigBuilder.build();
+
+ logger.debug(">> creating new container with containerConfig(%s)", containerConfig);
+ Container container = api.getRemoteApi().createContainer(name, containerConfig);
+ logger.trace("<< container(%s)", container.getId());
+
+ HostConfig.Builder hostConfigBuilder = HostConfig.builder()
+ .publishAllPorts(true)
+ .privileged(true);
+
+ if (templateOptions.getDns().isPresent()) {
+ hostConfigBuilder.dns(templateOptions.getDns().get());
+ }
+ // set up for volume bindings
+ if (templateOptions.getVolumes().isPresent()) {
+ for (Map.Entry<String, String> entry : templateOptions.getVolumes().get().entrySet()) {
+ hostConfigBuilder.binds(ImmutableList.of(entry.getKey() + ":" + entry.getValue()));
+ }
+ }
+ HostConfig hostConfig = hostConfigBuilder.build();
+
+ api.getRemoteApi().startContainer(container.getId(), hostConfig);
+ container = api.getRemoteApi().inspectContainer(container.getId());
+ if (container.getState().getExitCode() != 0) {
+ destroyNode(container.getId());
+ throw new IllegalStateException(String.format("Container %s has not started correctly", container.getId()));
+ }
+ return new NodeAndInitialCredentials<Container>(container, container.getId(),
+ LoginCredentials.builder().user(loginUser).password(loginUserPassword).build());
+ }
+
+ @Override
+ public Iterable<Hardware> listHardwareProfiles() {
+ Set<Hardware> hardware = Sets.newLinkedHashSet();
+ // todo they are only placeholders at the moment
+ hardware.add(new HardwareBuilder().ids("micro").hypervisor("lxc").name("micro").processor(new Processor(1, 1)).ram(512).build());
+ hardware.add(new HardwareBuilder().ids("small").hypervisor("lxc").name("small").processor(new Processor(1, 1)).ram(1024).build());
+ hardware.add(new HardwareBuilder().ids("medium").hypervisor("lxc").name("medium").processor(new Processor(1, 1)).ram(2048).build());
+ hardware.add(new HardwareBuilder().ids("large").hypervisor("lxc").name("large").processor(new Processor(1, 1)).ram(3072).build());
+ return hardware;
+ }
+
+ @Override
+ public Set<Image> listImages() {
+ Set<Image> images = Sets.newHashSet();
+ for (Image image : api.getRemoteApi().listImages()) {
+ // less efficient than just listImages but returns richer json that needs repoTags coming from listImages
+ Image inspected = api.getRemoteApi().inspectImage(image.getId());
+ if (inspected.getRepoTags().isEmpty()) {
+ inspected = Image.builder().fromImage(inspected).repoTags(image.getRepoTags()).build();
+ }
+ images.add(inspected);
+ }
+ return images;
+ }
+
+ @Override
+ public Image getImage(final String imageId) {
+ // less efficient than just inspectImage but listImages return repoTags
+ return find(listImages(), new Predicate<Image>() {
+
+ @Override
+ public boolean apply(Image input) {
+ return input.getId().equals(imageId);
+ }
+ }, null);
+ }
+
+ @Override
+ public Iterable<Container> listNodes() {
+ Set<Container> containers = Sets.newHashSet();
+ for (Container container : api.getRemoteApi().listContainers(ListContainerOptions.Builder.all(true))) {
+ // less efficient than just listNodes but returns richer json
+ containers.add(api.getRemoteApi().inspectContainer(container.getId()));
+ }
+ return containers;
+ }
+
+ @Override
+ public Iterable<Container> listNodesByIds(final Iterable<String> ids) {
+ Set<Container> containers = Sets.newHashSet();
+ for (String id : ids) {
+ containers.add(api.getRemoteApi().inspectContainer(id));
+ }
+ return containers;
+ }
+
+ @Override
+ public Iterable<Location> listLocations() {
+ return ImmutableSet.of();
+ }
+
+ @Override
+ public Container getNode(String id) {
+ return api.getRemoteApi().inspectContainer(id);
+ }
+
+ @Override
+ public void destroyNode(String id) {
+ api.getRemoteApi().removeContainer(id, RemoveContainerOptions.Builder.force(true));
+ }
+
+ @Override
+ public void rebootNode(String id) {
+ api.getRemoteApi().stopContainer(id);
+ api.getRemoteApi().startContainer(id);
+ }
+
+ @Override
+ public void resumeNode(String id) {
+ throw new UnsupportedOperationException("resume not supported");
+ }
+
+ @Override
+ public void suspendNode(String id) {
+ throw new UnsupportedOperationException("suspend not supported");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9b124ee9/docker/src/main/java/org/jclouds/docker/config/DockerHttpApiModule.java
----------------------------------------------------------------------
diff --git a/docker/src/main/java/org/jclouds/docker/config/DockerHttpApiModule.java b/docker/src/main/java/org/jclouds/docker/config/DockerHttpApiModule.java
new file mode 100644
index 0000000..e6da554
--- /dev/null
+++ b/docker/src/main/java/org/jclouds/docker/config/DockerHttpApiModule.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.docker.config;
+
+import org.jclouds.docker.DockerApi;
+import org.jclouds.docker.handlers.DockerErrorHandler;
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.annotation.ClientError;
+import org.jclouds.http.annotation.Redirection;
+import org.jclouds.http.annotation.ServerError;
+import org.jclouds.rest.ConfiguresHttpApi;
+import org.jclouds.rest.config.HttpApiModule;
+
+/**
+ * Configures the Docker connection.
+ */
+@ConfiguresHttpApi
+public class DockerHttpApiModule extends HttpApiModule<DockerApi> {
+
+ @Override
+ protected void bindErrorHandlers() {
+ bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(DockerErrorHandler.class);
+ bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(DockerErrorHandler.class);
+ bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(DockerErrorHandler.class);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9b124ee9/docker/src/main/java/org/jclouds/docker/config/DockerParserModule.java
----------------------------------------------------------------------
diff --git a/docker/src/main/java/org/jclouds/docker/config/DockerParserModule.java b/docker/src/main/java/org/jclouds/docker/config/DockerParserModule.java
new file mode 100644
index 0000000..533184f
--- /dev/null
+++ b/docker/src/main/java/org/jclouds/docker/config/DockerParserModule.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.docker.config;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
+import org.jclouds.docker.domain.Container;
+import org.jclouds.json.config.GsonModule;
+
+import javax.inject.Singleton;
+import java.lang.reflect.Type;
+import java.util.Map;
+
+public class DockerParserModule extends AbstractModule {
+
+ @Override
+ protected void configure() {
+ bind(GsonModule.DateAdapter.class).to(GsonModule.Iso8601DateAdapter.class);
+ }
+
+ @Provides
+ @Singleton
+ public Map<Type, Object> provideCustomAdapterBindings() {
+ return new ImmutableMap.Builder<Type, Object>()
+ .put(Container.class, new ContainerTypeAdapter())
+ .build();
+ }
+
+ protected static class ContainerTypeAdapter implements JsonDeserializer<Container> {
+
+ @Override
+ public Container deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws
+ JsonParseException {
+ Gson gson = new GsonBuilder().serializeNulls().create();
+ final JsonObject jsonObject = json.getAsJsonObject();
+ return gson.fromJson(jsonObject, Container.class);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9b124ee9/docker/src/main/java/org/jclouds/docker/config/DockerProperties.java
----------------------------------------------------------------------
diff --git a/docker/src/main/java/org/jclouds/docker/config/DockerProperties.java b/docker/src/main/java/org/jclouds/docker/config/DockerProperties.java
new file mode 100644
index 0000000..b870fea
--- /dev/null
+++ b/docker/src/main/java/org/jclouds/docker/config/DockerProperties.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.docker.config;
+
+public class DockerProperties {
+
+ /**
+ * default Docker host password
+ */
+ public static final String HOST_PASSWORD = "jclouds.docker.host.password";
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/9b124ee9/docker/src/main/java/org/jclouds/docker/domain/Config.java
----------------------------------------------------------------------
diff --git a/docker/src/main/java/org/jclouds/docker/domain/Config.java b/docker/src/main/java/org/jclouds/docker/domain/Config.java
new file mode 100644
index 0000000..9c80472
--- /dev/null
+++ b/docker/src/main/java/org/jclouds/docker/domain/Config.java
@@ -0,0 +1,457 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.docker.domain;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.gson.annotations.SerializedName;
+import org.jclouds.javax.annotation.Nullable;
+
+import java.beans.ConstructorProperties;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class Config {
+
+ @SerializedName("Hostname")
+ private final String hostname;
+ @SerializedName("Domainname")
+ private final String domainName;
+ @SerializedName("User")
+ private final String user;
+ @SerializedName("Memory")
+ private final int memory;
+ @SerializedName("MemorySwap")
+ private final int memorySwap;
+ @SerializedName("CpuShares")
+ private final int cpuShares;
+ @SerializedName("AttachStdin")
+ private final boolean attachStdin;
+ @SerializedName("AttachStdout")
+ private final boolean attachStdout;
+ @SerializedName("AttachStderr")
+ private final boolean attachStderr;
+ @SerializedName("ExposedPorts")
+ private final Map<String, ?> exposedPorts;
+ @SerializedName("Tty")
+ private final boolean tty;
+ @SerializedName("OpenStdin")
+ private final boolean openStdin;
+ @SerializedName("StdinOnce")
+ private final boolean stdinOnce;
+ @SerializedName("Env")
+ private final List<String> env;
+ @SerializedName("Cmd")
+ private final List<String> cmd;
+ @SerializedName("Dns")
+ private final List<String> dns;
+ @SerializedName("Image")
+ private final String imageId;
+ @SerializedName("Volumes")
+ private final Map<String, ?> volumes;
+ @SerializedName("VolumesFrom")
+ private final String volumesFrom;
+ @SerializedName("WorkingDir")
+ private final String workingDir;
+ @SerializedName("Entrypoint")
+ private final String entrypoint;
+ @SerializedName("NetworkDisabled")
+ private final boolean networkDisabled;
+ @SerializedName("OnBuild")
+ private final List<String> onBuild;
+
+
+ @ConstructorProperties({ "Hostname", "Domainname", "User", "Memory", "MemorySwap", "CpuShares", "AttachStdin",
+ "AttachStdout", "AttachStderr", "ExposedPorts", "Tty", "OpenStdin", "StdinOnce", "Env", "Cmd",
+ "Dns", "Image", "Volumes", "VolumesFrom", "WorkingDir", "Entrypoint", "NetworkDisabled", "OnBuild" })
+ protected Config(@Nullable String hostname, @Nullable String domainName, @Nullable String user,
+ int memory, int memorySwap, int cpuShares, boolean attachStdin, boolean attachStdout,
+ boolean attachStderr, Map<String, ?> exposedPorts, boolean tty, boolean openStdin,
+ boolean stdinOnce, @Nullable List<String> env, @Nullable List<String> cmd,
+ @Nullable List<String> dns, String imageId, @Nullable Map<String, ?> volumes,
+ @Nullable String volumesFrom, @Nullable String workingDir, @Nullable String entrypoint,
+ @Nullable boolean networkDisabled, @Nullable List<String> onBuild) {
+ this.hostname = hostname;
+ this.domainName = domainName;
+ this.user = user;
+ this.memory = checkNotNull(memory, "memory");
+ this.memorySwap = checkNotNull(memorySwap, "memorySwap");
+ this.cpuShares = checkNotNull(cpuShares, "cpuShares");
+ this.attachStdin = checkNotNull(attachStdin, "attachStdin");
+ this.attachStdout = checkNotNull(attachStdout, "attachStdout");
+ this.attachStderr = checkNotNull(attachStderr, "attachStderr");
+ this.exposedPorts = exposedPorts != null ? ImmutableMap.copyOf(exposedPorts) : ImmutableMap.<String, Object> of();
+ this.tty = checkNotNull(tty, "tty");
+ this.openStdin = checkNotNull(openStdin, "openStdin");
+ this.stdinOnce = checkNotNull(stdinOnce, "stdinOnce");
+ this.env = env != null ? ImmutableList.copyOf(env) : ImmutableList.<String> of();
+ this.cmd = cmd != null ? ImmutableList.copyOf(cmd) : ImmutableList.<String> of();
+ this.dns = dns != null ? ImmutableList.copyOf(dns) : ImmutableList.<String> of();
+ this.imageId = checkNotNull(imageId, "imageId");
+ this.volumes = volumes != null ? ImmutableMap.copyOf(volumes) : ImmutableMap.<String, Object> of();
+ this.volumesFrom = volumesFrom;
+ this.workingDir = workingDir;
+ this.entrypoint = entrypoint;
+ this.networkDisabled = networkDisabled;
+ this.onBuild = onBuild != null ? ImmutableList.copyOf(onBuild) : ImmutableList.<String> of();
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public String getDomainName() {
+ return domainName;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public int getMemory() {
+ return memory;
+ }
+
+ public int getMemorySwap() {
+ return memorySwap;
+ }
+
+ public int getCpuShares() {
+ return cpuShares;
+ }
+
+ public boolean isAttachStdin() {
+ return attachStdin;
+ }
+
+ public boolean isAttachStdout() {
+ return attachStdout;
+ }
+
+ public boolean isAttachStderr() {
+ return attachStderr;
+ }
+
+ public Map<String, ?> getExposedPorts() {
+ return exposedPorts;
+ }
+
+ public boolean isTty() {
+ return tty;
+ }
+
+ public boolean isOpenStdin() {
+ return openStdin;
+ }
+
+ public boolean isStdinOnce() {
+ return stdinOnce;
+ }
+
+ public List<String> getEnv() {
+ return env;
+ }
+
+ public List<String> getCmd() {
+ return cmd;
+ }
+
+ public List<String> getDns() {
+ return dns;
+ }
+
+ public String getImageId() {
+ return imageId;
+ }
+
+ public Map<String, ?> getVolumes() {
+ return volumes;
+ }
+
+ public String getVolumesFrom() {
+ return volumesFrom;
+ }
+
+ public String getWorkingDir() {
+ return workingDir;
+ }
+
+ public String getEntrypoint() {
+ return entrypoint;
+ }
+
+ public boolean isNetworkDisabled() {
+ return networkDisabled;
+ }
+
+ public List<String> getOnBuild() {
+ return onBuild;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Config that = (Config) o;
+
+ return Objects.equal(this.hostname, that.hostname) &&
+ Objects.equal(this.domainName, that.domainName) &&
+ Objects.equal(this.user, that.user) &&
+ Objects.equal(this.memory, that.memory) &&
+ Objects.equal(this.memorySwap, that.memorySwap) &&
+ Objects.equal(this.cpuShares, that.cpuShares) &&
+ Objects.equal(this.attachStdin, that.attachStdin) &&
+ Objects.equal(this.attachStdout, that.attachStdout) &&
+ Objects.equal(this.attachStderr, that.attachStderr) &&
+ Objects.equal(this.exposedPorts, that.exposedPorts) &&
+ Objects.equal(this.tty, that.tty) &&
+ Objects.equal(this.openStdin, that.openStdin) &&
+ Objects.equal(this.stdinOnce, that.stdinOnce) &&
+ Objects.equal(this.env, that.env) &&
+ Objects.equal(this.cmd, that.cmd) &&
+ Objects.equal(this.dns, that.dns) &&
+ Objects.equal(this.imageId, that.imageId) &&
+ Objects.equal(this.volumes, that.volumes) &&
+ Objects.equal(this.volumesFrom, that.volumesFrom) &&
+ Objects.equal(this.workingDir, that.workingDir) &&
+ Objects.equal(this.entrypoint, that.entrypoint) &&
+ Objects.equal(this.onBuild, that.onBuild);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(hostname, domainName, user, memory, memorySwap, cpuShares, attachStdin, attachStdout,
+ attachStderr, exposedPorts, tty, openStdin, stdinOnce, env, cmd, dns, imageId, volumes,
+ volumesFrom, workingDir, entrypoint, networkDisabled, onBuild);
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this)
+ .add("hostname", hostname)
+ .add("domainName", domainName)
+ .add("user", user)
+ .add("memory", memory)
+ .add("memorySwap", memorySwap)
+ .add("cpuShares", cpuShares)
+ .add("attachStdin", attachStdin)
+ .add("attachStdout", attachStdout)
+ .add("attachStderr", attachStderr)
+ .add("exposedPorts", exposedPorts)
+ .add("tty", tty)
+ .add("openStdin", openStdin)
+ .add("stdinOnce", stdinOnce)
+ .add("env", env)
+ .add("cmd", cmd)
+ .add("dns", dns)
+ .add("imageId", imageId)
+ .add("volumes", volumes)
+ .add("volumesFrom", volumesFrom)
+ .add("workingDir", workingDir)
+ .add("entrypoint", entrypoint)
+ .add("networkDisabled", networkDisabled)
+ .add("onBuild", onBuild)
+ .toString();
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public Builder toBuilder() {
+ return builder().fromConfig(this);
+ }
+
+ public static final class Builder {
+ private String hostname;
+ private String domainName;
+ private String user;
+ private int memory;
+ private int memorySwap;
+ private int cpuShares;
+ private boolean attachStdin;
+ private boolean attachStdout;
+ private boolean attachStderr;
+ private Map<String, ?> exposedPorts = ImmutableMap.of();
+ private boolean tty;
+ private boolean openStdin;
+ private boolean stdinOnce;
+ private List<String> env = ImmutableList.of();
+ private List<String> cmd = ImmutableList.of();
+ private List<String> dns = ImmutableList.of();
+ private String imageId;
+ private Map<String, ?> volumes = ImmutableMap.of();
+ private String volumesFrom;
+ private String workingDir;
+ private String entrypoint;
+ private boolean networkDisabled;
+ private List<String> onBuild = ImmutableList.of();
+
+ public Builder hostname(String hostname) {
+ this.hostname = hostname;
+ return this;
+ }
+
+ public Builder domainName(String domainName) {
+ this.domainName = domainName;
+ return this;
+ }
+
+ public Builder user(String user) {
+ this.user = user;
+ return this;
+ }
+
+ public Builder memory(int memory) {
+ this.memory = memory;
+ return this;
+ }
+
+ public Builder memorySwap(int memorySwap) {
+ this.memorySwap = memorySwap;
+ return this;
+ }
+
+ public Builder cpuShares(int cpuShares) {
+ this.cpuShares = cpuShares;
+ return this;
+ }
+
+ public Builder attachStdin(boolean attachStdin) {
+ this.attachStdin = attachStdin;
+ return this;
+ }
+
+ public Builder attachStdout(boolean attachStdout) {
+ this.attachStdout = attachStdout;
+ return this;
+ }
+
+ public Builder attachStderr(boolean attachStderr) {
+ this.attachStderr = attachStderr;
+ return this;
+ }
+
+ public Builder exposedPorts(Map<String, ?> exposedPorts) {
+ this.exposedPorts = ImmutableMap.copyOf(checkNotNull(exposedPorts, "exposedPorts"));
+ return this;
+ }
+
+ public Builder tty(boolean tty) {
+ this.tty = tty;
+ return this;
+ }
+
+ public Builder openStdin(boolean openStdin) {
+ this.openStdin = openStdin;
+ return this;
+ }
+
+ public Builder stdinOnce(boolean stdinOnce) {
+ this.stdinOnce = stdinOnce;
+ return this;
+ }
+
+ public Builder env(List<String> env) {
+ this.env = env;
+ return this;
+ }
+
+ public Builder cmd(List<String> cmd) {
+ this.cmd = ImmutableList.copyOf(checkNotNull(cmd, "cmd"));
+ return this;
+ }
+
+ public Builder dns(List<String> dns) {
+ this.dns = ImmutableList.copyOf(checkNotNull(dns, "dns"));
+ return this;
+ }
+
+ public Builder imageId(String imageId) {
+ this.imageId = imageId;
+ return this;
+ }
+
+ public Builder volumes(Map<String, ?> volumes) {
+ this.volumes = ImmutableMap.copyOf(checkNotNull(volumes, "volumes"));
+ return this;
+ }
+
+ public Builder volumesFrom(String volumesFrom) {
+ this.volumesFrom = volumesFrom;
+ return this;
+ }
+
+ public Builder workingDir(String workingDir) {
+ this.workingDir = workingDir;
+ return this;
+ }
+
+ public Builder entrypoint(String entrypoint) {
+ this.entrypoint = entrypoint;
+ return this;
+ }
+
+ public Builder networkDisabled(boolean networkDisabled) {
+ this.networkDisabled = networkDisabled;
+ return this;
+ }
+
+ public Builder onBuild(List<String> onBuild) {
+ this.onBuild = ImmutableList.copyOf(checkNotNull(onBuild, "onBuild"));
+ return this;
+ }
+
+ public Config build() {
+ return new Config(hostname, domainName, user, memory, memorySwap, cpuShares, attachStdin, attachStdout,
+ attachStderr, exposedPorts, tty, openStdin, stdinOnce, env, cmd, dns, imageId, volumes,
+ volumesFrom, workingDir, entrypoint, networkDisabled, onBuild);
+ }
+
+ public Builder fromConfig(Config in) {
+ return this
+ .hostname(in.getHostname())
+ .domainName(in.getDomainName())
+ .user(in.getUser())
+ .memory(in.getMemory())
+ .memorySwap(in.getMemorySwap())
+ .cpuShares(in.getCpuShares())
+ .attachStdin(in.isAttachStdin())
+ .attachStdout(in.isAttachStdout())
+ .attachStderr(in.isAttachStderr())
+ .exposedPorts(in.getExposedPorts())
+ .tty(in.isTty())
+ .openStdin(in.isOpenStdin())
+ .stdinOnce(in.isStdinOnce())
+ .env(in.getEnv())
+ .cmd(in.getCmd())
+ .dns(in.getDns())
+ .imageId(in.getImageId())
+ .volumes(in.getVolumes())
+ .volumesFrom(in.getVolumesFrom())
+ .workingDir(in.getWorkingDir())
+ .entrypoint(in.getEntrypoint())
+ .networkDisabled(in.isNetworkDisabled())
+ .onBuild(in.getOnBuild());
+ }
+
+ }
+}