diff --git a/apis/docker/README.md b/apis/docker/README.md index 9b55cbcea4..e6e0d9c84f 100644 --- a/apis/docker/README.md +++ b/apis/docker/README.md @@ -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` diff --git a/apis/docker/pom.xml b/apis/docker/pom.xml index b268a83da5..620cae139a 100644 --- a/apis/docker/pom.xml +++ b/apis/docker/pom.xml @@ -35,7 +35,7 @@ https://localhost:4243 - 1.10 + 1.15 FIXME FIXME org.jclouds.docker*;version="${project.version}" @@ -67,7 +67,16 @@ org.apache.jclouds.driver jclouds-sshj ${project.version} - test + + + org.apache.jclouds.driver + jclouds-bouncycastle + ${project.version} + + + org.apache.jclouds.driver + jclouds-okhttp + ${project.version} org.apache.jclouds diff --git a/apis/docker/src/main/java/org/jclouds/docker/DockerApiMetadata.java b/apis/docker/src/main/java/org/jclouds/docker/DockerApiMetadata.java index d5c470f415..25d75babaf 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/DockerApiMetadata.java +++ b/apis/docker/src/main/java/org/jclouds/docker/DockerApiMetadata.java @@ -52,8 +52,6 @@ public class DockerApiMetadata extends BaseHttpApiMetadata { 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 { 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") diff --git a/apis/docker/src/main/java/org/jclouds/docker/compute/strategy/DockerComputeServiceAdapter.java b/apis/docker/src/main/java/org/jclouds/docker/compute/strategy/DockerComputeServiceAdapter.java index 4cbb3b0165..920071b178 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/compute/strategy/DockerComputeServiceAdapter.java +++ b/apis/docker/src/main/java/org/jclouds/docker/compute/strategy/DockerComputeServiceAdapter.java @@ -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 listImages() { Set 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); } } diff --git a/apis/docker/src/main/java/org/jclouds/docker/config/DockerHttpApiModule.java b/apis/docker/src/main/java/org/jclouds/docker/config/DockerHttpApiModule.java index ced396c8a8..ed23d795ff 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/config/DockerHttpApiModule.java +++ b/apis/docker/src/main/java/org/jclouds/docker/config/DockerHttpApiModule.java @@ -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 { @Override @@ -53,11 +48,8 @@ public class DockerHttpApiModule extends HttpApiModule { @Override protected void configure() { super.configure(); - bind(new TypeLiteral>() { - }).to(new TypeLiteral() { - }); - bind(new TypeLiteral>() { - }).to(new TypeLiteral() { - }); + install(new OkHttpCommandExecutorServiceModule()); + bind(OkHttpClientSupplier.class).to(DockerOkHttpClientSupplier.class); } + } diff --git a/apis/docker/src/main/java/org/jclouds/docker/config/DockerOkHttpClientSupplier.java b/apis/docker/src/main/java/org/jclouds/docker/config/DockerOkHttpClientSupplier.java new file mode 100644 index 0000000000..f8a29b1057 --- /dev/null +++ b/apis/docker/src/main/java/org/jclouds/docker/config/DockerOkHttpClientSupplier.java @@ -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; + } + +} diff --git a/apis/docker/src/main/java/org/jclouds/docker/config/DockerParserModule.java b/apis/docker/src/main/java/org/jclouds/docker/config/DockerParserModule.java index 70c76cbda0..383f99ec72 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/config/DockerParserModule.java +++ b/apis/docker/src/main/java/org/jclouds/docker/config/DockerParserModule.java @@ -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); } + } diff --git a/apis/docker/src/main/java/org/jclouds/docker/domain/Config.java b/apis/docker/src/main/java/org/jclouds/docker/domain/Config.java index bef89692f6..05dcc4863b 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/domain/Config.java +++ b/apis/docker/src/main/java/org/jclouds/docker/domain/Config.java @@ -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 exposedPorts(); - public abstract boolean tty(); public abstract boolean openStdin(); @@ -61,34 +59,75 @@ public abstract class Config { public abstract List cmd(); - public abstract List dns(); + public abstract List entrypoint(); public abstract String image(); public abstract Map volumes(); - @Nullable public abstract String volumesFrom(); - @Nullable public abstract String workingDir(); - public abstract List entrypoint(); - public abstract boolean networkDisabled(); - public abstract List onBuild(); + public abstract Map exposedPorts(); + + public abstract List securityOpts(); + + @Nullable public abstract HostConfig hostConfig(); + + public abstract List binds(); + + public abstract List links(); + + public abstract List> lxcConf(); + + public abstract Map>> portBindings(); + + public abstract boolean publishAllPorts(); + + public abstract boolean privileged(); + + @Nullable public abstract List dns(); + + @Nullable public abstract String dnsSearch(); + + @Nullable public abstract String volumesFrom(); + + public abstract List capAdd(); + + public abstract List capDrop(); + + public abstract Map restartPolicy(); + + @Nullable public abstract String networkMode(); + + public abstract Map 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 exposedPorts, - boolean tty, boolean openStdin, boolean stdinOnce, List env, List cmd, List dns, - String image, Map volumes, String volumesFrom, String workingDir, List entrypoint, - boolean networkDisabled, List 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 env, List cmd, List entrypoint, + String image, Map volumes, String workingDir, boolean networkDisabled, + Map exposedPorts, List securityOpts, HostConfig hostConfig, List binds, + List links, List> lxcConf, Map>> portBindings, + boolean publishAllPorts, boolean privileged, List dns, String dnsSearch, String volumesFrom, + List capAdd, List capDrop, Map restartPolicy, String networkMode, Map 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 exposedPorts = ImmutableMap.of(); - private List env = ImmutableList.of(); private boolean tty; private boolean openStdin; private boolean stdinOnce; - private List cmd = ImmutableList.of(); - private List dns = ImmutableList.of(); + private List env = Lists.newArrayList(); + private List cmd = Lists.newArrayList(); + private List entrypoint = Lists.newArrayList(); private String image; - private Map volumes = ImmutableMap.of(); - private String volumesFrom; + private Map volumes = Maps.newHashMap(); private String workingDir; - private List entrypoint = ImmutableList.of(); private boolean networkDisabled; - private List onBuild = ImmutableList.of(); - private Map restartPolicy = ImmutableMap.of(); + private Map exposedPorts = Maps.newHashMap(); + private List securityOpts = Lists.newArrayList(); + private HostConfig hostConfig; + private List binds = Lists.newArrayList(); + private List links = Lists.newArrayList(); + private List> lxcConf = Lists.newArrayList(); + private Map>> portBindings = Maps.newHashMap(); + private boolean publishAllPorts; + private boolean privileged; + private List dns; + private String dnsSearch; + private String volumesFrom; + private List capAdd = Lists.newArrayList(); + private List capDrop = Lists.newArrayList(); + private Map restartPolicy = Maps.newHashMap(); + private String networkMode; + private Map 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 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 cmd) { - this.cmd = ImmutableList.copyOf(checkNotNull(cmd, "cmd")); - return this; - } - - public Builder dns(List dns) { - this.dns = ImmutableList.copyOf(checkNotNull(dns, "dns")); - return this; - } - - public Builder image(String image) { - this.image = image; - return this; - } - - public Builder volumes(Map 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 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 onBuild) { - this.onBuild = ImmutableList.copyOf(checkNotNull(onBuild, "onBuild")); + public Builder exposedPorts(Map exposedPorts) { + this.exposedPorts = exposedPorts; + return this; + } + + public Builder securityOpts(List securityOpts) { + this.securityOpts = securityOpts; + return this; + } + + public Builder hostConfig(HostConfig hostConfig) { + this.hostConfig = checkNotNull(hostConfig, "hostConfig"); + return this; + } + + public Builder binds(List binds) { + this.binds = binds; + return this; + } + + public Builder links(List links) { + this.links = links; + return this; + } + + public Builder lxcConf(List> lxcConf) { + this.lxcConf = lxcConf; + return this; + } + + public Builder portBindings(Map>> 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 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 capAdd) { + this.capAdd = capAdd; + return this; + } + + public Builder capDrop(List capDrop) { + this.capDrop = capDrop; return this; } public Builder restartPolicy(Map 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 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()); } } diff --git a/apis/docker/src/main/java/org/jclouds/docker/domain/Container.java b/apis/docker/src/main/java/org/jclouds/docker/domain/Container.java index b06c3a56f9..e784351b40 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/domain/Container.java +++ b/apis/docker/src/main/java/org/jclouds/docker/domain/Container.java @@ -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 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 volumes(); + + @Nullable public abstract HostConfig hostConfig(); + @Nullable public abstract String driver(); @Nullable public abstract String execDriver(); - public abstract Map volumes(); - public abstract Map volumesRW(); @Nullable public abstract String command(); @Nullable public abstract String status(); - @Nullable public abstract HostConfig hostConfig(); - public abstract List 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 args, Config config, - State state, String image, NetworkSettings networkSettings, String resolvConfPath, String driver, - String execDriver, Map volumes, Map volumesRW, String command, String status, - HostConfig hostConfig, List 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 args, Config config, + State state, String image, NetworkSettings networkSettings, String sysInitPath, + String resolvConfPath, Map volumes, HostConfig hostConfig, + String driver, String execDriver, Map volumesRW, String command, + String status, List 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 args; private Config config; private State state; private String image; private NetworkSettings networkSettings; + private String sysInitPath; private String resolvConfPath; + private Map volumes = ImmutableMap.of(); + private HostConfig hostConfig; private String driver; private String execDriver; - private Map volumes = ImmutableMap.of(); private Map volumesRW = ImmutableMap.of(); private String command; private String status; - private HostConfig hostConfig; private List 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 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 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 volumes) { - this.volumes = volumes; - return this; - } - public Builder volumesRW(Map 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 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()); } } } diff --git a/apis/docker/src/main/java/org/jclouds/docker/domain/ContainerSummary.java b/apis/docker/src/main/java/org/jclouds/docker/domain/ContainerSummary.java index 17d006427d..25bd5952cf 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/domain/ContainerSummary.java +++ b/apis/docker/src/main/java/org/jclouds/docker/domain/ContainerSummary.java @@ -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 names, String created, String image, String command, List ports, String status) { return new AutoValue_ContainerSummary(id, copyOf(names), created, image, command, copyOf(ports), status); diff --git a/apis/docker/src/main/java/org/jclouds/docker/domain/ExposedPorts.java b/apis/docker/src/main/java/org/jclouds/docker/domain/ExposedPorts.java index 413c84f498..ac57a988f9 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/domain/ExposedPorts.java +++ b/apis/docker/src/main/java/org/jclouds/docker/domain/ExposedPorts.java @@ -30,6 +30,9 @@ public abstract class ExposedPorts { public abstract List hostPorts(); + ExposedPorts() { + } + @SerializedNames({ "PortAndProtocol", "HostPorts" }) public static ExposedPorts create(String portAndProtocol, List hostPorts) { return new AutoValue_ExposedPorts(portAndProtocol, copyOf(hostPorts)); diff --git a/apis/docker/src/main/java/org/jclouds/docker/domain/HostConfig.java b/apis/docker/src/main/java/org/jclouds/docker/domain/HostConfig.java index 630be7c4ab..30efd9cd97 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/domain/HostConfig.java +++ b/apis/docker/src/main/java/org/jclouds/docker/domain/HostConfig.java @@ -51,6 +51,9 @@ public abstract class HostConfig { public abstract List volumesFrom(); + HostConfig() { + } + @SerializedNames({ "ContainerIDFile", "Binds", "LxcConf", "Privileged", "Dns", "DnsSearch", "PortBindings", "Links", "PublishAllPorts", "VolumesFrom" }) public static HostConfig create(String containerIDFile, List binds, List> lxcConf, diff --git a/apis/docker/src/main/java/org/jclouds/docker/domain/Image.java b/apis/docker/src/main/java/org/jclouds/docker/domain/Image.java index c80e44860c..f49a7b01f6 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/domain/Image.java +++ b/apis/docker/src/main/java/org/jclouds/docker/domain/Image.java @@ -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 repoTags(); + @Nullable public abstract List 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 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 repoTags) { + return new AutoValue_Image(id, author, comment, config, containerConfig, parent, created, container, + dockerVersion, architecture, os, size, virtualSize, copyOf(repoTags)); } } diff --git a/apis/docker/src/main/java/org/jclouds/docker/domain/ImageSummary.java b/apis/docker/src/main/java/org/jclouds/docker/domain/ImageSummary.java new file mode 100644 index 0000000000..f4ea9b9204 --- /dev/null +++ b/apis/docker/src/main/java/org/jclouds/docker/domain/ImageSummary.java @@ -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 repoTags(); + + ImageSummary() { + } + + @SerializedNames({"Id", "Created", "ParentId", "Size", "VirtualSize", "RepoTags"}) + public static ImageSummary create(String id, long created, String parentId, int size, int virtualSize, + List repoTags) { + return new AutoValue_ImageSummary(id, created, parentId, size, virtualSize, copyOf(repoTags)); + } + +} diff --git a/apis/docker/src/main/java/org/jclouds/docker/domain/Info.java b/apis/docker/src/main/java/org/jclouds/docker/domain/Info.java index 596c0a51f2..8a4c504130 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/domain/Info.java +++ b/apis/docker/src/main/java/org/jclouds/docker/domain/Info.java @@ -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> 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> 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); } } diff --git a/apis/docker/src/main/java/org/jclouds/docker/domain/NetworkSettings.java b/apis/docker/src/main/java/org/jclouds/docker/domain/NetworkSettings.java index f99bd7f3dd..fee82f2224 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/domain/NetworkSettings.java +++ b/apis/docker/src/main/java/org/jclouds/docker/domain/NetworkSettings.java @@ -42,6 +42,9 @@ public abstract class NetworkSettings { public abstract Map>> ports(); + NetworkSettings() { + } + @SerializedNames({ "IPAddress", "IPPrefixLen", "Gateway", "Bridge", "PortMapping", "Ports" }) public static NetworkSettings create(String ipAddress, int ipPrefixLen, String gateway, String bridge, String portMapping, Map>> ports) { diff --git a/apis/docker/src/main/java/org/jclouds/docker/domain/Port.java b/apis/docker/src/main/java/org/jclouds/docker/domain/Port.java index 0522be185d..b4bc93e1e1 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/domain/Port.java +++ b/apis/docker/src/main/java/org/jclouds/docker/domain/Port.java @@ -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); diff --git a/apis/docker/src/main/java/org/jclouds/docker/config/DockerProperties.java b/apis/docker/src/main/java/org/jclouds/docker/domain/Resource.java similarity index 69% rename from apis/docker/src/main/java/org/jclouds/docker/config/DockerProperties.java rename to apis/docker/src/main/java/org/jclouds/docker/domain/Resource.java index b870feac0f..701318ce08 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/config/DockerProperties.java +++ b/apis/docker/src/main/java/org/jclouds/docker/domain/Resource.java @@ -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); + } } diff --git a/apis/docker/src/main/java/org/jclouds/docker/domain/State.java b/apis/docker/src/main/java/org/jclouds/docker/domain/State.java index c0a8586029..1b3c809af3 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/domain/State.java +++ b/apis/docker/src/main/java/org/jclouds/docker/domain/State.java @@ -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); } } diff --git a/apis/docker/src/main/java/org/jclouds/docker/domain/StatusCode.java b/apis/docker/src/main/java/org/jclouds/docker/domain/StatusCode.java new file mode 100644 index 0000000000..0bdfdc735c --- /dev/null +++ b/apis/docker/src/main/java/org/jclouds/docker/domain/StatusCode.java @@ -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); + } +} diff --git a/apis/docker/src/main/java/org/jclouds/docker/domain/Version.java b/apis/docker/src/main/java/org/jclouds/docker/domain/Version.java index 7cf7960067..9002d41103 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/domain/Version.java +++ b/apis/docker/src/main/java/org/jclouds/docker/domain/Version.java @@ -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) { diff --git a/apis/docker/src/main/java/org/jclouds/docker/features/ContainerApi.java b/apis/docker/src/main/java/org/jclouds/docker/features/ContainerApi.java index 60f7749564..fb592c8597 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/features/ContainerApi.java +++ b/apis/docker/src/main/java/org/jclouds/docker/features/ContainerApi.java @@ -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 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 listContainers(ListContainerOptions options); /** - * Create a container - * * @param name the name for the new container. Must match /?[a-zA-Z0-9_-]+. * @param config the container’s 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 operation’s 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 container’s 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 container’s 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 container’s 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); } diff --git a/apis/docker/src/main/java/org/jclouds/docker/features/ImageApi.java b/apis/docker/src/main/java/org/jclouds/docker/features/ImageApi.java index 95c963c88d..9f7cebc0fd 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/features/ImageApi.java +++ b/apis/docker/src/main/java/org/jclouds/docker/features/ImageApi.java @@ -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 listImages(); + @Fallback(EmptyListOnNotFoundOr404.class) + List 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 listImages(ListImageOptions options); + @Fallback(EmptyListOnNotFoundOr404.class) + List 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. diff --git a/apis/docker/src/main/java/org/jclouds/docker/features/MiscApi.java b/apis/docker/src/main/java/org/jclouds/docker/features/MiscApi.java index 30cd1f31a9..6c49436632 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/features/MiscApi.java +++ b/apis/docker/src/main/java/org/jclouds/docker/features/MiscApi.java @@ -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 diff --git a/apis/docker/src/main/java/org/jclouds/docker/options/AttachOptions.java b/apis/docker/src/main/java/org/jclouds/docker/options/AttachOptions.java new file mode 100644 index 0000000000..95fb8b593c --- /dev/null +++ b/apis/docker/src/main/java/org/jclouds/docker/options/AttachOptions.java @@ -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); + } + + } + +} diff --git a/apis/docker/src/main/java/org/jclouds/docker/options/BuildOptions.java b/apis/docker/src/main/java/org/jclouds/docker/options/BuildOptions.java index 4d7196ceee..14bc4a4829 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/options/BuildOptions.java +++ b/apis/docker/src/main/java/org/jclouds/docker/options/BuildOptions.java @@ -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; diff --git a/apis/docker/src/main/java/org/jclouds/docker/options/CommitOptions.java b/apis/docker/src/main/java/org/jclouds/docker/options/CommitOptions.java index 5653fba57e..fbf35b6c3d 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/options/CommitOptions.java +++ b/apis/docker/src/main/java/org/jclouds/docker/options/CommitOptions.java @@ -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; diff --git a/apis/docker/src/main/java/org/jclouds/docker/options/CreateImageOptions.java b/apis/docker/src/main/java/org/jclouds/docker/options/CreateImageOptions.java index 51dc399d4d..91b8413c27 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/options/CreateImageOptions.java +++ b/apis/docker/src/main/java/org/jclouds/docker/options/CreateImageOptions.java @@ -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; diff --git a/apis/docker/src/main/java/org/jclouds/docker/options/DeleteImageOptions.java b/apis/docker/src/main/java/org/jclouds/docker/options/DeleteImageOptions.java index 9438616b56..1ac20d98e8 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/options/DeleteImageOptions.java +++ b/apis/docker/src/main/java/org/jclouds/docker/options/DeleteImageOptions.java @@ -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); + } } } diff --git a/apis/docker/src/main/java/org/jclouds/docker/options/ListContainerOptions.java b/apis/docker/src/main/java/org/jclouds/docker/options/ListContainerOptions.java index af16664010..7f73804c65 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/options/ListContainerOptions.java +++ b/apis/docker/src/main/java/org/jclouds/docker/options/ListContainerOptions.java @@ -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; diff --git a/apis/docker/src/main/java/org/jclouds/docker/options/ListImageOptions.java b/apis/docker/src/main/java/org/jclouds/docker/options/ListImageOptions.java index fab75d4233..613eff63ec 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/options/ListImageOptions.java +++ b/apis/docker/src/main/java/org/jclouds/docker/options/ListImageOptions.java @@ -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; diff --git a/apis/docker/src/main/java/org/jclouds/docker/options/RemoveContainerOptions.java b/apis/docker/src/main/java/org/jclouds/docker/options/RemoveContainerOptions.java index 5c3abba3a3..9334e69a4c 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/options/RemoveContainerOptions.java +++ b/apis/docker/src/main/java/org/jclouds/docker/options/RemoveContainerOptions.java @@ -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; diff --git a/apis/docker/src/main/java/org/jclouds/docker/suppliers/KeyStoreSupplier.java b/apis/docker/src/main/java/org/jclouds/docker/suppliers/KeyStoreSupplier.java deleted file mode 100644 index e8643cd9aa..0000000000 --- a/apis/docker/src/main/java/org/jclouds/docker/suppliers/KeyStoreSupplier.java +++ /dev/null @@ -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 { - private final Crypto crypto; - private final Supplier creds; - - @Inject - KeyStoreSupplier(Crypto crypto, @Provider Supplier 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 certs = (Collection) 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); - } - } -} diff --git a/apis/docker/src/main/java/org/jclouds/docker/suppliers/SSLContextWithKeysSupplier.java b/apis/docker/src/main/java/org/jclouds/docker/suppliers/SSLContextWithKeysSupplier.java index 59695d34bd..7aeee187e3 100644 --- a/apis/docker/src/main/java/org/jclouds/docker/suppliers/SSLContextWithKeysSupplier.java +++ b/apis/docker/src/main/java/org/jclouds/docker/suppliers/SSLContextWithKeysSupplier.java @@ -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 { - private final Supplier keyStore; private final TrustManager[] trustManager; private final Supplier creds; @Inject - SSLContextWithKeysSupplier(Supplier keyStore, @Provider Supplier creds, HttpUtils utils, - TrustAllCerts trustAllCerts) { - this.keyStore = keyStore; - this.trustManager = utils.trustAllCerts() ? new TrustManager[] { trustAllCerts } : null; + SSLContextWithKeysSupplier(@Provider Supplier 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}; + } + } + } diff --git a/apis/docker/src/test/java/org/jclouds/docker/compute/BaseDockerApiLiveTest.java b/apis/docker/src/test/java/org/jclouds/docker/compute/BaseDockerApiLiveTest.java index 9aca266574..447c9e4d68 100644 --- a/apis/docker/src/test/java/org/jclouds/docker/compute/BaseDockerApiLiveTest.java +++ b/apis/docker/src/test/java/org/jclouds/docker/compute/BaseDockerApiLiveTest.java @@ -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 { @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; } diff --git a/apis/docker/src/test/java/org/jclouds/docker/compute/DockerComputeServiceAdapterLiveTest.java b/apis/docker/src/test/java/org/jclouds/docker/compute/DockerComputeServiceAdapterLiveTest.java index c3da551d91..9aae9bffa4 100644 --- a/apis/docker/src/test/java/org/jclouds/docker/compute/DockerComputeServiceAdapterLiveTest.java +++ b/apis/docker/src/test/java/org/jclouds/docker/compute/DockerComputeServiceAdapterLiveTest.java @@ -116,10 +116,4 @@ public class DockerComputeServiceAdapterLiveTest extends BaseDockerApiLiveTest { return ImmutableSet.of(getLoggingModule(), new SshjSshClientModule()); } - @Override - protected Properties setupProperties() { - Properties properties = super.setupProperties(); - properties.setProperty("jclouds.ssh.max-retries", "10"); - return properties; - } } diff --git a/apis/docker/src/test/java/org/jclouds/docker/compute/functions/ContainerToNodeMetadataTest.java b/apis/docker/src/test/java/org/jclouds/docker/compute/functions/ContainerToNodeMetadataTest.java index 94ee205fb1..850863c1af 100644 --- a/apis/docker/src/test/java/org/jclouds/docker/compute/functions/ContainerToNodeMetadataTest.java +++ b/apis/docker/src/test/java/org/jclouds/docker/compute/functions/ContainerToNodeMetadataTest.java @@ -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) diff --git a/apis/docker/src/test/java/org/jclouds/docker/compute/functions/ImageToImageTest.java b/apis/docker/src/test/java/org/jclouds/docker/compute/functions/ImageToImageTest.java index 76d82ee753..db02e3dfd5 100644 --- a/apis/docker/src/test/java/org/jclouds/docker/compute/functions/ImageToImageTest.java +++ b/apis/docker/src/test/java/org/jclouds/docker/compute/functions/ImageToImageTest.java @@ -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(); } diff --git a/apis/docker/src/test/java/org/jclouds/docker/features/ContainerApiLiveTest.java b/apis/docker/src/test/java/org/jclouds/docker/features/ContainerApiLiveTest.java index 44edc573b9..684f5debb9 100644 --- a/apis/docker/src/test/java/org/jclouds/docker/features/ContainerApiLiveTest.java +++ b/apis/docker/src/test/java/org/jclouds/docker/features/ContainerApiLiveTest.java @@ -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 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(); } diff --git a/apis/docker/src/test/java/org/jclouds/docker/features/ContainerApiMockTest.java b/apis/docker/src/test/java/org/jclouds/docker/features/ContainerApiMockTest.java index 4bbff66fb6..ab3657b107 100644 --- a/apis/docker/src/test/java/org/jclouds/docker/features/ContainerApiMockTest.java +++ b/apis/docker/src/test/java/org/jclouds/docker/features/ContainerApiMockTest.java @@ -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 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 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 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(); } } diff --git a/apis/docker/src/test/java/org/jclouds/docker/features/ImageApiMockTest.java b/apis/docker/src/test/java/org/jclouds/docker/features/ImageApiMockTest.java index 7ad6414f52..5349c39c70 100644 --- a/apis/docker/src/test/java/org/jclouds/docker/features/ImageApiMockTest.java +++ b/apis/docker/src/test/java/org/jclouds/docker/features/ImageApiMockTest.java @@ -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(); } } diff --git a/apis/docker/src/test/java/org/jclouds/docker/features/MiscApiLiveTest.java b/apis/docker/src/test/java/org/jclouds/docker/features/MiscApiLiveTest.java index b14a1085e9..bfe1b40232 100644 --- a/apis/docker/src/test/java/org/jclouds/docker/features/MiscApiLiveTest.java +++ b/apis/docker/src/test/java/org/jclouds/docker/features/MiscApiLiveTest.java @@ -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(); } diff --git a/apis/docker/src/test/java/org/jclouds/docker/features/MiscApiMockTest.java b/apis/docker/src/test/java/org/jclouds/docker/features/MiscApiMockTest.java index e7b1e5b1b4..630d7af3b1 100644 --- a/apis/docker/src/test/java/org/jclouds/docker/features/MiscApiMockTest.java +++ b/apis/docker/src/test/java/org/jclouds/docker/features/MiscApiMockTest.java @@ -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(); } } diff --git a/apis/docker/src/test/java/org/jclouds/docker/internal/BaseDockerMockTest.java b/apis/docker/src/test/java/org/jclouds/docker/internal/BaseDockerMockTest.java index efdc9b5b2c..994519ece3 100644 --- a/apis/docker/src/test/java/org/jclouds/docker/internal/BaseDockerMockTest.java +++ b/apis/docker/src/test/java/org/jclouds/docker/internal/BaseDockerMockTest.java @@ -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 modules = ImmutableSet. 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. of()); - } - - protected static void assertRequestHasCommonFields(final RecordedRequest request, - final String verb, final String path) - throws InterruptedException { - assertRequestHasParameters(request, verb, path, ImmutableMultimap. of()); - } - - protected static void assertRequestHasParameters(final RecordedRequest request, final String path, - Multimap parameters) throws InterruptedException { - assertRequestHasParameters(request, "GET", path, parameters); - } - - protected static void assertRequestHasParameters(final RecordedRequest request, String verb, final String path, - Multimap parameters) throws InterruptedException { - String queryParameters = ""; - if (!parameters.isEmpty()) { - Multimap allparams = ImmutableMultimap.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; } } diff --git a/apis/docker/src/test/java/org/jclouds/docker/internal/BaseDockerParseTest.java b/apis/docker/src/test/java/org/jclouds/docker/internal/BaseDockerParseTest.java new file mode 100644 index 0000000000..5227ff8224 --- /dev/null +++ b/apis/docker/src/test/java/org/jclouds/docker/internal/BaseDockerParseTest.java @@ -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 extends BaseItemParserTest { + + @Override + protected Injector injector() { + return Guice.createInjector(new GsonModule(), new DockerParserModule()); + } + +} diff --git a/apis/docker/src/test/java/org/jclouds/docker/parse/ContainerParseTest.java b/apis/docker/src/test/java/org/jclouds/docker/parse/ContainerParseTest.java new file mode 100644 index 0000000000..dc5c791b03 --- /dev/null +++ b/apis/docker/src/test/java/org/jclouds/docker/parse/ContainerParseTest.java @@ -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 { + + @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.>>of( + "6783/tcp", ImmutableList.>of(ImmutableMap.of("HostIp", "0.0.0.0", "HostPort", "6783")), + "6783/udp", ImmutableList.>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.>>of( + "6783/tcp", ImmutableList.>of(ImmutableMap.of("HostIp", "", "HostPort", "6783")), + "6783/udp", ImmutableList.>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(); + } +} diff --git a/apis/docker/src/test/java/org/jclouds/docker/parse/ContainersParseTest.java b/apis/docker/src/test/java/org/jclouds/docker/parse/ContainersParseTest.java new file mode 100644 index 0000000000..bb3bd623be --- /dev/null +++ b/apis/docker/src/test/java/org/jclouds/docker/parse/ContainersParseTest.java @@ -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> { + + @Override + public String resource() { + return "/containers.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public List 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") + ); + } + +} diff --git a/apis/docker/src/test/java/org/jclouds/docker/parse/ImageParseTest.java b/apis/docker/src/test/java/org/jclouds/docker/parse/ImageParseTest.java new file mode 100644 index 0000000000..038be863a0 --- /dev/null +++ b/apis/docker/src/test/java/org/jclouds/docker/parse/ImageParseTest.java @@ -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 { + + @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); + } +} diff --git a/apis/docker/src/test/java/org/jclouds/docker/parse/ImagesParseTest.java b/apis/docker/src/test/java/org/jclouds/docker/parse/ImagesParseTest.java new file mode 100644 index 0000000000..d2ef5b6074 --- /dev/null +++ b/apis/docker/src/test/java/org/jclouds/docker/parse/ImagesParseTest.java @@ -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> { + + @Override + public String resource() { + return "/images.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public List expected() { + return ImmutableList.of( + ImageSummary.create("cbba6639a342646deed70d7ea6162fa2a0acea9300f911f4e014555fe37d3456", + 1416827360, + "05794515afd5724df1cdf0e674ae932455fce7dea3c70a94d77119ad1fa954ba", + 0, + 808709069, + ImmutableList.of("test:latest")), + ImageSummary.create("e1e548b03259ae30ba12232b6c16ef5205cf71b0363848e78b0394e1ecba4f57", + 1416826851, + "6f36bec79c7f184ceebf7000cfb7244c4bc9b397b6659ac7f420a53d114250d9", + 0, + 5609404, + ImmutableList.of(":")), + 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")) + ); + } + +} diff --git a/apis/docker/src/test/java/org/jclouds/docker/parse/InfoParseTest.java b/apis/docker/src/test/java/org/jclouds/docker/parse/InfoParseTest.java new file mode 100644 index 0000000000..5527e28845 --- /dev/null +++ b/apis/docker/src/test/java/org/jclouds/docker/parse/InfoParseTest.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.docker.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 { + + @Override + public String resource() { + return "/info.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Info expected() { + return Info.create(0, + 1, + "aufs", + ImmutableList.>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); + } +} diff --git a/apis/docker/src/test/java/org/jclouds/docker/parse/VersionParseTest.java b/apis/docker/src/test/java/org/jclouds/docker/parse/VersionParseTest.java new file mode 100644 index 0000000000..2d9781bc47 --- /dev/null +++ b/apis/docker/src/test/java/org/jclouds/docker/parse/VersionParseTest.java @@ -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 { + + @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"); + } +} diff --git a/apis/docker/src/test/resources/cert.pem b/apis/docker/src/test/resources/cert.pem new file mode 100644 index 0000000000..ab2c41a74e --- /dev/null +++ b/apis/docker/src/test/resources/cert.pem @@ -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----- diff --git a/apis/docker/src/test/resources/image.json b/apis/docker/src/test/resources/image.json new file mode 100644 index 0000000000..8d34de7e41 --- /dev/null +++ b/apis/docker/src/test/resources/image.json @@ -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 +} \ No newline at end of file diff --git a/apis/docker/src/test/resources/images.json b/apis/docker/src/test/resources/images.json new file mode 100644 index 0000000000..41d4f12f4b --- /dev/null +++ b/apis/docker/src/test/resources/images.json @@ -0,0 +1,42 @@ +[ + { + "Created": 1416827360, + "Id": "cbba6639a342646deed70d7ea6162fa2a0acea9300f911f4e014555fe37d3456", + "ParentId": "05794515afd5724df1cdf0e674ae932455fce7dea3c70a94d77119ad1fa954ba", + "RepoTags": [ + "test:latest" + ], + "Size": 0, + "VirtualSize": 808709069 + }, + { + "Created": 1416826851, + "Id": "e1e548b03259ae30ba12232b6c16ef5205cf71b0363848e78b0394e1ecba4f57", + "ParentId": "6f36bec79c7f184ceebf7000cfb7244c4bc9b397b6659ac7f420a53d114250d9", + "RepoTags": [ + ":" + ], + "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 + } +] \ No newline at end of file diff --git a/apis/docker/src/test/resources/key.pem b/apis/docker/src/test/resources/key.pem new file mode 100644 index 0000000000..23ebe5ea3b --- /dev/null +++ b/apis/docker/src/test/resources/key.pem @@ -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-----