diff --git a/apis/docker/src/main/java/org/jclouds/docker/compute/options/DockerTemplateOptions.java b/apis/docker/src/main/java/org/jclouds/docker/compute/options/DockerTemplateOptions.java
index 4088a547c9..4239661e8d 100644
--- a/apis/docker/src/main/java/org/jclouds/docker/compute/options/DockerTemplateOptions.java
+++ b/apis/docker/src/main/java/org/jclouds/docker/compute/options/DockerTemplateOptions.java
@@ -22,8 +22,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import java.util.Map;
-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;
@@ -34,23 +34,55 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
/**
- * Contains options supported by the {@link ComputeService#createNodesInGroup(String, int, TemplateOptions) createNodes}
- * operation on the docker provider.
- *
+ * Contains options supported by the
+ * {@link org.jclouds.compute.ComputeService#createNodesInGroup(String, int, TemplateOptions)
+ * createNodes} operation on the docker provider.
+ *
*
Usage
*
- * 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.
*
- * {@code import static org.jclouds.docker.compute.options.DockerTemplateOptions.Builder.*;
+ *
+ * {@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());}
+ * Set extends NodeMetadata> set = api.createNodesInGroup(tag, 2, templateBuilder.build());}
+ *
+ *
+ * Advanced Usage
+ *
+ * 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-null
configBuilder, then this configuration object
+ * takes precedence over the other configuration in this class (i.e. the other
+ * config entries are not used)
+ *
+ *
+ * Note: The {@code image} property in the provided {@link Config.Builder} is rewritten by a placeholder value.
+ * The real value is configured by ComputeServiceAdapter.
+ *
+ *
+ *
+ * {@code import static org.jclouds.docker.compute.options.DockerTemplateOptions.Builder.*;
+ *
+ * ComputeService api = // get connection
+ * DockerTemplateOptions options = DockerTemplateOptions.Builder
+ * .configBuilder(
+ * Config.builder().env(ImmutableList. of("SSH_PORT=8822"))
+ * .hostConfig(HostConfig.builder().networkMode("host").build()));
+ * templateBuilder.options(options);
+ * Set extends NodeMetadata> set = api.createNodesInGroup("sample-group", 1, templateBuilder.build());}
+ *
*/
public class DockerTemplateOptions extends TemplateOptions implements Cloneable {
+ private static final String NO_IMAGE = "jclouds-placeholder-for-image";
+
protected List dns = ImmutableList.of();
protected String hostname;
protected Integer memory;
@@ -63,6 +95,8 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
protected String networkMode;
protected Map extraHosts = ImmutableMap.of();
+ protected Config.Builder configBuilder;
+
@Override
public DockerTemplateOptions clone() {
DockerTemplateOptions options = new DockerTemplateOptions();
@@ -94,6 +128,7 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
if (!extraHosts.isEmpty()) {
eTo.extraHosts(extraHosts);
}
+ eTo.configBuilder(configBuilder);
}
}
@@ -113,12 +148,22 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
equal(this.cpuShares, that.cpuShares) &&
equal(this.env, that.env) &&
equal(this.portBindings, that.portBindings) &&
- equal(this.extraHosts, that.extraHosts);
+ equal(this.extraHosts, that.extraHosts) &&
+ 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
@@ -134,6 +179,7 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
.add("env", env)
.add("portBindings", portBindings)
.add("extraHosts", extraHosts)
+ .add("configBuilder", configBuilder)
.toString();
}
@@ -235,6 +281,23 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
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 getVolumes() { return volumes; }
public List getDns() { return dns; }
@@ -257,6 +320,8 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
public Map getExtraHosts() { return extraHosts; }
+ public Config.Builder getConfigBuilder() { return configBuilder; }
+
public static class Builder {
/**
@@ -379,6 +444,11 @@ public class DockerTemplateOptions extends TemplateOptions implements Cloneable
return options.extraHosts(extraHosts);
}
+ public static DockerTemplateOptions configBuilder(Config.Builder configBuilder) {
+ DockerTemplateOptions options = new DockerTemplateOptions();
+ return options.configBuilder(configBuilder);
+ }
+
/**
* @see TemplateOptions#inboundPorts(int...)
*/
diff --git a/apis/docker/src/main/java/org/jclouds/docker/compute/strategy/DockerComputeServiceAdapter.java b/apis/docker/src/main/java/org/jclouds/docker/compute/strategy/DockerComputeServiceAdapter.java
index d800b7e24c..64e9e679ea 100644
--- a/apis/docker/src/main/java/org/jclouds/docker/compute/strategy/DockerComputeServiceAdapter.java
+++ b/apis/docker/src/main/java/org/jclouds/docker/compute/strategy/DockerComputeServiceAdapter.java
@@ -32,6 +32,7 @@ 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;
@@ -74,83 +75,97 @@ public class DockerComputeServiceAdapter implements
this.api = checkNotNull(api, "api");
}
+ @SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public NodeAndInitialCredentials 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();
+ DockerTemplateOptions templateOptions = DockerTemplateOptions.class.cast(options);
+ Config.Builder containerConfigBuilder = templateOptions.getConfigBuilder();
+ if (containerConfigBuilder == null) {
+ containerConfigBuilder = Config.builder();
- Map exposedPorts = Maps.newHashMap();
- for (int inboundPort : inboundPorts) {
- exposedPorts.put(inboundPort + "/tcp", Maps.newHashMap());
- }
+ containerConfigBuilder.entrypoint(templateOptions.getEntrypoint());
+ containerConfigBuilder.cmd(templateOptions.getCommands());
+ containerConfigBuilder.memory(templateOptions.getMemory());
+ containerConfigBuilder.hostname(templateOptions.getHostname());
+ containerConfigBuilder.cpuShares(templateOptions.getCpuShares());
+ containerConfigBuilder.env(templateOptions.getEnv());
- 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 volumes = Maps.newLinkedHashMap();
- for (String containerDir : templateOptions.getVolumes().values()) {
- volumes.put(containerDir, Maps.newHashMap());
+ if (!templateOptions.getVolumes().isEmpty()) {
+ Map volumes = Maps.newLinkedHashMap();
+ for (String containerDir : templateOptions.getVolumes().values()) {
+ volumes.put(containerDir, Maps.newHashMap());
+ }
+ containerConfigBuilder.volumes(volumes);
}
- containerConfigBuilder.volumes(volumes);
+
+ HostConfig.Builder hostConfigBuilder = HostConfig.builder()
+ .publishAllPorts(true)
+ .privileged(true);
+
+ if (!templateOptions.getPortBindings().isEmpty()) {
+ Map>> portBindings = Maps.newHashMap();
+ for (Map.Entry entry : templateOptions.getPortBindings().entrySet()) {
+ portBindings.put(entry.getValue() + "/tcp",
+ Lists.