Promoted Docker from jclouds-labs

This commit is contained in:
Ignasi Barrera 2016-08-30 11:14:20 +02:00
commit c493e2aa49
116 changed files with 11616 additions and 0 deletions

89
apis/docker/README.md Normal file
View File

@ -0,0 +1,89 @@
# Docker as a local cloud provider
jclouds-docker is a local cloud provider modelled on [docker](http://www.docker.io). Similar to other jclouds supported
providers, it supports the same portable abstractions offered by jclouds.
## Setup
Please follow these steps to configure your workstation for jclouds-docker:
- install the latest Docker release (please visit https://docs.docker.com/installation/)
- [enable remote access](https://docs.docker.com/engine/quickstart/#bind-docker-to-another-host-port-or-a-unix-socket) to Docker
### Sample configuration for Linux systems using systemd
Run following commands on a machine where is the Docker Engine installed.
It enables remote access (plain TCP - only for loopback address 127.0.0.1)
on standard port `2375`.
```bash
# switch to root account
sudo su -
# create override for docker start-script
mkdir /etc/systemd/system/docker.service.d
cat << EOT > /etc/systemd/system/docker.service.d/allow-tcp.conf
[Service]
ExecStart=
ExecStart=/usr/bin/docker daemon -H fd:// -H tcp://
EOT
# reload configuration and restart docker daemon
systemctl daemon-reload
systemctl restart docker
# close the 'root' session
exit
```
If the `-H fd://` Docker daemon parameter doesn't work on your Linux (e.g. Fedora),
then replace it by `-H unix:///var/run/docker.sock`
Find more details in [Control and configure Docker with systemd](https://docs.docker.com/engine/admin/systemd/) guide.
### Running live tests
The `DOCKER_HOST` environment variable has to be configured as it's used as a value for `test.docker.endpoint` system property.
```
export DOCKER_HOST="http://localhost:2375/"
mvn -Plive integration-test
```
# How it works
--------------- -------------
| Image(s) | | Node(s) |
--------------- -------------
--------- docker remote api ----------------------------------------
| jclouds | ---------------------------> | DOCKER_HOST |
--------- ----------------------------------------
## Components
- jclouds \- acts as a java client to access to docker features
- DOCKER_HOST \- hosts Docker API, NB: jclouds-docker assumes that the latest Docker is installed
- Image \- it is a docker image that can be started.
- Node \- is a docker container
## Assumptions
- jclouds-docker assumes that the images specified using the template are ssh'able.
--------------
# Notes:
- report any issues you find at [jclouds issues](https://issues.apache.org/jira/browse/JCLOUDS)
- jclouds-docker has been tested on Mac OSX and Linux. However, it has never been tried on Windows.
--------------
# Troubleshooting
As jclouds docker support is quite new, issues may occasionally arise.
You can try to remove all containers to get things going again:
```bash
docker rm -f `docker ps -aq`
```

192
apis/docker/pom.xml Normal file
View File

@ -0,0 +1,192 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.jclouds.labs</groupId>
<artifactId>jclouds-labs</artifactId>
<version>2.0.0-SNAPSHOT</version>
</parent>
<!-- TODO: when out of labs, switch to org.jclouds.provider -->
<groupId>org.apache.jclouds.labs</groupId>
<artifactId>docker</artifactId>
<name>jclouds docker API</name>
<description>ComputeService binding to the Docker API</description>
<packaging>bundle</packaging>
<properties>
<test.docker.api-version>1.21</test.docker.api-version>
<test.docker.identity>${env.DOCKER_CERT_PATH}/cert.pem</test.docker.identity>
<test.docker.credential>${env.DOCKER_CERT_PATH}/key.pem</test.docker.credential>
<test.docker.cacert.path>${env.DOCKER_CERT_PATH}/ca.pem</test.docker.cacert.path>
<test.docker.endpoint>${env.DOCKER_HOST}</test.docker.endpoint>
<test.jclouds.trust-all-certs>false</test.jclouds.trust-all-certs>
<jclouds.osgi.export>org.jclouds.docker*;version="${project.version}"</jclouds.osgi.export>
<jclouds.osgi.import>
org.jclouds.compute.internal;version="${project.version}",
org.jclouds.rest.internal;version="${project.version}",
org.jclouds*;version="${project.version}",
*
</jclouds.osgi.import>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-compute</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.jclouds.driver</groupId>
<artifactId>jclouds-sshj</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jclouds.driver</groupId>
<artifactId>jclouds-bouncycastle</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jclouds.driver</groupId>
<artifactId>jclouds-okhttp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibindings</artifactId>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-compute</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.jclouds.driver</groupId>
<artifactId>jclouds-slf4j</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>mockwebserver</artifactId>
<scope>test</scope>
<exclusions>
<!-- Already provided by jclouds-sshj -->
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap</groupId>
<artifactId>shrinkwrap-depchain</artifactId>
<version>1.2.2</version>
<type>pom</type>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>live</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.9.1</version>
<executions>
<execution>
<id>regex-property</id>
<goals>
<goal>regex-property</goal>
</goals>
<configuration>
<name>test.docker.endpoint</name>
<value>${test.docker.endpoint}</value>
<regex>tcp</regex>
<replacement>https</replacement>
<failIfNoMatch>false</failIfNoMatch>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>integration</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<threadCount>1</threadCount>
<systemPropertyVariables>
<test.docker.endpoint>${test.docker.endpoint}</test.docker.endpoint>
<test.docker.api-version>${test.docker.api-version}</test.docker.api-version>
<test.docker.identity>${test.docker.identity}</test.docker.identity>
<test.docker.credential>${test.docker.credential}</test.docker.credential>
<test.docker.cacert.path>${test.docker.cacert.path}</test.docker.cacert.path>
<test.jclouds.trust-all-certs>${test.jclouds.trust-all-certs}</test.jclouds.trust-all-certs>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker;
import java.io.Closeable;
import org.jclouds.docker.features.ContainerApi;
import org.jclouds.docker.features.ImageApi;
import org.jclouds.docker.features.MiscApi;
import org.jclouds.docker.features.NetworkApi;
import org.jclouds.rest.annotations.Delegate;
public interface DockerApi extends Closeable {
@Delegate
MiscApi getMiscApi();
@Delegate
ContainerApi getContainerApi();
@Delegate
ImageApi getImageApi();
@Delegate
NetworkApi getNetworkApi();
}

View File

@ -0,0 +1,100 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker;
import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE;
import static org.jclouds.reflect.Reflection2.typeToken;
import java.net.URI;
import java.util.Properties;
import org.jclouds.Constants;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.config.ComputeServiceProperties;
import org.jclouds.docker.compute.config.DockerComputeServiceContextModule;
import org.jclouds.docker.config.DockerHttpApiModule;
import org.jclouds.docker.config.DockerParserModule;
import org.jclouds.rest.internal.BaseHttpApiMetadata;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
@AutoService(ApiMetadata.class)
public class DockerApiMetadata extends BaseHttpApiMetadata<DockerApi> {
public static final String DOCKER_CA_CERT_PATH = "docker.cacert.path";
public static final String DOCKER_CA_CERT_DATA = "docker.cacert.data";
@Override
public Builder toBuilder() {
return new Builder().fromApiMetadata(this);
}
public DockerApiMetadata() {
this(new Builder());
}
protected DockerApiMetadata(Builder builder) {
super(builder);
}
public static Properties defaultProperties() {
Properties properties = BaseHttpApiMetadata.defaultProperties();
properties.setProperty(Constants.PROPERTY_CONNECTION_TIMEOUT, "1200000"); // 15 minutes
properties.setProperty(ComputeServiceProperties.IMAGE_LOGIN_USER, "root:password");
properties.setProperty(TEMPLATE, "osFamily=UBUNTU,os64Bit=true");
properties.setProperty(DOCKER_CA_CERT_PATH, "");
properties.setProperty(DOCKER_CA_CERT_DATA, "");
return properties;
}
public static class Builder extends BaseHttpApiMetadata.Builder<DockerApi, Builder> {
protected Builder() {
super(DockerApi.class);
id("docker")
.name("Docker API")
.identityName("Path or data for certificate .pem file")
.credentialName("Path or data for key .pem file")
.documentation(URI.create("https://docs.docker.com/reference/api/docker_remote_api/"))
.version("1.21")
.defaultEndpoint("https://127.0.0.1:2376")
.defaultProperties(DockerApiMetadata.defaultProperties())
.view(typeToken(ComputeServiceContext.class))
.defaultModules(ImmutableSet.<Class<? extends Module>>of(
DockerParserModule.class,
DockerHttpApiModule.class,
DockerComputeServiceContextModule.class));
}
@Override
public DockerApiMetadata build() {
return new DockerApiMetadata(this);
}
@Override
protected Builder self() {
return this;
}
@Override
public Builder fromApiMetadata(ApiMetadata in) {
return this;
}
}
}

View File

@ -0,0 +1,62 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute.config;
import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.docker.compute.functions.ContainerToNodeMetadata;
import org.jclouds.docker.compute.functions.ImageToImage;
import org.jclouds.docker.compute.functions.StateToStatus;
import org.jclouds.docker.compute.options.DockerTemplateOptions;
import org.jclouds.docker.compute.strategy.DockerComputeServiceAdapter;
import org.jclouds.docker.domain.Container;
import org.jclouds.docker.domain.Image;
import org.jclouds.docker.domain.State;
import org.jclouds.domain.Location;
import org.jclouds.functions.IdentityFunction;
import com.google.common.base.Function;
import com.google.inject.TypeLiteral;
public class DockerComputeServiceContextModule extends
ComputeServiceAdapterContextModule<Container, Hardware, Image, Location> {
@SuppressWarnings("unchecked")
@Override
protected void configure() {
super.configure();
bind(new TypeLiteral<ComputeServiceAdapter<Container, Hardware, Image, Location>>() {
}).to(DockerComputeServiceAdapter.class);
bind(new TypeLiteral<Function<Container, NodeMetadata>>() {
}).to(ContainerToNodeMetadata.class);
bind(new TypeLiteral<Function<Image, org.jclouds.compute.domain.Image>>() {
}).to(ImageToImage.class);
bind(new TypeLiteral<Function<Hardware, Hardware>>() {
}).to(Class.class.cast(IdentityFunction.class));
bind(new TypeLiteral<Function<Location, Location>>() {
}).to(Class.class.cast(IdentityFunction.class));
bind(new TypeLiteral<Function<State, NodeMetadata.Status>>() {
}).to(StateToStatus.class);
bind(TemplateOptions.class).to(DockerTemplateOptions.class);
install(new LoginPortLookupModule());
}
}

View File

@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute.config;
import org.jclouds.docker.compute.functions.LoginPortForContainer;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.multibindings.MapBinder;
public class LoginPortLookupModule extends AbstractModule {
@Override
protected void configure() {
// Declare it to initialize the binder allowing duplicates. Users may
// provide different functions for the same image in different modules, or
// we could provide predefined functions for known images. This allows
// users to set their own ones too.
loginPortLookupBinder(binder());
}
public static MapBinder<String, LoginPortForContainer> loginPortLookupBinder(Binder binder) {
return MapBinder.newMapBinder(binder, String.class, LoginPortForContainer.class).permitDuplicates();
}
}

View File

@ -0,0 +1,141 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute.functions;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.domain.HardwareBuilder;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.Processor;
import org.jclouds.compute.functions.GroupNamingConvention;
import org.jclouds.docker.domain.Container;
import org.jclouds.docker.domain.NetworkSettings;
import org.jclouds.docker.domain.State;
import org.jclouds.domain.Location;
import org.jclouds.providers.ProviderMetadata;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.inject.Singleton;
@Singleton
public class ContainerToNodeMetadata implements Function<Container, NodeMetadata> {
/**
* This value is used when a container does not have an accessible
* login port (i.e. the SSH daemon is not running) due to being
* started outside jclouds. Client code should check for this value
* when accessing NodeMetadata from Docker.
*/
private static final Integer NO_LOGIN_PORT = Integer.valueOf(-1);
private final ProviderMetadata providerMetadata;
private final Function<State, NodeMetadata.Status> toPortableStatus;
private final GroupNamingConvention nodeNamingConvention;
private final Supplier<Map<String, ? extends Image>> images;
private final Supplier<Set<? extends Location>> locations;
private final LoginPortForContainer loginPortForContainer;
@Inject
ContainerToNodeMetadata(ProviderMetadata providerMetadata,
Function<State, NodeMetadata.Status> toPortableStatus, GroupNamingConvention.Factory namingConvention,
Supplier<Map<String, ? extends Image>> images, @Memoized Supplier<Set<? extends Location>> locations,
LoginPortForContainer loginPortForContainer) {
this.providerMetadata = providerMetadata;
this.toPortableStatus = toPortableStatus;
this.nodeNamingConvention = namingConvention.createWithoutPrefix();
this.images = images;
this.locations = locations;
this.loginPortForContainer = loginPortForContainer;
}
@Override
public NodeMetadata apply(Container container) {
String name = cleanUpName(container.name());
String group = nodeNamingConvention.extractGroup(name);
NodeMetadataBuilder builder = new NodeMetadataBuilder();
builder.ids(container.id())
.name(name)
.group(group)
.hostname(container.config().hostname())
// TODO Set up hardware
.hardware(new HardwareBuilder()
.id("")
.ram(container.config().memory())
.processor(new Processor(container.config().cpuShares(), container.config().cpuShares()))
.build());
builder.status(toPortableStatus.apply(container.state()));
builder.loginPort(loginPortForContainer.apply(container).or(NO_LOGIN_PORT));
builder.publicAddresses(getPublicIpAddresses(container));
builder.privateAddresses(getPrivateIpAddresses(container));
builder.location(Iterables.getOnlyElement(locations.get()));
String imageId = container.image();
builder.imageId(imageId);
if (images.get().containsKey(imageId)) {
Image image = images.get().get(imageId);
builder.operatingSystem(image.getOperatingSystem());
}
return builder.build();
}
private String cleanUpName(String name) {
return name.startsWith("/") ? name.substring(1) : name;
}
private Iterable<String> getPrivateIpAddresses(Container container) {
// A container can be attached to multiple networks. It can therefore have multiple private
// IPs. The NetworkSettings.ipAddress might in fact be blank, with the only IP being on
// network objects.
if (container.networkSettings() == null) return ImmutableList.of();
ImmutableSet.Builder<String> builder = ImmutableSet.<String>builder();
NetworkSettings settings = container.networkSettings();
if (settings.ipAddress() != null && settings.ipAddress().length() > 0) {
builder.add(settings.ipAddress());
}
if (settings.networks() != null) {
for (Map.Entry<String, NetworkSettings.Details> entry : settings.networks().entrySet()) {
String ipAddress = entry.getValue().ipAddress();
if (ipAddress != null && ipAddress.length() > 0) {
builder.add(ipAddress);
}
}
}
return builder.build();
}
private List<String> getPublicIpAddresses(Container container) {
String dockerIpAddress;
if (container.node().isPresent()) {
dockerIpAddress = container.node().get().ip();
} else {
dockerIpAddress = URI.create(providerMetadata.getEndpoint()).getHost();
}
return ImmutableList.of(dockerIpAddress);
}
}

View File

@ -0,0 +1,84 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute.functions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.docker.domain.Container;
import com.google.common.annotations.Beta;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Maps;
@Beta
public class CustomLoginPortFromImage implements LoginPortForContainer {
private final Map<String, Set<LoginPortForContainer>> imageToPortLookup;
@Inject
CustomLoginPortFromImage(Map<String, Set<LoginPortForContainer>> imageToPortLookup) {
this.imageToPortLookup = imageToPortLookup;
}
@Override
public Optional<Integer> apply(final Container container) {
Map<String, Set<LoginPortForContainer>> matchingFunctions = Maps.filterKeys(imageToPortLookup,
new Predicate<String>() {
@Override
public boolean apply(String input) {
return container.config().image().matches(input);
}
});
// We allow to provide several forms in the image-to-function map:
// - redis
// - redis:12
// - owner/redis:12
// - registry:5000/owner/redis:12
// We consider the longest match first, as it is the more accurate one
List<String> sortedImages = new ArrayList<String>(matchingFunctions.keySet());
Collections.sort(sortedImages, LongestStringFirst);
for (String currentImage : sortedImages) {
Set<LoginPortForContainer> functions = matchingFunctions.get(currentImage);
for (LoginPortForContainer function : functions) {
Optional<Integer> port = function.apply(container);
if (port.isPresent()) {
return port;
}
}
}
return Optional.absent();
}
private static final Comparator<String> LongestStringFirst = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s2.length() - s1.length();
}
};
}

View File

@ -0,0 +1,103 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.annotation.Resource;
import javax.inject.Named;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageBuilder;
import org.jclouds.compute.domain.OperatingSystem;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
public class ImageToImage implements Function<org.jclouds.docker.domain.Image, org.jclouds.compute.domain.Image> {
private static final String CENTOS = "centos";
private static final String UBUNTU = "ubuntu";
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
@Override
public Image apply(org.jclouds.docker.domain.Image from) {
checkNotNull(from, "image");
String firstRepoTag = Iterables.getFirst(from.repoTags(), "<none>");
final int versionSeparatorPos = firstRepoTag.lastIndexOf(':');
final String name;
final String osVersion;
if (versionSeparatorPos > -1) {
name = firstRepoTag.substring(0, versionSeparatorPos);
osVersion = firstRepoTag.substring(versionSeparatorPos + 1);
} else {
name = firstRepoTag;
osVersion = firstRepoTag;
}
logger.debug("os version for item: %s is %s", firstRepoTag, osVersion);
OsFamily osFamily = osFamily().apply(firstRepoTag);
OperatingSystem os = OperatingSystem.builder()
.description(firstRepoTag)
.family(osFamily)
.version(osVersion)
.is64Bit(is64bit(from))
.build();
return new ImageBuilder()
.ids(from.id())
.name(name)
.description(firstRepoTag)
.operatingSystem(os)
.status(Image.Status.AVAILABLE)
.build();
}
private boolean is64bit(org.jclouds.docker.domain.Image inspectedImage) {
if (inspectedImage.architecture() == null) return true;
return inspectedImage.architecture().matches("x86_64|amd64");
}
/**
* Parses the item description to determine the OSFamily
*
* @return the @see OsFamily or OsFamily.UNRECOGNIZED
*/
private Function<String, OsFamily> osFamily() {
return new Function<String, OsFamily>() {
@Override
public OsFamily apply(final String description) {
if (description != null) {
if (description.contains(CENTOS)) return OsFamily.CENTOS;
else if (description.contains(UBUNTU)) return OsFamily.UBUNTU;
}
return OsFamily.UNRECOGNIZED;
}
};
}
}

View File

@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute.functions;
import javax.inject.Inject;
import org.jclouds.docker.compute.functions.LoginPortForContainer.LoginPortLookupChain;
import org.jclouds.docker.domain.Container;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.inject.ImplementedBy;
@Beta
@ImplementedBy(LoginPortLookupChain.class)
public interface LoginPortForContainer extends Function<Container, Optional<Integer>> {
@Beta
static final class LoginPortLookupChain implements LoginPortForContainer {
private final PublicPortForContainerPort publicPortForContainerPort;
private final CustomLoginPortFromImage customLoginPortFromImage;
@Inject
LoginPortLookupChain(CustomLoginPortFromImage customLoginPortFromImage) {
this.publicPortForContainerPort = new PublicPortForContainerPort(22);
this.customLoginPortFromImage = customLoginPortFromImage;
}
@Override
public Optional<Integer> apply(Container input) {
Optional<Integer> loginPort = publicPortForContainerPort.apply(input);
return loginPort.isPresent() ? loginPort : customLoginPortFromImage.apply(input);
}
}
}

View File

@ -0,0 +1,58 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute.functions;
import static com.google.common.collect.Iterables.getOnlyElement;
import java.util.List;
import java.util.Map;
import org.jclouds.docker.domain.Container;
import org.jclouds.docker.domain.Port;
import com.google.common.annotations.Beta;
import com.google.common.base.Optional;
@Beta
public class PublicPortForContainerPort implements LoginPortForContainer {
private final int containerPort;
public PublicPortForContainerPort(int containerPort) {
this.containerPort = containerPort;
}
@Override
public Optional<Integer> apply(Container container) {
if (container.networkSettings() != null) {
Map<String, List<Map<String, String>>> ports = container.networkSettings().ports();
if (ports != null && ports.containsKey(containerPort + "/tcp")) {
return Optional.of(Integer.parseInt(getOnlyElement(ports.get(containerPort + "/tcp")).get("HostPort")));
}
// this is needed in case the container list is coming from
// listContainers
} else if (container.ports() != null) {
for (Port port : container.ports()) {
if (port.privatePort() == containerPort) {
return Optional.of(port.publicPort());
}
}
}
return Optional.absent();
}
}

View File

@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute.functions;
import javax.inject.Singleton;
import org.jclouds.compute.domain.NodeMetadata.Status;
import org.jclouds.docker.domain.State;
import com.google.common.base.Function;
/**
* Transforms an {@link org.jclouds.docker.domain.Container} to the jclouds portable model.
*/
@Singleton
public class StateToStatus implements Function<State, Status> {
@Override
public Status apply(final State state) {
if (state == null) return Status.UNRECOGNIZED;
return state.running() ? Status.RUNNING : Status.TERMINATED;
}
}

View File

@ -0,0 +1,780 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute.options;
import static com.google.common.base.Objects.equal;
import java.util.List;
import java.util.Map;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.docker.domain.Config;
import org.jclouds.docker.internal.NullSafeCopies;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.scriptbuilder.domain.Statement;
/**
* Contains options supported by the
* {@link org.jclouds.compute.ComputeService#createNodesInGroup(String, int, TemplateOptions)
* createNodes} operation on the <em>docker</em> provider.
*
* <h2>Usage</h2>
*
* The recommended way to instantiate a DockerTemplateOptions object is to
* statically import {@code DockerTemplateOptions.Builder.*} and invoke one of
* the static creation methods, followed by an instance mutator if needed.
*
* <pre>
* {@code import static org.jclouds.docker.compute.options.DockerTemplateOptions.Builder.*;
*
* ComputeService api = // get connection
* templateBuilder.options(inboundPorts(22, 80, 8080, 443));
* Set<? extends NodeMetadata> set = api.createNodesInGroup(tag, 2, templateBuilder.build());}
* </pre>
*
* <h2>Advanced Usage</h2>
* <p>
* In addition to basic configuration through its methods, this class also
* provides possibility to work directly with Docker API configuration object (
* {@link Config.Builder}). When the
* {@link #configBuilder(org.jclouds.docker.domain.Config.Builder)} is used to
* configure not-<code>null</code> configBuilder, then this configuration object
* takes precedence over the other configuration in this class (i.e. the other
* config entries are not used)
* </p>
* <p>
* Note: The {@code image} property in the provided {@link Config.Builder} is rewritten by a placeholder value.
* The real value is configured by ComputeServiceAdapter.
* </p>
*
* <pre>
* {@code import static org.jclouds.docker.compute.options.DockerTemplateOptions.Builder.*;
*
* ComputeService api = // get connection
* DockerTemplateOptions options = DockerTemplateOptions.Builder
* .configBuilder(
* Config.builder().env(ImmutableList.<String> of("SSH_PORT=8822"))
* .hostConfig(HostConfig.builder().networkMode("host").build()));
* templateBuilder.options(options);
* Set<? extends NodeMetadata> set = api.createNodesInGroup("sample-group", 1, templateBuilder.build());}
* </pre>
*/
public class DockerTemplateOptions extends TemplateOptions implements Cloneable {
private static final String NO_IMAGE = "jclouds-placeholder-for-image";
protected List<String> dns = ImmutableList.of();
@Nullable protected String hostname;
@Nullable protected Integer memory;
@Nullable protected Integer cpuShares;
@Nullable List<String> entrypoint;
@Nullable List<String> commands;
protected Map<String, String> volumes = ImmutableMap.of();
@Nullable protected List<String> env;
protected Map<Integer, Integer> portBindings = ImmutableMap.of();
@Nullable protected String networkMode;
protected Map<String, String> extraHosts = ImmutableMap.of();
protected List<String> volumesFrom = ImmutableList.of();
protected boolean privileged;
protected boolean openStdin;
protected Config.Builder configBuilder;
@Override
public DockerTemplateOptions clone() {
DockerTemplateOptions options = new DockerTemplateOptions();
copyTo(options);
return options;
}
@Override
public void copyTo(TemplateOptions to) {
super.copyTo(to);
if (to instanceof DockerTemplateOptions) {
DockerTemplateOptions eTo = DockerTemplateOptions.class.cast(to);
eTo.volumes(volumes);
eTo.hostname(hostname);
eTo.dns(dns);
eTo.memory(memory);
eTo.cpuShares(cpuShares);
eTo.entrypoint(entrypoint);
eTo.commands(commands);
eTo.env(env);
eTo.portBindings(portBindings);
eTo.networkMode(networkMode);
eTo.extraHosts(extraHosts);
eTo.volumesFrom(volumesFrom);
eTo.privileged(privileged);
eTo.openStdin(openStdin);
eTo.configBuilder(configBuilder);
}
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
DockerTemplateOptions that = DockerTemplateOptions.class.cast(o);
return super.equals(that) &&
equal(this.volumes, that.volumes) &&
equal(this.hostname, that.hostname) &&
equal(this.dns, that.dns) &&
equal(this.memory, that.memory) &&
equal(this.cpuShares, that.cpuShares) &&
equal(this.entrypoint, that.entrypoint) &&
equal(this.commands, that.commands) &&
equal(this.env, that.env) &&
equal(this.portBindings, that.portBindings) &&
equal(this.networkMode, that.networkMode) &&
equal(this.extraHosts, that.extraHosts) &&
equal(this.volumesFrom, that.volumesFrom) &&
equal(this.privileged, that.privileged) &&
equal(this.openStdin, that.openStdin) &&
buildersEqual(this.configBuilder, that.configBuilder);
}
/**
* Compares two Config.Builder instances.
*/
private boolean buildersEqual(Config.Builder b1, Config.Builder b2) {
return b1 == b2 || (b1 != null && b2 != null && b1.build().equals(b2.build()));
}
@Override
public int hashCode() {
return Objects.hashCode(super.hashCode(), volumes, hostname, dns, memory, entrypoint, commands, cpuShares, env,
portBindings, networkMode, extraHosts, volumesFrom, privileged, openStdin, configBuilder);
}
@Override
public String toString() {
return Objects.toStringHelper(this)
.add("volumes", volumes)
.add("hostname", hostname)
.add("dns", dns)
.add("memory", memory)
.add("cpuShares", cpuShares)
.add("entrypoint", entrypoint)
.add("commands", commands)
.add("env", env)
.add("portBindings", portBindings)
.add("networkMode", networkMode)
.add("extraHosts", extraHosts)
.add("volumesFrom", volumesFrom)
.add("privileged", privileged)
.add("openStdin", openStdin)
.add("configBuilder", configBuilder)
.toString();
}
public DockerTemplateOptions volumes(Map<String, String> volumes) {
this.volumes = NullSafeCopies.copyOf(volumes);
return this;
}
public DockerTemplateOptions dns(Iterable<String> dns) {
this.dns = NullSafeCopies.copyOf(dns);
return this;
}
public DockerTemplateOptions dns(String...dns) {
this.dns = NullSafeCopies.copyOf(dns);
return this;
}
public DockerTemplateOptions hostname(@Nullable String hostname) {
this.hostname = hostname;
return this;
}
public DockerTemplateOptions memory(@Nullable Integer memory) {
this.memory = memory;
return this;
}
public DockerTemplateOptions entrypoint(Iterable<String> entrypoint) {
this.entrypoint = NullSafeCopies.copyWithNullOf(entrypoint);
return this;
}
public DockerTemplateOptions entrypoint(String... entrypoint) {
this.entrypoint = NullSafeCopies.copyWithNullOf(entrypoint);
return this;
}
public DockerTemplateOptions commands(Iterable<String> commands) {
this.commands = NullSafeCopies.copyWithNullOf(commands);
return this;
}
public DockerTemplateOptions commands(String...commands) {
this.commands = NullSafeCopies.copyWithNullOf(commands);
return this;
}
public DockerTemplateOptions cpuShares(@Nullable Integer cpuShares) {
this.cpuShares = cpuShares;
return this;
}
public DockerTemplateOptions env(Iterable<String> env) {
this.env = NullSafeCopies.copyWithNullOf(env);
return this;
}
public DockerTemplateOptions env(String...env) {
this.env = NullSafeCopies.copyWithNullOf(env);
return this;
}
/**
* Set port bindings between the Docker host and a container.
* <p>
* The {@link Map} keys are host ports number, and the value for an entry is the
* container port number. This is the same order as the arguments for the
* {@code --publish} command-line option to {@code docker run} which is
* {@code hostPort:containerPort}.
*
* @param portBindings the map of host to container port bindings
*/
public DockerTemplateOptions portBindings(Map<Integer, Integer> portBindings) {
this.portBindings = NullSafeCopies.copyOf(portBindings);
return this;
}
/**
* Sets the networking mode for the container.
* <p>
* Supported values are: {@code bridge}, {@code none}, {@code host},
* {@code networkname}, {@code networkid} or {@code container:[name|id]}
*
* @param networkMode
* @return this instance
*/
public DockerTemplateOptions networkMode(@Nullable String networkMode) {
this.networkMode = networkMode;
return this;
}
/**
* Set extra hosts file entries for a container.
* <p>
* The {@link Map} keys are host names, and the value is an IP address that
* can be accessed by the container. This is the same order as the arguments for the
* {@code --add-host} command-line option to {@code docker run}.
*
* @param extraHosts the map of host names to IP addresses
*/
public DockerTemplateOptions extraHosts(Map<String, String> extraHosts) {
this.extraHosts = NullSafeCopies.copyOf(extraHosts);
return this;
}
/**
* Set list of containers to mount volumes from onto this container.
*
* @param volumesFrom the list of container names
*/
public DockerTemplateOptions volumesFrom(Iterable<String> volumesFrom) {
this.volumesFrom = NullSafeCopies.copyOf(volumesFrom);
return this;
}
/**
* By default, Docker containers are unprivileged and cannot execute privileged operations or access certain
* host devices.
*
* @param privileged Whether the container should run in privileged mode or not
* @return this instance
*/
public DockerTemplateOptions privileged(boolean privileged) {
this.privileged = privileged;
return this;
}
/**
* Keep {@code STDIN} open when running interactive workloads in the container.
*
* @param openStdin Whether the container should keep STDIN open
* @return this instance
*/
public DockerTemplateOptions openStdin(boolean openStdin) {
this.openStdin = openStdin;
return this;
}
/**
* This method sets Config.Builder configuration object, which can be used as
* a replacement for all the other settings from this class. Some values in
* the provided Config.Builder instance (the image name for instance) can be
* ignored or their value can be changed.
*
* @param configBuilder
* Config.Builder instance. This instance can be changed in this
* method!
*/
public DockerTemplateOptions configBuilder(Config.Builder configBuilder) {
this.configBuilder = configBuilder != null
? Config.builder().fromConfig(configBuilder.image(NO_IMAGE).build())
: null;
return this;
}
public Map<String, String> getVolumes() { return volumes; }
public List<String> getDns() { return dns; }
public List<String> getVolumesFrom() { return volumesFrom; }
public String getHostname() { return hostname; }
public Integer getMemory() { return memory; }
public List<String> getEntrypoint() { return entrypoint; }
public List<String> getCommands() { return commands; }
public Integer getCpuShares() { return cpuShares; }
public List<String> getEnv() { return env; }
public Map<Integer, Integer> getPortBindings() { return portBindings; }
public String getNetworkMode() { return networkMode; }
public Map<String, String> getExtraHosts() { return extraHosts; }
public boolean getPrivileged() { return privileged; }
public boolean getOpenStdin() { return openStdin; }
public Config.Builder getConfigBuilder() { return configBuilder; }
public static class Builder {
/**
* @see DockerTemplateOptions#volumes(Map)
*/
public static DockerTemplateOptions volumes(Map<String, String> volumes) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.volumes(volumes);
}
/**
* @see DockerTemplateOptions#dns(String...)
*/
public static DockerTemplateOptions dns(String...dns) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.dns(dns);
}
/**
* @see DockerTemplateOptions#dns(List)
*/
public static DockerTemplateOptions dns(Iterable<String> dns) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.dns(dns);
}
/**
* @see DockerTemplateOptions#hostname(String)
*/
public static DockerTemplateOptions hostname(@Nullable String hostname) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.hostname(hostname);
}
/**
* @see DockerTemplateOptions#memory(Integer)
*/
public static DockerTemplateOptions memory(@Nullable Integer memory) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.memory(memory);
}
/**
* @see DockerTemplateOptions#entrypoint(String...)
*/
public static DockerTemplateOptions entrypoint(String...entrypoint) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.entrypoint(entrypoint);
}
/**
* @see DockerTemplateOptions#entrypoint(Iterable)
*/
public static DockerTemplateOptions entrypoint(Iterable<String> entrypoint) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.entrypoint(entrypoint);
}
/**
* @see DockerTemplateOptions#commands(String...)
*/
public static DockerTemplateOptions commands(String...commands) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.commands(commands);
}
/**
* @see DockerTemplateOptions#commands(Iterable)
*/
public static DockerTemplateOptions commands(Iterable<String> commands) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.commands(commands);
}
/**
* @see DockerTemplateOptions#cpuShares(Integer)
*/
public static DockerTemplateOptions cpuShares(@Nullable Integer cpuShares) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.cpuShares(cpuShares);
}
/**
* @see DockerTemplateOptions#env(String...)
*/
public static DockerTemplateOptions env(String...env) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.env(env);
}
/**
* @see DockerTemplateOptions#env(Iterable)
*/
public static DockerTemplateOptions env(Iterable<String> env) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.env(env);
}
/**
* @see DockerTemplateOptions#portBindings(Map)
*/
public static DockerTemplateOptions portBindings(Map<Integer, Integer> portBindings) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.portBindings(portBindings);
}
/**
* @see DockerTemplateOptions#networkMode(String)
*/
public static DockerTemplateOptions networkMode(@Nullable String networkMode) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.networkMode(networkMode);
}
/**
* @see DockerTemplateOptions#extraHosts(Map)
*/
public static DockerTemplateOptions extraHosts(Map<String, String> extraHosts) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.extraHosts(extraHosts);
}
/**
* @see DockerTemplateOptions#privileged(boolean)
*/
public static DockerTemplateOptions privileged(boolean privileged) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.privileged(privileged);
}
/**
* @see DockerTemplateOptions#openStdin(boolean)
*/
public static DockerTemplateOptions openStdin(boolean openStdin) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.openStdin(openStdin);
}
/**
* @see DockerTemplateOptions#configBuilder(Config.Builder)
*/
public static DockerTemplateOptions configBuilder(Config.Builder configBuilder) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.configBuilder(configBuilder);
}
/**
* @see DockerTemplateOptions#volumesFrom(Iterable)
*/
public static DockerTemplateOptions volumesFrom(Iterable<String> volumesFrom) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.volumesFrom(volumesFrom);
}
/**
* @see TemplateOptions#inboundPorts(int...)
*/
public static DockerTemplateOptions inboundPorts(int... ports) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.inboundPorts(ports);
}
/**
* @see TemplateOptions#blockOnPort(int, int)
*/
public static DockerTemplateOptions blockOnPort(int port, int seconds) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.blockOnPort(port, seconds);
}
/**
* @see TemplateOptions#installPrivateKey(String)
*/
public static DockerTemplateOptions installPrivateKey(String rsaKey) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.installPrivateKey(rsaKey);
}
/**
* @see TemplateOptions#authorizePublicKey(String)
*/
public static DockerTemplateOptions authorizePublicKey(String rsaKey) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.authorizePublicKey(rsaKey);
}
/**
* @see TemplateOptions#userMetadata(Map)
*/
public static DockerTemplateOptions userMetadata(Map<String, String> userMetadata) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.userMetadata(userMetadata);
}
/**
* @see TemplateOptions#nodeNames(Iterable)
*/
public static DockerTemplateOptions nodeNames(Iterable<String> nodeNames) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.nodeNames(nodeNames);
}
/**
* @see TemplateOptions#networks(Iterable)
*/
public static DockerTemplateOptions networks(Iterable<String> networks) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.networks(networks);
}
/**
* @see TemplateOptions#overrideLoginUser(String)
*/
public static DockerTemplateOptions overrideLoginUser(String user) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.overrideLoginUser(user);
}
/**
* @see TemplateOptions#overrideLoginPassword(String)
*/
public static DockerTemplateOptions overrideLoginPassword(String password) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.overrideLoginPassword(password);
}
/**
* @see TemplateOptions#overrideLoginPrivateKey(String)
*/
public static DockerTemplateOptions overrideLoginPrivateKey(String privateKey) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.overrideLoginPrivateKey(privateKey);
}
/**
* @see TemplateOptions#overrideAuthenticateSudo(boolean)
*/
public static DockerTemplateOptions overrideAuthenticateSudo(boolean authenticateSudo) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.overrideAuthenticateSudo(authenticateSudo);
}
/**
* @see TemplateOptions#overrideLoginCredentials(LoginCredentials)
*/
public static DockerTemplateOptions overrideLoginCredentials(LoginCredentials credentials) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.overrideLoginCredentials(credentials);
}
/**
* @see TemplateOptions#blockUntilRunning(boolean)
*/
public static DockerTemplateOptions blockUntilRunning(boolean blockUntilRunning) {
DockerTemplateOptions options = new DockerTemplateOptions();
return options.blockUntilRunning(blockUntilRunning);
}
}
// methods that only facilitate returning the correct object type
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions blockOnPort(int port, int seconds) {
return DockerTemplateOptions.class.cast(super.blockOnPort(port, seconds));
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions inboundPorts(int... ports) {
return DockerTemplateOptions.class.cast(super.inboundPorts(ports));
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions authorizePublicKey(String publicKey) {
return DockerTemplateOptions.class.cast(super.authorizePublicKey(publicKey));
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions installPrivateKey(String privateKey) {
return DockerTemplateOptions.class.cast(super.installPrivateKey(privateKey));
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions blockUntilRunning(boolean blockUntilRunning) {
return DockerTemplateOptions.class.cast(super.blockUntilRunning(blockUntilRunning));
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions dontAuthorizePublicKey() {
return DockerTemplateOptions.class.cast(super.dontAuthorizePublicKey());
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions nameTask(String name) {
return DockerTemplateOptions.class.cast(super.nameTask(name));
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions runAsRoot(boolean runAsRoot) {
return DockerTemplateOptions.class.cast(super.runAsRoot(runAsRoot));
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions runScript(Statement script) {
return DockerTemplateOptions.class.cast(super.runScript(script));
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions overrideLoginCredentials(LoginCredentials overridingCredentials) {
return DockerTemplateOptions.class.cast(super.overrideLoginCredentials(overridingCredentials));
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions overrideLoginPassword(String password) {
return DockerTemplateOptions.class.cast(super.overrideLoginPassword(password));
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions overrideLoginPrivateKey(String privateKey) {
return DockerTemplateOptions.class.cast(super.overrideLoginPrivateKey(privateKey));
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions overrideLoginUser(String loginUser) {
return DockerTemplateOptions.class.cast(super.overrideLoginUser(loginUser));
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions overrideAuthenticateSudo(boolean authenticateSudo) {
return DockerTemplateOptions.class.cast(super.overrideAuthenticateSudo(authenticateSudo));
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions userMetadata(Map<String, String> userMetadata) {
return DockerTemplateOptions.class.cast(super.userMetadata(userMetadata));
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions userMetadata(String key, String value) {
return DockerTemplateOptions.class.cast(super.userMetadata(key, value));
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions nodeNames(Iterable<String> nodeNames) {
return DockerTemplateOptions.class.cast(super.nodeNames(nodeNames));
}
/**
* {@inheritDoc}
*/
@Override
public DockerTemplateOptions networks(Iterable<String> networks) {
return DockerTemplateOptions.class.cast(super.networks(networks));
}
}

View File

@ -0,0 +1,353 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.find;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.HardwareBuilder;
import org.jclouds.compute.domain.Processor;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.docker.DockerApi;
import org.jclouds.docker.compute.options.DockerTemplateOptions;
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.ImageSummary;
import org.jclouds.docker.options.CreateImageOptions;
import org.jclouds.docker.options.ListContainerOptions;
import org.jclouds.docker.options.RemoveContainerOptions;
import org.jclouds.domain.Location;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.logging.Logger;
/**
* defines the connection between the {@link org.jclouds.docker.DockerApi} implementation and
* the jclouds {@link org.jclouds.compute.ComputeService}
*/
@Singleton
public class DockerComputeServiceAdapter implements
ComputeServiceAdapter<Container, Hardware, Image, Location> {
/**
* Some Docker versions returns host prefix even for images from Docker hub in repoTags field. We use this constant
* to correctly identify requested image name.
*/
public static final String PREFIX_DOCKER_HUB_HOST = "docker.io/";
/**
* (Optional) Suffix used, when image version is not used during searching images.
*/
public static final String SUFFIX_LATEST_VERSION = ":latest";
private static final String PATTERN_IMAGE_PREFIX = "^(" + Pattern.quote(PREFIX_DOCKER_HUB_HOST) + ")?";
private static final String PATTERN_IMAGE_SUFFIX = "(" + Pattern.quote(SUFFIX_LATEST_VERSION) + ")?$";
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final DockerApi api;
@Inject
public DockerComputeServiceAdapter(DockerApi api) {
this.api = checkNotNull(api, "api");
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public NodeAndInitialCredentials<Container> createNodeWithGroupEncodedIntoName(String group, String name,
Template template) {
checkNotNull(template, "template was null");
TemplateOptions options = template.getOptions();
checkNotNull(options, "template options was null");
String imageId = checkNotNull(template.getImage().getId(), "template image id must not be null");
String loginUser = template.getImage().getDefaultCredentials().getUser();
String loginUserPassword = template.getImage().getDefaultCredentials().getOptionalPassword().or("password");
DockerTemplateOptions templateOptions = DockerTemplateOptions.class.cast(options);
Config containerConfig = null;
Config.Builder containerConfigBuilder = templateOptions.getConfigBuilder();
if (containerConfigBuilder == null) {
containerConfigBuilder = Config.builder().image(imageId);
containerConfigBuilder.entrypoint(templateOptions.getEntrypoint());
containerConfigBuilder.cmd(templateOptions.getCommands());
containerConfigBuilder.memory(templateOptions.getMemory());
containerConfigBuilder.hostname(templateOptions.getHostname());
containerConfigBuilder.cpuShares(templateOptions.getCpuShares());
containerConfigBuilder.openStdin(templateOptions.getOpenStdin());
containerConfigBuilder.env(templateOptions.getEnv());
if (!templateOptions.getVolumes().isEmpty()) {
Map<String, Object> volumes = Maps.newLinkedHashMap();
for (String containerDir : templateOptions.getVolumes().values()) {
volumes.put(containerDir, Maps.newHashMap());
}
containerConfigBuilder.volumes(volumes);
}
HostConfig.Builder hostConfigBuilder = HostConfig.builder()
.publishAllPorts(true)
.privileged(templateOptions.getPrivileged());
if (!templateOptions.getPortBindings().isEmpty()) {
Map<String, List<Map<String, String>>> portBindings = Maps.newHashMap();
for (Map.Entry<Integer, Integer> entry : templateOptions.getPortBindings().entrySet()) {
portBindings.put(entry.getValue() + "/tcp",
Lists.<Map<String, String>>newArrayList(ImmutableMap.of("HostIp", "0.0.0.0", "HostPort", Integer.toString(entry.getKey()))));
}
hostConfigBuilder.portBindings(portBindings);
}
if (!templateOptions.getDns().isEmpty()) {
hostConfigBuilder.dns(templateOptions.getDns());
}
if (!templateOptions.getExtraHosts().isEmpty()) {
List<String> extraHosts = Lists.newArrayList();
for (Map.Entry<String, String> entry : templateOptions.getExtraHosts().entrySet()) {
extraHosts.add(entry.getKey() + ":" + entry.getValue());
}
hostConfigBuilder.extraHosts(extraHosts);
}
if (!templateOptions.getVolumes().isEmpty()) {
for (Map.Entry<String, String> entry : templateOptions.getVolumes().entrySet()) {
hostConfigBuilder.binds(ImmutableList.of(entry.getKey() + ":" + entry.getValue()));
}
}
if (!templateOptions.getVolumesFrom().isEmpty()) {
hostConfigBuilder.volumesFrom(templateOptions.getVolumesFrom());
}
hostConfigBuilder.networkMode(templateOptions.getNetworkMode());
containerConfigBuilder.hostConfig(hostConfigBuilder.build());
// add the inbound ports into exposed ports map
containerConfig = containerConfigBuilder.build();
Map<String, Object> exposedPorts = Maps.newHashMap();
if (containerConfig.exposedPorts() == null) {
exposedPorts.putAll(containerConfig.exposedPorts());
}
for (int inboundPort : templateOptions.getInboundPorts()) {
String portKey = inboundPort + "/tcp";
if (!exposedPorts.containsKey(portKey)) {
exposedPorts.put(portKey, Maps.newHashMap());
}
}
containerConfigBuilder.exposedPorts(exposedPorts);
// build once more after setting inboundPorts
containerConfig = containerConfigBuilder.build();
// finally update port bindings
Map<String, List<Map<String, String>>> portBindings = Maps.newHashMap();
Map<String, List<Map<String, String>>> existingBindings = containerConfig.hostConfig().portBindings();
if (existingBindings != null) {
portBindings.putAll(existingBindings);
}
for (String exposedPort : containerConfig.exposedPorts().keySet()) {
if (!portBindings.containsKey(exposedPort)) {
portBindings.put(exposedPort, Lists.<Map<String, String>>newArrayList(ImmutableMap.of("HostIp", "0.0.0.0")));
}
}
hostConfigBuilder = HostConfig.builder().fromHostConfig(containerConfig.hostConfig());
hostConfigBuilder.portBindings(portBindings);
containerConfigBuilder.hostConfig(hostConfigBuilder.build());
} else {
containerConfigBuilder.image(imageId);
}
containerConfig = containerConfigBuilder.build();
logger.debug(">> creating new container with containerConfig(%s)", containerConfig);
Container container = api.getContainerApi().createContainer(name, containerConfig);
logger.trace("<< container(%s)", container.id());
if (templateOptions.getNetworks() != null) {
logger.debug(">> connecting container(%s) to networks(%s)", container.id(), Iterables.toString(templateOptions.getNetworks()));
for (String networkIdOrName : templateOptions.getNetworks()) {
api.getNetworkApi().connectContainerToNetwork(networkIdOrName, container.id());
}
logger.trace("<< connected(%s)", container.id());
}
HostConfig hostConfig = containerConfig.hostConfig();
logger.debug(">> starting container(%s) with hostConfig(%s)", container.id(), hostConfig);
api.getContainerApi().startContainer(container.id(), hostConfig);
logger.trace("<< started(%s)", container.id());
container = api.getContainerApi().inspectContainer(container.id());
if (container.state().exitCode() != 0) {
destroyNode(container.id());
throw new IllegalStateException(String.format("Container %s has not started correctly", container.id()));
}
return new NodeAndInitialCredentials(container, container.id(),
LoginCredentials.builder().user(loginUser).password(loginUserPassword).build());
}
@Override
public Iterable<Hardware> listHardwareProfiles() {
Set<Hardware> hardware = Sets.newLinkedHashSet();
// todo they are only placeholders at the moment
hardware.add(new HardwareBuilder().ids("micro").hypervisor("lxc").name("micro").processor(new Processor(1, 1)).ram(512).build());
hardware.add(new HardwareBuilder().ids("small").hypervisor("lxc").name("small").processor(new Processor(1, 1)).ram(1024).build());
hardware.add(new HardwareBuilder().ids("medium").hypervisor("lxc").name("medium").processor(new Processor(2, 1)).ram(2048).build());
hardware.add(new HardwareBuilder().ids("large").hypervisor("lxc").name("large").processor(new Processor(2, 1)).ram(3072).build());
return hardware;
}
/**
* Method based on {@link org.jclouds.docker.features.ImageApi#listImages()}. It retrieves additional
* information by inspecting each image.
*
* @see org.jclouds.compute.ComputeServiceAdapter#listImages()
*/
@Override
public Set<Image> listImages() {
Set<Image> images = Sets.newHashSet();
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(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;
}
@Override
public Image getImage(final String imageIdOrName) {
checkNotNull(imageIdOrName);
if (imageIdOrName.startsWith("sha256")) {
// less efficient than just inspectImage but listImages return repoTags
return find(listImages(), new Predicate<Image>() {
@Override
public boolean apply(Image input) {
// Only attempt match on id as we should try to pull again anyway if using name
return input.id().equals(imageIdOrName);
}
}, null);
}
// Image is not cached or getting image by name so try to pull it
api.getImageApi().createImage(CreateImageOptions.Builder.fromImage(imageIdOrName));
// as above this ensure repotags are returned
return find(listImages(), createPredicateMatchingRepoTags(imageIdOrName), null);
}
@Override
public Iterable<Container> listNodes() {
Set<Container> containers = Sets.newHashSet();
for (ContainerSummary containerSummary : api.getContainerApi().listContainers(ListContainerOptions.Builder.all(true))) {
// less efficient than just listNodes but returns richer json
containers.add(api.getContainerApi().inspectContainer(containerSummary.id()));
}
return containers;
}
@Override
public Iterable<Container> listNodesByIds(final Iterable<String> ids) {
Set<Container> containers = Sets.newHashSet();
for (String id : ids) {
containers.add(api.getContainerApi().inspectContainer(id));
}
return containers;
}
@Override
public Iterable<Location> listLocations() {
return ImmutableSet.of();
}
@Override
public Container getNode(String id) {
return api.getContainerApi().inspectContainer(id);
}
@Override
public void destroyNode(String id) {
api.getContainerApi().removeContainer(id, RemoveContainerOptions.Builder.force(true));
}
@Override
public void rebootNode(String id) {
api.getContainerApi().stopContainer(id);
api.getContainerApi().startContainer(id);
}
@Override
public void resumeNode(String id) {
api.getContainerApi().unpause(id);
}
@Override
public void suspendNode(String id) {
api.getContainerApi().pause(id);
}
protected static Predicate<Image> createPredicateMatchingRepoTags(final String imageIdOrName) {
final Pattern imgPattern = Pattern
.compile(PATTERN_IMAGE_PREFIX + Pattern.quote(imageIdOrName) + PATTERN_IMAGE_SUFFIX);
return new Predicate<Image>() {
@Override
public boolean apply(Image input) {
for (String tag : input.repoTags()) {
if (imgPattern.matcher(tag).matches()) {
return true;
}
}
return false;
}
};
}
}

View File

@ -0,0 +1,68 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.config;
import com.google.common.base.Supplier;
import com.google.inject.AbstractModule;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Names;
import com.google.inject.util.Modules;
import org.jclouds.docker.DockerApi;
import org.jclouds.docker.handlers.DockerErrorHandler;
import org.jclouds.docker.suppliers.DockerUntrustedSSLContextSupplier;
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 javax.net.ssl.SSLContext;
/**
* Configures the Docker connection.
*/
@ConfiguresHttpApi
@ConfiguresHttpCommandExecutorService
public class DockerHttpApiModule extends HttpApiModule<DockerApi> {
@Override
protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(DockerErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(DockerErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(DockerErrorHandler.class);
}
/**
* This configures SSL certificate authentication when the Docker daemon is set to use an encrypted TCP socket
*/
@Override
protected void configure() {
super.configure();
install(Modules.override(new OkHttpCommandExecutorServiceModule()).with(new AbstractModule() {
@Override
protected void configure() {
bind(new TypeLiteral<Supplier<SSLContext>>() {}).annotatedWith(Names.named("untrusted")).to(DockerUntrustedSSLContextSupplier.class);
}
}));
bind(OkHttpClientSupplier.class).to(DockerOkHttpClientSupplier.class);
}
}

View File

@ -0,0 +1,63 @@
/*
* 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 java.io.File;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.docker.suppliers.DockerSSLContextSupplier;
import org.jclouds.domain.Credentials;
import org.jclouds.http.okhttp.OkHttpClientSupplier;
import org.jclouds.location.Provider;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.squareup.okhttp.ConnectionSpec;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.TlsVersion;
@Singleton
public class DockerOkHttpClientSupplier implements OkHttpClientSupplier {
private final DockerSSLContextSupplier dockerSSLContextSupplier;
private final Supplier<Credentials> creds;
@Inject
DockerOkHttpClientSupplier(DockerSSLContextSupplier dockerSSLContextSupplier, @Provider Supplier<Credentials> creds) {
this.dockerSSLContextSupplier = dockerSSLContextSupplier;
this.creds = creds;
}
@Override
public OkHttpClient get() {
OkHttpClient client = new OkHttpClient();
ConnectionSpec tlsSpec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_0, TlsVersion.TLS_1_1, TlsVersion.TLS_1_2)
.build();
ConnectionSpec cleartextSpec = new ConnectionSpec.Builder(ConnectionSpec.CLEARTEXT)
.build();
client.setConnectionSpecs(ImmutableList.of(tlsSpec, cleartextSpec));
// check if identity and credential are files, to set up sslContext
if (new File(creds.get().identity).isFile() && new File(creds.get().credential).isFile()) {
client.setSslSocketFactory(dockerSSLContextSupplier.get().getSocketFactory());
}
return client;
}
}

View File

@ -0,0 +1,29 @@
/*
* 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.json.config.GsonModule;
import com.google.inject.AbstractModule;
public class DockerParserModule extends AbstractModule {
@Override protected void configure() {
bind(GsonModule.DateAdapter.class).to(GsonModule.Iso8601DateAdapter.class);
}
}

View File

@ -0,0 +1,265 @@
/*
* 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 com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.docker.internal.NullSafeCopies.copyOf;
import static org.jclouds.docker.internal.NullSafeCopies.copyWithNullOf;
import java.util.List;
import java.util.Map;
import org.jclouds.docker.domain.HostConfig.Builder;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@AutoValue
public abstract class Config {
@Nullable public abstract String hostname();
@Nullable public abstract String domainname();
@Nullable public abstract String user();
public abstract int memory();
public abstract int memorySwap();
public abstract int cpuShares();
public abstract boolean attachStdin();
public abstract boolean attachStdout();
public abstract boolean attachStderr();
public abstract boolean tty();
public abstract boolean openStdin();
public abstract boolean stdinOnce();
@Nullable public abstract List<String> env();
@Nullable public abstract List<String> cmd();
@Nullable public abstract List<String> entrypoint();
public abstract String image();
@Nullable public abstract Map<String, ?> volumes();
@Nullable public abstract String workingDir();
public abstract boolean networkDisabled();
public abstract Map<String, ?> exposedPorts();
public abstract List<String> securityOpts();
@Nullable public abstract HostConfig hostConfig();
Config() {
}
@SerializedNames(
{
"Hostname", "Domainname", "User", "Memory", "MemorySwap", "CpuShares", "AttachStdin", "AttachStdout",
"AttachStderr", "Tty", "OpenStdin", "StdinOnce", "Env", "Cmd", "Entrypoint", "Image", "Volumes",
"WorkingDir", "NetworkDisabled", "ExposedPorts", "SecurityOpts", "HostConfig"
})
public static Config create(String hostname, String domainname, String user, int memory, int memorySwap,
int cpuShares, boolean attachStdin, boolean attachStdout, boolean attachStderr, boolean tty,
boolean openStdin, boolean stdinOnce, List<String> env, List<String> cmd, List<String> entrypoint,
String image, Map<String, ?> volumes, String workingDir, boolean networkDisabled,
Map<String, ?> exposedPorts, List<String> securityOpts, HostConfig hostConfig) {
return new AutoValue_Config(hostname, domainname, user, memory, memorySwap, cpuShares, attachStdin,
attachStdout, attachStderr, tty, openStdin, stdinOnce, copyWithNullOf(env), copyWithNullOf(cmd),
copyWithNullOf(entrypoint), image, copyWithNullOf(volumes), workingDir, networkDisabled,
copyOf(exposedPorts), copyOf(securityOpts), hostConfig);
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().fromConfig(this);
}
public static final class Builder {
private String hostname;
private String domainname;
private String user;
private int memory;
private int memorySwap;
private int cpuShares;
private boolean attachStdin;
private boolean attachStdout;
private boolean attachStderr;
private boolean tty;
private boolean openStdin;
private boolean stdinOnce;
private List<String> env;
private List<String> cmd;
private List<String> entrypoint;
private String image;
private Map<String, ?> volumes;
private String workingDir;
private boolean networkDisabled;
private Map<String, ?> exposedPorts = Maps.newHashMap();
private List<String> securityOpts = Lists.newArrayList();
private HostConfig hostConfig;
public Builder hostname(String hostname) {
this.hostname = hostname;
return this;
}
public Builder domainname(String domainname) {
this.domainname = domainname;
return this;
}
public Builder user(String user) {
this.user = user;
return this;
}
public Builder memory(Integer memory) {
if (memory != null) {
this.memory = memory;
}
return this;
}
public Builder memorySwap(Integer memorySwap) {
if (memorySwap != null) {
this.memorySwap = memorySwap;
}
return this;
}
public Builder cpuShares(Integer cpuShares) {
if (cpuShares != null) {
this.cpuShares = cpuShares;
}
return this;
}
public Builder attachStdin(boolean attachStdin) {
this.attachStdin = attachStdin;
return this;
}
public Builder attachStdout(boolean attachStdout) {
this.attachStdout = attachStdout;
return this;
}
public Builder attachStderr(boolean attachStderr) {
this.attachStderr = attachStderr;
return this;
}
public Builder tty(boolean tty) {
this.tty = tty;
return this;
}
public Builder openStdin(boolean openStdin) {
this.openStdin = openStdin;
return this;
}
public Builder stdinOnce(boolean stdinOnce) {
this.stdinOnce = stdinOnce;
return this;
}
public Builder env(List<String> env) {
this.env = env;
return this;
}
public Builder cmd(List<String> cmd) {
this.cmd = cmd;
return this;
}
public Builder entrypoint(List<String> entrypoint) {
this.entrypoint = entrypoint;
return this;
}
public Builder image(String image) {
this.image = checkNotNull(image, "image");
return this;
}
public Builder volumes(Map<String, ?> volumes) {
this.volumes = volumes;
return this;
}
public Builder workingDir(String workingDir) {
this.workingDir = workingDir;
return this;
}
public Builder networkDisabled(boolean networkDisabled) {
this.networkDisabled = networkDisabled;
return this;
}
public Builder exposedPorts(Map<String, ?> exposedPorts) {
this.exposedPorts = exposedPorts;
return this;
}
public Builder securityOpts(List<String> securityOpts) {
this.securityOpts = securityOpts;
return this;
}
public Builder hostConfig(HostConfig hostConfig) {
this.hostConfig = hostConfig;
return this;
}
public Config build() {
return Config.create(hostname, domainname, user, memory, memorySwap, cpuShares, attachStdin, attachStdout,
attachStderr, tty, openStdin, stdinOnce, env, cmd, entrypoint, image, volumes, workingDir,
networkDisabled, exposedPorts, securityOpts, hostConfig);
}
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()).tty(in.tty())
.openStdin(in.openStdin()).stdinOnce(in.stdinOnce()).env(in.env()).cmd(in.cmd())
.entrypoint(in.entrypoint()).image(in.image()).volumes(in.volumes()).workingDir(in.workingDir())
.networkDisabled(in.networkDisabled()).exposedPorts(in.exposedPorts())
.securityOpts(in.securityOpts()).hostConfig(in.hostConfig());
}
}
}

View File

@ -0,0 +1,273 @@
/*
* 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.Date;
import java.util.List;
import java.util.Map;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@AutoValue
public abstract class Container {
public abstract String id();
@Nullable public abstract Date created();
@Nullable public abstract String path();
@Nullable public abstract String name();
public abstract List<String> args();
@Nullable public abstract Config config();
@Nullable public abstract State state();
@Nullable public abstract String image();
@Nullable public abstract NetworkSettings networkSettings();
@Nullable public abstract String sysInitPath();
@Nullable public abstract String resolvConfPath();
public abstract Map<String, String> volumes();
@Nullable public abstract HostConfig hostConfig();
@Nullable public abstract String driver();
@Nullable public abstract String execDriver();
public abstract Map<String, Boolean> volumesRW();
@Nullable public abstract String command();
@Nullable public abstract String status();
public abstract List<Port> ports();
@Nullable public abstract String hostnamePath();
@Nullable public abstract String hostsPath();
@Nullable public abstract String mountLabel();
@Nullable public abstract String processLabel();
public abstract Optional<Node> node();
Container() {
}
@SerializedNames(
{
"Id", "Created", "Path", "Name", "Args", "Config", "State", "Image", "NetworkSettings", "SysInitPath",
"ResolvConfPath", "Volumes", "HostConfig", "Driver", "ExecDriver", "VolumesRW", "Command", "Status",
"Ports", "HostnamePath", "HostsPath", "MountLabel", "ProcessLabel", "Node"
})
public static Container create(String id, Date created, String path, String name, List<String> args, Config config,
State state, String image, NetworkSettings networkSettings, String sysInitPath,
String resolvConfPath, Map<String, String> volumes, HostConfig hostConfig,
String driver, String execDriver, Map<String, Boolean> volumesRW, String command,
String status, List<Port> ports, String hostnamePath, String hostsPath,
String mountLabel, String processLabel, Optional<Node> node) {
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, node);
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().fromContainer(this);
}
public static final class Builder {
private String id;
private Date created;
private String path;
private String name;
private List<String> args;
private Config config;
private State state;
private String image;
private NetworkSettings networkSettings;
private String sysInitPath;
private String resolvConfPath;
private Map<String, String> volumes = ImmutableMap.of();
private HostConfig hostConfig;
private String driver;
private String execDriver;
private Map<String, Boolean> volumesRW = ImmutableMap.of();
private String command;
private String status;
private List<Port> ports = ImmutableList.of();
private String hostnamePath;
private String hostsPath;
private String mountLabel;
private String processLabel;
private Optional<Node> node = Optional.absent();
public Builder id(String id) {
this.id = id;
return this;
}
public Builder created(Date created) {
this.created = created;
return this;
}
public Builder path(String path) {
this.path = path;
return this;
}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder args(List<String> args) {
this.args = args;
return this;
}
public Builder config(Config config) {
this.config = config;
return this;
}
public Builder state(State state) {
this.state = state;
return this;
}
public Builder image(String imageName) {
this.image = imageName;
return this;
}
public Builder networkSettings(NetworkSettings networkSettings) {
this.networkSettings = networkSettings;
return this;
}
public Builder sysInitPath(String sysInitPath) {
this.sysInitPath = sysInitPath;
return this;
}
public Builder resolvConfPath(String resolvConfPath) {
this.resolvConfPath = resolvConfPath;
return this;
}
public Builder volumes(Map<String, String> volumes) {
this.volumes = volumes;
return this;
}
public Builder hostConfig(HostConfig hostConfig) {
this.hostConfig = hostConfig;
return this;
}
public Builder driver(String driver) {
this.driver = driver;
return this;
}
public Builder execDriver(String execDriver) {
this.execDriver = execDriver;
return this;
}
public Builder volumesRW(Map<String, Boolean> volumesRW) {
this.volumesRW = volumesRW;
return this;
}
public Builder command(String command) {
this.command = command;
return this;
}
public Builder status(String status) {
this.status = status;
return this;
}
public Builder ports(List<Port> ports) {
this.ports = ports;
return this;
}
public Builder hostnamePath(String hostnamePath) {
this.hostnamePath = hostnamePath;
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 Builder node(Node node) {
this.node = Optional.fromNullable(node);
return this;
}
public Container build() {
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, node);
}
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())
.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()).node(in.node().orNull());
}
}
}

View File

@ -0,0 +1,52 @@
/*
* 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 Container value class)
@AutoValue
public abstract class ContainerSummary {
public abstract String id();
public abstract List<String> names();
public abstract String created();
public abstract String image();
public abstract String command();
public abstract List<Port> ports();
public abstract String status();
ContainerSummary() {
}
@SerializedNames({"Id", "Names", "Created", "Image", "Command", "Ports", "Status"})
public static ContainerSummary create(String id, List<String> names, String created, String image, String command, List<Port> ports, String status) {
return new AutoValue_ContainerSummary(id, copyOf(names), created, image, command, copyOf(ports), status);
}
}

View File

@ -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;
/**
* Represents a response from Exec Create call (<code>POST /containers/(id)/exec</code>).
*/
@AutoValue
public abstract class Exec {
public abstract String id();
@SerializedNames({ "Id"})
public static Exec create(String id) {
return new AutoValue_Exec(id);
}
}

View File

@ -0,0 +1,72 @@
/*
* 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;
/**
* Json Parameters (some of them) of Exec Create call.
*/
@AutoValue
public abstract class ExecCreateParams {
public abstract boolean attachStdout();
public abstract boolean attachStderr();
public abstract List<String> cmd();
@SerializedNames({ "AttachStdout", "AttachStderr", "Cmd" })
private static ExecCreateParams create(boolean attachStdout, boolean attachStderr, List<String> cmd) {
return builder().attachStdout(attachStdout).attachStderr(attachStderr).cmd(cmd).build();
}
/**
* Creates builder for {@link ExecCreateParams}, it sets
* {@link #attachStderr()} and {@link #attachStdout()} to true as a default.
*
* @return new {@link ExecCreateParams.Builder} instance
*/
public static Builder builder() {
return new AutoValue_ExecCreateParams.Builder().attachStderr(true).attachStdout(true);
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder attachStdout(boolean b);
public abstract Builder attachStderr(boolean b);
public abstract Builder cmd(List<String> cmd);
abstract List<String> cmd();
abstract ExecCreateParams autoBuild();
public ExecCreateParams build() {
cmd(copyOf(cmd()));
return autoBuild();
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.domain;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
/**
* Represents a response (part of it) from Exec Inspect call (
* <code>GET /exec/(id)/json</code>).
*/
@AutoValue
public abstract class ExecInspect {
public abstract String id();
public abstract boolean running();
public abstract int exitCode();
@SerializedNames({ "ID", "Running", "ExitCode"})
public static ExecInspect create(String id, boolean running, int exitCode) {
return new AutoValue_ExecInspect(id, running, exitCode);
}
}

View File

@ -0,0 +1,47 @@
/*
* 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;
/**
* Json Parameter(s) (some of them) of Exec Start call.
*/
@AutoValue
public abstract class ExecStartParams {
public abstract boolean detach();
@SerializedNames({ "Detach" })
public static ExecStartParams create(boolean detach) {
return builder().detach(detach).build();
}
public static Builder builder() {
return new AutoValue_ExecStartParams.Builder().detach(false);
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder detach(boolean b);
public abstract ExecStartParams build();
}
}

View File

@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.domain;
import static org.jclouds.docker.internal.NullSafeCopies.copyOf;
import java.util.List;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class ExposedPorts {
public abstract String portAndProtocol();
public abstract List<String> hostPorts();
ExposedPorts() {
}
@SerializedNames({ "PortAndProtocol", "HostPorts" })
public static ExposedPorts create(String portAndProtocol, List<String> hostPorts) {
return new AutoValue_ExposedPorts(portAndProtocol, copyOf(hostPorts));
}
}

View File

@ -0,0 +1,203 @@
/*
* 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 static org.jclouds.docker.internal.NullSafeCopies.copyWithNullOf;
import java.util.List;
import java.util.Map;
import com.google.auto.value.AutoValue;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
@AutoValue
public abstract class HostConfig {
@Nullable public abstract String containerIDFile();
@Nullable public abstract List<String> binds();
public abstract List<Map<String, String>> lxcConf();
public abstract boolean privileged();
@Nullable public abstract List<String> dns();
@Nullable public abstract List<String> dnsSearch();
public abstract Map<String, List<Map<String, String>>> portBindings();
@Nullable public abstract List<String> links();
@Nullable public abstract List<String> extraHosts();
public abstract boolean publishAllPorts();
@Nullable public abstract List<String> volumesFrom();
@Nullable public abstract String networkMode();
@Nullable public abstract List<String> securityOpt();
@Nullable public abstract List<String> capAdd();
@Nullable public abstract List<String> capDrop();
public abstract Map<String, String> restartPolicy();
HostConfig() {
}
@SerializedNames({ "ContainerIDFile", "Binds", "LxcConf", "Privileged", "Dns", "DnsSearch", "PortBindings",
"Links", "ExtraHosts", "PublishAllPorts", "VolumesFrom", "NetworkMode", "SecurityOpt",
"CapAdd", "CapDrop", "RestartPolicy" })
public static HostConfig create(String containerIDFile, List<String> binds, List<Map<String, String>> lxcConf,
boolean privileged, List<String> dns, List<String> dnsSearch, Map<String, List<Map<String, String>>> portBindings,
List<String> links, List<String> extraHosts, boolean publishAllPorts, List<String> volumesFrom, String networkMode,
List<String> securityOpt, List<String> capAdd, List<String> capDrop, Map<String, String> restartPolicy) {
return new AutoValue_HostConfig(containerIDFile, copyWithNullOf(binds), copyOf(lxcConf), privileged, copyWithNullOf(dns), copyWithNullOf(dnsSearch),
copyOf(portBindings), copyWithNullOf(links), copyWithNullOf(extraHosts), publishAllPorts, copyWithNullOf(volumesFrom), networkMode,
copyOf(securityOpt), copyWithNullOf(capAdd), copyWithNullOf(capDrop), copyOf(restartPolicy));
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().fromHostConfig(this);
}
public static final class Builder {
private String containerIDFile;
private List<String> binds;
private List<Map<String, String>> lxcConf = Lists.newArrayList();
private boolean privileged;
private List<String> dns;
private List<String> dnsSearch;
private Map<String, List<Map<String, String>>> portBindings = Maps.newLinkedHashMap();
private List<String> links;
private List<String> extraHosts;
private boolean publishAllPorts;
private List<String> volumesFrom;
private String networkMode;
private List<String> securityOpt = Lists.newArrayList();
private List<String> capAdd;
private List<String> capDrop;
private Map<String, String> restartPolicy = Maps.newHashMap();
public Builder containerIDFile(String containerIDFile) {
this.containerIDFile = containerIDFile;
return this;
}
public Builder binds(List<String> binds) {
this.binds = binds;
return this;
}
public Builder lxcConf(List<Map<String, String>> lxcConf) {
this.lxcConf = lxcConf;
return this;
}
public Builder privileged(boolean privileged) {
this.privileged = privileged;
return this;
}
public Builder dns(List<String> dns) {
this.dns = dns;
return this;
}
public Builder dnsSearch(List<String> dnsSearch) {
this.dnsSearch = dnsSearch;
return this;
}
public Builder links(List<String> links) {
this.links = links;
return this;
}
public Builder extraHosts(List<String> extraHosts) {
this.extraHosts = extraHosts;
return this;
}
public Builder portBindings(Map<String, List<Map<String, String>>> portBindings) {
this.portBindings = portBindings;
return this;
}
public Builder publishAllPorts(boolean publishAllPorts) {
this.publishAllPorts = publishAllPorts;
return this;
}
public Builder volumesFrom(List<String> volumesFrom) {
this.volumesFrom = volumesFrom;
return this;
}
public Builder networkMode(String networkMode) {
this.networkMode = networkMode;
return this;
}
public Builder securityOpt(List<String> securityOpt) {
this.securityOpt = securityOpt;
return this;
}
public Builder capAdd(List<String> capAdd) {
this.capAdd = capAdd;
return this;
}
public Builder capDrop(List<String> capDrop) {
this.capDrop = capDrop;
return this;
}
public Builder restartPolicy(Map<String, String> restartPolicy) {
this.restartPolicy = restartPolicy;
return this;
}
public HostConfig build() {
return HostConfig.create(containerIDFile, binds, lxcConf, privileged, dns, dnsSearch, portBindings, links,
extraHosts, publishAllPorts, volumesFrom, networkMode, securityOpt, capAdd, capDrop, restartPolicy);
}
public Builder fromHostConfig(HostConfig in) {
return this.containerIDFile(in.containerIDFile()).binds(in.binds()).lxcConf(in.lxcConf())
.privileged(in.privileged()).dns(in.dns()).dnsSearch(in.dnsSearch()).links(in.links())
.extraHosts(in.extraHosts()).portBindings(in.portBindings()).publishAllPorts(in.publishAllPorts())
.volumesFrom(in.volumesFrom()).networkMode(in.networkMode()).securityOpt(in.securityOpt())
.capAdd(in.capAdd()).capDrop(in.capDrop()).restartPolicy(in.restartPolicy());
}
}
}

View File

@ -0,0 +1,84 @@
/*
* 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.Date;
import java.util.List;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
/**
* Represents a response from Docker "Inspect an image" call (<code>GET /images/(name)/json</code>).
*/
@AutoValue
public abstract class Image {
public abstract String id();
@Nullable public abstract String author();
@Nullable public abstract String comment();
@Nullable public abstract Config config();
@Nullable public abstract Config containerConfig();
public abstract String parent();
public abstract Date created();
public abstract String container();
public abstract String dockerVersion();
public abstract String architecture();
public abstract String os();
public abstract long size();
public abstract long virtualSize();
/**
* Tags of the image. The value is <code>null</code> when the instance comes
* from {@link org.jclouds.docker.features.ImageApi#inspectImage(String)}.
* Other methods can populate the content (e.g.
* {@link org.jclouds.docker.compute.strategy.DockerComputeServiceAdapter#listImages()}
* call.
* <p>
* The tags are in form "ubuntu:12.10", "docker.io/busybox:1.23.2", ...
* </p>
* @return list of tags or <code>null</code>
*/
@Nullable public abstract List<String> repoTags();
Image() {
}
@SerializedNames({ "Id", "Author", "Comment", "Config", "ContainerConfig", "Parent", "Created",
"Container", "DockerVersion", "Architecture", "Os", "Size", "VirtualSize", "RepoTags" })
public static Image create(String id, String author, String comment, Config config, Config containerConfig, String parent, Date created, String container, String dockerVersion, String architecture, String os, long size, long virtualSize, List<String> repoTags) {
return new AutoValue_Image(id, author, comment, config, containerConfig, parent, created, container,
dockerVersion, architecture, os, size, virtualSize, copyOf(repoTags));
}
}

View File

@ -0,0 +1,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.domain;
import static org.jclouds.docker.internal.NullSafeCopies.copyOf;
import java.util.List;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class ImageHistory {
public abstract String id();
public abstract long created();
public abstract String createdBy();
@Nullable public abstract List<String> tags();
public abstract long size();
public abstract String comment();
ImageHistory() {
}
@SerializedNames({"Id", "Created", "CreatedBy", "Tags", "Size", "Comment"})
public static ImageHistory create(String id, long created, String createdBy, List<String> tags, long size, String comment) {
return new AutoValue_ImageHistory(id, created, createdBy, copyOf(tags), size, comment);
}
}

View File

@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.domain;
import static org.jclouds.docker.internal.NullSafeCopies.copyOf;
import java.util.List;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
// TODO it may be redundant (we already have Image value class)
@AutoValue
public abstract class ImageSummary {
public abstract String id();
public abstract long created();
public abstract String parentId();
public abstract int size();
public abstract int virtualSize();
public abstract List<String> repoTags();
ImageSummary() {
}
@SerializedNames({"Id", "Created", "ParentId", "Size", "VirtualSize", "RepoTags"})
public static ImageSummary create(String id, long created, String parentId, int size, int virtualSize,
List<String> repoTags) {
return new AutoValue_ImageSummary(id, created, parentId, size, virtualSize, copyOf(repoTags));
}
}

View File

@ -0,0 +1,108 @@
/*
* 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 java.util.List;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class Info {
public abstract int containers();
public abstract boolean debug();
public abstract String driver();
public abstract List<List<String>> driverStatus();
public abstract String executionDriver();
public abstract boolean iPv4Forwarding();
public abstract int images();
public abstract String indexServerAddress();
@Nullable public abstract String initPath();
@Nullable public abstract String initSha1();
public abstract String kernelVersion();
public abstract boolean memoryLimit();
public abstract int nEventsListener();
public abstract int nFd();
public abstract int nGoroutines();
public abstract String operatingSystem();
public abstract boolean swapLimit();
public abstract String dockerRootDir();
/**
* @return a list of daemon labels
*/
@Nullable public abstract List<String> labels();
/**
* @return total memory available
*/
public abstract long memTotal();
/**
* @return the number of CPUs available on the machine
*/
public abstract int ncpu();
/**
* @return a unique ID identifying the daemon
*/
public abstract String id();
/**
* @return a user-friendly name describing the running Docker daemon
*/
public abstract String name();
Info() {
}
@SerializedNames({
"Containers", "Debug", "Driver", "DriverStatus", "ExecutionDriver", "IPv4Forwarding", "Images",
"IndexServerAddress", "InitPath", "InitSha1", "KernelVersion", "MemoryLimit", "NEventsListener",
"NFd", "NGoroutines", "OperatingSystem", "SwapLimit", "DockerRootDir", "Labels", "MemTotal", "NCPU",
"ID", "Name"
})
public static Info create(int containers, boolean debug, String driver, List<List<String>> driverStatus,
String executionDriver, boolean iPv4Forwarding, int images, String indexServerAddress,
String initPath, String initSha1, String kernelVersion, boolean memoryLimit,
int nEventsListener, int nFd, int nGoroutines, String operatingSystem, boolean swapLimit,
String dockerRootDir, List<String> labels, long memTotal, int ncpu, String id, String name) {
return new AutoValue_Info(containers, debug, driver, driverStatus, executionDriver, iPv4Forwarding, images,
indexServerAddress, initPath, initSha1, kernelVersion, memoryLimit, nEventsListener, nFd, nGoroutines,
operatingSystem, swapLimit, dockerRootDir, labels, memTotal, ncpu, id, name);
}
}

View File

@ -0,0 +1,215 @@
/*
* 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 static org.jclouds.docker.internal.NullSafeCopies.copyWithNullOf;
import java.util.List;
import java.util.Map;
import com.google.auto.value.AutoValue;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
@AutoValue
public abstract class Network {
@AutoValue
public abstract static class IPAM {
IPAM() { }
@Nullable public abstract String driver();
public abstract List<Config> config();
@SerializedNames({"Driver", "Config"})
public static IPAM create(@Nullable String driver, List<Config> config) {
return builder()
.driver(driver)
.config(config)
.build();
}
public static Builder builder() {
return new AutoValue_Network_IPAM.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder driver(@Nullable String driver);
public abstract Builder config(List<Config> config);
abstract List<Config> config();
abstract IPAM autoBuild();
public IPAM build() {
return config(copyOf(config()))
.autoBuild();
}
}
@AutoValue
public abstract static class Config {
Config() { }
public abstract String subnet();
@Nullable public abstract String ipRange();
@Nullable public abstract String gateway();
@SerializedNames({"Subnet", "IPRange", "Gateway"})
public static Config create(String subnet, @Nullable String ipRange, @Nullable String gateway) {
return builder()
.subnet(subnet)
.ipRange(ipRange)
.gateway(gateway)
.build();
}
public static Builder builder() {
return new AutoValue_Network_IPAM_Config.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder subnet(String subnet);
public abstract Builder ipRange(@Nullable String ipRange);
public abstract Builder gateway(@Nullable String gateway);
abstract Config build();
}
}
}
@AutoValue
public abstract static class Details {
Details() { }
public abstract String endpoint();
public abstract String macAddress();
public abstract String ipv4address();
public abstract String ipv6address();
@SerializedNames({ "EndpointID", "MacAddress", "IPv4Address", "IPv6Address" })
public static Details create(String endpoint, String macAddress, String ipv4address, String ipv6address) {
return builder()
.endpoint(endpoint)
.macAddress(macAddress)
.ipv4address(ipv4address)
.ipv6address(ipv6address)
.build();
}
public static Builder builder() {
return new AutoValue_Network_Details.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder endpoint(String endpoint);
public abstract Builder macAddress(String macAddress);
public abstract Builder ipv4address(String ipv4address);
public abstract Builder ipv6address(String ipv6address);
abstract Details build();
}
}
@Nullable public abstract String name();
@Nullable public abstract String id();
@Nullable public abstract String scope();
@Nullable public abstract String driver();
@Nullable public abstract IPAM ipam();
@Nullable public abstract Map<String, Details> containers();
@Nullable public abstract Map<String, String> options();
Network() { }
@SerializedNames({ "Name", "Id", "Scope", "Driver", "IPAM", "Containers", "Options" })
public static Network create(@Nullable String name, @Nullable String id, @Nullable String scope,
@Nullable String driver, @Nullable IPAM ipam, @Nullable Map<String, Details> containers,
@Nullable Map<String, String> options) {
return builder()
.name(name)
.id(id)
.scope(scope)
.driver(driver)
.ipam(ipam)
.containers(containers)
.options(options)
.build();
}
public static Builder builder() {
return new AutoValue_Network.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder name(@Nullable String name);
public abstract Builder id(@Nullable String id);
public abstract Builder scope(@Nullable String scope);
public abstract Builder driver(@Nullable String driver);
public abstract Builder ipam(@Nullable IPAM ipam);
public abstract Builder containers(@Nullable Map<String, Details> containers);
public abstract Builder options(@Nullable Map<String, String> options);
abstract Map<String, Details> containers();
abstract Map<String, String> options();
abstract Network autoBuild();
public Network build() {
return containers(copyWithNullOf(containers()))
.options(copyOf(options()))
.autoBuild();
}
}
}

View File

@ -0,0 +1,288 @@
/*
* 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 java.util.Map;
import org.jclouds.docker.internal.NullSafeCopies;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@AutoValue
public abstract class NetworkSettings {
@AutoValue
public abstract static class Details {
Details() {} // For AutoValue only!
public abstract String endpoint();
public abstract String gateway();
public abstract String ipAddress();
public abstract int ipPrefixLen();
public abstract String ipv6Gateway();
public abstract String globalIPv6Address();
public abstract int globalIPv6PrefixLen();
public abstract String macAddress();
@SerializedNames({ "EndpointID", "Gateway", "IPAddress", "IPPrefixLen", "IPv6Gateway", "GlobalIPv6Address", "GlobalIPv6PrefixLen", "MacAddress" })
public static Details create(String endpointId, String gateway, String ipAddress, int ipPrefixLen, String ipv6Gateway, String globalIPv6Address,
int globalIPv6PrefixLen, String macAddress) {
return builder().endpoint(endpointId).gateway(gateway).ipAddress(ipAddress).ipPrefixLen(ipPrefixLen)
.ipv6Gateway(ipv6Gateway).globalIPv6Address(globalIPv6Address)
.globalIPv6PrefixLen(globalIPv6PrefixLen).macAddress(macAddress)
.build();
}
public Builder toBuilder() {
return new AutoValue_NetworkSettings_Details.Builder(this);
}
public static Builder builder() {
return new AutoValue_NetworkSettings_Details.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder endpoint(String value);
public abstract Builder gateway(String value);
public abstract Builder ipAddress(String value);
public abstract Builder ipPrefixLen(int value);
public abstract Builder ipv6Gateway(String value);
public abstract Builder globalIPv6Address(String value);
public abstract Builder globalIPv6PrefixLen(int value);
public abstract Builder macAddress(String value);
public abstract Details build();
}
}
public abstract String bridge();
@Nullable public abstract String sandboxId();
public abstract boolean hairpinMode();
@Nullable public abstract String linkLocalIPv6Address();
public abstract int linkLocalIPv6PrefixLen();
@Nullable public abstract Map<String, List<Map<String, String>>> ports();
@Nullable public abstract String sandboxKey();
public abstract List<String> secondaryIPAddresses();
public abstract List<String> secondaryIPv6Addresses();
@Nullable public abstract String endpointId();
public abstract String gateway();
@Nullable public abstract String globalIPv6Address();
public abstract int globalIPv6PrefixLen();
public abstract String ipAddress();
public abstract int ipPrefixLen();
@Nullable public abstract String ipv6Gateway();
@Nullable public abstract String macAddress();
public abstract Map<String, Details> networks();
@Nullable public abstract String portMapping();
NetworkSettings() {
}
@SerializedNames({ "Bridge", "SandboxID", "HairpinMode", "LinkLocalIPv6Address",
"LinkLocalIPv6PrefixLen", "Ports", "SandboxKey", "SecondaryIPAddresses",
"SecondaryIPv6Addresses", "EndpointID", "Gateway", "GlobalIPv6Address",
"GlobalIPv6PrefixLen", "IPAddress", "IPPrefixLen", "IPv6Gateway",
"MacAddress", "Networks", "PortMapping" })
public static NetworkSettings create(String bridge, String sandboxId, boolean hairpinMode, String linkLocalIPv6Address,
int linkLocalIPv6PrefixLen, Map<String, List<Map<String, String>>> ports, String sandboxKey, List<String> secondaryIPAddresses,
List<String> secondaryIPv6Addresses, String endpointId, String gateway, String globalIPv6Address,
int globalIPv6PrefixLen, String ipAddress, int ipPrefixLen, String ipv6Gateway,
String macAddress, Map<String, Details> networks, String portMapping) {
return new AutoValue_NetworkSettings(
bridge, sandboxId, hairpinMode, linkLocalIPv6Address,
linkLocalIPv6PrefixLen, ports, sandboxKey, copyOf(secondaryIPAddresses), copyOf(secondaryIPv6Addresses),
endpointId, gateway, globalIPv6Address, globalIPv6PrefixLen,
ipAddress, ipPrefixLen, ipv6Gateway,
macAddress, copyOf(networks), portMapping);
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().fromNetworkSettings(this);
}
public static final class Builder {
private String ipAddress;
private int ipPrefixLen;
private String gateway;
private String bridge;
private String portMapping;
private Map<String, List<Map<String, String>>> ports;
private String sandboxId;
private boolean hairpinMode;
private String linkLocalIPv6Address;
private int linkLocalIPv6PrefixLen;
private String sandboxKey;
private List<String> secondaryIPAddresses = Lists.newArrayList();
private List<String> secondaryIPv6Addresses = Lists.newArrayList();
private String endpointId;
private String globalIPv6Address;
private int globalIPv6PrefixLen;
private String ipv6Gateway;
private String macAddress;
private Map<String, Details> networks = Maps.newHashMap();
public Builder ipAddress(String ipAddress) {
this.ipAddress = ipAddress;
return this;
}
public Builder ipPrefixLen(int ipPrefixLen) {
this.ipPrefixLen = ipPrefixLen;
return this;
}
public Builder gateway(String gateway) {
this.gateway = gateway;
return this;
}
public Builder bridge(String bridge) {
this.bridge = bridge;
return this;
}
public Builder portMapping(String portMapping) {
this.portMapping = portMapping;
return this;
}
public Builder ports(Map<String, List<Map<String, String>>> ports) {
this.ports = NullSafeCopies.copyWithNullOf(ports);
return this;
}
public Builder sandboxId(String sandboxId) {
this.sandboxId = sandboxId;
return this;
}
public Builder hairpinMode(boolean hairpinMode) {
this.hairpinMode = hairpinMode;
return this;
}
public Builder linkLocalIPv6Address(String linkLocalIPv6Address) {
this.linkLocalIPv6Address = linkLocalIPv6Address;
return this;
}
public Builder linkLocalIPv6PrefixLen(int linkLocalIPv6PrefixLen) {
this.linkLocalIPv6PrefixLen = linkLocalIPv6PrefixLen;
return this;
}
public Builder sandboxKey(String sandboxKey) {
this.sandboxKey = sandboxKey;
return this;
}
public Builder secondaryIPAddresses(List<String> secondaryIPAddresses) {
this.secondaryIPAddresses = secondaryIPAddresses;
return this;
}
public Builder secondaryIPv6Addresses(List<String> secondaryIPv6Addresses) {
this.secondaryIPv6Addresses = secondaryIPv6Addresses;
return this;
}
public Builder endpointId(String endpointId) {
this.endpointId = endpointId;
return this;
}
public Builder globalIPv6Address(String globalIPv6Address) {
this.globalIPv6Address = globalIPv6Address;
return this;
}
public Builder globalIPv6PrefixLen(int globalIPv6PrefixLen) {
this.globalIPv6PrefixLen = globalIPv6PrefixLen;
return this;
}
public Builder ipv6Gateway(String ipv6Gateway) {
this.ipv6Gateway = ipv6Gateway;
return this;
}
public Builder macAddress(String macAddress) {
this.macAddress = macAddress;
return this;
}
public Builder networks(Map<String, Details> networks) {
this.networks.putAll(networks);
return this;
}
public NetworkSettings build() {
return NetworkSettings.create(bridge, sandboxId, hairpinMode, linkLocalIPv6Address, linkLocalIPv6PrefixLen, ports,
sandboxKey, secondaryIPAddresses, secondaryIPv6Addresses, endpointId, gateway,
globalIPv6Address, globalIPv6PrefixLen, ipAddress, ipPrefixLen, ipv6Gateway, macAddress, networks, portMapping);
}
public Builder fromNetworkSettings(NetworkSettings in) {
return this.ipAddress(in.ipAddress()).ipPrefixLen(in.ipPrefixLen()).gateway(in.gateway()).bridge(in.bridge())
.portMapping(in.portMapping()).ports(in.ports()).sandboxId(in.sandboxId()).hairpinMode(in.hairpinMode()).linkLocalIPv6Address(in
.linkLocalIPv6Address()).linkLocalIPv6PrefixLen(in.linkLocalIPv6PrefixLen()).sandboxKey(in.sandboxKey()).secondaryIPAddresses(in
.secondaryIPAddresses()).secondaryIPv6Addresses(in.secondaryIPv6Addresses()).endpointId(in.endpointId()).globalIPv6Address(in
.globalIPv6Address()).globalIPv6PrefixLen(in.globalIPv6PrefixLen()).ipv6Gateway(in.ipv6Gateway()).macAddress(in.macAddress())
.networks(in.networks());
}
}
}

View File

@ -0,0 +1,63 @@
/*
* 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.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class Node {
Node() {
}
@SerializedNames({"IP"})
public static Node create(String ip) {
return new AutoValue_Node(ip);
}
public static Builder builder() {
return new Builder();
}
@Nullable
public abstract String ip();
public Builder toBuilder() {
return builder().fromNode(this);
}
public static final class Builder {
private String ip;
public Builder ip(String ip) {
this.ip = ip;
return this;
}
public Node build() {
return Node.create(this.ip);
}
public Builder fromNode(Node in) {
return this.ip(in.ip());
}
}
}

View File

@ -0,0 +1,41 @@
/*
* 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.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class Port {
@Nullable public abstract String ip();
public abstract int privatePort();
@Nullable public abstract Integer publicPort();
public abstract String type();
Port() {
}
@SerializedNames({ "IP", "PrivatePort", "PublicPort", "Type" })
public static Port create(String ip, int privatePort, Integer publicPort, String type) {
return new AutoValue_Port(ip, privatePort, publicPort, type);
}
}

View File

@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.domain;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class Resource {
public abstract String resource();
Resource() {
}
@SerializedNames({ "Resource" })
public static Resource create(String resource) {
return new AutoValue_Resource(resource);
}
}

View File

@ -0,0 +1,58 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.domain;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class State {
public abstract int pid();
public abstract boolean running();
public abstract int exitCode();
public abstract String startedAt();
public abstract String finishedAt();
public abstract boolean paused();
public abstract boolean restarting();
@Nullable public abstract String status();
public abstract boolean oomKilled();
public abstract boolean dead();
@Nullable public abstract String error();
State() {
}
@SerializedNames({ "Pid", "Running", "ExitCode", "StartedAt", "FinishedAt", "Paused", "Restarting", "Status", "OOMKilled", "Dead", "Error" })
public static State create(int pid, boolean running, int exitCode, String startedAt, String finishedAt,
boolean paused, boolean restarting, String status, boolean oomKilled, boolean dead, String error) {
return new AutoValue_State(pid, running, exitCode, startedAt, finishedAt, paused, restarting, status, oomKilled, dead, error);
}
}

View File

@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.domain;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class StatusCode {
public abstract int statusCode();
StatusCode() {
}
@SerializedNames({ "StatusCode" })
public static StatusCode create(int statusCode) {
return new AutoValue_StatusCode(statusCode);
}
}

View File

@ -0,0 +1,48 @@
/*
* 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 Version {
public abstract String apiVersion();
public abstract String arch();
public abstract String gitCommit();
public abstract String goVersion();
public abstract String kernelVersion();
public abstract String os();
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) {
return new AutoValue_Version(apiVersion, arch, gitCommit, goVersion, kernelVersion, os, version);
}
}

View File

@ -0,0 +1,252 @@
/*
* 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.features;
import java.io.InputStream;
import java.util.List;
import javax.inject.Named;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
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;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.binders.BindToJsonPayload;
@Consumes(MediaType.APPLICATION_JSON)
@Path("/v{jclouds.api-version}")
public interface ContainerApi {
/**
* @return a set of containers
*/
@Named("containers:list")
@GET
@Path("/containers/json")
@Fallback(EmptyListOnNotFoundOr404.class)
List<ContainerSummary> listContainers();
/**
* @param options the options to list the containers (@see ListContainerOptions)
* @return a set of containers
*/
@Named("containers:list")
@GET
@Path("/containers/json")
@Fallback(EmptyListOnNotFoundOr404.class)
List<ContainerSummary> listContainers(ListContainerOptions options);
/**
* @param name the name for the new container. Must match /?[a-zA-Z0-9_-]+.
* @param config the containers configuration (@see BindToJsonPayload)
* @return a new container
*/
@Named("container:create")
@POST
@Path("/containers/create")
Container createContainer(@QueryParam("name") String name, @BinderParam(BindToJsonPayload.class) Config config);
/**
* Return low-level information on the container id
* @param containerId The id of the container to get.
* @return The details of the container or <code>null</code> if the container with the given id doesn't exist.
*/
@Named("container:inspect")
@GET
@Path("/containers/{id}/json")
@Fallback(NullOnNotFoundOr404.class)
Container inspectContainer(@PathParam("id") String containerId);
/**
* @param containerId The id of the container to be removed.
*/
@Named("container:delete")
@DELETE
@Path("/containers/{id}")
void removeContainer(@PathParam("id") String containerId);
/**
* @param containerId The id of the container to be removed.
* @param options the operations configuration (@see RemoveContainerOptions)
*/
@Named("container:delete")
@DELETE
@Path("/containers/{id}")
void removeContainer(@PathParam("id") String containerId, RemoveContainerOptions options);
/**
* @param containerId The id of the container to be started.
*/
@Named("container:start")
@POST
@Path("/containers/{id}/start")
void startContainer(@PathParam("id") String containerId);
/**
* @param containerId The id of the container to be started.
* @param hostConfig the containers host configuration
*/
@Named("container:start")
@POST
@Path("/containers/{id}/start")
void startContainer(@PathParam("id") String containerId, @BinderParam(BindToJsonPayload.class) HostConfig hostConfig);
/**
* @param containerId The id of the container to be stopped.
*/
@Named("container:stop")
@POST
@Path("/containers/{id}/stop")
void stopContainer(@PathParam("id") String containerId);
@Named("container:stop")
@POST
@Path("/containers/{id}/stop")
void stopContainer(@PathParam("id") String containerId, @QueryParam("t") int secondsToWait);
/**
* Create a new image from a containers changes
*
* @return a new image created from the current container's status.
*/
@Named("container:commit")
@POST
@Path("/commit")
Image commit();
/**
* Create a new image from a containers changes
*
* @param options the commits configuration (@see CommitOptions)
* @return a new image created from the current container's status.
*/
@Named("container:commit")
@POST
@Path("/commit")
Image commit(CommitOptions options);
/**
* @param containerId The id of the container to be paused.
*/
@Named("container:pause")
@POST
@Path("/containers/{id}/pause")
void pause(@PathParam("id") String containerId);
/**
* @param containerId The id of the container to be unpaused.
*/
@Named("container:unpause")
@POST
@Path("/containers/{id}/unpause")
void unpause(@PathParam("id") String containerId);
/**
* @param containerId The id of the container to be attached.
*/
@Named("container:attach")
@POST
@Path("/containers/{id}/attach")
InputStream attach(@PathParam("id") String containerId);
/**
* @param containerId The id of the container to be attached.
* @param options the attach options @see org.jclouds.docker.options.AttachOptions
*
*/
@Named("container:attach")
@POST
@Path("/containers/{id}/attach")
InputStream attach(@PathParam("id") String containerId, AttachOptions options);
/**
* Block until container @param containerId stops, then returns the exit code
*/
@Named("container:wait")
@POST
@Path("/containers/{id}/wait")
StatusCode wait(@PathParam("id") String containerId);
/**
* @param containerId restarts
*/
@Named("container:restart")
@POST
@Path("/containers/{id}/restart")
void restart(@PathParam("id") String containerId);
@Named("container:restart")
@POST
@Path("/containers/{id}/restart")
void restart(@PathParam("id") String containerId, @QueryParam("t") int secondsToWait);
/**
* @param containerId to be killed
*/
@Named("container:kill")
@POST
@Path("/containers/{id}/kill")
void kill(@PathParam("id") String containerId);
/**
* @param containerId to be killed
* @param signal Signal to send to the container. When not set, SIGKILL is assumed and the call will waits for the
* container to exit.
*/
@Named("container:kill")
@POST
@Path("/containers/{id}/kill")
void kill(@PathParam("id") String containerId, @QueryParam("signal") int signal);
/**
* @param containerId to be killed
* @param signal Signal string like "SIGINT" to send to the container. When not set, SIGKILL is assumed and the call will waits for
* the container to exit.
*/
@Named("container:kill")
@POST
@Path("/containers/{id}/kill")
void kill(@PathParam("id") String containerId, @QueryParam("signal") String signal);
/**
* @param containerId id of the container to copy files from
*/
@Named("container:copy")
@POST
@Path("/containers/{id}/copy")
InputStream copy(@PathParam("id") String containerId, @BinderParam(BindToJsonPayload.class) Resource resource);
}

View File

@ -0,0 +1,139 @@
/*
* 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.features;
import java.io.InputStream;
import java.util.List;
import javax.inject.Named;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.docker.domain.Image;
import org.jclouds.docker.domain.ImageHistory;
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 {
/**
* @return the images available.
*/
@Named("images:list")
@GET
@Path("/images/json")
@Fallback(EmptyListOnNotFoundOr404.class)
List<ImageSummary> listImages();
/**
* @param options the configuration to list images (@see ListImageOptions)
* @return the images available.
*/
@Named("images:list")
@GET
@Path("/images/json")
@Fallback(EmptyListOnNotFoundOr404.class)
List<ImageSummary> listImages(ListImageOptions options);
/**
* Return low-level information on the image with given name. Not all fields from the returned {@link Image} instance
* are populated by this method (e.g. {@link Image#repoTags()}).
*
* @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(NullOnNotFoundOr404.class)
@Nullable
Image inspectImage(@PathParam("name") String imageName);
/**
* Create an image, either by pull it from the registry or by importing it
*
* @param options the configuration to create an image (@see CreateImageOptions)
* @return a stream of the image creation.
*/
@Named("image:create")
@POST
@Path("/images/create")
InputStream createImage(CreateImageOptions options);
/**
* @param name the image name to be deleted
* @return the stream of the deletion execution.
*/
@Named("image:delete")
@DELETE
@Path("/images/{name}")
InputStream deleteImage(@PathParam("name") String 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.
*/
@Named("image:delete")
@DELETE
@Path("/images/{name}")
InputStream deleteImage(@PathParam("name") String name, DeleteImageOptions options);
/**
* Tag the image name into a repository.
*
* @param name
* the name of the image to be tagged
* @param repoName
* the repository to tag in
* @param tag
* the new tag name
* @param force
* force create if tag already exists
*/
@Named("image:tag")
@POST
@Path("/images/{name}/tag")
void tagImage(@PathParam("name") String name, @QueryParam("repo") String repoName,
@QueryParam("tag") String tag, @QueryParam("force") boolean force);
/**
* Return the history of the image with given {@code name}.
*
* @param name
* the name of the image for which the history is retrieved
*/
@Named("image:history")
@GET
@Path("/images/{name}/history")
@Fallback(EmptyListOnNotFoundOr404.class)
List<ImageHistory> getHistory(@PathParam("name") String name);
}

View File

@ -0,0 +1,140 @@
/*
* 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.features;
import java.io.InputStream;
import javax.inject.Named;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.docker.domain.Exec;
import org.jclouds.docker.domain.ExecCreateParams;
import org.jclouds.docker.domain.ExecInspect;
import org.jclouds.docker.domain.ExecStartParams;
import org.jclouds.docker.domain.Info;
import org.jclouds.docker.domain.Version;
import org.jclouds.docker.options.BuildOptions;
import org.jclouds.docker.util.DockerInputStream;
import org.jclouds.io.Payload;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.binders.BindToJsonPayload;
@Consumes(MediaType.APPLICATION_JSON)
@Path("/v{jclouds.api-version}")
public interface MiscApi {
/**
* Get the information of the current docker version.
*
* @return The information of the current docker version.
*/
@Named("version")
@GET
@Path("/version")
Version getVersion();
/**
* Get the information of the current docker version.
*
* @return The information of the current docker version.
*/
@Named("info")
@GET
@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", "Connection" }, values = { "application/tar", "close" })
InputStream build(Payload inputStream);
/**
* 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.
* @param options the image build's options (@see BuildOptions)
* @return a stream of the build execution
*/
@Named("image:build")
@POST
@Path("/build")
@Headers(keys = { "Content-Type", "Connection" }, values = { "application/tar", "close" })
InputStream build(Payload inputStream, BuildOptions options);
/**
* Sets up an exec instance in a running container with given Id.
*
* @param containerId
* container Id
* @param execCreateParams
* exec parameters
* @return an instance which holds exec identifier
*/
@Named("container:exec")
@POST
@Path("/containers/{id}/exec")
Exec execCreate(@PathParam("id") String containerId,
@BinderParam(BindToJsonPayload.class) ExecCreateParams execCreateParams);
/**
* Starts a previously set up exec instance id. If
* {@link ExecStartParams#detach()} is true, this API returns after starting
* the exec command. Otherwise, this API sets up an interactive session with
* the exec command.
*
* @param execId
* exec instance id
* @param execStartParams
* start parameters
* @return raw docker stream which can be wrapped to
* {@link DockerInputStream}
* @see #execCreate(String, ExecCreateParams)
* @see DockerInputStream
*/
@Named("exec:start")
@POST
@Path("/exec/{id}/start")
InputStream execStart(@PathParam("id") String execId,
@BinderParam(BindToJsonPayload.class) ExecStartParams execStartParams);
/**
* Returns low-level information about the exec command id.
*
* @param execId
* exec instance id
* @return details about exec instance
*/
@Named("exec:inspect")
@GET
@Path("/exec/{id}/json")
ExecInspect execInspect(@PathParam("id") String execId);
}

View File

@ -0,0 +1,100 @@
/*
* 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.features;
import java.util.List;
import javax.inject.Named;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.docker.domain.Network;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.Payload;
import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.binders.BindToJsonPayload;
@Consumes(MediaType.APPLICATION_JSON)
@Path("/v{jclouds.api-version}/networks")
public interface NetworkApi {
/**
* @return a set of networks
*/
@Named("networks:list")
@GET
@Fallback(EmptyListOnNotFoundOr404.class)
List<Network> listNetworks();
/**
* @param network the networks configuration (@see BindToJsonPayload)
* @return a new network
*/
@Named("network:create")
@POST
@Path("/create")
Network createNetwork(@BinderParam(BindToJsonPayload.class) Network network);
/**
* Return low-level information on the network id
* @param networkIdOrName The id or name of the network to get.
* @return The details of the network or <code>null</code> if the network with the given id doesn't exist.
*/
@Named("network:inspect")
@GET
@Path("/{idOrName}")
@Fallback(NullOnNotFoundOr404.class)
Network inspectNetwork(@PathParam("idOrName") String networkIdOrName);
/**
* @param networkIdOrName The id or name of the network to be removed.
*/
@Named("network:delete")
@DELETE
@Path("/{idOrName}")
void removeNetwork(@PathParam("idOrName") String networkIdOrName);
/**
* @param networkIdOrName The id or name of the network where the container will be attached.
*/
@Named("network:connectContainer")
@POST
@Path("/{idOrName}/connect")
@Payload("%7B\"Container\":\"{containerIdOrName}\"%7D")
@Headers(keys = "Content-Type", values = "application/json")
void connectContainerToNetwork(@PathParam("idOrName") String networkIdOrName, @PayloadParam("containerIdOrName") String containerIdOrName);
/**
* @param networkIdOrName The id or name of the network where the container was attached.
*/
@Named("network:disconnectContainer")
@POST
@Path("/{idOrName}/disconnect")
@Payload("%7B\"Container\":\"{containerIdOrName}\"%7D")
@Headers(keys = "Content-Type", values = "application/json")
void disconnectContainerFromNetwork(@PathParam("idOrName") String networkIdOrName, @PayloadParam("containerIdOrName") String containerIdOrName);
}

View File

@ -0,0 +1,98 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.handlers;
import static org.jclouds.util.Closeables2.closeQuietly;
import java.io.IOException;
import javax.annotation.Resource;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.util.Strings2;
import com.google.common.base.Throwables;
/**
* This will parse and set an appropriate exception on the command object.
* <p/>
* <p/>
* Errors are returned with an appropriate HTTP status code, an X-Elastic- Error header specifying
* the error type, and a text description in the HTTP body.
*/
public class DockerErrorHandler implements HttpErrorHandler {
@Resource
protected Logger logger = Logger.NULL;
public void handleError(HttpCommand command, HttpResponse response) {
// it is important to always read fully and close streams
String message = parseMessage(response);
Exception exception = message != null ? new HttpResponseException(command, response, message)
: new HttpResponseException(command, response);
try {
message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
response.getStatusLine());
switch (response.getStatusCode()) {
case 400:
if ((command.getCurrentRequest().getEndpoint().getPath().endsWith("/info"))
|| (message != null && message.indexOf("could not be found") != -1))
exception = new ResourceNotFoundException(message, exception);
else if (message != null && message.indexOf("currently in use") != -1)
exception = new IllegalStateException(message, exception);
else
exception = new IllegalArgumentException(message, exception);
break;
case 401:
exception = new AuthorizationException(message, exception);
break;
case 402:
exception = new IllegalStateException(message, exception);
break;
case 404:
if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
exception = new ResourceNotFoundException(message, exception);
}
break;
case 405:
exception = new IllegalArgumentException(message, exception);
break;
case 409:
exception = new IllegalStateException(message, exception);
break;
}
} finally {
closeQuietly(response.getPayload());
command.setException(exception);
}
}
public String parseMessage(HttpResponse response) {
if (response.getPayload() == null)
return null;
try {
return Strings2.toStringAndClose(response.getPayload().openStream());
} catch (IOException e) {
throw Throwables.propagate(e);
}
}
}

View File

@ -0,0 +1,95 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.internal;
import java.util.List;
import java.util.Map;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
public class NullSafeCopies {
public static <K, V> Map<K, V> copyOf(@Nullable Map<K, V> map) {
return map != null ? ImmutableMap.copyOf(map) : ImmutableMap.<K, V> of();
}
public static <E> List<E> copyOf(@Nullable List<E> list) {
return list != null ? ImmutableList.copyOf(list) : ImmutableList.<E> of();
}
public static <E> List<E> copyOf(@Nullable Iterable<E> list) {
return list != null ? ImmutableList.copyOf(list) : ImmutableList.<E> of();
}
public static <E> List<E> copyOf(@Nullable E[] array) {
return array != null ? ImmutableList.copyOf(array) : ImmutableList.<E> of();
}
/**
* Copies given List with keeping null value if provided.
*
* @param list
* instance to copy (maybe <code>null</code>)
* @return if the parameter is not-<code>null</code> then immutable copy;
* <code>null</code> otherwise
*/
public static <E> List<E> copyWithNullOf(@Nullable List<E> list) {
return list != null ? ImmutableList.copyOf(list) : null;
}
/**
* Copies given Map with keeping null value if provided.
*
* @param map
* instance to copy (maybe <code>null</code>)
* @return if the parameter is not-<code>null</code> then immutable copy;
* <code>null</code> otherwise
*/
public static <K, V> Map<K, V> copyWithNullOf(@Nullable Map<K, V> map) {
return map != null ? ImmutableMap.copyOf(map) : null;
}
/**
* Copies given {@link Iterable} into immutable {@link List} with keeping null value if provided.
*
* @param iterable
* instance to copy (maybe <code>null</code>)
* @return if the parameter is not-<code>null</code> then immutable copy;
* <code>null</code> otherwise
*/
public static <E> List<E> copyWithNullOf(@Nullable Iterable<E> iterable) {
return iterable != null ? ImmutableList.copyOf(iterable) : null;
}
/**
* Copies given array into immutable {@link List} with keeping null value if provided.
*
* @param array
* instance to copy (maybe <code>null</code>)
* @return if the parameter is not-<code>null</code> then immutable copy;
* <code>null</code> otherwise
*/
public static <E> List<E> copyWithNullOf(@Nullable E[] array) {
return array != null ? ImmutableList.copyOf(array) : null;
}
private NullSafeCopies() {
}
}

View File

@ -0,0 +1,114 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.options;
import org.jclouds.http.options.BaseHttpRequestOptions;
public class AttachOptions extends BaseHttpRequestOptions {
/**
* @param stream When TTY is enabled, the stream is the raw data from the process PTY and client's stdin.
* When TTY is disabled, the stream is multiplexed to separate stdout and stderr.
* @return AttachOptions
*/
public AttachOptions stream(boolean stream) {
this.queryParameters.put("stream", String.valueOf(stream));
return this;
}
/**
* @param logs require logs to be attached. Default false.
* @return AttachOptions
*/
public AttachOptions logs(boolean logs) {
this.queryParameters.put("logs", String.valueOf(logs));
return this;
}
/**
* @param stdin if stream=true, attach to stdin. Default false
* @return AttachOptions
*/
public AttachOptions stdin(boolean stdin) {
this.queryParameters.put("stdin", String.valueOf(stdin));
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", String.valueOf(stdout));
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", String.valueOf(stderr));
return this;
}
public static class Builder {
/**
* @see org.jclouds.docker.options.AttachOptions#stream
*/
public static AttachOptions stream(boolean stream) {
AttachOptions options = new AttachOptions();
return options.stream(stream);
}
/**
* @see org.jclouds.docker.options.AttachOptions#logs(Boolean)
*/
public static AttachOptions logs(boolean logs) {
AttachOptions options = new AttachOptions();
return options.logs(logs);
}
/**
* @see org.jclouds.docker.options.AttachOptions#stdin(Boolean)
*/
public static AttachOptions stdin(boolean stdin) {
AttachOptions options = new AttachOptions();
return options.stdin(stdin);
}
/**
* @see org.jclouds.docker.options.AttachOptions#stdout(Boolean)
*/
public static AttachOptions stdout(boolean stdout) {
AttachOptions options = new AttachOptions();
return options.stdout(stdout);
}
/**
* @see org.jclouds.docker.options.AttachOptions#stderr(Boolean)
*/
public static AttachOptions stderr(boolean stderr) {
AttachOptions options = new AttachOptions();
return options.stderr(stderr);
}
}
}

View File

@ -0,0 +1,66 @@
/*
* 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 BuildOptions extends BaseHttpRequestOptions {
public BuildOptions tag(String tag) {
this.queryParameters.put("t", tag);
return this;
}
public BuildOptions verbose(boolean verbose) {
this.queryParameters.put("verbose", String.valueOf(verbose));
return this;
}
public BuildOptions nocache(boolean nocache) {
this.queryParameters.put("nocache", String.valueOf(nocache));
return this;
}
public static class Builder {
/**
* @see BuildOptions#tag
*/
public static BuildOptions tag(String tag) {
BuildOptions options = new BuildOptions();
return options.tag(tag);
}
/**
* @see BuildOptions#verbose(Boolean)
*/
public static BuildOptions verbose(boolean verbose) {
BuildOptions options = new BuildOptions();
return options.verbose(verbose);
}
/**
* @see BuildOptions#nocache(Boolean)
*/
public static BuildOptions nocache(boolean nocache) {
BuildOptions options = new BuildOptions();
return options.nocache(nocache);
}
}
}

View File

@ -0,0 +1,104 @@
/*
* 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 CommitOptions extends BaseHttpRequestOptions {
public CommitOptions containerId(String containerId) {
this.queryParameters.put("containerId", containerId);
return this;
}
public CommitOptions repository(String repository) {
this.queryParameters.put("repository", repository);
return this;
}
public CommitOptions tag(String tag) {
this.queryParameters.put("tag", tag);
return this;
}
public CommitOptions message(String message) {
this.queryParameters.put("message", message);
return this;
}
public CommitOptions author(String author) {
this.queryParameters.put("author", author);
return this;
}
public CommitOptions run(String run) {
this.queryParameters.put("run", run);
return this;
}
public static class Builder {
/**
* @see CommitOptions#containerId
*/
public static CommitOptions containerId(String containerId) {
CommitOptions options = new CommitOptions();
return options.containerId(containerId);
}
/**
* @see CommitOptions#repository
*/
public static CommitOptions repository(String repository) {
CommitOptions options = new CommitOptions();
return options.repository(repository);
}
/**
* @see CommitOptions#tag
*/
public static CommitOptions tag(String tag) {
CommitOptions options = new CommitOptions();
return options.tag(tag);
}
/**
* @see CommitOptions#message
*/
public static CommitOptions message(String message) {
CommitOptions options = new CommitOptions();
return options.message(message);
}
/**
* @see CommitOptions#author
*/
public static CommitOptions author(String author) {
CommitOptions options = new CommitOptions();
return options.author(author);
}
/**
* @see CommitOptions#run
*/
public static CommitOptions run(String run) {
CommitOptions options = new CommitOptions();
return options.run(run);
}
}
}

View File

@ -0,0 +1,90 @@
/*
* 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 CreateImageOptions extends BaseHttpRequestOptions {
public CreateImageOptions fromImage(String fromImage) {
this.queryParameters.put("fromImage", fromImage);
return this;
}
public CreateImageOptions fromSrc(String fromSrc) {
this.queryParameters.put("fromSrc", fromSrc);
return this;
}
public CreateImageOptions repo(String repo) {
this.queryParameters.put("repo", repo);
return this;
}
public CreateImageOptions tag(String tag) {
this.queryParameters.put("tag", tag);
return this;
}
public CreateImageOptions registry(String registry) {
this.queryParameters.put("registry", registry);
return this;
}
public static class Builder {
/**
* @see CreateImageOptions#fromImage
*/
public static CreateImageOptions fromImage(String fromImage) {
CreateImageOptions options = new CreateImageOptions();
return options.fromImage(fromImage);
}
/**
* @see CreateImageOptions#fromSrc
*/
public static CreateImageOptions fromSrc(String fromSrc) {
CreateImageOptions options = new CreateImageOptions();
return options.fromSrc(fromSrc);
}
/**
* @see CreateImageOptions#repo
*/
public static CreateImageOptions repo(String repo) {
CreateImageOptions options = new CreateImageOptions();
return options.repo(repo);
}
/**
* @see CreateImageOptions#tag
*/
public static CreateImageOptions tag(String tag) {
CreateImageOptions options = new CreateImageOptions();
return options.tag(tag);
}
/**
* @see CreateImageOptions#registry
*/
public static CreateImageOptions registry(String registry) {
CreateImageOptions options = new CreateImageOptions();
return options.registry(registry);
}
}
}

View File

@ -0,0 +1,52 @@
/*
* 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 DeleteImageOptions extends BaseHttpRequestOptions {
public DeleteImageOptions force(boolean force) {
this.queryParameters.put("force", String.valueOf(force));
return this;
}
public DeleteImageOptions noPrune(boolean noPrune) {
this.queryParameters.put("noPrune", String.valueOf(noPrune));
return this;
}
public static class Builder {
/**
* @see DeleteImageOptions#force
*/
public static DeleteImageOptions force(boolean force) {
DeleteImageOptions options = new DeleteImageOptions();
return options.force(force);
}
/**
* @see DeleteImageOptions#noPrune
*/
public static DeleteImageOptions noPrune(boolean noPrune) {
DeleteImageOptions options = new DeleteImageOptions();
return options.noPrune(noPrune);
}
}
}

View File

@ -0,0 +1,92 @@
/*
* 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 ListContainerOptions extends BaseHttpRequestOptions {
public ListContainerOptions all(boolean all) {
this.queryParameters.put("all", String.valueOf(all));
return this;
}
public ListContainerOptions limit(Integer limit) {
this.queryParameters.put("limit", limit.toString());
return this;
}
public ListContainerOptions since(Integer since) {
this.queryParameters.put("since", since.toString());
return this;
}
public ListContainerOptions before(Integer before) {
this.queryParameters.put("before", before.toString());
return this;
}
public ListContainerOptions size(Integer size) {
this.queryParameters.put("size", size.toString());
return this;
}
public static class Builder {
/**
* @see ListContainerOptions#all
*/
public static ListContainerOptions all(boolean all) {
ListContainerOptions options = new ListContainerOptions();
return options.all(all);
}
/**
* @see ListContainerOptions#limit(Integer)
*/
public static ListContainerOptions limit(Integer limit) {
ListContainerOptions options = new ListContainerOptions();
return options.limit(limit);
}
/**
* @see ListContainerOptions#since(Integer)
*/
public static ListContainerOptions since(Integer since) {
ListContainerOptions options = new ListContainerOptions();
return options.since(since);
}
/**
* @see ListContainerOptions#before(Integer)
*/
public static ListContainerOptions before(Integer before) {
ListContainerOptions options = new ListContainerOptions();
return options.before(before);
}
/**
* @see ListContainerOptions#limit(Integer)
*/
public static ListContainerOptions size(Integer size) {
ListContainerOptions options = new ListContainerOptions();
return options.size(size);
}
}
}

View File

@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.options;
import org.jclouds.http.options.BaseHttpRequestOptions;
public class ListImageOptions extends BaseHttpRequestOptions {
public ListImageOptions all(boolean all) {
this.queryParameters.put("all", String.valueOf(all));
return this;
}
public static class Builder {
/**
* @see ListImageOptions#all
*/
public static ListImageOptions all(boolean all) {
ListImageOptions options = new ListImageOptions();
return options.all(all);
}
}
}

View File

@ -0,0 +1,69 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.options;
import org.jclouds.http.options.BaseHttpRequestOptions;
public class RemoveContainerOptions extends BaseHttpRequestOptions {
public RemoveContainerOptions verbose(boolean verbose) {
this.queryParameters.put("verbose", String.valueOf(verbose));
return this;
}
public RemoveContainerOptions force(boolean force) {
this.queryParameters.put("force", String.valueOf(force));
return this;
}
/**
* Remove the volumes associated to the container
*
* @param volume If set to true the volume associated to the container will be removed.
* Otherwise it will not be removed.
*/
public RemoveContainerOptions volume(boolean volume) {
this.queryParameters.put("v", String.valueOf(volume));
return this;
}
public static class Builder {
/**
* @see RemoveContainerOptions#verbose
*/
public static RemoveContainerOptions verbose(boolean verbose) {
RemoveContainerOptions options = new RemoveContainerOptions();
return options.verbose(verbose);
}
/**
* @see RemoveContainerOptions#force
*/
public static RemoveContainerOptions force(boolean force) {
RemoveContainerOptions options = new RemoveContainerOptions();
return options.force(force);
}
/**
* @see RemoveContainerOptions#volume
*/
public static RemoveContainerOptions volume(boolean volume) {
RemoveContainerOptions options = new RemoveContainerOptions();
return options.volume(volume);
}
}
}

View File

@ -0,0 +1,74 @@
/*
* 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 com.google.common.base.Strings;
import com.google.common.base.Supplier;
import org.jclouds.docker.DockerApiMetadata;
import org.jclouds.domain.Credentials;
import org.jclouds.location.Provider;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.security.GeneralSecurityException;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Throwables.propagate;
import static org.jclouds.docker.suppliers.SSLContextBuilder.isClientKeyAndCertificateData;
@Singleton
public class DockerSSLContextSupplier implements Supplier<SSLContext> {
private final Supplier<Credentials> creds;
private final String caCertPath;
private final String caCertData;
@Inject
DockerSSLContextSupplier(@Provider Supplier<Credentials> creds, @Named(DockerApiMetadata.DOCKER_CA_CERT_PATH) String caCertPath, @Named(DockerApiMetadata.DOCKER_CA_CERT_DATA) String caCertData) {
this.creds = creds;
this.caCertPath = caCertPath;
this.caCertData = caCertData;
}
@Override
public SSLContext get() {
Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null");
try {
SSLContextBuilder builder = new SSLContextBuilder();
if (isClientKeyAndCertificateData(currentCreds.credential, currentCreds.identity)) {
builder.clientKeyAndCertificateData(currentCreds.credential, currentCreds.identity);
} else {
builder.clientKeyAndCertificatePaths(currentCreds.credential, currentCreds.identity);
}
if (!Strings.isNullOrEmpty(caCertPath)) {
builder.caCertificatePath(caCertPath);
} else if (!Strings.isNullOrEmpty(caCertData)) {
builder.caCertificateData(caCertData);
}
return builder.build();
} catch (GeneralSecurityException e) {
throw propagate(e);
} catch (IOException e) {
throw propagate(e);
}
}
}

View File

@ -0,0 +1,69 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.suppliers;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Supplier;
import org.jclouds.domain.Credentials;
import org.jclouds.http.config.SSLModule;
import org.jclouds.location.Provider;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import static com.google.common.base.Throwables.propagate;
import static org.jclouds.docker.suppliers.SSLContextBuilder.isClientKeyAndCertificateData;
@Singleton
public class DockerUntrustedSSLContextSupplier implements Supplier<SSLContext> {
private final Supplier<Credentials> creds;
private final SSLModule.TrustAllCerts insecureTrustManager;
@Inject
DockerUntrustedSSLContextSupplier(@Provider Supplier<Credentials> creds,
SSLModule.TrustAllCerts insecureTrustManager) {
this.creds = creds;
this.insecureTrustManager = insecureTrustManager;
}
@Override
public SSLContext get() {
Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null");
try {
SSLContextBuilder builder = new SSLContextBuilder();
if (isClientKeyAndCertificateData(currentCreds.credential, currentCreds.identity)) {
builder.clientKeyAndCertificateData(currentCreds.credential, currentCreds.identity);
} else if (new File(currentCreds.identity).isFile() && new File(currentCreds.credential).isFile()) {
builder.clientKeyAndCertificatePaths(currentCreds.credential, currentCreds.identity);
}
builder.trustManager(insecureTrustManager);
return builder.build();
} catch (GeneralSecurityException e) {
throw propagate(e);
} catch (IOException e) {
throw propagate(e);
}
}
}

View File

@ -0,0 +1,201 @@
/*
* 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 com.google.common.base.Charsets;
import com.google.common.io.Files;
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.crypto.Pems;
import org.jclouds.util.Closeables2;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509ExtendedKeyManager;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.net.Socket;
import java.security.GeneralSecurityException;
import java.security.KeyManagementException;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import static com.google.common.base.Throwables.propagate;
public class SSLContextBuilder {
private KeyManager[] keyManagers;
private TrustManager[] trustManagers;
public static final boolean isClientKeyAndCertificateData(String key, String cert) {
return (key.startsWith(Pems.PRIVATE_PKCS1_MARKER) || key.startsWith(Pems.PRIVATE_PKCS8_MARKER)) &&
cert.startsWith(Pems.CERTIFICATE_X509_MARKER);
}
public SSLContextBuilder() { }
public SSLContextBuilder clientKeyAndCertificatePaths(String keyPath, String certPath) throws IOException, CertificateException {
X509Certificate certificate = getCertificate(loadFile(certPath));
PrivateKey privateKey = getKey(loadFile(keyPath));
keyManager(new InMemoryKeyManager(certificate, privateKey));
return this;
}
public SSLContextBuilder clientKeyAndCertificateData(String keyData, String certData) throws CertificateException {
X509Certificate certificate = getCertificate(certData);
PrivateKey privateKey = getKey(keyData);
keyManager(new InMemoryKeyManager(certificate, privateKey));
return this;
}
public SSLContextBuilder caCertificatePath(String caCertPath) {
try {
trustManagers = getTrustManagerWithCaCert(loadFile(caCertPath));
} catch (IOException e) {
throw propagate(e);
}
return this;
}
public SSLContextBuilder caCertificateData(String caCertPath) {
trustManagers = getTrustManagerWithCaCert(caCertPath);
return this;
}
public SSLContextBuilder keyManager(KeyManager keyManager) {
keyManagers = new KeyManager[] { keyManager };
return this;
}
public SSLContextBuilder trustManager(TrustManager trustManager) {
trustManagers = new TrustManager[] { trustManager };
return this;
}
public SSLContext build() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, new SecureRandom());
return sslContext;
}
private TrustManager[] getTrustManagerWithCaCert(String caCertData) {
try {
X509Certificate caCert = getCertificate(caCertData);
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
trustStore.setCertificateEntry("ca", caCert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
return tmf.getTrustManagers();
} catch (GeneralSecurityException 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) {
PEMParser pemParser = new PEMParser(new StringReader(privateKey));
try {
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);
} finally {
Closeables2.closeQuietly(pemParser);
}
}
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 CertificateException {
this.certificate = certificate;
this.privateKey = privateKey;
}
@Override
public String chooseClientAlias(final String[] keyType, final Principal[] issuers, final Socket socket) {
return DEFAULT_ALIAS;
}
@Override
public String chooseServerAlias(final String keyType, final Principal[] issuers, final Socket socket) {
return DEFAULT_ALIAS;
}
@Override
public X509Certificate[] getCertificateChain(final String alias) {
return new X509Certificate[] { certificate };
}
@Override
public String[] getClientAliases(final String keyType, final Principal[] issuers) {
return new String[] { DEFAULT_ALIAS };
}
@Override
public PrivateKey getPrivateKey(final String alias) {
return privateKey;
}
@Override
public String[] getServerAliases(final String keyType, final Principal[] issuers) {
return new String[] { DEFAULT_ALIAS };
}
}
}

View File

@ -0,0 +1,73 @@
/*
* 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.util;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Extension to {@link DataInputStream} which adds method
* {@link #readStdStreamData()} to allow read multiplexed standard streams.
*/
public final class DockerInputStream extends DataInputStream {
/**
* Ctor from superclass.
*
* @param in
* @see DataInputStream#DataInputStream(InputStream)
*/
public DockerInputStream(InputStream in) {
super(in);
}
/**
* @return {@link StdStreamData} instance read from the input stream or
* <code>null</code> if we reached end of the stream.
* @throws IOException
*/
public StdStreamData readStdStreamData() throws IOException {
byte[] header = new byte[8];
// try to read first byte from the message header - just to check if we
// are at the end
// of stream
if (-1 == read(header, 0, 1)) {
return null;
}
// read the rest of the header
readFully(header, 1, 7);
// decode size as an unsigned int
long size = (long) (header[4] & 0xFF) << 24 | (header[5] & 0xFF) << 16 | (header[6] & 0xFF) << 8
| (header[7] & 0xFF);
byte[] payload;
// The size from the header is an unsigned int so it can happen the byte
// array has not a sufficient size and we'll have to truncate the frame
payload = new byte[(int) Math.min(Integer.MAX_VALUE, size)];
readFully(payload);
boolean truncated = false;
if (size > Integer.MAX_VALUE) {
truncated = true;
// skip the rest
readFully(new byte[(int) (size - Integer.MAX_VALUE)]);
}
return new StdStreamData(header[0], payload, truncated);
}
}

View File

@ -0,0 +1,87 @@
/*
* 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.util;
import java.util.Arrays;
/**
* Representation of single message from docker-raw-stream. It holds stream
* type, data (payload) and flag which says if the payload was truncated. The
* truncation can occur when the frame size is greater than
* {@link Integer#MAX_VALUE}.
*/
public final class StdStreamData {
private final StdStreamType type;
private final byte[] payload;
private final boolean truncated;
/**
* Ctor.
*
* @param streamTypeId
* standard stream type (0=stdIn, 1=stdOut, 2=stdErr)
* @param payload
* message data - must not be <code>null</code>
* @param truncated
* @throws ArrayIndexOutOfBoundsException
* if streamTypeId is not an index in {@link StdStreamType} enum.
* @throws NullPointerException
* if provided payload is <code>null</code>
*/
StdStreamData(byte streamTypeId, byte[] payload, boolean truncated)
throws ArrayIndexOutOfBoundsException, NullPointerException {
this.type = StdStreamType.values()[streamTypeId];
this.payload = Arrays.copyOf(payload, payload.length);
this.truncated = truncated;
}
/**
* Type of stream.
*
* @return
*/
public StdStreamType getType() {
return type;
}
/**
* Data from this message.
*
* @return payload.
*/
public byte[] getPayload() {
return payload;
}
/**
* Flag which says if the payload was truncated (because of size).
*
* @return true if truncated
*/
public boolean isTruncated() {
return truncated;
}
/**
* Standard streams enum. The order of entries is important!
*/
public static enum StdStreamType {
IN, OUT, ERR;
}
}

View File

@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.apis.Apis;
import org.jclouds.compute.internal.BaseComputeServiceApiMetadataTest;
import org.testng.annotations.Test;
/**
* Unit tests for the {@link DockerApiMetadata} class.
*/
@Test(groups = "unit", testName = "AbiquoApiMetadataTest")
public class DockerApiMetadataTest extends BaseComputeServiceApiMetadataTest {
public DockerApiMetadataTest() {
super(new DockerApiMetadata());
}
public void testDockerApiRegistered() {
ApiMetadata api = Apis.withId("docker");
assertNotNull(api);
assertTrue(api instanceof DockerApiMetadata);
assertEquals(api.getId(), "docker");
}
}

View File

@ -0,0 +1,101 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute;
import static com.google.common.base.Charsets.UTF_8;
import static org.jclouds.util.Closeables2.closeQuietly;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Properties;
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;
import org.jclouds.docker.internal.DockerTestUtils;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.CharStreams;
import com.google.inject.Module;
@Test(groups = "live")
public class BaseDockerApiLiveTest extends BaseApiLiveTest<DockerApi> {
protected static final String DEFAULT_IMAGE = "alpine";
protected static final String DEFAULT_TAG = "3.3";
protected static final String ALPINE_IMAGE_TAG = String.format("%s:%s", DEFAULT_IMAGE, DEFAULT_TAG);
public BaseDockerApiLiveTest() {
provider = "docker";
}
/**
* Removes Docker image if it's present on the Docker host.
*
* @param imageName
* image to be deleted (must be not-<code>null</code>)
* @see DockerTestUtils#removeImageIfExists(DockerApi, String)
*/
protected void removeImageIfExists(String imageName) {
DockerTestUtils.removeImageIfExists(api, imageName);
}
@Override
protected Iterable<Module> setupModules() {
return ImmutableSet.<Module>of(getLoggingModule(), new SshjSshClientModule());
}
@Override
protected Properties setupProperties() {
Properties overrides = super.setupProperties();
overrides.setProperty(ComputeServiceProperties.IMAGE_LOGIN_USER, "root:password");
setIfTestSystemPropertyPresent(overrides, provider + ".cacert.path");
setIfTestSystemPropertyPresent(overrides, Constants.PROPERTY_TRUST_ALL_CERTS);
return overrides;
}
protected String consumeStream(InputStream stream) {
try {
return CharStreams.toString(new InputStreamReader(stream, UTF_8));
} catch (IOException e) {
throw new AssertionError(e);
} finally {
closeQuietly(stream);
}
}
public static Payload tarredDockerfile() throws IOException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
ShrinkWrap.create(GenericArchive.class, "archive.tar")
.add(new ClassLoaderAsset("Dockerfile"), "Dockerfile")
.as(TarExporter.class).exportTo(bytes);
return Payloads.newByteArrayPayload(bytes.toByteArray());
}
}

View File

@ -0,0 +1,178 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import java.util.Properties;
import java.util.Random;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.inject.Injector;
import com.google.inject.Module;
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.docker.DockerApi;
import org.jclouds.docker.compute.options.DockerTemplateOptions;
import org.jclouds.docker.compute.strategy.DockerComputeServiceAdapter;
import org.jclouds.docker.domain.Container;
import org.jclouds.docker.domain.Image;
import org.jclouds.docker.domain.Network;
import org.jclouds.docker.features.NetworkApi;
import org.jclouds.sshj.config.SshjSshClientModule;
@Test(groups = "live", singleThreaded = true, testName = "DockerComputeServiceAdapterLiveTest")
public class DockerComputeServiceAdapterLiveTest extends BaseDockerApiLiveTest {
private static final String SSHABLE_IMAGE = "kwart/alpine-ext";
private static final String SSHABLE_IMAGE_TAG = "3.3-ssh";
private Image defaultImage;
private Network network1;
private Network network2;
private DockerComputeServiceAdapter adapter;
private TemplateBuilder templateBuilder;
private NodeAndInitialCredentials<Container> guest;
private static final String CHUANWEN_COWSAY = "chuanwen/cowsay";
@BeforeClass
protected void init() {
super.initialize();
String imageName = SSHABLE_IMAGE + ":" + SSHABLE_IMAGE_TAG;
defaultImage = adapter.getImage(imageName);
network1 = createAndInspectNetwork("network1");
network2 = createAndInspectNetwork("network2");
assertNotNull(defaultImage);
}
@AfterClass(alwaysRun = true)
protected void tearDown() {
if (guest != null) {
adapter.destroyNode(guest.getNode().id() + "");
}
if (api.getImageApi().inspectImage(CHUANWEN_COWSAY) != null) {
api.getImageApi().deleteImage(CHUANWEN_COWSAY);
}
if (api.getNetworkApi().inspectNetwork("network1") != null) {
api.getNetworkApi().removeNetwork("network1");
}
if (api.getNetworkApi().inspectNetwork("network2") != null) {
api.getNetworkApi().removeNetwork("network2");
}
super.tearDown();
}
@Override
protected DockerApi create(Properties props, Iterable<Module> modules) {
Injector injector = newBuilder().modules(modules).overrides(props).buildInjector();
adapter = injector.getInstance(DockerComputeServiceAdapter.class);
templateBuilder = injector.getInstance(TemplateBuilder.class);
return injector.getInstance(DockerApi.class);
}
public void testCreateNodeWithGroupEncodedIntoNameThenStoreCredentials() {
String name = "container" + new Random().nextInt();
Template template = templateBuilder.imageId(defaultImage.id()).build();
DockerTemplateOptions options = template.getOptions().as(DockerTemplateOptions.class);
options.env(ImmutableList.of("ROOT_PASSWORD=password"));
guest = adapter.createNodeWithGroupEncodedIntoName("test", name, template);
assertEquals(guest.getNodeId(), guest.getNode().id());
}
public void testListHardwareProfiles() {
Iterable<Hardware> profiles = adapter.listHardwareProfiles();
assertFalse(Iterables.isEmpty(profiles));
for (Hardware profile : profiles) {
assertNotNull(profile);
}
}
public void testGetImageNotHiddenByCache() {
// Ensure image to be tested is unknown to jclouds and docker and that
// cache is warm
assertNull(findImageFromListImages(CHUANWEN_COWSAY));
assertNull(api.getImageApi().inspectImage(CHUANWEN_COWSAY));
// Get new image
adapter.getImage(CHUANWEN_COWSAY);
assertNotNull(findImageFromListImages(CHUANWEN_COWSAY),
"New image is not available from listImages presumably due to caching");
}
public void testCreateNodeWithMultipleNetworks() {
String name = "container" + new Random().nextInt();
Template template = templateBuilder.imageId(defaultImage.id()).build();
DockerTemplateOptions options = template.getOptions().as(DockerTemplateOptions.class);
options.env(ImmutableList.of("ROOT_PASSWORD=password"));
options.networkMode("bridge");
options.networks(network1.name(), network2.name());
guest = adapter.createNodeWithGroupEncodedIntoName("test", name, template);
assertTrue(guest.getNode().networkSettings().networks().containsKey("network1"));
assertTrue(guest.getNode().networkSettings().networks().containsKey("network2"));
assertEquals(guest.getNode().networkSettings().networks().size(), 3);
}
private Image findImageFromListImages(final String image) {
return Iterables.find(adapter.listImages(), new Predicate<Image>() {
@Override
public boolean apply(Image input) {
for (String tag : input.repoTags()) {
if (tag.equals(CHUANWEN_COWSAY + DockerComputeServiceAdapter.SUFFIX_LATEST_VERSION)
|| tag.equals(DockerComputeServiceAdapter.PREFIX_DOCKER_HUB_HOST + CHUANWEN_COWSAY
+ DockerComputeServiceAdapter.SUFFIX_LATEST_VERSION)) {
return true;
}
}
return false;
}
}, null);
}
@Override
protected Iterable<Module> setupModules() {
return ImmutableSet.<Module> of(getLoggingModule(), new SshjSshClientModule());
}
/**
* Creates network (driver="bridge") with given name and then inspects it to
* fully populate the returned {@link Network} object.
*
* @param networkName
*/
private Network createAndInspectNetwork(final String networkName) {
final NetworkApi networkApi = api.getNetworkApi();
Network network = networkApi.createNetwork(Network.builder().name(networkName).driver("bridge").build());
return networkApi.inspectNetwork(network.id());
}
}

View File

@ -0,0 +1,214 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute;
import static com.google.common.collect.Iterables.getOnlyElement;
import static java.lang.String.format;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.logging.Logger.getAnonymousLogger;
import static org.jclouds.compute.options.RunScriptOptions.Builder.nameTask;
import static org.jclouds.compute.options.TemplateOptions.Builder.runAsRoot;
import static org.jclouds.util.Predicates2.retry;
import static org.testng.Assert.assertNotNull;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.TimeUnit;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.JettyStatements;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest;
import org.jclouds.compute.util.OpenSocketFinder;
import org.jclouds.docker.DockerApi;
import org.jclouds.docker.compute.options.DockerTemplateOptions;
import org.jclouds.docker.domain.Container;
import org.jclouds.docker.features.ImageApi;
import org.jclouds.docker.options.CreateImageOptions;
import org.jclouds.docker.options.DeleteImageOptions;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.predicates.SocketOpen;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.net.HostAndPort;
import com.google.inject.Module;
/**
* Live tests for the {@link org.jclouds.compute.ComputeService} integration.
*/
@Test(groups = "live", singleThreaded = true, testName = "DockerComputeServiceLiveTest")
public class DockerComputeServiceLiveTest extends BaseComputeServiceContextLiveTest {
private static final String SSHABLE_IMAGE = "tutum/ubuntu";
private static final String SSHABLE_IMAGE_TAG = "trusty";
private Image defaultImage;
protected Template template;
protected Predicate<HostAndPort> socketTester;
protected OpenSocketFinder openSocketFinder;
protected ComputeService client;
public DockerComputeServiceLiveTest() {
provider = "docker";
}
@Override
protected Module getSshModule() {
return new SshjSshClientModule();
}
@BeforeGroups(groups = { "integration", "live" })
@Override
public void setupContext() {
super.setupContext();
buildSocketTester();
}
@Override
protected void initializeContext() {
super.initializeContext();
client = view.getComputeService();
String imageName = SSHABLE_IMAGE + ":" + SSHABLE_IMAGE_TAG;
defaultImage = client.getImage(imageName);
assertNotNull(defaultImage);
}
@AfterClass
@Override
protected void tearDownContext() {
super.tearDownContext();
if (defaultImage != null) {
imageApi().deleteImage(SSHABLE_IMAGE + ":" + SSHABLE_IMAGE_TAG, DeleteImageOptions.Builder.force(true));
}
}
private ImageApi imageApi() {
return client.getContext().unwrapApi(DockerApi.class).getImageApi();
}
protected Template buildTemplate(TemplateBuilder templateBuilder) {
String imageName = SSHABLE_IMAGE + ":" + SSHABLE_IMAGE_TAG;
org.jclouds.docker.domain.Image image = imageApi().inspectImage(imageName);
if (image == null) {
CreateImageOptions options = CreateImageOptions.Builder.fromImage(SSHABLE_IMAGE).tag(SSHABLE_IMAGE_TAG);
imageApi().createImage(options);
}
image = imageApi().inspectImage(imageName);
defaultImage = client.getImage(image.id());
DockerTemplateOptions options = new DockerTemplateOptions();
options.env(ImmutableList.of("ROOT_PASS=password"));
options.overrideLoginCredentials(LoginCredentials.builder().identity("root").credential("password").build());
template = templateBuilder.imageId(defaultImage.getId()).options(options).build();
return template;
}
protected void createAndRunAServiceInGroup(String group) throws RunNodesException {
// note that some cloud providers do not support mixed case tag names
ImmutableMap<String, String> userMetadata = ImmutableMap.of("test", group);
ImmutableSet<String> tags = ImmutableSet.of(group);
Stopwatch watch = Stopwatch.createStarted();
template = buildTemplate(client.templateBuilder());
template.getOptions().inboundPorts(22, 8080).blockOnPort(22, 300).userMetadata(userMetadata).tags(tags);
NodeMetadata node = getOnlyElement(client.createNodesInGroup(group, 1, template));
long createSeconds = watch.elapsed(TimeUnit.SECONDS);
final String nodeId = node.getId();
//checkUserMetadataContains(node, userMetadata);
//checkTagsInNodeEquals(node, tags);
getAnonymousLogger().info(
format("<< available node(%s) os(%s) in %ss", node.getId(), node.getOperatingSystem(), createSeconds));
watch.reset().start();
client.runScriptOnNode(nodeId, JettyStatements.install(), nameTask("configure-jetty"));
long configureSeconds = watch.elapsed(TimeUnit.SECONDS);
getAnonymousLogger().info(
format(
"<< configured node(%s) with %s and jetty %s in %ss",
nodeId,
exec(nodeId, "java -fullversion"),
exec(nodeId, JettyStatements.version()), configureSeconds));
trackProcessOnNode(JettyStatements.start(), "start jetty", node);
client.runScriptOnNode(nodeId, JettyStatements.stop(), runAsRoot(false).wrapInInitScript(false));
trackProcessOnNode(JettyStatements.start(), "start jetty", node);
}
protected void trackProcessOnNode(Statement process, String processName, NodeMetadata node) {
ServiceStats stats = new ServiceStats();
Stopwatch watch = Stopwatch.createStarted();
ExecResponse exec = client.runScriptOnNode(node.getId(), process, runAsRoot(false).wrapInInitScript(false));
stats.backgroundProcessMilliseconds = watch.elapsed(TimeUnit.MILLISECONDS);
Container container = client.getContext().unwrapApi(DockerApi.class).getContainerApi().inspectContainer(node.getId());
Map<String, List<Map<String, String>>> ports = container.networkSettings().ports();
int port = Integer.parseInt(getOnlyElement(ports.get("8080/tcp")).get("HostPort"));
watch.reset().start();
HostAndPort socket;
try {
socket = openSocketFinder.findOpenSocketOnNode(node, port, 600, TimeUnit.SECONDS);
} catch (NoSuchElementException e) {
throw new NoSuchElementException(format("%s%n%s%s", e.getMessage(), exec.getOutput(), exec.getError()));
}
stats.socketOpenMilliseconds = watch.elapsed(TimeUnit.MILLISECONDS);
getAnonymousLogger().info(format("<< %s on node(%s)[%s] %s", processName, node.getId(), socket, stats));
}
static class ServiceStats {
long backgroundProcessMilliseconds;
long socketOpenMilliseconds;
@Override
public String toString() {
return format("[backgroundProcessMilliseconds=%s, socketOpenMilliseconds=%s]",
backgroundProcessMilliseconds, socketOpenMilliseconds);
}
}
protected String exec(final String nodeId, String command) {
return exec(nodeId, Statements.exec(command));
}
protected String exec(final String nodeId, Statement command) {
return client.runScriptOnNode(nodeId, command, runAsRoot(false).wrapInInitScript(false)).getOutput().trim();
}
protected void buildSocketTester() {
SocketOpen socketOpen = view.utils().injector().getInstance(SocketOpen.class);
socketTester = retry(socketOpen, 60, 1, SECONDS);
// wait a maximum of 60 seconds for port 8080 to open.
openSocketFinder = context.utils().injector().getInstance(OpenSocketFinder.class);
}
}

View File

@ -0,0 +1,245 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute;
import static org.assertj.core.api.Assertions.assertThat;
import static org.jclouds.compute.options.RunScriptOptions.Builder.wrapInInitScript;
import static org.jclouds.docker.internal.DockerTestUtils.consumeStreamSilently;
import static org.jclouds.docker.internal.DockerTestUtils.removeImageIfExists;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest;
import org.jclouds.docker.DockerApi;
import org.jclouds.docker.compute.functions.LoginPortForContainer;
import org.jclouds.docker.compute.options.DockerTemplateOptions;
import org.jclouds.docker.domain.Config;
import org.jclouds.docker.domain.Container;
import org.jclouds.docker.domain.HostConfig;
import org.jclouds.docker.domain.Image;
import org.jclouds.docker.domain.ImageSummary;
import org.jclouds.docker.options.BuildOptions;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
/**
* This class tests configuring custom SSH port for Docker images.
*/
@Test(groups = "live", testName = "SshToCustomPortLiveTest", singleThreaded = true)
public class SshToCustomPortLiveTest extends BaseComputeServiceContextLiveTest {
private static final int SSH_PORT = 8822;
private static final int SSH_PORT_BRIDGE = 18822;
private static final String IMAGE_REPOSITORY = "jclouds/testrepo";
private static final String IMAGE_TAG_1 = "testtag";
private static final String IMAGE_TAG_2 = "second";
private Image image;
public SshToCustomPortLiveTest() {
provider = "docker";
}
/**
* Asserts that the new image exists and tags were created successfully in
* the test preparation phase ({@link #setupContext()} method).
*/
@Test
public void testImageCreated() {
assertNotNull(image);
final String imageId = image.id();
assertNotNull(imageId);
List<ImageSummary> listImages = api().getImageApi().listImages();
assertNotNull(listImages);
ImageSummary testImage = Iterables.find(listImages, new Predicate<ImageSummary>() {
@Override
public boolean apply(ImageSummary input) {
return imageId.equals(input.id());
}
});
assertEquals(testImage.repoTags().size(), 2, "Unexpected number of tags on the image.");
assertThat(testImage.repoTags()).contains(toTag(IMAGE_REPOSITORY, IMAGE_TAG_1),
toTag(IMAGE_REPOSITORY, IMAGE_TAG_2));
}
/**
* Start a node from the newly created image. The dropbear SSH server running
* on custom port ( {@value #SSH_PORT}). The Docker networkMode used is
* "host". Execute a command through the SSH connection and check the result.
* Destroy the node when finished.
*
* @throws RunNodesException
*/
@Test(dependsOnMethods = "testImageCreated")
public void testCustomPortSsh() throws RunNodesException {
final DockerTemplateOptions options = DockerTemplateOptions.Builder
.env("SSH_PORT=" + SSH_PORT, "ROOT_PASSWORD=screencast")
.overrideLoginUser("root").overrideLoginPassword("screencast")
.blockOnPort(SSH_PORT, 30).networkMode("host");
final Template template = view.getComputeService().templateBuilder().imageId(image.id()).options(options).build();
String nodeId = null;
try {
NodeMetadata node = Iterables
.getOnlyElement(view.getComputeService().createNodesInGroup("ssh-net-host", 1, template));
nodeId = node.getId();
ExecResponse response = view.getComputeService().runScriptOnNode(nodeId, "sh -c 'echo hello && sleep 0.2'", wrapInInitScript(false));
assertThat(response.getOutput().trim()).endsWith("hello");
} finally {
if (nodeId != null)
view.getComputeService().destroyNode(nodeId);
}
}
@Test(dependsOnMethods = "testImageCreated")
public void testAdvancedConfig() throws RunNodesException {
final String portId = SSH_PORT + "/tcp";
final DockerTemplateOptions options = DockerTemplateOptions.Builder
.configBuilder(
Config.builder().env(ImmutableList.<String> of("SSH_PORT=" + SSH_PORT, "ROOT_PASSWORD=jcloudsRulez"))
.exposedPorts(ImmutableMap.<String, Object> of(portId, Maps.newHashMap()))
.hostConfig(HostConfig.builder().networkMode("bridge")
.portBindings(ImmutableMap.<String, List<Map<String, String>>> of(portId,
Lists.<Map<String, String>>newArrayList(ImmutableMap.of("HostPort", String.valueOf(SSH_PORT_BRIDGE)))))
.build())
.image("test-if-this-value-is-correctly-overriden"))
.overrideLoginUser("root").overrideLoginPassword("jcloudsRulez").blockOnPort(SSH_PORT_BRIDGE, 30);
final Template template = view.getComputeService().templateBuilder().imageId(image.id()).options(options).build();
String nodeId = null;
try {
NodeMetadata node = Iterables
.getOnlyElement(view.getComputeService().createNodesInGroup("ssh-net-bridge", 1, template));
nodeId = node.getId();
ExecResponse response = view.getComputeService().runScriptOnNode(nodeId, "sh -c 'true'",
wrapInInitScript(false));
assertEquals(response.getExitStatus(), 0);
} finally {
if (nodeId != null)
view.getComputeService().destroyNode(nodeId);
}
}
/**
* Build a new image with 2 tags on it in the test preparation phase.
*
* @see org.jclouds.apis.BaseContextLiveTest#setupContext()
*/
@Override
@BeforeClass(groups = { "integration", "live" })
public void setupContext() {
super.setupContext();
final String tag = toTag(IMAGE_REPOSITORY, IMAGE_TAG_1);
removeImageIfExists(api(), tag);
removeImageIfExists(api(), toTag(IMAGE_REPOSITORY, IMAGE_TAG_2));
BuildOptions options = BuildOptions.Builder.tag(tag).verbose(false).nocache(false);
InputStream buildImageStream;
try {
buildImageStream = api().getMiscApi().build(BaseDockerApiLiveTest.tarredDockerfile(), options);
consumeStreamSilently(buildImageStream);
} catch (IOException e) {
throw new RuntimeException("Error occured during building Docker image.", e);
}
image = api().getImageApi().inspectImage(tag);
api().getImageApi().tagImage(image.id(), IMAGE_REPOSITORY, IMAGE_TAG_2, true);
}
/**
* After the test remove created image (with all tags).
*
* @see #setupContext()
*/
@AfterClass(alwaysRun = true)
protected void tearDown() {
removeImageIfExists(api(), toTag(IMAGE_REPOSITORY, IMAGE_TAG_1));
removeImageIfExists(api(), toTag(IMAGE_REPOSITORY, IMAGE_TAG_2));
}
/**
* Configure used modules. A custom {@link LoginPortForContainer} binding is
* added among logging and SSH module.
*
* @see org.jclouds.compute.internal.BaseGenericComputeServiceContextLiveTest#setupModules()
*/
@Override
protected Iterable<Module> setupModules() {
return ImmutableSet.<Module> of(getLoggingModule(), new SshjSshClientModule(), new AbstractModule() {
@Override
protected void configure() {
bind(LoginPortForContainer.class).toInstance(new LoginPortForContainer() {
@Override
public Optional<Integer> apply(Container container) {
return Optional.of(container.name().contains("ssh-net-bridge") ? SSH_PORT_BRIDGE : SSH_PORT);
}
});
}
});
}
/**
* Return DockerApi for current Context.
*
* @return
*/
private DockerApi api() {
return view.unwrapApi(DockerApi.class);
}
/**
* Concatenate repository and tag name (if provided) in Docker format.
*
* @param repo
* @param tag
* @return
*/
private static String toTag(String repo, String tag) {
return repo + (tag != null ? ":" + tag : "");
}
}

View File

@ -0,0 +1,224 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute.functions;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.easymock.EasyMock;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageBuilder;
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;
import org.jclouds.docker.domain.NetworkSettings;
import org.jclouds.docker.domain.Port;
import org.jclouds.docker.domain.State;
import org.jclouds.domain.Location;
import org.jclouds.domain.LocationBuilder;
import org.jclouds.domain.LocationScope;
import org.jclouds.providers.ProviderMetadata;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice;
/**
* Unit tests for the {@link org.jclouds.docker.compute.functions.ContainerToNodeMetadata} class.
*/
@Test(groups = "unit", testName = "ContainerToNodeMetadataTest")
public class ContainerToNodeMetadataTest {
private ContainerToNodeMetadata function;
private Container container;
@BeforeMethod
public void setup() {
Config containerConfig = Config.builder()
.hostname("6d35806c1bd2")
.domainname("")
.user("")
.memory(0)
.memorySwap(0)
.cpuShares(0)
.attachStdin(false)
.attachStdout(false)
.attachStderr(false)
.exposedPorts(ImmutableMap.of("22/tcp", ImmutableMap.of()))
.tty(false)
.openStdin(false)
.stdinOnce(false)
.env(null)
.cmd(ImmutableList.of("/usr/sbin/sshd", "-D"))
.image("jclouds/ubuntu")
.workingDir("")
.entrypoint(null)
.networkDisabled(false)
.build();
State state = State.create( //
3626, // pid
true, // running
0, // exitCode
"2014-03-24T20:28:37.537659054Z", // startedAt
"0001-01-01T00:00:00Z", // finishedAt
false, // paused
false, // restarting
"running", // Status
false, // OOMKilled
false, // Dead
"" // Error
);
container = Container.builder()
.id("6d35806c1bd2b25cd92bba2d2c2c5169dc2156f53ab45c2b62d76e2d2fee14a9")
.name("/hopeful_mclean")
.created(new SimpleDateFormatDateService().iso8601DateParse("2014-03-22T07:16:45.784120972Z"))
.path("/usr/sbin/sshd")
.args(Arrays.asList("-D"))
.config(containerConfig)
.state(state)
.image("af0f59f1c19eef9471c3b8c8d587c39b8f130560b54f3766931b37d76d5de4b6")
.networkSettings(NetworkSettings.builder()
.ipAddress("172.17.0.2")
.ipPrefixLen(16)
.gateway("172.17.42.1")
.bridge("docker0")
.ports(ImmutableMap.<String, List<Map<String, String>>>of("22/tcp",
ImmutableList.<Map<String, String>>of(ImmutableMap.of("HostIp", "0.0.0.0", "HostPort",
"49199"))))
.build())
.resolvConfPath("/etc/resolv.conf")
.driver("aufs")
.execDriver("native-0.1")
.volumes(ImmutableMap.<String, String>of())
.volumesRW(ImmutableMap.<String, Boolean>of())
.command("")
.status("")
.hostConfig(HostConfig.builder().publishAllPorts(true).build())
.ports(ImmutableList.<Port>of())
.node(null)
.build();
ProviderMetadata providerMetadata = EasyMock.createMock(ProviderMetadata.class);
expect(providerMetadata.getEndpoint()).andReturn("http://127.0.0.1:4243").atLeastOnce();
replay(providerMetadata);
GroupNamingConvention.Factory namingConvention = Guice.createInjector().getInstance(GroupNamingConvention.Factory.class);
Supplier<Map<String, ? extends Image>> images = new Supplier<Map<String, ? extends Image>>() {
@Override
public Map<String, ? extends Image> get() {
OperatingSystem os = OperatingSystem.builder()
.description("Ubuntu 12.04 64bit")
.family(OsFamily.UBUNTU)
.version("12.04")
.is64Bit(true)
.build();
return ImmutableMap.of("af0f59f1c19eef9471c3b8c8d587c39b8f130560b54f3766931b37d76d5de4b6",
new ImageBuilder()
.ids("af0f59f1c19eef9471c3b8c8d587c39b8f130560b54f3766931b37d76d5de4b6")
.name("ubuntu")
.description("Ubuntu 12.04 64bit")
.operatingSystem(os)
.status(Image.Status.AVAILABLE)
.build());
}
};
Supplier<Set<? extends Location>> locations = new Supplier<Set< ? extends Location>>() {
@Override
public Set<? extends Location> get() {
return ImmutableSet.of(
new LocationBuilder()
.id("docker")
.description("http://localhost:2375")
.scope(LocationScope.PROVIDER)
.build()
);
}
};
function = new ContainerToNodeMetadata(providerMetadata, new StateToStatus(), namingConvention, images, locations,
new LoginPortForContainer.LoginPortLookupChain(null));
}
public void testVirtualMachineToNodeMetadata() {
NodeMetadata node = function.apply(container);
assertEquals(node.getId(), "6d35806c1bd2b25cd92bba2d2c2c5169dc2156f53ab45c2b62d76e2d2fee14a9");
assertEquals(node.getGroup(), "hopeful_mclean");
assertEquals(node.getImageId(), "af0f59f1c19eef9471c3b8c8d587c39b8f130560b54f3766931b37d76d5de4b6");
assertEquals(node.getLoginPort(), 49199);
assertEquals(node.getStatus(), NodeMetadata.Status.RUNNING);
assertEquals(node.getImageId(), "af0f59f1c19eef9471c3b8c8d587c39b8f130560b54f3766931b37d76d5de4b6");
assertEquals(node.getPrivateAddresses(), ImmutableSet.of("172.17.0.2"));
assertEquals(node.getPublicAddresses(), ImmutableSet.of("127.0.0.1"));
}
public void testVirtualMachineWithNetworksToNodeMetadata() {
// Example networks taken from container.json
Container containerWithNetwork = container.toBuilder()
.networkSettings(container.networkSettings().toBuilder()
.networks(ImmutableMap.<String, NetworkSettings.Details>builder()
.put("JCLOUDS_NETWORK", NetworkSettings.Details.builder()
.endpoint("1a10519f808faf1181cfdf3d1d6dd93e19ede2d1c8fed82562a4c17c297c4db3")
.gateway("172.19.0.1")
.ipAddress("172.19.0.2")
.ipPrefixLen(16)
.ipv6Gateway("")
.globalIPv6Address("")
.globalIPv6PrefixLen(0)
.macAddress("02:42:ac:13:00:02")
.build())
.put("bridge", NetworkSettings.Details.builder()
.endpoint("9e8dcc0c8288938a923018fee0728cee8e6de7c01a5150738ee6e51c1caf8cf6")
.gateway("172.17.0.1")
.ipAddress("172.17.0.2")
.ipPrefixLen(16)
.ipv6Gateway("")
.globalIPv6Address("")
.globalIPv6PrefixLen(0)
.macAddress("02:42:ac:11:00:02")
.build())
.build())
.build())
.build();
NodeMetadata node = function.apply(containerWithNetwork);
// Only asserting network-related aspects; the rest is covered by testVirtualMachineToNodeMetadata
assertEquals(node.getLoginPort(), 49199);
assertEquals(node.getPrivateAddresses(), ImmutableSet.of("172.17.0.2", "172.19.0.2"));
assertEquals(node.getPublicAddresses(), ImmutableSet.of("127.0.0.1"));
}
}

View File

@ -0,0 +1,106 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute.functions;
import static org.jclouds.docker.compute.config.LoginPortLookupModule.loginPortLookupBinder;
import static org.testng.Assert.assertEquals;
import org.jclouds.docker.compute.config.LoginPortLookupModule;
import org.jclouds.docker.domain.Config;
import org.jclouds.docker.domain.Container;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.multibindings.MapBinder;
@Test(groups = "unit")
public class CustomLoginPortFromImageTest {
private CustomLoginPortFromImage customLoginPortFromImage;
@BeforeClass
public void setup() {
Injector i = Guice.createInjector(new LoginPortLookupModule(), new AbstractModule() {
@Override
protected void configure() {
MapBinder<String, LoginPortForContainer> imageToFunction = loginPortLookupBinder(binder());
imageToFunction.addBinding(".*alpine-ext.*").toInstance(LoginPortFromEnvVar);
imageToFunction.addBinding(".*ubuntu.*").toInstance(AlwaysPort22);
imageToFunction.addBinding(".*ubuntu:12\\.04.*").toInstance(AlwaysPort8080);
}
});
customLoginPortFromImage = i.getInstance(CustomLoginPortFromImage.class);
}
public void testPortFromEnvironmentVariables() {
Config config = Config.builder().image("alpine-ext:3.2").env(ImmutableList.of("FOO=bar", "SSH_PORT=2345"))
.build();
Container container = Container.builder().id("id").config(config).build();
assertEquals(customLoginPortFromImage.apply(container).get().intValue(), 2345);
}
public void testMostSpecificImageIsPicked() {
Config config = Config.builder().image("ubuntu:12.04").build();
Container container = Container.builder().id("id").config(config).build();
assertEquals(customLoginPortFromImage.apply(container).get().intValue(), 8080);
}
public void testNoImageFoundInMap() {
Config config = Config.builder().image("unexisting").build();
Container container = Container.builder().id("id").config(config).build();
assertEquals(customLoginPortFromImage.apply(container), Optional.absent());
}
private static final LoginPortForContainer LoginPortFromEnvVar = new LoginPortForContainer() {
@Override
public Optional<Integer> apply(Container input) {
Optional<String> portVariable = Iterables.tryFind(input.config().env(), new Predicate<String>() {
@Override
public boolean apply(String input) {
String[] var = input.split("=");
return var[0].equals("SSH_PORT");
}
});
return portVariable.isPresent() ? Optional.of(Integer.valueOf(portVariable.get().split("=")[1])) : Optional
.<Integer> absent();
}
};
private static final LoginPortForContainer AlwaysPort22 = new LoginPortForContainer() {
@Override
public Optional<Integer> apply(Container input) {
return Optional.of(22);
}
};
private static final LoginPortForContainer AlwaysPort8080 = new LoginPortForContainer() {
@Override
public Optional<Integer> apply(Container input) {
return Optional.of(8080);
}
};
}

View File

@ -0,0 +1,148 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute.functions;
import static org.easymock.EasyMock.expect;
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;
import com.google.common.collect.ImmutableList;
/**
* Unit tests for the {@link org.jclouds.docker.compute.functions.ImageToImage} class.
*/
@Test(groups = "unit", testName = "ImageToImageTest")
public class ImageToImageTest {
private static final org.jclouds.docker.domain.Image IMAGE_EMPTY_REPOTAGS = org.jclouds.docker.domain.Image.create(
"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.<String> of() // repoTags
);
private static final org.jclouds.docker.domain.Image IMAGE_REPOTAG_WITH_PORT = org.jclouds.docker.domain.Image.create(
"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("registry.company.example:8888/a/b/c/d:latest") // repoTags
);
private ImageToImage function;
private org.jclouds.docker.domain.Image image;
@BeforeMethod
public void setup() {
image = org.jclouds.docker.domain.Image.create(
"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();
}
public void testImageToImage() {
org.jclouds.docker.domain.Image mockImage = mockImage();
Image image = function.apply(mockImage);
verify(mockImage);
assertEquals(mockImage.id(), image.getId().toString());
}
public void testEmptyRepoTags() {
Image image = function.apply(IMAGE_EMPTY_REPOTAGS);
assertEquals(image.getId(), "id");
assertEquals(image.getDescription(), "<none>");
assertEquals(image.getOperatingSystem().getVersion(), "<none>");
assertEquals(image.getName(), "<none>");
}
public void testRepoTagWithHostPort() {
Image image = function.apply(IMAGE_REPOTAG_WITH_PORT);
assertEquals(image.getDescription(), "registry.company.example:8888/a/b/c/d:latest");
assertEquals(image.getOperatingSystem().getVersion(), "latest");
assertEquals(image.getName(), "registry.company.example:8888/a/b/c/d");
}
private org.jclouds.docker.domain.Image mockImage() {
org.jclouds.docker.domain.Image mockImage = EasyMock.createMock(org.jclouds.docker.domain.Image.class);
expect(mockImage.id()).andReturn(image.id()).anyTimes();
expect(mockImage.repoTags()).andReturn(image.repoTags()).anyTimes();
expect(mockImage.architecture()).andReturn(image.architecture()).anyTimes();
replay(mockImage);
return mockImage;
}
}

View File

@ -0,0 +1,81 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute.functions;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.testng.Assert.assertEquals;
import org.easymock.EasyMock;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.docker.domain.State;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
/**
* Unit tests for the {@link StateToStatus} class.
*/
@Test(groups = "unit", testName = "StateToStatusTest")
public class StateToStatusTest {
private StateToStatus function;
@BeforeMethod
public void setup() {
function = new StateToStatus();
}
public void testStateRunningToStatusRunning() {
State mockState = mockStateRunning();
NodeMetadata.Status status = function.apply(mockState);
verify(mockState);
assertEquals(mockState.running(), true);
assertEquals(status, NodeMetadata.Status.RUNNING);
}
public void testStateNotRunningToStatusTerminated() {
State mockState = mockStateNotRunning();
NodeMetadata.Status status = function.apply(mockState);
verify(mockState);
assertEquals(mockState.running(), false);
assertEquals(status, NodeMetadata.Status.TERMINATED);
}
private State mockStateRunning() {
State mockState = EasyMock.createMock(State.class);
expect(mockState.running()).andReturn(true).anyTimes();
replay(mockState);
return mockState;
}
private State mockStateNotRunning() {
State mockState = EasyMock.createMock(State.class);
expect(mockState.running()).andReturn(false).anyTimes();
replay(mockState);
return mockState;
}
}

View File

@ -0,0 +1,159 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute.options;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.docker.domain.Config;
import org.jclouds.docker.domain.Config.Builder;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
/**
* Unit tests for the {@link DockerTemplateOptions} class.
*/
@Test(groups = "unit", testName = "DockerTemplateOptionsTest")
public class DockerTemplateOptionsTest {
@Test
public void testHostname() {
TemplateOptions options = DockerTemplateOptions.Builder.hostname("hostname");
assertEquals(options.as(DockerTemplateOptions.class).getHostname(), "hostname");
}
@Test
public void testMemory() {
TemplateOptions options = DockerTemplateOptions.Builder.memory(1024);
assertEquals(options.as(DockerTemplateOptions.class).getMemory(), Integer.valueOf(1024));
}
@Test
public void testCpuShares() {
TemplateOptions options = DockerTemplateOptions.Builder.cpuShares(2);
assertEquals(options.as(DockerTemplateOptions.class).getCpuShares(), Integer.valueOf(2));
}
@Test
public void testVolumes() {
TemplateOptions options = DockerTemplateOptions.Builder.volumes(ImmutableMap.of("/tmp", "/tmp"));
assertEquals(options.as(DockerTemplateOptions.class).getVolumes(), ImmutableMap.of("/tmp", "/tmp"));
}
@Test
public void testDns() {
TemplateOptions options = DockerTemplateOptions.Builder.dns("8.8.8.8", "8.8.4.4");
assertEquals(options.as(DockerTemplateOptions.class).getDns(), ImmutableList.of("8.8.8.8", "8.8.4.4"));
}
@Test
public void testEntrypoint() {
TemplateOptions options = DockerTemplateOptions.Builder.entrypoint("/bin/sh", "-c");
assertEquals(options.as(DockerTemplateOptions.class).getEntrypoint(), ImmutableList.of("/bin/sh", "-c"));
}
@Test
public void testCommands() {
TemplateOptions options = DockerTemplateOptions.Builder.commands("chmod 666 /etc/*", "rm -rf /var/run");
assertEquals(options.as(DockerTemplateOptions.class).getCommands(), ImmutableList.of("chmod 666 /etc/*", "rm -rf /var/run"));
}
@Test
public void testEnv() {
TemplateOptions options = DockerTemplateOptions.Builder.env(ImmutableList.of("HOST=abc", "PORT=1234"));
assertEquals(options.as(DockerTemplateOptions.class).getEnv(), ImmutableList.of("HOST=abc", "PORT=1234"));
}
@Test
public void testPortBindings() {
TemplateOptions options = DockerTemplateOptions.Builder.portBindings(ImmutableMap.<Integer, Integer>builder().put(8443, 443).put(8080, 80).build());
assertEquals(options.as(DockerTemplateOptions.class).getPortBindings(), ImmutableMap.<Integer, Integer>builder().put(8443, 443).put(8080, 80).build());
}
@Test
public void testNetworkMode() {
TemplateOptions options = DockerTemplateOptions.Builder.networkMode("host");
assertEquals(options.as(DockerTemplateOptions.class).getNetworkMode(), "host");
}
@Test
public void testPrivilegedDefaultFalse() {
TemplateOptions options = DockerTemplateOptions.Builder.memory(2);
assertEquals(options.as(DockerTemplateOptions.class).getPrivileged(), false);
}
@Test
public void testPrivileged() {
TemplateOptions options = DockerTemplateOptions.Builder.privileged(true);
assertEquals(options.as(DockerTemplateOptions.class).getPrivileged(), true);
}
@Test
public void testConfigBuilder() {
Builder builder = Config.builder().memory(1024)
.cpuShares(100).cmd(ImmutableList.<String> of("/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0"))
.env(ImmutableList.<String> of("JAVA_HOME=/opt/jdk-1.8", "MGMT_USER=admin",
"MGMT_PASSWORD=Schroedinger's Cat"));
TemplateOptions options = DockerTemplateOptions.Builder.configBuilder(builder);
Builder builderInOpts = options.as(DockerTemplateOptions.class).getConfigBuilder();
assertNotNull(builderInOpts);
Config configFromOptions = builderInOpts.build();
assertEquals(configFromOptions, builder.build());
assertEquals(configFromOptions.env(), ImmutableList.<String> of("JAVA_HOME=/opt/jdk-1.8", "MGMT_USER=admin",
"MGMT_PASSWORD=Schroedinger's Cat"));
}
@Test
public void testNonDockerOptions() {
TemplateOptions options = DockerTemplateOptions.Builder.userMetadata(ImmutableMap.of("key", "value")).cpuShares(1);
assertEquals(options.as(DockerTemplateOptions.class).getUserMetadata(), ImmutableMap.of("key", "value"));
assertEquals(options.as(DockerTemplateOptions.class).getCpuShares(), Integer.valueOf(1));
}
@Test
public void testMultipleOptions() {
TemplateOptions options = DockerTemplateOptions.Builder.memory(512).cpuShares(4);
assertEquals(options.as(DockerTemplateOptions.class).getMemory(), Integer.valueOf(512));
assertEquals(options.as(DockerTemplateOptions.class).getCpuShares(), Integer.valueOf(4));
}
@Test
public void testCopyTo() {
DockerTemplateOptions options = DockerTemplateOptions.Builder
.memory(512)
.cpuShares(4)
.entrypoint("entry", "point")
.commands("test", "abc")
.portBindings(
ImmutableMap.<Integer, Integer> builder()
.put(8443, 443).build())
.hostname("hostname")
.networkMode("host")
.userMetadata(ImmutableMap.of("key", "value"))
.env(ImmutableList.of("HOST=abc", "PORT=1234"))
.dns("8.8.8.8", "8.8.4.4")
.volumes(ImmutableMap.of("/tmp", "/tmp"));
DockerTemplateOptions optionsCopy = new DockerTemplateOptions();
options.copyTo(optionsCopy);
assertEquals(optionsCopy, options);
}
}

View File

@ -0,0 +1,111 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.compute.strategy;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import java.util.Date;
import org.jclouds.docker.domain.Config;
import org.jclouds.docker.domain.Image;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
/**
* Unit tests for finding images logic used in
* {@link DockerComputeServiceAdapter#getImage(String)} method. It's mainly a
* regression test for issue
* <a href="https://issues.apache.org/jira/browse/JCLOUDS-1158">JCLOUDS-1158</a>
* .
*/
@Test(groups = "unit", testName = "PredicateLocateImageByNameTest")
public class PredicateLocateImageByNameTest {
private static final Image IMAGE_REPO_TAGS_MULTI = Image.create("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.<String> of("kwart/alpine-ext:3.3-ssh", "kwart/alpine-ext:latest", "my-tag:latestdock") // repoTags
);
private static final Image IMAGE_REPO_TAGS_EMPTY = Image.create("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.<String> of() // repoTags
);
private static final Image IMAGE_REPO_TAGS_WITH_HOST = Image.create("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.<String> of("docker.io/kwart/alpine-ext:3.3-ssh", "docker.io/kwart/alpine-ext:latest") // repoTags
);
public void testRepoTagVersion() {
final Predicate<Image> predicate = DockerComputeServiceAdapter
.createPredicateMatchingRepoTags("kwart/alpine-ext:3.3-ssh");
assertTrue(predicate.apply(IMAGE_REPO_TAGS_MULTI));
assertFalse(predicate.apply(IMAGE_REPO_TAGS_EMPTY));
assertTrue(predicate.apply(IMAGE_REPO_TAGS_WITH_HOST));
}
public void testRepoTagLatest() {
final Predicate<Image> predicate = DockerComputeServiceAdapter.createPredicateMatchingRepoTags("kwart/alpine-ext");
assertTrue(predicate.apply(IMAGE_REPO_TAGS_MULTI));
assertFalse(predicate.apply(IMAGE_REPO_TAGS_EMPTY));
assertTrue(predicate.apply(IMAGE_REPO_TAGS_WITH_HOST));
}
public void testRepoTagVersionWithHost() {
final Predicate<Image> predicate = DockerComputeServiceAdapter
.createPredicateMatchingRepoTags("docker.io/kwart/alpine-ext:3.3-ssh");
assertFalse(predicate.apply(IMAGE_REPO_TAGS_MULTI));
assertFalse(predicate.apply(IMAGE_REPO_TAGS_EMPTY));
assertTrue(predicate.apply(IMAGE_REPO_TAGS_WITH_HOST));
}
public void testRepoTagLatestWithHost() {
final Predicate<Image> predicate = DockerComputeServiceAdapter
.createPredicateMatchingRepoTags("docker.io/kwart/alpine-ext");
assertFalse(predicate.apply(IMAGE_REPO_TAGS_MULTI));
assertFalse(predicate.apply(IMAGE_REPO_TAGS_EMPTY));
assertTrue(predicate.apply(IMAGE_REPO_TAGS_WITH_HOST));
}
}

View File

@ -0,0 +1,126 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.config;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.util.List;
import java.util.Map;
import org.jclouds.docker.domain.Container;
import org.jclouds.docker.domain.NetworkSettings;
import org.jclouds.docker.domain.Port;
import org.jclouds.json.Json;
import org.jclouds.json.config.GsonModule;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Guice;
/**
* Unit tests for the {@link org.jclouds.docker.config.DockerParserModule} class.
*/
@Test(groups = "unit", testName = "DockerParserModuleTest")
public class DockerParserModuleTest {
private Json json = Guice.createInjector(new GsonModule(), new DockerParserModule()).getInstance(Json.class);
public void testContainerWithVolumesNull() {
Container container = json.fromJson("{ \"Id\": \"foo\", \"Volumes\": null }", Container.class);
assertNotNull(container);
assertEquals(container.id(), "foo");
assertEquals(container.volumes(), ImmutableMap.of());
}
public void port() {
// Note IP, not Ip
String text = "{\"IP\":\"0.0.0.0\",\"PrivatePort\":4567,\"PublicPort\":49155,\"Type\":\"tcp\"}";
Port port = Port.create("0.0.0.0", 4567, 49155, "tcp");
assertEquals(json.fromJson(text, Port.class), port);
assertEquals(json.toJson(port), text);
}
public void networkSettings() {
String text = "{" +
"\"Bridge\":\"\"," +
"\"SandboxID\":\"3ef128b055eb9ef62a6a2c281d97a2dfde5f47947d490f1dd2a81612611d961f\"," +
"\"HairpinMode\":false," +
"\"LinkLocalIPv6Address\":\"\"," +
"\"LinkLocalIPv6PrefixLen\":0," +
"\"Ports\":{}," +
"\"SandboxKey\":\"/var/run/docker/netns/3ef128b055eb\"," +
"\"SecondaryIPAddresses\":[]," +
"\"SecondaryIPv6Addresses\":[]," +
"\"EndpointID\":\"9e8dcc0c8288938a923018fee0728cee8e6de7c01a5150738ee6e51c1caf8cf6\"," +
"\"Gateway\":\"172.17.0.1\"," +
"\"GlobalIPv6Address\":\"\"," +
"\"GlobalIPv6PrefixLen\":0," +
"\"IPAddress\":\"172.17.0.2\"," +
"\"IPPrefixLen\":16," +
"\"IPv6Gateway\":\"\"," +
"\"MacAddress\":\"02:42:ac:11:00:02\"," +
"\"Networks\":{" +
"\"bridge\":{" +
"\"EndpointID\":\"9e8dcc0c8288938a923018fee0728cee8e6de7c01a5150738ee6e51c1caf8cf6\"," +
"\"Gateway\":\"172.17.0.1\"," +
"\"IPAddress\":\"172.17.0.2\"," +
"\"IPPrefixLen\":16," +
"\"IPv6Gateway\":\"\"," +
"\"GlobalIPv6Address\":\"\"," +
"\"GlobalIPv6PrefixLen\":0," +
"\"MacAddress\":\"02:42:ac:11:00:02\"" +
"}" +
"}" +
"}";
NetworkSettings settings = NetworkSettings.create(
"", // Bridge
"3ef128b055eb9ef62a6a2c281d97a2dfde5f47947d490f1dd2a81612611d961f", // SandboxID
false, // HairpinMode
"", // LinkLocalIPv6Address
0, // LinkLocalIPv6PrefixLen
ImmutableMap.<String, List<Map<String, String>>> of(), // Ports
"/var/run/docker/netns/3ef128b055eb", // SandboxKey
null, // SecondaryIPAddresses
null, // SecondaryIPv6Addresses
"9e8dcc0c8288938a923018fee0728cee8e6de7c01a5150738ee6e51c1caf8cf6", // EndpointID
"172.17.0.1", // Gateway
"", // GlobalIPv6Address
0, // GlobalIPv6PrefixLen
"172.17.0.2", // IPAddress
16, // IPPrefixLen
"", // IPv6Gateway
"02:42:ac:11:00:02", // MacAddress
ImmutableMap.of(
"bridge", NetworkSettings.Details.create(
"9e8dcc0c8288938a923018fee0728cee8e6de7c01a5150738ee6e51c1caf8cf6", // EndpointID
"172.17.0.1", // Gateway
"172.17.0.2", // IPAddress
16, // IPPrefixLen
"", // IPv6Gateway
"", // GlobalIPv6Address
0, // GlobalIPv6PrefixLen
"02:42:ac:11:00:02" // MacAddress
)
),
null // PortMapping
);
assertEquals(json.fromJson(text, NetworkSettings.class), settings);
assertEquals(json.toJson(settings), text);
}
}

View File

@ -0,0 +1,62 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.domain;
import static org.assertj.core.api.Assertions.assertThat;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@Test(groups = "unit", testName = "ConfigTest")
public class ConfigTest {
@Test
public void testFromConfig() {
Config origConfig = 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();
Config newConfig = Config.builder().fromConfig(origConfig).build();
assertThat(origConfig).isEqualTo(newConfig);
}
@Test
public void testNullValuesPropagation() {
Config config = Config.builder()
.image("zettio/weave")
.build();
assertThat(config.cmd()).isNull();
assertThat(config.entrypoint()).isNull();
assertThat(config.env()).isNull();
assertThat(config.hostname()).isNull();
assertThat(config.domainname()).isNull();
assertThat(config.workingDir()).isNull();
assertThat(config.hostConfig()).isNull();
}
}

View File

@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.domain;
import static org.assertj.core.api.Assertions.assertThat;
import org.testng.annotations.Test;
@Test(groups = "unit", testName = "ContainerTest")
public class ContainerTest {
@Test
public void testFromContainer() {
Container testContainer = Container.builder()
.id("testcontainer")
.build();
Container newTestContainer = testContainer.toBuilder().build();
assertThat(newTestContainer).isEqualTo(testContainer);
}
}

View File

@ -0,0 +1,152 @@
/*
* 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.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;
import java.io.InputStream;
import java.util.List;
import org.jclouds.docker.compute.BaseDockerApiLiveTest;
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;
import com.google.common.collect.ImmutableList;
@Test(groups = "live", testName = "RemoteApiLiveTest", singleThreaded = true)
public class ContainerApiLiveTest extends BaseDockerApiLiveTest {
private Container container = null;
protected Image image = null;
@BeforeClass
protected void init() {
if (api.getImageApi().inspectImage(ALPINE_IMAGE_TAG) == null) {
CreateImageOptions options = CreateImageOptions.Builder.fromImage(ALPINE_IMAGE_TAG);
InputStream createImageStream = api.getImageApi().createImage(options);
consumeStream(createImageStream);
}
image = api.getImageApi().inspectImage(ALPINE_IMAGE_TAG);
assertNotNull(image);
}
@AfterClass
protected void tearDown() {
if (container != null) {
if (api.getContainerApi().inspectContainer(container.id()) != null) {
api.getContainerApi().removeContainer(container.id(), RemoveContainerOptions.Builder.force(true));
}
}
}
public void testCreateContainer() throws IOException, InterruptedException {
Config containerConfig = Config.builder().image(image.id())
.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);
assertNotNull(container.id());
}
@Test(dependsOnMethods = "testCreateContainer")
public void testStartContainer() throws IOException, InterruptedException {
api().startContainer(container.id());
assertTrue(api().inspectContainer(container.id()).state().running());
}
@Test(dependsOnMethods = "testStartContainer")
public void testAttachContainer() throws InterruptedException {
// wait 2 seconds - give a container chance to echo the string
Thread.sleep(2000L);
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(), 137);
}
@Test(dependsOnMethods = "testWaitContainer")
public void testRemoveContainer() {
api().removeContainer(container.id());
assertNull(api().inspectContainer(container.id()));
}
@Test
public void testListContainers() {
List<ContainerSummary> containerSummaries = api().listContainers(ListContainerOptions.Builder.all(true));
for (ContainerSummary containerSummary : containerSummaries) {
assertNotNull(containerSummary.id());
assertNotNull(containerSummary.image());
assertFalse(containerSummary.names().isEmpty());
}
}
private ContainerApi api() {
return api.getContainerApi();
}
}

View File

@ -0,0 +1,236 @@
/*
* 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.features;
import static org.assertj.core.api.Assertions.assertThat;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
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.Resource;
import org.jclouds.docker.internal.BaseDockerMockTest;
import org.jclouds.docker.options.ListContainerOptions;
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.squareup.okhttp.mockwebserver.MockResponse;
import com.squareup.okhttp.mockwebserver.MockWebServer;
/**
* Mock tests for the {@link org.jclouds.docker.features.ContainerApi} class.
*/
@Test(groups = "unit", testName = "ContainerApiMockTest")
public class ContainerApiMockTest extends BaseDockerMockTest {
public void testListContainers() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/containers.json")));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
assertEquals(api.listContainers(), new ContainersParseTest().expected());
assertSent(server, "GET", "/containers/json");
} finally {
server.shutdown();
}
}
public void testListNonexistentContainers() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(404));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
assertEquals(api.listContainers(), ImmutableList.of());
assertSent(server, "GET", "/containers/json");
} finally {
server.shutdown();
}
}
@Test(timeOut = 10000l)
public void testListAllContainers() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/containers.json")));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
assertEquals(api.listContainers(ListContainerOptions.Builder.all(true)), new ContainersParseTest().expected());
assertSent(server, "GET", "/containers/json?all=true");
} finally {
server.shutdown();
}
}
public void testGetContainer() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/container.json")));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString(), new DockerParserModule()).getContainerApi();
String containerId = "e475abdf3e139a5e1e158b38b6cb290a1bec856d39d5a951f015dfb8fcba7331";
try {
assertEquals(api.inspectContainer(containerId), new ContainerParseTest().expected());
assertSent(server, "GET", "/containers/" + containerId + "/json");
} finally {
server.shutdown();
}
}
public void testCreateContainer() throws Exception {
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)
.tty(false)
.image("base")
.build();
try {
Container container = api.createContainer("test", containerConfig);
assertSent(server, "POST", "/containers/create?name=test");
assertNotNull(container);
assertThat(container.id()).isEqualTo("c6c74153ae4b1d1633d68890a68d89c40aa5e284a1ea016cbc6ef0e634ee37b2");
} finally {
server.shutdown();
}
}
public void testRemoveContainer() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(204));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
String containerId = "6d35806c1bd2b25cd92bba2d2c2c5169dc2156f53ab45c2b62d76e2d2fee14a9";
try {
api.removeContainer(containerId);
assertSent(server, "DELETE", "/containers/" + containerId);
} finally {
server.shutdown();
}
}
public void testStartContainer() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(200));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
api.startContainer("1");
assertSent(server, "POST", "/containers/1/start");
} finally {
server.shutdown();
}
}
public void testStopContainer() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(200));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
api.stopContainer("1");
assertSent(server, "POST", "/containers/1/stop");
} finally {
server.shutdown();
}
}
public void testCommitContainer() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(201));
ContainerApi api = api(DockerApi.class, server.getUrl("/").toString()).getContainerApi();
try {
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 {
server.shutdown();
}
}
}

View File

@ -0,0 +1,86 @@
/*
* 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.features;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import java.io.InputStream;
import java.util.List;
import org.jclouds.docker.compute.BaseDockerApiLiveTest;
import org.jclouds.docker.domain.Image;
import org.jclouds.docker.domain.ImageSummary;
import org.jclouds.docker.options.CreateImageOptions;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
@Test(groups = "live", testName = "ImageApiLiveTest", singleThreaded = true)
public class ImageApiLiveTest extends BaseDockerApiLiveTest {
private Image image;
@Test
public void testCreateImage() {
InputStream createImageStream = api().createImage(CreateImageOptions.Builder.fromImage(DEFAULT_IMAGE).tag(DEFAULT_TAG));
consumeStream(createImageStream);
}
@Test(dependsOnMethods = "testCreateImage")
public void testInspectImage() {
image = api.getImageApi().inspectImage(String.format("%s:%s", DEFAULT_IMAGE, DEFAULT_TAG));
assertNotNull(image);
}
@Test(dependsOnMethods = "testInspectImage")
public void testTagImage() {
api.getImageApi().tagImage(image.id(), "jclouds", "testTag", true);
Image taggedImage = api.getImageApi().inspectImage("jclouds:testTag");
assertEquals(taggedImage.id(), image.id(), "Newly added image tag should point to the same image ID.");
}
@Test(dependsOnMethods = "testTagImage")
public void testListImages() {
List<ImageSummary> listImages = api().listImages();
assertNotNull(listImages);
Iterables.find(listImages, new Predicate<ImageSummary>() {
@Override
public boolean apply(ImageSummary input) {
return input.repoTags().contains("jclouds:testTag");
}
});
}
@Test(dependsOnMethods = "testListImages", alwaysRun = true)
public void testDeleteImage() {
consumeStream(api().deleteImage(String.format("%s:%s", DEFAULT_IMAGE, DEFAULT_TAG)));
assertNull(api().inspectImage(String.format("%s:%s", DEFAULT_IMAGE, DEFAULT_TAG)));
assertNotNull(api().inspectImage(image.id()), "Image should should still exist after removing original tag. There is a newly added tag referencing it.");
consumeStream(api().deleteImage("jclouds:testTag"));
assertNull(api().inspectImage("jclouds:testTag"));
}
private ImageApi api() {
return api.getImageApi();
}
}

View File

@ -0,0 +1,145 @@
/*
* 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.features;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.util.List;
import org.jclouds.docker.DockerApi;
import org.jclouds.docker.config.DockerParserModule;
import org.jclouds.docker.domain.ImageHistory;
import org.jclouds.docker.internal.BaseDockerMockTest;
import org.jclouds.docker.options.CreateImageOptions;
import org.jclouds.docker.parse.HistoryParseTest;
import org.jclouds.docker.parse.ImageParseTest;
import org.jclouds.docker.parse.ImagesParseTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.squareup.okhttp.mockwebserver.MockResponse;
import com.squareup.okhttp.mockwebserver.MockWebServer;
/**
* Mock tests for the {@link org.jclouds.docker.features.ImageApi} class.
*/
@Test(groups = "unit", testName = "ImageApiMockTest")
public class ImageApiMockTest extends BaseDockerMockTest {
public void testCreateImage() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(200));
ImageApi api = api(DockerApi.class, server.getUrl("/").toString()).getImageApi();
try {
api.createImage(CreateImageOptions.Builder.fromImage("base"));
assertSent(server, "POST", "/images/create?fromImage=base");
} finally {
server.shutdown();
}
}
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 {
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 {
server.shutdown();
}
}
public void testTagImage() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(201));
ImageApi api = api(DockerApi.class, server.getUrl("/").toString()).getImageApi();
try {
api.tagImage("633fcd11259e8d6bccfbb59a4086b95b0d0fb44edfc3912000ef1f70e8a7bfc6", "jclouds", "testTag", true);
assertSent(server, "POST",
"/images/633fcd11259e8d6bccfbb59a4086b95b0d0fb44edfc3912000ef1f70e8a7bfc6/tag?repo=jclouds&tag=testTag&force=true");
} finally {
server.shutdown();
}
}
public void testDeleteImage() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(204));
ImageApi api = api(DockerApi.class, server.getUrl("/").toString()).getImageApi();
try {
api.deleteImage("1");
assertSent(server, "DELETE", "/images/1");
} finally {
server.shutdown();
}
}
public void testGetHistory() throws Exception {
MockWebServer server = mockWebServer(
new MockResponse().setBody(payloadFromResource("/history.json")),
new MockResponse().setBody(payloadFromResource("/history-apiver22.json")),
new MockResponse().setResponseCode(404));
ImageApi api = api(DockerApi.class, server.getUrl("/").toString()).getImageApi();
try {
assertEquals(api.getHistory("ubuntu"), new HistoryParseTest().expected());
assertSent(server, "GET", "/images/ubuntu/history");
// Docker Engine 1.10 (REST API ver 22) doesn't return parent layer IDs
assertEquals(api.getHistory("fcf9d588ee9ab46c5a888e67f892fac66e6396eb195a743e50c0c5f9a4710e66"),
ImmutableList.of(
ImageHistory.create("sha256:fcf9d588ee9ab46c5a888e67f892fac66e6396eb195a743e50c0c5f9a4710e66",
1456304238,
"",
ImmutableList.of("registry.acme.com:8888/jboss-eap-test/eap-test:1.0-3"),
188605160,
""),
ImageHistory.create("<missing>",
1455838658,
"",
null,
195019519,
""),
ImageHistory.create("<missing>",
1455812978,
"",
null,
203250948,
"Imported from -")
));
assertSent(server, "GET", "/images/fcf9d588ee9ab46c5a888e67f892fac66e6396eb195a743e50c0c5f9a4710e66/history");
// check also if empty list is returned if the image is not found
List<ImageHistory> historyList = api.getHistory("missing-image");
assertNotNull(historyList);
assertTrue(historyList.isEmpty());
} finally {
server.shutdown();
}
}
}

View File

@ -0,0 +1,182 @@
/*
* 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.features;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import org.assertj.core.api.Fail;
import org.jclouds.docker.compute.BaseDockerApiLiveTest;
import org.jclouds.docker.domain.Config;
import org.jclouds.docker.domain.Container;
import org.jclouds.docker.domain.Exec;
import org.jclouds.docker.domain.ExecCreateParams;
import org.jclouds.docker.domain.ExecInspect;
import org.jclouds.docker.domain.ExecStartParams;
import org.jclouds.docker.domain.Image;
import org.jclouds.docker.options.BuildOptions;
import org.jclouds.docker.options.CreateImageOptions;
import org.jclouds.docker.options.RemoveContainerOptions;
import org.jclouds.docker.util.DockerInputStream;
import org.jclouds.docker.util.StdStreamData;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
@Test(groups = "live", testName = "MiscApiLiveTest", singleThreaded = true)
public class MiscApiLiveTest extends BaseDockerApiLiveTest {
private static final String IMAGE_TEST_TAG = "jclouds-test-test-build-image";
private static String imageId;
private Container container = null;
private Image image = null;
private Exec exec = null;
@BeforeClass
protected void init() {
if (api.getImageApi().inspectImage(ALPINE_IMAGE_TAG) == null) {
CreateImageOptions options = CreateImageOptions.Builder.fromImage(ALPINE_IMAGE_TAG);
InputStream createImageStream = api.getImageApi().createImage(options);
consumeStream(createImageStream);
}
image = api.getImageApi().inspectImage(ALPINE_IMAGE_TAG);
assertNotNull(image);
Config containerConfig = Config.builder().image(image.id())
.cmd(ImmutableList.of("/bin/sh", "-c", "touch hello; while true; do echo hello world; sleep 1; done"))
.build();
container = api.getContainerApi().createContainer("miscApiTest", containerConfig);
assertNotNull(container);
api.getContainerApi().startContainer(container.id());
assertTrue(api.getContainerApi().inspectContainer(container.id()).state().running());
}
@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(ALPINE_IMAGE_TAG);
}
}
@Test
public void testVersion() {
assertNotNull(api().getVersion().apiVersion());
assertNotNull(api().getVersion().version());
assertNotNull(api().getVersion().gitCommit());
assertNotNull(api().getVersion().goVersion());
assertNotNull(api().getVersion().kernelVersion());
assertNotNull(api().getVersion().arch());
assertNotNull(api().getVersion().os());
}
@Test
public void testInfo() {
assertNotNull(api().getInfo());
}
@Test
public void testBuildImageFromDockerfile() throws IOException, InterruptedException, URISyntaxException {
removeImageIfExists(IMAGE_TEST_TAG);
BuildOptions options = BuildOptions.Builder.tag(IMAGE_TEST_TAG).verbose(false).nocache(true);
InputStream buildImageStream = api().build(tarredDockerfile(), options);
String buildStream = consumeStream(buildImageStream);
try {
Iterable<String> splitted = Splitter.on("\n").split(buildStream.replace("\r", "").trim());
String lastStreamedLine = Iterables.getLast(splitted).trim();
String rawImageId = Iterables.getLast(Splitter.on("Successfully built ").split(lastStreamedLine));
imageId = rawImageId.substring(0, 11);
assertNotNull(imageId);
} finally {
removeImageIfExists(IMAGE_TEST_TAG);
}
}
@Test
public void testExecCreate() {
exec = api().execCreate(container.id(),
ExecCreateParams.builder()
.cmd(ImmutableList.<String> of("/bin/sh", "-c",
"echo -n Standard >&1 && echo -n Error >&2 && exit 2"))
.attachStderr(true).attachStdout(true).build());
assertNotNull(exec);
assertNotNull(exec.id());
}
@Test(dependsOnMethods = "testExecCreate")
public void testExecStart() throws IOException {
final ExecStartParams startParams = ExecStartParams.builder().detach(false).build();
DockerInputStream inputStream = null;
try {
inputStream = new DockerInputStream(api().execStart(exec.id(), startParams));
assertNotNull(inputStream);
ByteArrayOutputStream baosOut = new ByteArrayOutputStream();
ByteArrayOutputStream baosErr = new ByteArrayOutputStream();
StdStreamData data = null;
while (null != (data = inputStream.readStdStreamData())) {
assertFalse(data.isTruncated());
switch (data.getType()) {
case OUT:
baosOut.write(data.getPayload());
break;
case ERR:
baosErr.write(data.getPayload());
break;
default:
Fail.fail("Unexpected Stream type");
break;
}
}
assertEquals(baosOut.toString(), "Standard");
assertEquals(baosErr.toString(), "Error");
} finally {
if (inputStream != null) {
inputStream.close();
}
}
}
@Test(dependsOnMethods = "testExecStart")
public void testExecInspect() throws IOException {
ExecInspect execInspect = api().execInspect(exec.id());
assertNotNull(execInspect);
assertEquals(execInspect.id(), exec.id());
assertEquals(execInspect.running(), false);
assertEquals(execInspect.exitCode(), 2);
}
private MiscApi api() {
return api.getMiscApi();
}
}

View File

@ -0,0 +1,179 @@
/*
* 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.features;
import static org.assertj.core.api.Assertions.assertThat;
import static org.jclouds.docker.compute.BaseDockerApiLiveTest.tarredDockerfile;
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 java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.docker.DockerApi;
import org.jclouds.docker.config.DockerParserModule;
import org.jclouds.docker.domain.Exec;
import org.jclouds.docker.domain.ExecCreateParams;
import org.jclouds.docker.domain.ExecInspect;
import org.jclouds.docker.domain.ExecStartParams;
import org.jclouds.docker.internal.BaseDockerMockTest;
import org.jclouds.docker.parse.InfoParseTest;
import org.jclouds.docker.parse.VersionParseTest;
import org.jclouds.docker.util.DockerInputStream;
import org.jclouds.docker.util.StdStreamData;
import org.jclouds.docker.util.StdStreamData.StdStreamType;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.squareup.okhttp.mockwebserver.MockResponse;
import com.squareup.okhttp.mockwebserver.MockWebServer;
import com.squareup.okhttp.mockwebserver.RecordedRequest;
/**
* Mock tests for the {@link org.jclouds.docker.features.MiscApi} class.
*/
@Test(groups = "unit", testName = "MiscApiMockTest")
public class MiscApiMockTest extends BaseDockerMockTest {
public void testGetVersion() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/version.json")));
MiscApi api = api(DockerApi.class, server.getUrl("/").toString()).getMiscApi();
try {
assertEquals(api.getVersion(), new VersionParseTest().expected());
assertSent(server, "GET", "/version");
} finally {
server.shutdown();
}
}
public void testGetInfo() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/info.json")));
MiscApi api = api(DockerApi.class, server.getUrl("/").toString()).getMiscApi();
try {
assertEquals(api.getInfo(), new InfoParseTest().expected());
assertSent(server, "GET", "/info");
} finally {
server.shutdown();
}
}
public void testBuildContainer() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(200));
MiscApi api = api(DockerApi.class, server.getUrl("/").toString()).getMiscApi();
try {
api.build(tarredDockerfile());
RecordedRequest request = assertSent(server, "POST", "/build");
assertDockerBuildHttpHeaders(request);
} finally {
server.shutdown();
}
}
public void testBuildContainerUsingPayload() throws Exception {
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);
RecordedRequest request = assertSent(server, "POST", "/build");
assertDockerBuildHttpHeaders(request);
} finally {
server.shutdown();
}
}
public void testExecCreate() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/exec.json")));
MiscApi api = api(DockerApi.class, server.getUrl("/").toString(), new DockerParserModule()).getMiscApi();
try {
final String containerId = "a40d212a0a379de00426a1da2a8fd3fd20d5f74fd7c2dd42f6c93a6b1b0e6974";
final ExecCreateParams execParams = ExecCreateParams.builder()
.cmd(ImmutableList.<String> of("/bin/sh", "-c", "echo -n Standard >&1 && echo -n Error >&2"))
.attachStderr(true).attachStdout(true).build();
final Exec expectedExec = Exec.create("dbf45d296388032ebb9872edb75847f6655a72b4e9ab0d99ae1c75589c4ca957");
assertEquals(api.execCreate(containerId, execParams), expectedExec);
assertSent(server, "POST", "/containers/" + containerId + "/exec");
} finally {
server.shutdown();
}
}
public void testExecStart() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/exec.start")));
MiscApi api = api(DockerApi.class, server.getUrl("/").toString(), new DockerParserModule()).getMiscApi();
DockerInputStream dis = null;
try {
final String execId = "dbf45d296388032ebb9872edb75847f6655a72b4e9ab0d99ae1c75589c4ca957";
final ExecStartParams startParams = ExecStartParams.builder().detach(false).build();
dis = new DockerInputStream(api.execStart(execId, startParams));
final StdStreamData msg1 = dis.readStdStreamData();
assertFalse(msg1.isTruncated());
assertEquals(msg1.getPayload(), "Standard".getBytes(StandardCharsets.UTF_8));
assertEquals(msg1.getType(), StdStreamType.OUT);
final StdStreamData msg2 = dis.readStdStreamData();
assertFalse(msg2.isTruncated());
assertEquals(msg2.getPayload(), "Error".getBytes(StandardCharsets.UTF_8));
assertEquals(msg2.getType(), StdStreamType.ERR);
assertNull(dis.readStdStreamData());
assertSent(server, "POST", "/exec/" + execId + "/start");
} finally {
if (dis != null) {
dis.close();
}
server.shutdown();
}
}
public void testExecInspect() throws IOException, InterruptedException {
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/execInspect.json")));
MiscApi api = api(DockerApi.class, server.getUrl("/").toString(), new DockerParserModule()).getMiscApi();
final String expectedExecId = "fda1cf8064863fc0667c691c69793fdb7d0bd4a1fabb8250536abe5203e4208a";
ExecInspect execInspect = api.execInspect(expectedExecId);
assertNotNull(execInspect);
assertEquals(execInspect.id(), expectedExecId);
assertEquals(execInspect.running(), false);
assertEquals(execInspect.exitCode(), 2);
assertSent(server, "GET", "/exec/" + expectedExecId + "/json");
}
/**
* Asserts that correct values of HTTP headers are used in Docker build REST
* API calls.
*
* @param request
*/
private void assertDockerBuildHttpHeaders(RecordedRequest request) {
assertThat(request.getHeader("Connection")).isEqualTo("close");
assertThat(request.getHeader(HttpHeaders.CONTENT_TYPE)).isEqualTo("application/tar");
}
}

View File

@ -0,0 +1,125 @@
/*
* 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.features;
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;
import java.io.InputStream;
import java.util.List;
import org.jclouds.docker.compute.BaseDockerApiLiveTest;
import org.jclouds.docker.domain.Config;
import org.jclouds.docker.domain.Container;
import org.jclouds.docker.domain.Image;
import org.jclouds.docker.domain.Network;
import org.jclouds.docker.options.CreateImageOptions;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
@Test(groups = "live", testName = "NetworkApiLiveTest", singleThreaded = true)
public class NetworkApiLiveTest extends BaseDockerApiLiveTest {
private static final String NETWORK_NAME = "JCLOUDS_NETWORK";
private Network network = null;
protected Image image = null;
private Container container;
@BeforeClass
protected void init() {
if (api.getImageApi().inspectImage(ALPINE_IMAGE_TAG) == null) {
CreateImageOptions options = CreateImageOptions.Builder.fromImage(ALPINE_IMAGE_TAG);
InputStream createImageStream = api.getImageApi().createImage(options);
consumeStream(createImageStream);
}
image = api.getImageApi().inspectImage(ALPINE_IMAGE_TAG);
assertNotNull(image);
Config containerConfig = Config.builder().image(image.id())
.cmd(ImmutableList.of("sh", "-c", "touch hello; while true; do echo hello world; sleep 1; done"))
.build();
container = api.getContainerApi().createContainer("jclouds-test-network", containerConfig);
api.getContainerApi().startContainer(container.id());
container = api.getContainerApi().inspectContainer(container.id());
}
@AfterClass(alwaysRun = true)
protected void tearDown() {
if (container != null) {
api.getContainerApi().stopContainer(container.id());
api.getContainerApi().removeContainer(container.id());
}
if (network != null) {
api().removeNetwork(network.id());
}
}
public void testCreateNetwork() throws IOException, InterruptedException {
network = api().createNetwork(Network.create(NETWORK_NAME, null, null, null, null, ImmutableMap.<String, Network.Details> of(), ImmutableMap.<String, String> of()));
assertNotNull(network);
assertNotNull(network.id());
}
@Test(dependsOnMethods = "testCreateNetwork")
public void testGetNetwork() {
network = api().inspectNetwork(network.id());
assertNotNull(network);
}
@Test(dependsOnMethods = "testGetNetwork")
public void testAttachContainerToNetwork() {
api().connectContainerToNetwork(network.id(), container.id());
container = api.getContainerApi().inspectContainer(container.id());
assertTrue(Iterables.any(container.networkSettings().networks().keySet(), Predicates.equalTo(network.name())));
}
@Test(dependsOnMethods = "testAttachContainerToNetwork")
public void testDisconnectContainerFromNetwork() {
api().disconnectContainerFromNetwork(network.id(), container.id());
container = api.getContainerApi().inspectContainer(container.id());
assertFalse(Iterables.any(container.networkSettings().networks().keySet(), Predicates.equalTo(network.name())));
}
@Test(dependsOnMethods = "testCreateNetwork")
public void testListNetworks() {
List<Network> networks = api().listNetworks();
for (Network network : networks) {
assertNotNull(network.id());
}
}
@Test(dependsOnMethods = "testDisconnectContainerFromNetwork")
public void testRemoveNetwork() {
api().removeNetwork(network.id());
assertNull(api().inspectNetwork(network.id()));
network = null;
}
private NetworkApi api() {
return api.getNetworkApi();
}
}

View File

@ -0,0 +1,153 @@
/*
* 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.features;
import static org.assertj.core.api.Assertions.assertThat;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.util.Map;
import org.jclouds.docker.DockerApi;
import org.jclouds.docker.config.DockerParserModule;
import org.jclouds.docker.domain.Network;
import org.jclouds.docker.internal.BaseDockerMockTest;
import org.jclouds.docker.parse.NetworkParseTest;
import org.jclouds.docker.parse.NetworksParseTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.squareup.okhttp.mockwebserver.MockResponse;
import com.squareup.okhttp.mockwebserver.MockWebServer;
/**
* Mock tests for the {@link NetworkApi} class.
*/
@Test(groups = "unit", testName = "NetworkApiMockTest")
public class NetworkApiMockTest extends BaseDockerMockTest {
public void testListNetworks() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/networks.json")));
NetworkApi api = api(DockerApi.class, server.getUrl("/").toString()).getNetworkApi();
try {
assertEquals(api.listNetworks(), new NetworksParseTest().expected());
assertSent(server, "GET", "/networks");
} finally {
server.shutdown();
}
}
public void testListNonexistentNetworks() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(404));
NetworkApi api = api(DockerApi.class, server.getUrl("/").toString()).getNetworkApi();
try {
assertEquals(api.listNetworks(), ImmutableList.of());
assertSent(server, "GET", "/networks");
} finally {
server.shutdown();
}
}
public void testGetNetwork() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/network.json")));
NetworkApi api = api(DockerApi.class, server.getUrl("/").toString(), new DockerParserModule()).getNetworkApi();
String networkId = "b03d4cd15b76f8876110615cdeed15eadf77c9beb408d62f1687dcc69192cd6d";
try {
assertEquals(api.inspectNetwork(networkId), new NetworkParseTest().expected());
assertSent(server, "GET", "/networks/" + networkId);
} finally {
server.shutdown();
}
}
public void testCreateNetwork() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setBody(payloadFromResource("/network-creation.json")));
NetworkApi api = api(DockerApi.class, server.getUrl("/").toString()).getNetworkApi();
Map<String, String> options = ImmutableMap.<String, String> builder()
.put("com.docker.network.bridge.default_bridge", "true")
.put("com.docker.network.bridge.enable_icc", "true")
.put("com.docker.network.bridge.enable_ip_masquerade", "true")
.put("com.docker.network.bridge.host_binding_ipv4", "0.0.0.0")
.put("com.docker.network.bridge.name", "docker0")
.put("com.docker.network.driver.mtu", "1500")
.build();
Network network = Network.create(
"isolated_nw", // Name
null, // Id
"bridge", // Driver
null, // Scope
Network.IPAM.create(
"default", // driver
ImmutableList.of(Network.IPAM.Config.create("172.17.0.0/16", null, null)) // config
),
ImmutableMap.of("39b69226f9d79f5634485fb236a23b2fe4e96a0a94128390a7fbbcc167065867",
Network.Details.create(
"ed2419a97c1d9954d05b46e462e7002ea552f216e9b136b80a7db8d98b442eda", //endpointId
"02:42:ac:11:00:02", // MAC
"172.17.0.2/16", // ipv4address
"" // ipv6address
)
),
options);
try {
Network created = api.createNetwork(network);
assertNotNull(created);
assertThat(created.id()).isEqualTo("22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30");
assertSent(server, "POST", "/networks/create", "{\"Name\":\"isolated_nw\",\"Scope\":\"bridge\",\"IPAM\":{\"Driver\":\"default\",\"Config\":[{\"Subnet\":\"172.17.0.0/16\"}]},\"Containers\":{\"39b69226f9d79f5634485fb236a23b2fe4e96a0a94128390a7fbbcc167065867\":{\"EndpointID\":\"ed2419a97c1d9954d05b46e462e7002ea552f216e9b136b80a7db8d98b442eda\",\"MacAddress\":\"02:42:ac:11:00:02\",\"IPv4Address\":\"172.17.0.2/16\",\"IPv6Address\":\"\"}},\"Options\":{\"com.docker.network.bridge.default_bridge\":\"true\",\"com.docker.network.bridge.enable_icc\":\"true\",\"com.docker.network.bridge.enable_ip_masquerade\":\"true\",\"com.docker.network.bridge.host_binding_ipv4\":\"0.0.0.0\",\"com.docker.network.bridge.name\":\"docker0\",\"com.docker.network.driver.mtu\":\"1500\"}}");
} finally {
server.shutdown();
}
}
public void testRemoveNetwork() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(204));
NetworkApi api = api(DockerApi.class, server.getUrl("/").toString()).getNetworkApi();
String networkId = "6d35806c1bd2b25cd92bba2d2c2c5169dc2156f53ab45c2b62d76e2d2fee14a9";
try {
api.removeNetwork(networkId);
assertSent(server, "DELETE", "/networks/" + networkId);
} finally {
server.shutdown();
}
}
public void testConnectContainerToNetwork() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(200));
NetworkApi api = api(DockerApi.class, server.getUrl("/").toString()).getNetworkApi();
try {
api.connectContainerToNetwork("123456789", "containerName");
assertSent(server, "POST", "/networks/123456789/connect", "{ \"Container\": \"containerName\" }");
} finally {
server.shutdown();
}
}
public void testDisconnectContainerFromNetwork() throws Exception {
MockWebServer server = mockWebServer(new MockResponse().setResponseCode(200));
NetworkApi api = api(DockerApi.class, server.getUrl("/").toString()).getNetworkApi();
try {
api.disconnectContainerFromNetwork("123456789", "containerName");
assertSent(server, "POST", "/networks/123456789/disconnect", "{ \"Container\": \"containerName\" }");
} finally {
server.shutdown();
}
}
}

View File

@ -0,0 +1,84 @@
/*
* 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 static com.google.common.base.Charsets.UTF_8;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
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.util.Properties;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
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.gson.JsonParser;
import com.google.inject.Module;
import com.squareup.okhttp.mockwebserver.MockWebServer;
import com.squareup.okhttp.mockwebserver.RecordedRequest;
/**
* Base class for all Docker mock tests.
*/
public class BaseDockerMockTest extends BaseMockWebServerTest {
protected static final String API_VERSION = "1.15";
@Override
protected void addOverrideProperties(Properties properties) {
properties.setProperty("jclouds.api-version", API_VERSION);
}
@Override
protected Module createConnectionModule() {
return new OkHttpCommandExecutorServiceModule();
}
public byte[] payloadFromResource(String resource) {
try {
return toStringAndClose(getClass().getResourceAsStream(resource)).getBytes(Charsets.UTF_8);
} catch (IOException e) {
throw Throwables.propagate(e);
}
}
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;
}
protected RecordedRequest assertSent(MockWebServer server, String method, String path, String json)
throws InterruptedException {
RecordedRequest request = assertSent(server, method, path);
assertEquals(request.getHeader("Content-Type"), APPLICATION_JSON);
assertEquals(parser.parse(new String(request.getBody(), UTF_8)), parser.parse(json));
return request;
}
/** So that we can ignore formatting. */
private final JsonParser parser = new JsonParser();
}

View File

@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.internal;
import org.jclouds.docker.config.DockerParserModule;
import org.jclouds.json.BaseItemParserTest;
import org.jclouds.json.config.GsonModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
public abstract class BaseDockerParseTest<T> extends BaseItemParserTest<T> {
@Override
protected Injector injector() {
return Guice.createInjector(new GsonModule(), new DockerParserModule());
}
}

View File

@ -0,0 +1,79 @@
/*
* 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 java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.logging.Level;
import org.jclouds.docker.DockerApi;
import org.jclouds.docker.features.ImageApi;
import org.jclouds.docker.options.DeleteImageOptions;
import com.google.common.base.Preconditions;
/**
* Utility methods shared by Docker tests.
*/
public class DockerTestUtils {
/**
* Read all data from given {@link InputStream} and throw away all the bits.
* If an {@link IOException} occurs, it's not propagated to user. The given InputStream is closed after the read.
*
* @param is InputStream instance (may be null)
*/
public static void consumeStreamSilently(InputStream is) {
if (is == null) {
return;
}
char[] tmpBuff = new char[8 * 1024];
// throw everything away
InputStreamReader isr = new InputStreamReader(is);
try {
try {
while (isr.read(tmpBuff) > -1) {
// empty
}
} finally {
isr.close();
}
} catch (IOException e) {
java.util.logging.Logger.getAnonymousLogger().log(Level.WARNING, "Error ocured during reading InputStream.", e);
}
}
/**
* Removes Docker image if it's present on the Docker host. Docker Image API
* is used to inspect and remove image (({@link ImageApi#deleteImage(String)}
* method).
*
* @param dockerApi
* DockerApi instance (must be not-<code>null</code>)
* @param imageName
* image to be deleted (must be not-<code>null</code>)
*/
public static void removeImageIfExists(DockerApi dockerApi, String imageName) {
Preconditions.checkNotNull(dockerApi, "DockerApi instance has to be provided");
Preconditions.checkNotNull(imageName, "Docker image name has to be provided");
final ImageApi imageApi = dockerApi.getImageApi();
if (null != imageApi.inspectImage(imageName)) {
consumeStreamSilently(imageApi.deleteImage(imageName, DeleteImageOptions.Builder.force(true)));
}
}
}

View File

@ -0,0 +1,132 @@
/*
* 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.Node;
import org.jclouds.docker.domain.State;
import org.jclouds.docker.internal.BaseDockerParseTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@Test(groups = "unit")
public class ContainerParseTest extends BaseDockerParseTest<Container> {
@Override
public String resource() {
return "/container.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Container expected() {
return Container.builder()
.id("6c9932f478bd761f32ddb54ed28ab42ab6fac6f2a279f561ea31503ee9d39524")
.created(new SimpleDateFormatDateService().iso8601DateParse("2014-10-31T17:00:21.544197943Z"))
.path("/home/weave/weaver")
.name("/weave")
.args(ImmutableList.of("-iface", "ethwe", "-wait", "5", "-name", "7a:63:a2:39:7b:0f"))
.config(Config.builder()
.hostname("6c9932f478bd")
.env(ImmutableList.of("PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"))
.image("zettio/weave")
.domainname("")
.user("")
.cmd(ImmutableList.of("-name", "7a:63:a2:39:7b:0f"))
.entrypoint(ImmutableList.of("/home/weave/weaver", "-iface", "ethwe", "-wait", "5"))
.workingDir("/home/weave")
.exposedPorts(ImmutableMap.of("6783/tcp", ImmutableMap.of(), "6783/udp", ImmutableMap.of()))
.build())
.state(State.create(10357, true, 0, "2015-11-10T09:33:21.68146124Z", "0001-01-01T00:00:00Z", false, false, "running", false, false, ""))
.image("57e570db16baba1e8c0d6f3c15868ddb400f64ff76ec948e65c3ca3f15fb3587")
.networkSettings(NetworkSettings.builder()
.sandboxId("3ef128b055eb9ef62a6a2c281d97a2dfde5f47947d490f1dd2a81612611d961f")
.hairpinMode(false)
.linkLocalIPv6Address("")
.linkLocalIPv6PrefixLen(0)
.globalIPv6Address("")
.globalIPv6PrefixLen(0)
.ipv6Gateway("")
.sandboxKey("/var/run/docker/netns/3ef128b055eb")
.endpointId("9e8dcc0c8288938a923018fee0728cee8e6de7c01a5150738ee6e51c1caf8cf6")
.ipAddress("172.17.0.2")
.ipPrefixLen(16)
.gateway("172.17.0.1")
.bridge("")
.ports(ImmutableMap.<String, List<Map<String, String>>>of())
.macAddress("02:42:ac:11:00:02")
.networks(ImmutableMap.of(
"JCLOUDS_NETWORK", NetworkSettings.Details.create(
"04268fbb4dc368b5a53bb1c3f89294a4f0c72095deb944db3c4efc6d6a439304",
"172.19.0.1",
"172.19.0.2",
16,
"",
"",
0,
"02:42:ac:13:00:02"
),
"bridge", NetworkSettings.Details.create(
"9e8dcc0c8288938a923018fee0728cee8e6de7c01a5150738ee6e51c1caf8cf6",
"172.17.0.1",
"172.17.0.2",
16,
"",
"",
0,
"02:42:ac:11:00:02"
)
))
.build())
.resolvConfPath("/var/lib/docker/containers/6c9932f478bd761f32ddb54ed28ab42ab6fac6f2a279f561ea31503ee9d39524/resolv.conf")
.hostConfig(HostConfig.builder()
.containerIDFile("")
.portBindings(ImmutableMap.<String, List<Map<String, String>>>of(
"6783/tcp", ImmutableList.<Map<String, String>>of(ImmutableMap.of("HostIp", "", "HostPort", "6783")),
"6783/udp", ImmutableList.<Map<String, String>>of(ImmutableMap.of("HostIp", "", "HostPort", "6783")))
)
.capAdd(ImmutableList.of("NET_ADMIN"))
.capDrop(ImmutableList.of("MKNOD"))
.dns(ImmutableList.of("8.8.8.8", "8.8.4.4"))
.extraHosts(ImmutableList.<String>of("extra:169.254.0.1"))
.privileged(true)
.networkMode("bridge")
.restartPolicy(ImmutableMap.<String, String> of("MaximumRetryCount", "0", "Name", ""))
.build())
.driver("aufs")
.execDriver("native-0.2")
.hostnamePath("/var/lib/docker/containers/6c9932f478bd761f32ddb54ed28ab42ab6fac6f2a279f561ea31503ee9d39524/hostname")
.hostsPath("/var/lib/docker/containers/6c9932f478bd761f32ddb54ed28ab42ab6fac6f2a279f561ea31503ee9d39524/hosts")
.mountLabel("")
.processLabel("")
.node(Node.builder().
ip("10.10.10.10").build())
.build();
}
}

View File

@ -0,0 +1,264 @@
/*
* 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;
/**
* This class tests Containers and Config parsing for Docker API in version 1.21. The input JSON comes from examples in
* <a href="https://docs.docker.com/engine/reference/api/docker_remote_api_v1.21/">Docker Remote API documentation 1.21</a>.
* <p>
* Two modifications were made in the "/container-1.21-create.json" due to incompatible types
* <ul>
* <li>the Entrypoint field value was changed from String to List<li>
* <li>the LxcConf field value was changed from Map to List</li>
* <ul>
*/
public class ContainerVersionMajor1Minor21 {
@Test(groups = "unit")
public static class CreateTest extends BaseDockerParseTest<Config> {
@Override
public String resource() {
return "/container-1.21-create.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Config expected() {
return Config.builder()
.hostname("")
.domainname("")
.user("")
.attachStdin(false)
.attachStdout(true)
.attachStderr(true)
.tty(false)
.openStdin(false)
.stdinOnce(false)
.env(ImmutableList.of("FOO=bar", "BAZ=quux"))
.cmd(ImmutableList.of("date"))
//original value of the "Entrypoint" in JSON doesn't contain List but String!
//Both types are allowed by docker Remote API, but we are not able to parse both.
.entrypoint(ImmutableList.of(""))
.image("ubuntu")
// "Labels": {
// "com.example.vendor": "Acme",
// "com.example.license": "GPL",
// "com.example.version": "1.0"
// },
.volumes(ImmutableMap.of("/volumes/data", ImmutableMap.of()))
.workingDir("")
.networkDisabled(false)
// "MacAddress": "12:34:56:78:9a:bc",
.exposedPorts(ImmutableMap.of("22/tcp", ImmutableMap.of()))
// "StopSignal": "SIGTERM",
.hostConfig(HostConfig.builder()
.binds(ImmutableList.of("/tmp:/tmp"))
.links(ImmutableList.of("redis3:redis"))
//The LxcConf causes the type mismatch too (Map vs List<Map>)
.lxcConf(ImmutableList.<Map<String, String>> of(
ImmutableMap.<String, String> of("lxc.utsname", "docker")))
// "Memory": 0,
// "MemorySwap": 0,
// "MemoryReservation": 0,
// "KernelMemory": 0,
// "CpuShares": 512,
// "CpuPeriod": 100000,
// "CpuQuota": 50000,
// "CpusetCpus": "0,1",
// "CpusetMems": "0,1",
// "BlkioWeight": 300,
// "MemorySwappiness": 60,
// "OomKillDisable": false,
.portBindings(ImmutableMap.<String, List<Map<String, String>>> of(
"22/tcp", ImmutableList.<Map<String, String>> of(ImmutableMap.of("HostPort", "11022"))))
.publishAllPorts(false)
.privileged(false)
// "ReadonlyRootfs": false,
.dns(ImmutableList.of("8.8.8.8"))
// "DnsOptions": [""],
.dnsSearch(ImmutableList.of(""))
.extraHosts(null)
.volumesFrom(ImmutableList.of("parent", "other:ro"))
.capAdd(ImmutableList.of("NET_ADMIN"))
.capDrop(ImmutableList.of("MKNOD"))
// "GroupAdd": ["newgroup"],
.restartPolicy(ImmutableMap.of("Name", "", "MaximumRetryCount", "0"))
.networkMode("bridge")
// "Devices": [],
// "Ulimits": [{}],
// "LogConfig": { "Type": "json-file", "Config": {} },
.securityOpt(ImmutableList.<String>of())
// "CgroupParent": "",
// "VolumeDriver": ""
.build()
)
.build();
}
}
@Test(groups = "unit")
public static class InspectTest extends BaseDockerParseTest<Container> {
@Override
public String resource() {
return "/container-1.21-inspect.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Container expected() {
return Container.builder()
// "AppArmorProfile": "",
.args(ImmutableList.<String>of("-c", "exit 9"))
.config(Config.builder()
.attachStderr(true)
.attachStdin(false)
.attachStdout(true)
.cmd(ImmutableList.<String> of("/bin/sh", "-c", "exit 9"))
.domainname("")
.entrypoint(null)
.env(ImmutableList.<String> of("PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"))
.exposedPorts(null)
.hostname("ba033ac44011")
.image("ubuntu")
// "Labels": {
// "com.example.vendor": "Acme",
// "com.example.license": "GPL",
// "com.example.version": "1.0"
// },
// "MacAddress": "",
.networkDisabled(false)
// "OnBuild": null,
.openStdin(false)
.stdinOnce(false)
.tty(false)
.user("")
.volumes(null)
.workingDir("")
// "StopSignal": "SIGTERM"
.build())
.created(new SimpleDateFormatDateService().iso8601DateParse("2015-01-06T15:47:31.485331387Z"))
.driver("devicemapper")
.execDriver("native-0.2")
// "ExecIDs": null,
.hostConfig(HostConfig.builder()
.binds(null)
// "BlkioWeight": 0,
.capAdd(null)
.capDrop(null)
.containerIDFile("")
// "CpusetCpus": "",
// "CpusetMems": "",
// "CpuShares": 0,
// "CpuPeriod": 100000,
// "Devices": [],
.dns(null)
// "DnsOptions": null,
.dnsSearch(null)
.extraHosts(null)
// "IpcMode": "",
.links(null)
.lxcConf(ImmutableList.<Map<String, String>> of())
// "Memory": 0,
// "MemorySwap": 0,
// "MemoryReservation": 0,
// "KernelMemory": 0,
// "OomKillDisable": false,
.networkMode("bridge")
.portBindings(ImmutableMap.<String, List<Map<String, String>>> of())
.privileged(false)
// "ReadonlyRootfs": false,
.publishAllPorts(false)
.restartPolicy(ImmutableMap.<String, String> of("MaximumRetryCount", "2", "Name", "on-failure"))
// "LogConfig": {
// "Config": null,
// "Type": "json-file"
// },
.securityOpt(null)
.volumesFrom(null)
// "Ulimits": [{}],
// "VolumeDriver": ""
.build())
.hostnamePath("/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/hostname")
.hostsPath("/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/hosts")
// "LogPath": "/var/lib/docker/containers/1eb5fabf5a03807136561b3c00adcd2992b535d624d5e18b6cdc6a6844d9767b/1eb5fabf5a03807136561b3c00adcd2992b535d624d5e18b6cdc6a6844d9767b-json.log",
.id("ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39")
.image("04c5d3b7b0656168630d3ba35d8889bd0e9caafcaeb3004d2bfbc47e7c5d35d2")
.mountLabel("")
.name("/boring_euclid")
.networkSettings(NetworkSettings.builder()
.bridge("")
.sandboxId("")
.hairpinMode(false)
.linkLocalIPv6Address("")
.linkLocalIPv6PrefixLen(0)
.ports(null)
.sandboxKey("")
.secondaryIPAddresses(null)
.secondaryIPv6Addresses(null)
.endpointId("")
.gateway("")
.globalIPv6Address("")
.globalIPv6PrefixLen(0)
.ipAddress("")
.ipPrefixLen(0)
.ipv6Gateway("")
.macAddress("")
.networks(ImmutableMap.<String, NetworkSettings.Details> of(
"bridge", NetworkSettings.Details.create("", "", "", 0, "", "", 0, "")))
.build())
.path("/bin/sh")
.node(null)
.processLabel("")
.resolvConfPath("/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/resolv.conf")
// "RestartCount": 1,
.state(State.create(0, true, 9, "2015-01-06T15:47:32.072697474Z", "2015-01-06T15:47:32.080254511Z", false, false, "running", false,
// We don't have the "Dead" field in this API version!
false,
""
// "Paused": false,
// "Running": true,
))
// "Mounts": [
// {
// "Source": "/data",
// "Destination": "/data",
// "Mode": "ro,Z",
// "RW": false
// }
.build();
}
}
}

View File

@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.parse;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.docker.domain.ContainerSummary;
import org.jclouds.docker.domain.Port;
import org.jclouds.docker.internal.BaseDockerParseTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
@Test(groups = "unit")
public class ContainersParseTest extends BaseDockerParseTest<List<ContainerSummary>> {
@Override
public String resource() {
return "/containers.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public List<ContainerSummary> expected() {
return ImmutableList.of(ContainerSummary.create(
"6d35806c1bd2b25cd92bba2d2c2c5169dc2156f53ab45c2b62d76e2d2fee14a9", ImmutableList.of("/hopeful_mclean"),
"1395472605", "jclouds/ubuntu:latest", "/usr/sbin/sshd -D",
ImmutableList.of(Port.create("0.0.0.0", 22, 49231, "tcp")), "Up 55 seconds"), ContainerSummary.create(
"6d35806c1bd2b25cd92bba2d2c2c5169dc2156f53ab45c2b62d76e2d2fee14a2", ImmutableList.of("/hopeful_mclean"),
"1395472605", "jclouds/ubuntu:latest", "/usr/sbin/sshd -D",
ImmutableList.of(Port.create(null, 22, null, "tcp")), "Up 55 seconds"));
}
}

View File

@ -0,0 +1,63 @@
/*
* 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.ImageHistory;
import org.jclouds.docker.internal.BaseDockerParseTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
@Test(groups = "unit")
public class HistoryParseTest extends BaseDockerParseTest<List<ImageHistory>> {
@Override
public String resource() {
return "/history.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public List<ImageHistory> expected() {
return ImmutableList.of(
ImageHistory.create("3db9c44f45209632d6050b35958829c3a2aa256d81b9a7be45b362ff85c54710",
1398108230,
"/bin/sh -c #(nop) ADD file:eb15dbd63394e063b805a3c32ca7bf0266ef64676d5a6fab4801f2e81e2a5148 in /",
ImmutableList.of("ubuntu:lucid", "ubuntu:10.04"),
182964289,
""),
ImageHistory.create("6cfa4d1f33fb861d4d114f43b25abd0ac737509268065cdfd69d544a59c85ab8",
1398108222,
"/bin/sh -c #(nop) MAINTAINER Tianon Gravi <admwiggin@gmail.com> - mkimage-debootstrap.sh -i iproute,iputils-ping,ubuntu-minimal -t lucid.tar.xz lucid http://archive.ubuntu.com/ubuntu/",
null,
0,
""),
ImageHistory.create("511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158",
1371157430,
"",
ImmutableList.of("scratch12:latest", "scratch:latest"),
0,
"Imported from -")
);
}
}

View File

@ -0,0 +1,83 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.parse;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.docker.domain.Config;
import org.jclouds.docker.domain.Image;
import org.jclouds.docker.internal.BaseDockerParseTest;
import org.testng.annotations.Test;
import com.beust.jcommander.internal.Maps;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@Test(groups = "unit")
public class ImageParseTest extends BaseDockerParseTest<Image> {
@Override
public String resource() {
return "/image.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Image expected() {
return Image.create("cbba6639a342646deed70d7ea6162fa2a0acea9300f911f4e014555fe37d3456",
"author",
"comment",
Config.builder().cmd(ImmutableList.of("/bin/sh", "-c", "echo hello world"))
.env(ImmutableList.of(
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"HOME=/root",
"JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64"
)
)
.exposedPorts(ImmutableMap.of("8081/tcp", Maps.newHashMap()))
.hostname("f22711318734")
.domainname("")
.user("user")
.image("05794515afd5724df1cdf0e674ae932455fce7dea3c70a94d77119ad1fa954ba")
.workingDir("/home/user")
.build(),
Config.builder().cmd(ImmutableList.of("/bin/sh", "-c", "echo hello world"))
.env(ImmutableList.of(
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"HOME=/root",
"JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64")
)
.exposedPorts(ImmutableMap.of("8081/tcp", Maps.newHashMap()))
.hostname("f22711318734")
.domainname("")
.user("user")
.image("05794515afd5724df1cdf0e674ae932455fce7dea3c70a94d77119ad1fa954ba")
.workingDir("/home/user")
.build(),
"05794515afd5724df1cdf0e674ae932455fce7dea3c70a94d77119ad1fa954ba",
new SimpleDateFormatDateService().iso8601DateParse("2014-11-24T11:09:20.310023104Z"),
"0d14967353dbbd2ee78abe209f026f71654da49692fa2b044296ec3c810027b3",
"1.3.1",
"amd64",
"linux",
0,
808709069,
null);
}
}

View File

@ -0,0 +1,69 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.parse;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.docker.domain.ImageSummary;
import org.jclouds.docker.internal.BaseDockerParseTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
@Test(groups = "unit")
public class ImagesParseTest extends BaseDockerParseTest<List<ImageSummary>> {
@Override
public String resource() {
return "/images.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public List<ImageSummary> expected() {
return ImmutableList.of(
ImageSummary.create("d7057cb020844f245031d27b76cb18af05db1cc3a96a29fa7777af75f5ac91a3",
1442866547,
"cfa753dfea5e68a24366dfba16e6edf573daa447abf65bc11619c1a98a3aff54",
0,
1095501,
ImmutableList.of("docker.io/busybox:1.23.2", "docker.io/busybox:latest")),
ImageSummary.create("633fcd11259e8d6bccfbb59a4086b95b0d0fb44edfc3912000ef1f70e8a7bfc6",
1442598293,
"b65c936b5fb601d680ed656b1ccf8ab857c0e5cb521043a005405c194e9a69f3",
0,
5607885,
ImmutableList.of("docker.io/busybox:ubuntu-14.04", "jclouds:testTag")),
ImageSummary.create("f4fddc471ec22fc1f7d37768132f1753bc171121e30ac2af7fcb0302588197c0",
1442260874,
"",
5244426,
5244426,
ImmutableList.of("docker.io/alpine:3.2")),
ImageSummary.create("91e54dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c",
1440102075,
"d74508fb6632491cea586a1fd7d748dfc5274cd6fdfedee309ecdcbc2bf5cb82",
0,
188333286,
ImmutableList.of("docker.io/ubuntu:14.04", "docker.io/ubuntu:latest"))
);
}
}

View File

@ -0,0 +1,72 @@
/*
* 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 Info2ParseTest extends BaseDockerParseTest<Info> {
@Override
public String resource() {
return "/info2.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Info expected() {
return Info.create(
0, // containers
false, // debug
"aufs", // driver
ImmutableList.<List<String>>of(
ImmutableList.of("Root Dir", "/var/lib/docker/aufs"),
ImmutableList.of("Backing Filesystem", "extfs"),
ImmutableList.of("Dirs", "117"),
ImmutableList.of( "Dirperm1 Supported", "true")
), // driverStatus
"", // ExecutionDriver
true, // IPv4Forwarding
39, // Images
"https://index.docker.io/v1/", // IndexServerAddress
null, // InitPath
null, // InitSha1
"4.4.0-22-generic", // KernelVersion
true, // MemoryLimit
0, // NEventsListener
33, // NFd
83, // NGoroutines
"Ubuntu 16.04 LTS", // OperatingSystem
false, // SwapLimit
"/var/lib/docker", // DockerRootDir
null, // Labels
8248356864L, // MemTotal
4, // NCPU
"KFWR:PMVY:BEWE:TD52:5WEU:NXF4:I6S3:WDIE:GCRD:L3YA:VWC4:ZRYZ", // ID
"test" // name
);
}
}

View File

@ -0,0 +1,70 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.parse;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.docker.domain.Info;
import org.jclouds.docker.internal.BaseDockerParseTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
@Test(groups = "unit")
public class InfoParseTest extends BaseDockerParseTest<Info> {
@Override
public String resource() {
return "/info.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Info expected() {
return Info.create(
0, // containers
true, // debug
"aufs", // driver
ImmutableList.<List<String>>of(
ImmutableList.of("Root Dir", "/mnt/sda1/var/lib/docker/aufs"),
ImmutableList.of("Dirs", "46")
), // driverStatus
"native-0.2", // ExecutionDriver
true, // IPv4Forwarding
46, // Images
"https://index.docker.io/v1/", // IndexServerAddress
"/usr/local/bin/docker", // InitPath
"", // InitSha1
"3.16.7-tinycore64", // KernelVersion
true, // MemoryLimit
0, // NEventsListener
10, // NFd
11, // NGoroutines
"Boot2Docker 1.4.1 (TCL 5.4); master : 86f7ec8 - Tue Dec 16 23:11:29 UTC 2014", // OperatingSystem
true, // SwapLimit
"/mnt/sda1/var/lib/docker", // DockerRootDir
null, // Labels
2105585664, // MemTotal
8, // NCPU
"7V5Y:IQ2M:HWIL:AZJV:HKRD:Q7OZ:3EQA:ZHMO:4LAD:OSIY:YBAA:BSX6", // ID
"boot2docker" // name
);
}
}

View File

@ -0,0 +1,71 @@
/*
* 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.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.docker.domain.Network;
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 NetworkParseTest extends BaseDockerParseTest<Network> {
@Override
public String resource() {
return "/network.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Network expected() {
Map<String, String> options = ImmutableMap.<String, String> builder()
.put("com.docker.network.bridge.default_bridge", "true")
.put("com.docker.network.bridge.enable_icc", "true")
.put("com.docker.network.bridge.enable_ip_masquerade", "true")
.put("com.docker.network.bridge.host_binding_ipv4", "0.0.0.0")
.put("com.docker.network.bridge.name", "docker0")
.put("com.docker.network.driver.mtu", "1500")
.build();
return Network.create(
"bridge", // Name
"f2de39df4171b0dc801e8002d1d999b77256983dfc63041c0f34030aa3977566", // Id
"local", // Scope
"bridge", // Driver
Network.IPAM.create(
"default", // driver
ImmutableList.of(Network.IPAM.Config.create("172.17.0.0/16", null, null)) // config
),
ImmutableMap.of("39b69226f9d79f5634485fb236a23b2fe4e96a0a94128390a7fbbcc167065867",
Network.Details.create(
"ed2419a97c1d9954d05b46e462e7002ea552f216e9b136b80a7db8d98b442eda", //endpointId
"02:42:ac:11:00:02", // MAC
"172.17.0.2/16", // ipv4address
"" // ipv6address
)
),
options);
}
}

View File

@ -0,0 +1,97 @@
/*
* 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.Network;
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 NetworksParseTest extends BaseDockerParseTest<List<Network>> {
@Override
public String resource() {
return "/networks.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public List<Network> expected() {
return ImmutableList.of(
Network.create(
"bridge", // Name
"f2de39df4171b0dc801e8002d1d999b77256983dfc63041c0f34030aa3977566", // Id
"local", // Scope
"bridge", // Driver
Network.IPAM.create(
"default", // driver
ImmutableList.of(Network.IPAM.Config.create("172.17.0.0/16", null, null)) // config
),
ImmutableMap.of("39b69226f9d79f5634485fb236a23b2fe4e96a0a94128390a7fbbcc167065867",
Network.Details.create(
"ed2419a97c1d9954d05b46e462e7002ea552f216e9b136b80a7db8d98b442eda", //endpointId
"02:42:ac:11:00:02", // MAC
"172.17.0.2/16", // ipv4address
"" // ipv6address
)
),
ImmutableMap.<String, String> builder()
.put("com.docker.network.bridge.default_bridge", "true")
.put("com.docker.network.bridge.enable_icc", "true")
.put("com.docker.network.bridge.enable_ip_masquerade", "true")
.put("com.docker.network.bridge.host_binding_ipv4", "0.0.0.0")
.put("com.docker.network.bridge.name", "docker0")
.put("com.docker.network.driver.mtu", "1500")
.build()
),
Network.create(
"none", // Name
"e086a3893b05ab69242d3c44e49483a3bbbd3a26b46baa8f61ab797c1088d794", // Id
"local", // Scope
"null", // Driver
Network.IPAM.create(
"default", // driver
ImmutableList.<Network.IPAM.Config>of() // config
),
ImmutableMap.<String, Network.Details> of(),
ImmutableMap.<String, String> of()
),
Network.create(
"host", // Name
"13e871235c677f196c4e1ecebb9dc733b9b2d2ab589e30c539efeda84a24215e", // Id
"local", // Scope
"host", // Driver
Network.IPAM.create(
"default", // driver
ImmutableList.<Network.IPAM.Config>of() // config
),
ImmutableMap.<String, Network.Details> of(),
ImmutableMap.<String, String> of()
)
);
}
}

View File

@ -0,0 +1,46 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.docker.parse;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.docker.domain.Version;
import org.jclouds.docker.internal.BaseDockerParseTest;
import org.testng.annotations.Test;
@Test(groups = "unit")
public class VersionParseTest extends BaseDockerParseTest<Version> {
@Override
public String resource() {
return "/version.json";
}
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Version expected() {
return Version.create(
"1.15",
"amd64",
"c78088f",
"go1.3.3",
"3.16.4-tinycore64",
"linux",
"1.3.0");
}
}

View File

@ -0,0 +1,20 @@
#
# 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.
#
FROM kwart/alpine-ext:3.3-ssh
MAINTAINER JClouds Dev <dev@jclouds.apache.org>

View File

@ -0,0 +1,18 @@
#
# 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.
#
FROM scratch

View File

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

View File

@ -0,0 +1,72 @@
{
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": true,
"AttachStderr": true,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"FOO=bar",
"BAZ=quux"
],
"Cmd": [
"date"
],
"Entrypoint": [""],
"Image": "ubuntu",
"Labels": {
"com.example.vendor": "Acme",
"com.example.license": "GPL",
"com.example.version": "1.0"
},
"Volumes": {
"/volumes/data": {}
},
"WorkingDir": "",
"NetworkDisabled": false,
"MacAddress": "12:34:56:78:9a:bc",
"ExposedPorts": {
"22/tcp": {}
},
"StopSignal": "SIGTERM",
"HostConfig": {
"Binds": ["/tmp:/tmp"],
"Links": ["redis3:redis"],
"LxcConf": [{"lxc.utsname":"docker"}],
"Memory": 0,
"MemorySwap": 0,
"MemoryReservation": 0,
"KernelMemory": 0,
"CpuShares": 512,
"CpuPeriod": 100000,
"CpuQuota": 50000,
"CpusetCpus": "0,1",
"CpusetMems": "0,1",
"BlkioWeight": 300,
"MemorySwappiness": 60,
"OomKillDisable": false,
"PortBindings": { "22/tcp": [{ "HostPort": "11022" }] },
"PublishAllPorts": false,
"Privileged": false,
"ReadonlyRootfs": false,
"Dns": ["8.8.8.8"],
"DnsOptions": [""],
"DnsSearch": [""],
"ExtraHosts": null,
"VolumesFrom": ["parent", "other:ro"],
"CapAdd": ["NET_ADMIN"],
"CapDrop": ["MKNOD"],
"GroupAdd": ["newgroup"],
"RestartPolicy": { "Name": "", "MaximumRetryCount": 0 },
"NetworkMode": "bridge",
"Devices": [],
"Ulimits": [{}],
"LogConfig": { "Type": "json-file", "Config": {} },
"SecurityOpt": [],
"CgroupParent": "",
"VolumeDriver": ""
}
}

View File

@ -0,0 +1,147 @@
{
"AppArmorProfile": "",
"Args": [
"-c",
"exit 9"
],
"Config": {
"AttachStderr": true,
"AttachStdin": false,
"AttachStdout": true,
"Cmd": [
"/bin/sh",
"-c",
"exit 9"
],
"Domainname": "",
"Entrypoint": null,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"ExposedPorts": null,
"Hostname": "ba033ac44011",
"Image": "ubuntu",
"Labels": {
"com.example.vendor": "Acme",
"com.example.license": "GPL",
"com.example.version": "1.0"
},
"MacAddress": "",
"NetworkDisabled": false,
"OnBuild": null,
"OpenStdin": false,
"StdinOnce": false,
"Tty": false,
"User": "",
"Volumes": null,
"WorkingDir": "",
"StopSignal": "SIGTERM"
},
"Created": "2015-01-06T15:47:31.485331387Z",
"Driver": "devicemapper",
"ExecDriver": "native-0.2",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"BlkioWeight": 0,
"CapAdd": null,
"CapDrop": null,
"ContainerIDFile": "",
"CpusetCpus": "",
"CpusetMems": "",
"CpuShares": 0,
"CpuPeriod": 100000,
"Devices": [],
"Dns": null,
"DnsOptions": null,
"DnsSearch": null,
"ExtraHosts": null,
"IpcMode": "",
"Links": null,
"LxcConf": [],
"Memory": 0,
"MemorySwap": 0,
"MemoryReservation": 0,
"KernelMemory": 0,
"OomKillDisable": false,
"NetworkMode": "bridge",
"PortBindings": {},
"Privileged": false,
"ReadonlyRootfs": false,
"PublishAllPorts": false,
"RestartPolicy": {
"MaximumRetryCount": 2,
"Name": "on-failure"
},
"LogConfig": {
"Config": null,
"Type": "json-file"
},
"SecurityOpt": null,
"VolumesFrom": null,
"Ulimits": [{}],
"VolumeDriver": ""
},
"HostnamePath": "/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/hostname",
"HostsPath": "/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/hosts",
"LogPath": "/var/lib/docker/containers/1eb5fabf5a03807136561b3c00adcd2992b535d624d5e18b6cdc6a6844d9767b/1eb5fabf5a03807136561b3c00adcd2992b535d624d5e18b6cdc6a6844d9767b-json.log",
"Id": "ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39",
"Image": "04c5d3b7b0656168630d3ba35d8889bd0e9caafcaeb3004d2bfbc47e7c5d35d2",
"MountLabel": "",
"Name": "/boring_euclid",
"NetworkSettings": {
"Bridge": "",
"SandboxID": "",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": null,
"SandboxKey": "",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "",
"Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"MacAddress": "",
"Networks": {
"bridge": {
"EndpointID": "",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": ""
}
}
},
"Path": "/bin/sh",
"ProcessLabel": "",
"ResolvConfPath": "/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/resolv.conf",
"RestartCount": 1,
"State": {
"Error": "",
"ExitCode": 9,
"FinishedAt": "2015-01-06T15:47:32.080254511Z",
"OOMKilled": false,
"Paused": false,
"Pid": 0,
"Restarting": false,
"Running": true,
"StartedAt": "2015-01-06T15:47:32.072697474Z",
"Status": "running"
},
"Mounts": [
{
"Source": "/data",
"Destination": "/data",
"Mode": "ro,Z",
"RW": false
}
]
}

View File

@ -0,0 +1 @@
{"Id":"c6c74153ae4b1d1633d68890a68d89c40aa5e284a1ea016cbc6ef0e634ee37b2","Warnings":null}

View File

@ -0,0 +1,159 @@
{
"Args": [
"-iface",
"ethwe",
"-wait",
"5",
"-name",
"7a:63:a2:39:7b:0f"
],
"Config": {
"AttachStderr": false,
"AttachStdin": false,
"AttachStdout": false,
"Cmd": [
"-name",
"7a:63:a2:39:7b:0f"
],
"CpuShares": 0,
"Cpuset": "",
"Domainname": "",
"Entrypoint": [
"/home/weave/weaver",
"-iface",
"ethwe",
"-wait",
"5"
],
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"ExposedPorts": {
"6783/tcp": {},
"6783/udp": {}
},
"Hostname": "6c9932f478bd",
"Image": "zettio/weave",
"Memory": 0,
"MemorySwap": 0,
"NetworkDisabled": false,
"OnBuild": null,
"OpenStdin": false,
"PortSpecs": null,
"SecurityOpts": null,
"StdinOnce": false,
"Tty": false,
"User": "",
"Volumes": null,
"WorkingDir": "/home/weave"
},
"Created": "2014-10-31T17:00:21.544197943Z",
"Driver": "aufs",
"ExecDriver": "native-0.2",
"HostConfig": {
"Binds": null,
"CapAdd": ["NET_ADMIN"],
"CapDrop": ["MKNOD"],
"ContainerIDFile": "",
"Devices": [],
"Dns": [
"8.8.8.8",
"8.8.4.4"
],
"DnsSearch": null,
"ExtraHosts": ["extra:169.254.0.1"],
"Links": null,
"LxcConf": [],
"NetworkMode": "bridge",
"PortBindings": {
"6783/tcp": [
{
"HostIp": "",
"HostPort": "6783"
}
],
"6783/udp": [
{
"HostIp": "",
"HostPort": "6783"
}
]
},
"Privileged": true,
"PublishAllPorts": false,
"RestartPolicy": {
"MaximumRetryCount": 0,
"Name": ""
},
"VolumesFrom": null
},
"HostnamePath": "/var/lib/docker/containers/6c9932f478bd761f32ddb54ed28ab42ab6fac6f2a279f561ea31503ee9d39524/hostname",
"HostsPath": "/var/lib/docker/containers/6c9932f478bd761f32ddb54ed28ab42ab6fac6f2a279f561ea31503ee9d39524/hosts",
"Id": "6c9932f478bd761f32ddb54ed28ab42ab6fac6f2a279f561ea31503ee9d39524",
"Image": "57e570db16baba1e8c0d6f3c15868ddb400f64ff76ec948e65c3ca3f15fb3587",
"MountLabel": "",
"Name": "/weave",
"NetworkSettings": {
"Bridge": "",
"SandboxID": "3ef128b055eb9ef62a6a2c281d97a2dfde5f47947d490f1dd2a81612611d961f",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/3ef128b055eb",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "9e8dcc0c8288938a923018fee0728cee8e6de7c01a5150738ee6e51c1caf8cf6",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"JCLOUDS_NETWORK": {
"EndpointID": "04268fbb4dc368b5a53bb1c3f89294a4f0c72095deb944db3c4efc6d6a439304",
"Gateway": "172.19.0.1",
"IPAddress": "172.19.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:13:00:02"
},
"bridge": {
"EndpointID": "9e8dcc0c8288938a923018fee0728cee8e6de7c01a5150738ee6e51c1caf8cf6",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02"
}
}
},
"Node": {
"IP": "10.10.10.10"
},
"Path": "/home/weave/weaver",
"ProcessLabel": "",
"ResolvConfPath": "/var/lib/docker/containers/6c9932f478bd761f32ddb54ed28ab42ab6fac6f2a279f561ea31503ee9d39524/resolv.conf",
"SecurityOpt": [],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 10357,
"ExitCode": 0,
"Error": "",
"StartedAt": "2015-11-10T09:33:21.68146124Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Volumes": {},
"VolumesRW": {}
}

Some files were not shown because too many files have changed in this diff Show More