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 2016/04/26 11:18:40 UTC

[1/2] jclouds-labs git commit: Backport of latest changes to Docker compute service from 2.0.0

Repository: jclouds-labs
Updated Branches:
  refs/heads/1.9.x 5c892910d -> e0dfe0757


Backport of latest changes to Docker compute service from 2.0.0


Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs/commit/919ff2a8
Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs/tree/919ff2a8
Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs/diff/919ff2a8

Branch: refs/heads/1.9.x
Commit: 919ff2a84856ff3f30aafef9cd98d93ee5aa1017
Parents: 5c89291
Author: Andrew Donald Kennedy <an...@cloudsoftcorp.com>
Authored: Sat Apr 23 20:03:05 2016 +0100
Committer: Ignasi Barrera <na...@apache.org>
Committed: Tue Apr 26 11:14:16 2016 +0200

----------------------------------------------------------------------
 .../compute/options/DockerTemplateOptions.java  | 128 +++++++++++++++--
 .../strategy/DockerComputeServiceAdapter.java   | 144 ++++++++++---------
 2 files changed, 194 insertions(+), 78 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/919ff2a8/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
index 1139d68..8a42253 100644
--- a/docker/src/main/java/org/jclouds/docker/compute/options/DockerTemplateOptions.java
+++ b/docker/src/main/java/org/jclouds/docker/compute/options/DockerTemplateOptions.java
@@ -25,31 +25,63 @@ import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 
-import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.docker.domain.Config;
 import org.jclouds.docker.internal.NullSafeCopies;
 import org.jclouds.domain.LoginCredentials;
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.scriptbuilder.domain.Statement;
 
 /**
- * Contains options supported by the {@link ComputeService#createNodesInGroup(String, int, TemplateOptions) createNodes}
- * operation on the <em>docker</em> provider.
+ * Contains options supported by the
+ * {@link org.jclouds.compute.ComputeService#createNodesInGroup(String, int, TemplateOptions)
+ * createNodes} operation on the <em>docker</em> provider.
  *
  * <h2>Usage</h2>
  *
- * The recommended way to instantiate a
- * DockerTemplateOptions object is to statically import {@code DockerTemplateOptions.Builder.*}
- * and invoke one of the static creation methods, followed by an instance mutator if needed.
+ * The recommended way to instantiate a DockerTemplateOptions object is to
+ * statically import {@code DockerTemplateOptions.Builder.*} and invoke one of
+ * the static creation methods, followed by an instance mutator if needed.
  *
- * <pre>{@code import static org.jclouds.docker.compute.options.DockerTemplateOptions.Builder.*;
+ * <pre>
+ * {@code import static org.jclouds.docker.compute.options.DockerTemplateOptions.Builder.*;
  *
  * ComputeService api = // get connection
  * templateBuilder.options(inboundPorts(22, 80, 8080, 443));
- * Set<? extends NodeMetadata> set = api.createNodesInGroup(tag, 2, templateBuilder.build());}</pre>
+ * Set<? extends NodeMetadata> set = api.createNodesInGroup(tag, 2, templateBuilder.build());}
+ * </pre>
+ *
+ * <h2>Advanced Usage</h2>
+ * <p>
+ * In addition to basic configuration through its methods, this class also
+ * provides possibility to work directly with Docker API configuration object (
+ * {@link Config.Builder}). When the
+ * {@link #configBuilder(org.jclouds.docker.domain.Config.Builder)} is used to
+ * configure not-<code>null</code> configBuilder, then this configuration object
+ * takes precedence over the other configuration in this class (i.e. the other
+ * config entries are not used)
+ * </p>
+ * <p>
+ * Note: The {@code image} property in the provided {@link Config.Builder} is rewritten by a placeholder value.
+ * The real value is configured by ComputeServiceAdapter.
+ * </p>
+ *
+ * <pre>
+ * {@code import static org.jclouds.docker.compute.options.DockerTemplateOptions.Builder.*;
+ *
+ * ComputeService api = // get connection
+ * DockerTemplateOptions options = DockerTemplateOptions.Builder
+ *       .configBuilder(
+ *                Config.builder().env(ImmutableList.<String> of("SSH_PORT=8822"))
+ *                      .hostConfig(HostConfig.builder().networkMode("host").build()));
+ * templateBuilder.options(options);
+ * Set<? extends NodeMetadata> set = api.createNodesInGroup("sample-group", 1, templateBuilder.build());}
+ * </pre>
  */
 public class DockerTemplateOptions extends TemplateOptions implements Cloneable {
 
+   private static final String NO_IMAGE = "jclouds-placeholder-for-image";
+
    protected List<String> dns = ImmutableList.of();
    @Nullable protected String hostname;
    @Nullable protected Integer memory;
@@ -62,6 +94,8 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
    @Nullable protected String networkMode;
    protected Map<String, String> extraHosts = ImmutableMap.of();
    protected List<String> volumesFrom = ImmutableList.of();
+   protected boolean privileged;
+   protected Config.Builder configBuilder;
 
    @Override
    public DockerTemplateOptions clone() {
@@ -87,6 +121,8 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
          eTo.networkMode(networkMode);
          eTo.extraHosts(extraHosts);
          eTo.volumesFrom(volumesFrom);
+         eTo.privileged(privileged);
+         eTo.configBuilder(configBuilder);
       }
    }
 
@@ -97,38 +133,53 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
       if (o == null || getClass() != o.getClass())
          return false;
       DockerTemplateOptions that = DockerTemplateOptions.class.cast(o);
-      return super.equals(that) && equal(this.volumes, that.volumes) &&
+      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.cpuShares, that.cpuShares) &&
               equal(this.entrypoint, that.entrypoint) &&
               equal(this.commands, that.commands) &&
-              equal(this.cpuShares, that.cpuShares) &&
               equal(this.env, that.env) &&
               equal(this.portBindings, that.portBindings) &&
+              equal(this.networkMode, that.networkMode) &&
               equal(this.extraHosts, that.extraHosts) &&
-              equal(this.volumesFrom, that.volumesFrom);
+              equal(this.volumesFrom, that.volumesFrom) &&
+              equal(this.privileged, that.privileged) &&
+              buildersEqual(this.configBuilder, that.configBuilder);
+   }
+
+
+   /**
+    * Compares two Config.Builder instances.
+    */
+   private boolean buildersEqual(Config.Builder b1, Config.Builder b2) {
+      return b1 == b2 || (b1 != null && b2 != null && b1.build().equals(b2.build()));
    }
 
    @Override
    public int hashCode() {
-      return Objects.hashCode(super.hashCode(), volumes, hostname, dns, memory, entrypoint, commands, cpuShares, env, portBindings, extraHosts);
+      return Objects.hashCode(super.hashCode(), volumes, hostname, dns, memory, entrypoint, commands, cpuShares, env,
+            portBindings, extraHosts, configBuilder);
    }
 
    @Override
    public String toString() {
       return Objects.toStringHelper(this)
-              .add("dns", dns)
+              .add("volumes", volumes)
               .add("hostname", hostname)
+              .add("dns", dns)
               .add("memory", memory)
               .add("cpuShares", cpuShares)
               .add("entrypoint", entrypoint)
               .add("commands", commands)
-              .add("volumes", volumes)
               .add("env", env)
               .add("portBindings", portBindings)
+              .add("networkMode", networkMode)
               .add("extraHosts", extraHosts)
               .add("volumesFrom", volumesFrom)
+              .add("configBuilder", configBuilder)
               .toString();
    }
 
@@ -241,6 +292,35 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
       return this;
    }
 
+   /**
+    * By default, Docker containers are unprivileged and cannot execute privileged operations or access certain
+    * host devices.
+    *
+    * @param privileged Whether the container should run in privileged mode or not
+    * @return this instance
+    */
+   public DockerTemplateOptions privileged(boolean privileged) {
+      this.privileged = privileged;
+      return this;
+   }
+
+   /**
+    * This method sets Config.Builder configuration object, which can be used as
+    * a replacement for all the other settings from this class. Some values in
+    * the provided Config.Builder instance (the image name for instance) can be
+    * ignored or their value can be changed.
+    *
+    * @param configBuilder
+    *           Config.Builder instance. This instance can be changed in this
+    *           method!
+    */
+   public DockerTemplateOptions configBuilder(Config.Builder configBuilder) {
+      this.configBuilder = configBuilder != null
+            ? Config.builder().fromConfig(configBuilder.image(NO_IMAGE).build())
+            : null;
+      return this;
+   }
+
    public Map<String, String> getVolumes() { return volumes; }
 
    public List<String> getDns() { return dns; }
@@ -265,6 +345,10 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
 
    public Map<String, String> getExtraHosts() { return extraHosts; }
 
+   public boolean getPrivileged() { return privileged; }
+
+   public Config.Builder getConfigBuilder() { return configBuilder; }
+
    public static class Builder {
 
       /**
@@ -388,6 +472,22 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
       }
 
       /**
+       * @see DockerTemplateOptions#privileged(boolean)
+       */
+      public static DockerTemplateOptions privileged(boolean privileged) {
+         DockerTemplateOptions options = new DockerTemplateOptions();
+         return options.privileged(privileged);
+      }
+
+      /**
+       * @see DockerTemplateOptions#configBuilder(Config.Builder)
+       */
+      public static DockerTemplateOptions configBuilder(Config.Builder configBuilder) {
+         DockerTemplateOptions options = new DockerTemplateOptions();
+         return options.configBuilder(configBuilder);
+      }
+
+      /**
        * @see DockerTemplateOptions#volumesFrom(Iterable)
        */
       public static DockerTemplateOptions volumesFrom(Iterable<String> volumesFrom) {

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/919ff2a8/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
index 3bc6e47..ebd7f5b 100644
--- a/docker/src/main/java/org/jclouds/docker/compute/strategy/DockerComputeServiceAdapter.java
+++ b/docker/src/main/java/org/jclouds/docker/compute/strategy/DockerComputeServiceAdapter.java
@@ -28,11 +28,20 @@ import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
 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.options.TemplateOptions;
 import org.jclouds.compute.reference.ComputeServiceConstants;
 import org.jclouds.docker.DockerApi;
 import org.jclouds.docker.compute.options.DockerTemplateOptions;
@@ -48,14 +57,6 @@ 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.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-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}
@@ -75,87 +76,102 @@ public class DockerComputeServiceAdapter implements
       this.api = checkNotNull(api, "api");
    }
 
+   @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public NodeAndInitialCredentials<Container> createNodeWithGroupEncodedIntoName(String group, String name,
                                                                                   Template template) {
       checkNotNull(template, "template was null");
-      checkNotNull(template.getOptions(), "template options was null");
+      TemplateOptions options = template.getOptions();
+      checkNotNull(options, "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().getOptionalPassword().or("password");
 
-      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());
-      }
+      DockerTemplateOptions templateOptions = DockerTemplateOptions.class.cast(options);
+      Config.Builder containerConfigBuilder = templateOptions.getConfigBuilder();
+      if (containerConfigBuilder == null) {
+         containerConfigBuilder = Config.builder();
+
+         containerConfigBuilder.entrypoint(templateOptions.getEntrypoint());
+         containerConfigBuilder.cmd(templateOptions.getCommands());
+         containerConfigBuilder.memory(templateOptions.getMemory());
+         containerConfigBuilder.hostname(templateOptions.getHostname());
+         containerConfigBuilder.cpuShares(templateOptions.getCpuShares());
+         containerConfigBuilder.env(templateOptions.getEnv());
+
+         if (!templateOptions.getVolumes().isEmpty()) {
+            Map<String, Object> volumes = Maps.newLinkedHashMap();
+            for (String containerDir : templateOptions.getVolumes().values()) {
+               volumes.put(containerDir, Maps.newHashMap());
+            }
+            containerConfigBuilder.volumes(volumes);
+         }
 
-      Config.Builder containerConfigBuilder = Config.builder()
-              .image(imageId)
-              .exposedPorts(exposedPorts);
-
-      containerConfigBuilder.entrypoint(templateOptions.getEntrypoint());
-      containerConfigBuilder.cmd(templateOptions.getCommands());
-      containerConfigBuilder.memory(templateOptions.getMemory());
-      containerConfigBuilder.hostname(templateOptions.getHostname());
-      containerConfigBuilder.cpuShares(templateOptions.getCpuShares());
-      containerConfigBuilder.env(templateOptions.getEnv());
-
-      if (!templateOptions.getVolumes().isEmpty()) {
-         Map<String, Object> volumes = Maps.newLinkedHashMap();
-         for (String containerDir : templateOptions.getVolumes().values()) {
-            volumes.put(containerDir, Maps.newHashMap());
+         HostConfig.Builder hostConfigBuilder = HostConfig.builder()
+                 .publishAllPorts(true)
+                 .privileged( templateOptions.getPrivileged() );
+
+         if (!templateOptions.getPortBindings().isEmpty()) {
+            Map<String, List<Map<String, String>>> portBindings = Maps.newHashMap();
+            for (Map.Entry<Integer, Integer> entry : templateOptions.getPortBindings().entrySet()) {
+               portBindings.put(entry.getValue() + "/tcp",
+                       Lists.<Map<String, String>>newArrayList(ImmutableMap.of("HostPort", Integer.toString(entry.getKey()))));
+            }
+            hostConfigBuilder.portBindings(portBindings);
          }
-         containerConfigBuilder.volumes(volumes);
-      }
 
-      Config containerConfig = containerConfigBuilder.build();
+         if (!templateOptions.getDns().isEmpty()) {
+            hostConfigBuilder.dns(templateOptions.getDns());
+         }
 
-      logger.debug(">> creating new container with containerConfig(%s)", containerConfig);
-      Container container = api.getContainerApi().createContainer(name, containerConfig);
-      logger.trace("<< container(%s)", container.id());
+         if (!templateOptions.getExtraHosts().isEmpty()) {
+            List<String> extraHosts = Lists.newArrayList();
+            for (Map.Entry<String, String> entry : templateOptions.getExtraHosts().entrySet()) {
+               extraHosts.add(entry.getKey() + ":" + entry.getValue());
+            }
+            hostConfigBuilder.extraHosts(extraHosts);
+         }
 
-      HostConfig.Builder hostConfigBuilder = HostConfig.builder()
-              .publishAllPorts(true)
-              .privileged(true);
+         if (!templateOptions.getVolumes().isEmpty()) {
+            for (Map.Entry<String, String> entry : templateOptions.getVolumes().entrySet()) {
+               hostConfigBuilder.binds(ImmutableList.of(entry.getKey() + ":" + entry.getValue()));
+            }
+         }
 
-      if (!templateOptions.getPortBindings().isEmpty()) {
-         Map<String, List<Map<String, String>>> portBindings = Maps.newHashMap();
-         for (Map.Entry<Integer, Integer> entry : templateOptions.getPortBindings().entrySet()) {
-            portBindings.put(entry.getValue() + "/tcp",
-                  Lists.<Map<String, String>>newArrayList(ImmutableMap.of("HostPort", Integer.toString(entry.getKey()))));
+         if (!templateOptions.getVolumesFrom().isEmpty()) {
+            hostConfigBuilder.volumesFrom(templateOptions.getVolumesFrom());
          }
-         hostConfigBuilder.portBindings(portBindings);
-      }
 
-      if (!templateOptions.getDns().isEmpty()) {
-         hostConfigBuilder.dns(templateOptions.getDns());
-      }
+         hostConfigBuilder.networkMode(templateOptions.getNetworkMode());
 
-      if (!templateOptions.getExtraHosts().isEmpty()) {
-         List<String> extraHosts = Lists.newArrayList();
-         for (Map.Entry<String, String> entry : templateOptions.getExtraHosts().entrySet()) {
-            extraHosts.add(entry.getKey() + ":" + entry.getValue());
-         }
-         hostConfigBuilder.extraHosts(extraHosts);
+         containerConfigBuilder.hostConfig(hostConfigBuilder.build());
       }
 
-      if (!templateOptions.getVolumes().isEmpty()) {
-         for (Map.Entry<String, String> entry : templateOptions.getVolumes().entrySet()) {
-             hostConfigBuilder.binds(ImmutableList.of(entry.getKey() + ":" + entry.getValue()));
+      containerConfigBuilder.image(imageId);
+
+      // add the inbound ports into exposed ports map
+      Config containerConfig = containerConfigBuilder.build();
+      Map<String, Object> exposedPorts = Maps.newHashMap();
+      if (containerConfig.exposedPorts() == null) {
+         exposedPorts.putAll(containerConfig.exposedPorts());
+      }
+      for (int inboundPort : templateOptions.getInboundPorts()) {
+         String portKey = inboundPort + "/tcp";
+         if (!exposedPorts.containsKey(portKey)) {
+            exposedPorts.put(portKey, Maps.newHashMap());
          }
       }
+      containerConfigBuilder.exposedPorts(exposedPorts);
 
-      if (!templateOptions.getVolumesFrom().isEmpty()) {
-          hostConfigBuilder.volumesFrom(templateOptions.getVolumesFrom());
-      }
+      // build once more after setting inboundPorts
+      containerConfig = containerConfigBuilder.build();
 
-      hostConfigBuilder.networkMode(templateOptions.getNetworkMode());
+      logger.debug(">> creating new container with containerConfig(%s)", containerConfig);
+      Container container = api.getContainerApi().createContainer(name, containerConfig);
+      logger.trace("<< container(%s)", container.id());
 
-      HostConfig hostConfig = hostConfigBuilder.build();
+      HostConfig hostConfig = containerConfig.hostConfig();
 
       api.getContainerApi().startContainer(container.id(), hostConfig);
       container = api.getContainerApi().inspectContainer(container.id());


[2/2] jclouds-labs git commit: Add openStdin option to Docker template options and set all port bindings explicitly

Posted by na...@apache.org.
Add openStdin option to Docker template options and set all port bindings explicitly


Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs/commit/e0dfe075
Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs/tree/e0dfe075
Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs/diff/e0dfe075

Branch: refs/heads/1.9.x
Commit: e0dfe0757486faac071969a2c8cb0e572460a261
Parents: 919ff2a
Author: Andrew Donald Kennedy <an...@cloudsoftcorp.com>
Authored: Mon Apr 25 22:25:40 2016 +0100
Committer: Ignasi Barrera <na...@apache.org>
Committed: Tue Apr 26 11:14:19 2016 +0200

----------------------------------------------------------------------
 .../compute/options/DockerTemplateOptions.java  | 28 +++++++++++++++++++-
 .../strategy/DockerComputeServiceAdapter.java   | 21 +++++++++++++--
 2 files changed, 46 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e0dfe075/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
index 8a42253..1ff4b44 100644
--- a/docker/src/main/java/org/jclouds/docker/compute/options/DockerTemplateOptions.java
+++ b/docker/src/main/java/org/jclouds/docker/compute/options/DockerTemplateOptions.java
@@ -95,6 +95,7 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
    protected Map<String, String> extraHosts = ImmutableMap.of();
    protected List<String> volumesFrom = ImmutableList.of();
    protected boolean privileged;
+   protected boolean openStdin;
    protected Config.Builder configBuilder;
 
    @Override
@@ -122,6 +123,7 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
          eTo.extraHosts(extraHosts);
          eTo.volumesFrom(volumesFrom);
          eTo.privileged(privileged);
+         eTo.openStdin(openStdin);
          eTo.configBuilder(configBuilder);
       }
    }
@@ -147,6 +149,7 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
               equal(this.extraHosts, that.extraHosts) &&
               equal(this.volumesFrom, that.volumesFrom) &&
               equal(this.privileged, that.privileged) &&
+              equal(this.openStdin, that.openStdin) &&
               buildersEqual(this.configBuilder, that.configBuilder);
    }
 
@@ -161,7 +164,7 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
    @Override
    public int hashCode() {
       return Objects.hashCode(super.hashCode(), volumes, hostname, dns, memory, entrypoint, commands, cpuShares, env,
-            portBindings, extraHosts, configBuilder);
+            portBindings, extraHosts, volumesFrom, privileged, openStdin, configBuilder);
    }
 
    @Override
@@ -179,6 +182,8 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
               .add("networkMode", networkMode)
               .add("extraHosts", extraHosts)
               .add("volumesFrom", volumesFrom)
+              .add("privileged", privileged)
+              .add("openStdin", openStdin)
               .add("configBuilder", configBuilder)
               .toString();
    }
@@ -305,6 +310,17 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
    }
 
    /**
+    * Keep {@code STDIN} open when running interactive workloads in the container.
+    *
+    * @param openStdin Whether the container should keep STDIN open
+    * @return this instance
+    */
+   public DockerTemplateOptions openStdin(boolean openStdin) {
+      this.openStdin = openStdin;
+      return this;
+   }
+
+   /**
     * This method sets Config.Builder configuration object, which can be used as
     * a replacement for all the other settings from this class. Some values in
     * the provided Config.Builder instance (the image name for instance) can be
@@ -347,6 +363,8 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
 
    public boolean getPrivileged() { return privileged; }
 
+   public boolean getOpenStdin() { return openStdin; }
+
    public Config.Builder getConfigBuilder() { return configBuilder; }
 
    public static class Builder {
@@ -480,6 +498,14 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
       }
 
       /**
+       * @see DockerTemplateOptions#openStdin(boolean)
+       */
+      public static DockerTemplateOptions openStdin(boolean openStdin) {
+         DockerTemplateOptions options = new DockerTemplateOptions();
+         return options.openStdin(openStdin);
+      }
+
+      /**
        * @see DockerTemplateOptions#configBuilder(Config.Builder)
        */
       public static DockerTemplateOptions configBuilder(Config.Builder configBuilder) {

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e0dfe075/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
index ebd7f5b..a1c9cae 100644
--- a/docker/src/main/java/org/jclouds/docker/compute/strategy/DockerComputeServiceAdapter.java
+++ b/docker/src/main/java/org/jclouds/docker/compute/strategy/DockerComputeServiceAdapter.java
@@ -98,6 +98,7 @@ public class DockerComputeServiceAdapter implements
          containerConfigBuilder.memory(templateOptions.getMemory());
          containerConfigBuilder.hostname(templateOptions.getHostname());
          containerConfigBuilder.cpuShares(templateOptions.getCpuShares());
+         containerConfigBuilder.openStdin(templateOptions.getOpenStdin());
          containerConfigBuilder.env(templateOptions.getEnv());
 
          if (!templateOptions.getVolumes().isEmpty()) {
@@ -110,13 +111,13 @@ public class DockerComputeServiceAdapter implements
 
          HostConfig.Builder hostConfigBuilder = HostConfig.builder()
                  .publishAllPorts(true)
-                 .privileged( templateOptions.getPrivileged() );
+                 .privileged(templateOptions.getPrivileged());
 
          if (!templateOptions.getPortBindings().isEmpty()) {
             Map<String, List<Map<String, String>>> portBindings = Maps.newHashMap();
             for (Map.Entry<Integer, Integer> entry : templateOptions.getPortBindings().entrySet()) {
                portBindings.put(entry.getValue() + "/tcp",
-                       Lists.<Map<String, String>>newArrayList(ImmutableMap.of("HostPort", Integer.toString(entry.getKey()))));
+                       Lists.<Map<String, String>>newArrayList(ImmutableMap.of("HostIp", "0.0.0.0", "HostPort", Integer.toString(entry.getKey()))));
             }
             hostConfigBuilder.portBindings(portBindings);
          }
@@ -167,6 +168,22 @@ public class DockerComputeServiceAdapter implements
       // build once more after setting inboundPorts
       containerConfig = containerConfigBuilder.build();
 
+      // finally update port bindings
+      Map<String, List<Map<String, String>>> portBindings = Maps.newHashMap();
+      Map<String, List<Map<String, String>>> existingBindings = containerConfig.hostConfig().portBindings();
+      if (existingBindings != null) {
+          portBindings.putAll(existingBindings);
+      }
+      for (String exposedPort : containerConfig.exposedPorts().keySet()) {
+         if (!portBindings.containsKey(exposedPort)) {
+            portBindings.put(exposedPort, Lists.<Map<String, String>>newArrayList(ImmutableMap.of("HostIp", "0.0.0.0")));
+         }
+      }
+      HostConfig.Builder hostConfigBuilder = HostConfig.builder().fromHostConfig(containerConfig.hostConfig());
+      hostConfigBuilder.portBindings(portBindings);
+      containerConfigBuilder.hostConfig(hostConfigBuilder.build());
+      containerConfig = containerConfigBuilder.build();
+
       logger.debug(">> creating new container with containerConfig(%s)", containerConfig);
       Container container = api.getContainerApi().createContainer(name, containerConfig);
       logger.trace("<< container(%s)", container.id());