support for docker 1.3.2

- update value objects (Container, Config)
- add new value object (Resource, StatusCode)
- add more options for ContainerApi
- add support for pause/unpause, restart, kill, copy and attach APIs + Mock and Live tests
- add *ParseTest
- refactor MockTests
- removed *Options.NONE
- cleanup low-value javadoc
- more coverage in LiveTests
- removed useless DockerProperties
- add comments for TLS issue
- use Date where needed
- fix listImages
- add package-private constructor to value classes
- remove KillOptions, RestartOptions, StopOptions in favour of @QueryParam
- use PEM instead of PKCS12 format
- update docker/pom.xml to use sshj dependencies
- explicit usage of OkHttp driver
- simplify DockerApiMetadata
- add bouncycastle driver explicitly
This commit is contained in:
Andrea Turli 2014-11-24 17:34:22 +01:00
parent 6219b77dbc
commit 14da3d680a
55 changed files with 1806 additions and 780 deletions

View File

@ -7,10 +7,16 @@ providers, it supports the same portable abstractions offered by jclouds.
Please follow these steps to configure your workstation for jclouds-docker:
- install the latest Docker release (please visit https://docs.docker.com/installation/)
If you are using boot2docker, notice that from version v1.3.0 the Docker daemon is set to use an encrypted TCP socket (--tls, or --tlsverify),
then you need to create a p12 certificate using the following command:
If you are using `boot2docker`, notice that from version v1.3.0 the Docker daemon is set to use an encrypted TCP
socket (--tls, or --tlsverify),
then you need to import CA certificate into Trusted Certs:
`openssl pkcs12 -export -out $HOME/.jclouds/docker.p12 -inkey $HOME/.boot2docker/certs/boot2docker-vm/key.pem -in $HOME/.boot2docker/certs/boot2docker-vm/cert.pem -certfile $HOME/.boot2docker/certs/boot2docker-vm/ca.pem`
` keytool -import -trustcacerts -file /Users/andrea/.boot2docker/certs/boot2docker-vm/ca.pem -alias BOOT2DOCKER -keystore $JAVA_HOME/jre/lib/security/cacerts`
by default the passoword is `changeit`
N.B.: From `Docker 1.3.2+` the server doesn't accept sslv3 protocol (https://github.com/docker/docker/pull/8588/files)
#How it works
@ -45,8 +51,9 @@ then you need to create a p12 certificate using the following command:
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 -aq | xargs docker rm -f`
$ docker rm `docker ps -a`
2. remove all the images
`$ docker images -q | xargs docker rmi -f`
$ docker rmi -f `docker images -q`

View File

@ -35,7 +35,7 @@
<properties>
<test.docker.endpoint>https://localhost:4243</test.docker.endpoint>
<test.docker.api-version>1.10</test.docker.api-version>
<test.docker.api-version>1.15</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>
@ -67,7 +67,16 @@
<groupId>org.apache.jclouds.driver</groupId>
<artifactId>jclouds-sshj</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.jclouds.driver</groupId>
<artifactId>jclouds-bouncycastle</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jclouds.driver</groupId>
<artifactId>jclouds-okhttp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>

View File

@ -52,8 +52,6 @@ public class DockerApiMetadata extends BaseHttpApiMetadata<DockerApi> {
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");
@ -66,8 +64,8 @@ public class DockerApiMetadata extends BaseHttpApiMetadata<DockerApi> {
super(DockerApi.class);
id("docker")
.name("Docker API")
.identityName("Path to Certificate .p12 file")
.credentialName("Password to Certificate")
.identityName("Path to certificate .pem file")
.credentialName("Password to key .pem file")
.documentation(URI.create("https://docs.docker.com/reference/api/docker_remote_api/"))
.version("1.15")
.defaultEndpoint("https://127.0.0.1:2376")

View File

@ -40,6 +40,7 @@ import org.jclouds.docker.domain.Container;
import org.jclouds.docker.domain.ContainerSummary;
import org.jclouds.docker.domain.HostConfig;
import org.jclouds.docker.domain.Image;
import org.jclouds.docker.domain.ImageSummary;
import org.jclouds.docker.options.ListContainerOptions;
import org.jclouds.docker.options.RemoveContainerOptions;
import org.jclouds.domain.Location;
@ -170,14 +171,13 @@ public class DockerComputeServiceAdapter implements
@Override
public Set<Image> listImages() {
Set<Image> images = Sets.newHashSet();
for (Image image : api.getImageApi().listImages()) {
for (ImageSummary imageSummary : api.getImageApi().listImages()) {
// less efficient than just listImages but returns richer json that needs repoTags coming from listImages
Image inspected = api.getImageApi().inspectImage(image.id());
if (inspected.repoTags().isEmpty()) {
inspected = Image.create(inspected.id(), inspected.parent(), inspected.container(), inspected.created(),
inspected.dockerVersion(), inspected.architecture(), inspected.os(), inspected.size(),
inspected.virtualSize(), image.repoTags());
}
Image inspected = api.getImageApi().inspectImage(imageSummary.id());
inspected = Image.create(inspected.id(), inspected.author(), inspected.comment(), inspected.config(),
inspected.containerConfig(), inspected.parent(), inspected.created(), inspected.container(),
inspected.dockerVersion(), inspected.architecture(), inspected.os(), inspected.size(),
inspected.virtualSize(), imageSummary.repoTags());
images.add(inspected);
}
return images;
@ -237,12 +237,12 @@ public class DockerComputeServiceAdapter implements
@Override
public void resumeNode(String id) {
throw new UnsupportedOperationException("resume not supported");
api.getContainerApi().unpause(id);
}
@Override
public void suspendNode(String id) {
throw new UnsupportedOperationException("suspend not supported");
api.getContainerApi().pause(id);
}
}

View File

@ -16,28 +16,23 @@
*/
package org.jclouds.docker.config;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import org.jclouds.docker.DockerApi;
import org.jclouds.docker.handlers.DockerErrorHandler;
import org.jclouds.docker.suppliers.KeyStoreSupplier;
import org.jclouds.docker.suppliers.SSLContextWithKeysSupplier;
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.http.config.ConfiguresHttpCommandExecutorService;
import org.jclouds.http.okhttp.OkHttpClientSupplier;
import org.jclouds.http.okhttp.config.OkHttpCommandExecutorServiceModule;
import org.jclouds.rest.ConfiguresHttpApi;
import org.jclouds.rest.config.HttpApiModule;
import com.google.common.base.Supplier;
import com.google.inject.TypeLiteral;
/**
* Configures the Docker connection.
*/
@ConfiguresHttpApi
@ConfiguresHttpCommandExecutorService
public class DockerHttpApiModule extends HttpApiModule<DockerApi> {
@Override
@ -53,11 +48,8 @@ public class DockerHttpApiModule extends HttpApiModule<DockerApi> {
@Override
protected void configure() {
super.configure();
bind(new TypeLiteral<Supplier<SSLContext>>() {
}).to(new TypeLiteral<SSLContextWithKeysSupplier>() {
});
bind(new TypeLiteral<Supplier<KeyStore>>() {
}).to(new TypeLiteral<KeyStoreSupplier>() {
});
install(new OkHttpCommandExecutorServiceModule());
bind(OkHttpClientSupplier.class).to(DockerOkHttpClientSupplier.class);
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.suppliers.SSLContextWithKeysSupplier;
import org.jclouds.http.okhttp.OkHttpClientSupplier;
import com.google.common.collect.ImmutableList;
import com.squareup.okhttp.ConnectionSpec;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.TlsVersion;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class DockerOkHttpClientSupplier implements OkHttpClientSupplier {
private final SSLContextWithKeysSupplier sslContextWithKeysSupplier;
@Inject
DockerOkHttpClientSupplier(SSLContextWithKeysSupplier sslContextWithKeysSupplier) {
this.sslContextWithKeysSupplier = sslContextWithKeysSupplier;
}
@Override
public OkHttpClient get() {
OkHttpClient client = new OkHttpClient();
ConnectionSpec connectionSpecs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_0, TlsVersion.TLS_1_1, TlsVersion.TLS_1_2)
.build();
client.setConnectionSpecs(ImmutableList.of(connectionSpecs));
client.setSslSocketFactory(sslContextWithKeysSupplier.get().getSocketFactory());
return client;
}
}

View File

@ -21,7 +21,9 @@ import org.jclouds.json.config.GsonModule;
import com.google.inject.AbstractModule;
public class DockerParserModule extends AbstractModule {
@Override protected void configure() {
bind(GsonModule.DateAdapter.class).to(GsonModule.Iso8601DateAdapter.class);
}
}

View File

@ -26,8 +26,8 @@ import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@AutoValue
public abstract class Config {
@ -49,8 +49,6 @@ public abstract class Config {
public abstract boolean attachStderr();
public abstract Map<String, ?> exposedPorts();
public abstract boolean tty();
public abstract boolean openStdin();
@ -61,34 +59,75 @@ public abstract class Config {
public abstract List<String> cmd();
public abstract List<String> dns();
public abstract List<String> entrypoint();
public abstract String image();
public abstract Map<String, ?> volumes();
@Nullable public abstract String volumesFrom();
@Nullable public abstract String workingDir();
public abstract List<String> entrypoint();
public abstract boolean networkDisabled();
public abstract List<String> onBuild();
public abstract Map<String, ?> exposedPorts();
public abstract List<String> securityOpts();
@Nullable public abstract HostConfig hostConfig();
public abstract List<String> binds();
public abstract List<String> links();
public abstract List<Map<String, String>> lxcConf();
public abstract Map<String, List<Map<String, String>>> portBindings();
public abstract boolean publishAllPorts();
public abstract boolean privileged();
@Nullable public abstract List<String> dns();
@Nullable public abstract String dnsSearch();
@Nullable public abstract String volumesFrom();
public abstract List<String> capAdd();
public abstract List<String> capDrop();
public abstract Map<String, String> restartPolicy();
@Nullable public abstract String networkMode();
public abstract Map<String, String> devices();
Config() {
}
@SerializedNames(
{ "Hostname", "Domainname", "User", "Memory", "MemorySwap", "CpuShares", "AttachStdin", "AttachStdout",
"AttachStderr", "ExposedPorts", "Tty", "OpenStdin", "StdinOnce", "Env", "Cmd", "Dns", "Image", "Volumes",
"VolumesFrom", "WorkingDir", "Entrypoint", "NetworkDisabled", "OnBuild" })
{
"Hostname", "Domainname", "User", "Memory", "MemorySwap", "CpuShares", "AttachStdin", "AttachStdout",
"AttachStderr", "Tty", "OpenStdin", "StdinOnce", "Env", "Cmd", "Entrypoint", "Image", "Volumes",
"WorkingDir", "NetworkDisabled", "ExposedPorts", "SecurityOpts", "HostConfig", "Binds", "Links",
"LxcConf", "PortBindings", "PublishAllPorts", "Privileged", "Dns", "DnsSearch", "VolumesFrom",
"CapAdd", "CapDrop", "RestartPolicy", "NetworkMode", "Devices"
})
public static Config create(String hostname, String domainname, String user, int memory, int memorySwap,
int cpuShares, boolean attachStdin, boolean attachStdout, boolean attachStderr, Map<String, ?> exposedPorts,
boolean tty, boolean openStdin, boolean stdinOnce, List<String> env, List<String> cmd, List<String> dns,
String image, Map<String, ?> volumes, String volumesFrom, String workingDir, List<String> entrypoint,
boolean networkDisabled, List<String> onBuild) {
return new AutoValue_Config(hostname, domainname, user, memory, memorySwap, cpuShares, attachStdin, attachStdout,
attachStderr, copyOf(exposedPorts), tty, openStdin, stdinOnce, copyOf(env), copyOf(cmd), copyOf(dns), image,
copyOf(volumes), volumesFrom, workingDir, copyOf(entrypoint), networkDisabled, copyOf(onBuild));
int cpuShares, boolean attachStdin, boolean attachStdout, boolean attachStderr, boolean tty,
boolean openStdin, boolean stdinOnce, List<String> env, List<String> cmd, List<String> entrypoint,
String image, Map<String, ?> volumes, String workingDir, boolean networkDisabled,
Map<String, ?> exposedPorts, List<String> securityOpts, HostConfig hostConfig, List<String> binds,
List<String> links, List<Map<String, String>> lxcConf, Map<String, List<Map<String, String>>> portBindings,
boolean publishAllPorts, boolean privileged, List<String> dns, String dnsSearch, String volumesFrom,
List<String> capAdd, List<String> capDrop, Map<String, String> restartPolicy, String networkMode, Map<String, String> devices) {
return new AutoValue_Config(hostname, domainname, user, memory, memorySwap, cpuShares, attachStdin,
attachStdout, attachStderr, tty, openStdin, stdinOnce, copyOf(env), copyOf(cmd), copyOf(entrypoint),
image, copyOf(volumes), workingDir, networkDisabled, copyOf(exposedPorts), copyOf(securityOpts), hostConfig,
copyOf(binds), copyOf(links), copyOf(lxcConf), copyOf(portBindings), publishAllPorts, privileged,
copyOf(dns), dnsSearch, volumesFrom, copyOf(capAdd), copyOf(capDrop), copyOf(restartPolicy), networkMode,
copyOf(devices));
}
public static Builder builder() {
@ -109,21 +148,33 @@ public abstract class Config {
private boolean attachStdin;
private boolean attachStdout;
private boolean attachStderr;
private Map<String, ?> exposedPorts = ImmutableMap.of();
private List<String> env = ImmutableList.of();
private boolean tty;
private boolean openStdin;
private boolean stdinOnce;
private List<String> cmd = ImmutableList.of();
private List<String> dns = ImmutableList.of();
private List<String> env = Lists.newArrayList();
private List<String> cmd = Lists.newArrayList();
private List<String> entrypoint = Lists.newArrayList();
private String image;
private Map<String, ?> volumes = ImmutableMap.of();
private String volumesFrom;
private Map<String, ?> volumes = Maps.newHashMap();
private String workingDir;
private List<String> entrypoint = ImmutableList.of();
private boolean networkDisabled;
private List<String> onBuild = ImmutableList.of();
private Map<String, String> restartPolicy = ImmutableMap.of();
private Map<String, ?> exposedPorts = Maps.newHashMap();
private List<String> securityOpts = Lists.newArrayList();
private HostConfig hostConfig;
private List<String> binds = Lists.newArrayList();
private List<String> links = Lists.newArrayList();
private List<Map<String, String>> lxcConf = Lists.newArrayList();
private Map<String, List<Map<String, String>>> portBindings = Maps.newHashMap();
private boolean publishAllPorts;
private boolean privileged;
private List<String> dns;
private String dnsSearch;
private String volumesFrom;
private List<String> capAdd = Lists.newArrayList();
private List<String> capDrop = Lists.newArrayList();
private Map<String, String> restartPolicy = Maps.newHashMap();
private String networkMode;
private Map<String, String> devices = Maps.newHashMap();
public Builder hostname(String hostname) {
this.hostname = hostname;
@ -170,11 +221,6 @@ public abstract class Config {
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;
@ -196,32 +242,7 @@ public abstract class Config {
}
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 image(String image) {
this.image = image;
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;
this.cmd = cmd;
return this;
}
@ -230,35 +251,129 @@ public abstract class Config {
return this;
}
public Builder image(String image) {
this.image = checkNotNull(image, "image");
return this;
}
public Builder volumes(Map<String, ?> volumes) {
this.volumes = volumes;
return this;
}
public Builder workingDir(String workingDir) {
this.workingDir = workingDir;
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"));
public Builder exposedPorts(Map<String, ?> exposedPorts) {
this.exposedPorts = exposedPorts;
return this;
}
public Builder securityOpts(List<String> securityOpts) {
this.securityOpts = securityOpts;
return this;
}
public Builder hostConfig(HostConfig hostConfig) {
this.hostConfig = checkNotNull(hostConfig, "hostConfig");
return this;
}
public Builder binds(List<String> binds) {
this.binds = binds;
return this;
}
public Builder links(List<String> links) {
this.links = links;
return this;
}
public Builder lxcConf(List<Map<String, String>> lxcConf) {
this.lxcConf = lxcConf;
return this;
}
public Builder portBindings(Map<String, List<Map<String, String>>> portBindings) {
this.portBindings = portBindings;
return this;
}
public Builder publishAllPorts(boolean publishAllPorts) {
this.publishAllPorts = publishAllPorts;
return this;
}
public Builder privileged(boolean privileged) {
this.privileged = privileged;
return this;
}
public Builder dns(List<String> dns) {
this.dns = dns;
return this;
}
public Builder dnsSearch(String dnsSearch) {
this.dnsSearch = dnsSearch;
return this;
}
public Builder volumesFrom(String volumesFrom) {
this.volumesFrom = volumesFrom;
return this;
}
public Builder capAdd(List<String> capAdd) {
this.capAdd = capAdd;
return this;
}
public Builder capDrop(List<String> capDrop) {
this.capDrop = capDrop;
return this;
}
public Builder restartPolicy(Map<String, String> restartPolicy) {
this.restartPolicy = ImmutableMap.copyOf(restartPolicy);
this.restartPolicy = restartPolicy;
return this;
}
public Builder networkMode(String networkMode) {
this.networkMode = networkMode;
return this;
}
public Builder devices(Map<String, String> devices) {
this.devices = devices;
return this;
}
public Config build() {
return Config.create(hostname, domainname, user, memory, memorySwap, cpuShares, attachStdin, attachStdout,
attachStderr, exposedPorts, tty, openStdin, stdinOnce, env, cmd, dns, image, volumes, volumesFrom,
workingDir, entrypoint, networkDisabled, onBuild);
attachStderr, tty, openStdin, stdinOnce, env, cmd, entrypoint, image, volumes, workingDir,
networkDisabled, exposedPorts, securityOpts, hostConfig, binds, links, lxcConf, portBindings,
publishAllPorts, privileged, dns, dnsSearch, volumesFrom, capAdd, capDrop, restartPolicy,
networkMode, devices);
}
public Builder fromConfig(Config in) {
return hostname(in.hostname()).domainname(in.domainname()).user(in.user()).memory(in.memory())
.memorySwap(in.memorySwap()).cpuShares(in.cpuShares()).attachStdin(in.attachStdin())
.attachStdout(in.attachStdout()).attachStderr(in.attachStderr()).exposedPorts(in.exposedPorts())
.tty(in.tty()).openStdin(in.openStdin()).stdinOnce(in.stdinOnce()).env(in.env()).cmd(in.cmd())
.dns(in.dns()).image(in.image()).volumes(in.volumes()).volumesFrom(in.volumesFrom())
.workingDir(in.workingDir()).entrypoint(in.entrypoint()).networkDisabled(in.networkDisabled())
.onBuild(in.onBuild());
.memorySwap(in.memorySwap()).cpuShares(in.cpuShares()).attachStdin(in.attachStdin())
.attachStdout(in.attachStdout()).attachStderr(in.attachStderr()).tty(in.tty())
.image(in.image()).volumes(in.volumes()).workingDir(in.workingDir())
.networkDisabled(in.networkDisabled()).exposedPorts(in.exposedPorts()).securityOpts(in.securityOpts())
.hostConfig(in.hostConfig()).binds(in.binds()).links(in.links()).lxcConf(in.lxcConf())
.portBindings(in.portBindings()).publishAllPorts(in.publishAllPorts()).privileged(in.privileged())
.dns(in.dns()).dnsSearch(in.dnsSearch()).volumesFrom(in.volumesFrom()).capAdd(in.capAdd())
.capDrop(in.capDrop()).restartPolicy(in.restartPolicy()).networkMode(in.networkMode()).devices(in.devices());
}
}

View File

@ -18,6 +18,7 @@ package org.jclouds.docker.domain;
import static org.jclouds.docker.internal.NullSafeCopies.copyOf;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -32,12 +33,12 @@ import com.google.common.collect.ImmutableMap;
public abstract class Container {
public abstract String id();
@Nullable public abstract String name();
@Nullable public abstract String created();
@Nullable public abstract Date created();
@Nullable public abstract String path();
@Nullable public abstract String name();
public abstract List<String> args();
@Nullable public abstract Config config();
@ -48,37 +49,52 @@ public abstract class Container {
@Nullable public abstract NetworkSettings networkSettings();
@Nullable public abstract String sysInitPath();
@Nullable public abstract String resolvConfPath();
public abstract Map<String, String> volumes();
@Nullable public abstract HostConfig hostConfig();
@Nullable public abstract String driver();
@Nullable public abstract String execDriver();
public abstract Map<String, String> volumes();
public abstract Map<String, Boolean> volumesRW();
@Nullable public abstract String command();
@Nullable public abstract String status();
@Nullable public abstract HostConfig hostConfig();
public abstract List<Port> ports();
@Nullable public abstract String hostnamePath();
@Nullable public abstract String hostsPath();
@Nullable public abstract String mountLabel();
@Nullable public abstract String processLabel();
Container() {
}
@SerializedNames(
{ "Id", "Name", "Created", "Path", "Args", "Config", "State", "Image", "NetworkSettings", "ResolvConfPath",
"Driver", "ExecDriver", "Volumes", "VolumesRW", "Command", "Status", "HostConfig", "Ports",
"HostnamePath" })
public static Container create(String id, String name, String created, String path, List<String> args, Config config,
State state, String image, NetworkSettings networkSettings, String resolvConfPath, String driver,
String execDriver, Map<String, String> volumes, Map<String, Boolean> volumesRW, String command, String status,
HostConfig hostConfig, List<Port> ports, String hostnamePath) {
return new AutoValue_Container(id, name, created, path, copyOf(args), config, state, image, networkSettings,
resolvConfPath, driver, execDriver, copyOf(volumes), copyOf(volumesRW), command, status, hostConfig,
copyOf(ports), hostnamePath);
{
"Id", "Created", "Path", "Name", "Args", "Config", "State", "Image", "NetworkSettings", "SysInitPath",
"ResolvConfPath", "Volumes", "HostConfig", "Driver", "ExecDriver", "VolumesRW", "Command", "Status",
"Ports", "HostnamePath", "HostsPath", "MountLabel", "ProcessLabel"
})
public static Container create(String id, Date created, String path, String name, List<String> args, Config config,
State state, String image, NetworkSettings networkSettings, String sysInitPath,
String resolvConfPath, Map<String, String> volumes, HostConfig hostConfig,
String driver, String execDriver, Map<String, Boolean> volumesRW, String command,
String status, List<Port> ports, String hostnamePath, String hostsPath,
String mountLabel, String processLabel) {
return new AutoValue_Container(id, created, path, name, copyOf(args), config, state, image, networkSettings,
sysInitPath, resolvConfPath, copyOf(volumes), hostConfig, driver, execDriver, copyOf(volumesRW), command,
status, copyOf(ports), hostnamePath, hostsPath, mountLabel, processLabel);
}
public static Builder builder() {
@ -92,36 +108,35 @@ public abstract class Container {
public static final class Builder {
private String id;
private String name;
private String created;
private Date created;
private String path;
private String name;
private List<String> args;
private Config config;
private State state;
private String image;
private NetworkSettings networkSettings;
private String sysInitPath;
private String resolvConfPath;
private Map<String, String> volumes = ImmutableMap.of();
private HostConfig hostConfig;
private String driver;
private String execDriver;
private Map<String, String> volumes = ImmutableMap.of();
private Map<String, Boolean> volumesRW = ImmutableMap.of();
private String command;
private String status;
private HostConfig hostConfig;
private List<Port> ports = ImmutableList.of();
private String hostnamePath;
private String hostsPath;
private String mountLabel;
private String processLabel;
public Builder id(String id) {
this.id = id;
return this;
}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder created(String created) {
public Builder created(Date created) {
this.created = created;
return this;
}
@ -131,6 +146,11 @@ public abstract class Container {
return this;
}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder args(List<String> args) {
this.args = args;
return this;
@ -156,11 +176,26 @@ public abstract class Container {
return this;
}
public Builder sysInitPath(String sysInitPath) {
this.sysInitPath = sysInitPath;
return this;
}
public Builder resolvConfPath(String resolvConfPath) {
this.resolvConfPath = resolvConfPath;
return this;
}
public Builder volumes(Map<String, String> volumes) {
this.volumes = volumes;
return this;
}
public Builder hostConfig(HostConfig hostConfig) {
this.hostConfig = hostConfig;
return this;
}
public Builder driver(String driver) {
this.driver = driver;
return this;
@ -171,11 +206,6 @@ public abstract class Container {
return this;
}
public Builder volumes(Map<String, String> volumes) {
this.volumes = volumes;
return this;
}
public Builder volumesRW(Map<String, Boolean> volumesRW) {
this.volumesRW = volumesRW;
return this;
@ -191,11 +221,6 @@ public abstract class Container {
return this;
}
public Builder hostConfig(HostConfig hostConfig) {
this.hostConfig = hostConfig;
return this;
}
public Builder ports(List<Port> ports) {
this.ports = ports;
return this;
@ -206,17 +231,34 @@ public abstract class Container {
return this;
}
public Builder hostsPath(String hostsPath) {
this.hostsPath = hostsPath;
return this;
}
public Builder mountLabel(String mountLabel) {
this.mountLabel = mountLabel;
return this;
}
public Builder processLabel(String processLabel) {
this.processLabel = processLabel;
return this;
}
public Container build() {
return Container.create(id, name, created, path, args, config, state, image, networkSettings, resolvConfPath,
driver, execDriver, volumes, volumesRW, command, status, hostConfig, ports, hostnamePath);
return Container.create(id, created, path, name, args, config, state, image, networkSettings,
sysInitPath, resolvConfPath, volumes, hostConfig, driver, execDriver, volumesRW, command, status,
ports, hostnamePath, hostsPath, mountLabel, processLabel);
}
public Builder fromContainer(Container in) {
return this.id(in.id()).name(in.name()).created(in.created()).path(in.path()).args(in.args())
.config(in.config()).state(in.state()).image(in.image()).networkSettings(in.networkSettings())
.resolvConfPath(in.resolvConfPath()).driver(in.driver()).execDriver(in.execDriver())
.volumes(in.volumes()).volumesRW(in.volumesRW()).command(in.command()).status(in.status())
.hostConfig(in.hostConfig()).ports(in.ports()).hostnamePath(in.hostnamePath());
.config(in.config()).state(in.state()).image(in.image()).networkSettings(in.networkSettings())
.sysInitPath(in.sysInitPath()).resolvConfPath(in.resolvConfPath()).driver(in.driver())
.execDriver(in.execDriver()).volumes(in.volumes()).hostConfig(in.hostConfig()).volumesRW(in.volumesRW())
.command(in.command()).status(in.status()).ports(in.ports()).hostnamePath(in.hostnamePath())
.hostsPath(in.hostsPath()).mountLabel(in.mountLabel()).processLabel(in.processLabel());
}
}
}

View File

@ -41,6 +41,9 @@ public abstract class ContainerSummary {
public abstract String status();
ContainerSummary() {
}
@SerializedNames({"Id", "Names", "Created", "Image", "Command", "Ports", "Status"})
public static ContainerSummary create(String id, List<String> names, String created, String image, String command, List<Port> ports, String status) {
return new AutoValue_ContainerSummary(id, copyOf(names), created, image, command, copyOf(ports), status);

View File

@ -30,6 +30,9 @@ public abstract class ExposedPorts {
public abstract List<String> hostPorts();
ExposedPorts() {
}
@SerializedNames({ "PortAndProtocol", "HostPorts" })
public static ExposedPorts create(String portAndProtocol, List<String> hostPorts) {
return new AutoValue_ExposedPorts(portAndProtocol, copyOf(hostPorts));

View File

@ -51,6 +51,9 @@ public abstract class HostConfig {
public abstract List<String> volumesFrom();
HostConfig() {
}
@SerializedNames({ "ContainerIDFile", "Binds", "LxcConf", "Privileged", "Dns", "DnsSearch", "PortBindings",
"Links", "PublishAllPorts", "VolumesFrom" })
public static HostConfig create(String containerIDFile, List<String> binds, List<Map<String, String>> lxcConf,

View File

@ -18,6 +18,7 @@ package org.jclouds.docker.domain;
import static org.jclouds.docker.internal.NullSafeCopies.copyOf;
import java.util.Date;
import java.util.List;
import org.jclouds.javax.annotation.Nullable;
@ -27,32 +28,43 @@ import com.google.auto.value.AutoValue;
@AutoValue
public abstract class Image {
public abstract String id();
@Nullable public abstract String parent();
@Nullable public abstract String author();
@Nullable public abstract String created();
@Nullable public abstract String comment();
@Nullable public abstract String container();
@Nullable public abstract Config config();
@Nullable public abstract String dockerVersion();
@Nullable public abstract Config containerConfig();
@Nullable public abstract String architecture();
public abstract String parent();
@Nullable public abstract String os();
public abstract Date created();
public abstract String container();
public abstract String dockerVersion();
public abstract String architecture();
public abstract String os();
public abstract long size();
@Nullable public abstract long virtualSize();
public abstract long virtualSize();
public abstract List<String> repoTags();
@Nullable public abstract List<String> repoTags();
@SerializedNames({ "Id", "Parent", "Created", "Container", "DockerVersion", "Architecture", "Os", "Size",
"VirtualSize", "RepoTags" })
public static Image create(String id, String parent, String created, String container, String dockerVersion,
String architecture, String os, long size, long virtualSize, List<String> repoTags) {
return new AutoValue_Image(id, parent, created, container, dockerVersion, architecture, os, size, virtualSize,
copyOf(repoTags));
Image() {
}
@SerializedNames({ "Id", "Author", "Comment", "Config", "ContainerConfig", "Parent", "Created",
"Container", "DockerVersion", "Architecture", "Os", "Size", "VirtualSize", "RepoTags" })
public static Image create(String id, String author, String comment, Config config, Config containerConfig, String parent, Date created, String container, String dockerVersion, String architecture, String os, long size, long virtualSize, List<String> repoTags) {
return new AutoValue_Image(id, author, comment, config, containerConfig, parent, created, container,
dockerVersion, architecture, os, size, virtualSize, copyOf(repoTags));
}
}

View File

@ -0,0 +1,51 @@
/*
* 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 static org.jclouds.docker.internal.NullSafeCopies.copyOf;
import java.util.List;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
// TODO it may be redundant (we already have Image value class)
@AutoValue
public abstract class ImageSummary {
public abstract String id();
public abstract long created();
public abstract String parentId();
public abstract int size();
public abstract int virtualSize();
public abstract List<String> repoTags();
ImageSummary() {
}
@SerializedNames({"Id", "Created", "ParentId", "Size", "VirtualSize", "RepoTags"})
public static ImageSummary create(String id, long created, String parentId, int size, int virtualSize,
List<String> repoTags) {
return new AutoValue_ImageSummary(id, created, parentId, size, virtualSize, copyOf(repoTags));
}
}

View File

@ -16,6 +16,8 @@
*/
package org.jclouds.docker.domain;
import java.util.List;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
@ -25,39 +27,52 @@ public abstract class Info {
public abstract int containers();
public abstract int images();
public abstract int debug();
public abstract String driver();
public abstract List<List<String>> driverStatus();
public abstract String executionDriver();
public abstract int iPv4Forwarding();
public abstract int images();
public abstract String indexServerAddress();
public abstract String initPath();
public abstract String initSha1();
public abstract String kernelVersion();
public abstract int debug();
public abstract int memoryLimit();
public abstract int nEventsListener();
public abstract int nFd();
public abstract int nGoroutines();
public abstract int nEventsListener();
public abstract String initPath();
public abstract String indexServerAddress();
public abstract int memoryLimit();
public abstract String operatingSystem();
public abstract int swapLimit();
public abstract int iPv4Forwarding();
Info() {
}
@SerializedNames(
{"Containers", "Images", "Driver", "ExecutionDriver", "KernelVersion", "Debug", "NFd", "NGoroutines",
"NEventsListener", "InitPath", "IndexServerAddress", "MemoryLimit", "SwapLimit", "IPv4Forwarding"})
public static Info create(int containers, int images, String driver, String executionDriver, String kernelVersion, int debug,
int nFd, int nGoroutines, int nEventsListener, String initPath, String indexServerAddress,
int memoryLimit, int swapLimit, int iPv4Forwarding) {
return new AutoValue_Info(containers, images, driver, executionDriver, kernelVersion, debug, nFd, nGoroutines,
nEventsListener, initPath, indexServerAddress, memoryLimit, swapLimit, iPv4Forwarding);
@SerializedNames({
"Containers", "Debug", "Driver", "DriverStatus", "ExecutionDriver", "IPv4Forwarding", "Images",
"IndexServerAddress", "InitPath", "InitSha1", "KernelVersion", "MemoryLimit", "NEventsListener",
"NFd", "NGoroutines", "OperatingSystem", "SwapLimit"
})
public static Info create(int containers, int debug, String driver, List<List<String>> driverStatus,
String executionDriver, int iPv4Forwarding, int images, String indexServerAddress,
String initPath, String initSha1, String kernelVersion, int memoryLimit,
int nEventsListener, int nFd, int nGoroutines, String operatingSystem, int swapLimit) {
return new AutoValue_Info(containers, debug, driver, driverStatus, executionDriver, iPv4Forwarding, images,
indexServerAddress, initPath, initSha1, kernelVersion, memoryLimit, nEventsListener, nFd, nGoroutines,
operatingSystem, swapLimit);
}
}

View File

@ -42,6 +42,9 @@ public abstract class NetworkSettings {
public abstract Map<String, List<Map<String, String>>> ports();
NetworkSettings() {
}
@SerializedNames({ "IPAddress", "IPPrefixLen", "Gateway", "Bridge", "PortMapping", "Ports" })
public static NetworkSettings create(String ipAddress, int ipPrefixLen, String gateway, String bridge,
String portMapping, Map<String, List<Map<String, String>>> ports) {

View File

@ -30,6 +30,9 @@ public abstract class Port {
public abstract String type();
Port() {
}
@SerializedNames({ "IP", "PrivatePort", "PublicPort", "Type" })
public static Port create(String ip, int privatePort, int publicPort, String type) {
return new AutoValue_Port(ip, privatePort, publicPort, type);

View File

@ -14,13 +14,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.config;
package org.jclouds.docker.domain;
public class DockerProperties {
import org.jclouds.json.SerializedNames;
/**
* default Docker host password
*/
public static final String HOST_PASSWORD = "jclouds.docker.host.password";
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class Resource {
public abstract String resource();
Resource() {
}
@SerializedNames({ "Resource" })
public static Resource create(String resource) {
return new AutoValue_Resource(resource);
}
}

View File

@ -32,11 +32,16 @@ public abstract class State {
public abstract String finishedAt();
public abstract boolean ghost();
public abstract boolean paused();
@SerializedNames({ "Pid", "Running", "ExitCode", "StartedAt", "FinishedAt", "Ghost" })
public abstract boolean restarting();
State() {
}
@SerializedNames({ "Pid", "Running", "ExitCode", "StartedAt", "FinishedAt", "Paused", "Restarting" })
public static State create(int pid, boolean running, int exitCode, String startedAt, String finishedAt,
boolean ghost) {
return new AutoValue_State(pid, running, exitCode, startedAt, finishedAt, ghost);
boolean paused, boolean restarting) {
return new AutoValue_State(pid, running, exitCode, startedAt, finishedAt, paused, restarting);
}
}

View File

@ -0,0 +1,35 @@
/*
* 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 org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class StatusCode {
public abstract int statusCode();
StatusCode() {
}
@SerializedNames({ "StatusCode" })
public static StatusCode create(int statusCode) {
return new AutoValue_StatusCode(statusCode);
}
}

View File

@ -37,6 +37,9 @@ public abstract class Version {
public abstract String version();
Version() {
}
@SerializedNames({ "ApiVersion", "Arch", "GitCommit", "GoVersion", "KernelVersion", "Os", "Version" })
public static Version create(String apiVersion, String arch, String gitCommit, String goVersion,
String kernelVersion, String os, String version) {

View File

@ -16,6 +16,7 @@
*/
package org.jclouds.docker.features;
import java.io.InputStream;
import java.util.List;
import javax.inject.Named;
@ -28,12 +29,16 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.Fallbacks;
import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.docker.domain.Config;
import org.jclouds.docker.domain.Container;
import org.jclouds.docker.domain.ContainerSummary;
import org.jclouds.docker.domain.HostConfig;
import org.jclouds.docker.domain.Image;
import org.jclouds.docker.domain.Resource;
import org.jclouds.docker.domain.StatusCode;
import org.jclouds.docker.options.AttachOptions;
import org.jclouds.docker.options.CommitOptions;
import org.jclouds.docker.options.ListContainerOptions;
import org.jclouds.docker.options.RemoveContainerOptions;
@ -42,34 +47,29 @@ import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.binders.BindToJsonPayload;
@Consumes(MediaType.APPLICATION_JSON)
@Path("/v{jclouds.api-version}")
public interface ContainerApi {
/**
* List all running containers
*
* @return a set of containers
*/
@Named("containers:list")
@GET
@Path("/containers/json")
@Fallback(Fallbacks.EmptyListOnNotFoundOr404.class)
@Fallback(EmptyListOnNotFoundOr404.class)
List<ContainerSummary> listContainers();
/**
* List all running containers
*
* @param options the options to list the containers (@see ListContainerOptions)
* @return a set of containers
*/
@Named("containers:list")
@GET
@Path("/containers/json")
@Fallback(Fallbacks.EmptyListOnNotFoundOr404.class)
@Fallback(EmptyListOnNotFoundOr404.class)
List<ContainerSummary> listContainers(ListContainerOptions options);
/**
* Create a container
*
* @param name the name for the new container. Must match /?[a-zA-Z0-9_-]+.
* @param config the containers configuration (@see BindToJsonPayload)
* @return a new container
@ -87,12 +87,10 @@ public interface ContainerApi {
@Named("container:inspect")
@GET
@Path("/containers/{id}/json")
@Fallback(Fallbacks.NullOnNotFoundOr404.class)
@Fallback(NullOnNotFoundOr404.class)
Container inspectContainer(@PathParam("id") String containerId);
/**
* Remove the container by id from the filesystem
*
* @param containerId The id of the container to be removed.
*/
@Named("container:delete")
@ -101,8 +99,6 @@ public interface ContainerApi {
void removeContainer(@PathParam("id") String containerId);
/**
* Remove the container by id from the filesystem
*
* @param containerId The id of the container to be removed.
* @param options the operations configuration (@see RemoveContainerOptions)
*/
@ -112,8 +108,6 @@ public interface ContainerApi {
void removeContainer(@PathParam("id") String containerId, RemoveContainerOptions options);
/**
* Start a container by id.
*
* @param containerId The id of the container to be started.
*/
@Named("container:start")
@ -122,8 +116,6 @@ public interface ContainerApi {
void startContainer(@PathParam("id") String containerId);
/**
* Start a container.
*
* @param containerId The id of the container to be started.
* @param hostConfig the containers host configuration
*/
@ -133,16 +125,28 @@ public interface ContainerApi {
void startContainer(@PathParam("id") String containerId, @BinderParam(BindToJsonPayload.class) HostConfig hostConfig);
/**
* Stop a container by id.
*
* @param containerId The id of the container to be stopped.
* @return the stream of the stop execution.
*/
@Named("container:stop")
@POST
@Path("/containers/{id}/stop")
void stopContainer(@PathParam("id") String containerId);
@Named("container:stop")
@POST
@Path("/containers/{id}/stop")
void stopContainer(@PathParam("id") String containerId, @QueryParam("t") int secondsToWait);
/**
* Create a new image from a containers changes
*
* @return a new image created from the current container's status.
*/
@Named("container:commit")
@POST
@Path("/commit")
Image commit();
/**
* Create a new image from a containers changes
*
@ -154,4 +158,95 @@ public interface ContainerApi {
@Path("/commit")
Image commit(CommitOptions options);
/**
* @param containerId The id of the container to be paused.
*/
@Named("container:pause")
@POST
@Path("/containers/{id}/pause")
void pause(@PathParam("id") String containerId);
/**
* @param containerId The id of the container to be unpaused.
*/
@Named("container:unpause")
@POST
@Path("/containers/{id}/unpause")
void unpause(@PathParam("id") String containerId);
/**
* @param containerId The id of the container to be attached.
*/
@Named("container:attach")
@POST
@Path("/containers/{id}/attach")
InputStream attach(@PathParam("id") String containerId);
/**
* @param containerId The id of the container to be attached.
* @param options the attach options @see org.jclouds.docker.options.AttachOptions
*
*/
@Named("container:attach")
@POST
@Path("/containers/{id}/attach")
InputStream attach(@PathParam("id") String containerId, AttachOptions options);
/**
* Block until container @param containerId stops, then returns the exit code
*/
@Named("container:wait")
@POST
@Path("/containers/{id}/wait")
StatusCode wait(@PathParam("id") String containerId);
/**
* @param containerId restarts
*/
@Named("container:restart")
@POST
@Path("/containers/{id}/restart")
void restart(@PathParam("id") String containerId);
@Named("container:restart")
@POST
@Path("/containers/{id}/restart")
void restart(@PathParam("id") String containerId, @QueryParam("t") int secondsToWait);
/**
* @param containerId to be killed
*/
@Named("container:kill")
@POST
@Path("/containers/{id}/kill")
void kill(@PathParam("id") String containerId);
/**
* @param containerId to be killed
* @param signal Signal to send to the container. When not set, SIGKILL is assumed and the call will waits for the
* container to exit.
*/
@Named("container:kill")
@POST
@Path("/containers/{id}/kill")
void kill(@PathParam("id") String containerId, @QueryParam("signal") int signal);
/**
* @param containerId to be killed
* @param signal Signal string like "SIGINT" to send to the container. When not set, SIGKILL is assumed and the call will waits for
* the container to exit.
*/
@Named("container:kill")
@POST
@Path("/containers/{id}/kill")
void kill(@PathParam("id") String containerId, @QueryParam("signal") String signal);
/**
* @param containerId id of the container to copy files from
*/
@Named("container:copy")
@POST
@Path("/containers/{id}/copy")
InputStream copy(@PathParam("id") String containerId, @BinderParam(BindToJsonPayload.class) Resource resource);
}

View File

@ -28,49 +28,48 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.Fallbacks;
import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.docker.domain.Image;
import org.jclouds.docker.domain.ImageSummary;
import org.jclouds.docker.options.CreateImageOptions;
import org.jclouds.docker.options.DeleteImageOptions;
import org.jclouds.docker.options.ListImageOptions;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.rest.annotations.Fallback;
@Consumes(MediaType.APPLICATION_JSON)
@Path("/v{jclouds.api-version}")
public interface ImageApi {
/**
* List images
*
* @return the images available.
*/
@Named("images:list")
@GET
@Path("/images/json")
@Fallback(Fallbacks.EmptyListOnNotFoundOr404.class)
List<Image> listImages();
@Fallback(EmptyListOnNotFoundOr404.class)
List<ImageSummary> listImages();
/**
* List images
*
* @param options the configuration to list images (@see ListImageOptions)
* @return the images available.
*/
@Named("images:list")
@GET
@Path("/images/json")
@Fallback(Fallbacks.EmptyListOnNotFoundOr404.class)
List<Image> listImages(ListImageOptions options);
@Fallback(EmptyListOnNotFoundOr404.class)
List<ImageSummary> listImages(ListImageOptions options);
/**
* Inspect an image
*
* @param imageName The id of the image to inspect.
* @return low-level information on the image name
*/
@Named("image:inspect")
@GET
@Path("/images/{name}/json")
@Fallback(Fallbacks.VoidOnNotFoundOr404.class)
@Fallback(NullOnNotFoundOr404.class)
@Nullable
Image inspectImage(@PathParam("name") String imageName);
/**
@ -85,8 +84,6 @@ public interface ImageApi {
InputStream createImage(CreateImageOptions options);
/**
* Delete an image.
*
* @param name the image name to be deleted
* @return the stream of the deletion execution.
*/
@ -96,8 +93,6 @@ public interface ImageApi {
InputStream deleteImage(@PathParam("name") String name);
/**
* Remove the image from the filesystem by name
*
* @param name the name of the image to be removed
* @param options the image deletion's options (@see DeleteImageOptions)
* @return the stream of the deletion execution.

View File

@ -32,6 +32,7 @@ import org.jclouds.io.Payload;
import org.jclouds.rest.annotations.Headers;
@Consumes(MediaType.APPLICATION_JSON)
@Path("/v{jclouds.api-version}")
public interface MiscApi {
/**
@ -54,6 +55,18 @@ public interface MiscApi {
@Path("/info")
Info getInfo();
/**
* Build an image from Dockerfile via stdin
*
* @param inputStream The stream must be a tar archive compressed with one of the following algorithms: identity
* (no compression), gzip, bzip2, xz.
* @return a stream of the build execution
*/
@Named("image:build")
@POST
@Path("/build")
@Headers(keys = "Content-Type", values = "application/tar")
InputStream build(Payload inputStream);
/**
* Build an image from Dockerfile via stdin

View File

@ -0,0 +1,114 @@
/*
* 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.options;
import org.jclouds.http.options.BaseHttpRequestOptions;
public class AttachOptions extends BaseHttpRequestOptions {
/**
* @param stream When TTY is enabled, the stream is the raw data from the process PTY and client's stdin.
* When TTY is disabled, the stream is multiplexed to separate stdout and stderr.
* @return AttachOptions
*/
public AttachOptions stream(Boolean stream) {
this.queryParameters.put("stream", stream.toString());
return this;
}
/**
* @param logs require logs to be attached. Default false.
* @return AttachOptions
*/
public AttachOptions logs(Boolean logs) {
this.queryParameters.put("logs", logs.toString());
return this;
}
/**
* @param stdin if stream=true, attach to stdin. Default false
* @return AttachOptions
*/
public AttachOptions stdin(Boolean stdin) {
this.queryParameters.put("stdin", stdin.toString());
return this;
}
/**
* @param stdout if logs=true, return stdout log, if stream=true, attach to stdout. Default false
* @return
*/
public AttachOptions stdout(Boolean stdout) {
this.queryParameters.put("stdout", stdout.toString());
return this;
}
/**
*
* @param stderr if logs=true, return stderr log, if stream=true, attach to stderr. Default false
* @return
*/
public AttachOptions stderr(Boolean stderr) {
this.queryParameters.put("stderr", stderr.toString());
return this;
}
public static class Builder {
/**
* @see org.jclouds.docker.options.AttachOptions#stream
*/
public static AttachOptions stream(Boolean stream) {
AttachOptions options = new AttachOptions();
return options.stream(stream);
}
/**
* @see org.jclouds.docker.options.AttachOptions#logs(Boolean)
*/
public static AttachOptions logs(Boolean logs) {
AttachOptions options = new AttachOptions();
return options.logs(logs);
}
/**
* @see org.jclouds.docker.options.AttachOptions#stdin(Boolean)
*/
public static AttachOptions stdin(Boolean stdin) {
AttachOptions options = new AttachOptions();
return options.stdin(stdin);
}
/**
* @see org.jclouds.docker.options.AttachOptions#stdout(Boolean)
*/
public static AttachOptions stdout(Boolean stdout) {
AttachOptions options = new AttachOptions();
return options.stdout(stdout);
}
/**
* @see org.jclouds.docker.options.AttachOptions#stderr(Boolean)
*/
public static AttachOptions stderr(Boolean stderr) {
AttachOptions options = new AttachOptions();
return options.stderr(stderr);
}
}
}

View File

@ -18,13 +18,8 @@ package org.jclouds.docker.options;
import org.jclouds.http.options.BaseHttpRequestOptions;
/**
* Options to customize image builder.
*/
public class BuildOptions extends BaseHttpRequestOptions {
public static final BuildOptions NONE = new BuildOptions();
public BuildOptions tag(String tag) {
this.queryParameters.put("tag", tag);
return this;

View File

@ -18,13 +18,8 @@ package org.jclouds.docker.options;
import org.jclouds.http.options.BaseHttpRequestOptions;
/**
* Options to customize image commit.
*/
public class CommitOptions extends BaseHttpRequestOptions {
public static final CommitOptions NONE = new CommitOptions();
public CommitOptions containerId(String containerId) {
this.queryParameters.put("containerId", containerId);
return this;

View File

@ -18,13 +18,8 @@ package org.jclouds.docker.options;
import org.jclouds.http.options.BaseHttpRequestOptions;
/**
* Options to customize container creation.
*/
public class CreateImageOptions extends BaseHttpRequestOptions {
public static final CreateImageOptions NONE = new CreateImageOptions();
public CreateImageOptions fromImage(String fromImage) {
this.queryParameters.put("fromImage", fromImage);
return this;

View File

@ -18,18 +18,18 @@ package org.jclouds.docker.options;
import org.jclouds.http.options.BaseHttpRequestOptions;
/**
* Options to customize image deletion.
*/
public class DeleteImageOptions extends BaseHttpRequestOptions {
public static final DeleteImageOptions NONE = new DeleteImageOptions();
public DeleteImageOptions force(Boolean force) {
this.queryParameters.put("force", force.toString());
return this;
}
public DeleteImageOptions noPrune(Boolean noPrune) {
this.queryParameters.put("noPrune", noPrune.toString());
return this;
}
public static class Builder {
/**
@ -39,6 +39,14 @@ public class DeleteImageOptions extends BaseHttpRequestOptions {
DeleteImageOptions options = new DeleteImageOptions();
return options.force(force);
}
/**
* @see DeleteImageOptions#noPrune
*/
public static DeleteImageOptions noPrune(Boolean noPrune) {
DeleteImageOptions options = new DeleteImageOptions();
return options.noPrune(noPrune);
}
}
}

View File

@ -18,13 +18,8 @@ package org.jclouds.docker.options;
import org.jclouds.http.options.BaseHttpRequestOptions;
/**
* Options to customize container's listing.
*/
public class ListContainerOptions extends BaseHttpRequestOptions {
public static final ListContainerOptions NONE = new ListContainerOptions();
public ListContainerOptions all(Boolean all) {
this.queryParameters.put("all", all.toString());
return this;

View File

@ -18,13 +18,8 @@ package org.jclouds.docker.options;
import org.jclouds.http.options.BaseHttpRequestOptions;
/**
* Options to customize image's listing.
*/
public class ListImageOptions extends BaseHttpRequestOptions {
public static final ListImageOptions NONE = new ListImageOptions();
public ListImageOptions all(Boolean all) {
this.queryParameters.put("all", all.toString());
return this;

View File

@ -18,13 +18,8 @@ package org.jclouds.docker.options;
import org.jclouds.http.options.BaseHttpRequestOptions;
/**
* Options to customize container removal.
*/
public class RemoveContainerOptions extends BaseHttpRequestOptions {
public static final RemoveContainerOptions NONE = new RemoveContainerOptions();
public RemoveContainerOptions verbose(Boolean verbose) {
this.queryParameters.put("verbose", verbose.toString());
return this;

View File

@ -1,130 +0,0 @@
/*
* 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.suppliers;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Throwables.propagate;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Collection;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.crypto.Crypto;
import org.jclouds.crypto.Pems;
import org.jclouds.domain.Credentials;
import org.jclouds.location.Provider;
import org.jclouds.rest.AuthorizationException;
import com.google.common.base.Charsets;
import com.google.common.base.Supplier;
import com.google.common.io.ByteSource;
@Singleton
public class KeyStoreSupplier implements Supplier<KeyStore> {
private final Crypto crypto;
private final Supplier<Credentials> creds;
@Inject
KeyStoreSupplier(Crypto crypto, @Provider Supplier<Credentials> creds) {
this.crypto = crypto;
this.creds = creds;
}
@Override
public KeyStore get() {
Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null");
String cert = checkNotNull(currentCreds.identity, "credential supplier returned null identity (should be cert)");
String keyStorePassword = checkNotNull(currentCreds.credential,
"credential supplier returned null credential (should be keyStorePassword)");
try {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
File certFile = new File(checkNotNull(cert));
if (certFile.isFile()) { // cert is path to pkcs12 file
FileInputStream stream = new FileInputStream(certFile);
try {
keyStore.load(stream, keyStorePassword.toCharArray());
} finally {
stream.close();
}
} else { // cert is PEM encoded, containing private key and certs
// split in private key and certs
int privateKeyBeginIdx = cert.indexOf("-----BEGIN PRIVATE KEY");
int privateKeyEndIdx = cert.indexOf("-----END PRIVATE KEY");
if (privateKeyBeginIdx != -1) {
String pemPrivateKey = cert.substring(privateKeyBeginIdx, privateKeyEndIdx + 26);
StringBuilder pemCerts = new StringBuilder();
int certsBeginIdx = 0;
do {
certsBeginIdx = cert.indexOf("-----BEGIN CERTIFICATE", certsBeginIdx);
if (certsBeginIdx >= 0) {
int certsEndIdx = cert.indexOf("-----END CERTIFICATE", certsBeginIdx) + 26;
pemCerts.append(cert.substring(certsBeginIdx, certsEndIdx));
certsBeginIdx = certsEndIdx;
}
} while (certsBeginIdx != -1);
// parse private key
KeySpec keySpec = Pems.privateKeySpec(ByteSource.wrap(pemPrivateKey.getBytes(Charsets.UTF_8)));
PrivateKey privateKey = crypto.rsaKeyFactory().generatePrivate(keySpec);
// populate keystore with private key and certs
CertificateFactory cf = CertificateFactory.getInstance("X.509");
@SuppressWarnings("unchecked")
Collection<Certificate> certs = (Collection<Certificate>) cf.generateCertificates(new ByteArrayInputStream(
pemCerts.toString().getBytes(Charsets.UTF_8)));
keyStore.load(null);
keyStore.setKeyEntry("dummy", privateKey, keyStorePassword.toCharArray(),
certs.toArray(new Certificate[0]));
} else {
throw new AuthorizationException();
}
}
return keyStore;
} catch (NoSuchAlgorithmException e) {
throw propagate(e);
} catch (KeyStoreException e) {
throw propagate(e);
} catch (CertificateException e) {
throw propagate(e);
} catch (FileNotFoundException e) {
throw propagate(e);
} catch (IOException e) {
throw propagate(e);
} catch (InvalidKeySpecException e) {
throw propagate(e);
}
}
}

View File

@ -18,60 +18,146 @@ package org.jclouds.docker.suppliers;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Throwables.propagate;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedKeyManager;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.config.SSLModule.TrustAllCerts;
import org.jclouds.location.Provider;
import com.google.common.base.Charsets;
import com.google.common.base.Supplier;
import com.google.common.io.Files;
@Singleton
public class SSLContextWithKeysSupplier implements Supplier<SSLContext> {
private final Supplier<KeyStore> keyStore;
private final TrustManager[] trustManager;
private final Supplier<Credentials> creds;
@Inject
SSLContextWithKeysSupplier(Supplier<KeyStore> keyStore, @Provider Supplier<Credentials> creds, HttpUtils utils,
TrustAllCerts trustAllCerts) {
this.keyStore = keyStore;
this.trustManager = utils.trustAllCerts() ? new TrustManager[] { trustAllCerts } : null;
SSLContextWithKeysSupplier(@Provider Supplier<Credentials> creds, HttpUtils utils, TrustAllCerts trustAllCerts) {
this.trustManager = utils.trustAllCerts() ? new TrustManager[]{trustAllCerts} : null;
this.creds = creds;
}
@Override
public SSLContext get() {
Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null");
String keyStorePassword = checkNotNull(currentCreds.credential,
"credential supplier returned null credential (should be keyStorePassword)");
KeyManagerFactory kmf;
try {
kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keyStore.get(), keyStorePassword.toCharArray());
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), trustManager, new SecureRandom());
return sc;
SSLContext sslContext = SSLContext.getInstance("TLS");
X509Certificate certificate = getCertificate(loadFile(currentCreds.identity));
PrivateKey privateKey = getKey(loadFile(currentCreds.credential));
sslContext.init(new KeyManager[]{new InMemoryKeyManager(certificate, privateKey)}, trustManager, new SecureRandom());
return sslContext;
} catch (NoSuchAlgorithmException e) {
throw propagate(e);
} catch (UnrecoverableKeyException e) {
throw propagate(e);
} catch (KeyStoreException e) {
throw propagate(e);
} catch (KeyManagementException e) {
throw propagate(e);
} catch (CertificateException e) {
throw propagate(e);
} catch (IOException e) {
throw propagate(e);
}
}
private static X509Certificate getCertificate(String certificate) {
try {
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(
new ByteArrayInputStream(certificate.getBytes(Charsets.UTF_8)));
} catch (CertificateException ex) {
throw new RuntimeException("Invalid certificate", ex);
}
}
private static PrivateKey getKey(String privateKey) {
try {
PEMParser pemParser = new PEMParser(new StringReader(privateKey));
Object object = pemParser.readObject();
if (Security.getProvider("BC") == null) {
Security.addProvider(new BouncyCastleProvider());
}
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
KeyPair keyPair = converter.getKeyPair((PEMKeyPair) object);
return keyPair.getPrivate();
} catch (IOException ex) {
throw new RuntimeException("Invalid private key", ex);
}
}
private static String loadFile(final String filePath) throws IOException {
return Files.toString(new File(filePath), Charsets.UTF_8);
}
private static class InMemoryKeyManager extends X509ExtendedKeyManager {
private static final String DEFAULT_ALIAS = "docker";
private final X509Certificate certificate;
private final PrivateKey privateKey;
public InMemoryKeyManager(final X509Certificate certificate, final PrivateKey privateKey)
throws IOException, CertificateException {
this.certificate = certificate;
this.privateKey = privateKey;
}
@Override
public String chooseClientAlias(final String[] keyType, final Principal[] issuers,
final Socket socket) {
return DEFAULT_ALIAS;
}
@Override
public String chooseServerAlias(final String keyType, final Principal[] issuers,
final Socket socket) {
return DEFAULT_ALIAS;
}
@Override
public X509Certificate[] getCertificateChain(final String alias) {
return new X509Certificate[]{certificate};
}
@Override
public String[] getClientAliases(final String keyType, final Principal[] issuers) {
return new String[]{DEFAULT_ALIAS};
}
@Override
public PrivateKey getPrivateKey(final String alias) {
return privateKey;
}
@Override
public String[] getServerAliases(final String keyType, final Principal[] issuers) {
return new String[]{DEFAULT_ALIAS};
}
}
}

View File

@ -29,7 +29,6 @@ import org.jboss.shrinkwrap.api.GenericArchive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.ClassLoaderAsset;
import org.jboss.shrinkwrap.api.exporter.TarExporter;
import org.jclouds.Constants;
import org.jclouds.apis.BaseApiLiveTest;
import org.jclouds.compute.config.ComputeServiceProperties;
import org.jclouds.docker.DockerApi;
@ -57,8 +56,7 @@ public class BaseDockerApiLiveTest extends BaseApiLiveTest<DockerApi> {
@Override
protected Properties setupProperties() {
Properties overrides = super.setupProperties();
overrides.setProperty(Constants.PROPERTY_MAX_RETRIES, "15");
overrides.setProperty("jclouds.ssh.retry-auth", "true");
overrides.setProperty("jclouds.trust-all-certs", "false");
overrides.setProperty(ComputeServiceProperties.IMAGE_LOGIN_USER, "root:password");
return overrides;
}

View File

@ -116,10 +116,4 @@ public class DockerComputeServiceAdapterLiveTest extends BaseDockerApiLiveTest {
return ImmutableSet.<Module>of(getLoggingModule(), new SshjSshClientModule());
}
@Override
protected Properties setupProperties() {
Properties properties = super.setupProperties();
properties.setProperty("jclouds.ssh.max-retries", "10");
return properties;
}
}

View File

@ -34,6 +34,7 @@ import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.OperatingSystem;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.functions.GroupNamingConvention;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.docker.domain.Config;
import org.jclouds.docker.domain.Container;
import org.jclouds.docker.domain.HostConfig;
@ -97,12 +98,13 @@ public class ContainerToNodeMetadataTest {
0, // exitCode
"2014-03-24T20:28:37.537659054Z", // startedAt
"0001-01-01T00:00:00Z", // finishedAt
false // ghost
false, // paused
false // restarting
);
container = Container.builder()
.id("6d35806c1bd2b25cd92bba2d2c2c5169dc2156f53ab45c2b62d76e2d2fee14a9")
.name("/hopeful_mclean")
.created("2014-03-22T07:16:45.784120972Z")
.created(new SimpleDateFormatDateService().iso8601DateParse("2014-03-22T07:16:45.784120972Z"))
.path("/usr/sbin/sshd")
.args(Arrays.asList("-D"))
.config(containerConfig)

View File

@ -21,8 +21,11 @@ import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.testng.Assert.assertEquals;
import java.util.Date;
import org.easymock.EasyMock;
import org.jclouds.compute.domain.Image;
import org.jclouds.docker.domain.Config;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@ -41,16 +44,24 @@ public class ImageToImageTest {
@BeforeMethod
public void setup() {
image = org.jclouds.docker.domain.Image.create(
"id", // id
"parent", // parent
"created", // created
null, // container
null, // dockerVersion
"x86_64", // architecture
null, // os
0l, // size
0l, // virtualSize
ImmutableList.of("repoTag1:version") // repoTags
"id", // id
"author",
"comment",
Config.builder()
.image("imageId")
.build(),
Config.builder()
.image("imageId")
.build(),
"parent", // parent
new Date(), // created
"containerId", // container
"1.3.1", // dockerVersion
"x86_64", // architecture
"os", // os
0l, // size
0l, // virtualSize
ImmutableList.of("repoTag1:version") // repoTags
);
function = new ImageToImage();
}

View File

@ -16,8 +16,11 @@
*/
package org.jclouds.docker.features;
import static org.assertj.core.api.Assertions.assertThat;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.io.IOException;
@ -29,8 +32,11 @@ import org.jclouds.docker.domain.Config;
import org.jclouds.docker.domain.Container;
import org.jclouds.docker.domain.ContainerSummary;
import org.jclouds.docker.domain.Image;
import org.jclouds.docker.domain.Resource;
import org.jclouds.docker.options.AttachOptions;
import org.jclouds.docker.options.CreateImageOptions;
import org.jclouds.docker.options.ListContainerOptions;
import org.jclouds.docker.options.RemoveContainerOptions;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@ -57,6 +63,11 @@ public class ContainerApiLiveTest extends BaseDockerApiLiveTest {
@AfterClass
protected void tearDown() {
if (container != null) {
if (api.getContainerApi().inspectContainer(container.id()) != null) {
api.getContainerApi().removeContainer(container.id(), RemoveContainerOptions.Builder.force(true));
}
}
if (image != null) {
api.getImageApi().deleteImage(BUSYBOX_IMAGE_TAG);
}
@ -64,7 +75,7 @@ public class ContainerApiLiveTest extends BaseDockerApiLiveTest {
public void testCreateContainer() throws IOException, InterruptedException {
Config containerConfig = Config.builder().image(image.id())
.cmd(ImmutableList.of("/bin/sh", "-c", "while true; do echo hello world; sleep 1; done"))
.cmd(ImmutableList.of("/bin/sh", "-c", "touch hello; while true; do echo hello world; sleep 1; done"))
.build();
container = api().createContainer("testCreateContainer", containerConfig);
assertNotNull(container);
@ -78,11 +89,54 @@ public class ContainerApiLiveTest extends BaseDockerApiLiveTest {
}
@Test(dependsOnMethods = "testStartContainer")
public void testAttachContainer() {
InputStream attachStream = api().attach(container.id(), AttachOptions.Builder.logs(true).stream(false).stdout(true));
String stream = consumeStream(attachStream);
assertThat(stream.trim()).contains("hello world");
}
@Test(dependsOnMethods = "testAttachContainer")
public void testCopyFileFromContainer() {
InputStream tarredStream = api().copy(container.id(), Resource.create("hello"));
assertNotNull(consumeStream(tarredStream));
}
@Test(dependsOnMethods = "testCopyFileFromContainer")
public void testPauseContainer() {
api().pause(container.id());
assertTrue(api().inspectContainer(container.id()).state().paused());
}
@Test(dependsOnMethods = "testPauseContainer")
public void testUnpauseContainer() {
api().unpause(container.id());
assertFalse(api().inspectContainer(container.id()).state().paused());
}
@Test(dependsOnMethods = "testUnpauseContainer")
public void testStopContainer() {
api().stopContainer(container.id());
assertFalse(api().inspectContainer(container.id()).state().running());
}
@Test(dependsOnMethods = "testStopContainer")
public void testRestartContainer() {
api().restart(container.id());
assertTrue(api().inspectContainer(container.id()).state().running());
}
@Test(dependsOnMethods = "testRestartContainer")
public void testWaitContainer() {
api().stopContainer(container.id(), 1);
assertEquals(api().wait(container.id()).statusCode(), -1);
}
@Test(dependsOnMethods = "testWaitContainer")
public void testRemoveContainer() {
api().removeContainer(container.id());
assertNull(api().inspectContainer(container.id()));
}
@Test
public void testListContainers() {
List<ContainerSummary> containerSummaries = api().listContainers(ListContainerOptions.Builder.all(true));
@ -93,12 +147,6 @@ public class ContainerApiLiveTest extends BaseDockerApiLiveTest {
}
}
@Test(dependsOnMethods = "testStopContainer", expectedExceptions = NullPointerException.class)
public void testRemoveContainer() {
api().removeContainer(container.id());
assertFalse(api().inspectContainer(container.id()).state().running());
}
private ContainerApi api() {
return api.getContainerApi();
}

View File

@ -16,23 +16,22 @@
*/
package org.jclouds.docker.features;
import static org.assertj.core.api.Assertions.assertThat;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.util.List;
import org.jclouds.docker.DockerApi;
import org.jclouds.docker.config.DockerParserModule;
import org.jclouds.docker.domain.Config;
import org.jclouds.docker.domain.Container;
import org.jclouds.docker.domain.ContainerSummary;
import org.jclouds.docker.domain.Resource;
import org.jclouds.docker.internal.BaseDockerMockTest;
import org.jclouds.docker.options.ListContainerOptions;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.docker.parse.ContainerParseTest;
import org.jclouds.docker.parse.ContainersParseTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import com.squareup.okhttp.mockwebserver.MockResponse;
import com.squareup.okhttp.mockwebserver.MockWebServer;
@ -43,96 +42,56 @@ import com.squareup.okhttp.mockwebserver.MockWebServer;
public class ContainerApiMockTest extends BaseDockerMockTest {
public void testListContainers() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setBody(payloadFromResource("/containers.json")));
DockerApi dockerApi = api(server.getUrl("/"));
ContainerApi api = dockerApi.getContainerApi();
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/containers.json")));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
List<ContainerSummary> containerSummaries = api.listContainers();
assertRequestHasCommonFields(server.takeRequest(), "/containers/json");
assertEquals(containerSummaries.size(), 1);
assertEquals(api.listContainers(), new ContainersParseTest().expected());
assertSent(server, "GET", "/containers/json");
} finally {
dockerApi.close();
server.shutdown();
}
}
public void testListNonexistentContainers() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setResponseCode(404));
DockerApi dockerApi = api(server.getUrl("/"));
ContainerApi api = dockerApi.getContainerApi();
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(404));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
List<ContainerSummary> containerSummaries = api.listContainers();
assertRequestHasCommonFields(server.takeRequest(), "/containers/json");
assertTrue(containerSummaries.isEmpty());
assertEquals(api.listContainers(), ImmutableList.of());
assertSent(server, "GET", "/containers/json");
} finally {
dockerApi.close();
server.shutdown();
}
}
@Test(timeOut = 10000l)
public void testListAllContainers() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setBody(payloadFromResource("/containers.json")));
DockerApi dockerApi = api(server.getUrl("/"));
ContainerApi api = dockerApi.getContainerApi();
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/containers.json")));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
List<ContainerSummary> containerSummaries = api.listContainers(ListContainerOptions.Builder.all(true));
assertRequestHasParameters(server.takeRequest(), "/containers/json", ImmutableMultimap.of("all", "true"));
assertEquals(containerSummaries.size(), 1);
assertEquals(api.listContainers(ListContainerOptions.Builder.all(true)), new ContainersParseTest().expected());
assertSent(server, "GET", "/containers/json?all=true");
} finally {
dockerApi.close();
server.shutdown();
}
}
public void testGetContainer() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setBody(payloadFromResource("/container.json")));
DockerApi dockerApi = api(server.getUrl("/"));
ContainerApi api = dockerApi.getContainerApi();
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/container.json")));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString(), new DockerParserModule()).getContainerApi();
String containerId = "b03d4cd15b76f8876110615cdeed15eadf77c9beb408d62f1687dcc69192cd6d";
try {
Container container = api.inspectContainer(containerId);
assertRequestHasCommonFields(server.takeRequest(), "/containers/" + containerId + "/json");
assertNotNull(container);
assertNotNull(container.id(), containerId);
assertNotNull(container.config());
assertNotNull(container.hostConfig());
assertTrue(container.name().contains("/weave"));
assertEquals(container.state().running(), true);
assertEquals(api.inspectContainer(containerId), new ContainerParseTest().expected());
assertSent(server, "GET", "/containers/" + containerId + "/json");
} finally {
dockerApi.close();
server.shutdown();
}
}
public void testGetNonExistingContainer() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setResponseCode(404));
DockerApi dockerApi = api(server.getUrl("/"));
ContainerApi api = dockerApi.getContainerApi();
String containerId = "notExisting";
try {
Container container = api.inspectContainer(containerId);
assertRequestHasCommonFields(server.takeRequest(), "/containers/" + containerId + "/json");
} finally {
dockerApi.close();
server.shutdown();
}
}
public void testCreateContainer() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setBody(payloadFromResource("/container-creation.json")));
DockerApi dockerApi = api(server.getUrl("/"));
ContainerApi api = dockerApi.getContainerApi();
Config containerConfig = Config.builder().cmd(ImmutableList.of("date"))
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/container-creation.json")));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
Config containerConfig = Config.builder()
.cmd(ImmutableList.of("date"))
.attachStdin(false)
.attachStderr(true)
.attachStdout(true)
@ -141,106 +100,135 @@ public class ContainerApiMockTest extends BaseDockerMockTest {
.build();
try {
Container container = api.createContainer("test", containerConfig);
assertRequestHasCommonFields(server.takeRequest(), "POST", "/containers/create?name=test");
assertSent(server, "POST", "/containers/create?name=test");
assertNotNull(container);
assertEquals(container.id(), "c6c74153ae4b1d1633d68890a68d89c40aa5e284a1ea016cbc6ef0e634ee37b2");
assertThat(container.id()).isEqualTo("c6c74153ae4b1d1633d68890a68d89c40aa5e284a1ea016cbc6ef0e634ee37b2");
} finally {
dockerApi.close();
server.shutdown();
}
}
public void testRemoveContainer() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setResponseCode(204));
DockerApi dockerApi = api(server.getUrl("/"));
ContainerApi api = dockerApi.getContainerApi();
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(204));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
String containerId = "6d35806c1bd2b25cd92bba2d2c2c5169dc2156f53ab45c2b62d76e2d2fee14a9";
try {
api.removeContainer(containerId);
assertRequestHasCommonFields(server.takeRequest(), "DELETE", "/containers/" + containerId);
} finally {
dockerApi.close();
server.shutdown();
}
}
assertSent(server, "DELETE", "/containers/" + containerId);
public void testRemoveNonExistingContainer() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setResponseCode(404));
DockerApi dockerApi = api(server.getUrl("/"));
ContainerApi api = dockerApi.getContainerApi();
String containerId = "nonExisting";
try {
api.removeContainer(containerId);
fail("Remove container must fail on 404");
} catch (ResourceNotFoundException ex) {
// Expected exception
} finally {
dockerApi.close();
server.shutdown();
}
}
public void testStartContainer() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setResponseCode(200));
DockerApi dockerApi = api(server.getUrl("/"));
ContainerApi api = dockerApi.getContainerApi();
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(200));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
api.startContainer("1");
assertRequestHasCommonFields(server.takeRequest(), "POST", "/containers/1/start");
assertSent(server, "POST", "/containers/1/start");
} finally {
dockerApi.close();
server.shutdown();
}
}
public void testStartNonExistingContainer() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setResponseCode(404));
DockerApi dockerApi = api(server.getUrl("/"));
ContainerApi api = dockerApi.getContainerApi();
try {
try {
api.startContainer("1");
fail("Start container must fail on 404");
} catch (ResourceNotFoundException ex) {
// Expected exception
}
} finally {
dockerApi.close();
server.shutdown();
}
}
public void testStopContainer() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setResponseCode(200));
DockerApi dockerApi = api(server.getUrl("/"));
ContainerApi api = dockerApi.getContainerApi();
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(200));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
api.stopContainer("1");
assertRequestHasCommonFields(server.takeRequest(), "POST", "/containers/1/stop");
assertSent(server, "POST", "/containers/1/stop");
} finally {
dockerApi.close();
server.shutdown();
}
}
public void testStopNonExistingContainer() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setResponseCode(404));
DockerApi dockerApi = api(server.getUrl("/"));
ContainerApi api = dockerApi.getContainerApi();
public void testCommitContainer() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(201));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
api.stopContainer("1");
fail("Stop container must fail on 404");
} catch (ResourceNotFoundException ex) {
// Expected exception
api.commit();
assertSent(server, "POST", "/commit");
} finally {
server.shutdown();
}
}
public void testPauseContainer() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(204));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
api.pause("1");
assertSent(server, "POST", "/containers/1/pause");
} finally {
server.shutdown();
}
}
public void testUnpauseContainer() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(204));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
api.unpause("1");
assertSent(server, "POST", "/containers/1/unpause");
} finally {
server.shutdown();
}
}
public void testAttachContainer() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(200));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
api.attach("1");
assertSent(server, "POST", "/containers/1/attach");
} finally {
server.shutdown();
}
}
public void testWaitContainer() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(200));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
api.wait("1");
assertSent(server, "POST", "/containers/1/wait");
} finally {
server.shutdown();
}
}
public void testRestartContainer() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(204));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
api.restart("1");
assertSent(server, "POST", "/containers/1/restart");
} finally {
server.shutdown();
}
}
public void testKillContainer() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(204));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
api.kill("1");
assertSent(server, "POST", "/containers/1/kill");
} finally {
server.shutdown();
}
}
public void testCopyFileFromContainer() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(204));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
api.copy("1", Resource.create("test"));
assertSent(server, "POST", "/containers/1/copy");
} finally {
dockerApi.close();
server.shutdown();
}
}

View File

@ -16,15 +16,16 @@
*/
package org.jclouds.docker.features;
import static org.testng.Assert.fail;
import static org.testng.Assert.assertEquals;
import org.jclouds.docker.DockerApi;
import org.jclouds.docker.config.DockerParserModule;
import org.jclouds.docker.internal.BaseDockerMockTest;
import org.jclouds.docker.options.CreateImageOptions;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.docker.parse.ImageParseTest;
import org.jclouds.docker.parse.ImagesParseTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.squareup.okhttp.mockwebserver.MockResponse;
import com.squareup.okhttp.mockwebserver.MockWebServer;
@ -35,61 +36,47 @@ import com.squareup.okhttp.mockwebserver.MockWebServer;
public class ImageApiMockTest extends BaseDockerMockTest {
public void testCreateImage() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setResponseCode(200));
DockerApi dockerApi = api(server.getUrl("/"));
ImageApi api = dockerApi.getImageApi();
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(200));
ImageApi api = api(DockerApi.class, server.getUrl("/").toString()).getImageApi();
try {
api.createImage(CreateImageOptions.Builder.fromImage("base"));
assertRequestHasParameters(server.takeRequest(), "POST", "/images/create", ImmutableMultimap.of("fromImage", "base"));
assertSent(server, "POST", "/images/create?fromImage=base");
} finally {
dockerApi.close();
server.shutdown();
}
}
public void testCreateImageFailure() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setResponseCode(404));
DockerApi dockerApi = api(server.getUrl("/"));
ImageApi api = dockerApi.getImageApi();
public void testGetImage() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/image.json")));
ImageApi api = api(DockerApi.class, server.getUrl("/").toString(), new DockerParserModule()).getImageApi();
try {
api.createImage(CreateImageOptions.Builder.fromImage("base"));
fail("Create image must fail on 404");
} catch (ResourceNotFoundException ex) {
// Expected exception
String imageId = "cbba6639a342646deed70d7ea6162fa2a0acea9300f911f4e014555fe37d3456";
assertEquals(api.inspectImage(imageId), new ImageParseTest().expected());
assertSent(server, "GET", "/images/" + imageId + "/json");
} finally {
server.shutdown();
}
}
public void testListImages() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/images.json")));
ImageApi api = api(DockerApi.class, server.getUrl("/").toString()).getImageApi();
try {
assertEquals(api.listImages(), new ImagesParseTest().expected());
assertSent(server, "GET", "/images/json");
} finally {
dockerApi.close();
server.shutdown();
}
}
public void testDeleteImage() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setResponseCode(204));
DockerApi dockerApi = api(server.getUrl("/"));
ImageApi api = dockerApi.getImageApi();
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(204));
ImageApi api = api(DockerApi.class, server.getUrl("/").toString()).getImageApi();
try {
api.deleteImage("1");
assertRequestHasCommonFields(server.takeRequest(), "DELETE", "/images/1");
} finally {
dockerApi.close();
server.shutdown();
}
}
assertSent(server, "DELETE", "/images/1");
public void testDeleteNotExistingImage() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setResponseCode(404));
DockerApi dockerApi = api(server.getUrl("/"));
ImageApi api = dockerApi.getImageApi();
try {
api.deleteImage("1");
fail("Delete image must fail on 404");
} catch (ResourceNotFoundException ex) {
// Expected exception
} finally {
dockerApi.close();
server.shutdown();
}
}

View File

@ -18,7 +18,6 @@ package org.jclouds.docker.features;
import org.jclouds.docker.compute.BaseDockerApiLiveTest;
import org.jclouds.docker.options.BuildOptions;
import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
@ -34,10 +33,10 @@ import com.google.common.collect.Iterables;
public class MiscApiLiveTest extends BaseDockerApiLiveTest {
private static final String API_VERSION = "1.15";
private static final String VERSION = "1.3.0";
private static final String GIT_COMMIT = "c78088f";
private static final String VERSION = "1.3.2";
private static final String GIT_COMMIT = "39fa2fa";
private static final String GO_VERSION = "go1.3.3";
private static final String KERNEL_VERSION = "3.16.4-tinycore64";
private static final String KERNEL_VERSION = "3.16.7-tinycore64";
private static final String ARCH = "amd64";
private static final String OS = "linux";
@ -71,13 +70,6 @@ public class MiscApiLiveTest extends BaseDockerApiLiveTest {
assertNotNull(imageId);
}
@AfterClass
protected void tearDown() {
if (imageId != null) {
consumeStream(api.getImageApi().deleteImage(imageId));
}
}
private MiscApi api() {
return api.getMiscApi();
}

View File

@ -19,19 +19,15 @@ package org.jclouds.docker.features;
import com.squareup.okhttp.mockwebserver.MockResponse;
import com.squareup.okhttp.mockwebserver.MockWebServer;
import org.jclouds.docker.DockerApi;
import org.jclouds.docker.domain.Info;
import org.jclouds.docker.domain.Version;
import org.jclouds.docker.internal.BaseDockerMockTest;
import org.jclouds.docker.options.BuildOptions;
import org.jclouds.docker.parse.InfoParseTest;
import org.jclouds.docker.parse.VersionParseTest;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
import org.jclouds.rest.ResourceNotFoundException;
import org.testng.annotations.Test;
import static org.jclouds.docker.compute.BaseDockerApiLiveTest.tarredDockerfile;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.fail;
import java.io.File;
import java.io.FileInputStream;
@ -41,117 +37,50 @@ import java.io.FileInputStream;
@Test(groups = "unit", testName = "MiscApiMockTest")
public class MiscApiMockTest extends BaseDockerMockTest {
private static final String API_VERSION = "1.15";
private static final String VERSION = "1.3.0";
private static final String GIT_COMMIT = "c78088f";
private static final String GO_VERSION = "go1.3.3";
private static final String KERNEL_VERSION = "3.16.4-tinycore64";
private static final String ARCH = "amd64";
private static final String OS = "linux";
public void testGetVersion() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setBody(payloadFromResource("/version.json")));
DockerApi dockerApi = api(server.getUrl("/"));
MiscApi api = dockerApi.getMiscApi();
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/version.json")));
MiscApi api = api(DockerApi.class, server.getUrl("/").toString()).getMiscApi();
try {
Version version = api.getVersion();
assertRequestHasCommonFields(server.takeRequest(), "/version");
assertNotNull(version);
assertEquals(version.version(), VERSION);
assertEquals(version.gitCommit(), GIT_COMMIT);
assertEquals(version.apiVersion(), API_VERSION);
assertEquals(version.goVersion(), GO_VERSION);
assertEquals(version.kernelVersion(), KERNEL_VERSION);
assertEquals(version.arch(), ARCH);
assertEquals(version.os(), OS);
assertEquals(api.getVersion(), new VersionParseTest().expected());
assertSent(server, "GET", "/version");
} finally {
dockerApi.close();
server.shutdown();
}
}
public void testGetInfo() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setBody(payloadFromResource("/info.json")));
DockerApi dockerApi = api(server.getUrl("/"));
MiscApi api = dockerApi.getMiscApi();
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/info.json")));
MiscApi api = api(DockerApi.class, server.getUrl("/").toString()).getMiscApi();
try {
Info info = api.getInfo();
assertRequestHasCommonFields(server.takeRequest(), "/info");
assertNotNull(info);
assertNotNull(info.containers());
assertNotNull(info.debug());
assertNotNull(info.driver());
assertNotNull(info.executionDriver());
assertNotNull(info.images());
assertNotNull(info.indexServerAddress());
assertNotNull(info.initPath());
assertNotNull(info.iPv4Forwarding());
assertNotNull(info.kernelVersion());
assertNotNull(info.memoryLimit());
assertNotNull(info.nEventsListener());
assertNotNull(info.nFd());
assertNotNull(info.nGoroutines());
assertNotNull(info.swapLimit());
assertEquals(api.getInfo(), new InfoParseTest().expected());
assertSent(server, "GET", "/info");
} finally {
dockerApi.close();
server.shutdown();
}
}
public void testBuildContainer() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setResponseCode(200));
DockerApi dockerApi = api(server.getUrl("/"));
MiscApi api = dockerApi.getMiscApi();
File dockerFile = File.createTempFile("docker", "tmp");
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(200));
MiscApi api = api(DockerApi.class, server.getUrl("/").toString()).getMiscApi();
try {
api.build(tarredDockerfile(), BuildOptions.NONE);
assertRequestHasCommonFields(server.takeRequest(), "POST", "/build");
api.build(tarredDockerfile());
assertSent(server, "POST", "/build");
} finally {
dockerFile.delete();
dockerApi.close();
server.shutdown();
}
}
public void testBuildContainerUsingPayload() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setResponseCode(200));
DockerApi dockerApi = api(server.getUrl("/"));
MiscApi api = dockerApi.getMiscApi();
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(200));
MiscApi api = api(DockerApi.class, server.getUrl("/").toString()).getMiscApi();
File file = File.createTempFile("docker", "tmp");
FileInputStream data = new FileInputStream(file);
Payload payload = Payloads.newInputStreamPayload(data);
payload.getContentMetadata().setContentLength(file.length());
try {
api.build(payload, BuildOptions.NONE);
assertRequestHasCommonFields(server.takeRequest(), "POST", "/build");
api.build(payload);
assertSent(server, "POST", "/build");
} finally {
dockerApi.close();
server.shutdown();
}
}
public void testBuildNonexistentContainer() throws Exception {
MockWebServer server = mockWebServer();
server.enqueue(new MockResponse().setResponseCode(404));
DockerApi dockerApi = api(server.getUrl("/"));
MiscApi api = dockerApi.getMiscApi();
File dockerFile = File.createTempFile("docker", "tmp");
try {
try {
api.build(tarredDockerfile(), BuildOptions.NONE);
fail("Build container must fail on 404");
} catch (ResourceNotFoundException ex) {
// Expected exception
}
} finally {
dockerFile.delete();
dockerApi.close();
server.shutdown();
}
}

View File

@ -16,27 +16,19 @@
*/
package org.jclouds.docker.internal;
import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
import static org.jclouds.http.utils.Queries.encodeQueryLine;
import static org.assertj.core.api.Assertions.assertThat;
import static org.jclouds.util.Strings2.toStringAndClose;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.net.URL;
import java.util.Properties;
import java.util.Set;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import org.jclouds.ContextBuilder;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.docker.DockerApi;
import org.jclouds.http.BaseMockWebServerTest;
import org.jclouds.http.okhttp.config.OkHttpCommandExecutorServiceModule;
import com.google.common.base.Charsets;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.inject.Module;
import com.squareup.okhttp.mockwebserver.MockWebServer;
import com.squareup.okhttp.mockwebserver.RecordedRequest;
@ -44,33 +36,18 @@ import com.squareup.okhttp.mockwebserver.RecordedRequest;
/**
* Base class for all Docker mock tests.
*/
public class BaseDockerMockTest {
private final Set<Module> modules = ImmutableSet.<Module> of(new ExecutorServiceModule(sameThreadExecutor(),
sameThreadExecutor()));
public class BaseDockerMockTest extends BaseMockWebServerTest {
protected String provider;
protected static final String API_VERSION = "1.15";
public BaseDockerMockTest() {
provider = "docker";
@Override
protected void addOverrideProperties(Properties properties) {
properties.setProperty("jclouds.api-version", API_VERSION);
}
public DockerApi api(URL url) {
return ContextBuilder.newBuilder(provider)
.credentials("clientid", "apikey")
.endpoint(url.toString())
.modules(modules)
.overrides(setupProperties())
.buildApi(DockerApi.class);
}
protected Properties setupProperties() {
return new Properties();
}
public static MockWebServer mockWebServer() throws IOException {
MockWebServer server = new MockWebServer();
server.play();
return server;
@Override
protected Module createConnectionModule() {
return new OkHttpCommandExecutorServiceModule();
}
public byte[] payloadFromResource(String resource) {
@ -81,38 +58,12 @@ public class BaseDockerMockTest {
}
}
protected static void assertRequestHasCommonFields(final RecordedRequest request, final String path)
throws InterruptedException {
assertRequestHasParameters(request, "GET", path, ImmutableMultimap.<String, String> of());
}
protected static void assertRequestHasCommonFields(final RecordedRequest request,
final String verb, final String path)
throws InterruptedException {
assertRequestHasParameters(request, verb, path, ImmutableMultimap.<String, String> of());
}
protected static void assertRequestHasParameters(final RecordedRequest request, final String path,
Multimap<String, String> parameters) throws InterruptedException {
assertRequestHasParameters(request, "GET", path, parameters);
}
protected static void assertRequestHasParameters(final RecordedRequest request, String verb, final String path,
Multimap<String, String> parameters) throws InterruptedException {
String queryParameters = "";
if (!parameters.isEmpty()) {
Multimap<String, String> allparams = ImmutableMultimap.<String, String>builder()
.putAll(parameters)
.build();
assertRequestHasAcceptHeader(request);
queryParameters = "?" + encodeQueryLine(allparams);
}
assertEquals(request.getRequestLine(), verb + " " + path + queryParameters + " HTTP/1.1");
}
protected static void assertRequestHasAcceptHeader(final RecordedRequest request) throws InterruptedException {
assertEquals(request.getHeader(HttpHeaders.ACCEPT), MediaType.APPLICATION_JSON);
protected RecordedRequest assertSent(MockWebServer server, String method, String path) throws InterruptedException {
RecordedRequest request = server.takeRequest();
assertThat(request.getMethod()).isEqualTo(method);
assertThat(request.getPath()).isEqualTo("/v" + API_VERSION + path);
assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON);
return request;
}
}

View File

@ -0,0 +1,33 @@
/*
* 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.internal;
import org.jclouds.docker.config.DockerParserModule;
import org.jclouds.json.BaseItemParserTest;
import org.jclouds.json.config.GsonModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
public abstract class BaseDockerParseTest<T> extends BaseItemParserTest<T> {
@Override
protected Injector injector() {
return Guice.createInjector(new GsonModule(), new DockerParserModule());
}
}

View File

@ -0,0 +1,95 @@
/*
* 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.parse;
import java.util.List;
import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.docker.domain.Config;
import org.jclouds.docker.domain.Container;
import org.jclouds.docker.domain.HostConfig;
import org.jclouds.docker.domain.NetworkSettings;
import org.jclouds.docker.domain.State;
import org.jclouds.docker.internal.BaseDockerParseTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@Test(groups = "unit")
public class ContainerParseTest extends BaseDockerParseTest<Container> {
@Override
public String resource() {
return "/container.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Container expected() {
return Container.builder()
.id("6c9932f478bd761f32ddb54ed28ab42ab6fac6f2a279f561ea31503ee9d39524")
.created(new SimpleDateFormatDateService().iso8601DateParse("2014-10-31T17:00:21.544197943Z"))
.path("/home/weave/weaver")
.name("/weave")
.args(ImmutableList.of("-iface", "ethwe", "-wait", "5", "-name", "7a:63:a2:39:7b:0f"))
.config(Config.builder()
.hostname("6c9932f478bd")
.env(ImmutableList.of("PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"))
.image("57e570db16baba1e8c0d6f3c15868ddb400f64ff76ec948e65c3ca3f15fb3587")
.domainname("")
.user("")
.cmd(ImmutableList.of("-name", "7a:63:a2:39:7b:0f"))
.entrypoint(ImmutableList.of("/home/weave/weaver", "-iface", "ethwe", "-wait", "5"))
.image("zettio/weave")
.workingDir("/home/weave")
.exposedPorts(ImmutableMap.of("6783/tcp", ImmutableMap.of(), "6783/udp", ImmutableMap.of()))
.build())
.state(State.create(3939, true, 0, "2014-10-31T17:00:21.802008706Z", "0001-01-01T00:00:00Z", false, false))
.image("57e570db16baba1e8c0d6f3c15868ddb400f64ff76ec948e65c3ca3f15fb3587")
.networkSettings(NetworkSettings.builder()
.ipAddress("172.17.0.7")
.ipPrefixLen(16)
.gateway("172.17.42.1")
.bridge("docker0")
.ports(ImmutableMap.<String, List<Map<String, String>>>of(
"6783/tcp", ImmutableList.<Map<String, String>>of(ImmutableMap.of("HostIp", "0.0.0.0", "HostPort", "6783")),
"6783/udp", ImmutableList.<Map<String, String>>of(ImmutableMap.of("HostIp", "0.0.0.0", "HostPort", "6783")))
)
.build())
.resolvConfPath("/var/lib/docker/containers/6c9932f478bd761f32ddb54ed28ab42ab6fac6f2a279f561ea31503ee9d39524/resolv.conf")
.hostConfig(HostConfig.builder()
.containerIDFile("")
.portBindings(ImmutableMap.<String, List<Map<String, String>>>of(
"6783/tcp", ImmutableList.<Map<String, String>>of(ImmutableMap.of("HostIp", "", "HostPort", "6783")),
"6783/udp", ImmutableList.<Map<String, String>>of(ImmutableMap.of("HostIp", "", "HostPort", "6783")))
)
.privileged(true)
.build())
.driver("aufs")
.execDriver("native-0.2")
.hostnamePath("/var/lib/docker/containers/6c9932f478bd761f32ddb54ed28ab42ab6fac6f2a279f561ea31503ee9d39524/hostname")
.hostsPath("/var/lib/docker/containers/6c9932f478bd761f32ddb54ed28ab42ab6fac6f2a279f561ea31503ee9d39524/hosts")
.mountLabel("")
.processLabel("")
.build();
}
}

View File

@ -0,0 +1,53 @@
/*
* 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.parse;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.docker.domain.ContainerSummary;
import org.jclouds.docker.domain.Port;
import org.jclouds.docker.internal.BaseDockerParseTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
@Test(groups = "unit")
public class ContainersParseTest extends BaseDockerParseTest<List<ContainerSummary>> {
@Override
public String resource() {
return "/containers.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public List<ContainerSummary> expected() {
return ImmutableList.of(
ContainerSummary.create("6d35806c1bd2b25cd92bba2d2c2c5169dc2156f53ab45c2b62d76e2d2fee14a9",
ImmutableList.of("/hopeful_mclean"),
"1395472605",
"jclouds/ubuntu:latest",
"/usr/sbin/sshd -D",
ImmutableList.of(Port.create("0.0.0.0", 22, 49231, "tcp")),
"Up 55 seconds")
);
}
}

View File

@ -0,0 +1,83 @@
/*
* 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.parse;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.docker.domain.Config;
import org.jclouds.docker.domain.Image;
import org.jclouds.docker.internal.BaseDockerParseTest;
import org.testng.annotations.Test;
import com.beust.jcommander.internal.Maps;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@Test(groups = "unit")
public class ImageParseTest extends BaseDockerParseTest<Image> {
@Override
public String resource() {
return "/image.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Image expected() {
return Image.create("cbba6639a342646deed70d7ea6162fa2a0acea9300f911f4e014555fe37d3456",
"author",
"comment",
Config.builder().cmd(ImmutableList.of("/bin/sh", "-c", "echo hello world"))
.env(ImmutableList.of(
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"HOME=/root",
"JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64"
)
)
.exposedPorts(ImmutableMap.of("8081/tcp", Maps.newHashMap()))
.hostname("f22711318734")
.domainname("")
.user("user")
.image("05794515afd5724df1cdf0e674ae932455fce7dea3c70a94d77119ad1fa954ba")
.workingDir("/home/user")
.build(),
Config.builder().cmd(ImmutableList.of("/bin/sh", "-c", "echo hello world"))
.env(ImmutableList.of(
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"HOME=/root",
"JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64")
)
.exposedPorts(ImmutableMap.of("8081/tcp", Maps.newHashMap()))
.hostname("f22711318734")
.domainname("")
.user("user")
.image("05794515afd5724df1cdf0e674ae932455fce7dea3c70a94d77119ad1fa954ba")
.workingDir("/home/user")
.build(),
"05794515afd5724df1cdf0e674ae932455fce7dea3c70a94d77119ad1fa954ba",
new SimpleDateFormatDateService().iso8601DateParse("2014-11-24T11:09:20.310023104Z"),
"0d14967353dbbd2ee78abe209f026f71654da49692fa2b044296ec3c810027b3",
"1.3.1",
"amd64",
"linux",
0,
808709069,
null);
}
}

View File

@ -0,0 +1,69 @@
/*
* 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.parse;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.docker.domain.ImageSummary;
import org.jclouds.docker.internal.BaseDockerParseTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
@Test(groups = "unit")
public class ImagesParseTest extends BaseDockerParseTest<List<ImageSummary>> {
@Override
public String resource() {
return "/images.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public List<ImageSummary> expected() {
return ImmutableList.of(
ImageSummary.create("cbba6639a342646deed70d7ea6162fa2a0acea9300f911f4e014555fe37d3456",
1416827360,
"05794515afd5724df1cdf0e674ae932455fce7dea3c70a94d77119ad1fa954ba",
0,
808709069,
ImmutableList.of("test:latest")),
ImageSummary.create("e1e548b03259ae30ba12232b6c16ef5205cf71b0363848e78b0394e1ecba4f57",
1416826851,
"6f36bec79c7f184ceebf7000cfb7244c4bc9b397b6659ac7f420a53d114250d9",
0,
5609404,
ImmutableList.of("<none>:<none>")),
ImageSummary.create("8201388d2b288539aab6aabf5d3b15ec269eba95c6baa9d6771f16540abf3a3f",
1414247273,
"4671e2c549c5b60063e349f520c801dc73b53d2226a5a8e5501845ebe94761ca",
0,
755313702,
ImmutableList.of("dockerfile/java:openjdk-7-jdk")),
ImageSummary.create("5506de2b643be1e6febbf3b8a240760c6843244c41e12aa2f60ccbb7153d17f5",
1414108439,
"22093c35d77bb609b9257ffb2640845ec05018e3d96cb939f68d0e19127f1723",
0,
199257566,
ImmutableList.of("ubuntu:14.04"))
);
}
}

View File

@ -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.parse;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.docker.domain.Info;
import org.jclouds.docker.internal.BaseDockerParseTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
@Test(groups = "unit")
public class InfoParseTest extends BaseDockerParseTest<Info> {
@Override
public String resource() {
return "/info.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Info expected() {
return Info.create(0,
1,
"aufs",
ImmutableList.<List<String>>of(
ImmutableList.of("Root Dir", "/mnt/sda1/var/lib/docker/aufs"),
ImmutableList.of("Dirs", "15")
),
"native-0.2",
1,
15,
"https://index.docker.io/v1/",
"/usr/local/bin/docker",
"",
"3.16.4-tinycore64",
1,
0,
10,
11,
"Boot2Docker 1.3.0 (TCL 5.4); master : a083df4 - Thu Oct 16 17:05:03 UTC 2014",
1);
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.parse;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.docker.domain.Version;
import org.jclouds.docker.internal.BaseDockerParseTest;
import org.testng.annotations.Test;
@Test(groups = "unit")
public class VersionParseTest extends BaseDockerParseTest<Version> {
@Override
public String resource() {
return "/version.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Version expected() {
return Version.create(
"1.15",
"amd64",
"c78088f",
"go1.3.3",
"3.16.4-tinycore64",
"linux",
"1.3.0");
}
}

View File

@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDtTCCAp2gAwIBAgIJAL/TuOknjSR5MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTQxMjEyMTYwMDEyWhcNMjQxMjA5MTYwMDEyWjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAuUQcWlhrMXmzLSLiHUADdF98IHKRde7I1eDT91NndOtx4pKfvVc3WPei
REIMksrU8F1r4A086h5++xxDf27LxR4EC9ry0Q6GgJ9Un9RB9clCWRhLw8awHAS7
HgAEN8YOSCeF3qP+78muxyMkIKQbYn3TqqOzRZcK576hX+a6URNJDhbHHAzq2fxm
rOSRVdPXzKLl48ABfmqJ6+KiXc6e7mQSgmwBLfh51zxmJNNwZ5e+6sfZ8oz4yM4y
Kzek53GRSFj+VFNp5nS/x2072fUak2i6DGut5LibFfh1kqskIm+Iq5WwO15RbojZ
CR6fkktCl5QOtea5p8SETZpwWfaddQIDAQABo4GnMIGkMB0GA1UdDgQWBBQtOc1g
1gxisDQ7VTmRYI1U9WHVMDB1BgNVHSMEbjBsgBQtOc1g1gxisDQ7VTmRYI1U9WHV
MKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV
BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAL/TuOknjSR5MAwGA1UdEwQF
MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBABxYn5JdJYC8FUITqymJeNZ72/a2GVf8
+gGlWH+DuiyviEAGMGpv7O4GXfS/6UiUBO7zMe2z15fUvNgd5RQBh4T+l5bA9aS0
5JhENIpEApiIcEII4ISIk6pTLmAZjWvqq2kStiiFPNvdKFclYqFuKHv847EA8kGz
9u6MuUyFrJipWZ3g8zeYiwLWaAzvimbHomO7HU4pcvYaCSl7O5BQTToKwLfHcx5y
UG6uRf+0auC5QbotiXpYNdXhIbSD/2xXbjxGwYy4yRWHINcbwfK8iVRhR4eSvtBC
WvF3Vp8xLJxp6ujBd+a27AOWEiE1XM8oAoUpEzdIINY1GtUSbXzNboc=
-----END CERTIFICATE-----

View File

@ -0,0 +1,83 @@
{
"Architecture": "amd64",
"Author": "author",
"Comment": "comment",
"Config": {
"AttachStderr": false,
"AttachStdin": false,
"AttachStdout": false,
"Cmd": [
"/bin/sh",
"-c",
"echo hello world"
],
"CpuShares": 0,
"Cpuset": "",
"Domainname": "",
"Entrypoint": null,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"HOME=/root",
"JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64"
],
"ExposedPorts": {
"8081/tcp": {}
},
"Hostname": "f22711318734",
"Image": "05794515afd5724df1cdf0e674ae932455fce7dea3c70a94d77119ad1fa954ba",
"Memory": 0,
"MemorySwap": 0,
"NetworkDisabled": false,
"OnBuild": [],
"OpenStdin": false,
"PortSpecs": null,
"StdinOnce": false,
"Tty": false,
"User": "user",
"Volumes": null,
"WorkingDir": "/home/user"
},
"Container": "0d14967353dbbd2ee78abe209f026f71654da49692fa2b044296ec3c810027b3",
"ContainerConfig": {
"AttachStderr": false,
"AttachStdin": false,
"AttachStdout": false,
"Cmd": [
"/bin/sh",
"-c",
"echo hello world"
],
"CpuShares": 0,
"Cpuset": "",
"Domainname": "",
"Entrypoint": null,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"HOME=/root",
"JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64"
],
"ExposedPorts": {
"8081/tcp": {}
},
"Hostname": "f22711318734",
"Image": "05794515afd5724df1cdf0e674ae932455fce7dea3c70a94d77119ad1fa954ba",
"Memory": 0,
"MemorySwap": 0,
"NetworkDisabled": false,
"OnBuild": [],
"OpenStdin": false,
"PortSpecs": null,
"StdinOnce": false,
"Tty": false,
"User": "user",
"Volumes": null,
"WorkingDir": "/home/user"
},
"Created": "2014-11-24T11:09:20.310023104Z",
"DockerVersion": "1.3.1",
"Id": "cbba6639a342646deed70d7ea6162fa2a0acea9300f911f4e014555fe37d3456",
"Os": "linux",
"Parent": "05794515afd5724df1cdf0e674ae932455fce7dea3c70a94d77119ad1fa954ba",
"Size": 0,
"VirtualSize": 808709069
}

View File

@ -0,0 +1,42 @@
[
{
"Created": 1416827360,
"Id": "cbba6639a342646deed70d7ea6162fa2a0acea9300f911f4e014555fe37d3456",
"ParentId": "05794515afd5724df1cdf0e674ae932455fce7dea3c70a94d77119ad1fa954ba",
"RepoTags": [
"test:latest"
],
"Size": 0,
"VirtualSize": 808709069
},
{
"Created": 1416826851,
"Id": "e1e548b03259ae30ba12232b6c16ef5205cf71b0363848e78b0394e1ecba4f57",
"ParentId": "6f36bec79c7f184ceebf7000cfb7244c4bc9b397b6659ac7f420a53d114250d9",
"RepoTags": [
"<none>:<none>"
],
"Size": 0,
"VirtualSize": 5609404
},
{
"Created": 1414247273,
"Id": "8201388d2b288539aab6aabf5d3b15ec269eba95c6baa9d6771f16540abf3a3f",
"ParentId": "4671e2c549c5b60063e349f520c801dc73b53d2226a5a8e5501845ebe94761ca",
"RepoTags": [
"dockerfile/java:openjdk-7-jdk"
],
"Size": 0,
"VirtualSize": 755313702
},
{
"Created": 1414108439,
"Id": "5506de2b643be1e6febbf3b8a240760c6843244c41e12aa2f60ccbb7153d17f5",
"ParentId": "22093c35d77bb609b9257ffb2640845ec05018e3d96cb939f68d0e19127f1723",
"RepoTags": [
"ubuntu:14.04"
],
"Size": 0,
"VirtualSize": 199257566
}
]

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAuUQcWlhrMXmzLSLiHUADdF98IHKRde7I1eDT91NndOtx4pKf
vVc3WPeiREIMksrU8F1r4A086h5++xxDf27LxR4EC9ry0Q6GgJ9Un9RB9clCWRhL
w8awHAS7HgAEN8YOSCeF3qP+78muxyMkIKQbYn3TqqOzRZcK576hX+a6URNJDhbH
HAzq2fxmrOSRVdPXzKLl48ABfmqJ6+KiXc6e7mQSgmwBLfh51zxmJNNwZ5e+6sfZ
8oz4yM4yKzek53GRSFj+VFNp5nS/x2072fUak2i6DGut5LibFfh1kqskIm+Iq5Ww
O15RbojZCR6fkktCl5QOtea5p8SETZpwWfaddQIDAQABAoIBAAoj2zVqr3tGwPLQ
fPXC4i2FaGLSQnnk9uMV6iQYUYpJtLME+W9Ajcv1ydDYmJ2UMnFxe40IzHO39ZVC
58LaypZgXTJU6oNcuynhDp2s3WtZd6MuvD7b6hmufJtYvuJamb+DQkV8TmDLdiB6
IOkUcldCscoeKZq+eJ9UhLqeA0aaosVUa2cfxJM2seGhF6iJmrJChvaKlc0xfqxG
l3Y+w01YNQgFBT7vxMzfXHZkVjY8jrrsxhhfyVKiheyaBZ0G3hQCZkBywR6h2bns
2rWM2mOcaWL7+lJiMB0d9el58HzTxFVxuPENbE2Li1SqTG1pn+Fif0VwG3Te0lPo
xz7EL8UCgYEA3wJLL2nfVqS73yf5k2w1+uiBHK4RVHaJeQgxv1QlgeunCwOWZ0dp
MDPQVi9CfWhEQUZKYr118V3ikecOYh+o8ruStz9fNTeA+7IXtBaE1cAbqU9ZgeS2
vcAIfEzQmN9JtSiFsywJKLON4/aDYXGR1NZDSaXouFQ7T0F/SaL/CUsCgYEA1Kxu
1QjOwFC1tdB/2MF9Fn7X+YWBQsdE66a5HO30FTlMmLb/ecmngB5OxvdvpfMRMQeD
mhifSzAfnTBAzBcuz9/il6sKygfhQX6PyxtTJ5o4XlwOArkaBew8H0gBXwfAL33G
816rNF2kCfgDJisj9iPrl+QAgrg3sJsfIwk5fD8CgYAx075eyqYHIumDM9hUsyHg
fOCUOuROXenbbBRJbpCu1atOD7AkRVVgWsNa7lZJ1OkjOIRYSYK3ukVsWhbhn7dM
/NIMNZGdP1iHZERdjYaCh9jmXH9gQWz/Oo/qzfLxpTo/yt0MqnMlb/DtFWBHfmua
BYGlS/eSb+eMjtLU7iFTvwKBgDiGuFKhK6rMCPARQdnP27p97lOg23FvW28y+iKp
UGXPu/8fLJonMgEIjTGvFJrMFzar45uyjaxDVzPFXoOgac3QmP5s9Mor/AAXboqy
cZCmGfNijkrE/hiy6Gv8DHlAqyE0Ugvfjqu1c+M+az/a2Y0TkQvnCwezhQHIySbb
zc6rAoGAcg9GZnYk64V2c4uzaeTekkLkZhPTv4F7xFWb0JmTurL5BR//TDDk9Oy8
pd5VoiBnKyCRTo2oC8J8COobxJXbl5qUxEeapjtKlQeBiROWE51K2DHacD2SDgKu
nzn5qonnU2659Aw95bfv+rGljttOu8ySZXVhs4UUKgrQvXErXhU=
-----END RSA PRIVATE KEY-----