", "Config": {"key1": "val1"}}`.
+ Available types: `json-file`, `syslog`, `journald`, `none`.
+ `json-file` logging driver.
+- **CgroupParent** - Path to cgroups under which the cgroup for the container will be created. If the path is not absolute, the path is considered to be relative to the cgroups path of the init process. Cgroups will be created if they do not already exist.
+
Status Codes:
- **204** – no error
@@ -906,7 +992,7 @@ Status Codes:
1. Read 8 bytes
2. chose stdout or stderr depending on the first byte
- 3. Extract the frame size from the last 4 byets
+ 3. Extract the frame size from the last 4 bytes
4. Read the extracted size and output it on the correct output
5. Goto 1
@@ -1109,6 +1195,7 @@ Query Parameters:
- **all** – 1/True/true or 0/False/false, default false
- **filters** – a json encoded value of the filters (a map[string][]string) to process on the images list. Available filters:
- dangling=true
+ - label=`key` or `key=value` of an image label
### Build image from a Dockerfile
@@ -1163,12 +1250,12 @@ Query Parameters:
- **memory** - set memory limit for build
- **memswap** - Total memory (memory + swap), `-1` to disable swap
- **cpushares** - CPU shares (relative weight)
-- **cpusetcpus** - CPUs in which to allow exection, e.g., `0-3`, `0,1`
+- **cpusetcpus** - CPUs in which to allow execution, e.g., `0-3`, `0,1`
Request Headers:
- **Content-type** – should be set to `"application/tar"`.
-- **X-Registry-Config** – base64-encoded ConfigFile objec
+- **X-Registry-Config** – base64-encoded ConfigFile object
Status Codes:
@@ -1709,7 +1796,7 @@ Get a tarball containing all images and metadata for the repository specified
by `name`.
If `name` is a specific name and tag (e.g. ubuntu:latest), then only that image
-(and its parents) are returned. If `name` is an image ID, similarly only tha
+(and its parents) are returned. If `name` is an image ID, similarly only that
image (and its parents) are returned, but with the exclusion of the
'repositories' file in the tarball, as there were no image names referenced.
diff --git a/docs/sources/reference/api/docker_remote_api_v1.6.md b/docs/sources/reference/api/docker_remote_api_v1.6.md
index d0f9661e50913..cd8a7308841dc 100644
--- a/docs/sources/reference/api/docker_remote_api_v1.6.md
+++ b/docs/sources/reference/api/docker_remote_api_v1.6.md
@@ -560,7 +560,7 @@ Status Codes:
1. Read 8 bytes
2. chose stdout or stderr depending on the first byte
- 3. Extract the frame size from the last 4 byets
+ 3. Extract the frame size from the last 4 bytes
4. Read the extracted size and output it on the correct output
5. Goto 1)
diff --git a/docs/sources/reference/api/docker_remote_api_v1.7.md b/docs/sources/reference/api/docker_remote_api_v1.7.md
index 6cdd60374fb14..dade45fbc9d23 100644
--- a/docs/sources/reference/api/docker_remote_api_v1.7.md
+++ b/docs/sources/reference/api/docker_remote_api_v1.7.md
@@ -505,7 +505,7 @@ Status Codes:
1. Read 8 bytes
2. chose stdout or stderr depending on the first byte
- 3. Extract the frame size from the last 4 byets
+ 3. Extract the frame size from the last 4 bytes
4. Read the extracted size and output it on the correct output
5. Goto 1)
diff --git a/docs/sources/reference/api/docker_remote_api_v1.8.md b/docs/sources/reference/api/docker_remote_api_v1.8.md
index 409e63a163499..56260db867c02 100644
--- a/docs/sources/reference/api/docker_remote_api_v1.8.md
+++ b/docs/sources/reference/api/docker_remote_api_v1.8.md
@@ -553,7 +553,7 @@ Status Codes:
1. Read 8 bytes
2. chose stdout or stderr depending on the first byte
- 3. Extract the frame size from the last 4 byets
+ 3. Extract the frame size from the last 4 bytes
4. Read the extracted size and output it on the correct output
5. Goto 1)
diff --git a/docs/sources/reference/api/docker_remote_api_v1.9.md b/docs/sources/reference/api/docker_remote_api_v1.9.md
index 7ea3fc9ab1a94..26c6b453e0345 100644
--- a/docs/sources/reference/api/docker_remote_api_v1.9.md
+++ b/docs/sources/reference/api/docker_remote_api_v1.9.md
@@ -557,7 +557,7 @@ Status Codes:
1. Read 8 bytes
2. chose stdout or stderr depending on the first byte
- 3. Extract the frame size from the last 4 byets
+ 3. Extract the frame size from the last 4 bytes
4. Read the extracted size and output it on the correct output
5. Goto 1)
@@ -675,7 +675,7 @@ Status Codes:
## 2.2 Images
-### List Images
+### List images
`GET /images/json`
@@ -1052,7 +1052,7 @@ Query Parameters:
Request Headers:
- **Content-type** – should be set to `"application/tar"`.
-- **X-Registry-Config** – base64-encoded ConfigFile objec
+- **X-Registry-Config** – base64-encoded ConfigFile object
Status Codes:
@@ -1119,7 +1119,7 @@ Status Codes:
- **200** – no error
- **500** – server error
-### Show the docker version information
+### Show the Docker version information
`GET /version`
@@ -1343,7 +1343,7 @@ Here are the steps of `docker run` :
In this version of the API, /attach, uses hijacking to transport stdin,
stdout and stderr on the same socket. This might change in the future.
-## 3.3 CORS Requests
+## 3.3 CORS requests
To enable cross origin requests to the remote api add the flag
"--api-enable-cors" when running docker in daemon mode.
diff --git a/docs/sources/reference/api/hub_registry_spec.md b/docs/sources/reference/api/hub_registry_spec.md
index f01007587a37d..b1481e3a0344e 100644
--- a/docs/sources/reference/api/hub_registry_spec.md
+++ b/docs/sources/reference/api/hub_registry_spec.md
@@ -1,8 +1,8 @@
-page_title: Registry Documentation
+page_title: Registry documentation
page_description: Documentation for docker Registry and Registry API
page_keywords: docker, registry, api, hub
-# The Docker Hub and the Registry spec
+# The Docker Hub and the Registry 1.0 spec
## The three roles
@@ -28,9 +28,9 @@ The Docker Hub is authoritative for that information.
There is only one instance of the Docker Hub, run and
managed by Docker Inc.
-### Registry
+### Docker Registry 1.0
-The registry has the following characteristics:
+The 1.0 registry has the following characteristics:
- It stores the images and the graph for a set of repositories
- It does not have user accounts data
@@ -679,7 +679,7 @@ On every request, a special header can be returned:
On the next request, the client will always pick a server from this
list.
-## Authentication & Authorization
+## Authentication and authorization
### On the Docker Hub
@@ -747,7 +747,7 @@ Next request:
GET /(...)
Cookie: session="wD/J7LqL5ctqw8haL10vgfhrb2Q=?foo=UydiYXInCnAxCi4=×tamp=RjEzNjYzMTQ5NDcuNDc0NjQzCi4="
-## Document Version
+## Document version
- 1.0 : May 6th 2013 : initial release
- 1.1 : June 1st 2013 : Added Delete Repository and way to handle new
diff --git a/docs/sources/reference/api/registry_api.md b/docs/sources/reference/api/registry_api.md
index 54a158934a77c..13a51356f0462 100644
--- a/docs/sources/reference/api/registry_api.md
+++ b/docs/sources/reference/api/registry_api.md
@@ -2,11 +2,11 @@ page_title: Registry API
page_description: API Documentation for Docker Registry
page_keywords: API, Docker, index, registry, REST, documentation
-# Docker Registry API
+# Docker Registry API v1
## Introduction
- - This is the REST API for the Docker Registry
+ - This is the REST API for the Docker Registry 1.0
- It stores the images and the graph for a set of repositories
- It does not have user accounts data
- It has no notion of user accounts or authorization
diff --git a/docs/sources/reference/api/registry_api_client_libraries.md b/docs/sources/reference/api/registry_api_client_libraries.md
index 6977af3cc462f..965ba460330bd 100644
--- a/docs/sources/reference/api/registry_api_client_libraries.md
+++ b/docs/sources/reference/api/registry_api_client_libraries.md
@@ -1,8 +1,8 @@
-page_title: Registry API Client Libraries
+page_title: Registry API client libraries
page_description: Various client libraries available to use with the Docker registry API
page_keywords: API, Docker, index, registry, REST, documentation, clients, C#, Erlang, Go, Groovy, Java, JavaScript, Perl, PHP, Python, Ruby, Rust, Scala
-# Docker Registry API Client Libraries
+# Docker Registry 1.0 API client libraries
These libraries have not been tested by the Docker maintainers for
compatibility. Please file issues with the library owners. If you find
diff --git a/docs/sources/reference/api/remote_api_client_libraries.md b/docs/sources/reference/api/remote_api_client_libraries.md
index d79bbd89ab136..cbe8f3a32840f 100644
--- a/docs/sources/reference/api/remote_api_client_libraries.md
+++ b/docs/sources/reference/api/remote_api_client_libraries.md
@@ -1,8 +1,8 @@
-page_title: Remote API Client Libraries
+page_title: Remote API client libraries
page_description: Various client libraries available to use with the Docker remote API
page_keywords: API, Docker, index, registry, REST, documentation, clients, C#, Erlang, Go, Groovy, Java, JavaScript, Perl, PHP, Python, Ruby, Rust, Scala
-# Docker Remote API Client Libraries
+# Docker Remote API client libraries
These libraries have not been tested by the Docker maintainers for
compatibility. Please file issues with the library owners. If you find
@@ -61,110 +61,116 @@ will add the libraries here.
Active |
+ Haskell |
+ docker-hs |
+ https://github.com/denibertovic/docker-hs |
+ Active |
+
+
Java |
docker-java |
https://github.com/docker-java/docker-java |
Active |
-
+
Java |
docker-client |
https://github.com/spotify/docker-client |
Active |
-
+
Java |
jclouds-docker |
https://github.com/jclouds/jclouds-labs/tree/master/docker |
Active |
-
+
JavaScript (NodeJS) |
dockerode |
https://github.com/apocas/dockerode
Install via NPM: npm install dockerode |
Active |
-
+
JavaScript (NodeJS) |
docker.io |
https://github.com/appersonlabs/docker.io
Install via NPM: npm install docker.io |
Active |
-
+
JavaScript |
docker-js |
https://github.com/dgoujard/docker-js |
Outdated |
-
+
JavaScript (Angular) WebUI |
docker-cp |
https://github.com/13W/docker-cp |
Active |
-
+
JavaScript (Angular) WebUI |
dockerui |
https://github.com/crosbymichael/dockerui |
Active |
-
+
Perl |
Net::Docker |
https://metacpan.org/pod/Net::Docker |
Active |
-
+
Perl |
Eixo::Docker |
https://github.com/alambike/eixo-docker |
Active |
-
+
PHP |
Alvine |
http://pear.alvine.io/ (alpha) |
Active |
-
+
PHP |
Docker-PHP |
http://stage1.github.io/docker-php/ |
Active |
-
+
Python |
docker-py |
https://github.com/docker/docker-py |
Active |
-
+
Ruby |
docker-api |
https://github.com/swipely/docker-api |
Active |
-
+
Ruby |
docker-client |
https://github.com/geku/docker-client |
Outdated |
-
+
Rust |
docker-rust |
https://github.com/abh1nav/docker-rust |
Active |
-
+
Scala |
tugboat |
https://github.com/softprops/tugboat |
Active |
-
+
Scala |
reactive-docker |
https://github.com/almoehi/reactive-docker |
diff --git a/docs/sources/reference/builder.md b/docs/sources/reference/builder.md
index d837541aa2401..7dbe549237f13 100644
--- a/docs/sources/reference/builder.md
+++ b/docs/sources/reference/builder.md
@@ -1,8 +1,8 @@
-page_title: Dockerfile Reference
+page_title: Dockerfile reference
page_description: Dockerfiles use a simple DSL which allows you to automate the steps you would normally manually take to create an image.
page_keywords: builder, docker, Dockerfile, automation, image creation
-# Dockerfile Reference
+# Dockerfile reference
**Docker can build images automatically** by reading the instructions
from a `Dockerfile`. A `Dockerfile` is a text document that contains all
@@ -41,10 +41,11 @@ whole context must be transferred to the daemon. The Docker CLI reports
> repository, the entire contents of your hard drive will get sent to the daemon (and
> thus to the machine running the daemon). You probably don't want that.
-In most cases, it's best to put each Dockerfile in an empty directory, and then add only
-the files needed for building that Dockerfile to that directory. To further speed up the
-build, you can exclude files and directories by adding a `.dockerignore` file to the same
-directory.
+In most cases, it's best to put each Dockerfile in an empty directory. Then,
+only add the files needed for building the Dockerfile to the directory. To
+increase the build's performance, you can exclude files and directories by
+adding a `.dockerignore` file to the directory. For information about how to
+[create a `.dockerignore` file](#the-dockerignore-file) on this page.
You can specify a repository and tag at which to save the new image if
the build succeeds:
@@ -105,7 +106,7 @@ be treated as an argument. This allows statements like:
Here is the set of instructions you can use in a `Dockerfile` for building
images.
-### Environment Replacement
+### Environment replacement
> **Note**: prior to 1.3, `Dockerfile` environment variables were handled
> similarly, in that they would be replaced as described below. However, there
@@ -128,7 +129,7 @@ modifiers as specified below:
* `${variable:-word}` indicates that if `variable` is set then the result
will be that value. If `variable` is not set then `word` will be the result.
-* `${variable:+word}` indiates that if `variable` is set then `word` will be
+* `${variable:+word}` indicates that if `variable` is set then `word` will be
the result, otherwise the result is the empty string.
In all cases, `word` can be any string, including additional environment
@@ -158,7 +159,7 @@ The instructions that handle environment variables in the `Dockerfile` are:
`ONBUILD` instructions are **NOT** supported for environment replacement, even
the instructions above.
-Environment variable subtitution will use the same value for each variable
+Environment variable substitution will use the same value for each variable
throughout the entire command. In other words, in this example:
ENV abc=hello
@@ -169,43 +170,67 @@ will result in `def` having a value of `hello`, not `bye`. However,
`ghi` will have a value of `bye` because it is not part of the same command
that set `abc` to `bye`.
-## The `.dockerignore` file
+### .dockerignore file
-If a file named `.dockerignore` exists in the source repository, then it
-is interpreted as a newline-separated list of exclusion patterns.
-Exclusion patterns match files or directories relative to the source repository
-that will be excluded from the context. Globbing is done using Go's
+If a file named `.dockerignore` exists in the root of `PATH`, then Docker
+interprets it as a newline-separated list of exclusion patterns. Docker excludes
+files or directories relative to `PATH` that match these exclusion patterns. If
+there are any `.dockerignore` files in `PATH` subdirectories, Docker treats
+them as normal files.
+
+Filepaths in `.dockerignore` are absolute with the current directory as the
+root. Wildcards are allowed but the search is not recursive. Globbing (file name
+expansion) is done using Go's
[filepath.Match](http://golang.org/pkg/path/filepath#Match) rules.
-> **Note**:
-> The `.dockerignore` file can even be used to ignore the `Dockerfile` and
-> `.dockerignore` files. This might be useful if you are copying files from
-> the root of the build context into your new containter but do not want to
-> include the `Dockerfile` or `.dockerignore` files (e.g. `ADD . /someDir/`).
+You can specify exceptions to exclusion rules. To do this, simply prefix a
+pattern with an `!` (exclamation mark) in the same way you would in a
+`.gitignore` file. Currently there is no support for regular expressions.
+Formats like `[^temp*]` are ignored.
-The following example shows the use of the `.dockerignore` file to exclude the
-`.git` directory from the context. Its effect can be seen in the changed size of
-the uploaded context.
+The following is an example `.dockerignore` file:
+
+```
+ */temp*
+ */*/temp*
+ temp?
+ *.md
+ !LICENCSE.md
+```
+
+This file causes the following build behavior:
+
+| Rule | Behavior |
+|----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `*/temp*` | Exclude all files with names starting with`temp` in any subdirectory below the root directory. For example, a file named`/somedir/temporary.txt` is ignored. |
+| `*/*/temp*` | Exclude files starting with name `temp` from any subdirectory that is two levels below the root directory. For example, the file `/somedir/subdir/temporary.txt` is ignored. |
+| `temp?` | Exclude the files that match the pattern in the root directory. For example, the files `tempa`, `tempb` in the root directory are ignored. |
+| `*.md ` | Exclude all markdown files. |
+| `!LICENSE.md` | Exception to the exclude all Markdown files is this file, `LICENSE.md`, include this file in the build. |
+
+The placement of `!` exception rules influences the matching algorithm; the
+last line of the `.dockerignore` that matches a particular file determines
+whether it is included or excluded. In the above example, the `LICENSE.md` file
+matches both the `*.md` and `!LICENSE.md` rule. If you reverse the lines in the
+example:
+
+```
+ */temp*
+ */*/temp*
+ temp?
+ !LICENCSE.md
+ *.md
+```
+
+The build would exclude `LICENSE.md` because the last `*.md` rule adds all
+Markdown files back onto the ignore list. The `!LICENSE.md` rule has no effect
+because the subsequent `*.md` rule overrides it.
+
+You can even use the `.dockerignore` file to ignore the `Dockerfile` and
+`.dockerignore` files. This is useful if you are copying files from the root of
+the build context into your new container but do not want to include the
+`Dockerfile` or `.dockerignore` files (e.g. `ADD . /someDir/`).
- $ docker build .
- Uploading context 18.829 MB
- Uploading context
- Step 0 : FROM busybox
- ---> 769b9341d937
- Step 1 : CMD echo Hello World
- ---> Using cache
- ---> 99cc1ad10469
- Successfully built 99cc1ad10469
- $ echo ".git" > .dockerignore
- $ docker build .
- Uploading context 6.76 MB
- Uploading context
- Step 0 : FROM busybox
- ---> 769b9341d937
- Step 1 : CMD echo Hello World
- ---> Using cache
- ---> 99cc1ad10469
- Successfully built 99cc1ad10469
## FROM
@@ -288,7 +313,7 @@ guide](/articles/dockerfile_best-practices/#build-cache) for more information.
The cache for `RUN` instructions can be invalidated by `ADD` instructions. See
[below](#add) for details.
-### Known Issues (RUN)
+### Known issues (RUN)
- [Issue 783](https://github.com/docker/docker/issues/783) is about file
permissions problems that can occur when using the AUFS file system. You
@@ -299,7 +324,7 @@ The cache for `RUN` instructions can be invalidated by `ADD` instructions. See
the layers with `dirperm1` option. More details on `dirperm1` option can be
found at [`aufs` man page](http://aufs.sourceforge.net/aufs3/man.html)
- If your system doesnt have support for `dirperm1`, the issue describes a workaround.
+ If your system doesn't have support for `dirperm1`, the issue describes a workaround.
## CMD
@@ -368,14 +393,13 @@ default specified in `CMD`.
The `LABEL` instruction adds metadata to an image. A `LABEL` is a
key-value pair. To include spaces within a `LABEL` value, use quotes and
-blackslashes as you would in command-line parsing.
+backslashes as you would in command-line parsing.
LABEL "com.example.vendor"="ACME Incorporated"
An image can have more than one label. To specify multiple labels, separate each
-key-value pair by an EOL.
+key-value pair with whitespace.
- LABEL com.example.label-without-value
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
@@ -385,6 +409,8 @@ Docker recommends combining labels in a single `LABEL` instruction where
possible. Each `LABEL` instruction produces a new layer which can result in an
inefficient image if you use many labels. This example results in four image
layers.
+
+ LABEL multi.label1="value1" multi.label2="value2" other="value3"
Labels are additive including `LABEL`s in `FROM` images. As the system
encounters and then applies a new label, new `key`s override any previous labels
@@ -392,6 +418,16 @@ with identical keys.
To view an image's labels, use the `docker inspect` command.
+ "Labels": {
+ "com.example.vendor": "ACME Incorporated"
+ "com.example.label-with-value": "foo",
+ "version": "1.0",
+ "description": "This text illustrates that label-values can span multiple lines.",
+ "multi.label1": "value1",
+ "multi.label2": "value2",
+ "other": "value3"
+ },
+
## EXPOSE
EXPOSE [...]
@@ -962,7 +998,7 @@ For example you might add something like this:
> **Warning**: The `ONBUILD` instruction may not trigger `FROM` or `MAINTAINER` instructions.
-## Dockerfile Examples
+## Dockerfile examples
# Nginx
#
diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md
index 9f8daa03f5978..c69f0a170e2fa 100644
--- a/docs/sources/reference/commandline/cli.md
+++ b/docs/sources/reference/commandline/cli.md
@@ -24,7 +24,7 @@ the `docker` command, your system administrator can create a Unix group called
For more information about installing Docker or `sudo` configuration, refer to
the [installation](/installation) instructions for your operating system.
-## Environment Variables
+## Environment variables
For easy reference, the following list of environment variables are supported
by the `docker` command line:
@@ -48,6 +48,35 @@ These Go environment variables are case-insensitive. See the
[Go specification](http://golang.org/pkg/net/http/) for details on these
variables.
+## Configuration files
+
+The Docker command line stores its configuration files in a directory called
+`.docker` within your `HOME` directory. Docker manages most of the files in
+`.docker` and you should not modify them. However, you *can modify* the
+`.docker/config.json` file to control certain aspects of how the `docker`
+command behaves.
+
+Currently, you can modify the `docker` command behavior using environment
+variables or command-line options. You can also use options within
+`config.json` to modify some of the same behavior. When using these
+mechanisms, you must keep in mind the order of precedence among them. Command
+line options override environment variables and environment variables override
+properties you specify in a `config.json` file.
+
+The `config.json` file stores a JSON encoding of a single `HttpHeaders`
+property. The property specifies a set of headers to include in all
+messages sent from the Docker client to the daemon. Docker does not try to
+interpret or understand these header; it simply puts them into the messages.
+Docker does not allow these headers to change any headers it sets for itself.
+
+Following is a sample `config.json` file:
+
+ {
+ "HttpHeaders: {
+ "MyHeader": "MyValue"
+ }
+ }
+
## Help
To list the help on any command just execute the command, followed by the `--help` option.
@@ -116,6 +145,8 @@ expect an integer, and they can only be specified once.
--bip="" Specify network bridge IP
-D, --debug=false Enable debug mode
-d, --daemon=false Enable daemon mode
+ --default-gateway="" Container default gateway IPv4 address
+ --default-gateway-v6="" Container default gateway IPv6 address
--dns=[] DNS server to use
--dns-search=[] DNS search domains to use
-e, --exec-driver="native" Exec driver to use
@@ -134,7 +165,7 @@ expect an integer, and they can only be specified once.
--ipv6=false Enable IPv6 networking
-l, --log-level="info" Set the logging level
--label=[] Set key=value labels to the daemon
- --log-driver="json-file" Container's logging driver (json-file/none)
+ --log-driver="json-file" Default driver for container logs
--mtu=0 Set the containers network MTU
-p, --pidfile="/var/run/docker.pid" Path to use for daemon PID file
--registry-mirror=[] Preferred Docker registry mirror
@@ -376,7 +407,42 @@ Currently supported options are:
$ docker -d --storage-opt dm.blkdiscard=false
-### Docker exec-driver option
+ * `dm.override_udev_sync_check`
+
+ Overrides the `udev` synchronization checks between `devicemapper` and `udev`.
+ `udev` is the device manager for the Linux kernel.
+
+ To view the `udev` sync support of a Docker daemon that is using the
+ `devicemapper` driver, run:
+
+ $ docker info
+ [...]
+ Udev Sync Supported: true
+ [...]
+
+ When `udev` sync support is `true`, then `devicemapper` and udev can
+ coordinate the activation and deactivation of devices for containers.
+
+ When `udev` sync support is `false`, a race condition occurs between
+ the`devicemapper` and `udev` during create and cleanup. The race condition
+ results in errors and failures. (For information on these failures, see
+ [docker#4036](https://github.com/docker/docker/issues/4036))
+
+ To allow the `docker` daemon to start, regardless of `udev` sync not being
+ supported, set `dm.override_udev_sync_check` to true:
+
+ $ docker -d --storage-opt dm.override_udev_sync_check=true
+
+ When this value is `true`, the `devicemapper` continues and simply warns
+ you the errors are happening.
+
+ > **Note**: The ideal is to pursue a `docker` daemon and environment that
+ > does support synchronizing with `udev`. For further discussion on this
+ > topic, see [docker#4036](https://github.com/docker/docker/issues/4036).
+ > Otherwise, set this flag for migrating existing Docker daemons to a
+ > daemon with a supported environment.
+
+### Docker execdriver option
The Docker daemon uses a specifically built `libcontainer` execution driver as its
interface to the Linux kernel `namespaces`, `cgroups`, and `SELinux`.
@@ -386,6 +452,21 @@ https://linuxcontainers.org/) via the `lxc` execution driver, however, this is
not where the primary development of new functionality is taking place.
Add `-e lxc` to the daemon flags to use the `lxc` execution driver.
+#### Options for the native execdriver
+
+You can configure the `native` (libcontainer) execdriver using options specified
+with the `--exec-opt` flag. All the flag's options have the `native` prefix. A
+single `native.cgroupdriver` option is available.
+
+The `native.cgroupdriver` option specifies the management of the container's
+cgroups. You can specify `cgroupfs` or `systemd`. If you specify `systemd` and
+it is not available, the system uses `cgroupfs`. By default, if no option is
+specified, the execdriver first tries `systemd` and falls back to `cgroupfs`.
+This example sets the execdriver to `cgroupfs`:
+
+ $ sudo docker -d --exec-opt native.cgroupdriver=cgroupfs
+
+Setting this option applies to all containers the daemon launches.
### Daemon DNS options
@@ -481,10 +562,16 @@ interactively. You can attach to the same contained process multiple times
simultaneously, screen sharing style, or quickly view the progress of your
daemonized process.
-You can detach from the container (and leave it running) with `CTRL-p CTRL-q`
-(for a quiet exit) or `CTRL-c` which will send a `SIGKILL` to the container.
-When you are attached to a container, and exit its main process, the process's
-exit code will be returned to the client.
+You can detach from the container and leave it running with `CTRL-p
+CTRL-q` (for a quiet exit) or with `CTRL-c` if `--sig-proxy` is false.
+
+If `--sig-proxy` is true (the default),`CTRL-c` sends a `SIGINT`
+to the container.
+
+>**Note**: A process running as PID 1 inside a container is treated
+>specially by Linux: it ignores any signal with the default action.
+>So, the process will not terminate on `SIGINT` or `SIGTERM` unless it is
+>coded to do so.
It is forbidden to redirect the standard input of a `docker attach` command while
attaching to a tty-enabled container (i.e.: launched with `-t`).
@@ -556,6 +643,7 @@ is returned by the `docker attach` command to its caller too:
--memory-swap="" Total memory (memory + swap), `-1` to disable swap
-c, --cpu-shares CPU Shares (relative weight)
--cpuset-cpus="" CPUs in which to allow execution, e.g. `0-3`, `0,1`
+ --cpuset-mems="" MEMs in which to allow execution, e.g. `0-3`, `0,1`
Builds Docker images from a Dockerfile and a "context". A build's context is
the files located in the specified `PATH` or `URL`. The build process can
@@ -563,12 +651,13 @@ refer to any of the files in the context. For example, your build can use
an [*ADD*](/reference/builder/#add) instruction to reference a file in the
context.
-The `URL` parameter can specify the location of a Git repository; in this
-case, the repository is the context. The Git repository is recursively
-cloned with its submodules. The system does a fresh `git clone -recursive`
-in a temporary directory on your local host. Then, this clone is sent to
-the Docker daemon as the context. Local clones give you the ability to
-access private repositories using local user credentials, VPN's, and so forth.
+The `URL` parameter can specify the location of a Git repository;
+the repository acts as the build context. The system recursively clones the repository
+and its submodules using a `git clone --depth 1 --recursive` command.
+This command runs in a temporary directory on your local host.
+After the command succeeds, the directory is sent to the Docker daemon as the context.
+Local clones give you the ability to access private repositories using
+local user credentials, VPN's, and so forth.
Instead of specifying a context, you can pass a single Dockerfile in the
`URL` or pipe the file in via `STDIN`. To pipe a Dockerfile from `STDIN`:
@@ -579,6 +668,26 @@ If you use STDIN or specify a `URL`, the system places the contents into a
file called `Dockerfile`, and any `-f`, `--file` option is ignored. In this
scenario, there is no context.
+By default the `docker build` command will look for a `Dockerfile` at the
+root of the build context. The `-f`, `--file`, option lets you specify
+the path to an alternative file to use instead. This is useful
+in cases where the same set of files are used for multiple builds. The path
+must be to a file within the build context. If a relative path is specified
+then it must to be relative to the current directory.
+
+In most cases, it's best to put each Dockerfile in an empty directory. Then, add
+to that directory only the files needed for building the Dockerfile. To increase
+the build's performance, you can exclude files and directories by adding a
+`.dockerignore` file to that directory as well. For information on creating one,
+see the [.dockerignore file](../../reference/builder/#dockerignore-file).
+
+If the Docker client loses connection to the daemon, the build is canceled.
+This happens if you interrupt the Docker client with `ctrl-c` or if the Docker
+client is killed for any reason.
+
+> **Note:** Currently only the "run" phase of the build can be canceled until
+> pull cancelation is implemented).
+
### Return code
On a successful build, a return code of success `0` will be returned.
@@ -599,55 +708,11 @@ INFO[0000] The command [/bin/sh -c exit 13] returned a non-zero code: 13
$ echo $?
1
```
-
-### .dockerignore file
-
-If a file named `.dockerignore` exists in the root of `PATH` then it
-is interpreted as a newline-separated list of exclusion patterns.
-Exclusion patterns match files or directories relative to `PATH` that
-will be excluded from the context. Globbing is done using Go's
-[filepath.Match](http://golang.org/pkg/path/filepath#Match) rules.
-
-Please note that `.dockerignore` files in other subdirectories are
-considered as normal files. Filepaths in `.dockerignore` are absolute with
-the current directory as the root. Wildcards are allowed but the search
-is not recursive.
-
-#### Example .dockerignore file
- */temp*
- */*/temp*
- temp?
-
-The first line above `*/temp*`, would ignore all files with names starting with
-`temp` from any subdirectory below the root directory. For example, a file named
-`/somedir/temporary.txt` would be ignored. The second line `*/*/temp*`, will
-ignore files starting with name `temp` from any subdirectory that is two levels
-below the root directory. For example, the file `/somedir/subdir/temporary.txt`
-would get ignored in this case. The last line in the above example `temp?`
-will ignore the files that match the pattern from the root directory.
-For example, the files `tempa`, `tempb` are ignored from the root directory.
-Currently there is no support for regular expressions. Formats
-like `[^temp*]` are ignored.
-
-By default the `docker build` command will look for a `Dockerfile` at the
-root of the build context. The `-f`, `--file`, option lets you specify
-the path to an alternative file to use instead. This is useful
-in cases where the same set of files are used for multiple builds. The path
-must be to a file within the build context. If a relative path is specified
-then it must to be relative to the current directory.
-
-If the Docker client loses connection to the daemon, the build is canceled.
-This happens if you interrupt the Docker client with `ctrl-c` or if the Docker
-client is killed for any reason.
-
-> **Note:** Currently only the "run" phase of the build can be canceled until
-> pull cancelation is implemented).
-
See also:
[*Dockerfile Reference*](/reference/builder).
-#### Examples
+### Examples
$ docker build .
Uploading context 10240 bytes
@@ -716,7 +781,8 @@ affect the build cache.
This example shows the use of the `.dockerignore` file to exclude the `.git`
directory from the context. Its effect can be seen in the changed size of the
-uploaded context.
+uploaded context. The builder reference contains detailed information on
+[creating a .dockerignore file](../../builder/#dockerignore-file)
$ docker build -t vieux/apache:2.0 .
@@ -797,7 +863,8 @@ If this behavior is undesired, set the 'p' option to false.
The `--change` option will apply `Dockerfile` instructions to the image
that is created.
-Supported `Dockerfile` instructions: `ADD`|`CMD`|`ENTRYPOINT`|`ENV`|`EXPOSE`|`FROM`|`MAINTAINER`|`RUN`|`USER`|`LABEL`|`VOLUME`|`WORKDIR`|`COPY`
+Supported `Dockerfile` instructions:
+`CMD`|`ENTRYPOINT`|`ENV`|`EXPOSE`|`ONBUILD`|`USER`|`VOLUME`|`WORKDIR`
#### Commit a container
@@ -851,6 +918,8 @@ Creates a new container.
--cgroup-parent="" Optional parent cgroup for the container
--cidfile="" Write the container ID to the file
--cpuset-cpus="" CPUs in which to allow execution (0-3, 0,1)
+ --cpuset-mems="" Memory nodes (MEMs) in which to allow execution (0-3, 0,1)
+ --cpu-quota=0 Limit the CPU CFS (Completely Fair Scheduler) quota
--device=[] Add a host device to the container
--dns=[] Set custom DNS servers
--dns-search=[] Set custom DNS search domains
@@ -1079,7 +1148,9 @@ You'll need two shells for this example.
-d, --detach=false Detached mode: run command in the background
-i, --interactive=false Keep STDIN open even if not attached
+ --privileged=false Give extended privileges to the command
-t, --tty=false Allocate a pseudo-TTY
+ -u, --user= Username or UID (format: [:])
The `docker exec` command runs a new command in a running container.
@@ -1146,19 +1217,30 @@ This will create a new Bash session in the container `ubuntu_bash`.
Show the history of an image
+ -H, --human=true Print sizes and dates in human readable format
--no-trunc=false Don't truncate output
-q, --quiet=false Only show numeric IDs
To see how the `docker:latest` image was built:
$ docker history docker
- IMAGE CREATED CREATED BY SIZE
- 3e23a5875458790b7a806f95f7ec0d0b2a5c1659bfc899c89f939f6d5b8f7094 8 days ago /bin/sh -c #(nop) ENV LC_ALL=C.UTF-8 0 B
- 8578938dd17054dce7993d21de79e96a037400e8d28e15e7290fea4f65128a36 8 days ago /bin/sh -c dpkg-reconfigure locales && locale-gen C.UTF-8 && /usr/sbin/update-locale LANG=C.UTF-8 1.245 MB
- be51b77efb42f67a5e96437b3e102f81e0a1399038f77bf28cea0ed23a65cf60 8 days ago /bin/sh -c apt-get update && apt-get install -y git libxml2-dev python build-essential make gcc python-dev locales python-pip 338.3 MB
- 4b137612be55ca69776c7f30c2d2dd0aa2e7d72059820abf3e25b629f887a084 6 weeks ago /bin/sh -c #(nop) ADD jessie.tar.xz in / 121 MB
- 750d58736b4b6cc0f9a9abe8f258cef269e3e9dceced1146503522be9f985ada 6 weeks ago /bin/sh -c #(nop) MAINTAINER Tianon Gravi - mkimage-debootstrap.sh -t jessie.tar.xz jessie http://http.debian.net/debian 0 B
- 511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158 9 months ago 0 B
+ IMAGE CREATED CREATED BY SIZE COMMENT
+ 3e23a5875458 8 days ago /bin/sh -c #(nop) ENV LC_ALL=C.UTF-8 0 B
+ 8578938dd170 8 days ago /bin/sh -c dpkg-reconfigure locales && loc 1.245 MB
+ be51b77efb42 8 days ago /bin/sh -c apt-get update && apt-get install 338.3 MB
+ 4b137612be55 6 weeks ago /bin/sh -c #(nop) ADD jessie.tar.xz in / 121 MB
+ 750d58736b4b 6 weeks ago /bin/sh -c #(nop) MAINTAINER Tianon Gravi **Note**: A process running as PID 1 inside a container is treated
+>specially by Linux: it ignores any signal with the default action.
+>So, the process will not terminate on `SIGINT` or `SIGTERM` unless it is
+>coded to do so.
+
## Container identification
### Name (--name)
@@ -151,7 +156,7 @@ Images using the v2 or later image format have a content-addressable identifier
called a digest. As long as the input used to generate the image is unchanged,
the digest value is predictable and referenceable.
-## PID Settings (--pid)
+## PID settings (--pid)
--pid="" : Set the PID (Process) Namespace mode for the container,
'host': use the host's PID namespace inside the container
@@ -172,7 +177,7 @@ within the container.
This command would allow you to use `strace` inside the container on pid 1234 on
the host.
-## IPC Settings (--ipc)
+## IPC settings (--ipc)
--ipc="" : Set the IPC mode for the container,
'container:': reuses another container's IPC namespace
@@ -375,7 +380,7 @@ This means the daemon will wait for 100 ms, then 200 ms, 400, 800, 1600,
and so on until either the `on-failure` limit is hit, or when you `docker stop`
or `docker rm -f` the container.
-If a container is succesfully restarted (the container is started and runs
+If a container is successfully restarted (the container is started and runs
for at least 10 seconds), the delay is reset to its default value of 100 ms.
You can specify the maximum amount of times Docker will try to restart the
@@ -469,6 +474,8 @@ container:
-memory-swap="": Total memory limit (memory + swap, format: , where unit = b, k, m or g)
-c, --cpu-shares=0: CPU shares (relative weight)
--cpuset-cpus="": CPUs in which to allow execution (0-3, 0,1)
+ --cpuset-mems="": Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.
+ --cpu-quota=0: Limit the CPU CFS (Completely Fair Scheduler) quota
### Memory constraints
@@ -594,6 +601,30 @@ This means processes in container can be executed on cpu 1 and cpu 3.
This means processes in container can be executed on cpu 0, cpu 1 and cpu 2.
+We can set mems in which to allow execution for containers. Only effective
+on NUMA systems.
+
+Examples:
+
+ $ docker run -ti --cpuset-mems="1,3" ubuntu:14.04 /bin/bash
+
+This example restricts the processes in the container to only use memory from
+memory nodes 1 and 3.
+
+ $ docker run -ti --cpuset-mems="0-2" ubuntu:14.04 /bin/bash
+
+This example restricts the processes in the container to only use memory from
+memory nodes 0, 1 and 2.
+
+### CPU quota constraint
+
+The `--cpu-quota` flag limits the container's CPU usage. The default 0 value
+allows the container to take 100% of a CPU resource (1 CPU). The CFS (Completely Fair
+Scheduler) handles resource allocation for executing processes and is default
+Linux Scheduler used by the kernel. Set this value to 50000 to limit the container
+to 50% of a CPU resource. For multiple CPUs, adjust the `--cpu-quota` as necessary.
+For more information, see the [CFS documentation on bandwidth limiting](https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt).
+
## Runtime privilege, Linux capabilities, and LXC configuration
--cap-add: Add Linux capabilities
@@ -757,6 +788,10 @@ command is available only for this logging driver
Syslog logging driver for Docker. Writes log messages to syslog. `docker logs`
command is not available for this logging driver
+#### Logging driver: journald
+
+Journald logging driver for Docker. Writes log messages to journald. `docker logs` command is not available for this logging driver
+
## Overriding Dockerfile image defaults
When a developer builds an image from a [*Dockerfile*](/reference/builder)
diff --git a/docs/sources/release-notes.md b/docs/sources/release-notes.md
index fe79d881dc986..1a32cbb98073e 100644
--- a/docs/sources/release-notes.md
+++ b/docs/sources/release-notes.md
@@ -1,75 +1,133 @@
-page_title: Docker 1.x Series Release Notes
-page_description: Release Notes for Docker 1.x.
+page_title: Docker 1.x series release notes
+page_description: Release notes for Docker 1.x.
page_keywords: docker, documentation, about, technology, understanding, release
-# Release Notes
+# Release notes version 1.6.0
+(2015-04-16)
You can view release notes for earlier version of Docker by selecting the
-desired version from the drop-down list at the top right of this page.
-
-## Version 1.5.0
-(2015-02-03)
-
-For a complete list of patches, fixes, and other improvements, see the
-[merge PR on GitHub](https://github.com/docker/docker/pull/10286).
-
-*New Features*
-
-* [1.6] The Docker daemon will no longer ignore unknown commands
- while processing a `Dockerfile`. Instead it will generate an error and halt
- processing.
-* The Docker daemon has now supports for IPv6 networking between containers
- and on the `docker0` bridge. For more information see the
- [IPv6 networking reference](/articles/networking/#ipv6).
-* Docker container filesystems can now be set to`--read-only`, restricting your
- container to writing to volumes [PR# 10093](https://github.com/docker/docker/pull/10093).
-* A new `docker stats CONTAINERID` command has been added to allow users to view a
- continuously updating stream of container resource usage statistics. See the
- [`stats` command line reference](/reference/commandline/cli/#stats) and the
- [container `stats` API reference](/reference/api/docker_remote_api_v1.17/#get-container-stats-based-on-resource-usage).
- **Note**: this feature is only enabled for the `libcontainer` exec-driver at this point.
-* Users can now specify the file to use as the `Dockerfile` by running
- `docker build -f alternate.dockerfile .`. This will allow the definition of multiple
- `Dockerfile`s for a single project. See the [`docker build` command reference](
-/reference/commandline/cli/#build) for more information.
-* The v1 Open Image specification has been created to document the current Docker image
- format and metadata. Please see [the Open Image specification document](
-https://github.com/docker/docker/blob/master/image/spec/v1.md) for more details.
-* This release also includes a number of significant performance improvements in
- build and image management ([PR #9720](https://github.com/docker/docker/pull/9720),
- [PR #8827](https://github.com/docker/docker/pull/8827))
-* The `docker inspect` command now lists ExecIDs generated for each `docker exec` process.
- See [PR #9800](https://github.com/docker/docker/pull/9800)) for more details.
-* The `docker inspect` command now shows the number of container restarts when there
- is a restart policy ([PR #9621](https://github.com/docker/docker/pull/9621))
-* This version of Docker is built using Go 1.4
-
-> **Note:**
-> Development history prior to version 1.0 can be found by
-> searching in the [Docker GitHub repo](https://github.com/docker/docker).
-
-## Known Issues
-
-This section lists significant known issues present in Docker as of release
-date. It is not exhaustive; it lists only issues with potentially significant
-impact on users. This list will be updated as issues are resolved.
-
-* **Unexpected File Permissions in Containers**
-An idiosyncrasy in AUFS prevents permissions from propagating predictably
-between upper and lower layers. This can cause issues with accessing private
-keys, database instances, etc.
-
-For systems that have recent aufs version (i.e., `dirperm1` mount option can
-be set), docker will attempt to fix the issue automatically by mounting
-the layers with `dirperm1` option. More details on `dirperm1` option can be
-found at [`aufs` man page](http://aufs.sourceforge.net/aufs3/man.html)
-
-For complete information and workarounds see
+desired version from the drop-down list at the top right of this page. For the
+formal release announcement, see [the Docker
+blog](https://blog.docker.com/2015/04/docker-release-1-6/).
+
+
+
+## Docker Engine 1.6.0 features
+
+For a complete list of engine patches, fixes, and other improvements, see the
+[merge PR on GitHub](https://github.com/docker/docker/pull/11635). You'll also
+find [a changelog in the project
+repository](https://github.com/docker/docker/blob/master/CHANGELOG.md).
+
+
+| Feature | Description |
+|------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Container and Image Labels | Labels allow you to attach user-defined metadata to containers and images that can be used by your tools. For additional information on using labels, see [Apply custom metadata](http://docs.docker.com/userguide/labels-custom-metadata/#add-labels-to-images-the-label-instruction) in the documentation. |
+| Windows Client preview | The Windows Client can be used just like the Mac OS X client is today with a remote host. Our testing infrastructure was scaled out to accommodate Windows Client testing on every PR to the Engine. See the Azure blog for [details on using this new client](http://azure.microsoft.com/blog/2015/04/16/docker-client-for-windows-is-now-available). |
+| Logging drivers | The new logging driver follows the exec driver and storage driver concepts already available in Engine today. There is a new option `--log-driver` to `docker run` command. See the `run` reference for a [description on how to use this option](http://docs.docker.com/reference/run/#logging-drivers-log-driver). |
+| Image digests | When you pull, build, or run images, you specify them in the form `namespace/repository:tag`, or even just `repository`. In this release, you are now able to pull, run, build and refer to images by a new content addressable identifier called a “digest” with the syntax `namespace/repo@digest`. See the the command line reference for [examples of using the digest](http://docs.docker.com/reference/commandline/cli/#listing-image-digests). |
+| Custom cgroups | Containers are made from a combination of namespaces, capabilities, and cgroups. Docker already supports custom namespaces and capabilities. Additionally, in this release we’ve added support for custom cgroups. Using the `--cgroup-parent` flag, you can pass a specific `cgroup` to run a container in. See [the command line reference for more information](http://docs.docker.com/reference/commandline/cli/#create). |
+| Ulimits | You can now specify the default `ulimit` settings for all containers when configuring the daemon. For example:`docker -d --default-ulimit nproc=1024:2048` See [Default Ulimits](http://docs.docker.com/reference/commandline/cli/#default-ulimits) in this documentation. |
+| Commit and import Dockerfile | You can now make changes to images on the fly without having to re-build the entire image. The feature `commit --change` and `import --change` allows you to apply standard changes to a new image. These are expressed in the Dockerfile syntax and used to modify the image. For details on how to use these, see the [commit](http://docs.docker.com/reference/commandline/cli/#commit) and [import](http://docs.docker.com/reference/commandline/cli/#import). |
+
+### Known issues in Engine
+
+This section lists significant known issues present in Docker as of release date.
+For an exhaustive list of issues, see [the issues list on the project
+repository](https://github.com/docker/docker/issues/).
+
+* *Unexpected File Permissions in Containers*
+An idiosyncrasy in AUFS prevented permissions from propagating predictably
+between upper and lower layers. This caused issues with accessing private
+keys, database instances, etc. This issue was closed in this release:
[Github Issue 783](https://github.com/docker/docker/issues/783).
-* **Docker Hub incompatible with Safari 8**
-Docker Hub has multiple issues displaying on Safari 8, the default browser
-for OS X 10.10 (Yosemite). Users should access the hub using a different
-browser. Most notably, changes in the way Safari handles cookies means that the
-user is repeatedly logged out. For more information, see the [Docker
-forum post](https://forums.docker.com/t/new-safari-in-yosemite-issue/300).
+
+* *Docker Hub incompatible with Safari 8*
+Docker Hub had multiple issues displaying on Safari 8, the default browser for
+OS X 10.10 (Yosemite). Most notably, changes in the way Safari handled cookies
+means that the user was repeatedly logged out.
+Recently, Safari fixed the bug that was causing all the issues. If you upgrade
+to Safari 8.0.5 which was just released last week and see if that fixes your
+issues. You might have to flush your cookies if it doesn't work right away.
+For more information, see the [Docker forum
+post](https://forums.docker.com/t/new-safari-in-yosemite-issue/300).
+
+## Docker Registry 2.0 features
+
+This release includes Registry 2.0. The Docker Registry is a central server for
+pushing and pulling images. In this release, it was completely rewritten in Go
+around a new set of distribution APIs
+
+- **Webhook notifications**: You can now configure the Registry to send Webhooks
+when images are pushed. Spin off a CI build, send a notification to IRC –
+whatever you want! Included in the documentation is a detailed [notification
+specification](http://docs.docker.com/registry/notifications/).
+
+- **Native TLS support**: This release makes it easier to secure a registry with
+TLS. This documentation includes [expanded examples of secure
+deployments](http://docs.docker.com/registry/deploying/).
+
+- **New Distribution APIs**: This release includes an expanded set of new
+distribution APIs. You can read the [detailed specification
+here](http://docs.docker.com/registry/spec/api/).
+
+
+## Docker Compose 1.2
+
+For a complete list of compose patches, fixes, and other improvements, see the
+[changelog in the project
+repository](https://github.com/docker/compose/blob/master/CHANGES.md). The
+project also makes a [set of release
+notes](https://github.com/docker/compose/releases/tag/1.2.0) on the project.
+
+- **extends**: You can use `extends` to share configuration between services
+with the keyword “extends”. With extends, you can refer to a service defined
+elsewhere and include its configuration in a locally-defined service, while also
+adding or overriding configuration as necessary. The documentation describes
+[how to use extends in your
+configuration](http://docs.docker.com/compose/extends/#extending-services-in-
+compose).
+
+- **Relative directory handling may cause breaking change**: Compose now treats
+directories passed to build, filenames passed to `env_file` and volume host
+paths passed to volumes as relative to the configuration file's directory.
+Previously, they were treated as relative to the directory where you were
+running `docker-compose`. In the majority of cases, the location of the
+configuration file and where you ran `docker-compose` were the same directory.
+Now, you can use the `-f|--file` argument to specify a configuration file in
+another directory.
+
+
+## Docker Swarm 0.2
+
+You'll find the [release for download on
+GitHub](https://github.com/docker/swarm/releases/tag/v0.2.0) and [the
+documentation here](http://docs.docker.com/swarm/). This release includes the
+following features:
+
+- **Spread strategy**: A new strategy for scheduling containers on your cluster
+which evenly spreads them over available nodes.
+- **More Docker commands supported**: More progress has been made towards
+supporting the complete Docker API, such as pulling and inspecting images.
+- **Clustering drivers**: There are not any third-party drivers yet, but the
+first steps have been made towards making a pluggable driver interface that will
+make it possible to use Swarm with clustering systems such as Mesos.
+
+
+## Docker Machine 0.2 Pre-release
+
+You'll find the [release for download on
+GitHub](https://github.com/docker/machine/releases) and [the documentation
+here](http://docs.docker.com/machine/). For a complete list of machine changes
+see [the changelog in the project
+repository](https://github.com/docker/machine/blob/master/CHANGES.md#020-2015-03
+-22).
+
+- **Cleaner driver interface**: It is now much easier to write drivers for providers.
+- **More reliable and consistent provisioning**: Provisioning servers is now
+handled centrally by Machine instead of letting each driver individually do it.
+- **Regenerate TLS certificates**: A new command has been added to regenerate a
+host’s TLS certificates for good security practice and for if a host’s IP
+address changes.
+
diff --git a/docs/sources/terms/container.md b/docs/sources/terms/container.md
index 8b42868788eef..d0c31c2455058 100644
--- a/docs/sources/terms/container.md
+++ b/docs/sources/terms/container.md
@@ -17,7 +17,7 @@ Image*](/terms/image)
and some additional information like its unique id, networking
configuration, and resource limits is called a **container**.
-## Container State
+## Container state
Containers can change, and so they have state. A container may be
**running** or **exited**.
diff --git a/docs/sources/terms/filesystem.md b/docs/sources/terms/filesystem.md
index 5587e3c83179d..814246d8b998f 100644
--- a/docs/sources/terms/filesystem.md
+++ b/docs/sources/terms/filesystem.md
@@ -1,8 +1,8 @@
-page_title: File Systems
+page_title: File system
page_description: How Linux organizes its persistent storage
page_keywords: containers, files, linux
-# File System
+# File system
## Introduction
diff --git a/docs/sources/terms/image.md b/docs/sources/terms/image.md
index e42a6cfa12162..0a11d91c9ec90 100644
--- a/docs/sources/terms/image.md
+++ b/docs/sources/terms/image.md
@@ -1,4 +1,4 @@
-page_title: Images
+page_title: Image
page_description: Definition of an image
page_keywords: containers, lxc, concepts, explanation, image, container
@@ -19,7 +19,7 @@ images do not have state.
![](/terms/images/docker-filesystems-debianrw.png)
-## Parent Image
+## Parent image
![](/terms/images/docker-filesystems-multilayer.png)
@@ -27,7 +27,7 @@ Each image may depend on one more image which forms the layer beneath
it. We sometimes say that the lower image is the **parent** of the upper
image.
-## Base Image
+## Base image
An image that has no parent is a **base image**.
diff --git a/docs/sources/terms/registry.md b/docs/sources/terms/registry.md
index 68120812c37ea..ad5a81d640600 100644
--- a/docs/sources/terms/registry.md
+++ b/docs/sources/terms/registry.md
@@ -14,7 +14,7 @@ The default registry can be accessed using a browser at
[Docker Hub](https://hub.docker.com) or using the
`docker search` command.
-## Further Reading
+## Further reading
For more information see [*Working with
Repositories*](/userguide/dockerrepos/#working-with-the-repository)
diff --git a/docs/sources/terms/repository.md b/docs/sources/terms/repository.md
index 84963b4bf94a1..4b8579924fbf3 100644
--- a/docs/sources/terms/repository.md
+++ b/docs/sources/terms/repository.md
@@ -29,7 +29,7 @@ A Fully Qualified Image Name (FQIN) can be made up of 3 parts:
If you create a new repository which you want to share, you will need to
set at least the `user_name`, as the `default` blank `user_name` prefix is
-reserved for official Docker images.
+reserved for [Official Repositories](/docker-hub/official_repos).
For more information see [*Working with
Repositories*](/userguide/dockerrepos/#working-with-the-repository)
diff --git a/docs/sources/userguide/dockerhub.md b/docs/sources/userguide/dockerhub.md
index 3d4007d3025c9..2f7170d64f9f0 100644
--- a/docs/sources/userguide/dockerhub.md
+++ b/docs/sources/userguide/dockerhub.md
@@ -2,7 +2,7 @@ page_title: Getting started with Docker Hub
page_description: Introductory guide to getting an account on Docker Hub
page_keywords: documentation, docs, the docker guide, docker guide, docker, docker platform, virtualization framework, docker.io, central service, services, how to, container, containers, automation, collaboration, collaborators, registry, repo, repository, technology, github webhooks, trusted builds
-# Getting Started with Docker Hub
+# Getting started with Docker Hub
This section provides a quick introduction to the [Docker Hub](https://hub.docker.com),
@@ -21,7 +21,7 @@ most out of Docker. To do this, it provides services such as:
In order to use Docker Hub, you will first need to register and create an account. Don't
worry, creating an account is simple and free.
-## Creating a Docker Hub Account
+## Creating a Docker Hub account
There are two ways for you to register and create an account:
diff --git a/docs/sources/userguide/dockerimages.md b/docs/sources/userguide/dockerimages.md
index f97231506e3f1..c29b01032c94b 100644
--- a/docs/sources/userguide/dockerimages.md
+++ b/docs/sources/userguide/dockerimages.md
@@ -1,8 +1,8 @@
-page_title: Working with Docker Images
+page_title: Working with Docker images
page_description: How to work with Docker images.
page_keywords: documentation, docs, the docker guide, docker guide, docker, docker platform, virtualization framework, docker.io, Docker images, Docker image, image management, Docker repos, Docker repositories, docker, docker tag, docker tags, Docker Hub, collaboration
-# Working with Docker Images
+# Working with Docker images
In the [introduction](/introduction/understanding-docker/) we've discovered that Docker
images are the basis of containers. In the
@@ -131,11 +131,11 @@ term `sinatra`.
We can see we've returned a lot of images that use the term `sinatra`. We've
returned a list of image names, descriptions, Stars (which measure the social
popularity of images - if a user likes an image then they can "star" it), and
-the Official and Automated build statuses. Official repositories are built and
-maintained by the [Stackbrew](https://github.com/docker/stackbrew) project,
-and Automated repositories are [Automated Builds](
-/userguide/dockerrepos/#automated-builds) that allow you to validate the source
-and content of an image.
+the Official and Automated build statuses.
+[Official Repositories](/docker-hub/official_repos) are a carefully curated set
+of Docker repositories supported by Docker, Inc. Automated repositories are
+[Automated Builds](/userguide/dockerrepos/#automated-builds) that allow you to
+validate the source and content of an image.
We've reviewed the images available to use and we decided to use the
`training/sinatra` image. So far we've seen two types of images repositories,
@@ -505,6 +505,25 @@ Let's see our new tag using the `docker images` command.
ouruser/sinatra devel 5db5f8471261 11 hours ago 446.7 MB
ouruser/sinatra v2 5db5f8471261 11 hours ago 446.7 MB
+## Image Digests
+
+Images that use the v2 or later format have a content-addressable identifier
+called a `digest`. As long as the input used to generate the image is
+unchanged, the digest value is predictable. To list image digest values, use
+the `--digests` flag:
+
+ $ docker images --digests | head
+ REPOSITORY TAG DIGEST IMAGE ID CREATED VIRTUAL SIZE
+ ouruser/sinatra latest sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf 5db5f8471261 11 hours ago 446.7 MB
+
+When pushing or pulling to a 2.0 registry, the `push` or `pull` command
+output includes the image digest. You can `pull` using a digest value.
+
+ $ docker pull ouruser/sinatra@cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf
+
+You can also reference by digest in `create`, `run`, and `rmi` commands, as well as the
+`FROM` image reference in a Dockerfile.
+
## Push an image to Docker Hub
Once you've built or created a new image you can push it to [Docker
diff --git a/docs/sources/userguide/dockerizing.md b/docs/sources/userguide/dockerizing.md
index 5896dd78e0a1f..7124ba6c9ca1c 100644
--- a/docs/sources/userguide/dockerizing.md
+++ b/docs/sources/userguide/dockerizing.md
@@ -1,8 +1,8 @@
-page_title: Dockerizing Applications: A "Hello world"
+page_title: Dockerizing applications: A "Hello world"
page_description: A simple "Hello world" exercise that introduced you to Docker.
page_keywords: docker guide, docker, docker platform, virtualization framework, how to, dockerize, dockerizing apps, dockerizing applications, container, containers
-# Dockerizing Applications: A "Hello world"
+# Dockerizing applications: A "Hello world"
*So what's this Docker thing all about?*
@@ -48,7 +48,7 @@ So what happened to our container after that? Well Docker containers
only run as long as the command you specify is active. Here, as soon as
`Hello world` was echoed, the container stopped.
-## An Interactive Container
+## An interactive container
Let's try the `docker run` command again, this time specifying a new
command to run in our container.
@@ -90,7 +90,7 @@ use the `exit` command or enter Ctrl-D to finish.
As with our previous container, once the Bash shell process has
finished, the container is stopped.
-## A Daemonized Hello world
+## A daemonized Hello world
Now a container that runs a command and then exits has some uses but
it's not overly helpful. Let's create a container that runs as a daemon,
diff --git a/docs/sources/userguide/dockerlinks.md b/docs/sources/userguide/dockerlinks.md
index 66dd3d7a4ee67..8a20388463cfd 100644
--- a/docs/sources/userguide/dockerlinks.md
+++ b/docs/sources/userguide/dockerlinks.md
@@ -1,8 +1,8 @@
-page_title: Linking Containers Together
+page_title: Linking containers together
page_description: Learn how to connect Docker containers together.
page_keywords: Examples, Usage, user guide, links, linking, docker, documentation, examples, names, name, container naming, port, map, network port, network
-# Linking Containers Together
+# Linking containers together
In [the Using Docker section](/userguide/usingdocker), you saw how you can
connect to a service running inside a Docker container via a network
@@ -11,7 +11,7 @@ applications running inside Docker containers. In this section, we'll briefly re
connecting via a network port and then we'll introduce you to another method of access:
container linking.
-## Connect using Network port mapping
+## Connect using network port mapping
In [the Using Docker section](/userguide/usingdocker), you created a
container that ran a Python Flask application:
@@ -175,7 +175,7 @@ recipient container in two ways:
* Environment variables,
* Updating the `/etc/hosts` file.
-### Environment Variables
+### Environment variables
Docker creates several environment variables when you link containers. Docker
automatically creates environment variables in the target container based on
diff --git a/docs/sources/userguide/dockerrepos.md b/docs/sources/userguide/dockerrepos.md
index a8a1800f5129b..8fc2ba637fdfb 100644
--- a/docs/sources/userguide/dockerrepos.md
+++ b/docs/sources/userguide/dockerrepos.md
@@ -51,12 +51,12 @@ name, user name, or description:
tianon/centos CentOS 5 and 6, created using rinse instea... 21
...
-There you can see two example results: `centos` and
-`tianon/centos`. The second result shows that it comes from
-the public repository of a user, named `tianon/`, while the first result,
-`centos`, doesn't explicitly list a repository which means that it comes from the
-trusted top-level namespace. The `/` character separates a user's
-repository from the image name.
+There you can see two example results: `centos` and `tianon/centos`. The second
+result shows that it comes from the public repository of a user, named
+`tianon/`, while the first result, `centos`, doesn't explicitly list a
+repository which means that it comes from the trusted top-level namespace for
+[Official Repositories](/docker-hub/official_repos). The `/` character separates
+a user's repository from the image name.
Once you've found the image you want, you can download it with `docker pull `:
@@ -101,7 +101,7 @@ information [here](http://docs.docker.com/docker-hub/).
* Automated Builds
* Webhooks
-### Private Repositories
+### Private repositories
Sometimes you have images you don't want to make public and share with
everyone. So Docker Hub allows you to have private repositories. You can
@@ -150,7 +150,7 @@ repository.
You can create multiple Automated Builds per repository and configure them
to point to specific `Dockerfile`'s or Git branches.
-#### Build Triggers
+#### Build triggers
Automated Builds can also be triggered via a URL on Docker Hub. This
allows you to rebuild an Automated build image on demand.
diff --git a/docs/sources/userguide/dockervolumes.md b/docs/sources/userguide/dockervolumes.md
index c319ecee5cdf9..c7126d7c33796 100644
--- a/docs/sources/userguide/dockervolumes.md
+++ b/docs/sources/userguide/dockervolumes.md
@@ -1,8 +1,8 @@
-page_title: Managing Data in Containers
+page_title: Managing data in containers
page_description: How to manage data inside your Docker containers.
page_keywords: Examples, Usage, volume, docker, documentation, user guide, data, volumes
-# Managing Data in Containers
+# Managing data in containers
So far we've been introduced to some [basic Docker
concepts](/userguide/usingdocker/), seen how to work with [Docker
@@ -25,8 +25,8 @@ System*](/terms/layer/#union-file-system). Data volumes provide several
useful features for persistent or shared data:
- Volumes are initialized when a container is created. If the container's
- base image contains data at the specified mount point, that data is
- copied into the new volume.
+ base image contains data at the specified mount point, that existing data is
+ copied into the new volume upon volume initialization.
- Data volumes can be shared and reused among containers.
- Changes to a data volume are made directly.
- Changes to a data volume will not be included when you update an image.
@@ -73,7 +73,7 @@ volumes. The output should look something similar to the following:
You will notice in the above 'Volumes' is specifying the location on the host and
'VolumesRW' is specifying that the volume is read/write.
-### Mount a Host Directory as a Data Volume
+### Mount a host directory as a data volume
In addition to creating a volume using the `-v` flag you can also mount a
directory from your Docker daemon's host into a container.
@@ -116,7 +116,7 @@ read-only.
Here we've mounted the same `/src/webapp` directory but we've added the `ro`
option to specify that the mount should be read-only.
-### Mount a Host File as a Data Volume
+### Mount a host file as a data volume
The `-v` flag can also be used to mount a single file - instead of *just*
directories - from the host machine.
@@ -134,7 +134,7 @@ history of the commands typed while in the container.
> you want to edit the mounted file, it is often easiest to instead mount the
> parent directory.
-## Creating and mounting a Data Volume Container
+## Creating and mounting a data volume container
If you have some persistent data that you want to share between
containers, or want to use from non-persistent containers, it's best to
diff --git a/docs/sources/userguide/index.md b/docs/sources/userguide/index.md
index d0dbdb84ee199..9cc1c6db30312 100644
--- a/docs/sources/userguide/index.md
+++ b/docs/sources/userguide/index.md
@@ -1,8 +1,8 @@
-page_title: The Docker User Guide
-page_description: The Docker User Guide home page
+page_title: The Docker user guide
+page_description: The Docker user guide home page
page_keywords: docker, introduction, documentation, about, technology, docker.io, user, guide, user's, manual, platform, framework, virtualization, home, intro
-# Welcome to the Docker User Guide
+# Welcome to the Docker user guide
In the [Introduction](/) you got a taste of what Docker is and how it
works. In this guide we're going to take you through the fundamentals of
@@ -19,7 +19,7 @@ We’ll teach you how to use Docker to:
We've broken this guide into major sections that take you through
the Docker life cycle:
-## Getting Started with Docker Hub
+## Getting started with Docker Hub
*How do I use Docker Hub?*
@@ -29,7 +29,7 @@ environment. To learn more:
Go to [Using Docker Hub](/userguide/dockerhub).
-## Dockerizing Applications: A "Hello world"
+## Dockerizing applications: A "Hello world"
*How do I run applications inside containers?*
@@ -38,7 +38,7 @@ applications. To learn how to Dockerize applications and run them:
Go to [Dockerizing Applications](/userguide/dockerizing).
-## Working with Containers
+## Working with containers
*How do I manage my containers?*
@@ -48,7 +48,7 @@ about how to inspect, monitor and manage containers:
Go to [Working With Containers](/userguide/usingdocker).
-## Working with Docker Images
+## Working with Docker images
*How can I access, share and build my own images?*
@@ -57,7 +57,7 @@ learn how to build your own application images with Docker.
Go to [Working with Docker Images](/userguide/dockerimages).
-## Linking Containers Together
+## Linking containers together
Until now we've seen how to build individual applications inside Docker
containers. Now learn how to build whole application stacks with Docker
@@ -65,7 +65,7 @@ by linking together multiple Docker containers.
Go to [Linking Containers Together](/userguide/dockerlinks).
-## Managing Data in Containers
+## Managing data in containers
Now we know how to link Docker containers together the next step is
learning how to manage data, volumes and mounts inside our containers.
diff --git a/docs/sources/userguide/level1.md b/docs/sources/userguide/level1.md
index cca77dc36291d..320fbfee01be3 100644
--- a/docs/sources/userguide/level1.md
+++ b/docs/sources/userguide/level1.md
@@ -1,10 +1,10 @@
-page_title: Docker Images Test
+page_title: Docker images test
page_description: How to work with Docker images.
page_keywords: documentation, docs, the docker guide, docker guide, docker, docker platform, virtualization framework, docker.io, Docker images, Docker image, image management, Docker repos, Docker repositories, docker, docker tag, docker tags, Docker Hub, collaboration
Back
-# Dockerfile Tutorial
+# Dockerfile tutorial
## Test your Dockerfile knowledge - Level 1
diff --git a/docs/sources/userguide/level2.md b/docs/sources/userguide/level2.md
index fe6654e71f034..96e91a1c6c743 100644
--- a/docs/sources/userguide/level2.md
+++ b/docs/sources/userguide/level2.md
@@ -1,10 +1,10 @@
-page_title: Docker Images Test
+page_title: Docker images test
page_description: How to work with Docker images.
page_keywords: documentation, docs, the docker guide, docker guide, docker, docker platform, virtualization framework, docker.io, Docker images, Docker image, image management, Docker repos, Docker repositories, docker, docker tag, docker tags, Docker Hub, collaboration
Back
-#Dockerfile Tutorial
+#Dockerfile tutorial
## Test your Dockerfile knowledge - Level 2
diff --git a/docs/sources/userguide/usingdocker.md b/docs/sources/userguide/usingdocker.md
index 70996a21004b7..e33ca717d67a6 100644
--- a/docs/sources/userguide/usingdocker.md
+++ b/docs/sources/userguide/usingdocker.md
@@ -1,8 +1,8 @@
-page_title: Working with Containers
+page_title: Working with containers
page_description: Learn how to manage and operate Docker containers.
page_keywords: docker, the docker guide, documentation, docker.io, monitoring containers, docker top, docker inspect, docker port, ports, docker logs, log, Logs
-# Working with Containers
+# Working with containers
In the [last section of the Docker User Guide](/userguide/dockerizing)
we launched our first containers. We launched two containers using the
@@ -91,7 +91,7 @@ This will display the help text and all available flags:
> You can see a full list of Docker's commands
> [here](/reference/commandline/cli/).
-## Running a Web Application in Docker
+## Running a web application in Docker
So now we've learnt a bit more about the `docker` client let's move onto
the important stuff: running more containers. So far none of the
@@ -121,7 +121,7 @@ Lastly, we've specified a command for our container to run: `python app.py`. Thi
> reference](/reference/commandline/cli/#run) and the [Docker Run
> Reference](/reference/run/).
-## Viewing our Web Application Container
+## Viewing our web application container
Now let's see our running container using the `docker ps` command.
@@ -189,7 +189,7 @@ Our Python application is live!
>
> In this case you'd browse to http://192.168.59.103:49155 for the above example.
-## A Network Port Shortcut
+## A network port shortcut
Using the `docker ps` command to return the mapped port is a bit clumsy so
Docker has a useful shortcut we can use: `docker port`. To use `docker port` we
@@ -202,7 +202,7 @@ corresponding public-facing port.
In this case we've looked up what port is mapped externally to port 5000 inside
the container.
-## Viewing the Web Application's Logs
+## Viewing the web application's logs
Let's also find out a bit more about what's happening with our application and
use another of the commands we've learnt, `docker logs`.
@@ -217,7 +217,7 @@ logs` command to act like the `tail -f` command and watch the
container's standard out. We can see here the logs from Flask showing
the application running on port 5000 and the access log entries for it.
-## Looking at our Web Application Container's processes
+## Looking at our web application container's processes
In addition to the container's logs we can also examine the processes
running inside it using the `docker top` command.
@@ -229,7 +229,7 @@ running inside it using the `docker top` command.
Here we can see our `python app.py` command is the only process running inside
the container.
-## Inspecting our Web Application Container
+## Inspecting our web application container
Lastly, we can take a low-level dive into our Docker container using the
`docker inspect` command. It returns a JSON hash of useful configuration
@@ -258,7 +258,7 @@ specific element, for example to return the container's IP address we would:
$ docker inspect -f '{{ .NetworkSettings.IPAddress }}' nostalgic_morse
172.17.0.5
-## Stopping our Web Application Container
+## Stopping our web application container
Okay we've seen web application working. Now let's stop it using the
`docker stop` command and the name of our container: `nostalgic_morse`.
@@ -271,7 +271,7 @@ been stopped.
$ docker ps -l
-## Restarting our Web Application Container
+## Restarting our web application container
Oops! Just after you stopped the container you get a call to say another
developer needs the container back. From here you have two choices: you
@@ -289,7 +289,7 @@ responds.
> Also available is the `docker restart` command that runs a stop and
> then start on the container.
-## Removing our Web Application Container
+## Removing our web application container
Your colleague has let you know that they've now finished with the container
and won't need it again. So let's remove it using the `docker rm` command.
diff --git a/engine/engine.go b/engine/engine.go
index 1090675dfa557..79fae51cc3848 100644
--- a/engine/engine.go
+++ b/engine/engine.go
@@ -11,7 +11,7 @@ import (
"time"
"github.com/docker/docker/pkg/ioutils"
- "github.com/docker/docker/pkg/stringutils"
+ "github.com/docker/docker/pkg/stringid"
)
// Installer is a standard interface for objects which can "install" themselves
@@ -78,7 +78,7 @@ func (eng *Engine) RegisterCatchall(catchall Handler) {
func New() *Engine {
eng := &Engine{
handlers: make(map[string]Handler),
- id: stringutils.GenerateRandomString(),
+ id: stringid.GenerateRandomID(),
Stdout: os.Stdout,
Stderr: os.Stderr,
Stdin: os.Stdin,
diff --git a/engine/env.go b/engine/env.go
index c6c673271e9f0..107ae4a0d9160 100644
--- a/engine/env.go
+++ b/engine/env.go
@@ -9,7 +9,7 @@ import (
"strings"
"time"
- "github.com/docker/docker/utils"
+ "github.com/docker/docker/pkg/ioutils"
)
type Env []string
@@ -210,7 +210,7 @@ func (env *Env) SetAuto(k string, v interface{}) {
// FIXME: we fix-convert float values to int, because
// encoding/json decodes integers to float64, but cannot encode them back.
- // (See http://golang.org/src/pkg/encoding/json/decode.go#L46)
+ // (See https://golang.org/src/pkg/encoding/json/decode.go#L46)
if fval, ok := v.(float64); ok {
env.SetInt64(k, int64(fval))
} else if sval, ok := v.(string); ok {
@@ -245,7 +245,7 @@ func (env *Env) Encode(dst io.Writer) error {
if err := json.Unmarshal([]byte(v), &val); err == nil {
// FIXME: we fix-convert float values to int, because
// encoding/json decodes integers to float64, but cannot encode them back.
- // (See http://golang.org/src/pkg/encoding/json/decode.go#L46)
+ // (See https://golang.org/src/pkg/encoding/json/decode.go#L46)
m[k] = changeFloats(val)
} else {
m[k] = v
@@ -258,7 +258,7 @@ func (env *Env) Encode(dst io.Writer) error {
}
func (env *Env) WriteTo(dst io.Writer) (int64, error) {
- wc := utils.NewWriteCounter(dst)
+ wc := ioutils.NewWriteCounter(dst)
err := env.Encode(wc)
return wc.Count, err
}
diff --git a/engine/shutdown_test.go b/engine/shutdown_test.go
index cde177e398d6f..d2ef0339de399 100644
--- a/engine/shutdown_test.go
+++ b/engine/shutdown_test.go
@@ -18,9 +18,7 @@ func TestShutdownEmpty(t *testing.T) {
func TestShutdownAfterRun(t *testing.T) {
eng := New()
- var called bool
eng.Register("foo", func(job *Job) error {
- called = true
return nil
})
if err := eng.Job("foo").Run(); err != nil {
diff --git a/engine/streams_test.go b/engine/streams_test.go
index 476a721baf71e..c22338a32e752 100644
--- a/engine/streams_test.go
+++ b/engine/streams_test.go
@@ -182,7 +182,7 @@ func TestInputAddEmpty(t *testing.T) {
t.Fatal(err)
}
if len(data) > 0 {
- t.Fatalf("Read from empty input shoul yield no data")
+ t.Fatalf("Read from empty input should yield no data")
}
}
diff --git a/graph/export.go b/graph/export.go
index f689ba10efbe0..ae061a8a0fdc8 100644
--- a/graph/export.go
+++ b/graph/export.go
@@ -2,14 +2,12 @@ package graph
import (
"encoding/json"
- "fmt"
"io"
"io/ioutil"
"os"
"path"
"github.com/Sirupsen/logrus"
- "github.com/docker/docker/engine"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/registry"
@@ -20,10 +18,13 @@ import (
// uncompressed tar ball.
// name is the set of tags to export.
// out is the writer where the images are written to.
-func (s *TagStore) CmdImageExport(job *engine.Job) error {
- if len(job.Args) < 1 {
- return fmt.Errorf("Usage: %s IMAGE [IMAGE...]\n", job.Name)
- }
+type ImageExportConfig struct {
+ Names []string
+ Outstream io.Writer
+}
+
+func (s *TagStore) ImageExport(imageExportConfig *ImageExportConfig) error {
+
// get image json
tempdir, err := ioutil.TempDir("", "docker-export-")
if err != nil {
@@ -40,7 +41,7 @@ func (s *TagStore) CmdImageExport(job *engine.Job) error {
repo[tag] = id
}
}
- for _, name := range job.Args {
+ for _, name := range imageExportConfig.Names {
name = registry.NormalizeLocalName(name)
logrus.Debugf("Serializing %s", name)
rootRepo := s.Repositories[name]
@@ -48,7 +49,7 @@ func (s *TagStore) CmdImageExport(job *engine.Job) error {
// this is a base repo name, like 'busybox'
for tag, id := range rootRepo {
addKey(name, tag, id)
- if err := s.exportImage(job.Eng, id, tempdir); err != nil {
+ if err := s.exportImage(id, tempdir); err != nil {
return err
}
}
@@ -67,13 +68,13 @@ func (s *TagStore) CmdImageExport(job *engine.Job) error {
if len(repoTag) > 0 {
addKey(repoName, repoTag, img.ID)
}
- if err := s.exportImage(job.Eng, img.ID, tempdir); err != nil {
+ if err := s.exportImage(img.ID, tempdir); err != nil {
return err
}
} else {
// this must be an ID that didn't get looked up just right?
- if err := s.exportImage(job.Eng, name, tempdir); err != nil {
+ if err := s.exportImage(name, tempdir); err != nil {
return err
}
}
@@ -82,8 +83,15 @@ func (s *TagStore) CmdImageExport(job *engine.Job) error {
}
// write repositories, if there is something to write
if len(rootRepoMap) > 0 {
- rootRepoJson, _ := json.Marshal(rootRepoMap)
- if err := ioutil.WriteFile(path.Join(tempdir, "repositories"), rootRepoJson, os.FileMode(0644)); err != nil {
+ f, err := os.OpenFile(path.Join(tempdir, "repositories"), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
+ if err != nil {
+ f.Close()
+ return err
+ }
+ if err := json.NewEncoder(f).Encode(rootRepoMap); err != nil {
+ return err
+ }
+ if err := f.Close(); err != nil {
return err
}
} else {
@@ -96,15 +104,15 @@ func (s *TagStore) CmdImageExport(job *engine.Job) error {
}
defer fs.Close()
- if _, err := io.Copy(job.Stdout, fs); err != nil {
+ if _, err := io.Copy(imageExportConfig.Outstream, fs); err != nil {
return err
}
- logrus.Debugf("End export job: %s", job.Name)
+ logrus.Debugf("End export image")
return nil
}
// FIXME: this should be a top-level function, not a class method
-func (s *TagStore) exportImage(eng *engine.Engine, name, tempdir string) error {
+func (s *TagStore) exportImage(name, tempdir string) error {
for n := name; n != ""; {
// temporary directory
tmpImageDir := path.Join(tempdir, n)
@@ -127,31 +135,33 @@ func (s *TagStore) exportImage(eng *engine.Engine, name, tempdir string) error {
if err != nil {
return err
}
- job := eng.Job("image_inspect", n)
- job.SetenvBool("raw", true)
- job.Stdout.Add(json)
- if err := job.Run(); err != nil {
+ imageInspectRaw, err := s.LookupRaw(n)
+ if err != nil {
return err
}
+ written, err := json.Write(imageInspectRaw)
+ if err != nil {
+ return err
+ }
+ if written != len(imageInspectRaw) {
+ logrus.Warnf("%d byes should have been written instead %d have been written", written, len(imageInspectRaw))
+ }
// serialize filesystem
fsTar, err := os.Create(path.Join(tmpImageDir, "layer.tar"))
if err != nil {
return err
}
- job = eng.Job("image_tarlayer", n)
- job.Stdout.Add(fsTar)
- if err := job.Run(); err != nil {
+ if err := s.ImageTarLayer(n, fsTar); err != nil {
return err
}
// find parent
- job = eng.Job("image_get", n)
- info, _ := job.Stdout.AddEnv()
- if err := job.Run(); err != nil {
+ img, err := s.LookupImage(n)
+ if err != nil {
return err
}
- n = info.Get("Parent")
+ n = img.Parent
}
return nil
}
diff --git a/graph/graph.go b/graph/graph.go
index 087a6f093cede..9b2d7c2ee9634 100644
--- a/graph/graph.go
+++ b/graph/graph.go
@@ -25,7 +25,6 @@ import (
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/truncindex"
"github.com/docker/docker/runconfig"
- "github.com/docker/docker/utils"
)
// A Graph is a store for versioned filesystem images and the relationship between them.
@@ -154,7 +153,7 @@ func (graph *Graph) Register(img *image.Image, layerData archive.ArchiveReader)
graph.driver.Remove(img.ID)
}
}()
- if err := utils.ValidateID(img.ID); err != nil {
+ if err := image.ValidateID(img.ID); err != nil {
return err
}
// (This is a convenience to save time. Race conditions are taken care of by os.Rename)
@@ -349,9 +348,8 @@ func (graph *Graph) Delete(name string) error {
tmp, err := graph.Mktemp("")
graph.idIndex.Delete(id)
if err == nil {
- err = os.Rename(graph.ImageRoot(id), tmp)
- // On err make tmp point to old dir and cleanup unused tmp dir
- if err != nil {
+ if err := os.Rename(graph.ImageRoot(id), tmp); err != nil {
+ // On err make tmp point to old dir and cleanup unused tmp dir
os.RemoveAll(tmp)
tmp = graph.ImageRoot(id)
}
diff --git a/integration/graph_test.go b/graph/graph_test.go
similarity index 92%
rename from integration/graph_test.go
rename to graph/graph_test.go
index a481154551f19..81471b6749457 100644
--- a/integration/graph_test.go
+++ b/graph/graph_test.go
@@ -1,4 +1,4 @@
-package docker
+package graph
import (
"errors"
@@ -11,11 +11,8 @@ import (
"github.com/docker/docker/autogen/dockerversion"
"github.com/docker/docker/daemon/graphdriver"
- "github.com/docker/docker/graph"
"github.com/docker/docker/image"
- "github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/stringid"
- "github.com/docker/docker/utils"
)
func TestMount(t *testing.T) {
@@ -48,6 +45,7 @@ func TestMount(t *testing.T) {
if _, err := driver.Get(image.ID, ""); err != nil {
t.Fatal(err)
}
+
}
func TestInit(t *testing.T) {
@@ -103,7 +101,7 @@ func TestGraphCreate(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- if err := utils.ValidateID(img.ID); err != nil {
+ if err := image.ValidateID(img.ID); err != nil {
t.Fatal(err)
}
if img.Comment != "Testing" {
@@ -167,18 +165,6 @@ func TestDeletePrefix(t *testing.T) {
assertNImages(graph, t, 0)
}
-func createTestImage(graph *graph.Graph, t *testing.T) *image.Image {
- archive, err := fakeTar()
- if err != nil {
- t.Fatal(err)
- }
- img, err := graph.Create(archive, "", "", "Test image", "", nil, nil)
- if err != nil {
- t.Fatal(err)
- }
- return img
-}
-
func TestDelete(t *testing.T) {
graph, _ := tempGraph(t)
defer nukeGraph(graph)
@@ -278,11 +264,19 @@ func TestByParent(t *testing.T) {
}
}
-/*
- * HELPER FUNCTIONS
- */
+func createTestImage(graph *Graph, t *testing.T) *image.Image {
+ archive, err := fakeTar()
+ if err != nil {
+ t.Fatal(err)
+ }
+ img, err := graph.Create(archive, "", "", "Test image", "", nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return img
+}
-func assertNImages(graph *graph.Graph, t *testing.T, n int) {
+func assertNImages(graph *Graph, t *testing.T, n int) {
if images, err := graph.Map(); err != nil {
t.Fatal(err)
} else if actualN := len(images); actualN != n {
@@ -290,7 +284,7 @@ func assertNImages(graph *graph.Graph, t *testing.T, n int) {
}
}
-func tempGraph(t *testing.T) (*graph.Graph, graphdriver.Driver) {
+func tempGraph(t *testing.T) (*Graph, graphdriver.Driver) {
tmp, err := ioutil.TempDir("", "docker-graph-")
if err != nil {
t.Fatal(err)
@@ -299,22 +293,14 @@ func tempGraph(t *testing.T) (*graph.Graph, graphdriver.Driver) {
if err != nil {
t.Fatal(err)
}
- graph, err := graph.NewGraph(tmp, driver)
+ graph, err := NewGraph(tmp, driver)
if err != nil {
t.Fatal(err)
}
return graph, driver
}
-func nukeGraph(graph *graph.Graph) {
+func nukeGraph(graph *Graph) {
graph.Driver().Cleanup()
os.RemoveAll(graph.Root)
}
-
-func testArchive(t *testing.T) archive.Archive {
- archive, err := fakeTar()
- if err != nil {
- t.Fatal(err)
- }
- return archive
-}
diff --git a/graph/history.go b/graph/history.go
index 1290de9a30781..56e759a8ebb02 100644
--- a/graph/history.go
+++ b/graph/history.go
@@ -1,24 +1,17 @@
package graph
import (
- "encoding/json"
- "fmt"
"strings"
"github.com/docker/docker/api/types"
- "github.com/docker/docker/engine"
"github.com/docker/docker/image"
"github.com/docker/docker/utils"
)
-func (s *TagStore) CmdHistory(job *engine.Job) error {
- if n := len(job.Args); n != 1 {
- return fmt.Errorf("Usage: %s IMAGE", job.Name)
- }
- name := job.Args[0]
+func (s *TagStore) History(name string) ([]*types.ImageHistory, error) {
foundImage, err := s.LookupImage(name)
if err != nil {
- return err
+ return nil, err
}
lookupMap := make(map[string][]string)
@@ -32,22 +25,19 @@ func (s *TagStore) CmdHistory(job *engine.Job) error {
}
}
- history := []types.ImageHistory{}
+ history := []*types.ImageHistory{}
err = foundImage.WalkHistory(func(img *image.Image) error {
- history = append(history, types.ImageHistory{
+ history = append(history, &types.ImageHistory{
ID: img.ID,
Created: img.Created.Unix(),
- CreatedBy: strings.Join(img.ContainerConfig.Cmd, " "),
+ CreatedBy: strings.Join(img.ContainerConfig.Cmd.Slice(), " "),
Tags: lookupMap[img.ID],
Size: img.Size,
+ Comment: img.Comment,
})
return nil
})
- if err = json.NewEncoder(job.Stdout).Encode(history); err != nil {
- return err
- }
-
- return nil
+ return history, err
}
diff --git a/graph/import.go b/graph/import.go
index eb63af0b6046b..50e605c948e1e 100644
--- a/graph/import.go
+++ b/graph/import.go
@@ -1,40 +1,35 @@
package graph
import (
- "bytes"
- "encoding/json"
- "fmt"
+ "io"
"net/http"
"net/url"
- "github.com/docker/docker/engine"
"github.com/docker/docker/pkg/archive"
+ "github.com/docker/docker/pkg/httputils"
"github.com/docker/docker/pkg/progressreader"
"github.com/docker/docker/pkg/streamformatter"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/utils"
)
-func (s *TagStore) CmdImport(job *engine.Job) error {
- if n := len(job.Args); n != 2 && n != 3 {
- return fmt.Errorf("Usage: %s SRC REPO [TAG]", job.Name)
- }
+type ImageImportConfig struct {
+ Changes []string
+ InConfig io.ReadCloser
+ Json bool
+ OutStream io.Writer
+ ContainerConfig *runconfig.Config
+}
+
+func (s *TagStore) Import(src string, repo string, tag string, imageImportConfig *ImageImportConfig) error {
var (
- src = job.Args[0]
- repo = job.Args[1]
- tag string
- sf = streamformatter.NewStreamFormatter(job.GetenvBool("json"))
- archive archive.ArchiveReader
- resp *http.Response
- stdoutBuffer = bytes.NewBuffer(nil)
- newConfig runconfig.Config
+ sf = streamformatter.NewStreamFormatter(imageImportConfig.Json)
+ archive archive.ArchiveReader
+ resp *http.Response
)
- if len(job.Args) > 2 {
- tag = job.Args[2]
- }
if src == "-" {
- archive = job.Stdin
+ archive = imageImportConfig.InConfig
} else {
u, err := url.Parse(src)
if err != nil {
@@ -45,14 +40,14 @@ func (s *TagStore) CmdImport(job *engine.Job) error {
u.Host = src
u.Path = ""
}
- job.Stdout.Write(sf.FormatStatus("", "Downloading from %s", u))
- resp, err = utils.Download(u.String())
+ imageImportConfig.OutStream.Write(sf.FormatStatus("", "Downloading from %s", u))
+ resp, err = httputils.Download(u.String())
if err != nil {
return err
}
progressReader := progressreader.New(progressreader.Config{
In: resp.Body,
- Out: job.Stdout,
+ Out: imageImportConfig.OutStream,
Formatter: sf,
Size: int(resp.ContentLength),
NewLines: true,
@@ -63,30 +58,17 @@ func (s *TagStore) CmdImport(job *engine.Job) error {
archive = progressReader
}
- buildConfigJob := job.Eng.Job("build_config")
- buildConfigJob.Stdout.Add(stdoutBuffer)
- buildConfigJob.Setenv("changes", job.Getenv("changes"))
- // FIXME this should be remove when we remove deprecated config param
- buildConfigJob.Setenv("config", job.Getenv("config"))
-
- if err := buildConfigJob.Run(); err != nil {
- return err
- }
- if err := json.NewDecoder(stdoutBuffer).Decode(&newConfig); err != nil {
- return err
- }
-
- img, err := s.graph.Create(archive, "", "", "Imported from "+src, "", nil, &newConfig)
+ img, err := s.graph.Create(archive, "", "", "Imported from "+src, "", nil, imageImportConfig.ContainerConfig)
if err != nil {
return err
}
// Optionally register the image at REPO/TAG
if repo != "" {
- if err := s.Set(repo, tag, img.ID, true); err != nil {
+ if err := s.Tag(repo, tag, img.ID, true); err != nil {
return err
}
}
- job.Stdout.Write(sf.FormatStatus("", img.ID))
+ imageImportConfig.OutStream.Write(sf.FormatStatus("", img.ID))
logID := img.ID
if tag != "" {
logID = utils.ImageReference(logID, tag)
diff --git a/graph/load.go b/graph/load.go
index ace222e3fec3f..d978b1ee8e8ce 100644
--- a/graph/load.go
+++ b/graph/load.go
@@ -4,21 +4,20 @@ package graph
import (
"encoding/json"
+ "io"
"io/ioutil"
"os"
"path"
"github.com/Sirupsen/logrus"
- "github.com/docker/docker/engine"
"github.com/docker/docker/image"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/chrootarchive"
- "github.com/docker/docker/utils"
)
// Loads a set of images into the repository. This is the complementary of ImageExport.
// The input stream is an uncompressed tar ball containing images and metadata.
-func (s *TagStore) CmdLoad(job *engine.Job) error {
+func (s *TagStore) Load(inTar io.ReadCloser, outStream io.Writer) error {
tmpImageDir, err := ioutil.TempDir("", "docker-import-")
if err != nil {
return err
@@ -42,7 +41,7 @@ func (s *TagStore) CmdLoad(job *engine.Job) error {
excludes[i] = k
i++
}
- if err := chrootarchive.Untar(job.Stdin, repoDir, &archive.TarOptions{ExcludePatterns: excludes}); err != nil {
+ if err := chrootarchive.Untar(inTar, repoDir, &archive.TarOptions{ExcludePatterns: excludes}); err != nil {
return err
}
@@ -53,35 +52,39 @@ func (s *TagStore) CmdLoad(job *engine.Job) error {
for _, d := range dirs {
if d.IsDir() {
- if err := s.recursiveLoad(job.Eng, d.Name(), tmpImageDir); err != nil {
+ if err := s.recursiveLoad(d.Name(), tmpImageDir); err != nil {
return err
}
}
}
- repositoriesJson, err := ioutil.ReadFile(path.Join(tmpImageDir, "repo", "repositories"))
- if err == nil {
- repositories := map[string]Repository{}
- if err := json.Unmarshal(repositoriesJson, &repositories); err != nil {
+ reposJSONFile, err := os.Open(path.Join(tmpImageDir, "repo", "repositories"))
+ if err != nil {
+ if !os.IsNotExist(err) {
return err
}
+ return nil
+ }
+ defer reposJSONFile.Close()
- for imageName, tagMap := range repositories {
- for tag, address := range tagMap {
- if err := s.SetLoad(imageName, tag, address, true, job.Stdout); err != nil {
- return err
- }
+ repositories := map[string]Repository{}
+ if err := json.NewDecoder(reposJSONFile).Decode(&repositories); err != nil {
+ return err
+ }
+
+ for imageName, tagMap := range repositories {
+ for tag, address := range tagMap {
+ if err := s.SetLoad(imageName, tag, address, true, outStream); err != nil {
+ return err
}
}
- } else if !os.IsNotExist(err) {
- return err
}
return nil
}
-func (s *TagStore) recursiveLoad(eng *engine.Engine, address, tmpImageDir string) error {
- if err := eng.Job("image_get", address).Run(); err != nil {
+func (s *TagStore) recursiveLoad(address, tmpImageDir string) error {
+ if _, err := s.LookupImage(address); err != nil {
logrus.Debugf("Loading %s", address)
imageJson, err := ioutil.ReadFile(path.Join(tmpImageDir, "repo", address, "json"))
@@ -100,7 +103,7 @@ func (s *TagStore) recursiveLoad(eng *engine.Engine, address, tmpImageDir string
logrus.Debugf("Error unmarshalling json", err)
return err
}
- if err := utils.ValidateID(img.ID); err != nil {
+ if err := image.ValidateID(img.ID); err != nil {
logrus.Debugf("Error validating ID: %s", err)
return err
}
@@ -120,7 +123,7 @@ func (s *TagStore) recursiveLoad(eng *engine.Engine, address, tmpImageDir string
if img.Parent != "" {
if !s.graph.Exists(img.Parent) {
- if err := s.recursiveLoad(eng, img.Parent, tmpImageDir); err != nil {
+ if err := s.recursiveLoad(img.Parent, tmpImageDir); err != nil {
return err
}
}
diff --git a/graph/load_unsupported.go b/graph/load_unsupported.go
index 707534480f8d1..7c515596962e9 100644
--- a/graph/load_unsupported.go
+++ b/graph/load_unsupported.go
@@ -4,10 +4,9 @@ package graph
import (
"fmt"
-
- "github.com/docker/docker/engine"
+ "io"
)
-func (s *TagStore) CmdLoad(job *engine.Job) error {
- return fmt.Errorf("CmdLoad is not supported on this platform")
+func (s *TagStore) Load(inTar io.ReadCloser, outStream io.Writer) error {
+ return fmt.Errorf("Load is not supported on this platform")
}
diff --git a/graph/manifest.go b/graph/manifest.go
index 7e9281537e3bd..053a185ba5289 100644
--- a/graph/manifest.go
+++ b/graph/manifest.go
@@ -1,14 +1,13 @@
package graph
import (
- "bytes"
"encoding/json"
"fmt"
"github.com/Sirupsen/logrus"
"github.com/docker/distribution/digest"
- "github.com/docker/docker/engine"
"github.com/docker/docker/registry"
+ "github.com/docker/docker/trust"
"github.com/docker/docker/utils"
"github.com/docker/libtrust"
)
@@ -18,7 +17,7 @@ import (
// contains no signatures by a trusted key for the name in the manifest, the
// image is not considered verified. The parsed manifest object and a boolean
// for whether the manifest is verified is returned.
-func (s *TagStore) loadManifest(eng *engine.Engine, manifestBytes []byte, dgst, ref string) (*registry.ManifestData, bool, error) {
+func (s *TagStore) loadManifest(manifestBytes []byte, dgst, ref string) (*registry.ManifestData, bool, error) {
sig, err := libtrust.ParsePrettySignature(manifestBytes, "signatures")
if err != nil {
return nil, false, fmt.Errorf("error parsing payload: %s", err)
@@ -69,32 +68,28 @@ func (s *TagStore) loadManifest(eng *engine.Engine, manifestBytes []byte, dgst,
var verified bool
for _, key := range keys {
- job := eng.Job("trust_key_check")
- b, err := key.MarshalJSON()
- if err != nil {
- return nil, false, fmt.Errorf("error marshalling public key: %s", err)
- }
namespace := manifest.Name
if namespace[0] != '/' {
namespace = "/" + namespace
}
- stdoutBuffer := bytes.NewBuffer(nil)
-
- job.Args = append(job.Args, namespace)
- job.Setenv("PublicKey", string(b))
+ b, err := key.MarshalJSON()
+ if err != nil {
+ return nil, false, fmt.Errorf("error marshalling public key: %s", err)
+ }
// Check key has read/write permission (0x03)
- job.SetenvInt("Permission", 0x03)
- job.Stdout.Add(stdoutBuffer)
- if err = job.Run(); err != nil {
- return nil, false, fmt.Errorf("error running key check: %s", err)
+ v, err := s.trustService.CheckKey(namespace, b, 0x03)
+ if err != nil {
+ vErr, ok := err.(trust.NotVerifiedError)
+ if !ok {
+ return nil, false, fmt.Errorf("error running key check: %s", err)
+ }
+ logrus.Debugf("Key check result: %v", vErr)
}
- result := engine.Tail(stdoutBuffer, 1)
- logrus.Debugf("Key check result: %q", result)
- if result == "verified" {
- verified = true
+ verified = v
+ if verified {
+ logrus.Debug("Key check result: verified")
}
}
-
return &manifest, verified, nil
}
diff --git a/graph/manifest_test.go b/graph/manifest_test.go
index 9137041827b33..2702dcaf560aa 100644
--- a/graph/manifest_test.go
+++ b/graph/manifest_test.go
@@ -135,7 +135,7 @@ func TestManifestTarsumCache(t *testing.T) {
if err := store.graph.Register(img, archive); err != nil {
t.Fatal(err)
}
- if err := store.Set(testManifestImageName, testManifestTag, testManifestImageID, false); err != nil {
+ if err := store.Tag(testManifestImageName, testManifestTag, testManifestImageID, false); err != nil {
t.Fatal(err)
}
diff --git a/graph/pull.go b/graph/pull.go
index 13c69858fd0db..c3c064fc5842a 100644
--- a/graph/pull.go
+++ b/graph/pull.go
@@ -12,7 +12,7 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/distribution/digest"
- "github.com/docker/docker/engine"
+ "github.com/docker/docker/cliconfig"
"github.com/docker/docker/image"
"github.com/docker/docker/pkg/progressreader"
"github.com/docker/docker/pkg/streamformatter"
@@ -21,37 +21,34 @@ import (
"github.com/docker/docker/utils"
)
-func (s *TagStore) CmdPull(job *engine.Job) error {
- if n := len(job.Args); n != 1 && n != 2 {
- return fmt.Errorf("Usage: %s IMAGE [TAG|DIGEST]", job.Name)
- }
+type ImagePullConfig struct {
+ Parallel bool
+ MetaHeaders map[string][]string
+ AuthConfig *cliconfig.AuthConfig
+ Json bool
+ OutStream io.Writer
+}
+func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConfig) error {
var (
- localName = job.Args[0]
- tag string
- sf = streamformatter.NewStreamFormatter(job.GetenvBool("json"))
- authConfig = ®istry.AuthConfig{}
- metaHeaders map[string][]string
+ sf = streamformatter.NewStreamFormatter(imagePullConfig.Json)
)
// Resolve the Repository name from fqn to RepositoryInfo
- repoInfo, err := s.registryService.ResolveRepository(localName)
+ repoInfo, err := s.registryService.ResolveRepository(image)
if err != nil {
return err
}
- if len(job.Args) > 1 {
- tag = job.Args[1]
+ if err := validateRepoName(repoInfo.LocalName); err != nil {
+ return err
}
- job.GetenvJson("authConfig", authConfig)
- job.GetenvJson("metaHeaders", &metaHeaders)
-
c, err := s.poolAdd("pull", utils.ImageReference(repoInfo.LocalName, tag))
if err != nil {
if c != nil {
// Another pull of the same repository is already taking place; just wait for it to finish
- job.Stdout.Write(sf.FormatStatus("", "Repository %s already being pulled by another client. Waiting.", repoInfo.LocalName))
+ imagePullConfig.OutStream.Write(sf.FormatStatus("", "Repository %s already being pulled by another client. Waiting.", repoInfo.LocalName))
<-c
return nil
}
@@ -65,7 +62,7 @@ func (s *TagStore) CmdPull(job *engine.Job) error {
return err
}
- r, err := registry.NewSession(authConfig, registry.HTTPRequestFactory(metaHeaders), endpoint, true)
+ r, err := registry.NewSession(imagePullConfig.AuthConfig, registry.HTTPRequestFactory(imagePullConfig.MetaHeaders), endpoint, true)
if err != nil {
return err
}
@@ -77,14 +74,11 @@ func (s *TagStore) CmdPull(job *engine.Job) error {
if len(repoInfo.Index.Mirrors) == 0 && (repoInfo.Index.Official || endpoint.Version == registry.APIVersion2) {
if repoInfo.Official {
- j := job.Eng.Job("trust_update_base")
- if err = j.Run(); err != nil {
- logrus.Errorf("error updating trust base graph: %s", err)
- }
+ s.trustService.UpdateBase()
}
logrus.Debugf("pulling v2 repository with local name %q", repoInfo.LocalName)
- if err := s.pullV2Repository(job.Eng, r, job.Stdout, repoInfo, tag, sf, job.GetenvBool("parallel")); err == nil {
+ if err := s.pullV2Repository(r, imagePullConfig.OutStream, repoInfo, tag, sf, imagePullConfig.Parallel); err == nil {
s.eventsService.Log("pull", logName, "")
return nil
} else if err != registry.ErrDoesNotExist && err != ErrV2RegistryUnavailable {
@@ -95,7 +89,7 @@ func (s *TagStore) CmdPull(job *engine.Job) error {
}
logrus.Debugf("pulling v1 repository with local name %q", repoInfo.LocalName)
- if err = s.pullRepository(r, job.Stdout, repoInfo, tag, sf, job.GetenvBool("parallel")); err != nil {
+ if err = s.pullRepository(r, imagePullConfig.OutStream, repoInfo, tag, sf, imagePullConfig.Parallel); err != nil {
return err
}
@@ -249,7 +243,7 @@ func (s *TagStore) pullRepository(r *registry.Session, out io.Writer, repoInfo *
if askedTag != "" && tag != askedTag {
continue
}
- if err := s.Set(repoInfo.LocalName, tag, id, true); err != nil {
+ if err := s.Tag(repoInfo.LocalName, tag, id, true); err != nil {
return err
}
}
@@ -379,7 +373,7 @@ type downloadInfo struct {
err chan error
}
-func (s *TagStore) pullV2Repository(eng *engine.Engine, r *registry.Session, out io.Writer, repoInfo *registry.RepositoryInfo, tag string, sf *streamformatter.StreamFormatter, parallel bool) error {
+func (s *TagStore) pullV2Repository(r *registry.Session, out io.Writer, repoInfo *registry.RepositoryInfo, tag string, sf *streamformatter.StreamFormatter, parallel bool) error {
endpoint, err := r.V2RegistryEndpoint(repoInfo.Index)
if err != nil {
if repoInfo.Index.Official {
@@ -403,14 +397,14 @@ func (s *TagStore) pullV2Repository(eng *engine.Engine, r *registry.Session, out
return registry.ErrDoesNotExist
}
for _, t := range tags {
- if downloaded, err := s.pullV2Tag(eng, r, out, endpoint, repoInfo, t, sf, parallel, auth); err != nil {
+ if downloaded, err := s.pullV2Tag(r, out, endpoint, repoInfo, t, sf, parallel, auth); err != nil {
return err
} else if downloaded {
layersDownloaded = true
}
}
} else {
- if downloaded, err := s.pullV2Tag(eng, r, out, endpoint, repoInfo, tag, sf, parallel, auth); err != nil {
+ if downloaded, err := s.pullV2Tag(r, out, endpoint, repoInfo, tag, sf, parallel, auth); err != nil {
return err
} else if downloaded {
layersDownloaded = true
@@ -425,7 +419,7 @@ func (s *TagStore) pullV2Repository(eng *engine.Engine, r *registry.Session, out
return nil
}
-func (s *TagStore) pullV2Tag(eng *engine.Engine, r *registry.Session, out io.Writer, endpoint *registry.Endpoint, repoInfo *registry.RepositoryInfo, tag string, sf *streamformatter.StreamFormatter, parallel bool, auth *registry.RequestAuthorization) (bool, error) {
+func (s *TagStore) pullV2Tag(r *registry.Session, out io.Writer, endpoint *registry.Endpoint, repoInfo *registry.RepositoryInfo, tag string, sf *streamformatter.StreamFormatter, parallel bool, auth *registry.RequestAuthorization) (bool, error) {
logrus.Debugf("Pulling tag from V2 registry: %q", tag)
manifestBytes, manifestDigest, err := r.GetV2ImageManifest(endpoint, repoInfo.RemoteName, tag, auth)
@@ -435,7 +429,7 @@ func (s *TagStore) pullV2Tag(eng *engine.Engine, r *registry.Session, out io.Wri
// loadManifest ensures that the manifest payload has the expected digest
// if the tag is a digest reference.
- manifest, verified, err := s.loadManifest(eng, manifestBytes, manifestDigest, tag)
+ manifest, verified, err := s.loadManifest(manifestBytes, manifestDigest, tag)
if err != nil {
return false, fmt.Errorf("error verifying manifest: %s", err)
}
@@ -495,7 +489,7 @@ func (s *TagStore) pullV2Tag(eng *engine.Engine, r *registry.Session, out io.Wri
return err
}
- r, l, err := r.GetV2ImageBlobReader(endpoint, repoInfo.RemoteName, di.digest.Algorithm(), di.digest.Hex(), auth)
+ r, l, err := r.GetV2ImageBlobReader(endpoint, repoInfo.RemoteName, di.digest, auth)
if err != nil {
return err
}
@@ -543,8 +537,7 @@ func (s *TagStore) pullV2Tag(eng *engine.Engine, r *registry.Session, out io.Wri
di.err <- downloadFunc(di)
}(&downloads[i])
} else {
- err := downloadFunc(&downloads[i])
- if err != nil {
+ if err := downloadFunc(&downloads[i]); err != nil {
return false, err
}
}
@@ -554,8 +547,7 @@ func (s *TagStore) pullV2Tag(eng *engine.Engine, r *registry.Session, out io.Wri
for i := len(downloads) - 1; i >= 0; i-- {
d := &downloads[i]
if d.err != nil {
- err := <-d.err
- if err != nil {
+ if err := <-d.err; err != nil {
return false, err
}
}
@@ -617,7 +609,7 @@ func (s *TagStore) pullV2Tag(eng *engine.Engine, r *registry.Session, out io.Wri
}
} else {
// only set the repository/tag -> image ID mapping when pulling by tag (i.e. not by digest)
- if err = s.Set(repoInfo.LocalName, tag, downloads[0].img.ID, true); err != nil {
+ if err = s.Tag(repoInfo.LocalName, tag, downloads[0].img.ID, true); err != nil {
return false, err
}
}
diff --git a/graph/push.go b/graph/push.go
index a542dbf812c24..1b33288d8fedf 100644
--- a/graph/push.go
+++ b/graph/push.go
@@ -8,11 +8,11 @@ import (
"io/ioutil"
"os"
"path"
- "strings"
"sync"
"github.com/Sirupsen/logrus"
- "github.com/docker/docker/engine"
+ "github.com/docker/distribution/digest"
+ "github.com/docker/docker/cliconfig"
"github.com/docker/docker/image"
"github.com/docker/docker/pkg/progressreader"
"github.com/docker/docker/pkg/streamformatter"
@@ -25,6 +25,14 @@ import (
var ErrV2RegistryUnavailable = errors.New("error v2 registry unavailable")
+type ImagePushConfig struct {
+ MetaHeaders map[string][]string
+ AuthConfig *cliconfig.AuthConfig
+ Tag string
+ Json bool
+ OutStream io.Writer
+}
+
// Retrieve the all the images to be uploaded in the correct order
func (s *TagStore) getImageList(localRepo map[string]string, requestedTag string) ([]string, map[string][]string, error) {
var (
@@ -359,8 +367,7 @@ func (s *TagStore) pushV2Repository(r *registry.Session, localRepo Repository, o
logrus.Debugf("Pushing layer: %s", layer.ID)
if layer.Config != nil && metadata.Image != layer.ID {
- err = runconfig.Merge(&metadata, layer.Config)
- if err != nil {
+ if err := runconfig.Merge(&metadata, layer.Config); err != nil {
return err
}
}
@@ -376,13 +383,13 @@ func (s *TagStore) pushV2Repository(r *registry.Session, localRepo Repository, o
var exists bool
if len(checksum) > 0 {
- sumParts := strings.SplitN(checksum, ":", 2)
- if len(sumParts) < 2 {
- return fmt.Errorf("Invalid checksum: %s", checksum)
+ dgst, err := digest.ParseDigest(checksum)
+ if err != nil {
+ return fmt.Errorf("Invalid checksum %s: %s", checksum, err)
}
// Call mount blob
- exists, err = r.HeadV2ImageBlob(endpoint, repoInfo.RemoteName, sumParts[0], sumParts[1], auth)
+ exists, err = r.HeadV2ImageBlob(endpoint, repoInfo.RemoteName, dgst, auth)
if err != nil {
out.Write(sf.FormatProgress(stringid.TruncateID(layer.ID), "Image push failed", nil))
return err
@@ -468,7 +475,7 @@ func (s *TagStore) pushV2Image(r *registry.Session, img *image.Image, endpoint *
// Send the layer
logrus.Debugf("rendered layer for %s of [%d] size", img.ID, size)
- if err := r.PutV2ImageBlob(endpoint, imageName, dgst.Algorithm(), dgst.Hex(),
+ if err := r.PutV2ImageBlob(endpoint, imageName, dgst,
progressreader.New(progressreader.Config{
In: tf,
Out: out,
@@ -486,15 +493,9 @@ func (s *TagStore) pushV2Image(r *registry.Session, img *image.Image, endpoint *
}
// FIXME: Allow to interrupt current push when new push of same image is done.
-func (s *TagStore) CmdPush(job *engine.Job) error {
- if n := len(job.Args); n != 1 {
- return fmt.Errorf("Usage: %s IMAGE", job.Name)
- }
+func (s *TagStore) Push(localName string, imagePushConfig *ImagePushConfig) error {
var (
- localName = job.Args[0]
- sf = streamformatter.NewStreamFormatter(job.GetenvBool("json"))
- authConfig = ®istry.AuthConfig{}
- metaHeaders map[string][]string
+ sf = streamformatter.NewStreamFormatter(imagePushConfig.Json)
)
// Resolve the Repository name from fqn to RepositoryInfo
@@ -503,10 +504,6 @@ func (s *TagStore) CmdPush(job *engine.Job) error {
return err
}
- tag := job.Getenv("tag")
- job.GetenvJson("authConfig", authConfig)
- job.GetenvJson("metaHeaders", &metaHeaders)
-
if _, err := s.poolAdd("push", repoInfo.LocalName); err != nil {
return err
}
@@ -517,16 +514,18 @@ func (s *TagStore) CmdPush(job *engine.Job) error {
return err
}
- r, err := registry.NewSession(authConfig, registry.HTTPRequestFactory(metaHeaders), endpoint, false)
+ r, err := registry.NewSession(imagePushConfig.AuthConfig, registry.HTTPRequestFactory(imagePushConfig.MetaHeaders), endpoint, false)
if err != nil {
return err
}
reposLen := 1
- if tag == "" {
+ if imagePushConfig.Tag == "" {
reposLen = len(s.Repositories[repoInfo.LocalName])
}
- job.Stdout.Write(sf.FormatStatus("", "The push refers to a repository [%s] (len: %d)", repoInfo.CanonicalName, reposLen))
+
+ imagePushConfig.OutStream.Write(sf.FormatStatus("", "The push refers to a repository [%s] (len: %d)", repoInfo.CanonicalName, reposLen))
+
// If it fails, try to get the repository
localRepo, exists := s.Repositories[repoInfo.LocalName]
if !exists {
@@ -534,8 +533,9 @@ func (s *TagStore) CmdPush(job *engine.Job) error {
}
if repoInfo.Index.Official || endpoint.Version == registry.APIVersion2 {
- err := s.pushV2Repository(r, localRepo, job.Stdout, repoInfo, tag, sf)
+ err := s.pushV2Repository(r, localRepo, imagePushConfig.OutStream, repoInfo, imagePushConfig.Tag, sf)
if err == nil {
+ s.eventsService.Log("push", repoInfo.LocalName, "")
return nil
}
@@ -544,9 +544,10 @@ func (s *TagStore) CmdPush(job *engine.Job) error {
}
}
- if err := s.pushRepository(r, job.Stdout, repoInfo, localRepo, tag, sf); err != nil {
+ if err := s.pushRepository(r, imagePushConfig.OutStream, repoInfo, localRepo, imagePushConfig.Tag, sf); err != nil {
return err
}
+ s.eventsService.Log("push", repoInfo.LocalName, "")
return nil
}
diff --git a/graph/service.go b/graph/service.go
index a51d106e1389d..52dde1d980504 100644
--- a/graph/service.go
+++ b/graph/service.go
@@ -5,163 +5,51 @@ import (
"io"
"github.com/Sirupsen/logrus"
- "github.com/docker/docker/engine"
- "github.com/docker/docker/image"
+ "github.com/docker/docker/api/types"
)
-func (s *TagStore) Install(eng *engine.Engine) error {
- for name, handler := range map[string]engine.Handler{
- "image_set": s.CmdSet,
- "tag": s.CmdTag,
- "image_get": s.CmdGet,
- "image_inspect": s.CmdLookup,
- "image_tarlayer": s.CmdTarLayer,
- "image_export": s.CmdImageExport,
- "history": s.CmdHistory,
- "viz": s.CmdViz,
- "load": s.CmdLoad,
- "import": s.CmdImport,
- "pull": s.CmdPull,
- "push": s.CmdPush,
- } {
- if err := eng.Register(name, handler); err != nil {
- return fmt.Errorf("Could not register %q: %v", name, err)
- }
+func (s *TagStore) LookupRaw(name string) ([]byte, error) {
+ image, err := s.LookupImage(name)
+ if err != nil || image == nil {
+ return nil, fmt.Errorf("No such image %s", name)
}
- return nil
-}
-// CmdSet stores a new image in the graph.
-// Images are stored in the graph using 4 elements:
-// - A user-defined ID
-// - A collection of metadata describing the image
-// - A directory tree stored as a tar archive (also called the "layer")
-// - A reference to a "parent" ID on top of which the layer should be applied
-//
-// NOTE: even though the parent ID is only useful in relation to the layer and how
-// to apply it (ie you could represent the full directory tree as 'parent_layer + layer',
-// it is treated as a top-level property of the image. This is an artifact of early
-// design and should probably be cleaned up in the future to simplify the design.
-//
-// Syntax: image_set ID
-// Input:
-// - Layer content must be streamed in tar format on stdin. An empty input is
-// valid and represents a nil layer.
-//
-// - Image metadata must be passed in the command environment.
-// 'json': a json-encoded object with all image metadata.
-// It will be stored as-is, without any encoding/decoding artifacts.
-// That is a requirement of the current registry client implementation,
-// because a re-encoded json might invalidate the image checksum at
-// the next upload, even with functionaly identical content.
-func (s *TagStore) CmdSet(job *engine.Job) error {
- if len(job.Args) != 1 {
- return fmt.Errorf("usage: %s NAME", job.Name)
- }
- var (
- imgJSON = []byte(job.Getenv("json"))
- layer = job.Stdin
- )
- if len(imgJSON) == 0 {
- return fmt.Errorf("mandatory key 'json' is not set")
- }
- // We have to pass an *image.Image object, even though it will be completely
- // ignored in favor of the redundant json data.
- // FIXME: the current prototype of Graph.Register is redundant.
- img, err := image.NewImgJSON(imgJSON)
+ imageInspectRaw, err := image.RawJson()
if err != nil {
- return err
- }
- if err := s.graph.Register(img, layer); err != nil {
- return err
+ return nil, err
}
- return nil
-}
-// CmdGet returns information about an image.
-// If the image doesn't exist, an empty object is returned, to allow
-// checking for an image's existence.
-func (s *TagStore) CmdGet(job *engine.Job) error {
- if len(job.Args) != 1 {
- return fmt.Errorf("usage: %s NAME", job.Name)
- }
- name := job.Args[0]
- res := &engine.Env{}
- img, err := s.LookupImage(name)
- // Note: if the image doesn't exist, LookupImage returns
- // nil, nil.
- if err != nil {
- return err
- }
- if img != nil {
- // We don't directly expose all fields of the Image objects,
- // to maintain a clean public API which we can maintain over
- // time even if the underlying structure changes.
- // We should have done this with the Image object to begin with...
- // but we didn't, so now we're doing it here.
- //
- // Fields that we're probably better off not including:
- // - Config/ContainerConfig. Those structs have the same sprawl problem,
- // so we shouldn't include them wholesale either.
- // - Comment: initially created to fulfill the "every image is a git commit"
- // metaphor, in practice people either ignore it or use it as a
- // generic description field which it isn't. On deprecation shortlist.
- res.SetAuto("Created", img.Created)
- res.SetJson("Author", img.Author)
- res.Set("Os", img.OS)
- res.Set("Architecture", img.Architecture)
- res.Set("DockerVersion", img.DockerVersion)
- res.SetJson("Id", img.ID)
- res.SetJson("Parent", img.Parent)
- }
- res.WriteTo(job.Stdout)
- return nil
+ return imageInspectRaw, nil
}
-// CmdLookup return an image encoded in JSON
-func (s *TagStore) CmdLookup(job *engine.Job) error {
- if len(job.Args) != 1 {
- return fmt.Errorf("usage: %s NAME", job.Name)
+// Lookup return an image encoded in JSON
+func (s *TagStore) Lookup(name string) (*types.ImageInspect, error) {
+ image, err := s.LookupImage(name)
+ if err != nil || image == nil {
+ return nil, fmt.Errorf("No such image: %s", name)
}
- name := job.Args[0]
- if image, err := s.LookupImage(name); err == nil && image != nil {
- if job.GetenvBool("raw") {
- b, err := image.RawJson()
- if err != nil {
- return err
- }
- job.Stdout.Write(b)
- return nil
- }
- out := &engine.Env{}
- out.SetJson("Id", image.ID)
- out.SetJson("Parent", image.Parent)
- out.SetJson("Comment", image.Comment)
- out.SetAuto("Created", image.Created)
- out.SetJson("Container", image.Container)
- out.SetJson("ContainerConfig", image.ContainerConfig)
- out.Set("DockerVersion", image.DockerVersion)
- out.SetJson("Author", image.Author)
- out.SetJson("Config", image.Config)
- out.Set("Architecture", image.Architecture)
- out.Set("Os", image.OS)
- out.SetInt64("Size", image.Size)
- out.SetInt64("VirtualSize", image.GetParentsSize(0)+image.Size)
- if _, err = out.WriteTo(job.Stdout); err != nil {
- return err
- }
- return nil
+ imageInspect := &types.ImageInspect{
+ Id: image.ID,
+ Parent: image.Parent,
+ Comment: image.Comment,
+ Created: image.Created,
+ Container: image.Container,
+ ContainerConfig: &image.ContainerConfig,
+ DockerVersion: image.DockerVersion,
+ Author: image.Author,
+ Config: image.Config,
+ Architecture: image.Architecture,
+ Os: image.OS,
+ Size: image.Size,
+ VirtualSize: image.GetParentsSize(0) + image.Size,
}
- return fmt.Errorf("No such image: %s", name)
+
+ return imageInspect, nil
}
-// CmdTarLayer return the tarLayer of the image
-func (s *TagStore) CmdTarLayer(job *engine.Job) error {
- if len(job.Args) != 1 {
- return fmt.Errorf("usage: %s NAME", job.Name)
- }
- name := job.Args[0]
+// ImageTarLayer return the tarLayer of the image
+func (s *TagStore) ImageTarLayer(name string, dest io.Writer) error {
if image, err := s.LookupImage(name); err == nil && image != nil {
fs, err := image.TarLayer()
if err != nil {
@@ -169,7 +57,7 @@ func (s *TagStore) CmdTarLayer(job *engine.Job) error {
}
defer fs.Close()
- written, err := io.Copy(job.Stdout, fs)
+ written, err := io.Copy(dest, fs)
if err != nil {
return err
}
diff --git a/graph/tag.go b/graph/tag.go
deleted file mode 100644
index c0b269946f297..0000000000000
--- a/graph/tag.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package graph
-
-import (
- "fmt"
-
- "github.com/docker/docker/engine"
-)
-
-func (s *TagStore) CmdTag(job *engine.Job) error {
- if len(job.Args) != 2 && len(job.Args) != 3 {
- return fmt.Errorf("Usage: %s IMAGE REPOSITORY [TAG]\n", job.Name)
- }
- var tag string
- if len(job.Args) == 3 {
- tag = job.Args[2]
- }
- return s.Set(job.Args[1], tag, job.Args[0], job.GetenvBool("force"))
-}
diff --git a/graph/tags.go b/graph/tags.go
index 6346ea8b50dc6..abffe2f562c76 100644
--- a/graph/tags.go
+++ b/graph/tags.go
@@ -18,6 +18,7 @@ import (
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/registry"
+ "github.com/docker/docker/trust"
"github.com/docker/docker/utils"
"github.com/docker/libtrust"
)
@@ -42,6 +43,7 @@ type TagStore struct {
pushingPool map[string]chan struct{}
registryService *registry.Service
eventsService *events.Events
+ trustService *trust.TrustStore
}
type Repository map[string]string
@@ -64,7 +66,15 @@ func (r Repository) Contains(u Repository) bool {
return true
}
-func NewTagStore(path string, graph *Graph, key libtrust.PrivateKey, registryService *registry.Service, eventsService *events.Events) (*TagStore, error) {
+type TagStoreConfig struct {
+ Graph *Graph
+ Key libtrust.PrivateKey
+ Registry *registry.Service
+ Events *events.Events
+ Trust *trust.TrustStore
+}
+
+func NewTagStore(path string, cfg *TagStoreConfig) (*TagStore, error) {
abspath, err := filepath.Abs(path)
if err != nil {
return nil, err
@@ -72,13 +82,14 @@ func NewTagStore(path string, graph *Graph, key libtrust.PrivateKey, registrySer
store := &TagStore{
path: abspath,
- graph: graph,
- trustKey: key,
+ graph: cfg.Graph,
+ trustKey: cfg.Key,
Repositories: make(map[string]Repository),
pullingPool: make(map[string]chan struct{}),
pushingPool: make(map[string]chan struct{}),
- registryService: registryService,
- eventsService: eventsService,
+ registryService: cfg.Registry,
+ eventsService: cfg.Events,
+ trustService: cfg.Trust,
}
// Load the json file if it exists, otherwise create it.
if err := store.reload(); os.IsNotExist(err) {
@@ -104,11 +115,12 @@ func (store *TagStore) save() error {
}
func (store *TagStore) reload() error {
- jsonData, err := ioutil.ReadFile(store.path)
+ f, err := os.Open(store.path)
if err != nil {
return err
}
- if err := json.Unmarshal(jsonData, store); err != nil {
+ defer f.Close()
+ if err := json.NewDecoder(f).Decode(&store); err != nil {
return err
}
return nil
@@ -224,7 +236,7 @@ func (store *TagStore) Delete(repoName, ref string) (bool, error) {
return deleted, store.save()
}
-func (store *TagStore) Set(repoName, tag, imageName string, force bool) error {
+func (store *TagStore) Tag(repoName, tag, imageName string, force bool) error {
return store.SetLoad(repoName, tag, imageName, force, nil)
}
diff --git a/graph/tags_unit_test.go b/graph/tags_unit_test.go
index be5624245c596..0482fa58e3caa 100644
--- a/graph/tags_unit_test.go
+++ b/graph/tags_unit_test.go
@@ -60,7 +60,11 @@ func mkTestTagStore(root string, t *testing.T) *TagStore {
if err != nil {
t.Fatal(err)
}
- store, err := NewTagStore(path.Join(root, "tags"), graph, nil, nil, events.New())
+ tagCfg := &TagStoreConfig{
+ Graph: graph,
+ Events: events.New(),
+ }
+ store, err := NewTagStore(path.Join(root, "tags"), tagCfg)
if err != nil {
t.Fatal(err)
}
@@ -72,7 +76,7 @@ func mkTestTagStore(root string, t *testing.T) *TagStore {
if err := graph.Register(img, officialArchive); err != nil {
t.Fatal(err)
}
- if err := store.Set(testOfficialImageName, "", testOfficialImageID, false); err != nil {
+ if err := store.Tag(testOfficialImageName, "", testOfficialImageID, false); err != nil {
t.Fatal(err)
}
privateArchive, err := fakeTar()
@@ -83,7 +87,7 @@ func mkTestTagStore(root string, t *testing.T) *TagStore {
if err := graph.Register(img, privateArchive); err != nil {
t.Fatal(err)
}
- if err := store.Set(testPrivateImageName, "", testPrivateImageID, false); err != nil {
+ if err := store.Tag(testPrivateImageName, "", testPrivateImageID, false); err != nil {
t.Fatal(err)
}
if err := store.SetDigest(testPrivateImageName, testPrivateImageDigest, testPrivateImageID); err != nil {
diff --git a/graph/viz.go b/graph/viz.go
deleted file mode 100644
index 0c45caa9efbba..0000000000000
--- a/graph/viz.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package graph
-
-import (
- "fmt"
- "strings"
-
- "github.com/docker/docker/engine"
- "github.com/docker/docker/image"
-)
-
-func (s *TagStore) CmdViz(job *engine.Job) error {
- images, _ := s.graph.Map()
- if images == nil {
- return nil
- }
- job.Stdout.Write([]byte("digraph docker {\n"))
-
- var (
- parentImage *image.Image
- err error
- )
- for _, image := range images {
- parentImage, err = image.GetParent()
- if err != nil {
- return fmt.Errorf("Error while getting parent image: %v", err)
- }
- if parentImage != nil {
- job.Stdout.Write([]byte(" \"" + parentImage.ID + "\" -> \"" + image.ID + "\"\n"))
- } else {
- job.Stdout.Write([]byte(" base -> \"" + image.ID + "\" [style=invis]\n"))
- }
- }
-
- for id, repos := range s.GetRepoRefs() {
- job.Stdout.Write([]byte(" \"" + id + "\" [label=\"" + id + "\\n" + strings.Join(repos, "\\n") + "\",shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n"))
- }
- job.Stdout.Write([]byte(" base [style=invisible]\n}\n"))
- return nil
-}
diff --git a/hack/dind b/hack/dind
index 1242cbffe1ed0..9289ba65561b0 100755
--- a/hack/dind
+++ b/hack/dind
@@ -3,7 +3,7 @@ set -e
# DinD: a wrapper script which allows docker to be run inside a docker container.
# Original version by Jerome Petazzoni
-# See the blog post: http://blog.docker.com/2013/09/docker-can-now-run-within-docker/
+# See the blog post: https://blog.docker.com/2013/09/docker-can-now-run-within-docker/
#
# This script should be executed inside a docker container in privilieged mode
# ('docker run --privileged', introduced in docker 0.6).
@@ -60,7 +60,7 @@ for HIER in $(cut -d: -f2 /proc/1/cgroup); do
mkdir -p "$CGROUP/$HIER"
- if ! mountpoint -q $CGROUP/$HIER; then
+ if ! mountpoint -q "$CGROUP/$HIER"; then
mount -n -t cgroup -o "$OHIER" cgroup "$CGROUP/$HIER"
fi
diff --git a/hack/install.sh b/hack/install.sh
index fcea11d01e71d..e15565fc79a3f 100755
--- a/hack/install.sh
+++ b/hack/install.sh
@@ -20,213 +20,230 @@ command_exists() {
command -v "$@" > /dev/null 2>&1
}
-case "$(uname -m)" in
- *64)
- ;;
- *)
- echo >&2 'Error: you are not using a 64bit platform.'
- echo >&2 'Docker currently only supports 64bit platforms.'
- exit 1
- ;;
-esac
-
-if command_exists docker || command_exists lxc-docker; then
- echo >&2 'Warning: "docker" or "lxc-docker" command appears to already exist.'
- echo >&2 'Please ensure that you do not already have docker installed.'
- echo >&2 'You may press Ctrl+C now to abort this process and rectify this situation.'
- ( set -x; sleep 20 )
-fi
-
-user="$(id -un 2>/dev/null || true)"
-
-sh_c='sh -c'
-if [ "$user" != 'root' ]; then
- if command_exists sudo; then
- sh_c='sudo -E sh -c'
- elif command_exists su; then
- sh_c='su -c'
- else
- echo >&2 'Error: this installer needs the ability to run commands as root.'
- echo >&2 'We are unable to find either "sudo" or "su" available to make this happen.'
- exit 1
+echo_docker_as_nonroot() {
+ your_user=your-user
+ [ "$user" != 'root' ] && your_user="$user"
+ # intentionally mixed spaces and tabs here -- tabs are stripped by "<<-EOF", spaces are kept in the output
+ cat <<-EOF
+
+ If you would like to use Docker as a non-root user, you should now consider
+ adding your user to the "docker" group with something like:
+
+ sudo usermod -aG docker $your_user
+
+ Remember that you will have to log out and back in for this to take effect!
+
+ EOF
+}
+
+do_install() {
+ case "$(uname -m)" in
+ *64)
+ ;;
+ *)
+ cat >&2 <<-'EOF'
+ Error: you are not using a 64bit platform.
+ Docker currently only supports 64bit platforms.
+ EOF
+ exit 1
+ ;;
+ esac
+
+ if command_exists docker || command_exists lxc-docker; then
+ cat >&2 <<-'EOF'
+ Warning: "docker" or "lxc-docker" command appears to already exist.
+ Please ensure that you do not already have docker installed.
+ You may press Ctrl+C now to abort this process and rectify this situation.
+ EOF
+ ( set -x; sleep 20 )
fi
-fi
-
-curl=''
-if command_exists curl; then
- curl='curl -sSL'
-elif command_exists wget; then
- curl='wget -qO-'
-elif command_exists busybox && busybox --list-modules | grep -q wget; then
- curl='busybox wget -qO-'
-fi
-
-# perform some very rudimentary platform detection
-lsb_dist=''
-if command_exists lsb_release; then
- lsb_dist="$(lsb_release -si)"
-fi
-if [ -z "$lsb_dist" ] && [ -r /etc/lsb-release ]; then
- lsb_dist="$(. /etc/lsb-release && echo "$DISTRIB_ID")"
-fi
-if [ -z "$lsb_dist" ] && [ -r /etc/debian_version ]; then
- lsb_dist='debian'
-fi
-if [ -z "$lsb_dist" ] && [ -r /etc/fedora-release ]; then
- lsb_dist='fedora'
-fi
-if [ -z "$lsb_dist" ] && [ -r /etc/os-release ]; then
- lsb_dist="$(. /etc/os-release && echo "$ID")"
-fi
-
-lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')"
-case "$lsb_dist" in
- amzn|fedora|centos)
- if [ "$lsb_dist" = 'amzn' ]; then
- (
- set -x
- $sh_c 'sleep 3; yum -y -q install docker'
- )
+
+ user="$(id -un 2>/dev/null || true)"
+
+ sh_c='sh -c'
+ if [ "$user" != 'root' ]; then
+ if command_exists sudo; then
+ sh_c='sudo -E sh -c'
+ elif command_exists su; then
+ sh_c='su -c'
else
- (
- set -x
- $sh_c 'sleep 3; yum -y -q install docker-io'
- )
- fi
- if command_exists docker && [ -e /var/run/docker.sock ]; then
- (
- set -x
- $sh_c 'docker version'
- ) || true
+ cat >&2 <<-'EOF'
+ Error: this installer needs the ability to run commands as root.
+ We are unable to find either "sudo" or "su" available to make this happen.
+ EOF
+ exit 1
fi
- your_user=your-user
- [ "$user" != 'root' ] && your_user="$user"
- echo
- echo 'If you would like to use Docker as a non-root user, you should now consider'
- echo 'adding your user to the "docker" group with something like:'
- echo
- echo ' sudo usermod -aG docker' $your_user
- echo
- echo 'Remember that you will have to log out and back in for this to take effect!'
- echo
- exit 0
- ;;
-
- ubuntu|debian|linuxmint)
- export DEBIAN_FRONTEND=noninteractive
-
- did_apt_get_update=
- apt_get_update() {
- if [ -z "$did_apt_get_update" ]; then
- ( set -x; $sh_c 'sleep 3; apt-get update' )
- did_apt_get_update=1
- fi
- }
+ fi
- # aufs is preferred over devicemapper; try to ensure the driver is available.
- if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then
- if uname -r | grep -q -- '-generic' && dpkg -l 'linux-image-*-generic' | grep -q '^ii' 2>/dev/null; then
- kern_extras="linux-image-extra-$(uname -r) linux-image-extra-virtual"
+ curl=''
+ if command_exists curl; then
+ curl='curl -sSL'
+ elif command_exists wget; then
+ curl='wget -qO-'
+ elif command_exists busybox && busybox --list-modules | grep -q wget; then
+ curl='busybox wget -qO-'
+ fi
- apt_get_update
- ( set -x; $sh_c 'sleep 3; apt-get install -y -q '"$kern_extras" ) || true
+ # perform some very rudimentary platform detection
+ lsb_dist=''
+ if command_exists lsb_release; then
+ lsb_dist="$(lsb_release -si)"
+ fi
+ if [ -z "$lsb_dist" ] && [ -r /etc/lsb-release ]; then
+ lsb_dist="$(. /etc/lsb-release && echo "$DISTRIB_ID")"
+ fi
+ if [ -z "$lsb_dist" ] && [ -r /etc/debian_version ]; then
+ lsb_dist='debian'
+ fi
+ if [ -z "$lsb_dist" ] && [ -r /etc/fedora-release ]; then
+ lsb_dist='fedora'
+ fi
+ if [ -z "$lsb_dist" ] && [ -r /etc/os-release ]; then
+ lsb_dist="$(. /etc/os-release && echo "$ID")"
+ fi
- if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then
- echo >&2 'Warning: tried to install '"$kern_extras"' (for AUFS)'
- echo >&2 ' but we still have no AUFS. Docker may not work. Proceeding anyways!'
+ lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')"
+ case "$lsb_dist" in
+ amzn|fedora|centos)
+ if [ "$lsb_dist" = 'amzn' ]; then
+ (
+ set -x
+ $sh_c 'sleep 3; yum -y -q install docker'
+ )
+ else
+ (
+ set -x
+ $sh_c 'sleep 3; yum -y -q install docker-io'
+ )
+ fi
+ if command_exists docker && [ -e /var/run/docker.sock ]; then
+ (
+ set -x
+ $sh_c 'docker version'
+ ) || true
+ fi
+ echo_docker_as_nonroot
+ exit 0
+ ;;
+
+ ubuntu|debian|linuxmint|'elementary os'|kali)
+ export DEBIAN_FRONTEND=noninteractive
+
+ did_apt_get_update=
+ apt_get_update() {
+ if [ -z "$did_apt_get_update" ]; then
+ ( set -x; $sh_c 'sleep 3; apt-get update' )
+ did_apt_get_update=1
+ fi
+ }
+
+ # aufs is preferred over devicemapper; try to ensure the driver is available.
+ if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then
+ if uname -r | grep -q -- '-generic' && dpkg -l 'linux-image-*-generic' | grep -q '^ii' 2>/dev/null; then
+ kern_extras="linux-image-extra-$(uname -r) linux-image-extra-virtual"
+
+ apt_get_update
+ ( set -x; $sh_c 'sleep 3; apt-get install -y -q '"$kern_extras" ) || true
+
+ if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then
+ echo >&2 'Warning: tried to install '"$kern_extras"' (for AUFS)'
+ echo >&2 ' but we still have no AUFS. Docker may not work. Proceeding anyways!'
+ ( set -x; sleep 10 )
+ fi
+ else
+ echo >&2 'Warning: current kernel is not supported by the linux-image-extra-virtual'
+ echo >&2 ' package. We have no AUFS support. Consider installing the packages'
+ echo >&2 ' linux-image-virtual kernel and linux-image-extra-virtual for AUFS support.'
( set -x; sleep 10 )
fi
- else
- echo >&2 'Warning: current kernel is not supported by the linux-image-extra-virtual'
- echo >&2 ' package. We have no AUFS support. Consider installing the packages'
- echo >&2 ' linux-image-virtual kernel and linux-image-extra-virtual for AUFS support.'
- ( set -x; sleep 10 )
fi
- fi
- # install apparmor utils if they're missing and apparmor is enabled in the kernel
- # otherwise Docker will fail to start
- if [ "$(cat /sys/module/apparmor/parameters/enabled 2>/dev/null)" = 'Y' ]; then
- if command -v apparmor_parser &> /dev/null; then
- echo 'apparmor is enabled in the kernel and apparmor utils were already installed'
- else
- echo 'apparmor is enabled in the kernel, but apparmor_parser missing'
+ # install apparmor utils if they're missing and apparmor is enabled in the kernel
+ # otherwise Docker will fail to start
+ if [ "$(cat /sys/module/apparmor/parameters/enabled 2>/dev/null)" = 'Y' ]; then
+ if command -v apparmor_parser &> /dev/null; then
+ echo 'apparmor is enabled in the kernel and apparmor utils were already installed'
+ else
+ echo 'apparmor is enabled in the kernel, but apparmor_parser missing'
+ apt_get_update
+ ( set -x; $sh_c 'sleep 3; apt-get install -y -q apparmor' )
+ fi
+ fi
+
+ if [ ! -e /usr/lib/apt/methods/https ]; then
apt_get_update
- ( set -x; $sh_c 'sleep 3; apt-get install -y -q apparmor' )
+ ( set -x; $sh_c 'sleep 3; apt-get install -y -q apt-transport-https ca-certificates' )
fi
- fi
+ if [ -z "$curl" ]; then
+ apt_get_update
+ ( set -x; $sh_c 'sleep 3; apt-get install -y -q curl ca-certificates' )
+ curl='curl -sSL'
+ fi
+ (
+ set -x
+ if [ "https://get.docker.com/" = "$url" ]; then
+ $sh_c "apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9"
+ elif [ "https://test.docker.com/" = "$url" ]; then
+ $sh_c "apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 740B314AE3941731B942C66ADF4FD13717AAD7D6"
+ else
+ $sh_c "$curl ${url}gpg | apt-key add -"
+ fi
+ $sh_c "echo deb ${url}ubuntu docker main > /etc/apt/sources.list.d/docker.list"
+ $sh_c 'sleep 3; apt-get update; apt-get install -y -q lxc-docker'
+ )
+ if command_exists docker && [ -e /var/run/docker.sock ]; then
+ (
+ set -x
+ $sh_c 'docker version'
+ ) || true
+ fi
+ echo_docker_as_nonroot
+ exit 0
+ ;;
- if [ ! -e /usr/lib/apt/methods/https ]; then
- apt_get_update
- ( set -x; $sh_c 'sleep 3; apt-get install -y -q apt-transport-https ca-certificates' )
- fi
- if [ -z "$curl" ]; then
- apt_get_update
- ( set -x; $sh_c 'sleep 3; apt-get install -y -q curl ca-certificates' )
- curl='curl -sSL'
- fi
- (
- set -x
- if [ "https://get.docker.com/" = "$url" ]; then
- $sh_c "apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9"
- elif [ "https://test.docker.com/" = "$url" ]; then
- $sh_c "apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 740B314AE3941731B942C66ADF4FD13717AAD7D6"
- else
- $sh_c "$curl ${url}gpg | apt-key add -"
+ gentoo)
+ if [ "$url" = "https://test.docker.com/" ]; then
+ # intentionally mixed spaces and tabs here -- tabs are stripped by "<<-'EOF'", spaces are kept in the output
+ cat >&2 <<-'EOF'
+
+ You appear to be trying to install the latest nightly build in Gentoo.'
+ The portage tree should contain the latest stable release of Docker, but'
+ if you want something more recent, you can always use the live ebuild'
+ provided in the "docker" overlay available via layman. For more'
+ instructions, please see the following URL:'
+
+ https://github.com/tianon/docker-overlay#using-this-overlay'
+
+ After adding the "docker" overlay, you should be able to:'
+
+ emerge -av =app-emulation/docker-9999'
+
+ EOF
+ exit 1
fi
- $sh_c "echo deb ${url}ubuntu docker main > /etc/apt/sources.list.d/docker.list"
- $sh_c 'sleep 3; apt-get update; apt-get install -y -q lxc-docker'
- )
- if command_exists docker && [ -e /var/run/docker.sock ]; then
+
(
set -x
- $sh_c 'docker version'
- ) || true
- fi
- your_user=your-user
- [ "$user" != 'root' ] && your_user="$user"
- echo
- echo 'If you would like to use Docker as a non-root user, you should now consider'
- echo 'adding your user to the "docker" group with something like:'
- echo
- echo ' sudo usermod -aG docker' $your_user
- echo
- echo 'Remember that you will have to log out and back in for this to take effect!'
- echo
- exit 0
- ;;
-
- gentoo)
- if [ "$url" = "https://test.docker.com/" ]; then
- echo >&2
- echo >&2 ' You appear to be trying to install the latest nightly build in Gentoo.'
- echo >&2 ' The portage tree should contain the latest stable release of Docker, but'
- echo >&2 ' if you want something more recent, you can always use the live ebuild'
- echo >&2 ' provided in the "docker" overlay available via layman. For more'
- echo >&2 ' instructions, please see the following URL:'
- echo >&2 ' https://github.com/tianon/docker-overlay#using-this-overlay'
- echo >&2 ' After adding the "docker" overlay, you should be able to:'
- echo >&2 ' emerge -av =app-emulation/docker-9999'
- echo >&2
- exit 1
- fi
+ $sh_c 'sleep 3; emerge app-emulation/docker'
+ )
+ exit 0
+ ;;
+ esac
- (
- set -x
- $sh_c 'sleep 3; emerge app-emulation/docker'
- )
- exit 0
- ;;
-esac
+ # intentionally mixed spaces and tabs here -- tabs are stripped by "<<-'EOF'", spaces are kept in the output
+ cat >&2 <<-'EOF'
-cat >&2 <<'EOF'
+ Either your platform is not easily detectable, is not supported by this
+ installer script (yet - PRs welcome! [hack/install.sh]), or does not yet have
+ a package for Docker. Please visit the following URL for more detailed
+ installation instructions:
- Either your platform is not easily detectable, is not supported by this
- installer script (yet - PRs welcome! [hack/install.sh]), or does not yet have
- a package for Docker. Please visit the following URL for more detailed
- installation instructions:
+ https://docs.docker.com/en/latest/installation/
- https://docs.docker.com/en/latest/installation/
+ EOF
+ exit 1
+}
-EOF
-exit 1
+# wrapped up in a function so that we have some protection against only getting
+# half the file during "curl | sh"
+do_install
diff --git a/hack/make.sh b/hack/make.sh
index 4117469d6640f..31e08cd37618a 100755
--- a/hack/make.sh
+++ b/hack/make.sh
@@ -6,7 +6,7 @@ set -e
#
# Requirements:
# - The current directory should be a checkout of the docker source code
-# (http://github.com/docker/docker). Whatever version is checked out
+# (https://github.com/docker/docker). Whatever version is checked out
# will be built.
# - The VERSION file, at the root of the repository, should exist, and
# will be used as Docker binary version and package version.
@@ -24,10 +24,12 @@ set -e
set -o pipefail
export DOCKER_PKG='github.com/docker/docker'
+export SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+export MAKEDIR="$SCRIPTDIR/make"
# We're a nice, sexy, little shell script, and people might try to run us;
# but really, they shouldn't. We want to be in a container!
-if [ "$(pwd)" != "/go/src/$DOCKER_PKG" ] || [ -z "$DOCKER_CROSSPLATFORMS" ]; then
+if [ "$PWD" != "/go/src/$DOCKER_PKG" ] || [ -z "$DOCKER_CROSSPLATFORMS" ]; then
{
echo "# WARNING! I don't seem to be running in the Docker container."
echo "# The result of this command might be an incorrect build, and will not be"
@@ -44,7 +46,9 @@ echo
DEFAULT_BUNDLES=(
validate-dco
validate-gofmt
+ validate-test
validate-toml
+ validate-vet
binary
@@ -61,7 +65,7 @@ DEFAULT_BUNDLES=(
ubuntu
)
-VERSION=$(cat ./VERSION)
+VERSION=$(< ./VERSION)
if command -v git &> /dev/null && git rev-parse &> /dev/null; then
GITCOMMIT=$(git rev-parse --short HEAD)
if [ -n "$(git status --porcelain --untracked-files=no)" ]; then
@@ -81,11 +85,11 @@ if [ "$AUTO_GOPATH" ]; then
rm -rf .gopath
mkdir -p .gopath/src/"$(dirname "${DOCKER_PKG}")"
ln -sf ../../../.. .gopath/src/"${DOCKER_PKG}"
- export GOPATH="$(pwd)/.gopath:$(pwd)/vendor"
+ export GOPATH="${PWD}/.gopath:${PWD}/vendor"
fi
if [ ! "$GOPATH" ]; then
- echo >&2 'error: missing GOPATH; please see http://golang.org/doc/code.html#GOPATH'
+ echo >&2 'error: missing GOPATH; please see https://golang.org/doc/code.html#GOPATH'
echo >&2 ' alternatively, set AUTO_GOPATH=1'
exit 1
fi
@@ -109,7 +113,7 @@ fi
# Use these flags when compiling the tests and final binary
IAMSTATIC='true'
-source "$(dirname "$BASH_SOURCE")/make/.go-autogen"
+source "$SCRIPTDIR/make/.go-autogen"
LDFLAGS='-w'
LDFLAGS_STATIC='-linkmode external'
@@ -250,7 +254,7 @@ bundle() {
bundlescript=$1
bundle=$(basename $bundlescript)
echo "---> Making bundle: $bundle (in bundles/$VERSION/$bundle)"
- mkdir -p bundles/$VERSION/$bundle
+ mkdir -p "bundles/$VERSION/$bundle"
source "$bundlescript" "$(pwd)/bundles/$VERSION/$bundle"
}
@@ -260,17 +264,22 @@ main() {
mkdir -p bundles
if [ -e "bundles/$VERSION" ]; then
echo "bundles/$VERSION already exists. Removing."
- rm -fr bundles/$VERSION && mkdir bundles/$VERSION || exit 1
+ rm -fr "bundles/$VERSION" && mkdir "bundles/$VERSION" || exit 1
echo
fi
- SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+ if [ "$(go env GOHOSTOS)" != 'windows' ]; then
+ # Windows and symlinks don't get along well
+ ln -sfT "$VERSION" bundles/latest
+ fi
+
if [ $# -lt 1 ]; then
bundles=(${DEFAULT_BUNDLES[@]})
else
bundles=($@)
fi
for bundle in ${bundles[@]}; do
- bundle $SCRIPTDIR/make/$bundle
+ bundle "$SCRIPTDIR/make/$bundle"
echo
done
}
diff --git a/hack/make/.build-deb/compat b/hack/make/.build-deb/compat
new file mode 100644
index 0000000000000..ec635144f6004
--- /dev/null
+++ b/hack/make/.build-deb/compat
@@ -0,0 +1 @@
+9
diff --git a/hack/make/.build-deb/control b/hack/make/.build-deb/control
new file mode 100644
index 0000000000000..03caae8342a9e
--- /dev/null
+++ b/hack/make/.build-deb/control
@@ -0,0 +1,27 @@
+Source: docker-core
+Maintainer: Docker
+Homepage: https://dockerproject.com
+Vcs-Browser: https://github.com/docker/docker
+Vcs-Git: git://github.com/docker/docker.git
+
+Package: docker-core
+Architecture: linux-any
+Depends: iptables, ${misc:Depends}, ${perl:Depends}, ${shlibs:Depends}
+Recommends: aufs-tools,
+ ca-certificates,
+ cgroupfs-mount | cgroup-lite,
+ git,
+ xz-utils,
+ ${apparmor:Recommends}
+Conflicts: docker (<< 1.5~), docker.io, lxc-docker, lxc-docker-virtual-package
+Description: Docker: the open-source application container engine
+ Docker is an open source project to pack, ship and run any application as a
+ lightweight container
+ .
+ Docker containers are both hardware-agnostic and platform-agnostic. This means
+ they can run anywhere, from your laptop to the largest EC2 compute instance and
+ they can run anywhere, from your laptop to the largest EC2 compute instance and
+ everything in between - and they don't require you to use a particular
+ language, framework or packaging system. That makes them great building blocks
+ for deploying and scaling web apps, databases, and backend services without
+ depending on a particular stack or provider.
diff --git a/hack/make/.build-deb/docker-core.bash-completion b/hack/make/.build-deb/docker-core.bash-completion
new file mode 100644
index 0000000000000..6ea111930886d
--- /dev/null
+++ b/hack/make/.build-deb/docker-core.bash-completion
@@ -0,0 +1 @@
+contrib/completion/bash/docker
diff --git a/hack/make/.build-deb/docker-core.docker.default b/hack/make/.build-deb/docker-core.docker.default
new file mode 120000
index 0000000000000..4278533d65967
--- /dev/null
+++ b/hack/make/.build-deb/docker-core.docker.default
@@ -0,0 +1 @@
+../../../contrib/init/sysvinit-debian/docker.default
\ No newline at end of file
diff --git a/hack/make/.build-deb/docker-core.docker.init b/hack/make/.build-deb/docker-core.docker.init
new file mode 120000
index 0000000000000..8cb89d30dde93
--- /dev/null
+++ b/hack/make/.build-deb/docker-core.docker.init
@@ -0,0 +1 @@
+../../../contrib/init/sysvinit-debian/docker
\ No newline at end of file
diff --git a/hack/make/.build-deb/docker-core.docker.upstart b/hack/make/.build-deb/docker-core.docker.upstart
new file mode 120000
index 0000000000000..7e1b64a3e640a
--- /dev/null
+++ b/hack/make/.build-deb/docker-core.docker.upstart
@@ -0,0 +1 @@
+../../../contrib/init/upstart/docker.conf
\ No newline at end of file
diff --git a/hack/make/.build-deb/docker-core.install b/hack/make/.build-deb/docker-core.install
new file mode 100644
index 0000000000000..c3f4eb146574d
--- /dev/null
+++ b/hack/make/.build-deb/docker-core.install
@@ -0,0 +1,10 @@
+#contrib/syntax/vim/doc/* /usr/share/vim/vimfiles/doc/
+#contrib/syntax/vim/ftdetect/* /usr/share/vim/vimfiles/ftdetect/
+#contrib/syntax/vim/syntax/* /usr/share/vim/vimfiles/syntax/
+contrib/*-integration usr/share/docker-core/contrib/
+contrib/check-config.sh usr/share/docker-core/contrib/
+contrib/completion/zsh/_docker usr/share/zsh/vendor-completions/
+contrib/init/systemd/docker.service lib/systemd/system/
+contrib/init/systemd/docker.socket lib/systemd/system/
+contrib/mk* usr/share/docker-core/contrib/
+contrib/nuke-graph-directory.sh usr/share/docker-core/contrib/
diff --git a/hack/make/.build-deb/docker-core.manpages b/hack/make/.build-deb/docker-core.manpages
new file mode 100644
index 0000000000000..d5cff8a479fa3
--- /dev/null
+++ b/hack/make/.build-deb/docker-core.manpages
@@ -0,0 +1 @@
+docs/man/man*/*
diff --git a/hack/make/.build-deb/docker-core.postinst b/hack/make/.build-deb/docker-core.postinst
new file mode 100644
index 0000000000000..eeef6ca801605
--- /dev/null
+++ b/hack/make/.build-deb/docker-core.postinst
@@ -0,0 +1,20 @@
+#!/bin/sh
+set -e
+
+case "$1" in
+ configure)
+ if [ -z "$2" ]; then
+ if ! getent group docker > /dev/null; then
+ groupadd --system docker
+ fi
+ fi
+ ;;
+ abort-*)
+ # How'd we get here??
+ exit 1
+ ;;
+ *)
+ ;;
+esac
+
+#DEBHELPER#
diff --git a/hack/make/.build-deb/docker-core.udev b/hack/make/.build-deb/docker-core.udev
new file mode 120000
index 0000000000000..914a361959de3
--- /dev/null
+++ b/hack/make/.build-deb/docker-core.udev
@@ -0,0 +1 @@
+../../../contrib/udev/80-docker.rules
\ No newline at end of file
diff --git a/hack/make/.build-deb/docs b/hack/make/.build-deb/docs
new file mode 100644
index 0000000000000..b43bf86b50fd8
--- /dev/null
+++ b/hack/make/.build-deb/docs
@@ -0,0 +1 @@
+README.md
diff --git a/hack/make/.build-deb/rules b/hack/make/.build-deb/rules
new file mode 100755
index 0000000000000..3369f4fc54286
--- /dev/null
+++ b/hack/make/.build-deb/rules
@@ -0,0 +1,36 @@
+#!/usr/bin/make -f
+
+VERSION = $(shell cat VERSION)
+
+override_dh_gencontrol:
+ # if we're on Ubuntu, we need to Recommends: apparmor
+ echo 'apparmor:Recommends=$(shell dpkg-vendor --is Ubuntu && echo apparmor)' >> debian/docker-core.substvars
+ dh_gencontrol
+
+override_dh_auto_build:
+ ./hack/make.sh dynbinary
+ # ./docs/man/md2man-all.sh runs outside the build container (if at all), since we don't have go-md2man here
+
+override_dh_auto_test:
+ ./bundles/$(VERSION)/dynbinary/docker -v
+
+override_dh_strip:
+ # the SHA1 of dockerinit is important: don't strip it
+ # also, Go has lots of problems with stripping, so just don't
+
+override_dh_auto_install:
+ mkdir -p debian/docker-core/usr/bin
+ cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary/docker)" debian/docker-core/usr/bin/docker
+ mkdir -p debian/docker-core/usr/libexec/docker
+ cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary/dockerinit)" debian/docker-core/usr/libexec/docker/dockerinit
+
+override_dh_installinit:
+ # use "docker" as our service name, not "docker-core"
+ dh_installinit --name=docker
+
+override_dh_installudev:
+ # match our existing priority
+ dh_installudev --priority=z80
+
+%:
+ dh $@ --with=systemd,bash-completion
diff --git a/hack/make/.dockerinit b/hack/make/.dockerinit
index fceba7db920bb..4a62ee1addc36 100644
--- a/hack/make/.dockerinit
+++ b/hack/make/.dockerinit
@@ -2,7 +2,7 @@
set -e
IAMSTATIC="true"
-source "$(dirname "$BASH_SOURCE")/.go-autogen"
+source "${MAKEDIR}/.go-autogen"
# dockerinit still needs to be a static binary, even if docker is dynamic
go build \
@@ -30,4 +30,4 @@ else
fi
# sha1 our new dockerinit to ensure separate docker and dockerinit always run in a perfect pair compiled for one another
-export DOCKER_INITSHA1="$($sha1sum $DEST/dockerinit-$VERSION | cut -d' ' -f1)"
+export DOCKER_INITSHA1=$($sha1sum "$DEST/dockerinit-$VERSION" | cut -d' ' -f1)
diff --git a/hack/make/.dockerinit-gccgo b/hack/make/.dockerinit-gccgo
index 592a4152c857e..9890863841f23 100644
--- a/hack/make/.dockerinit-gccgo
+++ b/hack/make/.dockerinit-gccgo
@@ -2,7 +2,7 @@
set -e
IAMSTATIC="true"
-source "$(dirname "$BASH_SOURCE")/.go-autogen"
+source "${MAKEDIR}/.go-autogen"
# dockerinit still needs to be a static binary, even if docker is dynamic
go build --compiler=gccgo \
@@ -12,6 +12,7 @@ go build --compiler=gccgo \
-g
-Wl,--no-export-dynamic
$EXTLDFLAGS_STATIC_DOCKER
+ -lnetgo
" \
./dockerinit
@@ -27,4 +28,4 @@ else
fi
# sha1 our new dockerinit to ensure separate docker and dockerinit always run in a perfect pair compiled for one another
-export DOCKER_INITSHA1="$($sha1sum $DEST/dockerinit-$VERSION | cut -d' ' -f1)"
+export DOCKER_INITSHA1=$($sha1sum "$DEST/dockerinit-$VERSION" | cut -d' ' -f1)
diff --git a/hack/make/.integration-daemon-start b/hack/make/.integration-daemon-start
index 570c6c7a9af9f..57fd525028e74 100644
--- a/hack/make/.integration-daemon-start
+++ b/hack/make/.integration-daemon-start
@@ -25,6 +25,7 @@ if [ -z "$DOCKER_TEST_HOST" ]; then
--pidfile "$DEST/docker.pid" \
&> "$DEST/docker.log"
) &
+ trap "source '${MAKEDIR}/.integration-daemon-stop'" EXIT # make sure that if the script exits unexpectedly, we stop this daemon we just started
else
export DOCKER_HOST="$DOCKER_TEST_HOST"
fi
diff --git a/hack/make/.integration-daemon-stop b/hack/make/.integration-daemon-stop
index 319aaa4a1db54..6e1dc844def89 100644
--- a/hack/make/.integration-daemon-stop
+++ b/hack/make/.integration-daemon-stop
@@ -1,9 +1,11 @@
#!/bin/bash
+trap - EXIT # reset EXIT trap applied in .integration-daemon-start
+
for pidFile in $(find "$DEST" -name docker.pid); do
pid=$(set -x; cat "$pidFile")
- ( set -x; kill $pid )
- if ! wait $pid; then
+ ( set -x; kill "$pid" )
+ if ! wait "$pid"; then
echo >&2 "warning: PID $pid from $pidFile had a nonzero exit code"
fi
done
diff --git a/hack/make/binary b/hack/make/binary
index 0f57ea0d693e8..d3ec2939c00ca 100644
--- a/hack/make/binary
+++ b/hack/make/binary
@@ -11,7 +11,7 @@ if [[ "$(uname -s)" == CYGWIN* ]]; then
DEST=$(cygpath -mw $DEST)
fi
-source "$(dirname "$BASH_SOURCE")/.go-autogen"
+source "${MAKEDIR}/.go-autogen"
go build \
-o "$DEST/$BINARY_FULLNAME" \
diff --git a/hack/make/build-deb b/hack/make/build-deb
new file mode 100644
index 0000000000000..a5a6d43870b38
--- /dev/null
+++ b/hack/make/build-deb
@@ -0,0 +1,70 @@
+#!/bin/bash
+set -e
+
+DEST=$1
+
+# subshell so that we can export PATH without breaking other things
+(
+ source "${MAKEDIR}/.integration-daemon-start"
+
+ # TODO consider using frozen images for the dockercore/builder-deb tags
+
+ debVersion="${VERSION//-/'~'}"
+ # if we have a "-dev" suffix or have change in Git, let's make this package version more complex so it works better
+ if [[ "$VERSION" == *-dev ]] || [ -n "$(git status --porcelain)" ]; then
+ gitUnix="$(git log -1 --pretty='%at')"
+ gitDate="$(date --date "@$gitUnix" +'%Y%m%d.%H%M%S')"
+ gitCommit="$(git log -1 --pretty='%h')"
+ gitVersion="git${gitDate}.0.${gitCommit}"
+ # gitVersion is now something like 'git20150128.112847.0.17e840a'
+ debVersion="$debVersion~$gitVersion"
+
+ # $ dpkg --compare-versions 1.5.0 gt 1.5.0~rc1 && echo true || echo false
+ # true
+ # $ dpkg --compare-versions 1.5.0~rc1 gt 1.5.0~git20150128.112847.17e840a && echo true || echo false
+ # true
+ # $ dpkg --compare-versions 1.5.0~git20150128.112847.17e840a gt 1.5.0~dev~git20150128.112847.17e840a && echo true || echo false
+ # true
+
+ # ie, 1.5.0 > 1.5.0~rc1 > 1.5.0~git20150128.112847.17e840a > 1.5.0~dev~git20150128.112847.17e840a
+ fi
+
+ debSource="$(awk -F ': ' '$1 == "Source" { print $2; exit }' hack/make/.build-deb/control)"
+ debMaintainer="$(awk -F ': ' '$1 == "Maintainer" { print $2; exit }' hack/make/.build-deb/control)"
+ debDate="$(date --rfc-2822)"
+
+ # if go-md2man is available, pre-generate the man pages
+ ./docs/man/md2man-all.sh -q || true
+ # TODO decide if it's worth getting go-md2man in _each_ builder environment to avoid this
+
+ # TODO add a configurable knob for _which_ debs to build so we don't have to modify the file or build all of them every time we need to test
+ for dir in contrib/builder/deb/*/; do
+ version="$(basename "$dir")"
+ suite="${version##*-}"
+
+ image="dockercore/builder-deb:$version"
+ if ! docker inspect "$image" &> /dev/null; then
+ ( set -x && docker build -t "$image" "$dir" )
+ fi
+
+ mkdir -p "$DEST/$version"
+ cat > "$DEST/$version/Dockerfile.build" <<-EOF
+ FROM $image
+ WORKDIR /usr/src/docker
+ COPY . /usr/src/docker
+ RUN ln -sfv hack/make/.build-deb debian
+ RUN { echo '$debSource (${debVersion}-0~${suite}) $suite; urgency=low'; echo; echo ' * Version: $VERSION'; echo; echo " -- $debMaintainer $debDate"; } > debian/changelog && cat >&2 debian/changelog
+ RUN dpkg-buildpackage -uc -us
+ EOF
+ cp -a "$DEST/$version/Dockerfile.build" . # can't use $DEST because it's in .dockerignore...
+ tempImage="docker-temp/build-deb:$version"
+ ( set -x && docker build -t "$tempImage" -f Dockerfile.build . )
+ docker run --rm "$tempImage" bash -c 'cd .. && tar -c *_*' | tar -xvC "$DEST/$version"
+ docker rmi "$tempImage"
+ done
+
+ # clean up after ourselves
+ rm -f Dockerfile.build
+
+ source "${MAKEDIR}/.integration-daemon-stop"
+) 2>&1 | tee -a "$DEST/test.log"
diff --git a/hack/make/cross b/hack/make/cross
index 3c5cb0401dc7f..368ebc5ab970a 100644
--- a/hack/make/cross
+++ b/hack/make/cross
@@ -28,6 +28,6 @@ for platform in $DOCKER_CROSSPLATFORMS; do
export LDFLAGS_STATIC_DOCKER="" # we just need a simple client for these platforms
export BUILDFLAGS=( "${ORIG_BUILDFLAGS[@]/ daemon/}" ) # remove the "daemon" build tag from platforms that aren't supported
fi
- source "$(dirname "$BASH_SOURCE")/binary" "$DEST/$platform"
+ source "${MAKEDIR}/binary" "$DEST/$platform"
)
done
diff --git a/hack/make/dynbinary b/hack/make/dynbinary
index f9b43b0e77773..e1b65b48efc41 100644
--- a/hack/make/dynbinary
+++ b/hack/make/dynbinary
@@ -4,7 +4,7 @@ set -e
DEST=$1
if [ -z "$DOCKER_CLIENTONLY" ]; then
- source "$(dirname "$BASH_SOURCE")/.dockerinit"
+ source "${MAKEDIR}/.dockerinit"
hash_files "$DEST/dockerinit-$VERSION"
else
@@ -18,5 +18,5 @@ fi
export LDFLAGS_STATIC_DOCKER=''
export BUILDFLAGS=( "${BUILDFLAGS[@]/netgo /}" ) # disable netgo, since we don't need it for a dynamic binary
export BUILDFLAGS=( "${BUILDFLAGS[@]/static_build /}" ) # we're not building a "static" binary here
- source "$(dirname "$BASH_SOURCE")/binary"
+ source "${MAKEDIR}/binary"
)
diff --git a/hack/make/dyngccgo b/hack/make/dyngccgo
index 738e1450ac511..7bdd404f10573 100644
--- a/hack/make/dyngccgo
+++ b/hack/make/dyngccgo
@@ -4,7 +4,7 @@ set -e
DEST=$1
if [ -z "$DOCKER_CLIENTONLY" ]; then
- source "$(dirname "$BASH_SOURCE")/.dockerinit-gccgo"
+ source "${MAKEDIR}/.dockerinit-gccgo"
hash_files "$DEST/dockerinit-$VERSION"
else
@@ -19,5 +19,5 @@ fi
export LDFLAGS_STATIC_DOCKER=''
export BUILDFLAGS=( "${BUILDFLAGS[@]/netgo /}" ) # disable netgo, since we don't need it for a dynamic binary
export BUILDFLAGS=( "${BUILDFLAGS[@]/static_build /}" ) # we're not building a "static" binary here
- source "$(dirname "$BASH_SOURCE")/gccgo"
+ source "${MAKEDIR}/gccgo"
)
diff --git a/hack/make/gccgo b/hack/make/gccgo
index c85d2fbda55d2..896c2d46c1bc6 100644
--- a/hack/make/gccgo
+++ b/hack/make/gccgo
@@ -6,8 +6,11 @@ BINARY_NAME="docker-$VERSION"
BINARY_EXTENSION="$(binary_extension)"
BINARY_FULLNAME="$BINARY_NAME$BINARY_EXTENSION"
-source "$(dirname "$BASH_SOURCE")/.go-autogen"
+source "${MAKEDIR}/.go-autogen"
+if [[ "${BUILDFLAGS[@]}" =~ 'netgo ' ]]; then
+ EXTLDFLAGS_STATIC_DOCKER+=' -lnetgo'
+fi
go build -compiler=gccgo \
-o "$DEST/$BINARY_FULLNAME" \
"${BUILDFLAGS[@]}" \
diff --git a/hack/make/test-docker-py b/hack/make/test-docker-py
index b95cf40af511d..ac5ef3583344c 100644
--- a/hack/make/test-docker-py
+++ b/hack/make/test-docker-py
@@ -5,26 +5,16 @@ DEST=$1
# subshell so that we can export PATH without breaking other things
(
- source "$(dirname "$BASH_SOURCE")/.integration-daemon-start"
+ source "${MAKEDIR}/.integration-daemon-start"
- # we need to wrap up everything in between integration-daemon-start and
- # integration-daemon-stop to make sure we kill the daemon and don't hang,
- # even and especially on test failures
- didFail=
- if ! {
- dockerPy='/docker-py'
- [ -d "$dockerPy" ] || {
- dockerPy="$DEST/docker-py"
- git clone https://github.com/docker/docker-py.git "$dockerPy"
- }
+ dockerPy='/docker-py'
+ [ -d "$dockerPy" ] || {
+ dockerPy="$DEST/docker-py"
+ git clone https://github.com/docker/docker-py.git "$dockerPy"
+ }
- # exporting PYTHONPATH to import "docker" from our local docker-py
- test_env PYTHONPATH="$dockerPy" python "$dockerPy/tests/integration_test.py"
- }; then
- didFail=1
- fi
+ # exporting PYTHONPATH to import "docker" from our local docker-py
+ test_env PYTHONPATH="$dockerPy" python "$dockerPy/tests/integration_test.py"
- source "$(dirname "$BASH_SOURCE")/.integration-daemon-stop"
-
- [ -z "$didFail" ] # "set -e" ftw
-) 2>&1 | tee -a $DEST/test.log
+ source "${MAKEDIR}/.integration-daemon-stop"
+) 2>&1 | tee -a "$DEST/test.log"
diff --git a/hack/make/test-integration b/hack/make/test-integration
index 5cb7102bc8e1d..206e37abf0c4e 100644
--- a/hack/make/test-integration
+++ b/hack/make/test-integration
@@ -5,7 +5,7 @@ DEST=$1
INIT=$DEST/../dynbinary/dockerinit-$VERSION
[ -x "$INIT" ] || {
- source "$(dirname "$BASH_SOURCE")/.dockerinit"
+ source "${MAKEDIR}/.dockerinit"
INIT="$DEST/dockerinit"
}
export TEST_DOCKERINIT_PATH="$INIT"
@@ -22,4 +22,4 @@ bundle_test_integration() {
# spews when it is given packages that aren't used
bundle_test_integration 2>&1 \
| grep --line-buffered -v '^warning: no packages being tested depend on ' \
- | tee -a $DEST/test.log
+ | tee -a "$DEST/test.log"
diff --git a/hack/make/test-integration-cli b/hack/make/test-integration-cli
index 3ef41d919e55a..db1cb298fd592 100644
--- a/hack/make/test-integration-cli
+++ b/hack/make/test-integration-cli
@@ -9,23 +9,13 @@ bundle_test_integration_cli() {
# subshell so that we can export PATH without breaking other things
(
- source "$(dirname "$BASH_SOURCE")/.integration-daemon-start"
+ source "${MAKEDIR}/.integration-daemon-start"
- # we need to wrap up everything in between integration-daemon-start and
- # integration-daemon-stop to make sure we kill the daemon and don't hang,
- # even and especially on test failures
- didFail=
- if ! {
- source "$(dirname "$BASH_SOURCE")/.ensure-frozen-images"
- source "$(dirname "$BASH_SOURCE")/.ensure-httpserver"
- source "$(dirname "$BASH_SOURCE")/.ensure-emptyfs"
+ source "${MAKEDIR}/.ensure-frozen-images"
+ source "${MAKEDIR}/.ensure-httpserver"
+ source "${MAKEDIR}/.ensure-emptyfs"
- bundle_test_integration_cli
- }; then
- didFail=1
- fi
+ bundle_test_integration_cli
- source "$(dirname "$BASH_SOURCE")/.integration-daemon-stop"
-
- [ -z "$didFail" ] # "set -e" ftw
-) 2>&1 | tee -a $DEST/test.log
+ source "${MAKEDIR}/.integration-daemon-stop"
+) 2>&1 | tee -a "$DEST/test.log"
diff --git a/hack/make/test-unit b/hack/make/test-unit
index 7a26428201276..7b6ce089e2cdb 100644
--- a/hack/make/test-unit
+++ b/hack/make/test-unit
@@ -39,12 +39,12 @@ bundle_test_unit() {
mkdir -p "$HOME/.parallel"
touch "$HOME/.parallel/ignored_vars"
- echo "$TESTDIRS" | parallel --jobs "$PARALLEL_JOBS" --env _ "$(dirname "$BASH_SOURCE")/.go-compile-test-dir"
+ echo "$TESTDIRS" | parallel --jobs "$PARALLEL_JOBS" --env _ "${MAKEDIR}/.go-compile-test-dir"
rm -rf "$HOME"
else
# aww, no "parallel" available - fall back to boring
for test_dir in $TESTDIRS; do
- "$(dirname "$BASH_SOURCE")/.go-compile-test-dir" "$test_dir" || true
+ "${MAKEDIR}/.go-compile-test-dir" "$test_dir" || true
# don't let one directory that fails to build tank _all_ our tests!
done
fi
@@ -85,4 +85,4 @@ go_run_test_dir() {
fi
}
-bundle_test_unit 2>&1 | tee -a $DEST/test.log
+bundle_test_unit 2>&1 | tee -a "$DEST/test.log"
diff --git a/hack/make/ubuntu b/hack/make/ubuntu
index e34369eb16383..7543789a187d9 100644
--- a/hack/make/ubuntu
+++ b/hack/make/ubuntu
@@ -23,7 +23,7 @@ fi
# ie, 1.5.0 > 1.5.0~rc1 > 1.5.0~git20150128.112847.17e840a > 1.5.0~dev~git20150128.112847.17e840a
PACKAGE_ARCHITECTURE="$(dpkg-architecture -qDEB_HOST_ARCH)"
-PACKAGE_URL="http://www.docker.com/"
+PACKAGE_URL="https://www.docker.com/"
PACKAGE_MAINTAINER="support@docker.com"
PACKAGE_DESCRIPTION="Linux container runtime
Docker complements LXC with a high-level API which operates at the process
@@ -40,26 +40,26 @@ bundle_ubuntu() {
DIR=$DEST/build
# Include our udev rules
- mkdir -p $DIR/etc/udev/rules.d
- cp contrib/udev/80-docker.rules $DIR/etc/udev/rules.d/
+ mkdir -p "$DIR/etc/udev/rules.d"
+ cp contrib/udev/80-docker.rules "$DIR/etc/udev/rules.d/"
# Include our init scripts
- mkdir -p $DIR/etc/init
- cp contrib/init/upstart/docker.conf $DIR/etc/init/
- mkdir -p $DIR/etc/init.d
- cp contrib/init/sysvinit-debian/docker $DIR/etc/init.d/
- mkdir -p $DIR/etc/default
- cp contrib/init/sysvinit-debian/docker.default $DIR/etc/default/docker
- mkdir -p $DIR/lib/systemd/system
- cp contrib/init/systemd/docker.{service,socket} $DIR/lib/systemd/system/
+ mkdir -p "$DIR/etc/init"
+ cp contrib/init/upstart/docker.conf "$DIR/etc/init/"
+ mkdir -p "$DIR/etc/init.d"
+ cp contrib/init/sysvinit-debian/docker "$DIR/etc/init.d/"
+ mkdir -p "$DIR/etc/default"
+ cp contrib/init/sysvinit-debian/docker.default "$DIR/etc/default/docker"
+ mkdir -p "$DIR/lib/systemd/system"
+ cp contrib/init/systemd/docker.{service,socket} "$DIR/lib/systemd/system/"
# Include contributed completions
- mkdir -p $DIR/etc/bash_completion.d
- cp contrib/completion/bash/docker $DIR/etc/bash_completion.d/
- mkdir -p $DIR/usr/share/zsh/vendor-completions
- cp contrib/completion/zsh/_docker $DIR/usr/share/zsh/vendor-completions/
- mkdir -p $DIR/etc/fish/completions
- cp contrib/completion/fish/docker.fish $DIR/etc/fish/completions/
+ mkdir -p "$DIR/etc/bash_completion.d"
+ cp contrib/completion/bash/docker "$DIR/etc/bash_completion.d/"
+ mkdir -p "$DIR/usr/share/zsh/vendor-completions"
+ cp contrib/completion/zsh/_docker "$DIR/usr/share/zsh/vendor-completions/"
+ mkdir -p "$DIR/etc/fish/completions"
+ cp contrib/completion/fish/docker.fish "$DIR/etc/fish/completions/"
# Include contributed man pages
docs/man/md2man-all.sh -q
@@ -76,11 +76,11 @@ bundle_ubuntu() {
# Copy the binary
# This will fail if the binary bundle hasn't been built
- mkdir -p $DIR/usr/bin
- cp $DEST/../binary/docker-$VERSION $DIR/usr/bin/docker
+ mkdir -p "$DIR/usr/bin"
+ cp "$DEST/../binary/docker-$VERSION" "$DIR/usr/bin/docker"
# Generate postinst/prerm/postrm scripts
- cat > $DEST/postinst <<'EOF'
+ cat > "$DEST/postinst" <<'EOF'
#!/bin/sh
set -e
set -u
@@ -104,7 +104,7 @@ service docker $_dh_action 2>/dev/null || true
#DEBHELPER#
EOF
- cat > $DEST/prerm <<'EOF'
+ cat > "$DEST/prerm" <<'EOF'
#!/bin/sh
set -e
set -u
@@ -113,7 +113,7 @@ service docker stop 2>/dev/null || true
#DEBHELPER#
EOF
- cat > $DEST/postrm <<'EOF'
+ cat > "$DEST/postrm" <<'EOF'
#!/bin/sh
set -e
set -u
@@ -131,18 +131,18 @@ fi
#DEBHELPER#
EOF
# TODO swaths of these were borrowed from debhelper's auto-inserted stuff, because we're still using fpm - we need to use debhelper instead, and somehow reconcile Ubuntu that way
- chmod +x $DEST/postinst $DEST/prerm $DEST/postrm
+ chmod +x "$DEST/postinst" "$DEST/prerm" "$DEST/postrm"
(
# switch directories so we create *.deb in the right folder
- cd $DEST
+ cd "$DEST"
# create lxc-docker-VERSION package
- fpm -s dir -C $DIR \
- --name lxc-docker-$VERSION --version "$PKGVERSION" \
- --after-install $DEST/postinst \
- --before-remove $DEST/prerm \
- --after-remove $DEST/postrm \
+ fpm -s dir -C "$DIR" \
+ --name "lxc-docker-$VERSION" --version "$PKGVERSION" \
+ --after-install "$DEST/postinst" \
+ --before-remove "$DEST/prerm" \
+ --after-remove "$DEST/postrm" \
--architecture "$PACKAGE_ARCHITECTURE" \
--prefix / \
--depends iptables \
@@ -184,8 +184,8 @@ EOF
)
# clean up after ourselves so we have a clean output directory
- rm $DEST/postinst $DEST/prerm $DEST/postrm
- rm -r $DIR
+ rm "$DEST/postinst" "$DEST/prerm" "$DEST/postrm"
+ rm -r "$DIR"
}
bundle_ubuntu
diff --git a/hack/make/validate-dco b/hack/make/validate-dco
index 84c47f526d1d5..5ac98728f347d 100644
--- a/hack/make/validate-dco
+++ b/hack/make/validate-dco
@@ -1,6 +1,6 @@
#!/bin/bash
-source "$(dirname "$BASH_SOURCE")/.validate"
+source "${MAKEDIR}/.validate"
adds=$(validate_diff --numstat | awk '{ s += $1 } END { print s }')
dels=$(validate_diff --numstat | awk '{ s += $2 } END { print s }')
diff --git a/hack/make/validate-gofmt b/hack/make/validate-gofmt
index 8fc88cc559dec..7ad9e85576458 100644
--- a/hack/make/validate-gofmt
+++ b/hack/make/validate-gofmt
@@ -1,6 +1,6 @@
#!/bin/bash
-source "$(dirname "$BASH_SOURCE")/.validate"
+source "${MAKEDIR}/.validate"
IFS=$'\n'
files=( $(validate_diff --diff-filter=ACMR --name-only -- '*.go' | grep -v '^vendor/' || true) )
diff --git a/hack/make/validate-test b/hack/make/validate-test
new file mode 100644
index 0000000000000..d9d05f3bea8f9
--- /dev/null
+++ b/hack/make/validate-test
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+# Make sure we're not using gos' Testing package any more in integration-cli
+
+source "${MAKEDIR}/.validate"
+
+IFS=$'\n'
+files=( $(validate_diff --diff-filter=ACMR --name-only -- 'integration-cli/*.go' || true) )
+unset IFS
+
+badFiles=()
+for f in "${files[@]}"; do
+ # skip check_test.go since it *does* use the testing package
+ if [ "$f" = "integration-cli/check_test.go" ]; then
+ continue
+ fi
+
+ # we use "git show" here to validate that what's committed is formatted
+ if git show "$VALIDATE_HEAD:$f" | grep -q testing.T; then
+ badFiles+=( "$f" )
+ fi
+done
+
+if [ ${#badFiles[@]} -eq 0 ]; then
+ echo 'Congratulations! No testing.T found.'
+else
+ {
+ echo "These files use the wrong testing infrastructure:"
+ for f in "${badFiles[@]}"; do
+ echo " - $f"
+ done
+ echo
+ } >&2
+ false
+fi
diff --git a/hack/make/validate-toml b/hack/make/validate-toml
index 16c228d14eb97..18f26ee757997 100644
--- a/hack/make/validate-toml
+++ b/hack/make/validate-toml
@@ -1,6 +1,6 @@
#!/bin/bash
-source "$(dirname "$BASH_SOURCE")/.validate"
+source "${MAKEDIR}/.validate"
IFS=$'\n'
files=( $(validate_diff --diff-filter=ACMR --name-only -- 'MAINTAINERS' || true) )
diff --git a/hack/make/validate-vet b/hack/make/validate-vet
new file mode 100644
index 0000000000000..febe93e5c1e2e
--- /dev/null
+++ b/hack/make/validate-vet
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+source "${MAKEDIR}/.validate"
+
+IFS=$'\n'
+files=( $(validate_diff --diff-filter=ACMR --name-only -- '*.go' | grep -v '^vendor/' || true) )
+unset IFS
+
+errors=()
+for f in "${files[@]}"; do
+ # we use "git show" here to validate that what's committed passes go vet
+ failedVet=$(go vet "$f")
+ if [ "$failedVet" ]; then
+ errors+=( "$failedVet" )
+ fi
+done
+
+
+if [ ${#errors[@]} -eq 0 ]; then
+ echo 'Congratulations! All Go source files have been vetted.'
+else
+ {
+ echo "Errors from go vet:"
+ for err in "${errors[@]}"; do
+ echo " - $err"
+ done
+ echo
+ echo 'Please fix the above errors. You can test via "go vet" and commit the result.'
+ echo
+ } >&2
+ false
+fi
diff --git a/hack/release.sh b/hack/release.sh
index da95808c5a198..04772546fd658 100755
--- a/hack/release.sh
+++ b/hack/release.sh
@@ -60,7 +60,7 @@ if [ "$1" != '--release-regardless-of-test-failure' ]; then
)
fi
-VERSION=$(cat VERSION)
+VERSION=$(< VERSION)
BUCKET=$AWS_S3_BUCKET
# These are the 2 keys we've used to sign the deb's
@@ -71,23 +71,23 @@ BUCKET=$AWS_S3_BUCKET
setup_s3() {
# Try creating the bucket. Ignore errors (it might already exist).
- s3cmd mb s3://$BUCKET 2>/dev/null || true
+ s3cmd mb "s3://$BUCKET" 2>/dev/null || true
# Check access to the bucket.
# s3cmd has no useful exit status, so we cannot check that.
# Instead, we check if it outputs anything on standard output.
# (When there are problems, it uses standard error instead.)
- s3cmd info s3://$BUCKET | grep -q .
+ s3cmd info "s3://$BUCKET" | grep -q .
# Make the bucket accessible through website endpoints.
- s3cmd ws-create --ws-index index --ws-error error s3://$BUCKET
+ s3cmd ws-create --ws-index index --ws-error error "s3://$BUCKET"
}
# write_to_s3 uploads the contents of standard input to the specified S3 url.
write_to_s3() {
DEST=$1
F=`mktemp`
- cat > $F
- s3cmd --acl-public --mime-type='text/plain' put $F $DEST
- rm -f $F
+ cat > "$F"
+ s3cmd --acl-public --mime-type='text/plain' put "$F" "$DEST"
+ rm -f "$F"
}
s3_url() {
@@ -246,20 +246,20 @@ release_build() {
# 1. A full APT repository is published at $BUCKET/ubuntu/
# 2. Instructions for using the APT repository are uploaded at $BUCKET/ubuntu/index
release_ubuntu() {
- [ -e bundles/$VERSION/ubuntu ] || {
+ [ -e "bundles/$VERSION/ubuntu" ] || {
echo >&2 './hack/make.sh must be run before release_ubuntu'
exit 1
}
# Sign our packages
dpkg-sig -g "--passphrase $GPG_PASSPHRASE" -k releasedocker \
- --sign builder bundles/$VERSION/ubuntu/*.deb
+ --sign builder "bundles/$VERSION/ubuntu/"*.deb
# Setup the APT repo
APTDIR=bundles/$VERSION/ubuntu/apt
- mkdir -p $APTDIR/conf $APTDIR/db
- s3cmd sync s3://$BUCKET/ubuntu/db/ $APTDIR/db/ || true
- cat > $APTDIR/conf/distributions < "$APTDIR/conf/distributions" < bundles/$VERSION/ubuntu/gpg
- s3cmd --acl-public put bundles/$VERSION/ubuntu/gpg s3://$BUCKET/gpg
+ s3cmd sync "$HOME/.gnupg/" "s3://$BUCKET/ubuntu/.gnupg/"
+ gpg --armor --export releasedocker > "bundles/$VERSION/ubuntu/gpg"
+ s3cmd --acl-public put "bundles/$VERSION/ubuntu/gpg" "s3://$BUCKET/gpg"
local gpgFingerprint=36A1D7869245C8950F966E92D8576A8BA88D21E9
if [[ $BUCKET == test* ]]; then
@@ -287,7 +287,7 @@ EOF
fi
# Upload repo
- s3cmd --acl-public sync $APTDIR/ s3://$BUCKET/ubuntu/
+ s3cmd --acl-public sync "$APTDIR/" "s3://$BUCKET/ubuntu/"
cat <&2 './hack/make.sh must be run before release_binaries'
exit 1
}
@@ -341,29 +341,29 @@ EOF
# Add redirect at /builds/info for URL-backwards-compatibility
rm -rf /tmp/emptyfile && touch /tmp/emptyfile
- s3cmd --acl-public --add-header='x-amz-website-redirect-location:/builds/' --mime-type='text/plain' put /tmp/emptyfile s3://$BUCKET/builds/info
+ s3cmd --acl-public --add-header='x-amz-website-redirect-location:/builds/' --mime-type='text/plain' put /tmp/emptyfile "s3://$BUCKET/builds/info"
if [ -z "$NOLATEST" ]; then
echo "Advertising $VERSION on $BUCKET as most recent version"
- echo $VERSION | write_to_s3 s3://$BUCKET/latest
+ echo "$VERSION" | write_to_s3 "s3://$BUCKET/latest"
fi
}
# Upload the index script
release_index() {
- sed "s,url='https://get.docker.com/',url='$(s3_url)/'," hack/install.sh | write_to_s3 s3://$BUCKET/index
+ sed "s,url='https://get.docker.com/',url='$(s3_url)/'," hack/install.sh | write_to_s3 "s3://$BUCKET/index"
}
release_test() {
if [ -e "bundles/$VERSION/test" ]; then
- s3cmd --acl-public sync bundles/$VERSION/test/ s3://$BUCKET/test/
+ s3cmd --acl-public sync "bundles/$VERSION/test/" "s3://$BUCKET/test/"
fi
}
setup_gpg() {
# Make sure that we have our keys
- mkdir -p $HOME/.gnupg/
- s3cmd sync s3://$BUCKET/ubuntu/.gnupg/ $HOME/.gnupg/ || true
+ mkdir -p "$HOME/.gnupg/"
+ s3cmd sync "s3://$BUCKET/ubuntu/.gnupg/" "$HOME/.gnupg/" || true
gpg --list-keys releasedocker >/dev/null || {
gpg --gen-key --batch <
- Each layer has an associated A JSON structure which describes some
+ Each layer has an associated JSON structure which describes some
basic information about the image such as date created, author, and the
ID of its parent image as well as execution/runtime configuration like
its entry point, default arguments, CPU/memory shares, networking, and
@@ -81,7 +81,7 @@ This specification uses the following terms:
times of any entries differ. For this reason, image checksums are
generated using the TarSum algorithm which produces a cryptographic
hash of file contents and selected headers only. Details of this
- algorithm are described in the separate [TarSum specification](https://github.com/docker/docker/blob/master/pkg/tarsum/tarsum_spec.md).
+ algorithm are described in the separate TarSum specification.
Tag
@@ -492,9 +492,9 @@ Changeset tar archives.
There is also a format for a single archive which contains complete information
about an image, including:
- - repository names/tags
- - all image layer JSON files
- - all tar archives of each layer filesystem changesets
+ - repository names/tags
+ - all image layer JSON files
+ - all tar archives of each layer filesystem changesets
For example, here's what the full archive of `library/busybox` is (displayed in
`tree` format):
@@ -523,10 +523,10 @@ For example, here's what the full archive of `library/busybox` is (displayed in
There are one or more directories named with the ID for each layer in a full
image. Each of these directories contains 3 files:
- * `VERSION` - The schema version of the `json` file
- * `json` - The JSON metadata for an image layer
- * `layer.tar` - The Tar archive of the filesystem changeset for an image
- layer.
+ * `VERSION` - The schema version of the `json` file
+ * `json` - The JSON metadata for an image layer
+ * `layer.tar` - The Tar archive of the filesystem changeset for an image
+ layer.
The content of the `VERSION` files is simply the semantic version of the JSON
metadata schema:
diff --git a/integration-cli/check_test.go b/integration-cli/check_test.go
new file mode 100644
index 0000000000000..202799cbf153b
--- /dev/null
+++ b/integration-cli/check_test.go
@@ -0,0 +1,81 @@
+package main
+
+import (
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/go-check/check"
+)
+
+func Test(t *testing.T) {
+ check.TestingT(t)
+}
+
+type TimerSuite struct {
+ start time.Time
+}
+
+func (s *TimerSuite) SetUpTest(c *check.C) {
+ s.start = time.Now()
+}
+
+func (s *TimerSuite) TearDownTest(c *check.C) {
+ fmt.Printf("%-60s%.2f\n", c.TestName(), time.Since(s.start).Seconds())
+}
+
+func init() {
+ check.Suite(&DockerSuite{})
+}
+
+type DockerSuite struct {
+ TimerSuite
+}
+
+func (s *DockerSuite) TearDownTest(c *check.C) {
+ deleteAllContainers()
+ deleteAllImages()
+ s.TimerSuite.TearDownTest(c)
+}
+
+func init() {
+ check.Suite(&DockerRegistrySuite{
+ ds: &DockerSuite{},
+ })
+}
+
+type DockerRegistrySuite struct {
+ ds *DockerSuite
+ reg *testRegistryV2
+}
+
+func (s *DockerRegistrySuite) SetUpTest(c *check.C) {
+ s.reg = setupRegistry(c)
+ s.ds.SetUpTest(c)
+}
+
+func (s *DockerRegistrySuite) TearDownTest(c *check.C) {
+ s.reg.Close()
+ s.ds.TearDownTest(c)
+}
+
+func init() {
+ check.Suite(&DockerDaemonSuite{
+ ds: &DockerSuite{},
+ })
+}
+
+type DockerDaemonSuite struct {
+ ds *DockerSuite
+ d *Daemon
+}
+
+func (s *DockerDaemonSuite) SetUpTest(c *check.C) {
+ s.d = NewDaemon(c)
+ s.ds.SetUpTest(c)
+}
+
+func (s *DockerDaemonSuite) TearDownTest(c *check.C) {
+ s.d.Stop()
+ s.ds.TearDownTest(c)
+}
diff --git a/integration-cli/docker_api_attach_test.go b/integration-cli/docker_api_attach_test.go
index 3257798c563f5..c784d5c369cef 100644
--- a/integration-cli/docker_api_attach_test.go
+++ b/integration-cli/docker_api_attach_test.go
@@ -4,23 +4,23 @@ import (
"bytes"
"os/exec"
"strings"
- "testing"
"time"
+ "github.com/go-check/check"
+
"code.google.com/p/go.net/websocket"
)
-func TestGetContainersAttachWebsocket(t *testing.T) {
+func (s *DockerSuite) TestGetContainersAttachWebsocket(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-dit", "busybox", "cat")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf(out, err)
+ c.Fatalf(out, err)
}
- defer deleteAllContainers()
rwc, err := sockConn(time.Duration(10 * time.Second))
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -29,39 +29,51 @@ func TestGetContainersAttachWebsocket(t *testing.T) {
"http://localhost",
)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
ws, err := websocket.NewClient(config, rwc)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ws.Close()
expected := []byte("hello")
actual := make([]byte, len(expected))
- outChan := make(chan string)
+
+ outChan := make(chan error)
go func() {
- if _, err := ws.Read(actual); err != nil {
- t.Fatal(err)
- }
- outChan <- "done"
+ _, err := ws.Read(actual)
+ outChan <- err
+ close(outChan)
}()
- inChan := make(chan string)
+ inChan := make(chan error)
go func() {
- if _, err := ws.Write(expected); err != nil {
- t.Fatal(err)
- }
- inChan <- "done"
+ _, err := ws.Write(expected)
+ inChan <- err
+ close(inChan)
}()
- <-inChan
- <-outChan
+ select {
+ case err := <-inChan:
+ if err != nil {
+ c.Fatal(err)
+ }
+ case <-time.After(5 * time.Second):
+ c.Fatal("Timeout writing to ws")
+ }
+
+ select {
+ case err := <-outChan:
+ if err != nil {
+ c.Fatal(err)
+ }
+ case <-time.After(5 * time.Second):
+ c.Fatal("Timeout reading from ws")
+ }
if !bytes.Equal(expected, actual) {
- t.Fatal("Expected output on websocket to match input")
+ c.Fatal("Expected output on websocket to match input")
}
-
- logDone("container attach websocket - can echo input via cat")
}
diff --git a/integration-cli/docker_api_containers_test.go b/integration-cli/docker_api_containers_test.go
index 02d069f5987d1..1fec3912e6de1 100644
--- a/integration-cli/docker_api_containers_test.go
+++ b/integration-cli/docker_api_containers_test.go
@@ -4,67 +4,61 @@ import (
"bytes"
"encoding/json"
"io"
+ "net/http"
"os/exec"
"strings"
- "testing"
"time"
"github.com/docker/docker/api/types"
+ "github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
+ "github.com/go-check/check"
)
-func TestContainerApiGetAll(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestContainerApiGetAll(c *check.C) {
startCount, err := getContainerCount()
if err != nil {
- t.Fatalf("Cannot query container count: %v", err)
+ c.Fatalf("Cannot query container count: %v", err)
}
name := "getall"
runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "true")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("Error on container creation: %v, output: %q", err, out)
+ c.Fatalf("Error on container creation: %v, output: %q", err, out)
}
- body, err := sockRequest("GET", "/containers/json?all=1", nil)
- if err != nil {
- t.Fatalf("GET all containers sockRequest failed: %v", err)
- }
+ status, body, err := sockRequest("GET", "/containers/json?all=1", nil)
+ c.Assert(status, check.Equals, http.StatusOK)
+ c.Assert(err, check.IsNil)
var inspectJSON []struct {
Names []string
}
if err = json.Unmarshal(body, &inspectJSON); err != nil {
- t.Fatalf("unable to unmarshal response body: %v", err)
+ c.Fatalf("unable to unmarshal response body: %v", err)
}
if len(inspectJSON) != startCount+1 {
- t.Fatalf("Expected %d container(s), %d found (started with: %d)", startCount+1, len(inspectJSON), startCount)
+ c.Fatalf("Expected %d container(s), %d found (started with: %d)", startCount+1, len(inspectJSON), startCount)
}
if actual := inspectJSON[0].Names[0]; actual != "/"+name {
- t.Fatalf("Container Name mismatch. Expected: %q, received: %q\n", "/"+name, actual)
+ c.Fatalf("Container Name mismatch. Expected: %q, received: %q\n", "/"+name, actual)
}
-
- logDone("container REST API - check GET json/all=1")
}
-func TestContainerApiGetExport(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestContainerApiGetExport(c *check.C) {
name := "exportcontainer"
runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "touch", "/test")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("Error on container creation: %v, output: %q", err, out)
+ c.Fatalf("Error on container creation: %v, output: %q", err, out)
}
- body, err := sockRequest("GET", "/containers/"+name+"/export", nil)
- if err != nil {
- t.Fatalf("GET containers/export sockRequest failed: %v", err)
- }
+ status, body, err := sockRequest("GET", "/containers/"+name+"/export", nil)
+ c.Assert(status, check.Equals, http.StatusOK)
+ c.Assert(err, check.IsNil)
found := false
for tarReader := tar.NewReader(bytes.NewReader(body)); ; {
@@ -73,7 +67,7 @@ func TestContainerApiGetExport(t *testing.T) {
if err == io.EOF {
break
}
- t.Fatal(err)
+ c.Fatal(err)
}
if h.Name == "test" {
found = true
@@ -82,33 +76,28 @@ func TestContainerApiGetExport(t *testing.T) {
}
if !found {
- t.Fatalf("The created test file has not been found in the exported image")
+ c.Fatalf("The created test file has not been found in the exported image")
}
-
- logDone("container REST API - check GET containers/export")
}
-func TestContainerApiGetChanges(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestContainerApiGetChanges(c *check.C) {
name := "changescontainer"
runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "rm", "/etc/passwd")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("Error on container creation: %v, output: %q", err, out)
+ c.Fatalf("Error on container creation: %v, output: %q", err, out)
}
- body, err := sockRequest("GET", "/containers/"+name+"/changes", nil)
- if err != nil {
- t.Fatalf("GET containers/changes sockRequest failed: %v", err)
- }
+ status, body, err := sockRequest("GET", "/containers/"+name+"/changes", nil)
+ c.Assert(status, check.Equals, http.StatusOK)
+ c.Assert(err, check.IsNil)
changes := []struct {
Kind int
Path string
}{}
if err = json.Unmarshal(body, &changes); err != nil {
- t.Fatalf("unable to unmarshal response body: %v", err)
+ c.Fatalf("unable to unmarshal response body: %v", err)
}
// Check the changelog for removal of /etc/passwd
@@ -119,56 +108,50 @@ func TestContainerApiGetChanges(t *testing.T) {
}
}
if !success {
- t.Fatalf("/etc/passwd has been removed but is not present in the diff")
+ c.Fatalf("/etc/passwd has been removed but is not present in the diff")
}
-
- logDone("container REST API - check GET containers/changes")
}
-func TestContainerApiStartVolumeBinds(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestContainerApiStartVolumeBinds(c *check.C) {
name := "testing"
config := map[string]interface{}{
"Image": "busybox",
"Volumes": map[string]struct{}{"/tmp": {}},
}
- if _, err := sockRequest("POST", "/containers/create?name="+name, config); err != nil && !strings.Contains(err.Error(), "201 Created") {
- t.Fatal(err)
- }
+ status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
+ c.Assert(status, check.Equals, http.StatusCreated)
+ c.Assert(err, check.IsNil)
bindPath := randomUnixTmpDirPath("test")
config = map[string]interface{}{
"Binds": []string{bindPath + ":/tmp"},
}
- if _, err := sockRequest("POST", "/containers/"+name+"/start", config); err != nil && !strings.Contains(err.Error(), "204 No Content") {
- t.Fatal(err)
- }
+ status, _, err = sockRequest("POST", "/containers/"+name+"/start", config)
+ c.Assert(status, check.Equals, http.StatusNoContent)
+ c.Assert(err, check.IsNil)
pth, err := inspectFieldMap(name, "Volumes", "/tmp")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if pth != bindPath {
- t.Fatalf("expected volume host path to be %s, got %s", bindPath, pth)
+ c.Fatalf("expected volume host path to be %s, got %s", bindPath, pth)
}
-
- logDone("container REST API - check volume binds on start")
}
// Test for GH#10618
-func TestContainerApiStartDupVolumeBinds(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestContainerApiStartDupVolumeBinds(c *check.C) {
name := "testdups"
config := map[string]interface{}{
"Image": "busybox",
"Volumes": map[string]struct{}{"/tmp": {}},
}
- if _, err := sockRequest("POST", "/containers/create?name="+name, config); err != nil && !strings.Contains(err.Error(), "201 Created") {
- t.Fatal(err)
- }
+ status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
+ c.Assert(status, check.Equals, http.StatusCreated)
+ c.Assert(err, check.IsNil)
bindPath1 := randomUnixTmpDirPath("test1")
bindPath2 := randomUnixTmpDirPath("test2")
@@ -176,67 +159,62 @@ func TestContainerApiStartDupVolumeBinds(t *testing.T) {
config = map[string]interface{}{
"Binds": []string{bindPath1 + ":/tmp", bindPath2 + ":/tmp"},
}
- if body, err := sockRequest("POST", "/containers/"+name+"/start", config); err == nil {
- t.Fatal("expected container start to fail when duplicate volume binds to same container path")
- } else {
- if !strings.Contains(string(body), "Duplicate volume") {
- t.Fatalf("Expected failure due to duplicate bind mounts to same path, instead got: %q with error: %v", string(body), err)
- }
- }
+ status, body, err := sockRequest("POST", "/containers/"+name+"/start", config)
+ c.Assert(status, check.Equals, http.StatusInternalServerError)
+ c.Assert(err, check.IsNil)
- logDone("container REST API - check for duplicate volume binds error on start")
+ if !strings.Contains(string(body), "Duplicate volume") {
+ c.Fatalf("Expected failure due to duplicate bind mounts to same path, instead got: %q with error: %v", string(body), err)
+ }
}
-func TestContainerApiStartVolumesFrom(t *testing.T) {
- defer deleteAllContainers()
+
+func (s *DockerSuite) TestContainerApiStartVolumesFrom(c *check.C) {
volName := "voltst"
volPath := "/tmp"
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", volName, "-v", volPath, "busybox")); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
- name := "testing"
+ name := "TestContainerApiStartDupVolumeBinds"
config := map[string]interface{}{
"Image": "busybox",
"Volumes": map[string]struct{}{volPath: {}},
}
- if _, err := sockRequest("POST", "/containers/create?name="+name, config); err != nil && !strings.Contains(err.Error(), "201 Created") {
- t.Fatal(err)
- }
+ status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
+ c.Assert(status, check.Equals, http.StatusCreated)
+ c.Assert(err, check.IsNil)
config = map[string]interface{}{
"VolumesFrom": []string{volName},
}
- if _, err := sockRequest("POST", "/containers/"+name+"/start", config); err != nil && !strings.Contains(err.Error(), "204 No Content") {
- t.Fatal(err)
- }
+ status, _, err = sockRequest("POST", "/containers/"+name+"/start", config)
+ c.Assert(status, check.Equals, http.StatusNoContent)
+ c.Assert(err, check.IsNil)
pth, err := inspectFieldMap(name, "Volumes", volPath)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
pth2, err := inspectFieldMap(volName, "Volumes", volPath)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if pth != pth2 {
- t.Fatalf("expected volume host path to be %s, got %s", pth, pth2)
+ c.Fatalf("expected volume host path to be %s, got %s", pth, pth2)
}
-
- logDone("container REST API - check VolumesFrom on start")
}
// Ensure that volumes-from has priority over binds/anything else
// This is pretty much the same as TestRunApplyVolumesFromBeforeVolumes, except with passing the VolumesFrom and the bind on start
-func TestVolumesFromHasPriority(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestVolumesFromHasPriority(c *check.C) {
volName := "voltst2"
volPath := "/tmp"
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", volName, "-v", volPath, "busybox")); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
name := "testing"
@@ -245,108 +223,101 @@ func TestVolumesFromHasPriority(t *testing.T) {
"Volumes": map[string]struct{}{volPath: {}},
}
- if _, err := sockRequest("POST", "/containers/create?name="+name, config); err != nil && !strings.Contains(err.Error(), "201 Created") {
- t.Fatal(err)
- }
+ status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
+ c.Assert(status, check.Equals, http.StatusCreated)
+ c.Assert(err, check.IsNil)
bindPath := randomUnixTmpDirPath("test")
config = map[string]interface{}{
"VolumesFrom": []string{volName},
"Binds": []string{bindPath + ":/tmp"},
}
- if _, err := sockRequest("POST", "/containers/"+name+"/start", config); err != nil && !strings.Contains(err.Error(), "204 No Content") {
- t.Fatal(err)
- }
+ status, _, err = sockRequest("POST", "/containers/"+name+"/start", config)
+ c.Assert(status, check.Equals, http.StatusNoContent)
+ c.Assert(err, check.IsNil)
pth, err := inspectFieldMap(name, "Volumes", volPath)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
pth2, err := inspectFieldMap(volName, "Volumes", volPath)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if pth != pth2 {
- t.Fatalf("expected volume host path to be %s, got %s", pth, pth2)
+ c.Fatalf("expected volume host path to be %s, got %s", pth, pth2)
}
-
- logDone("container REST API - check VolumesFrom has priority")
}
-func TestGetContainerStats(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestGetContainerStats(c *check.C) {
var (
name = "statscontainer"
runCmd = exec.Command(dockerBinary, "run", "-d", "--name", name, "busybox", "top")
)
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("Error on container creation: %v, output: %q", err, out)
+ c.Fatalf("Error on container creation: %v, output: %q", err, out)
}
type b struct {
- body []byte
- err error
+ status int
+ body []byte
+ err error
}
bc := make(chan b, 1)
go func() {
- body, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
- bc <- b{body, err}
+ status, body, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
+ bc <- b{status, body, err}
}()
// allow some time to stream the stats from the container
time.Sleep(4 * time.Second)
if _, err := runCommand(exec.Command(dockerBinary, "rm", "-f", name)); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// collect the results from the stats stream or timeout and fail
// if the stream was not disconnected.
select {
case <-time.After(2 * time.Second):
- t.Fatal("stream was not closed after container was removed")
+ c.Fatal("stream was not closed after container was removed")
case sr := <-bc:
- if sr.err != nil {
- t.Fatal(sr.err)
- }
+ c.Assert(sr.err, check.IsNil)
+ c.Assert(sr.status, check.Equals, http.StatusOK)
dec := json.NewDecoder(bytes.NewBuffer(sr.body))
var s *types.Stats
// decode only one object from the stream
if err := dec.Decode(&s); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
}
- logDone("container REST API - check GET containers/stats")
}
-func TestGetStoppedContainerStats(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestGetStoppedContainerStats(c *check.C) {
+ // TODO: this test does nothing because we are c.Assert'ing in goroutine
var (
name = "statscontainer"
runCmd = exec.Command(dockerBinary, "create", "--name", name, "busybox", "top")
)
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("Error on container creation: %v, output: %q", err, out)
+ c.Fatalf("Error on container creation: %v, output: %q", err, out)
}
go func() {
// We'll never get return for GET stats from sockRequest as of now,
// just send request and see if panic or error would happen on daemon side.
- _, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
- if err != nil {
- t.Fatal(err)
- }
+ status, _, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
+ c.Assert(status, check.Equals, http.StatusOK)
+ c.Assert(err, check.IsNil)
}()
// allow some time to send request and let daemon deal with it
time.Sleep(1 * time.Second)
-
- logDone("container REST API - check GET stopped containers/stats")
}
-func TestBuildApiDockerfilePath(t *testing.T) {
+func (s *DockerSuite) TestBuildApiDockerfilePath(c *check.C) {
// Test to make sure we stop people from trying to leave the
// build context when specifying the path to the dockerfile
buffer := new(bytes.Buffer)
@@ -358,28 +329,30 @@ func TestBuildApiDockerfilePath(t *testing.T) {
Name: "Dockerfile",
Size: int64(len(dockerfile)),
}); err != nil {
- t.Fatalf("failed to write tar file header: %v", err)
+ c.Fatalf("failed to write tar file header: %v", err)
}
if _, err := tw.Write(dockerfile); err != nil {
- t.Fatalf("failed to write tar file content: %v", err)
+ c.Fatalf("failed to write tar file content: %v", err)
}
if err := tw.Close(); err != nil {
- t.Fatalf("failed to close tar archive: %v", err)
+ c.Fatalf("failed to close tar archive: %v", err)
}
- out, err := sockRequestRaw("POST", "/build?dockerfile=../Dockerfile", buffer, "application/x-tar")
- if err == nil {
- t.Fatalf("Build was supposed to fail: %s", out)
+ res, body, err := sockRequestRaw("POST", "/build?dockerfile=../Dockerfile", buffer, "application/x-tar")
+ c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
+ c.Assert(err, check.IsNil)
+
+ out, err := readBody(body)
+ if err != nil {
+ c.Fatal(err)
}
if !strings.Contains(string(out), "must be within the build context") {
- t.Fatalf("Didn't complain about leaving build context: %s", out)
+ c.Fatalf("Didn't complain about leaving build context: %s", out)
}
-
- logDone("container REST API - check build w/bad Dockerfile path")
}
-func TestBuildApiDockerFileRemote(t *testing.T) {
+func (s *DockerSuite) TestBuildApiDockerFileRemote(c *check.C) {
server, err := fakeStorage(map[string]string{
"testD": `FROM busybox
COPY * /tmp/
@@ -387,13 +360,17 @@ RUN find / -name ba*
RUN find /tmp/`,
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer server.Close()
- buf, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+server.URL()+"/testD", nil, "application/json")
+ res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+server.URL()+"/testD", nil, "application/json")
+ c.Assert(res.StatusCode, check.Equals, http.StatusOK)
+ c.Assert(err, check.IsNil)
+
+ buf, err := readBody(body)
if err != nil {
- t.Fatalf("Build failed: %s", err)
+ c.Fatal(err)
}
// Make sure Dockerfile exists.
@@ -401,36 +378,36 @@ RUN find /tmp/`,
out := string(buf)
if !strings.Contains(out, "/tmp/Dockerfile") ||
strings.Contains(out, "baz") {
- t.Fatalf("Incorrect output: %s", out)
+ c.Fatalf("Incorrect output: %s", out)
}
-
- logDone("container REST API - check build with -f from remote")
}
-func TestBuildApiLowerDockerfile(t *testing.T) {
+func (s *DockerSuite) TestBuildApiLowerDockerfile(c *check.C) {
git, err := fakeGIT("repo", map[string]string{
"dockerfile": `FROM busybox
RUN echo from dockerfile`,
}, false)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer git.Close()
- buf, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
+ res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
+ c.Assert(res.StatusCode, check.Equals, http.StatusOK)
+ c.Assert(err, check.IsNil)
+
+ buf, err := readBody(body)
if err != nil {
- t.Fatalf("Build failed: %s\n%q", err, buf)
+ c.Fatal(err)
}
out := string(buf)
if !strings.Contains(out, "from dockerfile") {
- t.Fatalf("Incorrect output: %s", out)
+ c.Fatalf("Incorrect output: %s", out)
}
-
- logDone("container REST API - check build with lower dockerfile")
}
-func TestBuildApiBuildGitWithF(t *testing.T) {
+func (s *DockerSuite) TestBuildApiBuildGitWithF(c *check.C) {
git, err := fakeGIT("repo", map[string]string{
"baz": `FROM busybox
RUN echo from baz`,
@@ -438,26 +415,28 @@ RUN echo from baz`,
RUN echo from Dockerfile`,
}, false)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer git.Close()
// Make sure it tries to 'dockerfile' query param value
- buf, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+git.RepoURL, nil, "application/json")
+ res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+git.RepoURL, nil, "application/json")
+ c.Assert(res.StatusCode, check.Equals, http.StatusOK)
+ c.Assert(err, check.IsNil)
+
+ buf, err := readBody(body)
if err != nil {
- t.Fatalf("Build failed: %s\n%q", err, buf)
+ c.Fatal(err)
}
out := string(buf)
if !strings.Contains(out, "from baz") {
- t.Fatalf("Incorrect output: %s", out)
+ c.Fatalf("Incorrect output: %s", out)
}
-
- logDone("container REST API - check build from git w/F")
}
-func TestBuildApiDoubleDockerfile(t *testing.T) {
- testRequires(t, UnixCli) // dockerfile overwrites Dockerfile on Windows
+func (s *DockerSuite) TestBuildApiDoubleDockerfile(c *check.C) {
+ testRequires(c, UnixCli) // dockerfile overwrites Dockerfile on Windows
git, err := fakeGIT("repo", map[string]string{
"Dockerfile": `FROM busybox
RUN echo from Dockerfile`,
@@ -465,25 +444,27 @@ RUN echo from Dockerfile`,
RUN echo from dockerfile`,
}, false)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer git.Close()
// Make sure it tries to 'dockerfile' query param value
- buf, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
+ res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
+ c.Assert(res.StatusCode, check.Equals, http.StatusOK)
+ c.Assert(err, check.IsNil)
+
+ buf, err := readBody(body)
if err != nil {
- t.Fatalf("Build failed: %s", err)
+ c.Fatal(err)
}
out := string(buf)
if !strings.Contains(out, "from Dockerfile") {
- t.Fatalf("Incorrect output: %s", out)
+ c.Fatalf("Incorrect output: %s", out)
}
-
- logDone("container REST API - check build with two dockerfiles")
}
-func TestBuildApiDockerfileSymlink(t *testing.T) {
+func (s *DockerSuite) TestBuildApiDockerfileSymlink(c *check.C) {
// Test to make sure we stop people from trying to leave the
// build context when specifying a symlink as the path to the dockerfile
buffer := new(bytes.Buffer)
@@ -495,15 +476,19 @@ func TestBuildApiDockerfileSymlink(t *testing.T) {
Typeflag: tar.TypeSymlink,
Linkname: "/etc/passwd",
}); err != nil {
- t.Fatalf("failed to write tar file header: %v", err)
+ c.Fatalf("failed to write tar file header: %v", err)
}
if err := tw.Close(); err != nil {
- t.Fatalf("failed to close tar archive: %v", err)
+ c.Fatalf("failed to close tar archive: %v", err)
}
- out, err := sockRequestRaw("POST", "/build", buffer, "application/x-tar")
- if err == nil {
- t.Fatalf("Build was supposed to fail: %s", out)
+ res, body, err := sockRequestRaw("POST", "/build", buffer, "application/x-tar")
+ c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
+ c.Assert(err, check.IsNil)
+
+ out, err := readBody(body)
+ if err != nil {
+ c.Fatal(err)
}
// The reason the error is "Cannot locate specified Dockerfile" is because
@@ -511,45 +496,365 @@ func TestBuildApiDockerfileSymlink(t *testing.T) {
// Dockerfile -> /etc/passwd becomes etc/passwd from the context which is
// a nonexistent file.
if !strings.Contains(string(out), "Cannot locate specified Dockerfile: Dockerfile") {
- t.Fatalf("Didn't complain about leaving build context: %s", out)
+ c.Fatalf("Didn't complain about leaving build context: %s", out)
}
-
- logDone("container REST API - check build w/bad Dockerfile symlink path")
}
// #9981 - Allow a docker created volume (ie, one in /var/lib/docker/volumes) to be used to overwrite (via passing in Binds on api start) an existing volume
-func TestPostContainerBindNormalVolume(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestPostContainerBindNormalVolume(c *check.C) {
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "-v", "/foo", "--name=one", "busybox"))
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
fooDir, err := inspectFieldMap("one", "Volumes", "/foo")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "create", "-v", "/foo", "--name=two", "busybox"))
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
bindSpec := map[string][]string{"Binds": {fooDir + ":/foo"}}
- _, err = sockRequest("POST", "/containers/two/start", bindSpec)
- if err != nil && !strings.Contains(err.Error(), "204 No Content") {
- t.Fatal(err)
- }
+ status, _, err := sockRequest("POST", "/containers/two/start", bindSpec)
+ c.Assert(status, check.Equals, http.StatusNoContent)
+ c.Assert(err, check.IsNil)
fooDir2, err := inspectFieldMap("two", "Volumes", "/foo")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if fooDir2 != fooDir {
- t.Fatalf("expected volume path to be %s, got: %s", fooDir, fooDir2)
+ c.Fatalf("expected volume path to be %s, got: %s", fooDir, fooDir2)
+ }
+}
+
+func (s *DockerSuite) TestContainerApiPause(c *check.C) {
+ defer unpauseAllContainers()
+ runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sleep", "30")
+ out, _, err := runCommandWithOutput(runCmd)
+
+ if err != nil {
+ c.Fatalf("failed to create a container: %s, %v", out, err)
+ }
+ ContainerID := strings.TrimSpace(out)
+
+ status, _, err := sockRequest("POST", "/containers/"+ContainerID+"/pause", nil)
+ c.Assert(status, check.Equals, http.StatusNoContent)
+ c.Assert(err, check.IsNil)
+
+ pausedContainers, err := getSliceOfPausedContainers()
+
+ if err != nil {
+ c.Fatalf("error thrown while checking if containers were paused: %v", err)
+ }
+
+ if len(pausedContainers) != 1 || stringid.TruncateID(ContainerID) != pausedContainers[0] {
+ c.Fatalf("there should be one paused container and not %d", len(pausedContainers))
+ }
+
+ status, _, err = sockRequest("POST", "/containers/"+ContainerID+"/unpause", nil)
+ c.Assert(status, check.Equals, http.StatusNoContent)
+ c.Assert(err, check.IsNil)
+
+ pausedContainers, err = getSliceOfPausedContainers()
+
+ if err != nil {
+ c.Fatalf("error thrown while checking if containers were paused: %v", err)
+ }
+
+ if pausedContainers != nil {
+ c.Fatalf("There should be no paused container.")
+ }
+}
+
+func (s *DockerSuite) TestContainerApiTop(c *check.C) {
+ out, err := exec.Command(dockerBinary, "run", "-d", "busybox", "/bin/sh", "-c", "top").CombinedOutput()
+ if err != nil {
+ c.Fatal(err, out)
+ }
+ id := strings.TrimSpace(string(out))
+ if err := waitRun(id); err != nil {
+ c.Fatal(err)
+ }
+
+ type topResp struct {
+ Titles []string
+ Processes [][]string
+ }
+ var top topResp
+ status, b, err := sockRequest("GET", "/containers/"+id+"/top?ps_args=aux", nil)
+ c.Assert(status, check.Equals, http.StatusOK)
+ c.Assert(err, check.IsNil)
+
+ if err := json.Unmarshal(b, &top); err != nil {
+ c.Fatal(err)
}
- logDone("container REST API - can use path from normal volume as bind-mount to overwrite another volume")
+ if len(top.Titles) != 11 {
+ c.Fatalf("expected 11 titles, found %d: %v", len(top.Titles), top.Titles)
+ }
+
+ if top.Titles[0] != "USER" || top.Titles[10] != "COMMAND" {
+ c.Fatalf("expected `USER` at `Titles[0]` and `COMMAND` at Titles[10]: %v", top.Titles)
+ }
+ if len(top.Processes) != 2 {
+ c.Fatalf("expected 2 processes, found %d: %v", len(top.Processes), top.Processes)
+ }
+ if top.Processes[0][10] != "/bin/sh -c top" {
+ c.Fatalf("expected `/bin/sh -c top`, found: %s", top.Processes[0][10])
+ }
+ if top.Processes[1][10] != "top" {
+ c.Fatalf("expected `top`, found: %s", top.Processes[1][10])
+ }
+}
+
+func (s *DockerSuite) TestContainerApiCommit(c *check.C) {
+ cName := "testapicommit"
+ out, err := exec.Command(dockerBinary, "run", "--name="+cName, "busybox", "/bin/sh", "-c", "touch /test").CombinedOutput()
+ if err != nil {
+ c.Fatal(err, out)
+ }
+
+ name := "TestContainerApiCommit"
+ status, b, err := sockRequest("POST", "/commit?repo="+name+"&testtag=tag&container="+cName, nil)
+ c.Assert(status, check.Equals, http.StatusCreated)
+ c.Assert(err, check.IsNil)
+
+ type resp struct {
+ Id string
+ }
+ var img resp
+ if err := json.Unmarshal(b, &img); err != nil {
+ c.Fatal(err)
+ }
+
+ cmd, err := inspectField(img.Id, "Config.Cmd")
+ if err != nil {
+ c.Fatal(err)
+ }
+ if cmd != "{[/bin/sh -c touch /test]}" {
+ c.Fatalf("got wrong Cmd from commit: %q", cmd)
+ }
+ // sanity check, make sure the image is what we think it is
+ out, err = exec.Command(dockerBinary, "run", img.Id, "ls", "/test").CombinedOutput()
+ if err != nil {
+ c.Fatalf("error checking committed image: %v - %q", err, string(out))
+ }
+}
+
+func (s *DockerSuite) TestContainerApiCreate(c *check.C) {
+ config := map[string]interface{}{
+ "Image": "busybox",
+ "Cmd": []string{"/bin/sh", "-c", "touch /test && ls /test"},
+ }
+
+ status, b, err := sockRequest("POST", "/containers/create", config)
+ c.Assert(status, check.Equals, http.StatusCreated)
+ c.Assert(err, check.IsNil)
+
+ type createResp struct {
+ Id string
+ }
+ var container createResp
+ if err := json.Unmarshal(b, &container); err != nil {
+ c.Fatal(err)
+ }
+
+ out, err := exec.Command(dockerBinary, "start", "-a", container.Id).CombinedOutput()
+ if err != nil {
+ c.Fatal(out, err)
+ }
+ if strings.TrimSpace(string(out)) != "/test" {
+ c.Fatalf("expected output `/test`, got %q", out)
+ }
+}
+
+func (s *DockerSuite) TestContainerApiCreateWithHostName(c *check.C) {
+ var hostName = "test-host"
+ config := map[string]interface{}{
+ "Image": "busybox",
+ "Hostname": hostName,
+ }
+
+ _, b, err := sockRequest("POST", "/containers/create", config)
+ if err != nil && !strings.Contains(err.Error(), "200 OK: 201") {
+ c.Fatal(err)
+ }
+ type createResp struct {
+ Id string
+ }
+ var container createResp
+ if err := json.Unmarshal(b, &container); err != nil {
+ c.Fatal(err)
+ }
+
+ var id = container.Id
+
+ _, bodyGet, err := sockRequest("GET", "/containers/"+id+"/json", nil)
+
+ type configLocal struct {
+ Hostname string
+ }
+ type getResponse struct {
+ Id string
+ Config configLocal
+ }
+
+ var containerInfo getResponse
+ if err := json.Unmarshal(bodyGet, &containerInfo); err != nil {
+ c.Fatal(err)
+ }
+ var hostNameActual = containerInfo.Config.Hostname
+ if hostNameActual != "test-host" {
+ c.Fatalf("Mismatched Hostname, Expected %v, Actual: %v ", hostName, hostNameActual)
+ }
+}
+
+func (s *DockerSuite) TestContainerApiVerifyHeader(c *check.C) {
+ config := map[string]interface{}{
+ "Image": "busybox",
+ }
+
+ create := func(ct string) (*http.Response, io.ReadCloser, error) {
+ jsonData := bytes.NewBuffer(nil)
+ if err := json.NewEncoder(jsonData).Encode(config); err != nil {
+ c.Fatal(err)
+ }
+ return sockRequestRaw("POST", "/containers/create", jsonData, ct)
+ }
+
+ // Try with no content-type
+ res, body, err := create("")
+ c.Assert(err, check.IsNil)
+ c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
+ body.Close()
+
+ // Try with wrong content-type
+ res, body, err = create("application/xml")
+ c.Assert(err, check.IsNil)
+ c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
+ body.Close()
+
+ // now application/json
+ res, body, err = create("application/json")
+ c.Assert(err, check.IsNil)
+ c.Assert(res.StatusCode, check.Equals, http.StatusCreated)
+ body.Close()
+}
+
+// Issue 7941 - test to make sure a "null" in JSON is just ignored.
+// W/o this fix a null in JSON would be parsed into a string var as "null"
+func (s *DockerSuite) TestContainerApiPostCreateNull(c *check.C) {
+ config := `{
+ "Hostname":"",
+ "Domainname":"",
+ "Memory":0,
+ "MemorySwap":0,
+ "CpuShares":0,
+ "Cpuset":null,
+ "AttachStdin":true,
+ "AttachStdout":true,
+ "AttachStderr":true,
+ "PortSpecs":null,
+ "ExposedPorts":{},
+ "Tty":true,
+ "OpenStdin":true,
+ "StdinOnce":true,
+ "Env":[],
+ "Cmd":"ls",
+ "Image":"busybox",
+ "Volumes":{},
+ "WorkingDir":"",
+ "Entrypoint":null,
+ "NetworkDisabled":false,
+ "OnBuild":null}`
+
+ res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
+ c.Assert(res.StatusCode, check.Equals, http.StatusCreated)
+ c.Assert(err, check.IsNil)
+
+ b, err := readBody(body)
+ if err != nil {
+ c.Fatal(err)
+ }
+ type createResp struct {
+ Id string
+ }
+ var container createResp
+ if err := json.Unmarshal(b, &container); err != nil {
+ c.Fatal(err)
+ }
+
+ out, err := inspectField(container.Id, "HostConfig.CpusetCpus")
+ if err != nil {
+ c.Fatal(err, out)
+ }
+ if out != "" {
+ c.Fatalf("expected empty string, got %q", out)
+ }
+}
+
+func (s *DockerSuite) TestCreateWithTooLowMemoryLimit(c *check.C) {
+ config := `{
+ "Image": "busybox",
+ "Cmd": "ls",
+ "OpenStdin": true,
+ "CpuShares": 100,
+ "Memory": 524287
+ }`
+
+ res, body, _ := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
+ b, err2 := readBody(body)
+ if err2 != nil {
+ c.Fatal(err2)
+ }
+
+ c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
+ c.Assert(strings.Contains(string(b), "Minimum memory limit allowed is 4MB"), check.Equals, true)
+}
+
+func (s *DockerSuite) TestStartWithTooLowMemoryLimit(c *check.C) {
+ out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "busybox"))
+ if err != nil {
+ c.Fatal(err, out)
+ }
+
+ containerID := strings.TrimSpace(out)
+
+ config := `{
+ "CpuShares": 100,
+ "Memory": 524287
+ }`
+
+ res, body, _ := sockRequestRaw("POST", "/containers/"+containerID+"/start", strings.NewReader(config), "application/json")
+ b, err2 := readBody(body)
+ if err2 != nil {
+ c.Fatal(err2)
+ }
+
+ c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
+ c.Assert(strings.Contains(string(b), "Minimum memory limit allowed is 4MB"), check.Equals, true)
+}
+
+func (s *DockerSuite) TestContainerApiRename(c *check.C) {
+ runCmd := exec.Command(dockerBinary, "run", "--name", "TestContainerApiRename", "-d", "busybox", "sh")
+ out, _, err := runCommandWithOutput(runCmd)
+ c.Assert(err, check.IsNil)
+
+ containerID := strings.TrimSpace(out)
+ newName := "TestContainerApiRenameNew"
+ statusCode, _, err := sockRequest("POST", "/containers/"+containerID+"/rename?name="+newName, nil)
+
+ // 204 No Content is expected, not 200
+ c.Assert(statusCode, check.Equals, http.StatusNoContent)
+ c.Assert(err, check.IsNil)
+
+ name, err := inspectField(containerID, "Name")
+ if name != "/"+newName {
+ c.Fatalf("Failed to rename container, expected %v, got %v. Container rename API failed", newName, name)
+ }
}
diff --git a/integration-cli/docker_api_exec_resize_test.go b/integration-cli/docker_api_exec_resize_test.go
new file mode 100644
index 0000000000000..ab753d8ecf163
--- /dev/null
+++ b/integration-cli/docker_api_exec_resize_test.go
@@ -0,0 +1,23 @@
+package main
+
+import (
+ "net/http"
+ "os/exec"
+ "strings"
+
+ "github.com/go-check/check"
+)
+
+func (s *DockerSuite) TestExecResizeApiHeightWidthNoInt(c *check.C) {
+ runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top")
+ out, _, err := runCommandWithOutput(runCmd)
+ if err != nil {
+ c.Fatalf(out, err)
+ }
+ cleanedContainerID := strings.TrimSpace(out)
+
+ endpoint := "/exec/" + cleanedContainerID + "/resize?h=foo&w=bar"
+ status, _, err := sockRequest("POST", endpoint, nil)
+ c.Assert(status, check.Equals, http.StatusInternalServerError)
+ c.Assert(err, check.IsNil)
+}
diff --git a/integration-cli/docker_api_exec_test.go b/integration-cli/docker_api_exec_test.go
index 1ed99a2561e86..b7957480f50a0 100644
--- a/integration-cli/docker_api_exec_test.go
+++ b/integration-cli/docker_api_exec_test.go
@@ -5,23 +5,25 @@ package main
import (
"bytes"
"fmt"
+ "net/http"
"os/exec"
- "testing"
+
+ "github.com/go-check/check"
)
// Regression test for #9414
-func TestExecApiCreateNoCmd(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestExecApiCreateNoCmd(c *check.C) {
name := "exec_test"
runCmd := exec.Command(dockerBinary, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
if out, _, err := runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
- body, err := sockRequest("POST", fmt.Sprintf("/containers/%s/exec", name), map[string]interface{}{"Cmd": nil})
- if err == nil || !bytes.Contains(body, []byte("No exec command specified")) {
- t.Fatalf("Expected error when creating exec command with no Cmd specified: %q", err)
- }
+ status, body, err := sockRequest("POST", fmt.Sprintf("/containers/%s/exec", name), map[string]interface{}{"Cmd": nil})
+ c.Assert(status, check.Equals, http.StatusInternalServerError)
+ c.Assert(err, check.IsNil)
- logDone("exec create API - returns error when missing Cmd")
+ if !bytes.Contains(body, []byte("No exec command specified")) {
+ c.Fatalf("Expected message when creating exec command with no Cmd specified")
+ }
}
diff --git a/integration-cli/docker_api_images_test.go b/integration-cli/docker_api_images_test.go
index 38d891fd5ad83..e88fbaeaad9c3 100644
--- a/integration-cli/docker_api_images_test.go
+++ b/integration-cli/docker_api_images_test.go
@@ -2,25 +2,99 @@ package main
import (
"encoding/json"
- "testing"
+ "net/http"
+ "net/url"
+ "os/exec"
+ "strings"
"github.com/docker/docker/api/types"
+ "github.com/go-check/check"
)
-func TestLegacyImages(t *testing.T) {
- body, err := sockRequest("GET", "/v1.6/images/json", nil)
- if err != nil {
- t.Fatalf("Error on GET: %s", err)
- }
+func (s *DockerSuite) TestLegacyImages(c *check.C) {
+ status, body, err := sockRequest("GET", "/v1.6/images/json", nil)
+ c.Assert(status, check.Equals, http.StatusOK)
+ c.Assert(err, check.IsNil)
images := []types.LegacyImage{}
if err = json.Unmarshal(body, &images); err != nil {
- t.Fatalf("Error on unmarshal: %s", err)
+ c.Fatalf("Error on unmarshal: %s", err)
}
if len(images) == 0 || images[0].Tag == "" || images[0].Repository == "" {
- t.Fatalf("Bad data: %q", images)
+ c.Fatalf("Bad data: %q", images)
+ }
+}
+
+func (s *DockerSuite) TestApiImagesFilter(c *check.C) {
+ name := "utest:tag1"
+ name2 := "utest/docker:tag2"
+ name3 := "utest:5000/docker:tag3"
+ for _, n := range []string{name, name2, name3} {
+ if out, err := exec.Command(dockerBinary, "tag", "busybox", n).CombinedOutput(); err != nil {
+ c.Fatal(err, out)
+ }
+ }
+ type image struct{ RepoTags []string }
+ getImages := func(filter string) []image {
+ v := url.Values{}
+ v.Set("filter", filter)
+ status, b, err := sockRequest("GET", "/images/json?"+v.Encode(), nil)
+ c.Assert(status, check.Equals, http.StatusOK)
+ c.Assert(err, check.IsNil)
+
+ var images []image
+ if err := json.Unmarshal(b, &images); err != nil {
+ c.Fatal(err)
+ }
+
+ return images
+ }
+
+ errMsg := "incorrect number of matches returned"
+ if images := getImages("utest*/*"); len(images[0].RepoTags) != 2 {
+ c.Fatal(errMsg)
+ }
+ if images := getImages("utest"); len(images[0].RepoTags) != 1 {
+ c.Fatal(errMsg)
+ }
+ if images := getImages("utest*"); len(images[0].RepoTags) != 1 {
+ c.Fatal(errMsg)
+ }
+ if images := getImages("*5000*/*"); len(images[0].RepoTags) != 1 {
+ c.Fatal(errMsg)
}
+}
+
+func (s *DockerSuite) TestApiImagesSaveAndLoad(c *check.C) {
+ testRequires(c, Network)
+ out, err := buildImage("saveandload", "FROM hello-world\nENV FOO bar", false)
+ if err != nil {
+ c.Fatal(err)
+ }
+ id := strings.TrimSpace(out)
- logDone("images - checking legacy json")
+ res, body, err := sockRequestRaw("GET", "/images/"+id+"/get", nil, "")
+ c.Assert(err, check.IsNil)
+ c.Assert(res.StatusCode, check.Equals, http.StatusOK)
+
+ defer body.Close()
+
+ if out, err := exec.Command(dockerBinary, "rmi", id).CombinedOutput(); err != nil {
+ c.Fatal(err, out)
+ }
+
+ res, loadBody, err := sockRequestRaw("POST", "/images/load", body, "application/x-tar")
+ c.Assert(err, check.IsNil)
+ c.Assert(res.StatusCode, check.Equals, http.StatusOK)
+
+ defer loadBody.Close()
+
+ inspectOut, err := exec.Command(dockerBinary, "inspect", "--format='{{ .Id }}'", id).CombinedOutput()
+ if err != nil {
+ c.Fatal(err, inspectOut)
+ }
+ if strings.TrimSpace(string(inspectOut)) != id {
+ c.Fatal("load did not work properly")
+ }
}
diff --git a/integration-cli/docker_api_info_test.go b/integration-cli/docker_api_info_test.go
new file mode 100644
index 0000000000000..4084289102932
--- /dev/null
+++ b/integration-cli/docker_api_info_test.go
@@ -0,0 +1,36 @@
+package main
+
+import (
+ "net/http"
+ "strings"
+
+ "github.com/go-check/check"
+)
+
+func (s *DockerSuite) TestInfoApi(c *check.C) {
+ endpoint := "/info"
+
+ status, body, err := sockRequest("GET", endpoint, nil)
+ c.Assert(status, check.Equals, http.StatusOK)
+ c.Assert(err, check.IsNil)
+
+ // always shown fields
+ stringsToCheck := []string{
+ "ID",
+ "Containers",
+ "Images",
+ "ExecutionDriver",
+ "LoggingDriver",
+ "OperatingSystem",
+ "NCPU",
+ "MemTotal",
+ "KernelVersion",
+ "Driver"}
+
+ out := string(body)
+ for _, linePrefix := range stringsToCheck {
+ if !strings.Contains(out, linePrefix) {
+ c.Errorf("couldn't find string %v in output", linePrefix)
+ }
+ }
+}
diff --git a/integration-cli/docker_api_inspect_test.go b/integration-cli/docker_api_inspect_test.go
index e43f10fd6e2bc..b90bdc7120444 100644
--- a/integration-cli/docker_api_inspect_test.go
+++ b/integration-cli/docker_api_inspect_test.go
@@ -2,18 +2,18 @@ package main
import (
"encoding/json"
+ "net/http"
"os/exec"
"strings"
- "testing"
-)
-func TestInspectApiContainerResponse(t *testing.T) {
- defer deleteAllContainers()
+ "github.com/go-check/check"
+)
+func (s *DockerSuite) TestInspectApiContainerResponse(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("failed to create a container: %s, %v", out, err)
+ c.Fatalf("failed to create a container: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -27,14 +27,13 @@ func TestInspectApiContainerResponse(t *testing.T) {
if testVersion != "latest" {
endpoint = "/" + testVersion + endpoint
}
- body, err := sockRequest("GET", endpoint, nil)
- if err != nil {
- t.Fatalf("sockRequest failed for %s version: %v", testVersion, err)
- }
+ status, body, err := sockRequest("GET", endpoint, nil)
+ c.Assert(status, check.Equals, http.StatusOK)
+ c.Assert(err, check.IsNil)
var inspectJSON map[string]interface{}
if err = json.Unmarshal(body, &inspectJSON); err != nil {
- t.Fatalf("unable to unmarshal body for %s version: %v", testVersion, err)
+ c.Fatalf("unable to unmarshal body for %s version: %v", testVersion, err)
}
keys := []string{"State", "Created", "Path", "Args", "Config", "Image", "NetworkSettings", "ResolvConfPath", "HostnamePath", "HostsPath", "LogPath", "Name", "Driver", "ExecDriver", "MountLabel", "ProcessLabel", "Volumes", "VolumesRW"}
@@ -47,14 +46,12 @@ func TestInspectApiContainerResponse(t *testing.T) {
for _, key := range keys {
if _, ok := inspectJSON[key]; !ok {
- t.Fatalf("%s does not exist in response for %s version", key, testVersion)
+ c.Fatalf("%s does not exist in response for %s version", key, testVersion)
}
}
//Issue #6830: type not properly converted to JSON/back
if _, ok := inspectJSON["Path"].(bool); ok {
- t.Fatalf("Path of `true` should not be converted to boolean `true` via JSON marshalling")
+ c.Fatalf("Path of `true` should not be converted to boolean `true` via JSON marshalling")
}
}
-
- logDone("container json - check keys in container json response")
}
diff --git a/integration-cli/docker_api_logs_test.go b/integration-cli/docker_api_logs_test.go
new file mode 100644
index 0000000000000..f9284494d2e88
--- /dev/null
+++ b/integration-cli/docker_api_logs_test.go
@@ -0,0 +1,62 @@
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "net/http"
+ "os/exec"
+ "strings"
+ "time"
+
+ "github.com/go-check/check"
+)
+
+func (s *DockerSuite) TestLogsApiWithStdout(c *check.C) {
+ out, _ := dockerCmd(c, "run", "-d", "-t", "busybox", "/bin/sh", "-c", "while true; do echo hello; sleep 1; done")
+ id := strings.TrimSpace(out)
+ if err := waitRun(id); err != nil {
+ c.Fatal(err)
+ }
+
+ type logOut struct {
+ out string
+ res *http.Response
+ err error
+ }
+ chLog := make(chan logOut)
+
+ go func() {
+ res, body, err := sockRequestRaw("GET", fmt.Sprintf("/containers/%s/logs?follow=1&stdout=1×tamps=1", id), nil, "")
+ out, _ := bufio.NewReader(body).ReadString('\n')
+ chLog <- logOut{strings.TrimSpace(out), res, err}
+ }()
+
+ select {
+ case l := <-chLog:
+ c.Assert(l.err, check.IsNil)
+ c.Assert(l.res.StatusCode, check.Equals, http.StatusOK)
+ if !strings.HasSuffix(l.out, "hello") {
+ c.Fatalf("expected log output to container 'hello', but it does not")
+ }
+ case <-time.After(2 * time.Second):
+ c.Fatal("timeout waiting for logs to exit")
+ }
+}
+
+func (s *DockerSuite) TestLogsApiNoStdoutNorStderr(c *check.C) {
+ name := "logs_test"
+ runCmd := exec.Command(dockerBinary, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
+ if out, _, err := runCommandWithOutput(runCmd); err != nil {
+ c.Fatal(out, err)
+ }
+
+ status, body, err := sockRequest("GET", fmt.Sprintf("/containers/%s/logs", name), nil)
+ c.Assert(status, check.Equals, http.StatusBadRequest)
+ c.Assert(err, check.IsNil)
+
+ expected := "Bad parameters: you must choose at least one stream"
+ if !bytes.Contains(body, []byte(expected)) {
+ c.Fatalf("Expected %s, got %s", expected, string(body[:]))
+ }
+}
diff --git a/integration-cli/docker_api_resize_test.go b/integration-cli/docker_api_resize_test.go
index 2e7677d100c4d..6d5528069952b 100644
--- a/integration-cli/docker_api_resize_test.go
+++ b/integration-cli/docker_api_resize_test.go
@@ -1,53 +1,62 @@
package main
import (
+ "net/http"
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
-func TestResizeApiResponse(t *testing.T) {
+func (s *DockerSuite) TestResizeApiResponse(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf(out, err)
+ c.Fatalf(out, err)
}
- defer deleteAllContainers()
cleanedContainerID := strings.TrimSpace(out)
endpoint := "/containers/" + cleanedContainerID + "/resize?h=40&w=40"
- _, err = sockRequest("POST", endpoint, nil)
+ status, _, err := sockRequest("POST", endpoint, nil)
+ c.Assert(status, check.Equals, http.StatusOK)
+ c.Assert(err, check.IsNil)
+}
+
+func (s *DockerSuite) TestResizeApiHeightWidthNoInt(c *check.C) {
+ runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top")
+ out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("resize Request failed %v", err)
+ c.Fatalf(out, err)
}
+ cleanedContainerID := strings.TrimSpace(out)
- logDone("container resize - when started")
+ endpoint := "/containers/" + cleanedContainerID + "/resize?h=foo&w=bar"
+ status, _, err := sockRequest("POST", endpoint, nil)
+ c.Assert(status, check.Equals, http.StatusInternalServerError)
+ c.Assert(err, check.IsNil)
}
-func TestResizeApiResponseWhenContainerNotStarted(t *testing.T) {
+func (s *DockerSuite) TestResizeApiResponseWhenContainerNotStarted(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf(out, err)
+ c.Fatalf(out, err)
}
- defer deleteAllContainers()
cleanedContainerID := strings.TrimSpace(out)
- // make sure the exited cintainer is not running
+ // make sure the exited container is not running
runCmd = exec.Command(dockerBinary, "wait", cleanedContainerID)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf(out, err)
+ c.Fatalf(out, err)
}
endpoint := "/containers/" + cleanedContainerID + "/resize?h=40&w=40"
- body, err := sockRequest("POST", endpoint, nil)
- if err == nil {
- t.Fatalf("resize should fail when container is not started")
- }
+ status, body, err := sockRequest("POST", endpoint, nil)
+ c.Assert(status, check.Equals, http.StatusInternalServerError)
+ c.Assert(err, check.IsNil)
+
if !strings.Contains(string(body), "Cannot resize container") && !strings.Contains(string(body), cleanedContainerID) {
- t.Fatalf("resize should fail with message 'Cannot resize container' but instead received %s", string(body))
+ c.Fatalf("resize should fail with message 'Cannot resize container' but instead received %s", string(body))
}
-
- logDone("container resize - when not started should not resize")
}
diff --git a/integration-cli/docker_api_version_test.go b/integration-cli/docker_api_version_test.go
new file mode 100644
index 0000000000000..b756794c265ee
--- /dev/null
+++ b/integration-cli/docker_api_version_test.go
@@ -0,0 +1,25 @@
+package main
+
+import (
+ "encoding/json"
+ "net/http"
+
+ "github.com/docker/docker/api/types"
+ "github.com/docker/docker/autogen/dockerversion"
+ "github.com/go-check/check"
+)
+
+func (s *DockerSuite) TestGetVersion(c *check.C) {
+ status, body, err := sockRequest("GET", "/version", nil)
+ c.Assert(status, check.Equals, http.StatusOK)
+ c.Assert(err, check.IsNil)
+
+ var v types.Version
+ if err := json.Unmarshal(body, &v); err != nil {
+ c.Fatal(err)
+ }
+
+ if v.Version != dockerversion.VERSION {
+ c.Fatal("Version mismatch")
+ }
+}
diff --git a/integration-cli/docker_cli_attach_test.go b/integration-cli/docker_cli_attach_test.go
index cf21cda5883f6..fc2ea1a1d1ed7 100644
--- a/integration-cli/docker_cli_attach_test.go
+++ b/integration-cli/docker_cli_attach_test.go
@@ -1,18 +1,20 @@
package main
import (
+ "bufio"
+ "fmt"
"io"
"os/exec"
"strings"
"sync"
- "testing"
"time"
+
+ "github.com/go-check/check"
)
const attachWait = 5 * time.Second
-func TestAttachMultipleAndRestart(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestAttachMultipleAndRestart(c *check.C) {
endGroup := &sync.WaitGroup{}
startGroup := &sync.WaitGroup{}
@@ -20,7 +22,7 @@ func TestAttachMultipleAndRestart(t *testing.T) {
startGroup.Add(3)
if err := waitForContainer("attacher", "-d", "busybox", "/bin/sh", "-c", "while true; do sleep 1; echo hello; done"); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
startDone := make(chan struct{})
@@ -38,32 +40,32 @@ func TestAttachMultipleAndRestart(t *testing.T) {
for i := 0; i < 3; i++ {
go func() {
- c := exec.Command(dockerBinary, "attach", "attacher")
+ cmd := exec.Command(dockerBinary, "attach", "attacher")
defer func() {
- c.Wait()
+ cmd.Wait()
endGroup.Done()
}()
- out, err := c.StdoutPipe()
+ out, err := cmd.StdoutPipe()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- if err := c.Start(); err != nil {
- t.Fatal(err)
+ if err := cmd.Start(); err != nil {
+ c.Fatal(err)
}
buf := make([]byte, 1024)
if _, err := out.Read(buf); err != nil && err != io.EOF {
- t.Fatal(err)
+ c.Fatal(err)
}
startGroup.Done()
if !strings.Contains(string(buf), "hello") {
- t.Fatalf("unexpected output %s expected hello\n", string(buf))
+ c.Fatalf("unexpected output %s expected hello\n", string(buf))
}
}()
}
@@ -71,66 +73,111 @@ func TestAttachMultipleAndRestart(t *testing.T) {
select {
case <-startDone:
case <-time.After(attachWait):
- t.Fatalf("Attaches did not initialize properly")
+ c.Fatalf("Attaches did not initialize properly")
}
cmd := exec.Command(dockerBinary, "kill", "attacher")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
select {
case <-endDone:
case <-time.After(attachWait):
- t.Fatalf("Attaches did not finish properly")
+ c.Fatalf("Attaches did not finish properly")
}
- logDone("attach - multiple attach")
}
-func TestAttachTtyWithoutStdin(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestAttachTtyWithoutStdin(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-d", "-ti", "busybox")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to start container: %v (%v)", out, err)
+ c.Fatalf("failed to start container: %v (%v)", out, err)
}
id := strings.TrimSpace(out)
if err := waitRun(id); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer func() {
cmd := exec.Command(dockerBinary, "kill", id)
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatalf("failed to kill container: %v (%v)", out, err)
+ c.Fatalf("failed to kill container: %v (%v)", out, err)
}
}()
- done := make(chan struct{})
+ done := make(chan error)
go func() {
defer close(done)
cmd := exec.Command(dockerBinary, "attach", id)
if _, err := cmd.StdinPipe(); err != nil {
- t.Fatal(err)
+ done <- err
+ return
}
expected := "cannot enable tty mode"
if out, _, err := runCommandWithOutput(cmd); err == nil {
- t.Fatal("attach should have failed")
+ done <- fmt.Errorf("attach should have failed")
+ return
} else if !strings.Contains(out, expected) {
- t.Fatalf("attach failed with error %q: expected %q", out, expected)
+ done <- fmt.Errorf("attach failed with error %q: expected %q", out, expected)
+ return
}
}()
select {
- case <-done:
+ case err := <-done:
+ c.Assert(err, check.IsNil)
case <-time.After(attachWait):
- t.Fatal("attach is running but should have failed")
+ c.Fatal("attach is running but should have failed")
+ }
+}
+
+func (s *DockerSuite) TestAttachDisconnect(c *check.C) {
+ out, _ := dockerCmd(c, "run", "-di", "busybox", "/bin/cat")
+ id := strings.TrimSpace(out)
+
+ cmd := exec.Command(dockerBinary, "attach", id)
+ stdin, err := cmd.StdinPipe()
+ if err != nil {
+ c.Fatal(err)
+ }
+ defer stdin.Close()
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ c.Fatal(err)
+ }
+ defer stdout.Close()
+ if err := cmd.Start(); err != nil {
+ c.Fatal(err)
+ }
+ defer cmd.Process.Kill()
+
+ if _, err := stdin.Write([]byte("hello\n")); err != nil {
+ c.Fatal(err)
+ }
+ out, err = bufio.NewReader(stdout).ReadString('\n')
+ if err != nil {
+ c.Fatal(err)
+ }
+ if strings.TrimSpace(out) != "hello" {
+ c.Fatalf("expected 'hello', got %q", out)
+ }
+
+ if err := stdin.Close(); err != nil {
+ c.Fatal(err)
+ }
+
+ // Expect container to still be running after stdin is closed
+ running, err := inspectField(id, "State.Running")
+ if err != nil {
+ c.Fatal(err)
+ }
+ if running != "true" {
+ c.Fatal("expected container to still be running")
}
- logDone("attach - forbid piped stdin to tty enabled container")
}
diff --git a/integration-cli/docker_cli_attach_unix_test.go b/integration-cli/docker_cli_attach_unix_test.go
index 8d15735120cb8..82808a5b087f1 100644
--- a/integration-cli/docker_cli_attach_unix_test.go
+++ b/integration-cli/docker_cli_attach_unix_test.go
@@ -3,37 +3,38 @@
package main
import (
+ "bufio"
"os/exec"
"strings"
- "testing"
"time"
+ "github.com/docker/docker/pkg/stringid"
+ "github.com/go-check/check"
"github.com/kr/pty"
)
// #9860
-func TestAttachClosedOnContainerStop(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestAttachClosedOnContainerStop(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-dti", "busybox", "sleep", "2")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to start container: %v (%v)", out, err)
+ c.Fatalf("failed to start container: %v (%v)", out, err)
}
id := strings.TrimSpace(out)
if err := waitRun(id); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- done := make(chan struct{})
-
+ errChan := make(chan error)
go func() {
- defer close(done)
+ defer close(errChan)
_, tty, err := pty.Open()
if err != nil {
- t.Fatalf("could not open pty: %v", err)
+ errChan <- err
+ return
}
attachCmd := exec.Command(dockerBinary, "attach", id)
attachCmd.Stdin = tty
@@ -41,58 +42,61 @@ func TestAttachClosedOnContainerStop(t *testing.T) {
attachCmd.Stderr = tty
if err := attachCmd.Run(); err != nil {
- t.Fatalf("attach returned error %s", err)
+ errChan <- err
+ return
}
}()
waitCmd := exec.Command(dockerBinary, "wait", id)
if out, _, err = runCommandWithOutput(waitCmd); err != nil {
- t.Fatalf("error thrown while waiting for container: %s, %v", out, err)
+ c.Fatalf("error thrown while waiting for container: %s, %v", out, err)
}
select {
- case <-done:
+ case err := <-errChan:
+ c.Assert(err, check.IsNil)
case <-time.After(attachWait):
- t.Fatal("timed out without attach returning")
+ c.Fatal("timed out without attach returning")
}
- logDone("attach - return after container finished")
}
-func TestAttachAfterDetach(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestAttachAfterDetach(c *check.C) {
name := "detachtest"
cpty, tty, err := pty.Open()
if err != nil {
- t.Fatalf("Could not open pty: %v", err)
+ c.Fatalf("Could not open pty: %v", err)
}
cmd := exec.Command(dockerBinary, "run", "-ti", "--name", name, "busybox")
cmd.Stdin = tty
cmd.Stdout = tty
cmd.Stderr = tty
- detached := make(chan struct{})
+ errChan := make(chan error)
go func() {
- if err := cmd.Run(); err != nil {
- t.Fatalf("attach returned error %s", err)
- }
- close(detached)
+ errChan <- cmd.Run()
+ close(errChan)
}()
time.Sleep(500 * time.Millisecond)
if err := waitRun(name); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cpty.Write([]byte{16})
time.Sleep(100 * time.Millisecond)
cpty.Write([]byte{17})
- <-detached
+ select {
+ case err := <-errChan:
+ c.Assert(err, check.IsNil)
+ case <-time.After(5 * time.Second):
+ c.Fatal("timeout while detaching")
+ }
cpty, tty, err = pty.Open()
if err != nil {
- t.Fatalf("Could not open pty: %v", err)
+ c.Fatalf("Could not open pty: %v", err)
}
cmd = exec.Command(dockerBinary, "attach", name)
@@ -101,7 +105,7 @@ func TestAttachAfterDetach(t *testing.T) {
cmd.Stderr = tty
if err := cmd.Start(); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
bytes := make([]byte, 10)
@@ -120,20 +124,162 @@ func TestAttachAfterDetach(t *testing.T) {
select {
case err := <-readErr:
- if err != nil {
- t.Fatal(err)
- }
+ c.Assert(err, check.IsNil)
case <-time.After(2 * time.Second):
- t.Fatal("timeout waiting for attach read")
+ c.Fatal("timeout waiting for attach read")
}
if err := cmd.Wait(); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !strings.Contains(string(bytes[:nBytes]), "/ #") {
- t.Fatalf("failed to get a new prompt. got %s", string(bytes[:nBytes]))
+ c.Fatalf("failed to get a new prompt. got %s", string(bytes[:nBytes]))
+ }
+
+}
+
+// TestAttachDetach checks that attach in tty mode can be detached using the long container ID
+func (s *DockerSuite) TestAttachDetach(c *check.C) {
+ out, _ := dockerCmd(c, "run", "-itd", "busybox", "cat")
+ id := strings.TrimSpace(out)
+ if err := waitRun(id); err != nil {
+ c.Fatal(err)
+ }
+
+ cpty, tty, err := pty.Open()
+ if err != nil {
+ c.Fatal(err)
+ }
+ defer cpty.Close()
+
+ cmd := exec.Command(dockerBinary, "attach", id)
+ cmd.Stdin = tty
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ c.Fatal(err)
+ }
+ defer stdout.Close()
+ if err := cmd.Start(); err != nil {
+ c.Fatal(err)
+ }
+ if err := waitRun(id); err != nil {
+ c.Fatalf("error waiting for container to start: %v", err)
+ }
+
+ if _, err := cpty.Write([]byte("hello\n")); err != nil {
+ c.Fatal(err)
+ }
+ out, err = bufio.NewReader(stdout).ReadString('\n')
+ if err != nil {
+ c.Fatal(err)
+ }
+ if strings.TrimSpace(out) != "hello" {
+ c.Fatalf("expected 'hello', got %q", out)
+ }
+
+ // escape sequence
+ if _, err := cpty.Write([]byte{16}); err != nil {
+ c.Fatal(err)
+ }
+ time.Sleep(100 * time.Millisecond)
+ if _, err := cpty.Write([]byte{17}); err != nil {
+ c.Fatal(err)
+ }
+
+ ch := make(chan struct{})
+ go func() {
+ cmd.Wait()
+ ch <- struct{}{}
+ }()
+
+ running, err := inspectField(id, "State.Running")
+ if err != nil {
+ c.Fatal(err)
+ }
+ if running != "true" {
+ c.Fatal("expected container to still be running")
+ }
+
+ go func() {
+ dockerCmd(c, "kill", id)
+ }()
+
+ select {
+ case <-ch:
+ case <-time.After(10 * time.Millisecond):
+ c.Fatal("timed out waiting for container to exit")
+ }
+
+}
+
+// TestAttachDetachTruncatedID checks that attach in tty mode can be detached
+func (s *DockerSuite) TestAttachDetachTruncatedID(c *check.C) {
+ out, _ := dockerCmd(c, "run", "-itd", "busybox", "cat")
+ id := stringid.TruncateID(strings.TrimSpace(out))
+ if err := waitRun(id); err != nil {
+ c.Fatal(err)
+ }
+
+ cpty, tty, err := pty.Open()
+ if err != nil {
+ c.Fatal(err)
+ }
+ defer cpty.Close()
+
+ cmd := exec.Command(dockerBinary, "attach", id)
+ cmd.Stdin = tty
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ c.Fatal(err)
+ }
+ defer stdout.Close()
+ if err := cmd.Start(); err != nil {
+ c.Fatal(err)
+ }
+
+ if _, err := cpty.Write([]byte("hello\n")); err != nil {
+ c.Fatal(err)
+ }
+ out, err = bufio.NewReader(stdout).ReadString('\n')
+ if err != nil {
+ c.Fatal(err)
+ }
+ if strings.TrimSpace(out) != "hello" {
+ c.Fatalf("expected 'hello', got %q", out)
+ }
+
+ // escape sequence
+ if _, err := cpty.Write([]byte{16}); err != nil {
+ c.Fatal(err)
+ }
+ time.Sleep(100 * time.Millisecond)
+ if _, err := cpty.Write([]byte{17}); err != nil {
+ c.Fatal(err)
+ }
+
+ ch := make(chan struct{})
+ go func() {
+ cmd.Wait()
+ ch <- struct{}{}
+ }()
+
+ running, err := inspectField(id, "State.Running")
+ if err != nil {
+ c.Fatal(err)
+ }
+ if running != "true" {
+ c.Fatal("expected container to still be running")
+ }
+
+ go func() {
+ dockerCmd(c, "kill", id)
+ }()
+
+ select {
+ case <-ch:
+ case <-time.After(10 * time.Millisecond):
+ c.Fatal("timed out waiting for container to exit")
}
- logDone("attach - reconnect after detaching")
}
diff --git a/integration-cli/docker_cli_build_test.go b/integration-cli/docker_cli_build_test.go
index 01e6d1d3d68d6..b74dce2cfa906 100644
--- a/integration-cli/docker_cli_build_test.go
+++ b/integration-cli/docker_cli_build_test.go
@@ -15,19 +15,17 @@ import (
"runtime"
"strconv"
"strings"
- "sync"
- "testing"
"text/template"
"time"
"github.com/docker/docker/builder/command"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/stringutils"
+ "github.com/go-check/check"
)
-func TestBuildJSONEmptyRun(t *testing.T) {
+func (s *DockerSuite) TestBuildJSONEmptyRun(c *check.C) {
name := "testbuildjsonemptyrun"
- defer deleteImages(name)
_, err := buildImage(
name,
@@ -38,15 +36,13 @@ func TestBuildJSONEmptyRun(t *testing.T) {
true)
if err != nil {
- t.Fatal("error when dealing with a RUN statement with empty JSON array")
+ c.Fatal("error when dealing with a RUN statement with empty JSON array")
}
- logDone("build - RUN with an empty array should not panic")
}
-func TestBuildEmptyWhitespace(t *testing.T) {
+func (s *DockerSuite) TestBuildEmptyWhitespace(c *check.C) {
name := "testbuildemptywhitespace"
- defer deleteImages(name)
_, err := buildImage(
name,
@@ -59,15 +55,13 @@ func TestBuildEmptyWhitespace(t *testing.T) {
true)
if err == nil {
- t.Fatal("no error when dealing with a COPY statement with no content on the same line")
+ c.Fatal("no error when dealing with a COPY statement with no content on the same line")
}
- logDone("build - statements with whitespace and no content should generate a parse error")
}
-func TestBuildShCmdJSONEntrypoint(t *testing.T) {
+func (s *DockerSuite) TestBuildShCmdJSONEntrypoint(c *check.C) {
name := "testbuildshcmdjsonentrypoint"
- defer deleteImages(name)
_, err := buildImage(
name,
@@ -79,7 +73,7 @@ func TestBuildShCmdJSONEntrypoint(t *testing.T) {
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
out, _, err := runCommandWithOutput(
@@ -90,19 +84,17 @@ func TestBuildShCmdJSONEntrypoint(t *testing.T) {
name))
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if strings.TrimSpace(out) != "/bin/sh -c echo test" {
- t.Fatal("CMD did not contain /bin/sh -c")
+ c.Fatal("CMD did not contain /bin/sh -c")
}
- logDone("build - CMD should always contain /bin/sh -c when specified without JSON")
}
-func TestBuildEnvironmentReplacementUser(t *testing.T) {
+func (s *DockerSuite) TestBuildEnvironmentReplacementUser(c *check.C) {
name := "testbuildenvironmentreplacement"
- defer deleteImages(name)
_, err := buildImage(name, `
FROM scratch
@@ -110,24 +102,22 @@ func TestBuildEnvironmentReplacementUser(t *testing.T) {
USER ${user}
`, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectFieldJSON(name, "Config.User")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != `"foo"` {
- t.Fatal("User foo from environment not in Config.User on image")
+ c.Fatal("User foo from environment not in Config.User on image")
}
- logDone("build - user environment replacement")
}
-func TestBuildEnvironmentReplacementVolume(t *testing.T) {
+func (s *DockerSuite) TestBuildEnvironmentReplacementVolume(c *check.C) {
name := "testbuildenvironmentreplacement"
- defer deleteImages(name)
_, err := buildImage(name, `
FROM scratch
@@ -135,30 +125,28 @@ func TestBuildEnvironmentReplacementVolume(t *testing.T) {
VOLUME ${volume}
`, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectFieldJSON(name, "Config.Volumes")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
var volumes map[string]interface{}
if err := json.Unmarshal([]byte(res), &volumes); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, ok := volumes["/quux"]; !ok {
- t.Fatal("Volume /quux from environment not in Config.Volumes on image")
+ c.Fatal("Volume /quux from environment not in Config.Volumes on image")
}
- logDone("build - volume environment replacement")
}
-func TestBuildEnvironmentReplacementExpose(t *testing.T) {
+func (s *DockerSuite) TestBuildEnvironmentReplacementExpose(c *check.C) {
name := "testbuildenvironmentreplacement"
- defer deleteImages(name)
_, err := buildImage(name, `
FROM scratch
@@ -166,30 +154,28 @@ func TestBuildEnvironmentReplacementExpose(t *testing.T) {
EXPOSE ${port}
`, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectFieldJSON(name, "Config.ExposedPorts")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
var exposedPorts map[string]interface{}
if err := json.Unmarshal([]byte(res), &exposedPorts); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, ok := exposedPorts["80/tcp"]; !ok {
- t.Fatal("Exposed port 80 from environment not in Config.ExposedPorts on image")
+ c.Fatal("Exposed port 80 from environment not in Config.ExposedPorts on image")
}
- logDone("build - expose environment replacement")
}
-func TestBuildEnvironmentReplacementWorkdir(t *testing.T) {
+func (s *DockerSuite) TestBuildEnvironmentReplacementWorkdir(c *check.C) {
name := "testbuildenvironmentreplacement"
- defer deleteImages(name)
_, err := buildImage(name, `
FROM busybox
@@ -199,15 +185,13 @@ func TestBuildEnvironmentReplacementWorkdir(t *testing.T) {
`, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - workdir environment replacement")
}
-func TestBuildEnvironmentReplacementAddCopy(t *testing.T) {
+func (s *DockerSuite) TestBuildEnvironmentReplacementAddCopy(c *check.C) {
name := "testbuildenvironmentreplacement"
- defer deleteImages(name)
ctx, err := fakeContext(`
FROM scratch
@@ -230,22 +214,19 @@ func TestBuildEnvironmentReplacementAddCopy(t *testing.T) {
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - add/copy environment replacement")
}
-func TestBuildEnvironmentReplacementEnv(t *testing.T) {
+func (s *DockerSuite) TestBuildEnvironmentReplacementEnv(c *check.C) {
name := "testbuildenvironmentreplacement"
- defer deleteImages(name)
-
_, err := buildImage(name,
`
FROM busybox
@@ -263,18 +244,18 @@ func TestBuildEnvironmentReplacementEnv(t *testing.T) {
`, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectFieldJSON(name, "Config.Env")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
envResult := []string{}
if err = unmarshalJSON([]byte(res), &envResult); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
found := false
@@ -285,37 +266,34 @@ func TestBuildEnvironmentReplacementEnv(t *testing.T) {
if parts[0] == "bar" {
found = true
if parts[1] != "zzz" {
- t.Fatalf("Could not find replaced var for env `bar`: got %q instead of `zzz`", parts[1])
+ c.Fatalf("Could not find replaced var for env `bar`: got %q instead of `zzz`", parts[1])
}
} else if strings.HasPrefix(parts[0], "env") {
envCount++
if parts[1] != "zzz" {
- t.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1])
+ c.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1])
}
} else if strings.HasPrefix(parts[0], "env") {
envCount++
if parts[1] != "foo" {
- t.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1])
+ c.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1])
}
}
}
if !found {
- t.Fatal("Never found the `bar` env variable")
+ c.Fatal("Never found the `bar` env variable")
}
if envCount != 4 {
- t.Fatalf("Didn't find all env vars - only saw %d\n%s", envCount, envResult)
+ c.Fatalf("Didn't find all env vars - only saw %d\n%s", envCount, envResult)
}
- logDone("build - env environment replacement")
}
-func TestBuildHandleEscapes(t *testing.T) {
+func (s *DockerSuite) TestBuildHandleEscapes(c *check.C) {
name := "testbuildhandleescapes"
- defer deleteImages(name)
-
_, err := buildImage(name,
`
FROM scratch
@@ -324,22 +302,22 @@ func TestBuildHandleEscapes(t *testing.T) {
`, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
var result map[string]map[string]struct{}
res, err := inspectFieldJSON(name, "Config.Volumes")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err = unmarshalJSON([]byte(res), &result); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, ok := result["bar"]; !ok {
- t.Fatal("Could not find volume bar set from env foo in volumes table")
+ c.Fatal("Could not find volume bar set from env foo in volumes table")
}
deleteImages(name)
@@ -352,20 +330,20 @@ func TestBuildHandleEscapes(t *testing.T) {
`, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err = inspectFieldJSON(name, "Config.Volumes")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err = unmarshalJSON([]byte(res), &result); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, ok := result["${FOO}"]; !ok {
- t.Fatal("Could not find volume ${FOO} set from env foo in volumes table")
+ c.Fatal("Could not find volume ${FOO} set from env foo in volumes table")
}
deleteImages(name)
@@ -382,31 +360,28 @@ func TestBuildHandleEscapes(t *testing.T) {
`, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err = inspectFieldJSON(name, "Config.Volumes")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err = unmarshalJSON([]byte(res), &result); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, ok := result[`\\\${FOO}`]; !ok {
- t.Fatal(`Could not find volume \\\${FOO} set from env foo in volumes table`, result)
+ c.Fatal(`Could not find volume \\\${FOO} set from env foo in volumes table`, result)
}
- logDone("build - handle escapes")
}
-func TestBuildOnBuildLowercase(t *testing.T) {
+func (s *DockerSuite) TestBuildOnBuildLowercase(c *check.C) {
name := "testbuildonbuildlowercase"
name2 := "testbuildonbuildlowercase2"
- defer deleteImages(name, name2)
-
_, err := buildImage(name,
`
FROM busybox
@@ -414,7 +389,7 @@ func TestBuildOnBuildLowercase(t *testing.T) {
`, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
_, out, err := buildImageWithOut(name2, fmt.Sprintf(`
@@ -422,24 +397,21 @@ func TestBuildOnBuildLowercase(t *testing.T) {
`, name), true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !strings.Contains(out, "quux") {
- t.Fatalf("Did not receive the expected echo text, got %s", out)
+ c.Fatalf("Did not receive the expected echo text, got %s", out)
}
if strings.Contains(out, "ONBUILD ONBUILD") {
- t.Fatalf("Got an ONBUILD ONBUILD error with no error: got %s", out)
+ c.Fatalf("Got an ONBUILD ONBUILD error with no error: got %s", out)
}
- logDone("build - handle case-insensitive onbuild statement")
}
-func TestBuildEnvEscapes(t *testing.T) {
+func (s *DockerSuite) TestBuildEnvEscapes(c *check.C) {
name := "testbuildenvescapes"
- defer deleteImages(name)
- defer deleteAllContainers()
_, err := buildImage(name,
`
FROM busybox
@@ -451,20 +423,17 @@ func TestBuildEnvEscapes(t *testing.T) {
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-t", name))
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if strings.TrimSpace(out) != "$" {
- t.Fatalf("Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q", strings.TrimSpace(out))
+ c.Fatalf("Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q", strings.TrimSpace(out))
}
- logDone("build - env should handle \\$ properly")
}
-func TestBuildEnvOverwrite(t *testing.T) {
+func (s *DockerSuite) TestBuildEnvOverwrite(c *check.C) {
name := "testbuildenvoverwrite"
- defer deleteImages(name)
- defer deleteAllContainers()
_, err := buildImage(name,
`
@@ -475,32 +444,28 @@ func TestBuildEnvOverwrite(t *testing.T) {
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-e", "TEST=bar", "-t", name))
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if strings.TrimSpace(out) != "bar" {
- t.Fatalf("Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q", strings.TrimSpace(out))
+ c.Fatalf("Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q", strings.TrimSpace(out))
}
- logDone("build - env should overwrite builder ENV during run")
}
-func TestBuildOnBuildForbiddenMaintainerInSourceImage(t *testing.T) {
+func (s *DockerSuite) TestBuildOnBuildForbiddenMaintainerInSourceImage(c *check.C) {
name := "testbuildonbuildforbiddenmaintainerinsourceimage"
- defer deleteImages("onbuild")
- defer deleteImages(name)
- defer deleteAllContainers()
createCmd := exec.Command(dockerBinary, "create", "busybox", "true")
out, _, _, err := runCommandWithStdoutStderr(createCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -508,7 +473,7 @@ func TestBuildOnBuildForbiddenMaintainerInSourceImage(t *testing.T) {
commitCmd := exec.Command(dockerBinary, "commit", "--run", "{\"OnBuild\":[\"MAINTAINER docker.io\"]}", cleanedContainerID, "onbuild")
if _, err := runCommand(commitCmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
_, err = buildImage(name,
@@ -516,25 +481,21 @@ func TestBuildOnBuildForbiddenMaintainerInSourceImage(t *testing.T) {
true)
if err != nil {
if !strings.Contains(err.Error(), "maintainer isn't allowed as an ONBUILD trigger") {
- t.Fatalf("Wrong error %v, must be about MAINTAINER and ONBUILD in source image", err)
+ c.Fatalf("Wrong error %v, must be about MAINTAINER and ONBUILD in source image", err)
}
} else {
- t.Fatal("Error must not be nil")
+ c.Fatal("Error must not be nil")
}
- logDone("build - onbuild forbidden maintainer in source image")
}
-func TestBuildOnBuildForbiddenFromInSourceImage(t *testing.T) {
+func (s *DockerSuite) TestBuildOnBuildForbiddenFromInSourceImage(c *check.C) {
name := "testbuildonbuildforbiddenfrominsourceimage"
- defer deleteImages("onbuild")
- defer deleteImages(name)
- defer deleteAllContainers()
createCmd := exec.Command(dockerBinary, "create", "busybox", "true")
out, _, _, err := runCommandWithStdoutStderr(createCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -542,7 +503,7 @@ func TestBuildOnBuildForbiddenFromInSourceImage(t *testing.T) {
commitCmd := exec.Command(dockerBinary, "commit", "--run", "{\"OnBuild\":[\"FROM busybox\"]}", cleanedContainerID, "onbuild")
if _, err := runCommand(commitCmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
_, err = buildImage(name,
@@ -550,25 +511,21 @@ func TestBuildOnBuildForbiddenFromInSourceImage(t *testing.T) {
true)
if err != nil {
if !strings.Contains(err.Error(), "from isn't allowed as an ONBUILD trigger") {
- t.Fatalf("Wrong error %v, must be about FROM and ONBUILD in source image", err)
+ c.Fatalf("Wrong error %v, must be about FROM and ONBUILD in source image", err)
}
} else {
- t.Fatal("Error must not be nil")
+ c.Fatal("Error must not be nil")
}
- logDone("build - onbuild forbidden from in source image")
}
-func TestBuildOnBuildForbiddenChainedInSourceImage(t *testing.T) {
+func (s *DockerSuite) TestBuildOnBuildForbiddenChainedInSourceImage(c *check.C) {
name := "testbuildonbuildforbiddenchainedinsourceimage"
- defer deleteImages("onbuild")
- defer deleteImages(name)
- defer deleteAllContainers()
createCmd := exec.Command(dockerBinary, "create", "busybox", "true")
out, _, _, err := runCommandWithStdoutStderr(createCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -576,7 +533,7 @@ func TestBuildOnBuildForbiddenChainedInSourceImage(t *testing.T) {
commitCmd := exec.Command(dockerBinary, "commit", "--run", "{\"OnBuild\":[\"ONBUILD RUN ls\"]}", cleanedContainerID, "onbuild")
if _, err := runCommand(commitCmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
_, err = buildImage(name,
@@ -584,23 +541,18 @@ func TestBuildOnBuildForbiddenChainedInSourceImage(t *testing.T) {
true)
if err != nil {
if !strings.Contains(err.Error(), "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed") {
- t.Fatalf("Wrong error %v, must be about chaining ONBUILD in source image", err)
+ c.Fatalf("Wrong error %v, must be about chaining ONBUILD in source image", err)
}
} else {
- t.Fatal("Error must not be nil")
+ c.Fatal("Error must not be nil")
}
- logDone("build - onbuild forbidden chained in source image")
}
-func TestBuildOnBuildCmdEntrypointJSON(t *testing.T) {
+func (s *DockerSuite) TestBuildOnBuildCmdEntrypointJSON(c *check.C) {
name1 := "onbuildcmd"
name2 := "onbuildgenerated"
- defer deleteImages(name2)
- defer deleteImages(name1)
- defer deleteAllContainers()
-
_, err := buildImage(name1, `
FROM busybox
ONBUILD CMD ["hello world"]
@@ -609,71 +561,64 @@ ONBUILD RUN ["true"]`,
false)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
_, err = buildImage(name2, fmt.Sprintf(`FROM %s`, name1), false)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-t", name2))
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !regexp.MustCompile(`(?m)^hello world`).MatchString(out) {
- t.Fatal("did not get echo output from onbuild", out)
+ c.Fatal("did not get echo output from onbuild", out)
}
- logDone("build - onbuild with json entrypoint/cmd")
}
-func TestBuildOnBuildEntrypointJSON(t *testing.T) {
+func (s *DockerSuite) TestBuildOnBuildEntrypointJSON(c *check.C) {
name1 := "onbuildcmd"
name2 := "onbuildgenerated"
- defer deleteImages(name2)
- defer deleteImages(name1)
- defer deleteAllContainers()
-
_, err := buildImage(name1, `
FROM busybox
ONBUILD ENTRYPOINT ["echo"]`,
false)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
_, err = buildImage(name2, fmt.Sprintf("FROM %s\nCMD [\"hello world\"]\n", name1), false)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-t", name2))
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !regexp.MustCompile(`(?m)^hello world`).MatchString(out) {
- t.Fatal("got malformed output from onbuild", out)
+ c.Fatal("got malformed output from onbuild", out)
}
- logDone("build - onbuild with json entrypoint")
}
-func TestBuildCacheADD(t *testing.T) {
+func (s *DockerSuite) TestBuildCacheADD(c *check.C) {
name := "testbuildtwoimageswithadd"
- defer deleteImages(name)
server, err := fakeStorage(map[string]string{
"robots.txt": "hello",
"index.html": "world",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer server.Close()
@@ -681,10 +626,10 @@ func TestBuildCacheADD(t *testing.T) {
fmt.Sprintf(`FROM scratch
ADD %s/robots.txt /`, server.URL()),
true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
deleteImages(name)
_, out, err := buildImageWithOut(name,
@@ -692,24 +637,22 @@ func TestBuildCacheADD(t *testing.T) {
ADD %s/index.html /`, server.URL()),
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if strings.Contains(out, "Using cache") {
- t.Fatal("2nd build used cache on ADD, it shouldn't")
+ c.Fatal("2nd build used cache on ADD, it shouldn't")
}
- logDone("build - build two images with remote ADD")
}
-func TestBuildLastModified(t *testing.T) {
+func (s *DockerSuite) TestBuildLastModified(c *check.C) {
name := "testbuildlastmodified"
- defer deleteImages(name)
server, err := fakeStorage(map[string]string{
"file": "hello",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer server.Close()
@@ -722,13 +665,13 @@ RUN ls -le /file`
dockerfile := fmt.Sprintf(dFmt, server.URL())
if _, out, err = buildImageWithOut(name, dockerfile, false); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
originMTime := regexp.MustCompile(`root.*/file.*\n`).FindString(out)
// Make sure our regexp is correct
if strings.Index(originMTime, "/file") < 0 {
- t.Fatalf("Missing ls info on 'file':\n%s", out)
+ c.Fatalf("Missing ls info on 'file':\n%s", out)
}
// Build it again and make sure the mtime of the file didn't change.
@@ -736,12 +679,12 @@ RUN ls -le /file`
time.Sleep(2 * time.Second)
if _, out2, err = buildImageWithOut(name, dockerfile, false); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
newMTime := regexp.MustCompile(`root.*/file.*\n`).FindString(out2)
if newMTime != originMTime {
- t.Fatalf("MTime changed:\nOrigin:%s\nNew:%s", originMTime, newMTime)
+ c.Fatalf("MTime changed:\nOrigin:%s\nNew:%s", originMTime, newMTime)
}
// Now 'touch' the file and make sure the timestamp DID change this time
@@ -750,45 +693,41 @@ RUN ls -le /file`
"file": "hello",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer server.Close()
dockerfile = fmt.Sprintf(dFmt, server.URL())
if _, out2, err = buildImageWithOut(name, dockerfile, false); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
newMTime = regexp.MustCompile(`root.*/file.*\n`).FindString(out2)
if newMTime == originMTime {
- t.Fatalf("MTime didn't change:\nOrigin:%s\nNew:%s", originMTime, newMTime)
+ c.Fatalf("MTime didn't change:\nOrigin:%s\nNew:%s", originMTime, newMTime)
}
- logDone("build - use Last-Modified header")
}
-func TestBuildSixtySteps(t *testing.T) {
+func (s *DockerSuite) TestBuildSixtySteps(c *check.C) {
name := "foobuildsixtysteps"
- defer deleteImages(name)
ctx, err := fakeContext("FROM scratch\n"+strings.Repeat("ADD foo /\n", 60),
map[string]string{
"foo": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - build an image with sixty build steps")
}
-func TestBuildAddSingleFileToRoot(t *testing.T) {
+func (s *DockerSuite) TestBuildAddSingleFileToRoot(c *check.C) {
name := "testaddimg"
- defer deleteImages(name)
ctx, err := fakeContext(fmt.Sprintf(`FROM busybox
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
RUN echo 'dockerio:x:1001:' >> /etc/group
@@ -802,48 +741,44 @@ RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expecte
"test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - add single file to root")
}
// Issue #3960: "ADD src ." hangs
-func TestBuildAddSingleFileToWorkdir(t *testing.T) {
+func (s *DockerSuite) TestBuildAddSingleFileToWorkdir(c *check.C) {
name := "testaddsinglefiletoworkdir"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
ADD test_file .`,
map[string]string{
"test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
- done := make(chan struct{})
+ errChan := make(chan error)
go func() {
- if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
- }
- close(done)
+ _, err := buildImageFromContext(name, ctx, true)
+ errChan <- err
+ close(errChan)
}()
select {
case <-time.After(5 * time.Second):
- t.Fatal("Build with adding to workdir timed out")
- case <-done:
+ c.Fatal("Build with adding to workdir timed out")
+ case err := <-errChan:
+ c.Assert(err, check.IsNil)
}
- logDone("build - add single file to workdir")
}
-func TestBuildAddSingleFileToExistDir(t *testing.T) {
+func (s *DockerSuite) TestBuildAddSingleFileToExistDir(c *check.C) {
name := "testaddsinglefiletoexistdir"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
RUN echo 'dockerio:x:1001:' >> /etc/group
@@ -858,27 +793,25 @@ RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio'
"test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - add single file to existing dir")
}
-func TestBuildCopyAddMultipleFiles(t *testing.T) {
+func (s *DockerSuite) TestBuildCopyAddMultipleFiles(c *check.C) {
server, err := fakeStorage(map[string]string{
"robots.txt": "hello",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer server.Close()
name := "testcopymultiplefilestofile"
- defer deleteImages(name)
ctx, err := fakeContext(fmt.Sprintf(`FROM busybox
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
RUN echo 'dockerio:x:1001:' >> /etc/group
@@ -905,18 +838,16 @@ RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio'
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - multiple file copy/add tests")
}
-func TestBuildAddMultipleFilesToFile(t *testing.T) {
+func (s *DockerSuite) TestBuildAddMultipleFilesToFile(c *check.C) {
name := "testaddmultiplefilestofile"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM scratch
ADD file1.txt file2.txt test
`,
@@ -926,20 +857,18 @@ func TestBuildAddMultipleFilesToFile(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
expected := "When using ADD with more than one source file, the destination must be a directory and end with a /"
if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) {
- t.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err)
+ c.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err)
}
- logDone("build - multiple add files to file")
}
-func TestBuildJSONAddMultipleFilesToFile(t *testing.T) {
+func (s *DockerSuite) TestBuildJSONAddMultipleFilesToFile(c *check.C) {
name := "testjsonaddmultiplefilestofile"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM scratch
ADD ["file1.txt", "file2.txt", "test"]
`,
@@ -949,20 +878,18 @@ func TestBuildJSONAddMultipleFilesToFile(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
expected := "When using ADD with more than one source file, the destination must be a directory and end with a /"
if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) {
- t.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err)
+ c.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err)
}
- logDone("build - multiple add files to file json syntax")
}
-func TestBuildAddMultipleFilesToFileWild(t *testing.T) {
+func (s *DockerSuite) TestBuildAddMultipleFilesToFileWild(c *check.C) {
name := "testaddmultiplefilestofilewild"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM scratch
ADD file*.txt test
`,
@@ -972,20 +899,18 @@ func TestBuildAddMultipleFilesToFileWild(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
expected := "When using ADD with more than one source file, the destination must be a directory and end with a /"
if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) {
- t.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err)
+ c.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err)
}
- logDone("build - multiple add files to file wild")
}
-func TestBuildJSONAddMultipleFilesToFileWild(t *testing.T) {
+func (s *DockerSuite) TestBuildJSONAddMultipleFilesToFileWild(c *check.C) {
name := "testjsonaddmultiplefilestofilewild"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM scratch
ADD ["file*.txt", "test"]
`,
@@ -995,20 +920,18 @@ func TestBuildJSONAddMultipleFilesToFileWild(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
expected := "When using ADD with more than one source file, the destination must be a directory and end with a /"
if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) {
- t.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err)
+ c.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err)
}
- logDone("build - multiple add files to file wild json syntax")
}
-func TestBuildCopyMultipleFilesToFile(t *testing.T) {
+func (s *DockerSuite) TestBuildCopyMultipleFilesToFile(c *check.C) {
name := "testcopymultiplefilestofile"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM scratch
COPY file1.txt file2.txt test
`,
@@ -1018,20 +941,18 @@ func TestBuildCopyMultipleFilesToFile(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
expected := "When using COPY with more than one source file, the destination must be a directory and end with a /"
if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) {
- t.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err)
+ c.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err)
}
- logDone("build - multiple copy files to file")
}
-func TestBuildJSONCopyMultipleFilesToFile(t *testing.T) {
+func (s *DockerSuite) TestBuildJSONCopyMultipleFilesToFile(c *check.C) {
name := "testjsoncopymultiplefilestofile"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM scratch
COPY ["file1.txt", "file2.txt", "test"]
`,
@@ -1041,20 +962,18 @@ func TestBuildJSONCopyMultipleFilesToFile(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
expected := "When using COPY with more than one source file, the destination must be a directory and end with a /"
if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) {
- t.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err)
+ c.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err)
}
- logDone("build - multiple copy files to file json syntax")
}
-func TestBuildAddFileWithWhitespace(t *testing.T) {
+func (s *DockerSuite) TestBuildAddFileWithWhitespace(c *check.C) {
name := "testaddfilewithwhitespace"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
RUN mkdir "/test dir"
RUN mkdir "/test_dir"
@@ -1080,18 +999,16 @@ RUN [ $(cat "/test dir/test_file6") = 'test6' ]`,
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - add file with whitespace")
}
-func TestBuildCopyFileWithWhitespace(t *testing.T) {
+func (s *DockerSuite) TestBuildCopyFileWithWhitespace(c *check.C) {
name := "testcopyfilewithwhitespace"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
RUN mkdir "/test dir"
RUN mkdir "/test_dir"
@@ -1117,18 +1034,16 @@ RUN [ $(cat "/test dir/test_file6") = 'test6' ]`,
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - copy file with whitespace")
}
-func TestBuildAddMultipleFilesToFileWithWhitespace(t *testing.T) {
+func (s *DockerSuite) TestBuildAddMultipleFilesToFileWithWhitespace(c *check.C) {
name := "testaddmultiplefilestofilewithwhitespace"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
ADD [ "test file1", "test file2", "test" ]
`,
@@ -1138,20 +1053,18 @@ func TestBuildAddMultipleFilesToFileWithWhitespace(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
expected := "When using ADD with more than one source file, the destination must be a directory and end with a /"
if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) {
- t.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err)
+ c.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err)
}
- logDone("build - multiple add files to file with whitespace")
}
-func TestBuildCopyMultipleFilesToFileWithWhitespace(t *testing.T) {
+func (s *DockerSuite) TestBuildCopyMultipleFilesToFileWithWhitespace(c *check.C) {
name := "testcopymultiplefilestofilewithwhitespace"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
COPY [ "test file1", "test file2", "test" ]
`,
@@ -1161,26 +1074,24 @@ func TestBuildCopyMultipleFilesToFileWithWhitespace(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
expected := "When using COPY with more than one source file, the destination must be a directory and end with a /"
if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) {
- t.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err)
+ c.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err)
}
- logDone("build - multiple copy files to file with whitespace")
}
-func TestBuildCopyWildcard(t *testing.T) {
+func (s *DockerSuite) TestBuildCopyWildcard(c *check.C) {
name := "testcopywildcard"
- defer deleteImages(name)
server, err := fakeStorage(map[string]string{
"robots.txt": "hello",
"index.html": "world",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer server.Close()
@@ -1203,52 +1114,48 @@ func TestBuildCopyWildcard(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id1, err := buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// Now make sure we use a cache the 2nd time
id2, err := buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 != id2 {
- t.Fatal("didn't use the cache")
+ c.Fatal("didn't use the cache")
}
- logDone("build - copy wild card")
}
-func TestBuildCopyWildcardNoFind(t *testing.T) {
+func (s *DockerSuite) TestBuildCopyWildcardNoFind(c *check.C) {
name := "testcopywildcardnofind"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
COPY file*.txt /tmp/
`, nil)
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
_, err = buildImageFromContext(name, ctx, true)
if err == nil {
- t.Fatal("should have failed to find a file")
+ c.Fatal("should have failed to find a file")
}
if !strings.Contains(err.Error(), "No source files were specified") {
- t.Fatalf("Wrong error %v, must be about no source files", err)
+ c.Fatalf("Wrong error %v, must be about no source files", err)
}
- logDone("build - copy wild card no find")
}
-func TestBuildCopyWildcardCache(t *testing.T) {
+func (s *DockerSuite) TestBuildCopyWildcardCache(c *check.C) {
name := "testcopywildcardcache"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
COPY file1.txt /tmp/`,
map[string]string{
@@ -1256,12 +1163,12 @@ func TestBuildCopyWildcardCache(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id1, err := buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// Now make sure we use a cache the 2nd time even with wild cards.
@@ -1271,19 +1178,17 @@ func TestBuildCopyWildcardCache(t *testing.T) {
id2, err := buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 != id2 {
- t.Fatal("didn't use the cache")
+ c.Fatal("didn't use the cache")
}
- logDone("build - copy wild card cache")
}
-func TestBuildAddSingleFileToNonExistingDir(t *testing.T) {
+func (s *DockerSuite) TestBuildAddSingleFileToNonExistingDir(c *check.C) {
name := "testaddsinglefiletononexistingdir"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
RUN echo 'dockerio:x:1001:' >> /etc/group
@@ -1297,20 +1202,18 @@ RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`,
"test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - add single file to non-existing dir")
}
-func TestBuildAddDirContentToRoot(t *testing.T) {
+func (s *DockerSuite) TestBuildAddDirContentToRoot(c *check.C) {
name := "testadddircontenttoroot"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
RUN echo 'dockerio:x:1001:' >> /etc/group
@@ -1323,19 +1226,17 @@ RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`,
"test_dir/test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - add directory contents to root")
}
-func TestBuildAddDirContentToExistingDir(t *testing.T) {
+func (s *DockerSuite) TestBuildAddDirContentToExistingDir(c *check.C) {
name := "testadddircontenttoexistingdir"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
RUN echo 'dockerio:x:1001:' >> /etc/group
@@ -1350,19 +1251,17 @@ RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]`,
"test_dir/test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - add directory contents to existing dir")
}
-func TestBuildAddWholeDirToRoot(t *testing.T) {
+func (s *DockerSuite) TestBuildAddWholeDirToRoot(c *check.C) {
name := "testaddwholedirtoroot"
- defer deleteImages(name)
ctx, err := fakeContext(fmt.Sprintf(`FROM busybox
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
RUN echo 'dockerio:x:1001:' >> /etc/group
@@ -1378,40 +1277,36 @@ RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expecte
"test_dir/test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - add whole directory to root")
}
// Testing #5941
-func TestBuildAddEtcToRoot(t *testing.T) {
+func (s *DockerSuite) TestBuildAddEtcToRoot(c *check.C) {
name := "testaddetctoroot"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM scratch
ADD . /`,
map[string]string{
"etc/test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - add etc directory to root")
}
// Testing #9401
-func TestBuildAddPreservesFilesSpecialBits(t *testing.T) {
+func (s *DockerSuite) TestBuildAddPreservesFilesSpecialBits(c *check.C) {
name := "testaddpreservesfilesspecialbits"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
ADD suidbin /usr/bin/suidbin
RUN chmod 4755 /usr/bin/suidbin
@@ -1423,19 +1318,17 @@ RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ]`,
"/data/usr/test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - add preserves files special bits")
}
-func TestBuildCopySingleFileToRoot(t *testing.T) {
+func (s *DockerSuite) TestBuildCopySingleFileToRoot(c *check.C) {
name := "testcopysinglefiletoroot"
- defer deleteImages(name)
ctx, err := fakeContext(fmt.Sprintf(`FROM busybox
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
RUN echo 'dockerio:x:1001:' >> /etc/group
@@ -1449,48 +1342,44 @@ RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expecte
"test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - copy single file to root")
}
// Issue #3960: "ADD src ." hangs - adapted for COPY
-func TestBuildCopySingleFileToWorkdir(t *testing.T) {
+func (s *DockerSuite) TestBuildCopySingleFileToWorkdir(c *check.C) {
name := "testcopysinglefiletoworkdir"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
COPY test_file .`,
map[string]string{
"test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
- done := make(chan struct{})
+ errChan := make(chan error)
go func() {
- if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
- }
- close(done)
+ _, err := buildImageFromContext(name, ctx, true)
+ errChan <- err
+ close(errChan)
}()
select {
case <-time.After(5 * time.Second):
- t.Fatal("Build with adding to workdir timed out")
- case <-done:
+ c.Fatal("Build with adding to workdir timed out")
+ case err := <-errChan:
+ c.Assert(err, check.IsNil)
}
- logDone("build - copy single file to workdir")
}
-func TestBuildCopySingleFileToExistDir(t *testing.T) {
+func (s *DockerSuite) TestBuildCopySingleFileToExistDir(c *check.C) {
name := "testcopysinglefiletoexistdir"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
RUN echo 'dockerio:x:1001:' >> /etc/group
@@ -1505,19 +1394,17 @@ RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio'
"test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - copy single file to existing dir")
}
-func TestBuildCopySingleFileToNonExistDir(t *testing.T) {
+func (s *DockerSuite) TestBuildCopySingleFileToNonExistDir(c *check.C) {
name := "testcopysinglefiletononexistdir"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
RUN echo 'dockerio:x:1001:' >> /etc/group
@@ -1531,19 +1418,17 @@ RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`,
"test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - copy single file to non-existing dir")
}
-func TestBuildCopyDirContentToRoot(t *testing.T) {
+func (s *DockerSuite) TestBuildCopyDirContentToRoot(c *check.C) {
name := "testcopydircontenttoroot"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
RUN echo 'dockerio:x:1001:' >> /etc/group
@@ -1556,19 +1441,17 @@ RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`,
"test_dir/test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - copy directory contents to root")
}
-func TestBuildCopyDirContentToExistDir(t *testing.T) {
+func (s *DockerSuite) TestBuildCopyDirContentToExistDir(c *check.C) {
name := "testcopydircontenttoexistdir"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
RUN echo 'dockerio:x:1001:' >> /etc/group
@@ -1583,19 +1466,17 @@ RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]`,
"test_dir/test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - copy directory contents to existing dir")
}
-func TestBuildCopyWholeDirToRoot(t *testing.T) {
+func (s *DockerSuite) TestBuildCopyWholeDirToRoot(c *check.C) {
name := "testcopywholedirtoroot"
- defer deleteImages(name)
ctx, err := fakeContext(fmt.Sprintf(`FROM busybox
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
RUN echo 'dockerio:x:1001:' >> /etc/group
@@ -1611,48 +1492,43 @@ RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expecte
"test_dir/test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - copy whole directory to root")
}
-func TestBuildCopyEtcToRoot(t *testing.T) {
+func (s *DockerSuite) TestBuildCopyEtcToRoot(c *check.C) {
name := "testcopyetctoroot"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM scratch
COPY . /`,
map[string]string{
"etc/test_file": "test1",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - copy etc directory to root")
}
-func TestBuildCopyDisallowRemote(t *testing.T) {
+func (s *DockerSuite) TestBuildCopyDisallowRemote(c *check.C) {
name := "testcopydisallowremote"
- defer deleteImages(name)
_, out, err := buildImageWithOut(name, `FROM scratch
COPY https://index.docker.io/robots.txt /`,
true)
if err == nil || !strings.Contains(out, "Source can't be a URL for COPY") {
- t.Fatalf("Error should be about disallowed remote source, got err: %s, out: %q", err, out)
+ c.Fatalf("Error should be about disallowed remote source, got err: %s, out: %q", err, out)
}
- logDone("build - copy - disallow copy from remote")
}
-func TestBuildAddBadLinks(t *testing.T) {
+func (s *DockerSuite) TestBuildAddBadLinks(c *check.C) {
const (
dockerfile = `
FROM scratch
@@ -1664,16 +1540,15 @@ func TestBuildAddBadLinks(t *testing.T) {
var (
name = "test-link-absolute"
)
- defer deleteImages(name)
ctx, err := fakeContext(dockerfile, nil)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
tempDir, err := ioutil.TempDir("", "test-link-absolute-temp-")
if err != nil {
- t.Fatalf("failed to create temporary directory: %s", tempDir)
+ c.Fatalf("failed to create temporary directory: %s", tempDir)
}
defer os.RemoveAll(tempDir)
@@ -1681,7 +1556,7 @@ func TestBuildAddBadLinks(t *testing.T) {
if runtime.GOOS == "windows" {
var driveLetter string
if abs, err := filepath.Abs(tempDir); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
} else {
driveLetter = abs[:1]
}
@@ -1697,7 +1572,7 @@ func TestBuildAddBadLinks(t *testing.T) {
tarOut, err := os.Create(tarPath)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
tarWriter := tar.NewWriter(tarOut)
@@ -1713,7 +1588,7 @@ func TestBuildAddBadLinks(t *testing.T) {
err = tarWriter.WriteHeader(header)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
tarWriter.Close()
@@ -1721,26 +1596,25 @@ func TestBuildAddBadLinks(t *testing.T) {
foo, err := os.Create(fooPath)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer foo.Close()
if _, err := foo.WriteString("test"); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := os.Stat(nonExistingFile); err == nil || err != nil && !os.IsNotExist(err) {
- t.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile)
+ c.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile)
}
- logDone("build - ADD must add files in container")
}
-func TestBuildAddBadLinksVolume(t *testing.T) {
+func (s *DockerSuite) TestBuildAddBadLinksVolume(c *check.C) {
const (
dockerfileTemplate = `
FROM busybox
@@ -1753,11 +1627,10 @@ func TestBuildAddBadLinksVolume(t *testing.T) {
name = "test-link-absolute-volume"
dockerfile = ""
)
- defer deleteImages(name)
tempDir, err := ioutil.TempDir("", "test-link-absolute-volume-temp-")
if err != nil {
- t.Fatalf("failed to create temporary directory: %s", tempDir)
+ c.Fatalf("failed to create temporary directory: %s", tempDir)
}
defer os.RemoveAll(tempDir)
@@ -1766,76 +1639,73 @@ func TestBuildAddBadLinksVolume(t *testing.T) {
ctx, err := fakeContext(dockerfile, nil)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
fooPath := filepath.Join(ctx.Dir, targetFile)
foo, err := os.Create(fooPath)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer foo.Close()
if _, err := foo.WriteString("test"); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := os.Stat(nonExistingFile); err == nil || err != nil && !os.IsNotExist(err) {
- t.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile)
+ c.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile)
}
- logDone("build - ADD should add files in volume")
}
// Issue #5270 - ensure we throw a better error than "unexpected EOF"
// when we can't access files in the context.
-func TestBuildWithInaccessibleFilesInContext(t *testing.T) {
- testRequires(t, UnixCli) // test uses chown/chmod: not available on windows
+func (s *DockerSuite) TestBuildWithInaccessibleFilesInContext(c *check.C) {
+ testRequires(c, UnixCli) // test uses chown/chmod: not available on windows
{
name := "testbuildinaccessiblefiles"
- defer deleteImages(name)
ctx, err := fakeContext("FROM scratch\nADD . /foo/", map[string]string{"fileWithoutReadAccess": "foo"})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
// This is used to ensure we detect inaccessible files early during build in the cli client
pathToFileWithoutReadAccess := filepath.Join(ctx.Dir, "fileWithoutReadAccess")
if err = os.Chown(pathToFileWithoutReadAccess, 0, 0); err != nil {
- t.Fatalf("failed to chown file to root: %s", err)
+ c.Fatalf("failed to chown file to root: %s", err)
}
if err = os.Chmod(pathToFileWithoutReadAccess, 0700); err != nil {
- t.Fatalf("failed to chmod file to 700: %s", err)
+ c.Fatalf("failed to chmod file to 700: %s", err)
}
buildCmd := exec.Command("su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name))
buildCmd.Dir = ctx.Dir
out, _, err := runCommandWithOutput(buildCmd)
if err == nil {
- t.Fatalf("build should have failed: %s %s", err, out)
+ c.Fatalf("build should have failed: %s %s", err, out)
}
// check if we've detected the failure before we started building
if !strings.Contains(out, "no permission to read from ") {
- t.Fatalf("output should've contained the string: no permission to read from but contained: %s", out)
+ c.Fatalf("output should've contained the string: no permission to read from but contained: %s", out)
}
if !strings.Contains(out, "Error checking context is accessible") {
- t.Fatalf("output should've contained the string: Error checking context is accessible")
+ c.Fatalf("output should've contained the string: Error checking context is accessible")
}
}
{
name := "testbuildinaccessibledirectory"
- defer deleteImages(name)
ctx, err := fakeContext("FROM scratch\nADD . /foo/", map[string]string{"directoryWeCantStat/bar": "foo"})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
// This is used to ensure we detect inaccessible directories early during build in the cli client
@@ -1843,116 +1713,111 @@ func TestBuildWithInaccessibleFilesInContext(t *testing.T) {
pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar")
if err = os.Chown(pathToDirectoryWithoutReadAccess, 0, 0); err != nil {
- t.Fatalf("failed to chown directory to root: %s", err)
+ c.Fatalf("failed to chown directory to root: %s", err)
}
if err = os.Chmod(pathToDirectoryWithoutReadAccess, 0444); err != nil {
- t.Fatalf("failed to chmod directory to 444: %s", err)
+ c.Fatalf("failed to chmod directory to 444: %s", err)
}
if err = os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700); err != nil {
- t.Fatalf("failed to chmod file to 700: %s", err)
+ c.Fatalf("failed to chmod file to 700: %s", err)
}
buildCmd := exec.Command("su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name))
buildCmd.Dir = ctx.Dir
out, _, err := runCommandWithOutput(buildCmd)
if err == nil {
- t.Fatalf("build should have failed: %s %s", err, out)
+ c.Fatalf("build should have failed: %s %s", err, out)
}
// check if we've detected the failure before we started building
if !strings.Contains(out, "can't stat") {
- t.Fatalf("output should've contained the string: can't access %s", out)
+ c.Fatalf("output should've contained the string: can't access %s", out)
}
if !strings.Contains(out, "Error checking context is accessible") {
- t.Fatalf("output should've contained the string: Error checking context is accessible")
+ c.Fatalf("output should've contained the string: Error checking context is accessible")
}
}
{
name := "testlinksok"
- defer deleteImages(name)
ctx, err := fakeContext("FROM scratch\nADD . /foo/", nil)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
target := "../../../../../../../../../../../../../../../../../../../azA"
if err := os.Symlink(filepath.Join(ctx.Dir, "g"), target); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.Remove(target)
// This is used to ensure we don't follow links when checking if everything in the context is accessible
// This test doesn't require that we run commands as an unprivileged user
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
}
{
name := "testbuildignoredinaccessible"
- defer deleteImages(name)
ctx, err := fakeContext("FROM scratch\nADD . /foo/",
map[string]string{
"directoryWeCantStat/bar": "foo",
".dockerignore": "directoryWeCantStat",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
// This is used to ensure we don't try to add inaccessible files when they are ignored by a .dockerignore pattern
pathToDirectoryWithoutReadAccess := filepath.Join(ctx.Dir, "directoryWeCantStat")
pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar")
if err = os.Chown(pathToDirectoryWithoutReadAccess, 0, 0); err != nil {
- t.Fatalf("failed to chown directory to root: %s", err)
+ c.Fatalf("failed to chown directory to root: %s", err)
}
if err = os.Chmod(pathToDirectoryWithoutReadAccess, 0444); err != nil {
- t.Fatalf("failed to chmod directory to 755: %s", err)
+ c.Fatalf("failed to chmod directory to 755: %s", err)
}
if err = os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700); err != nil {
- t.Fatalf("failed to chmod file to 444: %s", err)
+ c.Fatalf("failed to chmod file to 444: %s", err)
}
buildCmd := exec.Command("su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name))
buildCmd.Dir = ctx.Dir
if out, _, err := runCommandWithOutput(buildCmd); err != nil {
- t.Fatalf("build should have worked: %s %s", err, out)
+ c.Fatalf("build should have worked: %s %s", err, out)
}
}
- logDone("build - ADD from context with inaccessible files must not pass")
}
-func TestBuildForceRm(t *testing.T) {
+func (s *DockerSuite) TestBuildForceRm(c *check.C) {
containerCountBefore, err := getContainerCount()
if err != nil {
- t.Fatalf("failed to get the container count: %s", err)
+ c.Fatalf("failed to get the container count: %s", err)
}
name := "testbuildforcerm"
- defer deleteImages(name)
ctx, err := fakeContext("FROM scratch\nRUN true\nRUN thiswillfail", nil)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
buildCmd := exec.Command(dockerBinary, "build", "-t", name, "--force-rm", ".")
buildCmd.Dir = ctx.Dir
if out, _, err := runCommandWithOutput(buildCmd); err == nil {
- t.Fatalf("failed to build the image: %s, %v", out, err)
+ c.Fatalf("failed to build the image: %s, %v", out, err)
}
containerCountAfter, err := getContainerCount()
if err != nil {
- t.Fatalf("failed to get the container count: %s", err)
+ c.Fatalf("failed to get the container count: %s", err)
}
if containerCountBefore != containerCountAfter {
- t.Fatalf("--force-rm shouldn't have left containers behind")
+ c.Fatalf("--force-rm shouldn't have left containers behind")
}
- logDone("build - ensure --force-rm doesn't leave containers behind")
}
// Test that an infinite sleep during a build is killed if the client disconnects.
@@ -1962,18 +1827,13 @@ func TestBuildForceRm(t *testing.T) {
// * Run a 1-year-long sleep from a docker build.
// * When docker events sees container start, close the "docker build" command
// * Wait for docker events to emit a dying event.
-func TestBuildCancelationKillsSleep(t *testing.T) {
- var wg sync.WaitGroup
- defer wg.Wait()
-
+func (s *DockerSuite) TestBuildCancelationKillsSleep(c *check.C) {
name := "testbuildcancelation"
- defer deleteImages(name)
- defer deleteAllContainers()
// (Note: one year, will never finish)
ctx, err := fakeContext("FROM busybox\nRUN sleep 31536000", nil)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
@@ -1984,27 +1844,22 @@ func TestBuildCancelationKillsSleep(t *testing.T) {
eventDie := make(chan struct{})
containerID := make(chan string)
- startEpoch := daemonTime(t).Unix()
+ startEpoch := daemonTime(c).Unix()
+ // Watch for events since epoch.
+ eventsCmd := exec.Command(
+ dockerBinary, "events",
+ "--since", strconv.FormatInt(startEpoch, 10))
+ stdout, err := eventsCmd.StdoutPipe()
+ if err != nil {
+ c.Fatal(err)
+ }
+ if err := eventsCmd.Start(); err != nil {
+ c.Fatal(err)
+ }
+ defer eventsCmd.Process.Kill()
- wg.Add(1)
// Goroutine responsible for watching start/die events from `docker events`
go func() {
- defer wg.Done()
- // Watch for events since epoch.
- eventsCmd := exec.Command(
- dockerBinary, "events",
- "--since", strconv.FormatInt(startEpoch, 10))
- stdout, err := eventsCmd.StdoutPipe()
- err = eventsCmd.Start()
- if err != nil {
- t.Fatalf("failed to start 'docker events': %s", err)
- }
-
- go func() {
- <-finish
- eventsCmd.Process.Kill()
- }()
-
cid := <-containerID
matchStart := regexp.MustCompile(cid + `(.*) start$`)
@@ -2022,20 +1877,14 @@ func TestBuildCancelationKillsSleep(t *testing.T) {
close(eventDie)
}
}
-
- err = eventsCmd.Wait()
- if err != nil && !IsKilled(err) {
- t.Fatalf("docker events had bad exit status: %s", err)
- }
}()
buildCmd := exec.Command(dockerBinary, "build", "-t", name, ".")
buildCmd.Dir = ctx.Dir
stdoutBuild, err := buildCmd.StdoutPipe()
- err = buildCmd.Start()
- if err != nil {
- t.Fatalf("failed to run build: %s", err)
+ if err := buildCmd.Start(); err != nil {
+ c.Fatalf("failed to run build: %s", err)
}
matchCID := regexp.MustCompile("Running in ")
@@ -2050,7 +1899,7 @@ func TestBuildCancelationKillsSleep(t *testing.T) {
select {
case <-time.After(5 * time.Second):
- t.Fatal("failed to observe build container start in timely fashion")
+ c.Fatal("failed to observe build container start in timely fashion")
case <-eventStart:
// Proceeds from here when we see the container fly past in the
// output of "docker events".
@@ -2059,56 +1908,52 @@ func TestBuildCancelationKillsSleep(t *testing.T) {
// Send a kill to the `docker build` command.
// Causes the underlying build to be cancelled due to socket close.
- err = buildCmd.Process.Kill()
- if err != nil {
- t.Fatalf("error killing build command: %s", err)
+ if err := buildCmd.Process.Kill(); err != nil {
+ c.Fatalf("error killing build command: %s", err)
}
// Get the exit status of `docker build`, check it exited because killed.
- err = buildCmd.Wait()
- if err != nil && !IsKilled(err) {
- t.Fatalf("wait failed during build run: %T %s", err, err)
+ if err := buildCmd.Wait(); err != nil && !IsKilled(err) {
+ c.Fatalf("wait failed during build run: %T %s", err, err)
}
select {
case <-time.After(5 * time.Second):
// If we don't get here in a timely fashion, it wasn't killed.
- t.Fatal("container cancel did not succeed")
+ c.Fatal("container cancel did not succeed")
case <-eventDie:
// We saw the container shut down in the `docker events` stream,
// as expected.
}
- logDone("build - ensure canceled job finishes immediately")
}
-func TestBuildRm(t *testing.T) {
+func (s *DockerSuite) TestBuildRm(c *check.C) {
name := "testbuildrm"
- defer deleteImages(name)
ctx, err := fakeContext("FROM scratch\nADD foo /\nADD foo /", map[string]string{"foo": "bar"})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
{
containerCountBefore, err := getContainerCount()
if err != nil {
- t.Fatalf("failed to get the container count: %s", err)
+ c.Fatalf("failed to get the container count: %s", err)
}
- out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "--rm", "-t", name, ".")
+ out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "--rm", "-t", name, ".")
if err != nil {
- t.Fatal("failed to build the image", out)
+ c.Fatal("failed to build the image", out)
}
containerCountAfter, err := getContainerCount()
if err != nil {
- t.Fatalf("failed to get the container count: %s", err)
+ c.Fatalf("failed to get the container count: %s", err)
}
if containerCountBefore != containerCountAfter {
- t.Fatalf("-rm shouldn't have left containers behind")
+ c.Fatalf("-rm shouldn't have left containers behind")
}
deleteImages(name)
}
@@ -2116,22 +1961,22 @@ func TestBuildRm(t *testing.T) {
{
containerCountBefore, err := getContainerCount()
if err != nil {
- t.Fatalf("failed to get the container count: %s", err)
+ c.Fatalf("failed to get the container count: %s", err)
}
- out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-t", name, ".")
+ out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", name, ".")
if err != nil {
- t.Fatal("failed to build the image", out)
+ c.Fatal("failed to build the image", out)
}
containerCountAfter, err := getContainerCount()
if err != nil {
- t.Fatalf("failed to get the container count: %s", err)
+ c.Fatalf("failed to get the container count: %s", err)
}
if containerCountBefore != containerCountAfter {
- t.Fatalf("--rm shouldn't have left containers behind")
+ c.Fatalf("--rm shouldn't have left containers behind")
}
deleteImages(name)
}
@@ -2139,32 +1984,30 @@ func TestBuildRm(t *testing.T) {
{
containerCountBefore, err := getContainerCount()
if err != nil {
- t.Fatalf("failed to get the container count: %s", err)
+ c.Fatalf("failed to get the container count: %s", err)
}
- out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "--rm=false", "-t", name, ".")
+ out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "--rm=false", "-t", name, ".")
if err != nil {
- t.Fatal("failed to build the image", out)
+ c.Fatal("failed to build the image", out)
}
containerCountAfter, err := getContainerCount()
if err != nil {
- t.Fatalf("failed to get the container count: %s", err)
+ c.Fatalf("failed to get the container count: %s", err)
}
if containerCountBefore == containerCountAfter {
- t.Fatalf("--rm=false should have left containers behind")
+ c.Fatalf("--rm=false should have left containers behind")
}
- deleteAllContainers()
deleteImages(name)
}
- logDone("build - ensure --rm doesn't leave containers behind and that --rm=true is the default")
}
-func TestBuildWithVolumes(t *testing.T) {
+func (s *DockerSuite) TestBuildWithVolumes(c *check.C) {
var (
result map[string]map[string]struct{}
name = "testbuildvolumes"
@@ -2180,7 +2023,6 @@ func TestBuildWithVolumes(t *testing.T) {
"/test8]": emptyMap,
}
)
- defer deleteImages(name)
_, err := buildImage(name,
`FROM scratch
VOLUME /test1
@@ -2191,52 +2033,48 @@ func TestBuildWithVolumes(t *testing.T) {
`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectFieldJSON(name, "Config.Volumes")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
err = unmarshalJSON([]byte(res), &result)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
equal := reflect.DeepEqual(&result, &expected)
if !equal {
- t.Fatalf("Volumes %s, expected %s", result, expected)
+ c.Fatalf("Volumes %s, expected %s", result, expected)
}
- logDone("build - with volumes")
}
-func TestBuildMaintainer(t *testing.T) {
+func (s *DockerSuite) TestBuildMaintainer(c *check.C) {
name := "testbuildmaintainer"
expected := "dockerio"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM scratch
MAINTAINER dockerio`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectField(name, "Author")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != expected {
- t.Fatalf("Maintainer %s, expected %s", res, expected)
+ c.Fatalf("Maintainer %s, expected %s", res, expected)
}
- logDone("build - maintainer")
}
-func TestBuildUser(t *testing.T) {
+func (s *DockerSuite) TestBuildUser(c *check.C) {
name := "testbuilduser"
expected := "dockerio"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM busybox
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
@@ -2244,22 +2082,20 @@ func TestBuildUser(t *testing.T) {
RUN [ $(whoami) = 'dockerio' ]`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectField(name, "Config.User")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != expected {
- t.Fatalf("User %s, expected %s", res, expected)
+ c.Fatalf("User %s, expected %s", res, expected)
}
- logDone("build - user")
}
-func TestBuildRelativeWorkdir(t *testing.T) {
+func (s *DockerSuite) TestBuildRelativeWorkdir(c *check.C) {
name := "testbuildrelativeworkdir"
expected := "/test2/test3"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM busybox
RUN [ "$PWD" = '/' ]
@@ -2271,22 +2107,20 @@ func TestBuildRelativeWorkdir(t *testing.T) {
RUN [ "$PWD" = '/test2/test3' ]`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectField(name, "Config.WorkingDir")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != expected {
- t.Fatalf("Workdir %s, expected %s", res, expected)
+ c.Fatalf("Workdir %s, expected %s", res, expected)
}
- logDone("build - relative workdir")
}
-func TestBuildWorkdirWithEnvVariables(t *testing.T) {
+func (s *DockerSuite) TestBuildWorkdirWithEnvVariables(c *check.C) {
name := "testbuildworkdirwithenvvariables"
expected := "/test1/test2"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM busybox
ENV DIRPATH /test1
@@ -2295,21 +2129,19 @@ func TestBuildWorkdirWithEnvVariables(t *testing.T) {
WORKDIR $SUBDIRNAME/$MISSING_VAR`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectField(name, "Config.WorkingDir")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != expected {
- t.Fatalf("Workdir %s, expected %s", res, expected)
+ c.Fatalf("Workdir %s, expected %s", res, expected)
}
- logDone("build - workdir with env variables")
}
-func TestBuildRelativeCopy(t *testing.T) {
+func (s *DockerSuite) TestBuildRelativeCopy(c *check.C) {
name := "testbuildrelativecopy"
- defer deleteImages(name)
dockerfile := `
FROM busybox
WORKDIR /test1
@@ -2338,19 +2170,17 @@ func TestBuildRelativeCopy(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
_, err = buildImageFromContext(name, ctx, false)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - relative copy/add")
}
-func TestBuildEnv(t *testing.T) {
+func (s *DockerSuite) TestBuildEnv(c *check.C) {
name := "testbuildenv"
expected := "[PATH=/test:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PORT=2375]"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM busybox
ENV PATH /test:$PATH
@@ -2358,116 +2188,106 @@ func TestBuildEnv(t *testing.T) {
RUN [ $(env | grep PORT) = 'PORT=2375' ]`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectField(name, "Config.Env")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != expected {
- t.Fatalf("Env %s, expected %s", res, expected)
+ c.Fatalf("Env %s, expected %s", res, expected)
}
- logDone("build - env")
}
-func TestBuildContextCleanup(t *testing.T) {
- testRequires(t, SameHostDaemon)
+func (s *DockerSuite) TestBuildContextCleanup(c *check.C) {
+ testRequires(c, SameHostDaemon)
name := "testbuildcontextcleanup"
- defer deleteImages(name)
entries, err := ioutil.ReadDir("/var/lib/docker/tmp")
if err != nil {
- t.Fatalf("failed to list contents of tmp dir: %s", err)
+ c.Fatalf("failed to list contents of tmp dir: %s", err)
}
_, err = buildImage(name,
`FROM scratch
ENTRYPOINT ["/bin/echo"]`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
entriesFinal, err := ioutil.ReadDir("/var/lib/docker/tmp")
if err != nil {
- t.Fatalf("failed to list contents of tmp dir: %s", err)
+ c.Fatalf("failed to list contents of tmp dir: %s", err)
}
if err = compareDirectoryEntries(entries, entriesFinal); err != nil {
- t.Fatalf("context should have been deleted, but wasn't")
+ c.Fatalf("context should have been deleted, but wasn't")
}
- logDone("build - verify context cleanup works properly")
}
-func TestBuildContextCleanupFailedBuild(t *testing.T) {
- testRequires(t, SameHostDaemon)
+func (s *DockerSuite) TestBuildContextCleanupFailedBuild(c *check.C) {
+ testRequires(c, SameHostDaemon)
name := "testbuildcontextcleanup"
- defer deleteImages(name)
- defer deleteAllContainers()
entries, err := ioutil.ReadDir("/var/lib/docker/tmp")
if err != nil {
- t.Fatalf("failed to list contents of tmp dir: %s", err)
+ c.Fatalf("failed to list contents of tmp dir: %s", err)
}
_, err = buildImage(name,
`FROM scratch
RUN /non/existing/command`,
true)
if err == nil {
- t.Fatalf("expected build to fail, but it didn't")
+ c.Fatalf("expected build to fail, but it didn't")
}
entriesFinal, err := ioutil.ReadDir("/var/lib/docker/tmp")
if err != nil {
- t.Fatalf("failed to list contents of tmp dir: %s", err)
+ c.Fatalf("failed to list contents of tmp dir: %s", err)
}
if err = compareDirectoryEntries(entries, entriesFinal); err != nil {
- t.Fatalf("context should have been deleted, but wasn't")
+ c.Fatalf("context should have been deleted, but wasn't")
}
- logDone("build - verify context cleanup works properly after an unsuccessful build")
}
-func TestBuildCmd(t *testing.T) {
+func (s *DockerSuite) TestBuildCmd(c *check.C) {
name := "testbuildcmd"
- expected := "[/bin/echo Hello World]"
- defer deleteImages(name)
+ expected := "{[/bin/echo Hello World]}"
_, err := buildImage(name,
`FROM scratch
CMD ["/bin/echo", "Hello World"]`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectField(name, "Config.Cmd")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != expected {
- t.Fatalf("Cmd %s, expected %s", res, expected)
+ c.Fatalf("Cmd %s, expected %s", res, expected)
}
- logDone("build - cmd")
}
-func TestBuildExpose(t *testing.T) {
+func (s *DockerSuite) TestBuildExpose(c *check.C) {
name := "testbuildexpose"
- expected := "map[2375/tcp:map[]]"
- defer deleteImages(name)
+ expected := "map[2375/tcp:{}]"
_, err := buildImage(name,
`FROM scratch
EXPOSE 2375`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectField(name, "Config.ExposedPorts")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != expected {
- t.Fatalf("Exposed ports %s, expected %s", res, expected)
+ c.Fatalf("Exposed ports %s, expected %s", res, expected)
}
- logDone("build - expose")
}
-func TestBuildExposeMorePorts(t *testing.T) {
+func (s *DockerSuite) TestBuildExposeMorePorts(c *check.C) {
// start building docker file with a large number of ports
portList := make([]string, 50)
line := make([]string, 100)
@@ -2493,127 +2313,118 @@ func TestBuildExposeMorePorts(t *testing.T) {
tmpl.Execute(buf, portList)
name := "testbuildexpose"
- defer deleteImages(name)
_, err := buildImage(name, buf.String(), true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// check if all the ports are saved inside Config.ExposedPorts
res, err := inspectFieldJSON(name, "Config.ExposedPorts")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
var exposedPorts map[string]interface{}
if err := json.Unmarshal([]byte(res), &exposedPorts); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
for _, p := range expectedPorts {
ep := fmt.Sprintf("%d/tcp", p)
if _, ok := exposedPorts[ep]; !ok {
- t.Errorf("Port(%s) is not exposed", ep)
+ c.Errorf("Port(%s) is not exposed", ep)
} else {
delete(exposedPorts, ep)
}
}
if len(exposedPorts) != 0 {
- t.Errorf("Unexpected extra exposed ports %v", exposedPorts)
+ c.Errorf("Unexpected extra exposed ports %v", exposedPorts)
}
- logDone("build - expose large number of ports")
}
-func TestBuildExposeOrder(t *testing.T) {
+func (s *DockerSuite) TestBuildExposeOrder(c *check.C) {
buildID := func(name, exposed string) string {
_, err := buildImage(name, fmt.Sprintf(`FROM scratch
EXPOSE %s`, exposed), true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id, err := inspectField(name, "Id")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
return id
}
id1 := buildID("testbuildexpose1", "80 2375")
id2 := buildID("testbuildexpose2", "2375 80")
- defer deleteImages("testbuildexpose1", "testbuildexpose2")
if id1 != id2 {
- t.Errorf("EXPOSE should invalidate the cache only when ports actually changed")
+ c.Errorf("EXPOSE should invalidate the cache only when ports actually changed")
}
- logDone("build - expose order")
}
-func TestBuildExposeUpperCaseProto(t *testing.T) {
+func (s *DockerSuite) TestBuildExposeUpperCaseProto(c *check.C) {
name := "testbuildexposeuppercaseproto"
- expected := "map[5678/udp:map[]]"
- defer deleteImages(name)
+ expected := "map[5678/udp:{}]"
_, err := buildImage(name,
`FROM scratch
EXPOSE 5678/UDP`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectField(name, "Config.ExposedPorts")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != expected {
- t.Fatalf("Exposed ports %s, expected %s", res, expected)
+ c.Fatalf("Exposed ports %s, expected %s", res, expected)
}
- logDone("build - expose port with upper case proto")
}
-func TestBuildExposeHostPort(t *testing.T) {
+func (s *DockerSuite) TestBuildExposeHostPort(c *check.C) {
// start building docker file with ip:hostPort:containerPort
name := "testbuildexpose"
- expected := "map[5678/tcp:map[]]"
- defer deleteImages(name)
+ expected := "map[5678/tcp:{}]"
_, out, err := buildImageWithOut(name,
`FROM scratch
EXPOSE 192.168.1.2:2375:5678`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !strings.Contains(out, "to map host ports to container ports (ip:hostPort:containerPort) is deprecated.") {
- t.Fatal("Missing warning message")
+ c.Fatal("Missing warning message")
}
res, err := inspectField(name, "Config.ExposedPorts")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != expected {
- t.Fatalf("Exposed ports %s, expected %s", res, expected)
+ c.Fatalf("Exposed ports %s, expected %s", res, expected)
}
- logDone("build - ignore exposing host's port")
}
-func TestBuildEmptyEntrypointInheritance(t *testing.T) {
+func (s *DockerSuite) TestBuildEmptyEntrypointInheritance(c *check.C) {
name := "testbuildentrypointinheritance"
name2 := "testbuildentrypointinheritance2"
- defer deleteImages(name, name2)
_, err := buildImage(name,
`FROM busybox
ENTRYPOINT ["/bin/echo"]`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectField(name, "Config.Entrypoint")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- expected := "[/bin/echo]"
+ expected := "{[/bin/echo]}"
if res != expected {
- t.Fatalf("Entrypoint %s, expected %s", res, expected)
+ c.Fatalf("Entrypoint %s, expected %s", res, expected)
}
_, err = buildImage(name2,
@@ -2621,69 +2432,64 @@ func TestBuildEmptyEntrypointInheritance(t *testing.T) {
ENTRYPOINT []`, name),
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err = inspectField(name2, "Config.Entrypoint")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- expected = "[]"
+ expected = "{[]}"
if res != expected {
- t.Fatalf("Entrypoint %s, expected %s", res, expected)
+ c.Fatalf("Entrypoint %s, expected %s", res, expected)
}
- logDone("build - empty entrypoint inheritance")
}
-func TestBuildEmptyEntrypoint(t *testing.T) {
+func (s *DockerSuite) TestBuildEmptyEntrypoint(c *check.C) {
name := "testbuildentrypoint"
- defer deleteImages(name)
- expected := "[]"
+ expected := "{[]}"
_, err := buildImage(name,
`FROM busybox
ENTRYPOINT []`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectField(name, "Config.Entrypoint")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != expected {
- t.Fatalf("Entrypoint %s, expected %s", res, expected)
+ c.Fatalf("Entrypoint %s, expected %s", res, expected)
}
- logDone("build - empty entrypoint")
}
-func TestBuildEntrypoint(t *testing.T) {
+func (s *DockerSuite) TestBuildEntrypoint(c *check.C) {
name := "testbuildentrypoint"
- expected := "[/bin/echo]"
- defer deleteImages(name)
+ expected := "{[/bin/echo]}"
_, err := buildImage(name,
`FROM scratch
ENTRYPOINT ["/bin/echo"]`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectField(name, "Config.Entrypoint")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != expected {
- t.Fatalf("Entrypoint %s, expected %s", res, expected)
+ c.Fatalf("Entrypoint %s, expected %s", res, expected)
}
- logDone("build - entrypoint")
}
// #6445 ensure ONBUILD triggers aren't committed to grandchildren
-func TestBuildOnBuildLimitedInheritence(t *testing.T) {
+func (s *DockerSuite) TestBuildOnBuildLimitedInheritence(c *check.C) {
var (
out2, out3 string
)
@@ -2696,15 +2502,14 @@ func TestBuildOnBuildLimitedInheritence(t *testing.T) {
`
ctx, err := fakeContext(dockerfile1, nil)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
- out1, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-t", name1, ".")
+ out1, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", name1, ".")
if err != nil {
- t.Fatalf("build failed to complete: %s, %v", out1, err)
+ c.Fatalf("build failed to complete: %s, %v", out1, err)
}
- defer deleteImages(name1)
}
{
name2 := "testonbuildtrigger2"
@@ -2713,15 +2518,14 @@ func TestBuildOnBuildLimitedInheritence(t *testing.T) {
`
ctx, err := fakeContext(dockerfile2, nil)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
- out2, _, err = dockerCmdInDir(t, ctx.Dir, "build", "-t", name2, ".")
+ out2, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-t", name2, ".")
if err != nil {
- t.Fatalf("build failed to complete: %s, %v", out2, err)
+ c.Fatalf("build failed to complete: %s, %v", out2, err)
}
- defer deleteImages(name2)
}
{
name3 := "testonbuildtrigger3"
@@ -2730,34 +2534,31 @@ func TestBuildOnBuildLimitedInheritence(t *testing.T) {
`
ctx, err := fakeContext(dockerfile3, nil)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
- out3, _, err = dockerCmdInDir(t, ctx.Dir, "build", "-t", name3, ".")
+ out3, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-t", name3, ".")
if err != nil {
- t.Fatalf("build failed to complete: %s, %v", out3, err)
+ c.Fatalf("build failed to complete: %s, %v", out3, err)
}
- defer deleteImages(name3)
}
// ONBUILD should be run in second build.
if !strings.Contains(out2, "ONBUILD PARENT") {
- t.Fatalf("ONBUILD instruction did not run in child of ONBUILD parent")
+ c.Fatalf("ONBUILD instruction did not run in child of ONBUILD parent")
}
// ONBUILD should *not* be run in third build.
if strings.Contains(out3, "ONBUILD PARENT") {
- t.Fatalf("ONBUILD instruction ran in grandchild of ONBUILD parent")
+ c.Fatalf("ONBUILD instruction ran in grandchild of ONBUILD parent")
}
- logDone("build - onbuild")
}
-func TestBuildWithCache(t *testing.T) {
+func (s *DockerSuite) TestBuildWithCache(c *check.C) {
name := "testbuildwithcache"
- defer deleteImages(name)
id1, err := buildImage(name,
`FROM scratch
MAINTAINER dockerio
@@ -2765,7 +2566,7 @@ func TestBuildWithCache(t *testing.T) {
ENTRYPOINT ["/bin/echo"]`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id2, err := buildImage(name,
`FROM scratch
@@ -2774,18 +2575,16 @@ func TestBuildWithCache(t *testing.T) {
ENTRYPOINT ["/bin/echo"]`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 != id2 {
- t.Fatal("The cache should have been used but hasn't.")
+ c.Fatal("The cache should have been used but hasn't.")
}
- logDone("build - with cache")
}
-func TestBuildWithoutCache(t *testing.T) {
+func (s *DockerSuite) TestBuildWithoutCache(c *check.C) {
name := "testbuildwithoutcache"
name2 := "testbuildwithoutcache2"
- defer deleteImages(name, name2)
id1, err := buildImage(name,
`FROM scratch
MAINTAINER dockerio
@@ -2793,7 +2592,7 @@ func TestBuildWithoutCache(t *testing.T) {
ENTRYPOINT ["/bin/echo"]`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id2, err := buildImage(name2,
@@ -2803,18 +2602,15 @@ func TestBuildWithoutCache(t *testing.T) {
ENTRYPOINT ["/bin/echo"]`,
false)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 == id2 {
- t.Fatal("The cache should have been invalided but hasn't.")
+ c.Fatal("The cache should have been invalided but hasn't.")
}
- logDone("build - without cache")
}
-func TestBuildConditionalCache(t *testing.T) {
+func (s *DockerSuite) TestBuildConditionalCache(c *check.C) {
name := "testbuildconditionalcache"
- name2 := "testbuildconditionalcache2"
- defer deleteImages(name, name2)
dockerfile := `
FROM busybox
@@ -2823,42 +2619,39 @@ func TestBuildConditionalCache(t *testing.T) {
"foo": "hello",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
id1, err := buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatalf("Error building #1: %s", err)
+ c.Fatalf("Error building #1: %s", err)
}
if err := ctx.Add("foo", "bye"); err != nil {
- t.Fatalf("Error modifying foo: %s", err)
+ c.Fatalf("Error modifying foo: %s", err)
}
id2, err := buildImageFromContext(name, ctx, false)
if err != nil {
- t.Fatalf("Error building #2: %s", err)
+ c.Fatalf("Error building #2: %s", err)
}
if id2 == id1 {
- t.Fatal("Should not have used the cache")
+ c.Fatal("Should not have used the cache")
}
id3, err := buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatalf("Error building #3: %s", err)
+ c.Fatalf("Error building #3: %s", err)
}
if id3 != id2 {
- t.Fatal("Should have used the cache")
+ c.Fatal("Should have used the cache")
}
-
- logDone("build - conditional cache")
}
-func TestBuildADDLocalFileWithCache(t *testing.T) {
+func (s *DockerSuite) TestBuildADDLocalFileWithCache(c *check.C) {
name := "testbuildaddlocalfilewithcache"
name2 := "testbuildaddlocalfilewithcache2"
- defer deleteImages(name, name2)
dockerfile := `
FROM busybox
MAINTAINER dockerio
@@ -2869,26 +2662,24 @@ func TestBuildADDLocalFileWithCache(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id1, err := buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id2, err := buildImageFromContext(name2, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 != id2 {
- t.Fatal("The cache should have been used but hasn't.")
+ c.Fatal("The cache should have been used but hasn't.")
}
- logDone("build - add local file with cache")
}
-func TestBuildADDMultipleLocalFileWithCache(t *testing.T) {
+func (s *DockerSuite) TestBuildADDMultipleLocalFileWithCache(c *check.C) {
name := "testbuildaddmultiplelocalfilewithcache"
name2 := "testbuildaddmultiplelocalfilewithcache2"
- defer deleteImages(name, name2)
dockerfile := `
FROM busybox
MAINTAINER dockerio
@@ -2899,26 +2690,24 @@ func TestBuildADDMultipleLocalFileWithCache(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id1, err := buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id2, err := buildImageFromContext(name2, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 != id2 {
- t.Fatal("The cache should have been used but hasn't.")
+ c.Fatal("The cache should have been used but hasn't.")
}
- logDone("build - add multiple local files with cache")
}
-func TestBuildADDLocalFileWithoutCache(t *testing.T) {
+func (s *DockerSuite) TestBuildADDLocalFileWithoutCache(c *check.C) {
name := "testbuildaddlocalfilewithoutcache"
name2 := "testbuildaddlocalfilewithoutcache2"
- defer deleteImages(name, name2)
dockerfile := `
FROM busybox
MAINTAINER dockerio
@@ -2929,26 +2718,24 @@ func TestBuildADDLocalFileWithoutCache(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id1, err := buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id2, err := buildImageFromContext(name2, ctx, false)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 == id2 {
- t.Fatal("The cache should have been invalided but hasn't.")
+ c.Fatal("The cache should have been invalided but hasn't.")
}
- logDone("build - add local file without cache")
}
-func TestBuildCopyDirButNotFile(t *testing.T) {
+func (s *DockerSuite) TestBuildCopyDirButNotFile(c *check.C) {
name := "testbuildcopydirbutnotfile"
name2 := "testbuildcopydirbutnotfile2"
- defer deleteImages(name, name2)
dockerfile := `
FROM scratch
COPY dir /tmp/`
@@ -2957,33 +2744,31 @@ func TestBuildCopyDirButNotFile(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id1, err := buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// Check that adding file with similar name doesn't mess with cache
if err := ctx.Add("dir_file", "hello2"); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id2, err := buildImageFromContext(name2, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 != id2 {
- t.Fatal("The cache should have been used but wasn't")
+ c.Fatal("The cache should have been used but wasn't")
}
- logDone("build - add current directory but not file")
}
-func TestBuildADDCurrentDirWithCache(t *testing.T) {
+func (s *DockerSuite) TestBuildADDCurrentDirWithCache(c *check.C) {
name := "testbuildaddcurrentdirwithcache"
name2 := name + "2"
name3 := name + "3"
name4 := name + "4"
name5 := name + "5"
- defer deleteImages(name, name2, name3, name4, name5)
dockerfile := `
FROM scratch
MAINTAINER dockerio
@@ -2993,60 +2778,58 @@ func TestBuildADDCurrentDirWithCache(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id1, err := buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// Check that adding file invalidate cache of "ADD ."
if err := ctx.Add("bar", "hello2"); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id2, err := buildImageFromContext(name2, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 == id2 {
- t.Fatal("The cache should have been invalided but hasn't.")
+ c.Fatal("The cache should have been invalided but hasn't.")
}
// Check that changing file invalidate cache of "ADD ."
if err := ctx.Add("foo", "hello1"); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id3, err := buildImageFromContext(name3, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id2 == id3 {
- t.Fatal("The cache should have been invalided but hasn't.")
+ c.Fatal("The cache should have been invalided but hasn't.")
}
// Check that changing file to same content invalidate cache of "ADD ."
time.Sleep(1 * time.Second) // wait second because of mtime precision
if err := ctx.Add("foo", "hello1"); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id4, err := buildImageFromContext(name4, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id3 == id4 {
- t.Fatal("The cache should have been invalided but hasn't.")
+ c.Fatal("The cache should have been invalided but hasn't.")
}
id5, err := buildImageFromContext(name5, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id4 != id5 {
- t.Fatal("The cache should have been used but hasn't.")
+ c.Fatal("The cache should have been used but hasn't.")
}
- logDone("build - add current directory with cache")
}
-func TestBuildADDCurrentDirWithoutCache(t *testing.T) {
+func (s *DockerSuite) TestBuildADDCurrentDirWithoutCache(c *check.C) {
name := "testbuildaddcurrentdirwithoutcache"
name2 := "testbuildaddcurrentdirwithoutcache2"
- defer deleteImages(name, name2)
dockerfile := `
FROM scratch
MAINTAINER dockerio
@@ -3056,30 +2839,28 @@ func TestBuildADDCurrentDirWithoutCache(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id1, err := buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id2, err := buildImageFromContext(name2, ctx, false)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 == id2 {
- t.Fatal("The cache should have been invalided but hasn't.")
+ c.Fatal("The cache should have been invalided but hasn't.")
}
- logDone("build - add current directory without cache")
}
-func TestBuildADDRemoteFileWithCache(t *testing.T) {
+func (s *DockerSuite) TestBuildADDRemoteFileWithCache(c *check.C) {
name := "testbuildaddremotefilewithcache"
- defer deleteImages(name)
server, err := fakeStorage(map[string]string{
"baz": "hello",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer server.Close()
@@ -3089,7 +2870,7 @@ func TestBuildADDRemoteFileWithCache(t *testing.T) {
ADD %s/baz /usr/lib/baz/quux`, server.URL()),
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id2, err := buildImage(name,
fmt.Sprintf(`FROM scratch
@@ -3097,23 +2878,21 @@ func TestBuildADDRemoteFileWithCache(t *testing.T) {
ADD %s/baz /usr/lib/baz/quux`, server.URL()),
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 != id2 {
- t.Fatal("The cache should have been used but hasn't.")
+ c.Fatal("The cache should have been used but hasn't.")
}
- logDone("build - add remote file with cache")
}
-func TestBuildADDRemoteFileWithoutCache(t *testing.T) {
+func (s *DockerSuite) TestBuildADDRemoteFileWithoutCache(c *check.C) {
name := "testbuildaddremotefilewithoutcache"
name2 := "testbuildaddremotefilewithoutcache2"
- defer deleteImages(name, name2)
server, err := fakeStorage(map[string]string{
"baz": "hello",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer server.Close()
@@ -3123,7 +2902,7 @@ func TestBuildADDRemoteFileWithoutCache(t *testing.T) {
ADD %s/baz /usr/lib/baz/quux`, server.URL()),
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id2, err := buildImage(name2,
fmt.Sprintf(`FROM scratch
@@ -3131,26 +2910,23 @@ func TestBuildADDRemoteFileWithoutCache(t *testing.T) {
ADD %s/baz /usr/lib/baz/quux`, server.URL()),
false)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 == id2 {
- t.Fatal("The cache should have been invalided but hasn't.")
+ c.Fatal("The cache should have been invalided but hasn't.")
}
- logDone("build - add remote file without cache")
}
-func TestBuildADDRemoteFileMTime(t *testing.T) {
+func (s *DockerSuite) TestBuildADDRemoteFileMTime(c *check.C) {
name := "testbuildaddremotefilemtime"
name2 := name + "2"
name3 := name + "3"
name4 := name + "4"
- defer deleteImages(name, name2, name3, name4)
-
files := map[string]string{"baz": "hello"}
server, err := fakeStorage(files)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer server.Close()
@@ -3158,21 +2934,21 @@ func TestBuildADDRemoteFileMTime(t *testing.T) {
MAINTAINER dockerio
ADD %s/baz /usr/lib/baz/quux`, server.URL()), nil)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
id1, err := buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id2, err := buildImageFromContext(name2, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 != id2 {
- t.Fatal("The cache should have been used but wasn't - #1")
+ c.Fatal("The cache should have been used but wasn't - #1")
}
// Now create a different server withsame contents (causes different mtim)
@@ -3183,7 +2959,7 @@ func TestBuildADDRemoteFileMTime(t *testing.T) {
server2, err := fakeStorage(files)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer server2.Close()
@@ -3191,36 +2967,34 @@ func TestBuildADDRemoteFileMTime(t *testing.T) {
MAINTAINER dockerio
ADD %s/baz /usr/lib/baz/quux`, server2.URL()), nil)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx2.Close()
id3, err := buildImageFromContext(name3, ctx2, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 == id3 {
- t.Fatal("The cache should not have been used but was")
+ c.Fatal("The cache should not have been used but was")
}
// And for good measure do it again and make sure cache is used this time
id4, err := buildImageFromContext(name4, ctx2, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id3 != id4 {
- t.Fatal("The cache should have been used but wasn't - #2")
+ c.Fatal("The cache should have been used but wasn't - #2")
}
- logDone("build - add remote file testing mtime")
}
-func TestBuildADDLocalAndRemoteFilesWithCache(t *testing.T) {
+func (s *DockerSuite) TestBuildADDLocalAndRemoteFilesWithCache(c *check.C) {
name := "testbuildaddlocalandremotefilewithcache"
- defer deleteImages(name)
server, err := fakeStorage(map[string]string{
"baz": "hello",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer server.Close()
@@ -3232,24 +3006,23 @@ func TestBuildADDLocalAndRemoteFilesWithCache(t *testing.T) {
"foo": "hello world",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
id1, err := buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id2, err := buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 != id2 {
- t.Fatal("The cache should have been used but hasn't.")
+ c.Fatal("The cache should have been used but hasn't.")
}
- logDone("build - add local and remote file with cache")
}
-func testContextTar(t *testing.T, compression archive.Compression) {
+func testContextTar(c *check.C, compression archive.Compression) {
ctx, err := fakeContext(
`FROM busybox
ADD foo /foo
@@ -3260,58 +3033,51 @@ CMD ["cat", "/foo"]`,
)
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
context, err := archive.Tar(ctx.Dir, compression)
if err != nil {
- t.Fatalf("failed to build context tar: %v", err)
+ c.Fatalf("failed to build context tar: %v", err)
}
name := "contexttar"
buildCmd := exec.Command(dockerBinary, "build", "-t", name, "-")
- defer deleteImages(name)
buildCmd.Stdin = context
if out, _, err := runCommandWithOutput(buildCmd); err != nil {
- t.Fatalf("build failed to complete: %v %v", out, err)
+ c.Fatalf("build failed to complete: %v %v", out, err)
}
}
-func TestBuildContextTarGzip(t *testing.T) {
- testContextTar(t, archive.Gzip)
- logDone(fmt.Sprintf("build - build an image with a context tar, compression: %v", archive.Gzip))
+func (s *DockerSuite) TestBuildContextTarGzip(c *check.C) {
+ testContextTar(c, archive.Gzip)
}
-func TestBuildContextTarNoCompression(t *testing.T) {
- testContextTar(t, archive.Uncompressed)
- logDone(fmt.Sprintf("build - build an image with a context tar, compression: %v", archive.Uncompressed))
+func (s *DockerSuite) TestBuildContextTarNoCompression(c *check.C) {
+ testContextTar(c, archive.Uncompressed)
}
-func TestBuildNoContext(t *testing.T) {
+func (s *DockerSuite) TestBuildNoContext(c *check.C) {
buildCmd := exec.Command(dockerBinary, "build", "-t", "nocontext", "-")
buildCmd.Stdin = strings.NewReader("FROM busybox\nCMD echo ok\n")
if out, _, err := runCommandWithOutput(buildCmd); err != nil {
- t.Fatalf("build failed to complete: %v %v", out, err)
+ c.Fatalf("build failed to complete: %v %v", out, err)
}
- if out, _, err := dockerCmd(t, "run", "--rm", "nocontext"); out != "ok\n" || err != nil {
- t.Fatalf("run produced invalid output: %q, expected %q", out, "ok")
+ if out, _ := dockerCmd(c, "run", "--rm", "nocontext"); out != "ok\n" {
+ c.Fatalf("run produced invalid output: %q, expected %q", out, "ok")
}
-
- deleteImages("nocontext")
- logDone("build - build an image with no context")
}
// TODO: TestCaching
-func TestBuildADDLocalAndRemoteFilesWithoutCache(t *testing.T) {
+func (s *DockerSuite) TestBuildADDLocalAndRemoteFilesWithoutCache(c *check.C) {
name := "testbuildaddlocalandremotefilewithoutcache"
name2 := "testbuildaddlocalandremotefilewithoutcache2"
- defer deleteImages(name, name2)
server, err := fakeStorage(map[string]string{
"baz": "hello",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer server.Close()
@@ -3323,26 +3089,24 @@ func TestBuildADDLocalAndRemoteFilesWithoutCache(t *testing.T) {
"foo": "hello world",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
id1, err := buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id2, err := buildImageFromContext(name2, ctx, false)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 == id2 {
- t.Fatal("The cache should have been invalided but hasn't.")
+ c.Fatal("The cache should have been invalided but hasn't.")
}
- logDone("build - add local and remote file without cache")
}
-func TestBuildWithVolumeOwnership(t *testing.T) {
+func (s *DockerSuite) TestBuildWithVolumeOwnership(c *check.C) {
name := "testbuildimg"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM busybox:latest
@@ -3351,36 +3115,34 @@ func TestBuildWithVolumeOwnership(t *testing.T) {
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd := exec.Command(dockerBinary, "run", "--rm", "testbuildimg", "ls", "-la", "/test")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if expected := "drw-------"; !strings.Contains(out, expected) {
- t.Fatalf("expected %s received %s", expected, out)
+ c.Fatalf("expected %s received %s", expected, out)
}
if expected := "daemon daemon"; !strings.Contains(out, expected) {
- t.Fatalf("expected %s received %s", expected, out)
+ c.Fatalf("expected %s received %s", expected, out)
}
- logDone("build - volume ownership")
}
// testing #1405 - config.Cmd does not get cleaned up if
// utilizing cache
-func TestBuildEntrypointRunCleanup(t *testing.T) {
+func (s *DockerSuite) TestBuildEntrypointRunCleanup(c *check.C) {
name := "testbuildcmdcleanup"
- defer deleteImages(name)
if _, err := buildImage(name,
`FROM busybox
RUN echo "hello"`,
true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
ctx, err := fakeContext(`FROM busybox
@@ -3392,25 +3154,23 @@ func TestBuildEntrypointRunCleanup(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectField(name, "Config.Cmd")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// Cmd must be cleaned up
- if expected := ""; res != expected {
- t.Fatalf("Cmd %s, expected %s", res, expected)
+ if res != "" {
+ c.Fatalf("Cmd %s, expected nil", res)
}
- logDone("build - cleanup cmd after RUN")
}
-func TestBuildForbiddenContextPath(t *testing.T) {
+func (s *DockerSuite) TestBuildForbiddenContextPath(c *check.C) {
name := "testbuildforbidpath"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM scratch
ADD ../../ test/
`,
@@ -3420,51 +3180,47 @@ func TestBuildForbiddenContextPath(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
expected := "Forbidden path outside the build context: ../../ "
if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) {
- t.Fatalf("Wrong error: (should contain \"%s\") got:\n%v", expected, err)
+ c.Fatalf("Wrong error: (should contain \"%s\") got:\n%v", expected, err)
}
- logDone("build - forbidden context path")
}
-func TestBuildADDFileNotFound(t *testing.T) {
+func (s *DockerSuite) TestBuildADDFileNotFound(c *check.C) {
name := "testbuildaddnotfound"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM scratch
ADD foo /usr/local/bar`,
map[string]string{"bar": "hello"})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := buildImageFromContext(name, ctx, true); err != nil {
if !strings.Contains(err.Error(), "foo: no such file or directory") {
- t.Fatalf("Wrong error %v, must be about missing foo file or directory", err)
+ c.Fatalf("Wrong error %v, must be about missing foo file or directory", err)
}
} else {
- t.Fatal("Error must not be nil")
+ c.Fatal("Error must not be nil")
}
- logDone("build - add file not found")
}
-func TestBuildInheritance(t *testing.T) {
+func (s *DockerSuite) TestBuildInheritance(c *check.C) {
name := "testbuildinheritance"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM scratch
EXPOSE 2375`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
ports1, err := inspectField(name, "Config.ExposedPorts")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
_, err = buildImage(name,
@@ -3472,133 +3228,118 @@ func TestBuildInheritance(t *testing.T) {
ENTRYPOINT ["/bin/echo"]`, name),
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectField(name, "Config.Entrypoint")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- if expected := "[/bin/echo]"; res != expected {
- t.Fatalf("Entrypoint %s, expected %s", res, expected)
+ if expected := "{[/bin/echo]}"; res != expected {
+ c.Fatalf("Entrypoint %s, expected %s", res, expected)
}
ports2, err := inspectField(name, "Config.ExposedPorts")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if ports1 != ports2 {
- t.Fatalf("Ports must be same: %s != %s", ports1, ports2)
+ c.Fatalf("Ports must be same: %s != %s", ports1, ports2)
}
- logDone("build - inheritance")
}
-func TestBuildFails(t *testing.T) {
+func (s *DockerSuite) TestBuildFails(c *check.C) {
name := "testbuildfails"
- defer deleteImages(name)
- defer deleteAllContainers()
_, err := buildImage(name,
`FROM busybox
RUN sh -c "exit 23"`,
true)
if err != nil {
if !strings.Contains(err.Error(), "returned a non-zero code: 23") {
- t.Fatalf("Wrong error %v, must be about non-zero code 23", err)
+ c.Fatalf("Wrong error %v, must be about non-zero code 23", err)
}
} else {
- t.Fatal("Error must not be nil")
+ c.Fatal("Error must not be nil")
}
- logDone("build - unsuccessful")
}
-func TestBuildFailsDockerfileEmpty(t *testing.T) {
+func (s *DockerSuite) TestBuildFailsDockerfileEmpty(c *check.C) {
name := "testbuildfails"
- defer deleteImages(name)
_, err := buildImage(name, ``, true)
if err != nil {
if !strings.Contains(err.Error(), "The Dockerfile (Dockerfile) cannot be empty") {
- t.Fatalf("Wrong error %v, must be about empty Dockerfile", err)
+ c.Fatalf("Wrong error %v, must be about empty Dockerfile", err)
}
} else {
- t.Fatal("Error must not be nil")
+ c.Fatal("Error must not be nil")
}
- logDone("build - unsuccessful with empty dockerfile")
}
-func TestBuildOnBuild(t *testing.T) {
+func (s *DockerSuite) TestBuildOnBuild(c *check.C) {
name := "testbuildonbuild"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM busybox
ONBUILD RUN touch foobar`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
_, err = buildImage(name,
fmt.Sprintf(`FROM %s
RUN [ -f foobar ]`, name),
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - onbuild")
}
-func TestBuildOnBuildForbiddenChained(t *testing.T) {
+func (s *DockerSuite) TestBuildOnBuildForbiddenChained(c *check.C) {
name := "testbuildonbuildforbiddenchained"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM busybox
ONBUILD ONBUILD RUN touch foobar`,
true)
if err != nil {
if !strings.Contains(err.Error(), "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed") {
- t.Fatalf("Wrong error %v, must be about chaining ONBUILD", err)
+ c.Fatalf("Wrong error %v, must be about chaining ONBUILD", err)
}
} else {
- t.Fatal("Error must not be nil")
+ c.Fatal("Error must not be nil")
}
- logDone("build - onbuild forbidden chained")
}
-func TestBuildOnBuildForbiddenFrom(t *testing.T) {
+func (s *DockerSuite) TestBuildOnBuildForbiddenFrom(c *check.C) {
name := "testbuildonbuildforbiddenfrom"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM busybox
ONBUILD FROM scratch`,
true)
if err != nil {
if !strings.Contains(err.Error(), "FROM isn't allowed as an ONBUILD trigger") {
- t.Fatalf("Wrong error %v, must be about FROM forbidden", err)
+ c.Fatalf("Wrong error %v, must be about FROM forbidden", err)
}
} else {
- t.Fatal("Error must not be nil")
+ c.Fatal("Error must not be nil")
}
- logDone("build - onbuild forbidden from")
}
-func TestBuildOnBuildForbiddenMaintainer(t *testing.T) {
+func (s *DockerSuite) TestBuildOnBuildForbiddenMaintainer(c *check.C) {
name := "testbuildonbuildforbiddenmaintainer"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM busybox
ONBUILD MAINTAINER docker.io`,
true)
if err != nil {
if !strings.Contains(err.Error(), "MAINTAINER isn't allowed as an ONBUILD trigger") {
- t.Fatalf("Wrong error %v, must be about MAINTAINER forbidden", err)
+ c.Fatalf("Wrong error %v, must be about MAINTAINER forbidden", err)
}
} else {
- t.Fatal("Error must not be nil")
+ c.Fatal("Error must not be nil")
}
- logDone("build - onbuild forbidden maintainer")
}
// gh #2446
-func TestBuildAddToSymlinkDest(t *testing.T) {
+func (s *DockerSuite) TestBuildAddToSymlinkDest(c *check.C) {
name := "testbuildaddtosymlinkdest"
- defer deleteImages(name)
ctx, err := fakeContext(`FROM busybox
RUN mkdir /foo
RUN ln -s /foo /bar
@@ -3609,18 +3350,16 @@ func TestBuildAddToSymlinkDest(t *testing.T) {
"foo": "hello",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - add to symlink destination")
}
-func TestBuildEscapeWhitespace(t *testing.T) {
+func (s *DockerSuite) TestBuildEscapeWhitespace(c *check.C) {
name := "testbuildescaping"
- defer deleteImages(name)
_, err := buildImage(name, `
FROM busybox
@@ -3632,20 +3371,18 @@ docker.com>"
res, err := inspectField(name, "Author")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != "\"Docker IO \"" {
- t.Fatalf("Parsed string did not match the escaped string. Got: %q", res)
+ c.Fatalf("Parsed string did not match the escaped string. Got: %q", res)
}
- logDone("build - validate escaping whitespace")
}
-func TestBuildVerifyIntString(t *testing.T) {
+func (s *DockerSuite) TestBuildVerifyIntString(c *check.C) {
// Verify that strings that look like ints are still passed as strings
name := "testbuildstringing"
- defer deleteImages(name)
_, err := buildImage(name, `
FROM busybox
@@ -3654,19 +3391,17 @@ func TestBuildVerifyIntString(t *testing.T) {
out, rc, err := runCommandWithOutput(exec.Command(dockerBinary, "inspect", name))
if rc != 0 || err != nil {
- t.Fatalf("Unexcepted error from inspect: rc: %v err: %v", rc, err)
+ c.Fatalf("Unexpected error from inspect: rc: %v err: %v", rc, err)
}
if !strings.Contains(out, "\"123\"") {
- t.Fatalf("Output does not contain the int as a string:\n%s", out)
+ c.Fatalf("Output does not contain the int as a string:\n%s", out)
}
- logDone("build - verify int/strings as strings")
}
-func TestBuildDockerignore(t *testing.T) {
+func (s *DockerSuite) TestBuildDockerignore(c *check.C) {
name := "testbuilddockerignore"
- defer deleteImages(name)
dockerfile := `
FROM busybox
ADD . /bla
@@ -3675,29 +3410,36 @@ func TestBuildDockerignore(t *testing.T) {
RUN [[ ! -e /bla/src/_vendor ]]
RUN [[ ! -e /bla/.gitignore ]]
RUN [[ ! -e /bla/README.md ]]
+ RUN [[ ! -e /bla/dir/foo ]]
+ RUN [[ ! -e /bla/foo ]]
RUN [[ ! -e /bla/.git ]]`
ctx, err := fakeContext(dockerfile, map[string]string{
"Makefile": "all:",
".git/HEAD": "ref: foo",
"src/x.go": "package main",
"src/_vendor/v.go": "package main",
+ "dir/foo": "",
".gitignore": "",
"README.md": "readme",
- ".dockerignore": ".git\npkg\n.gitignore\nsrc/_vendor\n*.md",
+ ".dockerignore": `
+.git
+pkg
+.gitignore
+src/_vendor
+*.md
+dir`,
})
- defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
+ defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - test .dockerignore")
}
-func TestBuildDockerignoreCleanPaths(t *testing.T) {
+func (s *DockerSuite) TestBuildDockerignoreCleanPaths(c *check.C) {
name := "testbuilddockerignorecleanpaths"
- defer deleteImages(name)
dockerfile := `
FROM busybox
ADD . /tmp/
@@ -3709,19 +3451,66 @@ func TestBuildDockerignoreCleanPaths(t *testing.T) {
".dockerignore": "./foo\ndir1//foo\n./dir1/../foo2",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - test .dockerignore with clean paths")
}
-func TestBuildDockerignoringDockerfile(t *testing.T) {
- name := "testbuilddockerignoredockerfile"
+func (s *DockerSuite) TestBuildDockerignoreExceptions(c *check.C) {
+ name := "testbuilddockerignoreexceptions"
defer deleteImages(name)
dockerfile := `
+ FROM busybox
+ ADD . /bla
+ RUN [[ -f /bla/src/x.go ]]
+ RUN [[ -f /bla/Makefile ]]
+ RUN [[ ! -e /bla/src/_vendor ]]
+ RUN [[ ! -e /bla/.gitignore ]]
+ RUN [[ ! -e /bla/README.md ]]
+ RUN [[ -e /bla/dir/dir/foo ]]
+ RUN [[ ! -e /bla/dir/foo1 ]]
+ RUN [[ -f /bla/dir/e ]]
+ RUN [[ -f /bla/dir/e-dir/foo ]]
+ RUN [[ ! -e /bla/foo ]]
+ RUN [[ ! -e /bla/.git ]]`
+ ctx, err := fakeContext(dockerfile, map[string]string{
+ "Makefile": "all:",
+ ".git/HEAD": "ref: foo",
+ "src/x.go": "package main",
+ "src/_vendor/v.go": "package main",
+ "dir/foo": "",
+ "dir/foo1": "",
+ "dir/dir/f1": "",
+ "dir/dir/foo": "",
+ "dir/e": "",
+ "dir/e-dir/foo": "",
+ ".gitignore": "",
+ "README.md": "readme",
+ ".dockerignore": `
+.git
+pkg
+.gitignore
+src/_vendor
+*.md
+dir
+!dir/e*
+!dir/dir/foo`,
+ })
+ if err != nil {
+ c.Fatal(err)
+ }
+ defer ctx.Close()
+ if _, err := buildImageFromContext(name, ctx, true); err != nil {
+ c.Fatal(err)
+ }
+}
+
+func (s *DockerSuite) TestBuildDockerignoringDockerfile(c *check.C) {
+ name := "testbuilddockerignoredockerfile"
+ dockerfile := `
FROM busybox
ADD . /tmp/
RUN ! ls /tmp/Dockerfile
@@ -3731,26 +3520,24 @@ func TestBuildDockerignoringDockerfile(t *testing.T) {
".dockerignore": "Dockerfile\n",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err = buildImageFromContext(name, ctx, true); err != nil {
- t.Fatalf("Didn't ignore Dockerfile correctly:%s", err)
+ c.Fatalf("Didn't ignore Dockerfile correctly:%s", err)
}
// now try it with ./Dockerfile
ctx.Add(".dockerignore", "./Dockerfile\n")
if _, err = buildImageFromContext(name, ctx, true); err != nil {
- t.Fatalf("Didn't ignore ./Dockerfile correctly:%s", err)
+ c.Fatalf("Didn't ignore ./Dockerfile correctly:%s", err)
}
- logDone("build - test .dockerignore of Dockerfile")
}
-func TestBuildDockerignoringRenamedDockerfile(t *testing.T) {
+func (s *DockerSuite) TestBuildDockerignoringRenamedDockerfile(c *check.C) {
name := "testbuilddockerignoredockerfile"
- defer deleteImages(name)
dockerfile := `
FROM busybox
ADD . /tmp/
@@ -3763,26 +3550,24 @@ func TestBuildDockerignoringRenamedDockerfile(t *testing.T) {
".dockerignore": "MyDockerfile\n",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err = buildImageFromContext(name, ctx, true); err != nil {
- t.Fatalf("Didn't ignore MyDockerfile correctly:%s", err)
+ c.Fatalf("Didn't ignore MyDockerfile correctly:%s", err)
}
// now try it with ./MyDockerfile
ctx.Add(".dockerignore", "./MyDockerfile\n")
if _, err = buildImageFromContext(name, ctx, true); err != nil {
- t.Fatalf("Didn't ignore ./MyDockerfile correctly:%s", err)
+ c.Fatalf("Didn't ignore ./MyDockerfile correctly:%s", err)
}
- logDone("build - test .dockerignore of renamed Dockerfile")
}
-func TestBuildDockerignoringDockerignore(t *testing.T) {
+func (s *DockerSuite) TestBuildDockerignoringDockerignore(c *check.C) {
name := "testbuilddockerignoredockerignore"
- defer deleteImages(name)
dockerfile := `
FROM busybox
ADD . /tmp/
@@ -3794,20 +3579,18 @@ func TestBuildDockerignoringDockerignore(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err = buildImageFromContext(name, ctx, true); err != nil {
- t.Fatalf("Didn't ignore .dockerignore correctly:%s", err)
+ c.Fatalf("Didn't ignore .dockerignore correctly:%s", err)
}
- logDone("build - test .dockerignore of .dockerignore")
}
-func TestBuildDockerignoreTouchDockerfile(t *testing.T) {
+func (s *DockerSuite) TestBuildDockerignoreTouchDockerfile(c *check.C) {
var id1 string
var id2 string
name := "testbuilddockerignoretouchdockerfile"
- defer deleteImages(name)
dockerfile := `
FROM busybox
ADD . /tmp/`
@@ -3817,48 +3600,46 @@ func TestBuildDockerignoreTouchDockerfile(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1, err = buildImageFromContext(name, ctx, true); err != nil {
- t.Fatalf("Didn't build it correctly:%s", err)
+ c.Fatalf("Didn't build it correctly:%s", err)
}
if id2, err = buildImageFromContext(name, ctx, true); err != nil {
- t.Fatalf("Didn't build it correctly:%s", err)
+ c.Fatalf("Didn't build it correctly:%s", err)
}
if id1 != id2 {
- t.Fatalf("Didn't use the cache - 1")
+ c.Fatalf("Didn't use the cache - 1")
}
// Now make sure touching Dockerfile doesn't invalidate the cache
if err = ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil {
- t.Fatalf("Didn't add Dockerfile: %s", err)
+ c.Fatalf("Didn't add Dockerfile: %s", err)
}
if id2, err = buildImageFromContext(name, ctx, true); err != nil {
- t.Fatalf("Didn't build it correctly:%s", err)
+ c.Fatalf("Didn't build it correctly:%s", err)
}
if id1 != id2 {
- t.Fatalf("Didn't use the cache - 2")
+ c.Fatalf("Didn't use the cache - 2")
}
// One more time but just 'touch' it instead of changing the content
if err = ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil {
- t.Fatalf("Didn't add Dockerfile: %s", err)
+ c.Fatalf("Didn't add Dockerfile: %s", err)
}
if id2, err = buildImageFromContext(name, ctx, true); err != nil {
- t.Fatalf("Didn't build it correctly:%s", err)
+ c.Fatalf("Didn't build it correctly:%s", err)
}
if id1 != id2 {
- t.Fatalf("Didn't use the cache - 3")
+ c.Fatalf("Didn't use the cache - 3")
}
- logDone("build - test .dockerignore touch dockerfile")
}
-func TestBuildDockerignoringWholeDir(t *testing.T) {
+func (s *DockerSuite) TestBuildDockerignoringWholeDir(c *check.C) {
name := "testbuilddockerignorewholedir"
- defer deleteImages(name)
dockerfile := `
FROM busybox
COPY . /
@@ -3867,21 +3648,20 @@ func TestBuildDockerignoringWholeDir(t *testing.T) {
ctx, err := fakeContext(dockerfile, map[string]string{
"Dockerfile": "FROM scratch",
"Makefile": "all:",
+ ".gitignore": "",
".dockerignore": ".*\n",
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err = buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - test .dockerignore whole dir with .*")
}
-func TestBuildLineBreak(t *testing.T) {
+func (s *DockerSuite) TestBuildLineBreak(c *check.C) {
name := "testbuildlinebreak"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM busybox
RUN sh -c 'echo root:testpass \
@@ -3891,14 +3671,12 @@ RUN [ "$(cat /tmp/passwd)" = "root:testpass" ]
RUN [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - line break with \\")
}
-func TestBuildEOLInLine(t *testing.T) {
+func (s *DockerSuite) TestBuildEOLInLine(c *check.C) {
name := "testbuildeolinline"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM busybox
RUN sh -c 'echo root:testpass > /tmp/passwd'
@@ -3908,14 +3686,12 @@ RUN [ "$(cat /tmp/passwd)" = "root:testpass" ]
RUN [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - end of line in dockerfile instruction")
}
-func TestBuildCommentsShebangs(t *testing.T) {
+func (s *DockerSuite) TestBuildCommentsShebangs(c *check.C) {
name := "testbuildcomments"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM busybox
# This is an ordinary comment.
@@ -3928,14 +3704,12 @@ RUN [ "$(cat /hello.sh)" = $'#!/bin/sh\necho hello world' ]
RUN [ "$(/hello.sh)" = "hello world" ]`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - comments and shebangs")
}
-func TestBuildUsersAndGroups(t *testing.T) {
+func (s *DockerSuite) TestBuildUsersAndGroups(c *check.C) {
name := "testbuildusers"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM busybox
@@ -3992,14 +3766,12 @@ USER 1042:1043
RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1042:1043/1042:1043/1043:1043' ]`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - users and groups")
}
-func TestBuildEnvUsage(t *testing.T) {
+func (s *DockerSuite) TestBuildEnvUsage(c *check.C) {
name := "testbuildenvusage"
- defer deleteImages(name)
dockerfile := `FROM busybox
ENV HOME /root
ENV PATH $HOME/bin:$PATH
@@ -4023,20 +3795,18 @@ RUN [ "$ghi" = "def" ]
"hello/docker/world": "hello",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
_, err = buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - environment variables usage")
}
-func TestBuildEnvUsage2(t *testing.T) {
+func (s *DockerSuite) TestBuildEnvUsage2(c *check.C) {
name := "testbuildenvusage2"
- defer deleteImages(name)
dockerfile := `FROM busybox
ENV abc=def
RUN [ "$abc" = "def" ]
@@ -4127,20 +3897,18 @@ RUN [ "$eee1,$eee2,$eee3,$eee4" = 'foo,foo,foo,foo' ]
"hello/docker/world": "hello",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
_, err = buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - environment variables usage2")
}
-func TestBuildAddScript(t *testing.T) {
+func (s *DockerSuite) TestBuildAddScript(c *check.C) {
name := "testbuildaddscript"
- defer deleteImages(name)
dockerfile := `
FROM busybox
ADD test /test
@@ -4151,20 +3919,18 @@ RUN [ "$(cat /testfile)" = 'test!' ]`
"test": "#!/bin/sh\necho 'test!' > /testfile",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
_, err = buildImageFromContext(name, ctx, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - add and run script")
}
-func TestBuildAddTar(t *testing.T) {
+func (s *DockerSuite) TestBuildAddTar(c *check.C) {
name := "testbuildaddtar"
- defer deleteImages(name)
ctx := func() *FakeContext {
dockerfile := `
@@ -4185,7 +3951,7 @@ RUN cat /existing-directory-trailing-slash/test/foo | grep Hi`
tmpDir, err := ioutil.TempDir("", "fake-context")
testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
if err != nil {
- t.Fatalf("failed to create test.tar archive: %v", err)
+ c.Fatalf("failed to create test.tar archive: %v", err)
}
defer testTar.Close()
@@ -4195,32 +3961,30 @@ RUN cat /existing-directory-trailing-slash/test/foo | grep Hi`
Name: "test/foo",
Size: 2,
}); err != nil {
- t.Fatalf("failed to write tar file header: %v", err)
+ c.Fatalf("failed to write tar file header: %v", err)
}
if _, err := tw.Write([]byte("Hi")); err != nil {
- t.Fatalf("failed to write tar file content: %v", err)
+ c.Fatalf("failed to write tar file content: %v", err)
}
if err := tw.Close(); err != nil {
- t.Fatalf("failed to close tar archive: %v", err)
+ c.Fatalf("failed to close tar archive: %v", err)
}
if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
- t.Fatalf("failed to open destination dockerfile: %v", err)
+ c.Fatalf("failed to open destination dockerfile: %v", err)
}
return fakeContextFromDir(tmpDir)
}()
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatalf("build failed to complete for TestBuildAddTar: %v", err)
+ c.Fatalf("build failed to complete for TestBuildAddTar: %v", err)
}
- logDone("build - ADD tar")
}
-func TestBuildAddTarXz(t *testing.T) {
+func (s *DockerSuite) TestBuildAddTarXz(c *check.C) {
name := "testbuildaddtarxz"
- defer deleteImages(name)
ctx := func() *FakeContext {
dockerfile := `
@@ -4230,7 +3994,7 @@ func TestBuildAddTarXz(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "fake-context")
testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
if err != nil {
- t.Fatalf("failed to create test.tar archive: %v", err)
+ c.Fatalf("failed to create test.tar archive: %v", err)
}
defer testTar.Close()
@@ -4240,23 +4004,23 @@ func TestBuildAddTarXz(t *testing.T) {
Name: "test/foo",
Size: 2,
}); err != nil {
- t.Fatalf("failed to write tar file header: %v", err)
+ c.Fatalf("failed to write tar file header: %v", err)
}
if _, err := tw.Write([]byte("Hi")); err != nil {
- t.Fatalf("failed to write tar file content: %v", err)
+ c.Fatalf("failed to write tar file content: %v", err)
}
if err := tw.Close(); err != nil {
- t.Fatalf("failed to close tar archive: %v", err)
+ c.Fatalf("failed to close tar archive: %v", err)
}
xzCompressCmd := exec.Command("xz", "-k", "test.tar")
xzCompressCmd.Dir = tmpDir
out, _, err := runCommandWithOutput(xzCompressCmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
- t.Fatalf("failed to open destination dockerfile: %v", err)
+ c.Fatalf("failed to open destination dockerfile: %v", err)
}
return fakeContextFromDir(tmpDir)
}()
@@ -4264,15 +4028,13 @@ func TestBuildAddTarXz(t *testing.T) {
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err)
+ c.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err)
}
- logDone("build - ADD tar.xz")
}
-func TestBuildAddTarXzGz(t *testing.T) {
+func (s *DockerSuite) TestBuildAddTarXzGz(c *check.C) {
name := "testbuildaddtarxzgz"
- defer deleteImages(name)
ctx := func() *FakeContext {
dockerfile := `
@@ -4282,7 +4044,7 @@ func TestBuildAddTarXzGz(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "fake-context")
testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
if err != nil {
- t.Fatalf("failed to create test.tar archive: %v", err)
+ c.Fatalf("failed to create test.tar archive: %v", err)
}
defer testTar.Close()
@@ -4292,31 +4054,31 @@ func TestBuildAddTarXzGz(t *testing.T) {
Name: "test/foo",
Size: 2,
}); err != nil {
- t.Fatalf("failed to write tar file header: %v", err)
+ c.Fatalf("failed to write tar file header: %v", err)
}
if _, err := tw.Write([]byte("Hi")); err != nil {
- t.Fatalf("failed to write tar file content: %v", err)
+ c.Fatalf("failed to write tar file content: %v", err)
}
if err := tw.Close(); err != nil {
- t.Fatalf("failed to close tar archive: %v", err)
+ c.Fatalf("failed to close tar archive: %v", err)
}
xzCompressCmd := exec.Command("xz", "-k", "test.tar")
xzCompressCmd.Dir = tmpDir
out, _, err := runCommandWithOutput(xzCompressCmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
gzipCompressCmd := exec.Command("gzip", "test.tar.xz")
gzipCompressCmd.Dir = tmpDir
out, _, err = runCommandWithOutput(gzipCompressCmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
- t.Fatalf("failed to open destination dockerfile: %v", err)
+ c.Fatalf("failed to open destination dockerfile: %v", err)
}
return fakeContextFromDir(tmpDir)
}()
@@ -4324,15 +4086,13 @@ func TestBuildAddTarXzGz(t *testing.T) {
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err)
+ c.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err)
}
- logDone("build - ADD tar.xz.gz")
}
-func TestBuildFromGIT(t *testing.T) {
+func (s *DockerSuite) TestBuildFromGIT(c *check.C) {
name := "testbuildfromgit"
- defer deleteImages(name)
git, err := fakeGIT("repo", map[string]string{
"Dockerfile": `FROM busybox
ADD first /first
@@ -4341,321 +4101,290 @@ func TestBuildFromGIT(t *testing.T) {
"first": "test git data",
}, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer git.Close()
_, err = buildImageFromPath(name, git.RepoURL, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectField(name, "Author")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != "docker" {
- t.Fatalf("Maintainer should be docker, got %s", res)
+ c.Fatalf("Maintainer should be docker, got %s", res)
}
- logDone("build - build from GIT")
}
-func TestBuildCleanupCmdOnEntrypoint(t *testing.T) {
+func (s *DockerSuite) TestBuildCleanupCmdOnEntrypoint(c *check.C) {
name := "testbuildcmdcleanuponentrypoint"
- defer deleteImages(name)
if _, err := buildImage(name,
`FROM scratch
CMD ["test"]
ENTRYPOINT ["echo"]`,
true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := buildImage(name,
fmt.Sprintf(`FROM %s
ENTRYPOINT ["cat"]`, name),
true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectField(name, "Config.Cmd")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- if expected := ""; res != expected {
- t.Fatalf("Cmd %s, expected %s", res, expected)
+ if res != "" {
+ c.Fatalf("Cmd %s, expected nil", res)
}
+
res, err = inspectField(name, "Config.Entrypoint")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- if expected := "[cat]"; res != expected {
- t.Fatalf("Entrypoint %s, expected %s", res, expected)
+ if expected := "{[cat]}"; res != expected {
+ c.Fatalf("Entrypoint %s, expected %s", res, expected)
}
- logDone("build - cleanup cmd on ENTRYPOINT")
}
-func TestBuildClearCmd(t *testing.T) {
+func (s *DockerSuite) TestBuildClearCmd(c *check.C) {
name := "testbuildclearcmd"
- defer deleteImages(name)
_, err := buildImage(name,
`From scratch
ENTRYPOINT ["/bin/bash"]
CMD []`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectFieldJSON(name, "Config.Cmd")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != "[]" {
- t.Fatalf("Cmd %s, expected %s", res, "[]")
+ c.Fatalf("Cmd %s, expected %s", res, "[]")
}
- logDone("build - clearcmd")
}
-func TestBuildEmptyCmd(t *testing.T) {
+func (s *DockerSuite) TestBuildEmptyCmd(c *check.C) {
name := "testbuildemptycmd"
- defer deleteImages(name)
if _, err := buildImage(name, "FROM scratch\nMAINTAINER quux\n", true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectFieldJSON(name, "Config.Cmd")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != "null" {
- t.Fatalf("Cmd %s, expected %s", res, "null")
+ c.Fatalf("Cmd %s, expected %s", res, "null")
}
- logDone("build - empty cmd")
}
-func TestBuildOnBuildOutput(t *testing.T) {
+func (s *DockerSuite) TestBuildOnBuildOutput(c *check.C) {
name := "testbuildonbuildparent"
- defer deleteImages(name)
if _, err := buildImage(name, "FROM busybox\nONBUILD RUN echo foo\n", true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- childname := "testbuildonbuildchild"
- defer deleteImages(childname)
-
_, out, err := buildImageWithOut(name, "FROM "+name+"\nMAINTAINER quux\n", true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !strings.Contains(out, "Trigger 0, RUN echo foo") {
- t.Fatal("failed to find the ONBUILD output", out)
+ c.Fatal("failed to find the ONBUILD output", out)
}
- logDone("build - onbuild output")
}
-func TestBuildInvalidTag(t *testing.T) {
+func (s *DockerSuite) TestBuildInvalidTag(c *check.C) {
name := "abcd:" + stringutils.GenerateRandomAlphaOnlyString(200)
- defer deleteImages(name)
_, out, err := buildImageWithOut(name, "FROM scratch\nMAINTAINER quux\n", true)
// if the error doesnt check for illegal tag name, or the image is built
// then this should fail
if !strings.Contains(out, "Illegal tag name") || strings.Contains(out, "Sending build context to Docker daemon") {
- t.Fatalf("failed to stop before building. Error: %s, Output: %s", err, out)
+ c.Fatalf("failed to stop before building. Error: %s, Output: %s", err, out)
}
- logDone("build - invalid tag")
}
-func TestBuildCmdShDashC(t *testing.T) {
+func (s *DockerSuite) TestBuildCmdShDashC(c *check.C) {
name := "testbuildcmdshc"
- defer deleteImages(name)
if _, err := buildImage(name, "FROM busybox\nCMD echo cmd\n", true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectFieldJSON(name, "Config.Cmd")
if err != nil {
- t.Fatal(err, res)
+ c.Fatal(err, res)
}
expected := `["/bin/sh","-c","echo cmd"]`
if res != expected {
- t.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res)
+ c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res)
}
- logDone("build - cmd should have sh -c for non-json")
}
-func TestBuildCmdSpaces(t *testing.T) {
+func (s *DockerSuite) TestBuildCmdSpaces(c *check.C) {
// Test to make sure that when we strcat arrays we take into account
// the arg separator to make sure ["echo","hi"] and ["echo hi"] don't
// look the same
name := "testbuildcmdspaces"
- defer deleteImages(name)
var id1 string
var id2 string
var err error
if id1, err = buildImage(name, "FROM busybox\nCMD [\"echo hi\"]\n", true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id2, err = buildImage(name, "FROM busybox\nCMD [\"echo\", \"hi\"]\n", true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 == id2 {
- t.Fatal("Should not have resulted in the same CMD")
+ c.Fatal("Should not have resulted in the same CMD")
}
// Now do the same with ENTRYPOINT
if id1, err = buildImage(name, "FROM busybox\nENTRYPOINT [\"echo hi\"]\n", true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id2, err = buildImage(name, "FROM busybox\nENTRYPOINT [\"echo\", \"hi\"]\n", true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if id1 == id2 {
- t.Fatal("Should not have resulted in the same ENTRYPOINT")
+ c.Fatal("Should not have resulted in the same ENTRYPOINT")
}
- logDone("build - cmd with spaces")
}
-func TestBuildCmdJSONNoShDashC(t *testing.T) {
+func (s *DockerSuite) TestBuildCmdJSONNoShDashC(c *check.C) {
name := "testbuildcmdjson"
- defer deleteImages(name)
if _, err := buildImage(name, "FROM busybox\nCMD [\"echo\", \"cmd\"]", true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectFieldJSON(name, "Config.Cmd")
if err != nil {
- t.Fatal(err, res)
+ c.Fatal(err, res)
}
expected := `["echo","cmd"]`
if res != expected {
- t.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res)
+ c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res)
}
- logDone("build - cmd should not have /bin/sh -c for json")
}
-func TestBuildErrorInvalidInstruction(t *testing.T) {
+func (s *DockerSuite) TestBuildErrorInvalidInstruction(c *check.C) {
name := "testbuildignoreinvalidinstruction"
- defer deleteImages(name)
out, _, err := buildImageWithOut(name, "FROM busybox\nfoo bar", true)
if err == nil {
- t.Fatalf("Should have failed: %s", out)
+ c.Fatalf("Should have failed: %s", out)
}
- logDone("build - error invalid Dockerfile instruction")
}
-func TestBuildEntrypointInheritance(t *testing.T) {
- defer deleteImages("parent", "child")
- defer deleteAllContainers()
+func (s *DockerSuite) TestBuildEntrypointInheritance(c *check.C) {
if _, err := buildImage("parent", `
FROM busybox
ENTRYPOINT exit 130
`, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
status, _ := runCommand(exec.Command(dockerBinary, "run", "parent"))
if status != 130 {
- t.Fatalf("expected exit code 130 but received %d", status)
+ c.Fatalf("expected exit code 130 but received %d", status)
}
if _, err := buildImage("child", `
FROM parent
ENTRYPOINT exit 5
`, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
status, _ = runCommand(exec.Command(dockerBinary, "run", "child"))
if status != 5 {
- t.Fatalf("expected exit code 5 but received %d", status)
+ c.Fatalf("expected exit code 5 but received %d", status)
}
- logDone("build - clear entrypoint")
}
-func TestBuildEntrypointInheritanceInspect(t *testing.T) {
+func (s *DockerSuite) TestBuildEntrypointInheritanceInspect(c *check.C) {
var (
name = "testbuildepinherit"
name2 = "testbuildepinherit2"
expected = `["/bin/sh","-c","echo quux"]`
)
- defer deleteImages(name, name2)
- defer deleteAllContainers()
-
if _, err := buildImage(name, "FROM busybox\nENTRYPOINT /foo/bar", true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := buildImage(name2, fmt.Sprintf("FROM %s\nENTRYPOINT echo quux", name), true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectFieldJSON(name2, "Config.Entrypoint")
if err != nil {
- t.Fatal(err, res)
+ c.Fatal(err, res)
}
if res != expected {
- t.Fatalf("Expected value %s not in Config.Entrypoint: %s", expected, res)
+ c.Fatalf("Expected value %s not in Config.Entrypoint: %s", expected, res)
}
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-t", name2))
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
expected = "quux"
if strings.TrimSpace(out) != expected {
- t.Fatalf("Expected output is %s, got %s", expected, out)
+ c.Fatalf("Expected output is %s, got %s", expected, out)
}
- logDone("build - entrypoint override inheritance properly")
}
-func TestBuildRunShEntrypoint(t *testing.T) {
+func (s *DockerSuite) TestBuildRunShEntrypoint(c *check.C) {
name := "testbuildentrypoint"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM busybox
ENTRYPOINT /bin/echo`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name))
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
- logDone("build - entrypoint with /bin/echo running successfully")
}
-func TestBuildExoticShellInterpolation(t *testing.T) {
+func (s *DockerSuite) TestBuildExoticShellInterpolation(c *check.C) {
name := "testbuildexoticshellinterpolation"
- defer deleteImages(name)
_, err := buildImage(name, `
FROM busybox
-
+
ENV SOME_VAR a.b.c
RUN [ "$SOME_VAR" = 'a.b.c' ]
@@ -4673,21 +4402,18 @@ func TestBuildExoticShellInterpolation(t *testing.T) {
RUN [ "${SOME_UNSET_VAR:-${SOME_VAR:-d.e.f}}" = 'a.b.c' ]
`, false)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - exotic shell interpolation")
}
-func TestBuildVerifySingleQuoteFails(t *testing.T) {
+func (s *DockerSuite) TestBuildVerifySingleQuoteFails(c *check.C) {
// This testcase is supposed to generate an error because the
// JSON array we're passing in on the CMD uses single quotes instead
// of double quotes (per the JSON spec). This means we interpret it
// as a "string" insead of "JSON array" and pass it on to "sh -c" and
// it should barf on it.
name := "testbuildsinglequotefails"
- defer deleteImages(name)
- defer deleteAllContainers()
_, err := buildImage(name,
`FROM busybox
@@ -4696,15 +4422,13 @@ func TestBuildVerifySingleQuoteFails(t *testing.T) {
_, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name))
if err == nil {
- t.Fatal("The image was not supposed to be able to run")
+ c.Fatal("The image was not supposed to be able to run")
}
- logDone("build - verify single quotes break the build")
}
-func TestBuildVerboseOut(t *testing.T) {
+func (s *DockerSuite) TestBuildVerboseOut(c *check.C) {
name := "testbuildverboseout"
- defer deleteImages(name)
_, out, err := buildImageWithOut(name,
`FROM busybox
@@ -4712,87 +4436,81 @@ RUN echo 123`,
false)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !strings.Contains(out, "\n123\n") {
- t.Fatalf("Output should contain %q: %q", "123", out)
+ c.Fatalf("Output should contain %q: %q", "123", out)
}
- logDone("build - verbose output from commands")
}
-func TestBuildWithTabs(t *testing.T) {
+func (s *DockerSuite) TestBuildWithTabs(c *check.C) {
name := "testbuildwithtabs"
- defer deleteImages(name)
_, err := buildImage(name,
"FROM busybox\nRUN echo\tone\t\ttwo", true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectFieldJSON(name, "ContainerConfig.Cmd")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
expected1 := `["/bin/sh","-c","echo\tone\t\ttwo"]`
expected2 := `["/bin/sh","-c","echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates
if res != expected1 && res != expected2 {
- t.Fatalf("Missing tabs.\nGot: %s\nExp: %s or %s", res, expected1, expected2)
+ c.Fatalf("Missing tabs.\nGot: %s\nExp: %s or %s", res, expected1, expected2)
}
- logDone("build - with tabs")
}
-func TestBuildLabels(t *testing.T) {
+func (s *DockerSuite) TestBuildLabels(c *check.C) {
name := "testbuildlabel"
expected := `{"License":"GPL","Vendor":"Acme"}`
- defer deleteImages(name)
_, err := buildImage(name,
`FROM busybox
LABEL Vendor=Acme
LABEL License GPL`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
res, err := inspectFieldJSON(name, "Config.Labels")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != expected {
- t.Fatalf("Labels %s, expected %s", res, expected)
+ c.Fatalf("Labels %s, expected %s", res, expected)
}
- logDone("build - label")
}
-func TestBuildLabelsCache(t *testing.T) {
+func (s *DockerSuite) TestBuildLabelsCache(c *check.C) {
name := "testbuildlabelcache"
- defer deleteImages(name)
id1, err := buildImage(name,
`FROM busybox
LABEL Vendor=Acme`, false)
if err != nil {
- t.Fatalf("Build 1 should have worked: %v", err)
+ c.Fatalf("Build 1 should have worked: %v", err)
}
id2, err := buildImage(name,
`FROM busybox
LABEL Vendor=Acme`, true)
if err != nil || id1 != id2 {
- t.Fatalf("Build 2 should have worked & used cache(%s,%s): %v", id1, id2, err)
+ c.Fatalf("Build 2 should have worked & used cache(%s,%s): %v", id1, id2, err)
}
id2, err = buildImage(name,
`FROM busybox
LABEL Vendor=Acme1`, true)
if err != nil || id1 == id2 {
- t.Fatalf("Build 3 should have worked & NOT used cache(%s,%s): %v", id1, id2, err)
+ c.Fatalf("Build 3 should have worked & NOT used cache(%s,%s): %v", id1, id2, err)
}
id2, err = buildImage(name,
`FROM busybox
LABEL Vendor Acme`, true) // Note: " " and "=" should be same
if err != nil || id1 != id2 {
- t.Fatalf("Build 4 should have worked & used cache(%s,%s): %v", id1, id2, err)
+ c.Fatalf("Build 4 should have worked & used cache(%s,%s): %v", id1, id2, err)
}
// Now make sure the cache isn't used by mistake
@@ -4800,28 +4518,26 @@ func TestBuildLabelsCache(t *testing.T) {
`FROM busybox
LABEL f1=b1 f2=b2`, false)
if err != nil {
- t.Fatalf("Build 5 should have worked: %q", err)
+ c.Fatalf("Build 5 should have worked: %q", err)
}
id2, err = buildImage(name,
`FROM busybox
LABEL f1="b1 f2=b2"`, true)
if err != nil || id1 == id2 {
- t.Fatalf("Build 6 should have worked & NOT used the cache(%s,%s): %q", id1, id2, err)
+ c.Fatalf("Build 6 should have worked & NOT used the cache(%s,%s): %q", id1, id2, err)
}
- logDone("build - label cache")
}
-func TestBuildStderr(t *testing.T) {
+func (s *DockerSuite) TestBuildStderr(c *check.C) {
// This test just makes sure that no non-error output goes
// to stderr
name := "testbuildstderr"
- defer deleteImages(name)
_, _, stderr, err := buildImageWithStdoutStderr(name,
"FROM busybox\nRUN echo one", true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if runtime.GOOS == "windows" {
@@ -4829,22 +4545,20 @@ func TestBuildStderr(t *testing.T) {
lines := strings.Split(stderr, "\n")
for _, v := range lines {
if v != "" && !strings.Contains(v, "SECURITY WARNING:") {
- t.Fatalf("Stderr contains unexpected output line: %q", v)
+ c.Fatalf("Stderr contains unexpected output line: %q", v)
}
}
} else {
if stderr != "" {
- t.Fatalf("Stderr should have been empty, instead its: %q", stderr)
+ c.Fatalf("Stderr should have been empty, instead its: %q", stderr)
}
}
- logDone("build - testing stderr")
}
-func TestBuildChownSingleFile(t *testing.T) {
- testRequires(t, UnixCli) // test uses chown: not available on windows
+func (s *DockerSuite) TestBuildChownSingleFile(c *check.C) {
+ testRequires(c, UnixCli) // test uses chown: not available on windows
name := "testbuildchownsinglefile"
- defer deleteImages(name)
ctx, err := fakeContext(`
FROM busybox
@@ -4855,46 +4569,45 @@ RUN [ $(ls -l /test | awk '{print $3":"$4}') = 'root:root' ]
"test": "test",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if err := os.Chown(filepath.Join(ctx.Dir, "test"), 4242, 4242); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - change permission on single file")
}
-func TestBuildSymlinkBreakout(t *testing.T) {
+func (s *DockerSuite) TestBuildSymlinkBreakout(c *check.C) {
name := "testbuildsymlinkbreakout"
tmpdir, err := ioutil.TempDir("", name)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(tmpdir)
ctx := filepath.Join(tmpdir, "context")
if err := os.MkdirAll(ctx, 0755); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte(`
from busybox
add symlink.tar /
add inject /symlink/
`), 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
inject := filepath.Join(ctx, "inject")
if err := ioutil.WriteFile(inject, nil, 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
f, err := os.Create(filepath.Join(ctx, "symlink.tar"))
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
w := tar.NewWriter(f)
w.WriteHeader(&tar.Header{
@@ -4914,19 +4627,17 @@ func TestBuildSymlinkBreakout(t *testing.T) {
w.Close()
f.Close()
if _, err := buildImageFromContext(name, fakeContextFromDir(ctx), false); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := os.Lstat(filepath.Join(tmpdir, "inject")); err == nil {
- t.Fatal("symlink breakout - inject")
+ c.Fatal("symlink breakout - inject")
} else if !os.IsNotExist(err) {
- t.Fatalf("unexpected error: %v", err)
+ c.Fatalf("unexpected error: %v", err)
}
- logDone("build - symlink breakout")
}
-func TestBuildXZHost(t *testing.T) {
+func (s *DockerSuite) TestBuildXZHost(c *check.C) {
name := "testbuildxzhost"
- defer deleteImages(name)
ctx, err := fakeContext(`
FROM busybox
@@ -4942,23 +4653,21 @@ RUN [ ! -e /injected ]`,
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("build - xz host is being used")
}
-func TestBuildVolumesRetainContents(t *testing.T) {
+func (s *DockerSuite) TestBuildVolumesRetainContents(c *check.C) {
var (
name = "testbuildvolumescontent"
expected = "some text"
)
- defer deleteImages(name)
ctx, err := fakeContext(`
FROM busybox
COPY content /foo/file
@@ -4968,27 +4677,25 @@ CMD cat /foo/file`,
"content": expected,
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err := buildImageFromContext(name, ctx, false); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name))
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if out != expected {
- t.Fatalf("expected file contents for /foo/file to be %q but received %q", expected, out)
+ c.Fatalf("expected file contents for /foo/file to be %q but received %q", expected, out)
}
- logDone("build - volumes retain contents in build")
}
-func TestBuildRenamedDockerfile(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestBuildRenamedDockerfile(c *check.C) {
ctx, err := fakeContext(`FROM busybox
RUN echo from Dockerfile`,
@@ -5001,100 +4708,98 @@ func TestBuildRenamedDockerfile(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-t", "test1", ".")
+ out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".")
if err != nil {
- t.Fatalf("Failed to build: %s\n%s", out, err)
+ c.Fatalf("Failed to build: %s\n%s", out, err)
}
if !strings.Contains(out, "from Dockerfile") {
- t.Fatalf("test1 should have used Dockerfile, output:%s", out)
+ c.Fatalf("test1 should have used Dockerfile, output:%s", out)
}
- out, _, err = dockerCmdInDir(t, ctx.Dir, "build", "-f", filepath.Join("files", "Dockerfile"), "-t", "test2", ".")
+ out, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-f", filepath.Join("files", "Dockerfile"), "-t", "test2", ".")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !strings.Contains(out, "from files/Dockerfile") {
- t.Fatalf("test2 should have used files/Dockerfile, output:%s", out)
+ c.Fatalf("test2 should have used files/Dockerfile, output:%s", out)
}
- out, _, err = dockerCmdInDir(t, ctx.Dir, "build", fmt.Sprintf("--file=%s", filepath.Join("files", "dFile")), "-t", "test3", ".")
+ out, _, err = dockerCmdInDir(c, ctx.Dir, "build", fmt.Sprintf("--file=%s", filepath.Join("files", "dFile")), "-t", "test3", ".")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !strings.Contains(out, "from files/dFile") {
- t.Fatalf("test3 should have used files/dFile, output:%s", out)
+ c.Fatalf("test3 should have used files/dFile, output:%s", out)
}
- out, _, err = dockerCmdInDir(t, ctx.Dir, "build", "--file=dFile", "-t", "test4", ".")
+ out, _, err = dockerCmdInDir(c, ctx.Dir, "build", "--file=dFile", "-t", "test4", ".")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !strings.Contains(out, "from dFile") {
- t.Fatalf("test4 should have used dFile, output:%s", out)
+ c.Fatalf("test4 should have used dFile, output:%s", out)
}
dirWithNoDockerfile, _ := ioutil.TempDir(os.TempDir(), "test5")
nonDockerfileFile := filepath.Join(dirWithNoDockerfile, "notDockerfile")
if _, err = os.Create(nonDockerfileFile); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- out, _, err = dockerCmdInDir(t, ctx.Dir, "build", fmt.Sprintf("--file=%s", nonDockerfileFile), "-t", "test5", ".")
+ out, _, err = dockerCmdInDir(c, ctx.Dir, "build", fmt.Sprintf("--file=%s", nonDockerfileFile), "-t", "test5", ".")
if err == nil {
- t.Fatalf("test5 was supposed to fail to find passwd")
+ c.Fatalf("test5 was supposed to fail to find passwd")
}
if expected := fmt.Sprintf("The Dockerfile (%s) must be within the build context (.)", strings.Replace(nonDockerfileFile, `\`, `\\`, -1)); !strings.Contains(out, expected) {
- t.Fatalf("wrong error messsage:%v\nexpected to contain=%v", out, expected)
+ c.Fatalf("wrong error messsage:%v\nexpected to contain=%v", out, expected)
}
- out, _, err = dockerCmdInDir(t, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test6", "..")
+ out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test6", "..")
if err != nil {
- t.Fatalf("test6 failed: %s", err)
+ c.Fatalf("test6 failed: %s", err)
}
if !strings.Contains(out, "from Dockerfile") {
- t.Fatalf("test6 should have used root Dockerfile, output:%s", out)
+ c.Fatalf("test6 should have used root Dockerfile, output:%s", out)
}
- out, _, err = dockerCmdInDir(t, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join(ctx.Dir, "files", "Dockerfile"), "-t", "test7", "..")
+ out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join(ctx.Dir, "files", "Dockerfile"), "-t", "test7", "..")
if err != nil {
- t.Fatalf("test7 failed: %s", err)
+ c.Fatalf("test7 failed: %s", err)
}
if !strings.Contains(out, "from files/Dockerfile") {
- t.Fatalf("test7 should have used files Dockerfile, output:%s", out)
+ c.Fatalf("test7 should have used files Dockerfile, output:%s", out)
}
- out, _, err = dockerCmdInDir(t, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test8", ".")
+ out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test8", ".")
if err == nil || !strings.Contains(out, "must be within the build context") {
- t.Fatalf("test8 should have failed with Dockerfile out of context: %s", err)
+ c.Fatalf("test8 should have failed with Dockerfile out of context: %s", err)
}
tmpDir := os.TempDir()
- out, _, err = dockerCmdInDir(t, tmpDir, "build", "-t", "test9", ctx.Dir)
+ out, _, err = dockerCmdInDir(c, tmpDir, "build", "-t", "test9", ctx.Dir)
if err != nil {
- t.Fatalf("test9 - failed: %s", err)
+ c.Fatalf("test9 - failed: %s", err)
}
if !strings.Contains(out, "from Dockerfile") {
- t.Fatalf("test9 should have used root Dockerfile, output:%s", out)
+ c.Fatalf("test9 should have used root Dockerfile, output:%s", out)
}
- out, _, err = dockerCmdInDir(t, filepath.Join(ctx.Dir, "files"), "build", "-f", "dFile2", "-t", "test10", ".")
+ out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", "dFile2", "-t", "test10", ".")
if err != nil {
- t.Fatalf("test10 should have worked: %s", err)
+ c.Fatalf("test10 should have worked: %s", err)
}
if !strings.Contains(out, "from files/dFile2") {
- t.Fatalf("test10 should have used files/dFile2, output:%s", out)
+ c.Fatalf("test10 should have used files/dFile2, output:%s", out)
}
- logDone("build - rename dockerfile")
}
-func TestBuildFromMixedcaseDockerfile(t *testing.T) {
- testRequires(t, UnixCli) // Dockerfile overwrites dockerfile on windows
- defer deleteImages("test1")
+func (s *DockerSuite) TestBuildFromMixedcaseDockerfile(c *check.C) {
+ testRequires(c, UnixCli) // Dockerfile overwrites dockerfile on windows
ctx, err := fakeContext(`FROM busybox
RUN echo from dockerfile`,
@@ -5103,24 +4808,22 @@ func TestBuildFromMixedcaseDockerfile(t *testing.T) {
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-t", "test1", ".")
+ out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".")
if err != nil {
- t.Fatalf("Failed to build: %s\n%s", out, err)
+ c.Fatalf("Failed to build: %s\n%s", out, err)
}
if !strings.Contains(out, "from dockerfile") {
- t.Fatalf("Missing proper output: %s", out)
+ c.Fatalf("Missing proper output: %s", out)
}
- logDone("build - mixedcase Dockerfile")
}
-func TestBuildWithTwoDockerfiles(t *testing.T) {
- testRequires(t, UnixCli) // Dockerfile overwrites dockerfile on windows
- defer deleteImages("test1")
+func (s *DockerSuite) TestBuildWithTwoDockerfiles(c *check.C) {
+ testRequires(c, UnixCli) // Dockerfile overwrites dockerfile on windows
ctx, err := fakeContext(`FROM busybox
RUN echo from Dockerfile`,
@@ -5129,30 +4832,28 @@ RUN echo from Dockerfile`,
})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-t", "test1", ".")
+ out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".")
if err != nil {
- t.Fatalf("Failed to build: %s\n%s", out, err)
+ c.Fatalf("Failed to build: %s\n%s", out, err)
}
if !strings.Contains(out, "from Dockerfile") {
- t.Fatalf("Missing proper output: %s", out)
+ c.Fatalf("Missing proper output: %s", out)
}
- logDone("build - two Dockerfiles")
}
-func TestBuildFromURLWithF(t *testing.T) {
- defer deleteImages("test1")
+func (s *DockerSuite) TestBuildFromURLWithF(c *check.C) {
server, err := fakeStorage(map[string]string{"baz": `FROM busybox
RUN echo from baz
COPY * /tmp/
RUN find /tmp/`})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer server.Close()
@@ -5161,34 +4862,32 @@ RUN echo from Dockerfile`,
map[string]string{})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// Make sure that -f is ignored and that we don't use the Dockerfile
// that's in the current dir
- out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-f", "baz", "-t", "test1", server.URL()+"/baz")
+ out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-f", "baz", "-t", "test1", server.URL()+"/baz")
if err != nil {
- t.Fatalf("Failed to build: %s\n%s", out, err)
+ c.Fatalf("Failed to build: %s\n%s", out, err)
}
if !strings.Contains(out, "from baz") ||
strings.Contains(out, "/tmp/baz") ||
!strings.Contains(out, "/tmp/Dockerfile") {
- t.Fatalf("Missing proper output: %s", out)
+ c.Fatalf("Missing proper output: %s", out)
}
- logDone("build - from URL with -f")
}
-func TestBuildFromStdinWithF(t *testing.T) {
- defer deleteImages("test1")
+func (s *DockerSuite) TestBuildFromStdinWithF(c *check.C) {
ctx, err := fakeContext(`FROM busybox
RUN echo from Dockerfile`,
map[string]string{})
defer ctx.Close()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// Make sure that -f is ignored and that we don't use the Dockerfile
@@ -5201,19 +4900,18 @@ COPY * /tmp/
RUN find /tmp/`)
out, status, err := runCommandWithOutput(dockerCommand)
if err != nil || status != 0 {
- t.Fatalf("Error building: %s", err)
+ c.Fatalf("Error building: %s", err)
}
if !strings.Contains(out, "from baz") ||
strings.Contains(out, "/tmp/baz") ||
!strings.Contains(out, "/tmp/Dockerfile") {
- t.Fatalf("Missing proper output: %s", out)
+ c.Fatalf("Missing proper output: %s", out)
}
- logDone("build - from stdin with -f")
}
-func TestBuildFromOfficialNames(t *testing.T) {
+func (s *DockerSuite) TestBuildFromOfficialNames(c *check.C) {
name := "testbuildfromofficial"
fromNames := []string{
"busybox",
@@ -5227,45 +4925,44 @@ func TestBuildFromOfficialNames(t *testing.T) {
imgName := fmt.Sprintf("%s%d", name, idx)
_, err := buildImage(imgName, "FROM "+fromName, true)
if err != nil {
- t.Errorf("Build failed using FROM %s: %s", fromName, err)
+ c.Errorf("Build failed using FROM %s: %s", fromName, err)
}
deleteImages(imgName)
}
- logDone("build - from official names")
}
-func TestBuildDockerfileOutsideContext(t *testing.T) {
- testRequires(t, UnixCli) // uses os.Symlink: not implemented in windows at the time of writing (go-1.4.2)
+func (s *DockerSuite) TestBuildDockerfileOutsideContext(c *check.C) {
+ testRequires(c, UnixCli) // uses os.Symlink: not implemented in windows at the time of writing (go-1.4.2)
name := "testbuilddockerfileoutsidecontext"
tmpdir, err := ioutil.TempDir("", name)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(tmpdir)
ctx := filepath.Join(tmpdir, "context")
if err := os.MkdirAll(ctx, 0755); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte("FROM scratch\nENV X Y"), 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
wd, err := os.Getwd()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.Chdir(wd)
if err := os.Chdir(ctx); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err := ioutil.WriteFile(filepath.Join(tmpdir, "outsideDockerfile"), []byte("FROM scratch\nENV x y"), 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err := os.Symlink(filepath.Join("..", "outsideDockerfile"), filepath.Join(ctx, "dockerfile1")); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err := os.Symlink(filepath.Join(tmpdir, "outsideDockerfile"), filepath.Join(ctx, "dockerfile2")); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
for _, dockerfilePath := range []string{
@@ -5275,10 +4972,10 @@ func TestBuildDockerfileOutsideContext(t *testing.T) {
} {
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "build", "-t", name, "--no-cache", "-f", dockerfilePath, "."))
if err == nil {
- t.Fatalf("Expected error with %s. Out: %s", dockerfilePath, out)
+ c.Fatalf("Expected error with %s. Out: %s", dockerfilePath, out)
}
if !strings.Contains(out, "must be within the build context") && !strings.Contains(out, "Cannot locate Dockerfile") {
- t.Fatalf("Unexpected error with %s. Out: %s", dockerfilePath, out)
+ c.Fatalf("Unexpected error with %s. Out: %s", dockerfilePath, out)
}
deleteImages(name)
}
@@ -5289,14 +4986,11 @@ func TestBuildDockerfileOutsideContext(t *testing.T) {
// There is a Dockerfile in the context, but since there is no Dockerfile in the current directory, the following should fail
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "build", "-t", name, "--no-cache", "-f", "Dockerfile", ctx))
if err == nil {
- t.Fatalf("Expected error. Out: %s", out)
+ c.Fatalf("Expected error. Out: %s", out)
}
- deleteImages(name)
-
- logDone("build - Dockerfile outside context")
}
-func TestBuildSpaces(t *testing.T) {
+func (s *DockerSuite) TestBuildSpaces(c *check.C) {
// Test to make sure that leading/trailing spaces on a command
// doesn't change the error msg we get
var (
@@ -5305,23 +4999,22 @@ func TestBuildSpaces(t *testing.T) {
)
name := "testspaces"
- defer deleteImages(name)
ctx, err := fakeContext("FROM busybox\nCOPY\n",
map[string]string{
"Dockerfile": "FROM busybox\nCOPY\n",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err1 = buildImageFromContext(name, ctx, false); err1 == nil {
- t.Fatal("Build 1 was supposed to fail, but didn't")
+ c.Fatal("Build 1 was supposed to fail, but didn't")
}
ctx.Add("Dockerfile", "FROM busybox\nCOPY ")
if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil {
- t.Fatal("Build 2 was supposed to fail, but didn't")
+ c.Fatal("Build 2 was supposed to fail, but didn't")
}
removeLogTimestamps := func(s string) string {
@@ -5334,12 +5027,12 @@ func TestBuildSpaces(t *testing.T) {
// Ignore whitespace since that's what were verifying doesn't change stuff
if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) {
- t.Fatalf("Build 2's error wasn't the same as build 1's\n1:%s\n2:%s", err1, err2)
+ c.Fatalf("Build 2's error wasn't the same as build 1's\n1:%s\n2:%s", err1, err2)
}
ctx.Add("Dockerfile", "FROM busybox\n COPY")
if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil {
- t.Fatal("Build 3 was supposed to fail, but didn't")
+ c.Fatal("Build 3 was supposed to fail, but didn't")
}
// Skip over the times
@@ -5348,12 +5041,12 @@ func TestBuildSpaces(t *testing.T) {
// Ignore whitespace since that's what were verifying doesn't change stuff
if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) {
- t.Fatalf("Build 3's error wasn't the same as build 1's\n1:%s\n3:%s", err1, err2)
+ c.Fatalf("Build 3's error wasn't the same as build 1's\n1:%s\n3:%s", err1, err2)
}
ctx.Add("Dockerfile", "FROM busybox\n COPY ")
if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil {
- t.Fatal("Build 4 was supposed to fail, but didn't")
+ c.Fatal("Build 4 was supposed to fail, but didn't")
}
// Skip over the times
@@ -5362,16 +5055,14 @@ func TestBuildSpaces(t *testing.T) {
// Ignore whitespace since that's what were verifying doesn't change stuff
if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) {
- t.Fatalf("Build 4's error wasn't the same as build 1's\n1:%s\n4:%s", err1, err2)
+ c.Fatalf("Build 4's error wasn't the same as build 1's\n1:%s\n4:%s", err1, err2)
}
- logDone("build - test spaces")
}
-func TestBuildSpacesWithQuotes(t *testing.T) {
+func (s *DockerSuite) TestBuildSpacesWithQuotes(c *check.C) {
// Test to make sure that spaces in quotes aren't lost
name := "testspacesquotes"
- defer deleteImages(name)
dockerfile := `FROM busybox
RUN echo " \
@@ -5379,19 +5070,18 @@ RUN echo " \
_, out, err := buildImageWithOut(name, dockerfile, false)
if err != nil {
- t.Fatal("Build failed:", err)
+ c.Fatal("Build failed:", err)
}
expecting := "\n foo \n"
if !strings.Contains(out, expecting) {
- t.Fatalf("Bad output: %q expecting to contian %q", out, expecting)
+ c.Fatalf("Bad output: %q expecting to contain %q", out, expecting)
}
- logDone("build - test spaces with quotes")
}
// #4393
-func TestBuildVolumeFileExistsinContainer(t *testing.T) {
+func (s *DockerSuite) TestBuildVolumeFileExistsinContainer(c *check.C) {
buildCmd := exec.Command(dockerBinary, "build", "-t", "docker-test-errcreatevolumewithfile", "-")
buildCmd.Stdin = strings.NewReader(`
FROM busybox
@@ -5401,13 +5091,12 @@ func TestBuildVolumeFileExistsinContainer(t *testing.T) {
out, _, err := runCommandWithOutput(buildCmd)
if err == nil || !strings.Contains(out, "file exists") {
- t.Fatalf("expected build to fail when file exists in container at requested volume path")
+ c.Fatalf("expected build to fail when file exists in container at requested volume path")
}
- logDone("build - errors when volume is specified where a file exists")
}
-func TestBuildMissingArgs(t *testing.T) {
+func (s *DockerSuite) TestBuildMissingArgs(c *check.C) {
// Test to make sure that all Dockerfile commands (except the ones listed
// in skipCmds) will generate an error if no args are provided.
// Note: INSERT is deprecated so we exclude it because of that.
@@ -5418,8 +5107,6 @@ func TestBuildMissingArgs(t *testing.T) {
"INSERT": {},
}
- defer deleteAllContainers()
-
for cmd := range command.Commands {
cmd = strings.ToUpper(cmd)
if _, ok := skipCmds[cmd]; ok {
@@ -5436,57 +5123,50 @@ func TestBuildMissingArgs(t *testing.T) {
ctx, err := fakeContext(dockerfile, map[string]string{})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
var out string
if out, err = buildImageFromContext("args", ctx, true); err == nil {
- t.Fatalf("%s was supposed to fail. Out:%s", cmd, out)
+ c.Fatalf("%s was supposed to fail. Out:%s", cmd, out)
}
if !strings.Contains(err.Error(), cmd+" requires") {
- t.Fatalf("%s returned the wrong type of error:%s", cmd, err)
+ c.Fatalf("%s returned the wrong type of error:%s", cmd, err)
}
}
- logDone("build - verify missing args")
}
-func TestBuildEmptyScratch(t *testing.T) {
- defer deleteImages("sc")
+func (s *DockerSuite) TestBuildEmptyScratch(c *check.C) {
_, out, err := buildImageWithOut("sc", "FROM scratch", true)
if err == nil {
- t.Fatalf("Build was supposed to fail")
+ c.Fatalf("Build was supposed to fail")
}
if !strings.Contains(out, "No image was generated") {
- t.Fatalf("Wrong error message: %v", out)
+ c.Fatalf("Wrong error message: %v", out)
}
- logDone("build - empty scratch Dockerfile")
}
-func TestBuildDotDotFile(t *testing.T) {
- defer deleteImages("sc")
+func (s *DockerSuite) TestBuildDotDotFile(c *check.C) {
ctx, err := fakeContext("FROM busybox\n",
map[string]string{
"..gitme": "",
})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
if _, err = buildImageFromContext("sc", ctx, false); err != nil {
- t.Fatalf("Build was supposed to work: %s", err)
+ c.Fatalf("Build was supposed to work: %s", err)
}
- logDone("build - ..file")
}
-func TestBuildNotVerbose(t *testing.T) {
- defer deleteAllContainers()
- defer deleteImages("verbose")
+func (s *DockerSuite) TestBuildNotVerbose(c *check.C) {
ctx, err := fakeContext("FROM busybox\nENV abc=hi\nRUN echo $abc there", map[string]string{})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
@@ -5495,10 +5175,10 @@ func TestBuildNotVerbose(t *testing.T) {
buildCmd.Dir = ctx.Dir
out, _, err := runCommandWithOutput(buildCmd)
if err != nil {
- t.Fatalf("failed to build the image w/o -q: %s, %v", out, err)
+ c.Fatalf("failed to build the image w/o -q: %s, %v", out, err)
}
if !strings.Contains(out, "hi there") {
- t.Fatalf("missing output:%s\n", out)
+ c.Fatalf("missing output:%s\n", out)
}
// Now do it w/o verbose
@@ -5506,25 +5186,21 @@ func TestBuildNotVerbose(t *testing.T) {
buildCmd.Dir = ctx.Dir
out, _, err = runCommandWithOutput(buildCmd)
if err != nil {
- t.Fatalf("failed to build the image w/ -q: %s, %v", out, err)
+ c.Fatalf("failed to build the image w/ -q: %s, %v", out, err)
}
if strings.Contains(out, "hi there") {
- t.Fatalf("Bad output, should not contain 'hi there':%s", out)
+ c.Fatalf("Bad output, should not contain 'hi there':%s", out)
}
- logDone("build - not verbose")
}
-func TestBuildRUNoneJSON(t *testing.T) {
+func (s *DockerSuite) TestBuildRUNoneJSON(c *check.C) {
name := "testbuildrunonejson"
- defer deleteAllContainers()
- defer deleteImages(name, "hello-world")
-
ctx, err := fakeContext(`FROM hello-world:frozen
RUN [ "/hello" ]`, map[string]string{})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer ctx.Close()
@@ -5532,90 +5208,80 @@ RUN [ "/hello" ]`, map[string]string{})
buildCmd.Dir = ctx.Dir
out, _, err := runCommandWithOutput(buildCmd)
if err != nil {
- t.Fatalf("failed to build the image: %s, %v", out, err)
+ c.Fatalf("failed to build the image: %s, %v", out, err)
}
if !strings.Contains(out, "Hello from Docker") {
- t.Fatalf("bad output: %s", out)
+ c.Fatalf("bad output: %s", out)
}
- logDone("build - RUN with one JSON arg")
}
-func TestBuildResourceConstraintsAreUsed(t *testing.T) {
+func (s *DockerSuite) TestBuildResourceConstraintsAreUsed(c *check.C) {
name := "testbuildresourceconstraints"
- defer deleteAllContainers()
- defer deleteImages(name, "hello-world")
ctx, err := fakeContext(`
FROM hello-world:frozen
RUN ["/hello"]
`, map[string]string{})
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- cmd := exec.Command(dockerBinary, "build", "--rm=false", "--memory=64m", "--memory-swap=-1", "--cpuset-cpus=0", "--cpu-shares=100", "-t", name, ".")
+ cmd := exec.Command(dockerBinary, "build", "--no-cache", "--rm=false", "--memory=64m", "--memory-swap=-1", "--cpuset-cpus=0", "--cpuset-mems=0", "--cpu-shares=100", "--cpu-quota=8000", "-t", name, ".")
cmd.Dir = ctx.Dir
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
- }
- out, _, err = dockerCmd(t, "ps", "-lq")
- if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
+ out, _ = dockerCmd(c, "ps", "-lq")
cID := strings.TrimSpace(out)
type hostConfig struct {
- Memory float64 // Use float64 here since the json decoder sees it that way
- MemorySwap int
+ Memory int64
+ MemorySwap int64
CpusetCpus string
- CpuShares int
+ CpusetMems string
+ CpuShares int64
+ CpuQuota int64
}
cfg, err := inspectFieldJSON(cID, "HostConfig")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
var c1 hostConfig
if err := json.Unmarshal([]byte(cfg), &c1); err != nil {
- t.Fatal(err, cfg)
+ c.Fatal(err, cfg)
}
- mem := int64(c1.Memory)
- if mem != 67108864 || c1.MemorySwap != -1 || c1.CpusetCpus != "0" || c1.CpuShares != 100 {
- t.Fatalf("resource constraints not set properly:\nMemory: %d, MemSwap: %d, CpusetCpus: %s, CpuShares: %d",
- mem, c1.MemorySwap, c1.CpusetCpus, c1.CpuShares)
+ if c1.Memory != 67108864 || c1.MemorySwap != -1 || c1.CpusetCpus != "0" || c1.CpusetMems != "0" || c1.CpuShares != 100 || c1.CpuQuota != 8000 {
+ c.Fatalf("resource constraints not set properly:\nMemory: %d, MemSwap: %d, CpusetCpus: %s, CpusetMems: %s, CpuShares: %d, CpuQuota: %d",
+ c1.Memory, c1.MemorySwap, c1.CpusetCpus, c1.CpusetMems, c1.CpuShares, c1.CpuQuota)
}
// Make sure constraints aren't saved to image
- _, _, err = dockerCmd(t, "run", "--name=test", name)
- if err != nil {
- t.Fatal(err)
- }
+ _, _ = dockerCmd(c, "run", "--name=test", name)
+
cfg, err = inspectFieldJSON("test", "HostConfig")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
var c2 hostConfig
if err := json.Unmarshal([]byte(cfg), &c2); err != nil {
- t.Fatal(err, cfg)
+ c.Fatal(err, cfg)
}
- mem = int64(c2.Memory)
- if mem == 67108864 || c2.MemorySwap == -1 || c2.CpusetCpus == "0" || c2.CpuShares == 100 {
- t.Fatalf("resource constraints leaked from build:\nMemory: %d, MemSwap: %d, CpusetCpus: %s, CpuShares: %d",
- mem, c2.MemorySwap, c2.CpusetCpus, c2.CpuShares)
+ if c2.Memory == 67108864 || c2.MemorySwap == -1 || c2.CpusetCpus == "0" || c2.CpusetMems == "0" || c2.CpuShares == 100 || c2.CpuQuota == 8000 {
+ c.Fatalf("resource constraints leaked from build:\nMemory: %d, MemSwap: %d, CpusetCpus: %s, CpusetMems: %s, CpuShares: %d, CpuQuota: %d",
+ c2.Memory, c2.MemorySwap, c2.CpusetCpus, c2.CpusetMems, c2.CpuShares, c2.CpuQuota)
}
- logDone("build - resource constraints applied")
}
-func TestBuildEmptyStringVolume(t *testing.T) {
+func (s *DockerSuite) TestBuildEmptyStringVolume(c *check.C) {
name := "testbuildemptystringvolume"
- defer deleteImages(name)
_, err := buildImage(name, `
FROM busybox
@@ -5623,8 +5289,7 @@ func TestBuildEmptyStringVolume(t *testing.T) {
VOLUME $foo
`, false)
if err == nil {
- t.Fatal("Should have failed to build")
+ c.Fatal("Should have failed to build")
}
- logDone("build - empty string volume")
}
diff --git a/integration-cli/docker_cli_by_digest_test.go b/integration-cli/docker_cli_by_digest_test.go
index 24ebf0cf70b7c..b9b319cf94a41 100644
--- a/integration-cli/docker_cli_by_digest_test.go
+++ b/integration-cli/docker_cli_by_digest_test.go
@@ -5,9 +5,9 @@ import (
"os/exec"
"regexp"
"strings"
- "testing"
"github.com/docker/docker/utils"
+ "github.com/go-check/check"
)
var (
@@ -22,18 +22,17 @@ func setupImage() (string, error) {
func setupImageWithTag(tag string) (string, error) {
containerName := "busyboxbydigest"
- c := exec.Command(dockerBinary, "run", "-d", "-e", "digest=1", "--name", containerName, "busybox")
- if _, err := runCommand(c); err != nil {
+ cmd := exec.Command(dockerBinary, "run", "-d", "-e", "digest=1", "--name", containerName, "busybox")
+ if _, err := runCommand(cmd); err != nil {
return "", err
}
// tag the image to upload it to the private registry
repoAndTag := utils.ImageReference(repoName, tag)
- c = exec.Command(dockerBinary, "commit", containerName, repoAndTag)
- if out, _, err := runCommandWithOutput(c); err != nil {
+ cmd = exec.Command(dockerBinary, "commit", containerName, repoAndTag)
+ if out, _, err := runCommandWithOutput(cmd); err != nil {
return "", fmt.Errorf("image tagging failed: %s, %v", out, err)
}
- defer deleteImages(repoAndTag)
// delete the container as we don't need it any more
if err := deleteContainer(containerName); err != nil {
@@ -41,15 +40,15 @@ func setupImageWithTag(tag string) (string, error) {
}
// push the image
- c = exec.Command(dockerBinary, "push", repoAndTag)
- out, _, err := runCommandWithOutput(c)
+ cmd = exec.Command(dockerBinary, "push", repoAndTag)
+ out, _, err := runCommandWithOutput(cmd)
if err != nil {
return "", fmt.Errorf("pushing the image to the private registry has failed: %s, %v", out, err)
}
// delete our local repo that we previously tagged
- c = exec.Command(dockerBinary, "rmi", repoAndTag)
- if out, _, err := runCommandWithOutput(c); err != nil {
+ cmd = exec.Command(dockerBinary, "rmi", repoAndTag)
+ if out, _, err := runCommandWithOutput(cmd); err != nil {
return "", fmt.Errorf("error deleting images prior to real test: %s, %v", out, err)
}
@@ -63,473 +62,426 @@ func setupImageWithTag(tag string) (string, error) {
return pushDigest, nil
}
-func TestPullByTagDisplaysDigest(t *testing.T) {
- defer setupRegistry(t)()
-
+func (s *DockerRegistrySuite) TestPullByTagDisplaysDigest(c *check.C) {
pushDigest, err := setupImage()
if err != nil {
- t.Fatalf("error setting up image: %v", err)
+ c.Fatalf("error setting up image: %v", err)
}
// pull from the registry using the tag
- c := exec.Command(dockerBinary, "pull", repoName)
- out, _, err := runCommandWithOutput(c)
+ cmd := exec.Command(dockerBinary, "pull", repoName)
+ out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error pulling by tag: %s, %v", out, err)
+ c.Fatalf("error pulling by tag: %s, %v", out, err)
}
- defer deleteImages(repoName)
// the pull output includes "Digest: ", so find that
matches := digestRegex.FindStringSubmatch(out)
if len(matches) != 2 {
- t.Fatalf("unable to parse digest from pull output: %s", out)
+ c.Fatalf("unable to parse digest from pull output: %s", out)
}
pullDigest := matches[1]
// make sure the pushed and pull digests match
if pushDigest != pullDigest {
- t.Fatalf("push digest %q didn't match pull digest %q", pushDigest, pullDigest)
+ c.Fatalf("push digest %q didn't match pull digest %q", pushDigest, pullDigest)
}
-
- logDone("by_digest - pull by tag displays digest")
}
-func TestPullByDigest(t *testing.T) {
- defer setupRegistry(t)()
-
+func (s *DockerRegistrySuite) TestPullByDigest(c *check.C) {
pushDigest, err := setupImage()
if err != nil {
- t.Fatalf("error setting up image: %v", err)
+ c.Fatalf("error setting up image: %v", err)
}
// pull from the registry using the @ reference
imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest)
- c := exec.Command(dockerBinary, "pull", imageReference)
- out, _, err := runCommandWithOutput(c)
+ cmd := exec.Command(dockerBinary, "pull", imageReference)
+ out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error pulling by digest: %s, %v", out, err)
+ c.Fatalf("error pulling by digest: %s, %v", out, err)
}
- defer deleteImages(imageReference)
// the pull output includes "Digest: ", so find that
matches := digestRegex.FindStringSubmatch(out)
if len(matches) != 2 {
- t.Fatalf("unable to parse digest from pull output: %s", out)
+ c.Fatalf("unable to parse digest from pull output: %s", out)
}
pullDigest := matches[1]
// make sure the pushed and pull digests match
if pushDigest != pullDigest {
- t.Fatalf("push digest %q didn't match pull digest %q", pushDigest, pullDigest)
+ c.Fatalf("push digest %q didn't match pull digest %q", pushDigest, pullDigest)
}
-
- logDone("by_digest - pull by digest")
}
-func TestCreateByDigest(t *testing.T) {
- defer setupRegistry(t)()
-
+func (s *DockerRegistrySuite) TestCreateByDigest(c *check.C) {
pushDigest, err := setupImage()
if err != nil {
- t.Fatalf("error setting up image: %v", err)
+ c.Fatalf("error setting up image: %v", err)
}
imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest)
containerName := "createByDigest"
- c := exec.Command(dockerBinary, "create", "--name", containerName, imageReference)
- out, _, err := runCommandWithOutput(c)
+ cmd := exec.Command(dockerBinary, "create", "--name", containerName, imageReference)
+ out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error creating by digest: %s, %v", out, err)
+ c.Fatalf("error creating by digest: %s, %v", out, err)
}
- defer deleteContainer(containerName)
res, err := inspectField(containerName, "Config.Image")
if err != nil {
- t.Fatalf("failed to get Config.Image: %s, %v", out, err)
+ c.Fatalf("failed to get Config.Image: %s, %v", out, err)
}
if res != imageReference {
- t.Fatalf("unexpected Config.Image: %s (expected %s)", res, imageReference)
+ c.Fatalf("unexpected Config.Image: %s (expected %s)", res, imageReference)
}
-
- logDone("by_digest - create by digest")
}
-func TestRunByDigest(t *testing.T) {
- defer setupRegistry(t)()
-
+func (s *DockerRegistrySuite) TestRunByDigest(c *check.C) {
pushDigest, err := setupImage()
if err != nil {
- t.Fatalf("error setting up image: %v", err)
+ c.Fatalf("error setting up image: %v", err)
}
imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest)
containerName := "runByDigest"
- c := exec.Command(dockerBinary, "run", "--name", containerName, imageReference, "sh", "-c", "echo found=$digest")
- out, _, err := runCommandWithOutput(c)
+ cmd := exec.Command(dockerBinary, "run", "--name", containerName, imageReference, "sh", "-c", "echo found=$digest")
+ out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error run by digest: %s, %v", out, err)
+ c.Fatalf("error run by digest: %s, %v", out, err)
}
- defer deleteContainer(containerName)
foundRegex := regexp.MustCompile("found=([^\n]+)")
matches := foundRegex.FindStringSubmatch(out)
if len(matches) != 2 {
- t.Fatalf("error locating expected 'found=1' output: %s", out)
+ c.Fatalf("error locating expected 'found=1' output: %s", out)
}
if matches[1] != "1" {
- t.Fatalf("Expected %q, got %q", "1", matches[1])
+ c.Fatalf("Expected %q, got %q", "1", matches[1])
}
res, err := inspectField(containerName, "Config.Image")
if err != nil {
- t.Fatalf("failed to get Config.Image: %s, %v", out, err)
+ c.Fatalf("failed to get Config.Image: %s, %v", out, err)
}
if res != imageReference {
- t.Fatalf("unexpected Config.Image: %s (expected %s)", res, imageReference)
+ c.Fatalf("unexpected Config.Image: %s (expected %s)", res, imageReference)
}
-
- logDone("by_digest - run by digest")
}
-func TestRemoveImageByDigest(t *testing.T) {
- defer setupRegistry(t)()
-
+func (s *DockerRegistrySuite) TestRemoveImageByDigest(c *check.C) {
digest, err := setupImage()
if err != nil {
- t.Fatalf("error setting up image: %v", err)
+ c.Fatalf("error setting up image: %v", err)
}
imageReference := fmt.Sprintf("%s@%s", repoName, digest)
// pull from the registry using the @ reference
- c := exec.Command(dockerBinary, "pull", imageReference)
- out, _, err := runCommandWithOutput(c)
+ cmd := exec.Command(dockerBinary, "pull", imageReference)
+ out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error pulling by digest: %s, %v", out, err)
+ c.Fatalf("error pulling by digest: %s, %v", out, err)
}
// make sure inspect runs ok
if _, err := inspectField(imageReference, "Id"); err != nil {
- t.Fatalf("failed to inspect image: %v", err)
+ c.Fatalf("failed to inspect image: %v", err)
}
// do the delete
if err := deleteImages(imageReference); err != nil {
- t.Fatalf("unexpected error deleting image: %v", err)
+ c.Fatalf("unexpected error deleting image: %v", err)
}
// try to inspect again - it should error this time
if _, err := inspectField(imageReference, "Id"); err == nil {
- t.Fatalf("unexpected nil err trying to inspect what should be a non-existent image")
+ c.Fatalf("unexpected nil err trying to inspect what should be a non-existent image")
} else if !strings.Contains(err.Error(), "No such image") {
- t.Fatalf("expected 'No such image' output, got %v", err)
+ c.Fatalf("expected 'No such image' output, got %v", err)
}
-
- logDone("by_digest - remove image by digest")
}
-func TestBuildByDigest(t *testing.T) {
- defer setupRegistry(t)()
-
+func (s *DockerRegistrySuite) TestBuildByDigest(c *check.C) {
digest, err := setupImage()
if err != nil {
- t.Fatalf("error setting up image: %v", err)
+ c.Fatalf("error setting up image: %v", err)
}
imageReference := fmt.Sprintf("%s@%s", repoName, digest)
// pull from the registry using the @ reference
- c := exec.Command(dockerBinary, "pull", imageReference)
- out, _, err := runCommandWithOutput(c)
+ cmd := exec.Command(dockerBinary, "pull", imageReference)
+ out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error pulling by digest: %s, %v", out, err)
+ c.Fatalf("error pulling by digest: %s, %v", out, err)
}
// get the image id
imageID, err := inspectField(imageReference, "Id")
if err != nil {
- t.Fatalf("error getting image id: %v", err)
+ c.Fatalf("error getting image id: %v", err)
}
// do the build
name := "buildbydigest"
- defer deleteImages(name)
_, err = buildImage(name, fmt.Sprintf(
`FROM %s
CMD ["/bin/echo", "Hello World"]`, imageReference),
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// get the build's image id
res, err := inspectField(name, "Config.Image")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// make sure they match
if res != imageID {
- t.Fatalf("Image %s, expected %s", res, imageID)
+ c.Fatalf("Image %s, expected %s", res, imageID)
}
-
- logDone("by_digest - build by digest")
}
-func TestTagByDigest(t *testing.T) {
- defer setupRegistry(t)()
-
+func (s *DockerRegistrySuite) TestTagByDigest(c *check.C) {
digest, err := setupImage()
if err != nil {
- t.Fatalf("error setting up image: %v", err)
+ c.Fatalf("error setting up image: %v", err)
}
imageReference := fmt.Sprintf("%s@%s", repoName, digest)
// pull from the registry using the @ reference
- c := exec.Command(dockerBinary, "pull", imageReference)
- out, _, err := runCommandWithOutput(c)
+ cmd := exec.Command(dockerBinary, "pull", imageReference)
+ out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error pulling by digest: %s, %v", out, err)
+ c.Fatalf("error pulling by digest: %s, %v", out, err)
}
// tag it
tag := "tagbydigest"
- c = exec.Command(dockerBinary, "tag", imageReference, tag)
- if _, err := runCommand(c); err != nil {
- t.Fatalf("unexpected error tagging: %v", err)
+ cmd = exec.Command(dockerBinary, "tag", imageReference, tag)
+ if _, err := runCommand(cmd); err != nil {
+ c.Fatalf("unexpected error tagging: %v", err)
}
expectedID, err := inspectField(imageReference, "Id")
if err != nil {
- t.Fatalf("error getting original image id: %v", err)
+ c.Fatalf("error getting original image id: %v", err)
}
tagID, err := inspectField(tag, "Id")
if err != nil {
- t.Fatalf("error getting tagged image id: %v", err)
+ c.Fatalf("error getting tagged image id: %v", err)
}
if tagID != expectedID {
- t.Fatalf("expected image id %q, got %q", expectedID, tagID)
+ c.Fatalf("expected image id %q, got %q", expectedID, tagID)
}
-
- logDone("by_digest - tag by digest")
}
-func TestListImagesWithoutDigests(t *testing.T) {
- defer setupRegistry(t)()
-
+func (s *DockerRegistrySuite) TestListImagesWithoutDigests(c *check.C) {
digest, err := setupImage()
if err != nil {
- t.Fatalf("error setting up image: %v", err)
+ c.Fatalf("error setting up image: %v", err)
}
imageReference := fmt.Sprintf("%s@%s", repoName, digest)
// pull from the registry using the @ reference
- c := exec.Command(dockerBinary, "pull", imageReference)
- out, _, err := runCommandWithOutput(c)
+ cmd := exec.Command(dockerBinary, "pull", imageReference)
+ out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error pulling by digest: %s, %v", out, err)
+ c.Fatalf("error pulling by digest: %s, %v", out, err)
}
- c = exec.Command(dockerBinary, "images")
- out, _, err = runCommandWithOutput(c)
+ cmd = exec.Command(dockerBinary, "images")
+ out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error listing images: %s, %v", out, err)
+ c.Fatalf("error listing images: %s, %v", out, err)
}
if strings.Contains(out, "DIGEST") {
- t.Fatalf("list output should not have contained DIGEST header: %s", out)
+ c.Fatalf("list output should not have contained DIGEST header: %s", out)
}
- logDone("by_digest - list images - digest header not displayed by default")
}
-func TestListImagesWithDigests(t *testing.T) {
- defer setupRegistry(t)()
- defer deleteImages(repoName+":tag1", repoName+":tag2")
+func (s *DockerRegistrySuite) TestListImagesWithDigests(c *check.C) {
// setup image1
digest1, err := setupImageWithTag("tag1")
if err != nil {
- t.Fatalf("error setting up image: %v", err)
+ c.Fatalf("error setting up image: %v", err)
}
imageReference1 := fmt.Sprintf("%s@%s", repoName, digest1)
- defer deleteImages(imageReference1)
- t.Logf("imageReference1 = %s", imageReference1)
+ c.Logf("imageReference1 = %s", imageReference1)
// pull image1 by digest
- c := exec.Command(dockerBinary, "pull", imageReference1)
- out, _, err := runCommandWithOutput(c)
+ cmd := exec.Command(dockerBinary, "pull", imageReference1)
+ out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error pulling by digest: %s, %v", out, err)
+ c.Fatalf("error pulling by digest: %s, %v", out, err)
}
// list images
- c = exec.Command(dockerBinary, "images", "--digests")
- out, _, err = runCommandWithOutput(c)
+ cmd = exec.Command(dockerBinary, "images", "--digests")
+ out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error listing images: %s, %v", out, err)
+ c.Fatalf("error listing images: %s, %v", out, err)
}
// make sure repo shown, tag=, digest = $digest1
re1 := regexp.MustCompile(`\s*` + repoName + `\s*\s*` + digest1 + `\s`)
if !re1.MatchString(out) {
- t.Fatalf("expected %q: %s", re1.String(), out)
+ c.Fatalf("expected %q: %s", re1.String(), out)
}
// setup image2
digest2, err := setupImageWithTag("tag2")
if err != nil {
- t.Fatalf("error setting up image: %v", err)
+ c.Fatalf("error setting up image: %v", err)
}
imageReference2 := fmt.Sprintf("%s@%s", repoName, digest2)
- defer deleteImages(imageReference2)
- t.Logf("imageReference2 = %s", imageReference2)
+ c.Logf("imageReference2 = %s", imageReference2)
// pull image1 by digest
- c = exec.Command(dockerBinary, "pull", imageReference1)
- out, _, err = runCommandWithOutput(c)
+ cmd = exec.Command(dockerBinary, "pull", imageReference1)
+ out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error pulling by digest: %s, %v", out, err)
+ c.Fatalf("error pulling by digest: %s, %v", out, err)
}
// pull image2 by digest
- c = exec.Command(dockerBinary, "pull", imageReference2)
- out, _, err = runCommandWithOutput(c)
+ cmd = exec.Command(dockerBinary, "pull", imageReference2)
+ out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error pulling by digest: %s, %v", out, err)
+ c.Fatalf("error pulling by digest: %s, %v", out, err)
}
// list images
- c = exec.Command(dockerBinary, "images", "--digests")
- out, _, err = runCommandWithOutput(c)
+ cmd = exec.Command(dockerBinary, "images", "--digests")
+ out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error listing images: %s, %v", out, err)
+ c.Fatalf("error listing images: %s, %v", out, err)
}
// make sure repo shown, tag=, digest = $digest1
if !re1.MatchString(out) {
- t.Fatalf("expected %q: %s", re1.String(), out)
+ c.Fatalf("expected %q: %s", re1.String(), out)
}
// make sure repo shown, tag=, digest = $digest2
re2 := regexp.MustCompile(`\s*` + repoName + `\s*\s*` + digest2 + `\s`)
if !re2.MatchString(out) {
- t.Fatalf("expected %q: %s", re2.String(), out)
+ c.Fatalf("expected %q: %s", re2.String(), out)
}
// pull tag1
- c = exec.Command(dockerBinary, "pull", repoName+":tag1")
- out, _, err = runCommandWithOutput(c)
+ cmd = exec.Command(dockerBinary, "pull", repoName+":tag1")
+ out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error pulling tag1: %s, %v", out, err)
+ c.Fatalf("error pulling tag1: %s, %v", out, err)
}
// list images
- c = exec.Command(dockerBinary, "images", "--digests")
- out, _, err = runCommandWithOutput(c)
+ cmd = exec.Command(dockerBinary, "images", "--digests")
+ out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error listing images: %s, %v", out, err)
+ c.Fatalf("error listing images: %s, %v", out, err)
}
// make sure image 1 has repo, tag, AND repo, , digest
reWithTag1 := regexp.MustCompile(`\s*` + repoName + `\s*tag1\s*\s`)
reWithDigest1 := regexp.MustCompile(`\s*` + repoName + `\s*\s*` + digest1 + `\s`)
if !reWithTag1.MatchString(out) {
- t.Fatalf("expected %q: %s", reWithTag1.String(), out)
+ c.Fatalf("expected %q: %s", reWithTag1.String(), out)
}
if !reWithDigest1.MatchString(out) {
- t.Fatalf("expected %q: %s", reWithDigest1.String(), out)
+ c.Fatalf("expected %q: %s", reWithDigest1.String(), out)
}
// make sure image 2 has repo, , digest
if !re2.MatchString(out) {
- t.Fatalf("expected %q: %s", re2.String(), out)
+ c.Fatalf("expected %q: %s", re2.String(), out)
}
// pull tag 2
- c = exec.Command(dockerBinary, "pull", repoName+":tag2")
- out, _, err = runCommandWithOutput(c)
+ cmd = exec.Command(dockerBinary, "pull", repoName+":tag2")
+ out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error pulling tag2: %s, %v", out, err)
+ c.Fatalf("error pulling tag2: %s, %v", out, err)
}
// list images
- c = exec.Command(dockerBinary, "images", "--digests")
- out, _, err = runCommandWithOutput(c)
+ cmd = exec.Command(dockerBinary, "images", "--digests")
+ out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error listing images: %s, %v", out, err)
+ c.Fatalf("error listing images: %s, %v", out, err)
}
// make sure image 1 has repo, tag, digest
if !reWithTag1.MatchString(out) {
- t.Fatalf("expected %q: %s", re1.String(), out)
+ c.Fatalf("expected %q: %s", re1.String(), out)
}
// make sure image 2 has repo, tag, digest
reWithTag2 := regexp.MustCompile(`\s*` + repoName + `\s*tag2\s*\s`)
reWithDigest2 := regexp.MustCompile(`\s*` + repoName + `\s*\s*` + digest2 + `\s`)
if !reWithTag2.MatchString(out) {
- t.Fatalf("expected %q: %s", reWithTag2.String(), out)
+ c.Fatalf("expected %q: %s", reWithTag2.String(), out)
}
if !reWithDigest2.MatchString(out) {
- t.Fatalf("expected %q: %s", reWithDigest2.String(), out)
+ c.Fatalf("expected %q: %s", reWithDigest2.String(), out)
}
// list images
- c = exec.Command(dockerBinary, "images", "--digests")
- out, _, err = runCommandWithOutput(c)
+ cmd = exec.Command(dockerBinary, "images", "--digests")
+ out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error listing images: %s, %v", out, err)
+ c.Fatalf("error listing images: %s, %v", out, err)
}
// make sure image 1 has repo, tag, digest
if !reWithTag1.MatchString(out) {
- t.Fatalf("expected %q: %s", re1.String(), out)
+ c.Fatalf("expected %q: %s", re1.String(), out)
}
// make sure image 2 has repo, tag, digest
if !reWithTag2.MatchString(out) {
- t.Fatalf("expected %q: %s", re2.String(), out)
+ c.Fatalf("expected %q: %s", re2.String(), out)
}
// make sure busybox has tag, but not digest
busyboxRe := regexp.MustCompile(`\s*busybox\s*latest\s*\s`)
if !busyboxRe.MatchString(out) {
- t.Fatalf("expected %q: %s", busyboxRe.String(), out)
+ c.Fatalf("expected %q: %s", busyboxRe.String(), out)
}
-
- logDone("by_digest - list images with digests")
}
-func TestDeleteImageByIDOnlyPulledByDigest(t *testing.T) {
- defer setupRegistry(t)()
-
+func (s *DockerRegistrySuite) TestDeleteImageByIDOnlyPulledByDigest(c *check.C) {
pushDigest, err := setupImage()
if err != nil {
- t.Fatalf("error setting up image: %v", err)
+ c.Fatalf("error setting up image: %v", err)
}
// pull from the registry using the @ reference
imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest)
- c := exec.Command(dockerBinary, "pull", imageReference)
- out, _, err := runCommandWithOutput(c)
+ cmd := exec.Command(dockerBinary, "pull", imageReference)
+ out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error pulling by digest: %s, %v", out, err)
+ c.Fatalf("error pulling by digest: %s, %v", out, err)
}
// just in case...
- defer deleteImages(imageReference)
imageID, err := inspectField(imageReference, ".Id")
if err != nil {
- t.Fatalf("error inspecting image id: %v", err)
+ c.Fatalf("error inspecting image id: %v", err)
}
- c = exec.Command(dockerBinary, "rmi", imageID)
- if _, err := runCommand(c); err != nil {
- t.Fatalf("error deleting image by id: %v", err)
+ cmd = exec.Command(dockerBinary, "rmi", imageID)
+ if _, err := runCommand(cmd); err != nil {
+ c.Fatalf("error deleting image by id: %v", err)
}
-
- logDone("by_digest - delete image by id only pulled by digest")
}
diff --git a/integration-cli/docker_cli_commit_test.go b/integration-cli/docker_cli_commit_test.go
index 3143c21fcdf11..391cd4ebc5a34 100644
--- a/integration-cli/docker_cli_commit_test.go
+++ b/integration-cli/docker_cli_commit_test.go
@@ -3,149 +3,132 @@ package main
import (
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
-func TestCommitAfterContainerIsDone(t *testing.T) {
+func (s *DockerSuite) TestCommitAfterContainerIsDone(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-i", "-a", "stdin", "busybox", "echo", "foo")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("failed to run container: %s, %v", out, err)
+ c.Fatalf("failed to run container: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
waitCmd := exec.Command(dockerBinary, "wait", cleanedContainerID)
if _, _, err = runCommandWithOutput(waitCmd); err != nil {
- t.Fatalf("error thrown while waiting for container: %s, %v", out, err)
+ c.Fatalf("error thrown while waiting for container: %s, %v", out, err)
}
commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID)
out, _, err = runCommandWithOutput(commitCmd)
if err != nil {
- t.Fatalf("failed to commit container to image: %s, %v", out, err)
+ c.Fatalf("failed to commit container to image: %s, %v", out, err)
}
cleanedImageID := strings.TrimSpace(out)
inspectCmd := exec.Command(dockerBinary, "inspect", cleanedImageID)
if out, _, err = runCommandWithOutput(inspectCmd); err != nil {
- t.Fatalf("failed to inspect image: %s, %v", out, err)
+ c.Fatalf("failed to inspect image: %s, %v", out, err)
}
-
- deleteContainer(cleanedContainerID)
- deleteImages(cleanedImageID)
-
- logDone("commit - echo foo and commit the image")
}
-func TestCommitWithoutPause(t *testing.T) {
+func (s *DockerSuite) TestCommitWithoutPause(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-i", "-a", "stdin", "busybox", "echo", "foo")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("failed to run container: %s, %v", out, err)
+ c.Fatalf("failed to run container: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
waitCmd := exec.Command(dockerBinary, "wait", cleanedContainerID)
if _, _, err = runCommandWithOutput(waitCmd); err != nil {
- t.Fatalf("error thrown while waiting for container: %s, %v", out, err)
+ c.Fatalf("error thrown while waiting for container: %s, %v", out, err)
}
commitCmd := exec.Command(dockerBinary, "commit", "-p=false", cleanedContainerID)
out, _, err = runCommandWithOutput(commitCmd)
if err != nil {
- t.Fatalf("failed to commit container to image: %s, %v", out, err)
+ c.Fatalf("failed to commit container to image: %s, %v", out, err)
}
cleanedImageID := strings.TrimSpace(out)
inspectCmd := exec.Command(dockerBinary, "inspect", cleanedImageID)
if out, _, err = runCommandWithOutput(inspectCmd); err != nil {
- t.Fatalf("failed to inspect image: %s, %v", out, err)
+ c.Fatalf("failed to inspect image: %s, %v", out, err)
}
-
- deleteContainer(cleanedContainerID)
- deleteImages(cleanedImageID)
-
- logDone("commit - echo foo and commit the image with --pause=false")
}
//test commit a paused container should not unpause it after commit
-func TestCommitPausedContainer(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestCommitPausedContainer(c *check.C) {
defer unpauseAllContainers()
cmd := exec.Command(dockerBinary, "run", "-i", "-d", "busybox")
out, _, _, err := runCommandWithStdoutStderr(cmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
cleanedContainerID := strings.TrimSpace(out)
cmd = exec.Command(dockerBinary, "pause", cleanedContainerID)
out, _, _, err = runCommandWithStdoutStderr(cmd)
if err != nil {
- t.Fatalf("failed to pause container: %v, output: %q", err, out)
+ c.Fatalf("failed to pause container: %v, output: %q", err, out)
}
commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID)
out, _, err = runCommandWithOutput(commitCmd)
if err != nil {
- t.Fatalf("failed to commit container to image: %s, %v", out, err)
+ c.Fatalf("failed to commit container to image: %s, %v", out, err)
}
- cleanedImageID := strings.TrimSpace(out)
- defer deleteImages(cleanedImageID)
cmd = exec.Command(dockerBinary, "inspect", "-f", "{{.State.Paused}}", cleanedContainerID)
out, _, _, err = runCommandWithStdoutStderr(cmd)
if err != nil {
- t.Fatalf("failed to inspect container: %v, output: %q", err, out)
+ c.Fatalf("failed to inspect container: %v, output: %q", err, out)
}
if !strings.Contains(out, "true") {
- t.Fatalf("commit should not unpause a paused container")
+ c.Fatalf("commit should not unpause a paused container")
}
- logDone("commit - commit a paused container will not unpause it")
}
-func TestCommitNewFile(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestCommitNewFile(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--name", "commiter", "busybox", "/bin/sh", "-c", "echo koye > /foo")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "commit", "commiter")
imageID, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
imageID = strings.Trim(imageID, "\r\n")
- defer deleteImages(imageID)
cmd = exec.Command(dockerBinary, "run", imageID, "cat", "/foo")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actual := strings.Trim(out, "\r\n"); actual != "koye" {
- t.Fatalf("expected output koye received %q", actual)
+ c.Fatalf("expected output koye received %q", actual)
}
- logDone("commit - commit file and read")
}
-func TestCommitHardlink(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestCommitHardlink(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-t", "--name", "hardlinks", "busybox", "sh", "-c", "touch file1 && ln file1 file2 && ls -di file1 file2")
firstOuput, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
chunks := strings.Split(strings.TrimSpace(firstOuput), " ")
@@ -158,21 +141,20 @@ func TestCommitHardlink(t *testing.T) {
}
}
if !found {
- t.Fatalf("Failed to create hardlink in a container. Expected to find %q in %q", inode, chunks[1:])
+ c.Fatalf("Failed to create hardlink in a container. Expected to find %q in %q", inode, chunks[1:])
}
cmd = exec.Command(dockerBinary, "commit", "hardlinks", "hardlinks")
imageID, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(imageID, err)
+ c.Fatal(imageID, err)
}
imageID = strings.Trim(imageID, "\r\n")
- defer deleteImages(imageID)
cmd = exec.Command(dockerBinary, "run", "-t", "hardlinks", "ls", "-di", "file1", "file2")
secondOuput, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
chunks = strings.Split(strings.TrimSpace(secondOuput), " ")
@@ -185,68 +167,60 @@ func TestCommitHardlink(t *testing.T) {
}
}
if !found {
- t.Fatalf("Failed to create hardlink in a container. Expected to find %q in %q", inode, chunks[1:])
+ c.Fatalf("Failed to create hardlink in a container. Expected to find %q in %q", inode, chunks[1:])
}
- logDone("commit - commit hardlinks")
}
-func TestCommitTTY(t *testing.T) {
- defer deleteImages("ttytest")
- defer deleteAllContainers()
+func (s *DockerSuite) TestCommitTTY(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-t", "--name", "tty", "busybox", "/bin/ls")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "commit", "tty", "ttytest")
imageID, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
imageID = strings.Trim(imageID, "\r\n")
cmd = exec.Command(dockerBinary, "run", "ttytest", "/bin/ls")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("commit - commit tty")
}
-func TestCommitWithHostBindMount(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestCommitWithHostBindMount(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--name", "bind-commit", "-v", "/dev/null:/winning", "busybox", "true")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "commit", "bind-commit", "bindtest")
imageID, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(imageID, err)
+ c.Fatal(imageID, err)
}
imageID = strings.Trim(imageID, "\r\n")
- defer deleteImages(imageID)
cmd = exec.Command(dockerBinary, "run", "bindtest", "true")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("commit - commit bind mounted file")
}
-func TestCommitChange(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestCommitChange(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--name", "test", "busybox", "true")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "commit",
@@ -257,25 +231,70 @@ func TestCommitChange(t *testing.T) {
"test", "test-commit")
imageId, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(imageId, err)
+ c.Fatal(imageId, err)
}
imageId = strings.Trim(imageId, "\r\n")
- defer deleteImages(imageId)
expected := map[string]string{
- "Config.ExposedPorts": "map[8080/tcp:map[]]",
+ "Config.ExposedPorts": "map[8080/tcp:{}]",
"Config.Env": "[DEBUG=true test=1 PATH=/foo]",
}
for conf, value := range expected {
res, err := inspectField(imageId, conf)
if err != nil {
- t.Errorf("failed to get value %s, error: %s", conf, err)
+ c.Errorf("failed to get value %s, error: %s", conf, err)
}
if res != value {
- t.Errorf("%s('%s'), expected %s", conf, res, value)
+ c.Errorf("%s('%s'), expected %s", conf, res, value)
}
}
- logDone("commit - commit --change")
+}
+
+// TODO: commit --run is deprecated, remove this once --run is removed
+func (s *DockerSuite) TestCommitMergeConfigRun(c *check.C) {
+ name := "commit-test"
+ out, _ := dockerCmd(c, "run", "-d", "-e=FOO=bar", "busybox", "/bin/sh", "-c", "echo testing > /tmp/foo")
+ id := strings.TrimSpace(out)
+
+ dockerCmd(c, "commit", `--run={"Cmd": ["cat", "/tmp/foo"]}`, id, "commit-test")
+
+ out, _ = dockerCmd(c, "run", "--name", name, "commit-test")
+ if strings.TrimSpace(out) != "testing" {
+ c.Fatal("run config in committed container was not merged")
+ }
+
+ type cfg struct {
+ Env []string
+ Cmd []string
+ }
+ config1 := cfg{}
+ if err := inspectFieldAndMarshall(id, "Config", &config1); err != nil {
+ c.Fatal(err)
+ }
+ config2 := cfg{}
+ if err := inspectFieldAndMarshall(name, "Config", &config2); err != nil {
+ c.Fatal(err)
+ }
+
+ // Env has at least PATH loaded as well here, so let's just grab the FOO one
+ var env1, env2 string
+ for _, e := range config1.Env {
+ if strings.HasPrefix(e, "FOO") {
+ env1 = e
+ break
+ }
+ }
+ for _, e := range config2.Env {
+ if strings.HasPrefix(e, "FOO") {
+ env2 = e
+ break
+ }
+ }
+
+ if len(config1.Env) != len(config2.Env) || env1 != env2 && env2 != "" {
+ c.Fatalf("expected envs to match: %v - %v", config1.Env, config2.Env)
+ }
+
}
diff --git a/integration-cli/docker_cli_config_test.go b/integration-cli/docker_cli_config_test.go
new file mode 100644
index 0000000000000..5ccd7af10e0cb
--- /dev/null
+++ b/integration-cli/docker_cli_config_test.go
@@ -0,0 +1,56 @@
+package main
+
+import (
+ "io/ioutil"
+ "net/http"
+ "net/http/httptest"
+ "os"
+ "os/exec"
+ "path/filepath"
+
+ "github.com/docker/docker/pkg/homedir"
+ "github.com/go-check/check"
+)
+
+func (s *DockerSuite) TestConfigHttpHeader(c *check.C) {
+ testRequires(c, UnixCli) // Can't set/unset HOME on windows right now
+ // We either need a level of Go that supports Unsetenv (for cases
+ // when HOME/USERPROFILE isn't set), or we need to be able to use
+ // os/user but user.Current() only works if we aren't statically compiling
+
+ var headers map[string][]string
+
+ server := httptest.NewServer(http.HandlerFunc(
+ func(w http.ResponseWriter, r *http.Request) {
+ headers = r.Header
+ }))
+ defer server.Close()
+
+ homeKey := homedir.Key()
+ homeVal := homedir.Get()
+ tmpDir, _ := ioutil.TempDir("", "fake-home")
+ defer os.RemoveAll(tmpDir)
+
+ dotDocker := filepath.Join(tmpDir, ".docker")
+ os.Mkdir(dotDocker, 0600)
+ tmpCfg := filepath.Join(dotDocker, "config.json")
+
+ defer func() { os.Setenv(homeKey, homeVal) }()
+ os.Setenv(homeKey, tmpDir)
+
+ data := `{
+ "HttpHeaders": { "MyHeader": "MyValue" }
+ }`
+
+ err := ioutil.WriteFile(tmpCfg, []byte(data), 0600)
+ if err != nil {
+ c.Fatalf("Err creating file(%s): %v", tmpCfg, err)
+ }
+
+ cmd := exec.Command(dockerBinary, "-H="+server.URL[7:], "ps")
+ out, _, _ := runCommandWithOutput(cmd)
+
+ if headers["Myheader"] == nil || headers["Myheader"][0] != "MyValue" {
+ c.Fatalf("Missing/bad header: %q\nout:%v", headers, out)
+ }
+}
diff --git a/integration-cli/docker_cli_cp_test.go b/integration-cli/docker_cli_cp_test.go
index 37e4659e917ac..26e778e4f2b80 100644
--- a/integration-cli/docker_cli_cp_test.go
+++ b/integration-cli/docker_cli_cp_test.go
@@ -9,7 +9,8 @@ import (
"path"
"path/filepath"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
const (
@@ -24,27 +25,26 @@ const (
// Test for #5656
// Check that garbage paths don't escape the container's rootfs
-func TestCpGarbagePath(t *testing.T) {
- out, exitCode, err := dockerCmd(t, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
- if err != nil || exitCode != 0 {
- t.Fatal("failed to create a container", out, err)
+func (s *DockerSuite) TestCpGarbagePath(c *check.C) {
+ out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
+ if exitCode != 0 {
+ c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
- defer deleteContainer(cleanedContainerID)
- out, _, err = dockerCmd(t, "wait", cleanedContainerID)
- if err != nil || strings.TrimSpace(out) != "0" {
- t.Fatal("failed to set up container", out, err)
+ out, _ = dockerCmd(c, "wait", cleanedContainerID)
+ if strings.TrimSpace(out) != "0" {
+ c.Fatal("failed to set up container", out)
}
if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
hostFile, err := os.Create(cpFullPath)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer hostFile.Close()
defer os.RemoveAll(cpTestPathParent)
@@ -53,7 +53,7 @@ func TestCpGarbagePath(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-integration")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
tmpname := filepath.Join(tmpdir, cpTestName)
@@ -61,52 +61,47 @@ func TestCpGarbagePath(t *testing.T) {
path := path.Join("../../../../../../../../../../../../", cpFullPath)
- _, _, err = dockerCmd(t, "cp", cleanedContainerID+":"+path, tmpdir)
- if err != nil {
- t.Fatalf("couldn't copy from garbage path: %s:%s %s", cleanedContainerID, path, err)
- }
+ _, _ = dockerCmd(c, "cp", cleanedContainerID+":"+path, tmpdir)
file, _ := os.Open(tmpname)
defer file.Close()
test, err := ioutil.ReadAll(file)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if string(test) == cpHostContents {
- t.Errorf("output matched host file -- garbage path can escape container rootfs")
+ c.Errorf("output matched host file -- garbage path can escape container rootfs")
}
if string(test) != cpContainerContents {
- t.Errorf("output doesn't match the input for garbage path")
+ c.Errorf("output doesn't match the input for garbage path")
}
- logDone("cp - garbage paths relative to container's rootfs")
}
// Check that relative paths are relative to the container's rootfs
-func TestCpRelativePath(t *testing.T) {
- out, exitCode, err := dockerCmd(t, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
- if err != nil || exitCode != 0 {
- t.Fatal("failed to create a container", out, err)
+func (s *DockerSuite) TestCpRelativePath(c *check.C) {
+ out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
+ if exitCode != 0 {
+ c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
- defer deleteContainer(cleanedContainerID)
- out, _, err = dockerCmd(t, "wait", cleanedContainerID)
- if err != nil || strings.TrimSpace(out) != "0" {
- t.Fatal("failed to set up container", out, err)
+ out, _ = dockerCmd(c, "wait", cleanedContainerID)
+ if strings.TrimSpace(out) != "0" {
+ c.Fatal("failed to set up container", out)
}
if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
hostFile, err := os.Create(cpFullPath)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer hostFile.Close()
defer os.RemoveAll(cpTestPathParent)
@@ -116,7 +111,7 @@ func TestCpRelativePath(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-integration")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
tmpname := filepath.Join(tmpdir, cpTestName)
@@ -128,55 +123,50 @@ func TestCpRelativePath(t *testing.T) {
// get this unix-path manipulation on windows with filepath.
relPath = cpFullPath[1:]
} else {
- t.Fatalf("path %s was assumed to be an absolute path", cpFullPath)
+ c.Fatalf("path %s was assumed to be an absolute path", cpFullPath)
}
- _, _, err = dockerCmd(t, "cp", cleanedContainerID+":"+relPath, tmpdir)
- if err != nil {
- t.Fatalf("couldn't copy from relative path: %s:%s %s", cleanedContainerID, relPath, err)
- }
+ _, _ = dockerCmd(c, "cp", cleanedContainerID+":"+relPath, tmpdir)
file, _ := os.Open(tmpname)
defer file.Close()
test, err := ioutil.ReadAll(file)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if string(test) == cpHostContents {
- t.Errorf("output matched host file -- relative path can escape container rootfs")
+ c.Errorf("output matched host file -- relative path can escape container rootfs")
}
if string(test) != cpContainerContents {
- t.Errorf("output doesn't match the input for relative path")
+ c.Errorf("output doesn't match the input for relative path")
}
- logDone("cp - relative paths relative to container's rootfs")
}
// Check that absolute paths are relative to the container's rootfs
-func TestCpAbsolutePath(t *testing.T) {
- out, exitCode, err := dockerCmd(t, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
- if err != nil || exitCode != 0 {
- t.Fatal("failed to create a container", out, err)
+func (s *DockerSuite) TestCpAbsolutePath(c *check.C) {
+ out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
+ if exitCode != 0 {
+ c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
- defer deleteContainer(cleanedContainerID)
- out, _, err = dockerCmd(t, "wait", cleanedContainerID)
- if err != nil || strings.TrimSpace(out) != "0" {
- t.Fatal("failed to set up container", out, err)
+ out, _ = dockerCmd(c, "wait", cleanedContainerID)
+ if strings.TrimSpace(out) != "0" {
+ c.Fatal("failed to set up container", out)
}
if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
hostFile, err := os.Create(cpFullPath)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer hostFile.Close()
defer os.RemoveAll(cpTestPathParent)
@@ -186,7 +176,7 @@ func TestCpAbsolutePath(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-integration")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
tmpname := filepath.Join(tmpdir, cpTestName)
@@ -194,53 +184,48 @@ func TestCpAbsolutePath(t *testing.T) {
path := cpFullPath
- _, _, err = dockerCmd(t, "cp", cleanedContainerID+":"+path, tmpdir)
- if err != nil {
- t.Fatalf("couldn't copy from absolute path: %s:%s %s", cleanedContainerID, path, err)
- }
+ _, _ = dockerCmd(c, "cp", cleanedContainerID+":"+path, tmpdir)
file, _ := os.Open(tmpname)
defer file.Close()
test, err := ioutil.ReadAll(file)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if string(test) == cpHostContents {
- t.Errorf("output matched host file -- absolute path can escape container rootfs")
+ c.Errorf("output matched host file -- absolute path can escape container rootfs")
}
if string(test) != cpContainerContents {
- t.Errorf("output doesn't match the input for absolute path")
+ c.Errorf("output doesn't match the input for absolute path")
}
- logDone("cp - absolute paths relative to container's rootfs")
}
// Test for #5619
// Check that absolute symlinks are still relative to the container's rootfs
-func TestCpAbsoluteSymlink(t *testing.T) {
- out, exitCode, err := dockerCmd(t, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpFullPath+" container_path")
- if err != nil || exitCode != 0 {
- t.Fatal("failed to create a container", out, err)
+func (s *DockerSuite) TestCpAbsoluteSymlink(c *check.C) {
+ out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpFullPath+" container_path")
+ if exitCode != 0 {
+ c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
- defer deleteContainer(cleanedContainerID)
- out, _, err = dockerCmd(t, "wait", cleanedContainerID)
- if err != nil || strings.TrimSpace(out) != "0" {
- t.Fatal("failed to set up container", out, err)
+ out, _ = dockerCmd(c, "wait", cleanedContainerID)
+ if strings.TrimSpace(out) != "0" {
+ c.Fatal("failed to set up container", out)
}
if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
hostFile, err := os.Create(cpFullPath)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer hostFile.Close()
defer os.RemoveAll(cpTestPathParent)
@@ -250,7 +235,7 @@ func TestCpAbsoluteSymlink(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-integration")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
tmpname := filepath.Join(tmpdir, cpTestName)
@@ -258,53 +243,48 @@ func TestCpAbsoluteSymlink(t *testing.T) {
path := path.Join("/", "container_path")
- _, _, err = dockerCmd(t, "cp", cleanedContainerID+":"+path, tmpdir)
- if err != nil {
- t.Fatalf("couldn't copy from absolute path: %s:%s %s", cleanedContainerID, path, err)
- }
+ _, _ = dockerCmd(c, "cp", cleanedContainerID+":"+path, tmpdir)
file, _ := os.Open(tmpname)
defer file.Close()
test, err := ioutil.ReadAll(file)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if string(test) == cpHostContents {
- t.Errorf("output matched host file -- absolute symlink can escape container rootfs")
+ c.Errorf("output matched host file -- absolute symlink can escape container rootfs")
}
if string(test) != cpContainerContents {
- t.Errorf("output doesn't match the input for absolute symlink")
+ c.Errorf("output doesn't match the input for absolute symlink")
}
- logDone("cp - absolute symlink relative to container's rootfs")
}
// Test for #5619
// Check that symlinks which are part of the resource path are still relative to the container's rootfs
-func TestCpSymlinkComponent(t *testing.T) {
- out, exitCode, err := dockerCmd(t, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpTestPath+" container_path")
- if err != nil || exitCode != 0 {
- t.Fatal("failed to create a container", out, err)
+func (s *DockerSuite) TestCpSymlinkComponent(c *check.C) {
+ out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpTestPath+" container_path")
+ if exitCode != 0 {
+ c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
- defer deleteContainer(cleanedContainerID)
- out, _, err = dockerCmd(t, "wait", cleanedContainerID)
- if err != nil || strings.TrimSpace(out) != "0" {
- t.Fatal("failed to set up container", out, err)
+ out, _ = dockerCmd(c, "wait", cleanedContainerID)
+ if strings.TrimSpace(out) != "0" {
+ c.Fatal("failed to set up container", out)
}
if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
hostFile, err := os.Create(cpFullPath)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer hostFile.Close()
defer os.RemoveAll(cpTestPathParent)
@@ -314,7 +294,7 @@ func TestCpSymlinkComponent(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-integration")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
tmpname := filepath.Join(tmpdir, cpTestName)
@@ -322,301 +302,297 @@ func TestCpSymlinkComponent(t *testing.T) {
path := path.Join("/", "container_path", cpTestName)
- _, _, err = dockerCmd(t, "cp", cleanedContainerID+":"+path, tmpdir)
- if err != nil {
- t.Fatalf("couldn't copy from symlink path component: %s:%s %s", cleanedContainerID, path, err)
- }
+ _, _ = dockerCmd(c, "cp", cleanedContainerID+":"+path, tmpdir)
file, _ := os.Open(tmpname)
defer file.Close()
test, err := ioutil.ReadAll(file)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if string(test) == cpHostContents {
- t.Errorf("output matched host file -- symlink path component can escape container rootfs")
+ c.Errorf("output matched host file -- symlink path component can escape container rootfs")
}
if string(test) != cpContainerContents {
- t.Errorf("output doesn't match the input for symlink path component")
+ c.Errorf("output doesn't match the input for symlink path component")
}
- logDone("cp - symlink path components relative to container's rootfs")
}
// Check that cp with unprivileged user doesn't return any error
-func TestCpUnprivilegedUser(t *testing.T) {
- testRequires(t, UnixCli) // uses chmod/su: not available on windows
+func (s *DockerSuite) TestCpUnprivilegedUser(c *check.C) {
+ testRequires(c, UnixCli) // uses chmod/su: not available on windows
- out, exitCode, err := dockerCmd(t, "run", "-d", "busybox", "/bin/sh", "-c", "touch "+cpTestName)
- if err != nil || exitCode != 0 {
- t.Fatal("failed to create a container", out, err)
+ out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "touch "+cpTestName)
+ if exitCode != 0 {
+ c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
- defer deleteContainer(cleanedContainerID)
- out, _, err = dockerCmd(t, "wait", cleanedContainerID)
- if err != nil || strings.TrimSpace(out) != "0" {
- t.Fatal("failed to set up container", out, err)
+ out, _ = dockerCmd(c, "wait", cleanedContainerID)
+ if strings.TrimSpace(out) != "0" {
+ c.Fatal("failed to set up container", out)
}
tmpdir, err := ioutil.TempDir("", "docker-integration")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(tmpdir)
if err = os.Chmod(tmpdir, 0777); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
path := cpTestName
_, _, err = runCommandWithOutput(exec.Command("su", "unprivilegeduser", "-c", dockerBinary+" cp "+cleanedContainerID+":"+path+" "+tmpdir))
if err != nil {
- t.Fatalf("couldn't copy with unprivileged user: %s:%s %s", cleanedContainerID, path, err)
+ c.Fatalf("couldn't copy with unprivileged user: %s:%s %s", cleanedContainerID, path, err)
}
- logDone("cp - unprivileged user")
}
-func TestCpSpecialFiles(t *testing.T) {
- testRequires(t, SameHostDaemon)
+func (s *DockerSuite) TestCpSpecialFiles(c *check.C) {
+ testRequires(c, SameHostDaemon)
outDir, err := ioutil.TempDir("", "cp-test-special-files")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(outDir)
- out, exitCode, err := dockerCmd(t, "run", "-d", "busybox", "/bin/sh", "-c", "touch /foo")
- if err != nil || exitCode != 0 {
- t.Fatal("failed to create a container", out, err)
+ out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "touch /foo")
+ if exitCode != 0 {
+ c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
- defer deleteContainer(cleanedContainerID)
- out, _, err = dockerCmd(t, "wait", cleanedContainerID)
- if err != nil || strings.TrimSpace(out) != "0" {
- t.Fatal("failed to set up container", out, err)
+ out, _ = dockerCmd(c, "wait", cleanedContainerID)
+ if strings.TrimSpace(out) != "0" {
+ c.Fatal("failed to set up container", out)
}
// Copy actual /etc/resolv.conf
- _, _, err = dockerCmd(t, "cp", cleanedContainerID+":/etc/resolv.conf", outDir)
- if err != nil {
- t.Fatalf("couldn't copy from container: %s:%s %v", cleanedContainerID, "/etc/resolv.conf", err)
- }
+ _, _ = dockerCmd(c, "cp", cleanedContainerID+":/etc/resolv.conf", outDir)
expected, err := ioutil.ReadFile("/var/lib/docker/containers/" + cleanedContainerID + "/resolv.conf")
actual, err := ioutil.ReadFile(outDir + "/resolv.conf")
if !bytes.Equal(actual, expected) {
- t.Fatalf("Expected copied file to be duplicate of the container resolvconf")
+ c.Fatalf("Expected copied file to be duplicate of the container resolvconf")
}
// Copy actual /etc/hosts
- _, _, err = dockerCmd(t, "cp", cleanedContainerID+":/etc/hosts", outDir)
- if err != nil {
- t.Fatalf("couldn't copy from container: %s:%s %v", cleanedContainerID, "/etc/hosts", err)
- }
+ _, _ = dockerCmd(c, "cp", cleanedContainerID+":/etc/hosts", outDir)
expected, err = ioutil.ReadFile("/var/lib/docker/containers/" + cleanedContainerID + "/hosts")
actual, err = ioutil.ReadFile(outDir + "/hosts")
if !bytes.Equal(actual, expected) {
- t.Fatalf("Expected copied file to be duplicate of the container hosts")
+ c.Fatalf("Expected copied file to be duplicate of the container hosts")
}
// Copy actual /etc/resolv.conf
- _, _, err = dockerCmd(t, "cp", cleanedContainerID+":/etc/hostname", outDir)
- if err != nil {
- t.Fatalf("couldn't copy from container: %s:%s %v", cleanedContainerID, "/etc/hostname", err)
- }
+ _, _ = dockerCmd(c, "cp", cleanedContainerID+":/etc/hostname", outDir)
expected, err = ioutil.ReadFile("/var/lib/docker/containers/" + cleanedContainerID + "/hostname")
actual, err = ioutil.ReadFile(outDir + "/hostname")
if !bytes.Equal(actual, expected) {
- t.Fatalf("Expected copied file to be duplicate of the container resolvconf")
+ c.Fatalf("Expected copied file to be duplicate of the container resolvconf")
}
- logDone("cp - special files (resolv.conf, hosts, hostname)")
}
-func TestCpVolumePath(t *testing.T) {
- testRequires(t, SameHostDaemon)
+func (s *DockerSuite) TestCpVolumePath(c *check.C) {
+ testRequires(c, SameHostDaemon)
tmpDir, err := ioutil.TempDir("", "cp-test-volumepath")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(tmpDir)
outDir, err := ioutil.TempDir("", "cp-test-volumepath-out")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(outDir)
_, err = os.Create(tmpDir + "/test")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- out, exitCode, err := dockerCmd(t, "run", "-d", "-v", "/foo", "-v", tmpDir+"/test:/test", "-v", tmpDir+":/baz", "busybox", "/bin/sh", "-c", "touch /foo/bar")
- if err != nil || exitCode != 0 {
- t.Fatal("failed to create a container", out, err)
+ out, exitCode := dockerCmd(c, "run", "-d", "-v", "/foo", "-v", tmpDir+"/test:/test", "-v", tmpDir+":/baz", "busybox", "/bin/sh", "-c", "touch /foo/bar")
+ if exitCode != 0 {
+ c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
- defer dockerCmd(t, "rm", "-fv", cleanedContainerID)
+ defer dockerCmd(c, "rm", "-fv", cleanedContainerID)
- out, _, err = dockerCmd(t, "wait", cleanedContainerID)
- if err != nil || strings.TrimSpace(out) != "0" {
- t.Fatal("failed to set up container", out, err)
+ out, _ = dockerCmd(c, "wait", cleanedContainerID)
+ if strings.TrimSpace(out) != "0" {
+ c.Fatal("failed to set up container", out)
}
// Copy actual volume path
- _, _, err = dockerCmd(t, "cp", cleanedContainerID+":/foo", outDir)
- if err != nil {
- t.Fatalf("couldn't copy from volume path: %s:%s %v", cleanedContainerID, "/foo", err)
- }
+ _, _ = dockerCmd(c, "cp", cleanedContainerID+":/foo", outDir)
+
stat, err := os.Stat(outDir + "/foo")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !stat.IsDir() {
- t.Fatal("expected copied content to be dir")
+ c.Fatal("expected copied content to be dir")
}
stat, err = os.Stat(outDir + "/foo/bar")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if stat.IsDir() {
- t.Fatal("Expected file `bar` to be a file")
+ c.Fatal("Expected file `bar` to be a file")
}
// Copy file nested in volume
- _, _, err = dockerCmd(t, "cp", cleanedContainerID+":/foo/bar", outDir)
- if err != nil {
- t.Fatalf("couldn't copy from volume path: %s:%s %v", cleanedContainerID, "/foo", err)
- }
+ _, _ = dockerCmd(c, "cp", cleanedContainerID+":/foo/bar", outDir)
+
stat, err = os.Stat(outDir + "/bar")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if stat.IsDir() {
- t.Fatal("Expected file `bar` to be a file")
+ c.Fatal("Expected file `bar` to be a file")
}
// Copy Bind-mounted dir
- _, _, err = dockerCmd(t, "cp", cleanedContainerID+":/baz", outDir)
- if err != nil {
- t.Fatalf("couldn't copy from bind-mounted volume path: %s:%s %v", cleanedContainerID, "/baz", err)
- }
+ _, _ = dockerCmd(c, "cp", cleanedContainerID+":/baz", outDir)
stat, err = os.Stat(outDir + "/baz")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !stat.IsDir() {
- t.Fatal("Expected `baz` to be a dir")
+ c.Fatal("Expected `baz` to be a dir")
}
// Copy file nested in bind-mounted dir
- _, _, err = dockerCmd(t, "cp", cleanedContainerID+":/baz/test", outDir)
+ _, _ = dockerCmd(c, "cp", cleanedContainerID+":/baz/test", outDir)
fb, err := ioutil.ReadFile(outDir + "/baz/test")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
fb2, err := ioutil.ReadFile(tmpDir + "/test")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !bytes.Equal(fb, fb2) {
- t.Fatalf("Expected copied file to be duplicate of bind-mounted file")
+ c.Fatalf("Expected copied file to be duplicate of bind-mounted file")
}
// Copy bind-mounted file
- _, _, err = dockerCmd(t, "cp", cleanedContainerID+":/test", outDir)
+ _, _ = dockerCmd(c, "cp", cleanedContainerID+":/test", outDir)
fb, err = ioutil.ReadFile(outDir + "/test")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
fb2, err = ioutil.ReadFile(tmpDir + "/test")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !bytes.Equal(fb, fb2) {
- t.Fatalf("Expected copied file to be duplicate of bind-mounted file")
+ c.Fatalf("Expected copied file to be duplicate of bind-mounted file")
}
- logDone("cp - volume path")
}
-func TestCpToDot(t *testing.T) {
- out, exitCode, err := dockerCmd(t, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /test")
- if err != nil || exitCode != 0 {
- t.Fatal("failed to create a container", out, err)
+func (s *DockerSuite) TestCpToDot(c *check.C) {
+ out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /test")
+ if exitCode != 0 {
+ c.Fatal("failed to create a container", out)
}
cleanedContainerID := strings.TrimSpace(out)
- defer deleteContainer(cleanedContainerID)
- out, _, err = dockerCmd(t, "wait", cleanedContainerID)
- if err != nil || strings.TrimSpace(out) != "0" {
- t.Fatal("failed to set up container", out, err)
+ out, _ = dockerCmd(c, "wait", cleanedContainerID)
+ if strings.TrimSpace(out) != "0" {
+ c.Fatal("failed to set up container", out)
}
tmpdir, err := ioutil.TempDir("", "docker-integration")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(tmpdir)
cwd, err := os.Getwd()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.Chdir(cwd)
if err := os.Chdir(tmpdir); err != nil {
- t.Fatal(err)
- }
- _, _, err = dockerCmd(t, "cp", cleanedContainerID+":/test", ".")
- if err != nil {
- t.Fatalf("couldn't docker cp to \".\" path: %s", err)
+ c.Fatal(err)
}
+ _, _ = dockerCmd(c, "cp", cleanedContainerID+":/test", ".")
content, err := ioutil.ReadFile("./test")
if string(content) != "lololol\n" {
- t.Fatalf("Wrong content in copied file %q, should be %q", content, "lololol\n")
+ c.Fatalf("Wrong content in copied file %q, should be %q", content, "lololol\n")
}
- logDone("cp - to dot path")
}
-func TestCpToStdout(t *testing.T) {
- out, exitCode, err := dockerCmd(t, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /test")
- if err != nil || exitCode != 0 {
- t.Fatalf("failed to create a container:%s\n%s", out, err)
+func (s *DockerSuite) TestCpToStdout(c *check.C) {
+ out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /test")
+ if exitCode != 0 {
+ c.Fatalf("failed to create a container:%s\n", out)
}
cID := strings.TrimSpace(out)
- defer deleteContainer(cID)
- out, _, err = dockerCmd(t, "wait", cID)
- if err != nil || strings.TrimSpace(out) != "0" {
- t.Fatalf("failed to set up container:%s\n%s", out, err)
+ out, _ = dockerCmd(c, "wait", cID)
+ if strings.TrimSpace(out) != "0" {
+ c.Fatalf("failed to set up container:%s\n", out)
}
- out, _, err = runCommandPipelineWithOutput(
+ out, _, err := runCommandPipelineWithOutput(
exec.Command(dockerBinary, "cp", cID+":/test", "-"),
exec.Command("tar", "-vtf", "-"))
+
if err != nil {
- t.Fatalf("Failed to run commands: %s", err)
+ c.Fatalf("Failed to run commands: %s", err)
}
if !strings.Contains(out, "test") || !strings.Contains(out, "-rw") {
- t.Fatalf("Missing file from tar TOC:\n%s", out)
+ c.Fatalf("Missing file from tar TOC:\n%s", out)
+ }
+}
+
+func (s *DockerSuite) TestCpNameHasColon(c *check.C) {
+ testRequires(c, SameHostDaemon)
+
+ out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /te:s:t")
+ if exitCode != 0 {
+ c.Fatal("failed to create a container", out)
+ }
+
+ cleanedContainerID := strings.TrimSpace(out)
+
+ out, _ = dockerCmd(c, "wait", cleanedContainerID)
+ if strings.TrimSpace(out) != "0" {
+ c.Fatal("failed to set up container", out)
+ }
+
+ tmpdir, err := ioutil.TempDir("", "docker-integration")
+ if err != nil {
+ c.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+ _, _ = dockerCmd(c, "cp", cleanedContainerID+":/te:s:t", tmpdir)
+ content, err := ioutil.ReadFile(tmpdir + "/te:s:t")
+ if string(content) != "lololol\n" {
+ c.Fatalf("Wrong content in copied file %q, should be %q", content, "lololol\n")
}
- logDone("cp - to stdout")
}
diff --git a/integration-cli/docker_cli_create_test.go b/integration-cli/docker_cli_create_test.go
index 3a3c2f07df249..646a8eafe023b 100644
--- a/integration-cli/docker_cli_create_test.go
+++ b/integration-cli/docker_cli_create_test.go
@@ -6,20 +6,18 @@ import (
"os/exec"
"reflect"
"strings"
- "testing"
"time"
"github.com/docker/docker/nat"
+ "github.com/go-check/check"
)
// Make sure we can create a simple container with some args
-func TestCreateArgs(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestCreateArgs(c *check.C) {
runCmd := exec.Command(dockerBinary, "create", "busybox", "command", "arg1", "arg2", "arg with space")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -27,7 +25,7 @@ func TestCreateArgs(t *testing.T) {
inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
out, _, err = runCommandWithOutput(inspectCmd)
if err != nil {
- t.Fatalf("out should've been a container id: %s, %v", out, err)
+ c.Fatalf("out should've been a container id: %s, %v", out, err)
}
containers := []struct {
@@ -38,40 +36,38 @@ func TestCreateArgs(t *testing.T) {
Image string
}{}
if err := json.Unmarshal([]byte(out), &containers); err != nil {
- t.Fatalf("Error inspecting the container: %s", err)
+ c.Fatalf("Error inspecting the container: %s", err)
}
if len(containers) != 1 {
- t.Fatalf("Unexpected container count. Expected 0, received: %d", len(containers))
+ c.Fatalf("Unexpected container count. Expected 0, received: %d", len(containers))
}
- c := containers[0]
- if c.Path != "command" {
- t.Fatalf("Unexpected container path. Expected command, received: %s", c.Path)
+ cont := containers[0]
+ if cont.Path != "command" {
+ c.Fatalf("Unexpected container path. Expected command, received: %s", cont.Path)
}
b := false
expected := []string{"arg1", "arg2", "arg with space"}
for i, arg := range expected {
- if arg != c.Args[i] {
+ if arg != cont.Args[i] {
b = true
break
}
}
- if len(c.Args) != len(expected) || b {
- t.Fatalf("Unexpected args. Expected %v, received: %v", expected, c.Args)
+ if len(cont.Args) != len(expected) || b {
+ c.Fatalf("Unexpected args. Expected %v, received: %v", expected, cont.Args)
}
- logDone("create - args")
}
// Make sure we can set hostconfig options too
-func TestCreateHostConfig(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestCreateHostConfig(c *check.C) {
runCmd := exec.Command(dockerBinary, "create", "-P", "busybox", "echo")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -79,7 +75,7 @@ func TestCreateHostConfig(t *testing.T) {
inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
out, _, err = runCommandWithOutput(inspectCmd)
if err != nil {
- t.Fatalf("out should've been a container id: %s, %v", out, err)
+ c.Fatalf("out should've been a container id: %s, %v", out, err)
}
containers := []struct {
@@ -88,31 +84,29 @@ func TestCreateHostConfig(t *testing.T) {
}
}{}
if err := json.Unmarshal([]byte(out), &containers); err != nil {
- t.Fatalf("Error inspecting the container: %s", err)
+ c.Fatalf("Error inspecting the container: %s", err)
}
if len(containers) != 1 {
- t.Fatalf("Unexpected container count. Expected 0, received: %d", len(containers))
+ c.Fatalf("Unexpected container count. Expected 0, received: %d", len(containers))
}
- c := containers[0]
- if c.HostConfig == nil {
- t.Fatalf("Expected HostConfig, got none")
+ cont := containers[0]
+ if cont.HostConfig == nil {
+ c.Fatalf("Expected HostConfig, got none")
}
- if !c.HostConfig.PublishAllPorts {
- t.Fatalf("Expected PublishAllPorts, got false")
+ if !cont.HostConfig.PublishAllPorts {
+ c.Fatalf("Expected PublishAllPorts, got false")
}
- logDone("create - hostconfig")
}
-func TestCreateWithPortRange(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestCreateWithPortRange(c *check.C) {
runCmd := exec.Command(dockerBinary, "create", "-p", "3300-3303:3300-3303/tcp", "busybox", "echo")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -120,7 +114,7 @@ func TestCreateWithPortRange(t *testing.T) {
inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
out, _, err = runCommandWithOutput(inspectCmd)
if err != nil {
- t.Fatalf("out should've been a container id: %s, %v", out, err)
+ c.Fatalf("out should've been a container id: %s, %v", out, err)
}
containers := []struct {
@@ -129,39 +123,37 @@ func TestCreateWithPortRange(t *testing.T) {
}
}{}
if err := json.Unmarshal([]byte(out), &containers); err != nil {
- t.Fatalf("Error inspecting the container: %s", err)
+ c.Fatalf("Error inspecting the container: %s", err)
}
if len(containers) != 1 {
- t.Fatalf("Unexpected container count. Expected 0, received: %d", len(containers))
+ c.Fatalf("Unexpected container count. Expected 0, received: %d", len(containers))
}
- c := containers[0]
- if c.HostConfig == nil {
- t.Fatalf("Expected HostConfig, got none")
+ cont := containers[0]
+ if cont.HostConfig == nil {
+ c.Fatalf("Expected HostConfig, got none")
}
- if len(c.HostConfig.PortBindings) != 4 {
- t.Fatalf("Expected 4 ports bindings, got %d", len(c.HostConfig.PortBindings))
+ if len(cont.HostConfig.PortBindings) != 4 {
+ c.Fatalf("Expected 4 ports bindings, got %d", len(cont.HostConfig.PortBindings))
}
- for k, v := range c.HostConfig.PortBindings {
+ for k, v := range cont.HostConfig.PortBindings {
if len(v) != 1 {
- t.Fatalf("Expected 1 ports binding, for the port %s but found %s", k, v)
+ c.Fatalf("Expected 1 ports binding, for the port %s but found %s", k, v)
}
if k.Port() != v[0].HostPort {
- t.Fatalf("Expected host port %d to match published port %d", k.Port(), v[0].HostPort)
+ c.Fatalf("Expected host port %d to match published port %d", k.Port(), v[0].HostPort)
}
}
- logDone("create - port range")
}
-func TestCreateWithiLargePortRange(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestCreateWithiLargePortRange(c *check.C) {
runCmd := exec.Command(dockerBinary, "create", "-p", "1-65535:1-65535/tcp", "busybox", "echo")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -169,7 +161,7 @@ func TestCreateWithiLargePortRange(t *testing.T) {
inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
out, _, err = runCommandWithOutput(inspectCmd)
if err != nil {
- t.Fatalf("out should've been a container id: %s, %v", out, err)
+ c.Fatalf("out should've been a container id: %s, %v", out, err)
}
containers := []struct {
@@ -178,40 +170,38 @@ func TestCreateWithiLargePortRange(t *testing.T) {
}
}{}
if err := json.Unmarshal([]byte(out), &containers); err != nil {
- t.Fatalf("Error inspecting the container: %s", err)
+ c.Fatalf("Error inspecting the container: %s", err)
}
if len(containers) != 1 {
- t.Fatalf("Unexpected container count. Expected 0, received: %d", len(containers))
+ c.Fatalf("Unexpected container count. Expected 0, received: %d", len(containers))
}
- c := containers[0]
- if c.HostConfig == nil {
- t.Fatalf("Expected HostConfig, got none")
+ cont := containers[0]
+ if cont.HostConfig == nil {
+ c.Fatalf("Expected HostConfig, got none")
}
- if len(c.HostConfig.PortBindings) != 65535 {
- t.Fatalf("Expected 65535 ports bindings, got %d", len(c.HostConfig.PortBindings))
+ if len(cont.HostConfig.PortBindings) != 65535 {
+ c.Fatalf("Expected 65535 ports bindings, got %d", len(cont.HostConfig.PortBindings))
}
- for k, v := range c.HostConfig.PortBindings {
+ for k, v := range cont.HostConfig.PortBindings {
if len(v) != 1 {
- t.Fatalf("Expected 1 ports binding, for the port %s but found %s", k, v)
+ c.Fatalf("Expected 1 ports binding, for the port %s but found %s", k, v)
}
if k.Port() != v[0].HostPort {
- t.Fatalf("Expected host port %d to match published port %d", k.Port(), v[0].HostPort)
+ c.Fatalf("Expected host port %d to match published port %d", k.Port(), v[0].HostPort)
}
}
- logDone("create - large port range")
}
// "test123" should be printed by docker create + start
-func TestCreateEchoStdout(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestCreateEchoStdout(c *check.C) {
runCmd := exec.Command(dockerBinary, "create", "busybox", "echo", "test123")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -219,89 +209,84 @@ func TestCreateEchoStdout(t *testing.T) {
runCmd = exec.Command(dockerBinary, "start", "-ai", cleanedContainerID)
out, _, _, err = runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if out != "test123\n" {
- t.Errorf("container should've printed 'test123', got %q", out)
+ c.Errorf("container should've printed 'test123', got %q", out)
}
- logDone("create - echo test123")
}
-func TestCreateVolumesCreated(t *testing.T) {
- testRequires(t, SameHostDaemon)
- defer deleteAllContainers()
+func (s *DockerSuite) TestCreateVolumesCreated(c *check.C) {
+ testRequires(c, SameHostDaemon)
name := "test_create_volume"
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "--name", name, "-v", "/foo", "busybox")); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
dir, err := inspectFieldMap(name, "Volumes", "/foo")
if err != nil {
- t.Fatalf("Error getting volume host path: %q", err)
+ c.Fatalf("Error getting volume host path: %q", err)
}
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
- t.Fatalf("Volume was not created")
+ c.Fatalf("Volume was not created")
}
if err != nil {
- t.Fatalf("Error statting volume host path: %q", err)
+ c.Fatalf("Error statting volume host path: %q", err)
}
- logDone("create - volumes are created")
}
-func TestCreateLabels(t *testing.T) {
+func (s *DockerSuite) TestCreateLabels(c *check.C) {
name := "test_create_labels"
expected := map[string]string{"k1": "v1", "k2": "v2"}
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "--name", name, "-l", "k1=v1", "--label", "k2=v2", "busybox")); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
actual := make(map[string]string)
err := inspectFieldAndMarshall(name, "Config.Labels", &actual)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !reflect.DeepEqual(expected, actual) {
- t.Fatalf("Expected %s got %s", expected, actual)
+ c.Fatalf("Expected %s got %s", expected, actual)
}
-
- deleteAllContainers()
-
- logDone("create - labels")
}
-func TestCreateLabelFromImage(t *testing.T) {
+func (s *DockerSuite) TestCreateLabelFromImage(c *check.C) {
imageName := "testcreatebuildlabel"
- defer deleteImages(imageName)
_, err := buildImage(imageName,
`FROM busybox
LABEL k1=v1 k2=v2`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
name := "test_create_labels_from_image"
expected := map[string]string{"k2": "x", "k3": "v3", "k1": "v1"}
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "--name", name, "-l", "k2=x", "--label", "k3=v3", imageName)); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
actual := make(map[string]string)
err = inspectFieldAndMarshall(name, "Config.Labels", &actual)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !reflect.DeepEqual(expected, actual) {
- t.Fatalf("Expected %s got %s", expected, actual)
+ c.Fatalf("Expected %s got %s", expected, actual)
}
+}
- deleteAllContainers()
-
- logDone("create - labels from image")
+func (s *DockerSuite) TestCreateHostnameWithNumber(c *check.C) {
+ out, _ := dockerCmd(c, "run", "-h", "web.0", "busybox", "hostname")
+ if strings.TrimSpace(out) != "web.0" {
+ c.Fatalf("hostname not set, expected `web.0`, got: %s", out)
+ }
}
diff --git a/integration-cli/docker_cli_daemon_test.go b/integration-cli/docker_cli_daemon_test.go
index 3a10fb004cb21..e099995ad3aed 100644
--- a/integration-cli/docker_cli_daemon_test.go
+++ b/integration-cli/docker_cli_daemon_test.go
@@ -10,144 +10,119 @@ import (
"os/exec"
"path/filepath"
"strings"
- "testing"
"time"
"github.com/docker/libtrust"
+ "github.com/go-check/check"
)
-func TestDaemonRestartWithRunningContainersPorts(t *testing.T) {
- d := NewDaemon(t)
- if err := d.StartWithBusybox(); err != nil {
- t.Fatalf("Could not start daemon with busybox: %v", err)
+func (s *DockerDaemonSuite) TestDaemonRestartWithRunningContainersPorts(c *check.C) {
+ if err := s.d.StartWithBusybox(); err != nil {
+ c.Fatalf("Could not start daemon with busybox: %v", err)
}
- defer d.Stop()
- if out, err := d.Cmd("run", "-d", "--name", "top1", "-p", "1234:80", "--restart", "always", "busybox:latest", "top"); err != nil {
- t.Fatalf("Could not run top1: err=%v\n%s", err, out)
+ if out, err := s.d.Cmd("run", "-d", "--name", "top1", "-p", "1234:80", "--restart", "always", "busybox:latest", "top"); err != nil {
+ c.Fatalf("Could not run top1: err=%v\n%s", err, out)
}
// --restart=no by default
- if out, err := d.Cmd("run", "-d", "--name", "top2", "-p", "80", "busybox:latest", "top"); err != nil {
- t.Fatalf("Could not run top2: err=%v\n%s", err, out)
+ if out, err := s.d.Cmd("run", "-d", "--name", "top2", "-p", "80", "busybox:latest", "top"); err != nil {
+ c.Fatalf("Could not run top2: err=%v\n%s", err, out)
}
testRun := func(m map[string]bool, prefix string) {
var format string
- for c, shouldRun := range m {
- out, err := d.Cmd("ps")
+ for cont, shouldRun := range m {
+ out, err := s.d.Cmd("ps")
if err != nil {
- t.Fatalf("Could not run ps: err=%v\n%q", err, out)
+ c.Fatalf("Could not run ps: err=%v\n%q", err, out)
}
if shouldRun {
format = "%scontainer %q is not running"
} else {
format = "%scontainer %q is running"
}
- if shouldRun != strings.Contains(out, c) {
- t.Fatalf(format, prefix, c)
+ if shouldRun != strings.Contains(out, cont) {
+ c.Fatalf(format, prefix, cont)
}
}
}
testRun(map[string]bool{"top1": true, "top2": true}, "")
- if err := d.Restart(); err != nil {
- t.Fatalf("Could not restart daemon: %v", err)
+ if err := s.d.Restart(); err != nil {
+ c.Fatalf("Could not restart daemon: %v", err)
}
-
testRun(map[string]bool{"top1": true, "top2": false}, "After daemon restart: ")
-
- logDone("daemon - running containers on daemon restart")
}
-func TestDaemonRestartWithVolumesRefs(t *testing.T) {
- d := NewDaemon(t)
- if err := d.StartWithBusybox(); err != nil {
- t.Fatal(err)
+func (s *DockerDaemonSuite) TestDaemonRestartWithVolumesRefs(c *check.C) {
+ if err := s.d.StartWithBusybox(); err != nil {
+ c.Fatal(err)
}
- defer d.Stop()
- if out, err := d.Cmd("run", "-d", "--name", "volrestarttest1", "-v", "/foo", "busybox"); err != nil {
- t.Fatal(err, out)
+ if out, err := s.d.Cmd("run", "-d", "--name", "volrestarttest1", "-v", "/foo", "busybox"); err != nil {
+ c.Fatal(err, out)
}
- if err := d.Restart(); err != nil {
- t.Fatal(err)
+ if err := s.d.Restart(); err != nil {
+ c.Fatal(err)
}
- if _, err := d.Cmd("run", "-d", "--volumes-from", "volrestarttest1", "--name", "volrestarttest2", "busybox", "top"); err != nil {
- t.Fatal(err)
+ if _, err := s.d.Cmd("run", "-d", "--volumes-from", "volrestarttest1", "--name", "volrestarttest2", "busybox", "top"); err != nil {
+ c.Fatal(err)
}
- if out, err := d.Cmd("rm", "-fv", "volrestarttest2"); err != nil {
- t.Fatal(err, out)
+ if out, err := s.d.Cmd("rm", "-fv", "volrestarttest2"); err != nil {
+ c.Fatal(err, out)
}
- v, err := d.Cmd("inspect", "--format", "{{ json .Volumes }}", "volrestarttest1")
+ v, err := s.d.Cmd("inspect", "--format", "{{ json .Volumes }}", "volrestarttest1")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
volumes := make(map[string]string)
json.Unmarshal([]byte(v), &volumes)
if _, err := os.Stat(volumes["/foo"]); err != nil {
- t.Fatalf("Expected volume to exist: %s - %s", volumes["/foo"], err)
+ c.Fatalf("Expected volume to exist: %s - %s", volumes["/foo"], err)
}
-
- logDone("daemon - volume refs are restored")
}
-func TestDaemonStartIptablesFalse(t *testing.T) {
- d := NewDaemon(t)
- if err := d.Start("--iptables=false"); err != nil {
- t.Fatalf("we should have been able to start the daemon with passing iptables=false: %v", err)
+func (s *DockerDaemonSuite) TestDaemonStartIptablesFalse(c *check.C) {
+ if err := s.d.Start("--iptables=false"); err != nil {
+ c.Fatalf("we should have been able to start the daemon with passing iptables=false: %v", err)
}
- d.Stop()
-
- logDone("daemon - started daemon with iptables=false")
}
// Issue #8444: If docker0 bridge is modified (intentionally or unintentionally) and
// no longer has an IP associated, we should gracefully handle that case and associate
// an IP with it rather than fail daemon start
-func TestDaemonStartBridgeWithoutIPAssociation(t *testing.T) {
- d := NewDaemon(t)
+func (s *DockerDaemonSuite) TestDaemonStartBridgeWithoutIPAssociation(c *check.C) {
// rather than depending on brctl commands to verify docker0 is created and up
// let's start the daemon and stop it, and then make a modification to run the
// actual test
- if err := d.Start(); err != nil {
- t.Fatalf("Could not start daemon: %v", err)
+ if err := s.d.Start(); err != nil {
+ c.Fatalf("Could not start daemon: %v", err)
}
- if err := d.Stop(); err != nil {
- t.Fatalf("Could not stop daemon: %v", err)
+ if err := s.d.Stop(); err != nil {
+ c.Fatalf("Could not stop daemon: %v", err)
}
// now we will remove the ip from docker0 and then try starting the daemon
ipCmd := exec.Command("ip", "addr", "flush", "dev", "docker0")
stdout, stderr, _, err := runCommandWithStdoutStderr(ipCmd)
if err != nil {
- t.Fatalf("failed to remove docker0 IP association: %v, stdout: %q, stderr: %q", err, stdout, stderr)
+ c.Fatalf("failed to remove docker0 IP association: %v, stdout: %q, stderr: %q", err, stdout, stderr)
}
- if err := d.Start(); err != nil {
+ if err := s.d.Start(); err != nil {
warning := "**WARNING: Docker bridge network in bad state--delete docker0 bridge interface to fix"
- t.Fatalf("Could not start daemon when docker0 has no IP address: %v\n%s", err, warning)
+ c.Fatalf("Could not start daemon when docker0 has no IP address: %v\n%s", err, warning)
}
-
- // cleanup - stop the daemon if test passed
- if err := d.Stop(); err != nil {
- t.Fatalf("Could not stop daemon: %v", err)
- }
-
- logDone("daemon - successful daemon start when bridge has no IP association")
}
-func TestDaemonIptablesClean(t *testing.T) {
- defer deleteAllContainers()
-
- d := NewDaemon(t)
- if err := d.StartWithBusybox(); err != nil {
- t.Fatalf("Could not start daemon with busybox: %v", err)
+func (s *DockerDaemonSuite) TestDaemonIptablesClean(c *check.C) {
+ if err := s.d.StartWithBusybox(); err != nil {
+ c.Fatalf("Could not start daemon with busybox: %v", err)
}
- defer d.Stop()
- if out, err := d.Cmd("run", "-d", "--name", "top", "-p", "80", "busybox:latest", "top"); err != nil {
- t.Fatalf("Could not run top: %s, %v", out, err)
+ if out, err := s.d.Cmd("run", "-d", "--name", "top", "-p", "80", "busybox:latest", "top"); err != nil {
+ c.Fatalf("Could not run top: %s, %v", out, err)
}
// get output from iptables with container running
@@ -155,42 +130,36 @@ func TestDaemonIptablesClean(t *testing.T) {
ipTablesCmd := exec.Command("iptables", "-nvL")
out, _, err := runCommandWithOutput(ipTablesCmd)
if err != nil {
- t.Fatalf("Could not run iptables -nvL: %s, %v", out, err)
+ c.Fatalf("Could not run iptables -nvL: %s, %v", out, err)
}
if !strings.Contains(out, ipTablesSearchString) {
- t.Fatalf("iptables output should have contained %q, but was %q", ipTablesSearchString, out)
+ c.Fatalf("iptables output should have contained %q, but was %q", ipTablesSearchString, out)
}
- if err := d.Stop(); err != nil {
- t.Fatalf("Could not stop daemon: %v", err)
+ if err := s.d.Stop(); err != nil {
+ c.Fatalf("Could not stop daemon: %v", err)
}
// get output from iptables after restart
ipTablesCmd = exec.Command("iptables", "-nvL")
out, _, err = runCommandWithOutput(ipTablesCmd)
if err != nil {
- t.Fatalf("Could not run iptables -nvL: %s, %v", out, err)
+ c.Fatalf("Could not run iptables -nvL: %s, %v", out, err)
}
if strings.Contains(out, ipTablesSearchString) {
- t.Fatalf("iptables output should not have contained %q, but was %q", ipTablesSearchString, out)
+ c.Fatalf("iptables output should not have contained %q, but was %q", ipTablesSearchString, out)
}
-
- logDone("daemon - run,iptables - iptables rules cleaned after daemon restart")
}
-func TestDaemonIptablesCreate(t *testing.T) {
- defer deleteAllContainers()
-
- d := NewDaemon(t)
- if err := d.StartWithBusybox(); err != nil {
- t.Fatalf("Could not start daemon with busybox: %v", err)
+func (s *DockerDaemonSuite) TestDaemonIptablesCreate(c *check.C) {
+ if err := s.d.StartWithBusybox(); err != nil {
+ c.Fatalf("Could not start daemon with busybox: %v", err)
}
- defer d.Stop()
- if out, err := d.Cmd("run", "-d", "--name", "top", "--restart=always", "-p", "80", "busybox:latest", "top"); err != nil {
- t.Fatalf("Could not run top: %s, %v", out, err)
+ if out, err := s.d.Cmd("run", "-d", "--name", "top", "--restart=always", "-p", "80", "busybox:latest", "top"); err != nil {
+ c.Fatalf("Could not run top: %s, %v", out, err)
}
// get output from iptables with container running
@@ -198,101 +167,94 @@ func TestDaemonIptablesCreate(t *testing.T) {
ipTablesCmd := exec.Command("iptables", "-nvL")
out, _, err := runCommandWithOutput(ipTablesCmd)
if err != nil {
- t.Fatalf("Could not run iptables -nvL: %s, %v", out, err)
+ c.Fatalf("Could not run iptables -nvL: %s, %v", out, err)
}
if !strings.Contains(out, ipTablesSearchString) {
- t.Fatalf("iptables output should have contained %q, but was %q", ipTablesSearchString, out)
+ c.Fatalf("iptables output should have contained %q, but was %q", ipTablesSearchString, out)
}
- if err := d.Restart(); err != nil {
- t.Fatalf("Could not restart daemon: %v", err)
+ if err := s.d.Restart(); err != nil {
+ c.Fatalf("Could not restart daemon: %v", err)
}
// make sure the container is not running
- runningOut, err := d.Cmd("inspect", "--format='{{.State.Running}}'", "top")
+ runningOut, err := s.d.Cmd("inspect", "--format='{{.State.Running}}'", "top")
if err != nil {
- t.Fatalf("Could not inspect on container: %s, %v", out, err)
+ c.Fatalf("Could not inspect on container: %s, %v", out, err)
}
if strings.TrimSpace(runningOut) != "true" {
- t.Fatalf("Container should have been restarted after daemon restart. Status running should have been true but was: %q", strings.TrimSpace(runningOut))
+ c.Fatalf("Container should have been restarted after daemon restart. Status running should have been true but was: %q", strings.TrimSpace(runningOut))
}
// get output from iptables after restart
ipTablesCmd = exec.Command("iptables", "-nvL")
out, _, err = runCommandWithOutput(ipTablesCmd)
if err != nil {
- t.Fatalf("Could not run iptables -nvL: %s, %v", out, err)
+ c.Fatalf("Could not run iptables -nvL: %s, %v", out, err)
}
if !strings.Contains(out, ipTablesSearchString) {
- t.Fatalf("iptables output after restart should have contained %q, but was %q", ipTablesSearchString, out)
+ c.Fatalf("iptables output after restart should have contained %q, but was %q", ipTablesSearchString, out)
}
-
- logDone("daemon - run,iptables - iptables rules for always restarted container created after daemon restart")
}
-func TestDaemonLoggingLevel(t *testing.T) {
- d := NewDaemon(t)
-
- if err := d.Start("--log-level=bogus"); err == nil {
- t.Fatal("Daemon should not have been able to start")
- }
+func (s *DockerDaemonSuite) TestDaemonLogLevelWrong(c *check.C) {
+ c.Assert(s.d.Start("--log-level=bogus"), check.NotNil, check.Commentf("Daemon shouldn't start with wrong log level"))
+}
- d = NewDaemon(t)
- if err := d.Start("--log-level=debug"); err != nil {
- t.Fatal(err)
+func (s *DockerDaemonSuite) TestDaemonLogLevelDebug(c *check.C) {
+ if err := s.d.Start("--log-level=debug"); err != nil {
+ c.Fatal(err)
}
- d.Stop()
- content, _ := ioutil.ReadFile(d.logFile.Name())
+ content, _ := ioutil.ReadFile(s.d.logFile.Name())
if !strings.Contains(string(content), `level=debug`) {
- t.Fatalf(`Missing level="debug" in log file:\n%s`, string(content))
+ c.Fatalf(`Missing level="debug" in log file:\n%s`, string(content))
}
+}
- d = NewDaemon(t)
- if err := d.Start("--log-level=fatal"); err != nil {
- t.Fatal(err)
+func (s *DockerDaemonSuite) TestDaemonLogLevelFatal(c *check.C) {
+ // we creating new daemons to create new logFile
+ if err := s.d.Start("--log-level=fatal"); err != nil {
+ c.Fatal(err)
}
- d.Stop()
- content, _ = ioutil.ReadFile(d.logFile.Name())
+ content, _ := ioutil.ReadFile(s.d.logFile.Name())
if strings.Contains(string(content), `level=debug`) {
- t.Fatalf(`Should not have level="debug" in log file:\n%s`, string(content))
+ c.Fatalf(`Should not have level="debug" in log file:\n%s`, string(content))
}
+}
- d = NewDaemon(t)
- if err := d.Start("-D"); err != nil {
- t.Fatal(err)
+func (s *DockerDaemonSuite) TestDaemonFlagD(c *check.C) {
+ if err := s.d.Start("-D"); err != nil {
+ c.Fatal(err)
}
- d.Stop()
- content, _ = ioutil.ReadFile(d.logFile.Name())
+ content, _ := ioutil.ReadFile(s.d.logFile.Name())
if !strings.Contains(string(content), `level=debug`) {
- t.Fatalf(`Missing level="debug" in log file using -D:\n%s`, string(content))
+ c.Fatalf(`Missing level="debug" in log file using -D:\n%s`, string(content))
}
+}
- d = NewDaemon(t)
- if err := d.Start("--debug"); err != nil {
- t.Fatal(err)
+func (s *DockerDaemonSuite) TestDaemonFlagDebug(c *check.C) {
+ if err := s.d.Start("--debug"); err != nil {
+ c.Fatal(err)
}
- d.Stop()
- content, _ = ioutil.ReadFile(d.logFile.Name())
+ content, _ := ioutil.ReadFile(s.d.logFile.Name())
if !strings.Contains(string(content), `level=debug`) {
- t.Fatalf(`Missing level="debug" in log file using --debug:\n%s`, string(content))
+ c.Fatalf(`Missing level="debug" in log file using --debug:\n%s`, string(content))
}
+}
- d = NewDaemon(t)
- if err := d.Start("--debug", "--log-level=fatal"); err != nil {
- t.Fatal(err)
+func (s *DockerDaemonSuite) TestDaemonFlagDebugLogLevelFatal(c *check.C) {
+ if err := s.d.Start("--debug", "--log-level=fatal"); err != nil {
+ c.Fatal(err)
}
- d.Stop()
- content, _ = ioutil.ReadFile(d.logFile.Name())
+ content, _ := ioutil.ReadFile(s.d.logFile.Name())
if !strings.Contains(string(content), `level=debug`) {
- t.Fatalf(`Missing level="debug" in log file when using both --debug and --log-level=fatal:\n%s`, string(content))
+ c.Fatalf(`Missing level="debug" in log file when using both --debug and --log-level=fatal:\n%s`, string(content))
}
-
- logDone("daemon - Logging Level")
}
-func TestDaemonAllocatesListeningPort(t *testing.T) {
+func (s *DockerDaemonSuite) TestDaemonAllocatesListeningPort(c *check.C) {
listeningPorts := [][]string{
{"0.0.0.0", "0.0.0.0", "5678"},
{"127.0.0.1", "127.0.0.1", "1234"},
@@ -304,320 +266,283 @@ func TestDaemonAllocatesListeningPort(t *testing.T) {
cmdArgs = append(cmdArgs, "--host", fmt.Sprintf("tcp://%s:%s", hostDirective[0], hostDirective[2]))
}
- d := NewDaemon(t)
- if err := d.StartWithBusybox(cmdArgs...); err != nil {
- t.Fatalf("Could not start daemon with busybox: %v", err)
+ if err := s.d.StartWithBusybox(cmdArgs...); err != nil {
+ c.Fatalf("Could not start daemon with busybox: %v", err)
}
- defer d.Stop()
for _, hostDirective := range listeningPorts {
- output, err := d.Cmd("run", "-p", fmt.Sprintf("%s:%s:80", hostDirective[1], hostDirective[2]), "busybox", "true")
+ output, err := s.d.Cmd("run", "-p", fmt.Sprintf("%s:%s:80", hostDirective[1], hostDirective[2]), "busybox", "true")
if err == nil {
- t.Fatalf("Container should not start, expected port already allocated error: %q", output)
+ c.Fatalf("Container should not start, expected port already allocated error: %q", output)
} else if !strings.Contains(output, "port is already allocated") {
- t.Fatalf("Expected port is already allocated error: %q", output)
+ c.Fatalf("Expected port is already allocated error: %q", output)
}
}
-
- logDone("daemon - daemon listening port is allocated")
}
// #9629
-func TestDaemonVolumesBindsRefs(t *testing.T) {
- d := NewDaemon(t)
-
- if err := d.StartWithBusybox(); err != nil {
- t.Fatal(err)
+func (s *DockerDaemonSuite) TestDaemonVolumesBindsRefs(c *check.C) {
+ if err := s.d.StartWithBusybox(); err != nil {
+ c.Fatal(err)
}
- defer d.Stop()
tmp, err := ioutil.TempDir(os.TempDir(), "")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(tmp)
if err := ioutil.WriteFile(tmp+"/test", []byte("testing"), 0655); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- if out, err := d.Cmd("create", "-v", tmp+":/foo", "--name=voltest", "busybox"); err != nil {
- t.Fatal(err, out)
+ if out, err := s.d.Cmd("create", "-v", tmp+":/foo", "--name=voltest", "busybox"); err != nil {
+ c.Fatal(err, out)
}
- if err := d.Restart(); err != nil {
- t.Fatal(err)
+ if err := s.d.Restart(); err != nil {
+ c.Fatal(err)
}
- if out, err := d.Cmd("run", "--volumes-from=voltest", "--name=consumer", "busybox", "/bin/sh", "-c", "[ -f /foo/test ]"); err != nil {
- t.Fatal(err, out)
+ if out, err := s.d.Cmd("run", "--volumes-from=voltest", "--name=consumer", "busybox", "/bin/sh", "-c", "[ -f /foo/test ]"); err != nil {
+ c.Fatal(err, out)
}
-
- logDone("daemon - bind refs in data-containers survive daemon restart")
}
-func TestDaemonKeyGeneration(t *testing.T) {
+func (s *DockerDaemonSuite) TestDaemonKeyGeneration(c *check.C) {
// TODO: skip or update for Windows daemon
os.Remove("/etc/docker/key.json")
- d := NewDaemon(t)
- if err := d.Start(); err != nil {
- t.Fatalf("Could not start daemon: %v", err)
+ if err := s.d.Start(); err != nil {
+ c.Fatalf("Could not start daemon: %v", err)
}
- d.Stop()
+ s.d.Stop()
k, err := libtrust.LoadKeyFile("/etc/docker/key.json")
if err != nil {
- t.Fatalf("Error opening key file")
+ c.Fatalf("Error opening key file")
}
kid := k.KeyID()
// Test Key ID is a valid fingerprint (e.g. QQXN:JY5W:TBXI:MK3X:GX6P:PD5D:F56N:NHCS:LVRZ:JA46:R24J:XEFF)
if len(kid) != 59 {
- t.Fatalf("Bad key ID: %s", kid)
+ c.Fatalf("Bad key ID: %s", kid)
}
-
- logDone("daemon - key generation")
}
-func TestDaemonKeyMigration(t *testing.T) {
+func (s *DockerDaemonSuite) TestDaemonKeyMigration(c *check.C) {
// TODO: skip or update for Windows daemon
os.Remove("/etc/docker/key.json")
k1, err := libtrust.GenerateECP256PrivateKey()
if err != nil {
- t.Fatalf("Error generating private key: %s", err)
+ c.Fatalf("Error generating private key: %s", err)
}
if err := os.MkdirAll(filepath.Join(os.Getenv("HOME"), ".docker"), 0755); err != nil {
- t.Fatalf("Error creating .docker directory: %s", err)
+ c.Fatalf("Error creating .docker directory: %s", err)
}
if err := libtrust.SaveKey(filepath.Join(os.Getenv("HOME"), ".docker", "key.json"), k1); err != nil {
- t.Fatalf("Error saving private key: %s", err)
+ c.Fatalf("Error saving private key: %s", err)
}
- d := NewDaemon(t)
- if err := d.Start(); err != nil {
- t.Fatalf("Could not start daemon: %v", err)
+ if err := s.d.Start(); err != nil {
+ c.Fatalf("Could not start daemon: %v", err)
}
- d.Stop()
+ s.d.Stop()
k2, err := libtrust.LoadKeyFile("/etc/docker/key.json")
if err != nil {
- t.Fatalf("Error opening key file")
+ c.Fatalf("Error opening key file")
}
if k1.KeyID() != k2.KeyID() {
- t.Fatalf("Key not migrated")
+ c.Fatalf("Key not migrated")
}
-
- logDone("daemon - key migration")
}
// Simulate an older daemon (pre 1.3) coming up with volumes specified in containers
// without corresponding volume json
-func TestDaemonUpgradeWithVolumes(t *testing.T) {
- d := NewDaemon(t)
-
+func (s *DockerDaemonSuite) TestDaemonUpgradeWithVolumes(c *check.C) {
graphDir := filepath.Join(os.TempDir(), "docker-test")
defer os.RemoveAll(graphDir)
- if err := d.StartWithBusybox("-g", graphDir); err != nil {
- t.Fatal(err)
+ if err := s.d.StartWithBusybox("-g", graphDir); err != nil {
+ c.Fatal(err)
}
- defer d.Stop()
tmpDir := filepath.Join(os.TempDir(), "test")
defer os.RemoveAll(tmpDir)
- if out, err := d.Cmd("create", "-v", tmpDir+":/foo", "--name=test", "busybox"); err != nil {
- t.Fatal(err, out)
+ if out, err := s.d.Cmd("create", "-v", tmpDir+":/foo", "--name=test", "busybox"); err != nil {
+ c.Fatal(err, out)
}
- if err := d.Stop(); err != nil {
- t.Fatal(err)
+ if err := s.d.Stop(); err != nil {
+ c.Fatal(err)
}
// Remove this since we're expecting the daemon to re-create it too
if err := os.RemoveAll(tmpDir); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
configDir := filepath.Join(graphDir, "volumes")
if err := os.RemoveAll(configDir); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- if err := d.Start("-g", graphDir); err != nil {
- t.Fatal(err)
+ if err := s.d.Start("-g", graphDir); err != nil {
+ c.Fatal(err)
}
if _, err := os.Stat(tmpDir); os.IsNotExist(err) {
- t.Fatalf("expected volume path %s to exist but it does not", tmpDir)
+ c.Fatalf("expected volume path %s to exist but it does not", tmpDir)
}
dir, err := ioutil.ReadDir(configDir)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if len(dir) == 0 {
- t.Fatalf("expected volumes config dir to contain data for new volume")
+ c.Fatalf("expected volumes config dir to contain data for new volume")
}
// Now with just removing the volume config and not the volume data
- if err := d.Stop(); err != nil {
- t.Fatal(err)
+ if err := s.d.Stop(); err != nil {
+ c.Fatal(err)
}
if err := os.RemoveAll(configDir); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- if err := d.Start("-g", graphDir); err != nil {
- t.Fatal(err)
+ if err := s.d.Start("-g", graphDir); err != nil {
+ c.Fatal(err)
}
dir, err = ioutil.ReadDir(configDir)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if len(dir) == 0 {
- t.Fatalf("expected volumes config dir to contain data for new volume")
+ c.Fatalf("expected volumes config dir to contain data for new volume")
}
-
- logDone("daemon - volumes from old(pre 1.3) daemon work")
}
// GH#11320 - verify that the daemon exits on failure properly
// Note that this explicitly tests the conflict of {-b,--bridge} and {--bip} options as the means
// to get a daemon init failure; no other tests for -b/--bip conflict are therefore required
-func TestDaemonExitOnFailure(t *testing.T) {
- d := NewDaemon(t)
- defer d.Stop()
-
+func (s *DockerDaemonSuite) TestDaemonExitOnFailure(c *check.C) {
//attempt to start daemon with incorrect flags (we know -b and --bip conflict)
- if err := d.Start("--bridge", "nosuchbridge", "--bip", "1.1.1.1"); err != nil {
+ if err := s.d.Start("--bridge", "nosuchbridge", "--bip", "1.1.1.1"); err != nil {
//verify we got the right error
if !strings.Contains(err.Error(), "Daemon exited and never started") {
- t.Fatalf("Expected daemon not to start, got %v", err)
+ c.Fatalf("Expected daemon not to start, got %v", err)
}
// look in the log and make sure we got the message that daemon is shutting down
- runCmd := exec.Command("grep", "Shutting down daemon due to", d.LogfileName())
+ runCmd := exec.Command("grep", "Error starting daemon", s.d.LogfileName())
if out, _, err := runCommandWithOutput(runCmd); err != nil {
- t.Fatalf("Expected 'shutting down daemon due to error' message; but doesn't exist in log: %q, err: %v", out, err)
+ c.Fatalf("Expected 'Error starting daemon' message; but doesn't exist in log: %q, err: %v", out, err)
}
} else {
//if we didn't get an error and the daemon is running, this is a failure
- d.Stop()
- t.Fatal("Conflicting options should cause the daemon to error out with a failure")
+ c.Fatal("Conflicting options should cause the daemon to error out with a failure")
}
-
- logDone("daemon - verify no start on daemon init errors")
}
-func TestDaemonUlimitDefaults(t *testing.T) {
- testRequires(t, NativeExecDriver)
- d := NewDaemon(t)
+func (s *DockerDaemonSuite) TestDaemonUlimitDefaults(c *check.C) {
+ testRequires(c, NativeExecDriver)
- if err := d.StartWithBusybox("--default-ulimit", "nofile=42:42", "--default-ulimit", "nproc=1024:1024"); err != nil {
- t.Fatal(err)
+ if err := s.d.StartWithBusybox("--default-ulimit", "nofile=42:42", "--default-ulimit", "nproc=1024:1024"); err != nil {
+ c.Fatal(err)
}
- defer d.Stop()
- out, err := d.Cmd("run", "--ulimit", "nproc=2048", "--name=test", "busybox", "/bin/sh", "-c", "echo $(ulimit -n); echo $(ulimit -p)")
+ out, err := s.d.Cmd("run", "--ulimit", "nproc=2048", "--name=test", "busybox", "/bin/sh", "-c", "echo $(ulimit -n); echo $(ulimit -p)")
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
outArr := strings.Split(out, "\n")
if len(outArr) < 2 {
- t.Fatalf("got unexpected output: %s", out)
+ c.Fatalf("got unexpected output: %s", out)
}
nofile := strings.TrimSpace(outArr[0])
nproc := strings.TrimSpace(outArr[1])
if nofile != "42" {
- t.Fatalf("expected `ulimit -n` to be `42`, got: %s", nofile)
+ c.Fatalf("expected `ulimit -n` to be `42`, got: %s", nofile)
}
if nproc != "2048" {
- t.Fatalf("exepcted `ulimit -p` to be 2048, got: %s", nproc)
+ c.Fatalf("exepcted `ulimit -p` to be 2048, got: %s", nproc)
}
// Now restart daemon with a new default
- if err := d.Restart("--default-ulimit", "nofile=43"); err != nil {
- t.Fatal(err)
+ if err := s.d.Restart("--default-ulimit", "nofile=43"); err != nil {
+ c.Fatal(err)
}
- out, err = d.Cmd("start", "-a", "test")
+ out, err = s.d.Cmd("start", "-a", "test")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
outArr = strings.Split(out, "\n")
if len(outArr) < 2 {
- t.Fatalf("got unexpected output: %s", out)
+ c.Fatalf("got unexpected output: %s", out)
}
nofile = strings.TrimSpace(outArr[0])
nproc = strings.TrimSpace(outArr[1])
if nofile != "43" {
- t.Fatalf("expected `ulimit -n` to be `43`, got: %s", nofile)
+ c.Fatalf("expected `ulimit -n` to be `43`, got: %s", nofile)
}
if nproc != "2048" {
- t.Fatalf("exepcted `ulimit -p` to be 2048, got: %s", nproc)
+ c.Fatalf("exepcted `ulimit -p` to be 2048, got: %s", nproc)
}
-
- logDone("daemon - default ulimits are applied")
}
// #11315
-func TestDaemonRestartRenameContainer(t *testing.T) {
- d := NewDaemon(t)
- if err := d.StartWithBusybox(); err != nil {
- t.Fatal(err)
+func (s *DockerDaemonSuite) TestDaemonRestartRenameContainer(c *check.C) {
+ if err := s.d.StartWithBusybox(); err != nil {
+ c.Fatal(err)
}
- defer d.Stop()
- if out, err := d.Cmd("run", "--name=test", "busybox"); err != nil {
- t.Fatal(err, out)
+ if out, err := s.d.Cmd("run", "--name=test", "busybox"); err != nil {
+ c.Fatal(err, out)
}
- if out, err := d.Cmd("rename", "test", "test2"); err != nil {
- t.Fatal(err, out)
+ if out, err := s.d.Cmd("rename", "test", "test2"); err != nil {
+ c.Fatal(err, out)
}
- if err := d.Restart(); err != nil {
- t.Fatal(err)
+ if err := s.d.Restart(); err != nil {
+ c.Fatal(err)
}
- if out, err := d.Cmd("start", "test2"); err != nil {
- t.Fatal(err, out)
+ if out, err := s.d.Cmd("start", "test2"); err != nil {
+ c.Fatal(err, out)
}
-
- logDone("daemon - rename persists through daemon restart")
}
-func TestDaemonLoggingDriverDefault(t *testing.T) {
- d := NewDaemon(t)
-
- if err := d.StartWithBusybox(); err != nil {
- t.Fatal(err)
+func (s *DockerDaemonSuite) TestDaemonLoggingDriverDefault(c *check.C) {
+ if err := s.d.StartWithBusybox(); err != nil {
+ c.Fatal(err)
}
- defer d.Stop()
- out, err := d.Cmd("run", "-d", "busybox", "echo", "testline")
+ out, err := s.d.Cmd("run", "-d", "busybox", "echo", "testline")
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
id := strings.TrimSpace(out)
- if out, err := d.Cmd("wait", id); err != nil {
- t.Fatal(out, err)
+ if out, err := s.d.Cmd("wait", id); err != nil {
+ c.Fatal(out, err)
}
- logPath := filepath.Join(d.folder, "graph", "containers", id, id+"-json.log")
+ logPath := filepath.Join(s.d.folder, "graph", "containers", id, id+"-json.log")
if _, err := os.Stat(logPath); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
f, err := os.Open(logPath)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
var res struct {
Log string `json:"log"`
@@ -625,95 +550,83 @@ func TestDaemonLoggingDriverDefault(t *testing.T) {
Time time.Time `json:"time"`
}
if err := json.NewDecoder(f).Decode(&res); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res.Log != "testline\n" {
- t.Fatalf("Unexpected log line: %q, expected: %q", res.Log, "testline\n")
+ c.Fatalf("Unexpected log line: %q, expected: %q", res.Log, "testline\n")
}
if res.Stream != "stdout" {
- t.Fatalf("Unexpected stream: %q, expected: %q", res.Stream, "stdout")
+ c.Fatalf("Unexpected stream: %q, expected: %q", res.Stream, "stdout")
}
if !time.Now().After(res.Time) {
- t.Fatalf("Log time %v in future", res.Time)
+ c.Fatalf("Log time %v in future", res.Time)
}
- logDone("daemon - default 'json-file' logging driver")
}
-func TestDaemonLoggingDriverDefaultOverride(t *testing.T) {
- d := NewDaemon(t)
-
- if err := d.StartWithBusybox(); err != nil {
- t.Fatal(err)
+func (s *DockerDaemonSuite) TestDaemonLoggingDriverDefaultOverride(c *check.C) {
+ if err := s.d.StartWithBusybox(); err != nil {
+ c.Fatal(err)
}
- defer d.Stop()
- out, err := d.Cmd("run", "-d", "--log-driver=none", "busybox", "echo", "testline")
+ out, err := s.d.Cmd("run", "-d", "--log-driver=none", "busybox", "echo", "testline")
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
id := strings.TrimSpace(out)
- if out, err := d.Cmd("wait", id); err != nil {
- t.Fatal(out, err)
+ if out, err := s.d.Cmd("wait", id); err != nil {
+ c.Fatal(out, err)
}
- logPath := filepath.Join(d.folder, "graph", "containers", id, id+"-json.log")
+ logPath := filepath.Join(s.d.folder, "graph", "containers", id, id+"-json.log")
if _, err := os.Stat(logPath); err == nil || !os.IsNotExist(err) {
- t.Fatalf("%s shouldn't exits, error on Stat: %s", logPath, err)
+ c.Fatalf("%s shouldn't exits, error on Stat: %s", logPath, err)
}
- logDone("daemon - default logging driver override in run")
}
-func TestDaemonLoggingDriverNone(t *testing.T) {
- d := NewDaemon(t)
-
- if err := d.StartWithBusybox("--log-driver=none"); err != nil {
- t.Fatal(err)
+func (s *DockerDaemonSuite) TestDaemonLoggingDriverNone(c *check.C) {
+ if err := s.d.StartWithBusybox("--log-driver=none"); err != nil {
+ c.Fatal(err)
}
- defer d.Stop()
- out, err := d.Cmd("run", "-d", "busybox", "echo", "testline")
+ out, err := s.d.Cmd("run", "-d", "busybox", "echo", "testline")
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
id := strings.TrimSpace(out)
- if out, err := d.Cmd("wait", id); err != nil {
- t.Fatal(out, err)
+ if out, err := s.d.Cmd("wait", id); err != nil {
+ c.Fatal(out, err)
}
- logPath := filepath.Join(d.folder, "graph", "containers", id, id+"-json.log")
+ logPath := filepath.Join(s.d.folder, "graph", "containers", id, id+"-json.log")
if _, err := os.Stat(logPath); err == nil || !os.IsNotExist(err) {
- t.Fatalf("%s shouldn't exits, error on Stat: %s", logPath, err)
+ c.Fatalf("%s shouldn't exits, error on Stat: %s", logPath, err)
}
- logDone("daemon - 'none' logging driver")
}
-func TestDaemonLoggingDriverNoneOverride(t *testing.T) {
- d := NewDaemon(t)
-
- if err := d.StartWithBusybox("--log-driver=none"); err != nil {
- t.Fatal(err)
+func (s *DockerDaemonSuite) TestDaemonLoggingDriverNoneOverride(c *check.C) {
+ if err := s.d.StartWithBusybox("--log-driver=none"); err != nil {
+ c.Fatal(err)
}
- defer d.Stop()
- out, err := d.Cmd("run", "-d", "--log-driver=json-file", "busybox", "echo", "testline")
+ out, err := s.d.Cmd("run", "-d", "--log-driver=json-file", "busybox", "echo", "testline")
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
id := strings.TrimSpace(out)
- if out, err := d.Cmd("wait", id); err != nil {
- t.Fatal(out, err)
+ if out, err := s.d.Cmd("wait", id); err != nil {
+ c.Fatal(out, err)
}
- logPath := filepath.Join(d.folder, "graph", "containers", id, id+"-json.log")
+ logPath := filepath.Join(s.d.folder, "graph", "containers", id, id+"-json.log")
if _, err := os.Stat(logPath); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
f, err := os.Open(logPath)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
var res struct {
Log string `json:"log"`
@@ -721,121 +634,107 @@ func TestDaemonLoggingDriverNoneOverride(t *testing.T) {
Time time.Time `json:"time"`
}
if err := json.NewDecoder(f).Decode(&res); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res.Log != "testline\n" {
- t.Fatalf("Unexpected log line: %q, expected: %q", res.Log, "testline\n")
+ c.Fatalf("Unexpected log line: %q, expected: %q", res.Log, "testline\n")
}
if res.Stream != "stdout" {
- t.Fatalf("Unexpected stream: %q, expected: %q", res.Stream, "stdout")
+ c.Fatalf("Unexpected stream: %q, expected: %q", res.Stream, "stdout")
}
if !time.Now().After(res.Time) {
- t.Fatalf("Log time %v in future", res.Time)
+ c.Fatalf("Log time %v in future", res.Time)
}
- logDone("daemon - 'none' logging driver override in run")
}
-func TestDaemonLoggingDriverNoneLogsError(t *testing.T) {
- d := NewDaemon(t)
-
- if err := d.StartWithBusybox("--log-driver=none"); err != nil {
- t.Fatal(err)
+func (s *DockerDaemonSuite) TestDaemonLoggingDriverNoneLogsError(c *check.C) {
+ if err := s.d.StartWithBusybox("--log-driver=none"); err != nil {
+ c.Fatal(err)
}
- defer d.Stop()
- out, err := d.Cmd("run", "-d", "busybox", "echo", "testline")
+ out, err := s.d.Cmd("run", "-d", "busybox", "echo", "testline")
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
id := strings.TrimSpace(out)
- out, err = d.Cmd("logs", id)
+ out, err = s.d.Cmd("logs", id)
if err == nil {
- t.Fatalf("Logs should fail with \"none\" driver")
+ c.Fatalf("Logs should fail with \"none\" driver")
}
if !strings.Contains(out, `\"logs\" command is supported only for \"json-file\" logging driver`) {
- t.Fatalf("There should be error about non-json-file driver, got %s", out)
+ c.Fatalf("There should be error about non-json-file driver, got %s", out)
}
- logDone("daemon - logs not available for non-json-file drivers")
}
-func TestDaemonDots(t *testing.T) {
- defer deleteAllContainers()
- d := NewDaemon(t)
- if err := d.StartWithBusybox(); err != nil {
- t.Fatal(err)
+func (s *DockerDaemonSuite) TestDaemonDots(c *check.C) {
+ if err := s.d.StartWithBusybox(); err != nil {
+ c.Fatal(err)
}
- defer d.Stop()
// Now create 4 containers
- if _, err := d.Cmd("create", "busybox"); err != nil {
- t.Fatalf("Error creating container: %q", err)
+ if _, err := s.d.Cmd("create", "busybox"); err != nil {
+ c.Fatalf("Error creating container: %q", err)
}
- if _, err := d.Cmd("create", "busybox"); err != nil {
- t.Fatalf("Error creating container: %q", err)
+ if _, err := s.d.Cmd("create", "busybox"); err != nil {
+ c.Fatalf("Error creating container: %q", err)
}
- if _, err := d.Cmd("create", "busybox"); err != nil {
- t.Fatalf("Error creating container: %q", err)
+ if _, err := s.d.Cmd("create", "busybox"); err != nil {
+ c.Fatalf("Error creating container: %q", err)
}
- if _, err := d.Cmd("create", "busybox"); err != nil {
- t.Fatalf("Error creating container: %q", err)
+ if _, err := s.d.Cmd("create", "busybox"); err != nil {
+ c.Fatalf("Error creating container: %q", err)
}
- d.Stop()
+ s.d.Stop()
- d.Start("--log-level=debug")
- d.Stop()
- content, _ := ioutil.ReadFile(d.logFile.Name())
+ s.d.Start("--log-level=debug")
+ s.d.Stop()
+ content, _ := ioutil.ReadFile(s.d.logFile.Name())
if strings.Contains(string(content), "....") {
- t.Fatalf("Debug level should not have ....\n%s", string(content))
+ c.Fatalf("Debug level should not have ....\n%s", string(content))
}
- d.Start("--log-level=error")
- d.Stop()
- content, _ = ioutil.ReadFile(d.logFile.Name())
+ s.d.Start("--log-level=error")
+ s.d.Stop()
+ content, _ = ioutil.ReadFile(s.d.logFile.Name())
if strings.Contains(string(content), "....") {
- t.Fatalf("Error level should not have ....\n%s", string(content))
+ c.Fatalf("Error level should not have ....\n%s", string(content))
}
- d.Start("--log-level=info")
- d.Stop()
- content, _ = ioutil.ReadFile(d.logFile.Name())
+ s.d.Start("--log-level=info")
+ s.d.Stop()
+ content, _ = ioutil.ReadFile(s.d.logFile.Name())
if !strings.Contains(string(content), "....") {
- t.Fatalf("Info level should have ....\n%s", string(content))
+ c.Fatalf("Info level should have ....\n%s", string(content))
}
-
- logDone("daemon - test dots on INFO")
}
-func TestDaemonUnixSockCleanedUp(t *testing.T) {
- d := NewDaemon(t)
+func (s *DockerDaemonSuite) TestDaemonUnixSockCleanedUp(c *check.C) {
dir, err := ioutil.TempDir("", "socket-cleanup-test")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(dir)
sockPath := filepath.Join(dir, "docker.sock")
- if err := d.Start("--host", "unix://"+sockPath); err != nil {
- t.Fatal(err)
+ if err := s.d.Start("--host", "unix://"+sockPath); err != nil {
+ c.Fatal(err)
}
- defer d.Stop()
if _, err := os.Stat(sockPath); err != nil {
- t.Fatal("socket does not exist")
+ c.Fatal("socket does not exist")
}
- if err := d.Stop(); err != nil {
- t.Fatal(err)
+ if err := s.d.Stop(); err != nil {
+ c.Fatal(err)
}
if _, err := os.Stat(sockPath); err == nil || !os.IsNotExist(err) {
- t.Fatal("unix socket is not cleaned up")
+ c.Fatal("unix socket is not cleaned up")
}
-
- logDone("daemon - unix socket is cleaned up")
}
-func TestDaemonwithwrongkey(t *testing.T) {
+func (s *DockerDaemonSuite) TestDaemonwithwrongkey(c *check.C) {
type Config struct {
Crv string `json:"crv"`
D string `json:"d"`
@@ -846,24 +745,23 @@ func TestDaemonwithwrongkey(t *testing.T) {
}
os.Remove("/etc/docker/key.json")
- d := NewDaemon(t)
- if err := d.Start(); err != nil {
- t.Fatalf("Failed to start daemon: %v", err)
+ if err := s.d.Start(); err != nil {
+ c.Fatalf("Failed to start daemon: %v", err)
}
- if err := d.Stop(); err != nil {
- t.Fatalf("Could not stop daemon: %v", err)
+ if err := s.d.Stop(); err != nil {
+ c.Fatalf("Could not stop daemon: %v", err)
}
config := &Config{}
bytes, err := ioutil.ReadFile("/etc/docker/key.json")
if err != nil {
- t.Fatalf("Error reading key.json file: %s", err)
+ c.Fatalf("Error reading key.json file: %s", err)
}
// byte[] to Data-Struct
if err := json.Unmarshal(bytes, &config); err != nil {
- t.Fatalf("Error Unmarshal: %s", err)
+ c.Fatalf("Error Unmarshal: %s", err)
}
//replace config.Kid with the fake value
@@ -872,27 +770,122 @@ func TestDaemonwithwrongkey(t *testing.T) {
// NEW Data-Struct to byte[]
newBytes, err := json.Marshal(&config)
if err != nil {
- t.Fatalf("Error Marshal: %s", err)
+ c.Fatalf("Error Marshal: %s", err)
}
// write back
if err := ioutil.WriteFile("/etc/docker/key.json", newBytes, 0400); err != nil {
- t.Fatalf("Error ioutil.WriteFile: %s", err)
+ c.Fatalf("Error ioutil.WriteFile: %s", err)
}
- d1 := NewDaemon(t)
+ defer os.Remove("/etc/docker/key.json")
- if err := d1.Start(); err == nil {
- d1.Stop()
- t.Fatalf("It should not be succssful to start daemon with wrong key: %v", err)
+ if err := s.d.Start(); err == nil {
+ c.Fatalf("It should not be successful to start daemon with wrong key: %v", err)
}
- content, _ := ioutil.ReadFile(d1.logFile.Name())
+ content, _ := ioutil.ReadFile(s.d.logFile.Name())
if !strings.Contains(string(content), "Public Key ID does not match") {
- t.Fatal("Missing KeyID message from daemon logs")
+ c.Fatal("Missing KeyID message from daemon logs")
}
+}
- os.Remove("/etc/docker/key.json")
- logDone("daemon - it should be failed to start daemon with wrong key")
+func (s *DockerDaemonSuite) TestDaemonRestartKillWait(c *check.C) {
+ if err := s.d.StartWithBusybox(); err != nil {
+ c.Fatalf("Could not start daemon with busybox: %v", err)
+ }
+
+ out, err := s.d.Cmd("run", "-id", "busybox", "/bin/cat")
+ if err != nil {
+ c.Fatalf("Could not run /bin/cat: err=%v\n%s", err, out)
+ }
+ containerID := strings.TrimSpace(out)
+
+ if out, err := s.d.Cmd("kill", containerID); err != nil {
+ c.Fatalf("Could not kill %s: err=%v\n%s", containerID, err, out)
+ }
+
+ if err := s.d.Restart(); err != nil {
+ c.Fatalf("Could not restart daemon: %v", err)
+ }
+
+ errchan := make(chan error)
+ go func() {
+ if out, err := s.d.Cmd("wait", containerID); err != nil {
+ errchan <- fmt.Errorf("%v:\n%s", err, out)
+ }
+ close(errchan)
+ }()
+
+ select {
+ case <-time.After(5 * time.Second):
+ c.Fatal("Waiting on a stopped (killed) container timed out")
+ case err := <-errchan:
+ if err != nil {
+ c.Fatal(err)
+ }
+ }
+}
+
+// TestHttpsInfo connects via two-way authenticated HTTPS to the info endpoint
+func (s *DockerDaemonSuite) TestHttpsInfo(c *check.C) {
+ const (
+ testDaemonHttpsAddr = "localhost:4271"
+ )
+
+ if err := s.d.Start("--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/server-cert.pem",
+ "--tlskey", "fixtures/https/server-key.pem", "-H", testDaemonHttpsAddr); err != nil {
+ c.Fatalf("Could not start daemon with busybox: %v", err)
+ }
+
+ //force tcp protocol
+ host := fmt.Sprintf("tcp://%s", testDaemonHttpsAddr)
+ daemonArgs := []string{"--host", host, "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/client-cert.pem", "--tlskey", "fixtures/https/client-key.pem"}
+ out, err := s.d.CmdWithArgs(daemonArgs, "info")
+ if err != nil {
+ c.Fatalf("Error Occurred: %s and output: %s", err, out)
+ }
+}
+
+// TestHttpsInfoRogueCert connects via two-way authenticated HTTPS to the info endpoint
+// by using a rogue client certificate and checks that it fails with the expected error.
+func (s *DockerDaemonSuite) TestHttpsInfoRogueCert(c *check.C) {
+ const (
+ errBadCertificate = "remote error: bad certificate"
+ testDaemonHttpsAddr = "localhost:4271"
+ )
+ if err := s.d.Start("--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/server-cert.pem",
+ "--tlskey", "fixtures/https/server-key.pem", "-H", testDaemonHttpsAddr); err != nil {
+ c.Fatalf("Could not start daemon with busybox: %v", err)
+ }
+
+ //force tcp protocol
+ host := fmt.Sprintf("tcp://%s", testDaemonHttpsAddr)
+ daemonArgs := []string{"--host", host, "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/client-rogue-cert.pem", "--tlskey", "fixtures/https/client-rogue-key.pem"}
+ out, err := s.d.CmdWithArgs(daemonArgs, "info")
+ if err == nil || !strings.Contains(out, errBadCertificate) {
+ c.Fatalf("Expected err: %s, got instead: %s and output: %s", errBadCertificate, err, out)
+ }
+}
+
+// TestHttpsInfoRogueServerCert connects via two-way authenticated HTTPS to the info endpoint
+// which provides a rogue server certificate and checks that it fails with the expected error
+func (s *DockerDaemonSuite) TestHttpsInfoRogueServerCert(c *check.C) {
+ const (
+ errCaUnknown = "x509: certificate signed by unknown authority"
+ testDaemonRogueHttpsAddr = "localhost:4272"
+ )
+ if err := s.d.Start("--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/server-rogue-cert.pem",
+ "--tlskey", "fixtures/https/server-rogue-key.pem", "-H", testDaemonRogueHttpsAddr); err != nil {
+ c.Fatalf("Could not start daemon with busybox: %v", err)
+ }
+
+ //force tcp protocol
+ host := fmt.Sprintf("tcp://%s", testDaemonRogueHttpsAddr)
+ daemonArgs := []string{"--host", host, "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/client-rogue-cert.pem", "--tlskey", "fixtures/https/client-rogue-key.pem"}
+ out, err := s.d.CmdWithArgs(daemonArgs, "info")
+ if err == nil || !strings.Contains(out, errCaUnknown) {
+ c.Fatalf("Expected err: %s, got instead: %s and output: %s", errCaUnknown, err, out)
+ }
}
diff --git a/integration-cli/docker_cli_diff_test.go b/integration-cli/docker_cli_diff_test.go
index f7f8cd7a9d356..332b128ed8f4c 100644
--- a/integration-cli/docker_cli_diff_test.go
+++ b/integration-cli/docker_cli_diff_test.go
@@ -3,16 +3,17 @@ package main
import (
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
// ensure that an added file shows up in docker diff
-func TestDiffFilenameShownInOutput(t *testing.T) {
+func (s *DockerSuite) TestDiffFilenameShownInOutput(c *check.C) {
containerCmd := `echo foo > /root/bar`
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", containerCmd)
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("failed to start the container: %s, %v", out, err)
+ c.Fatalf("failed to start the container: %s, %v", out, err)
}
cleanCID := strings.TrimSpace(out)
@@ -20,7 +21,7 @@ func TestDiffFilenameShownInOutput(t *testing.T) {
diffCmd := exec.Command(dockerBinary, "diff", cleanCID)
out, _, err = runCommandWithOutput(diffCmd)
if err != nil {
- t.Fatalf("failed to run diff: %s %v", out, err)
+ c.Fatalf("failed to run diff: %s %v", out, err)
}
found := false
@@ -31,15 +32,12 @@ func TestDiffFilenameShownInOutput(t *testing.T) {
}
}
if !found {
- t.Errorf("couldn't find the new file in docker diff's output: %v", out)
+ c.Errorf("couldn't find the new file in docker diff's output: %v", out)
}
- deleteContainer(cleanCID)
-
- logDone("diff - check if created file shows up")
}
// test to ensure GH #3840 doesn't occur any more
-func TestDiffEnsureDockerinitFilesAreIgnored(t *testing.T) {
+func (s *DockerSuite) TestDiffEnsureDockerinitFilesAreIgnored(c *check.C) {
// this is a list of files which shouldn't show up in `docker diff`
dockerinitFiles := []string{"/etc/resolv.conf", "/etc/hostname", "/etc/hosts", "/.dockerinit", "/.dockerenv"}
@@ -49,7 +47,7 @@ func TestDiffEnsureDockerinitFilesAreIgnored(t *testing.T) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", containerCmd)
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanCID := strings.TrimSpace(out)
@@ -57,26 +55,22 @@ func TestDiffEnsureDockerinitFilesAreIgnored(t *testing.T) {
diffCmd := exec.Command(dockerBinary, "diff", cleanCID)
out, _, err = runCommandWithOutput(diffCmd)
if err != nil {
- t.Fatalf("failed to run diff: %s, %v", out, err)
+ c.Fatalf("failed to run diff: %s, %v", out, err)
}
- deleteContainer(cleanCID)
-
for _, filename := range dockerinitFiles {
if strings.Contains(out, filename) {
- t.Errorf("found file which should've been ignored %v in diff output", filename)
+ c.Errorf("found file which should've been ignored %v in diff output", filename)
}
}
}
-
- logDone("diff - check if ignored files show up in diff")
}
-func TestDiffEnsureOnlyKmsgAndPtmx(t *testing.T) {
+func (s *DockerSuite) TestDiffEnsureOnlyKmsgAndPtmx(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sleep", "0")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanCID := strings.TrimSpace(out)
@@ -84,9 +78,8 @@ func TestDiffEnsureOnlyKmsgAndPtmx(t *testing.T) {
diffCmd := exec.Command(dockerBinary, "diff", cleanCID)
out, _, err = runCommandWithOutput(diffCmd)
if err != nil {
- t.Fatalf("failed to run diff: %s, %v", out, err)
+ c.Fatalf("failed to run diff: %s, %v", out, err)
}
- deleteContainer(cleanCID)
expected := map[string]bool{
"C /dev": true,
@@ -109,9 +102,7 @@ func TestDiffEnsureOnlyKmsgAndPtmx(t *testing.T) {
for _, line := range strings.Split(out, "\n") {
if line != "" && !expected[line] {
- t.Errorf("%q is shown in the diff but shouldn't", line)
+ c.Errorf("%q is shown in the diff but shouldn't", line)
}
}
-
- logDone("diff - ensure that only kmsg and ptmx in diff")
}
diff --git a/integration-cli/docker_cli_events_test.go b/integration-cli/docker_cli_events_test.go
index 767af55018392..80cc0c69d54b8 100644
--- a/integration-cli/docker_cli_events_test.go
+++ b/integration-cli/docker_cli_events_test.go
@@ -7,20 +7,22 @@ import (
"regexp"
"strconv"
"strings"
- "testing"
+ "sync"
"time"
+
+ "github.com/go-check/check"
)
-func TestEventsUntag(t *testing.T) {
+func (s *DockerSuite) TestEventsUntag(c *check.C) {
image := "busybox"
- dockerCmd(t, "tag", image, "utest:tag1")
- dockerCmd(t, "tag", image, "utest:tag2")
- dockerCmd(t, "rmi", "utest:tag1")
- dockerCmd(t, "rmi", "utest:tag2")
+ dockerCmd(c, "tag", image, "utest:tag1")
+ dockerCmd(c, "tag", image, "utest:tag2")
+ dockerCmd(c, "rmi", "utest:tag1")
+ dockerCmd(c, "rmi", "utest:tag2")
eventsCmd := exec.Command(dockerBinary, "events", "--since=1")
out, exitCode, _, err := runCommandWithOutputForDuration(eventsCmd, time.Duration(time.Millisecond*200))
if exitCode != 0 || err != nil {
- t.Fatalf("Failed to get events - exit code %d: %s", exitCode, err)
+ c.Fatalf("Failed to get events - exit code %d: %s", exitCode, err)
}
events := strings.Split(out, "\n")
nEvents := len(events)
@@ -29,194 +31,224 @@ func TestEventsUntag(t *testing.T) {
// looking for.
for _, v := range events[nEvents-3 : nEvents-1] {
if !strings.Contains(v, "untag") {
- t.Fatalf("event should be untag, not %#v", v)
+ c.Fatalf("event should be untag, not %#v", v)
}
}
- logDone("events - untags are logged")
}
-func TestEventsContainerFailStartDie(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestEventsContainerFailStartDie(c *check.C) {
- out, _, _ := dockerCmd(t, "images", "-q")
+ out, _ := dockerCmd(c, "images", "-q")
image := strings.Split(out, "\n")[0]
eventsCmd := exec.Command(dockerBinary, "run", "--name", "testeventdie", image, "blerg")
_, _, err := runCommandWithOutput(eventsCmd)
if err == nil {
- t.Fatalf("Container run with command blerg should have failed, but it did not")
+ c.Fatalf("Container run with command blerg should have failed, but it did not")
}
- eventsCmd = exec.Command(dockerBinary, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(t).Unix()))
+ eventsCmd = exec.Command(dockerBinary, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
out, _, _ = runCommandWithOutput(eventsCmd)
events := strings.Split(out, "\n")
if len(events) <= 1 {
- t.Fatalf("Missing expected event")
+ c.Fatalf("Missing expected event")
}
startEvent := strings.Fields(events[len(events)-3])
dieEvent := strings.Fields(events[len(events)-2])
if startEvent[len(startEvent)-1] != "start" {
- t.Fatalf("event should be start, not %#v", startEvent)
+ c.Fatalf("event should be start, not %#v", startEvent)
}
if dieEvent[len(dieEvent)-1] != "die" {
- t.Fatalf("event should be die, not %#v", dieEvent)
+ c.Fatalf("event should be die, not %#v", dieEvent)
}
- logDone("events - container unwilling to start logs die")
}
-func TestEventsLimit(t *testing.T) {
- defer deleteAllContainers()
- for i := 0; i < 30; i++ {
- dockerCmd(t, "run", "busybox", "echo", strconv.Itoa(i))
+func (s *DockerSuite) TestEventsLimit(c *check.C) {
+
+ var waitGroup sync.WaitGroup
+ errChan := make(chan error, 17)
+
+ args := []string{"run", "--rm", "busybox", "true"}
+ for i := 0; i < 17; i++ {
+ waitGroup.Add(1)
+ go func() {
+ defer waitGroup.Done()
+ errChan <- exec.Command(dockerBinary, args...).Run()
+ }()
+ }
+
+ waitGroup.Wait()
+ close(errChan)
+
+ for err := range errChan {
+ if err != nil {
+ c.Fatalf("%q failed with error: %v", strings.Join(args, " "), err)
+ }
}
- eventsCmd := exec.Command(dockerBinary, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(t).Unix()))
+
+ eventsCmd := exec.Command(dockerBinary, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
out, _, _ := runCommandWithOutput(eventsCmd)
events := strings.Split(out, "\n")
nEvents := len(events) - 1
if nEvents != 64 {
- t.Fatalf("events should be limited to 64, but received %d", nEvents)
+ c.Fatalf("events should be limited to 64, but received %d", nEvents)
}
- logDone("events - limited to 64 entries")
}
-func TestEventsContainerEvents(t *testing.T) {
- dockerCmd(t, "run", "--rm", "busybox", "true")
- eventsCmd := exec.Command(dockerBinary, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(t).Unix()))
+func (s *DockerSuite) TestEventsContainerEvents(c *check.C) {
+ dockerCmd(c, "run", "--rm", "busybox", "true")
+ eventsCmd := exec.Command(dockerBinary, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
out, exitCode, err := runCommandWithOutput(eventsCmd)
if exitCode != 0 || err != nil {
- t.Fatalf("Failed to get events with exit code %d: %s", exitCode, err)
+ c.Fatalf("Failed to get events with exit code %d: %s", exitCode, err)
}
events := strings.Split(out, "\n")
events = events[:len(events)-1]
if len(events) < 4 {
- t.Fatalf("Missing expected event")
+ c.Fatalf("Missing expected event")
}
createEvent := strings.Fields(events[len(events)-4])
startEvent := strings.Fields(events[len(events)-3])
dieEvent := strings.Fields(events[len(events)-2])
destroyEvent := strings.Fields(events[len(events)-1])
if createEvent[len(createEvent)-1] != "create" {
- t.Fatalf("event should be create, not %#v", createEvent)
+ c.Fatalf("event should be create, not %#v", createEvent)
}
if startEvent[len(startEvent)-1] != "start" {
- t.Fatalf("event should be start, not %#v", startEvent)
+ c.Fatalf("event should be start, not %#v", startEvent)
}
if dieEvent[len(dieEvent)-1] != "die" {
- t.Fatalf("event should be die, not %#v", dieEvent)
+ c.Fatalf("event should be die, not %#v", dieEvent)
}
if destroyEvent[len(destroyEvent)-1] != "destroy" {
- t.Fatalf("event should be destroy, not %#v", destroyEvent)
+ c.Fatalf("event should be destroy, not %#v", destroyEvent)
}
- logDone("events - container create, start, die, destroy is logged")
}
-func TestEventsContainerEventsSinceUnixEpoch(t *testing.T) {
- dockerCmd(t, "run", "--rm", "busybox", "true")
+func (s *DockerSuite) TestEventsContainerEventsSinceUnixEpoch(c *check.C) {
+ dockerCmd(c, "run", "--rm", "busybox", "true")
timeBeginning := time.Unix(0, 0).Format(time.RFC3339Nano)
timeBeginning = strings.Replace(timeBeginning, "Z", ".000000000Z", -1)
eventsCmd := exec.Command(dockerBinary, "events", fmt.Sprintf("--since='%s'", timeBeginning),
- fmt.Sprintf("--until=%d", daemonTime(t).Unix()))
+ fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
out, exitCode, err := runCommandWithOutput(eventsCmd)
if exitCode != 0 || err != nil {
- t.Fatalf("Failed to get events with exit code %d: %s", exitCode, err)
+ c.Fatalf("Failed to get events with exit code %d: %s", exitCode, err)
}
events := strings.Split(out, "\n")
events = events[:len(events)-1]
if len(events) < 4 {
- t.Fatalf("Missing expected event")
+ c.Fatalf("Missing expected event")
}
createEvent := strings.Fields(events[len(events)-4])
startEvent := strings.Fields(events[len(events)-3])
dieEvent := strings.Fields(events[len(events)-2])
destroyEvent := strings.Fields(events[len(events)-1])
if createEvent[len(createEvent)-1] != "create" {
- t.Fatalf("event should be create, not %#v", createEvent)
+ c.Fatalf("event should be create, not %#v", createEvent)
}
if startEvent[len(startEvent)-1] != "start" {
- t.Fatalf("event should be start, not %#v", startEvent)
+ c.Fatalf("event should be start, not %#v", startEvent)
}
if dieEvent[len(dieEvent)-1] != "die" {
- t.Fatalf("event should be die, not %#v", dieEvent)
+ c.Fatalf("event should be die, not %#v", dieEvent)
}
if destroyEvent[len(destroyEvent)-1] != "destroy" {
- t.Fatalf("event should be destroy, not %#v", destroyEvent)
+ c.Fatalf("event should be destroy, not %#v", destroyEvent)
}
- logDone("events - container create, start, die, destroy since Unix Epoch time")
}
-func TestEventsImageUntagDelete(t *testing.T) {
+func (s *DockerSuite) TestEventsImageUntagDelete(c *check.C) {
name := "testimageevents"
- defer deleteImages(name)
_, err := buildImage(name,
`FROM scratch
MAINTAINER "docker"`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err := deleteImages(name); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- eventsCmd := exec.Command(dockerBinary, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(t).Unix()))
+ eventsCmd := exec.Command(dockerBinary, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
out, exitCode, err := runCommandWithOutput(eventsCmd)
if exitCode != 0 || err != nil {
- t.Fatalf("Failed to get events with exit code %d: %s", exitCode, err)
+ c.Fatalf("Failed to get events with exit code %d: %s", exitCode, err)
}
events := strings.Split(out, "\n")
events = events[:len(events)-1]
if len(events) < 2 {
- t.Fatalf("Missing expected event")
+ c.Fatalf("Missing expected event")
}
untagEvent := strings.Fields(events[len(events)-2])
deleteEvent := strings.Fields(events[len(events)-1])
if untagEvent[len(untagEvent)-1] != "untag" {
- t.Fatalf("untag should be untag, not %#v", untagEvent)
+ c.Fatalf("untag should be untag, not %#v", untagEvent)
}
if deleteEvent[len(deleteEvent)-1] != "delete" {
- t.Fatalf("delete should be delete, not %#v", deleteEvent)
+ c.Fatalf("delete should be delete, not %#v", deleteEvent)
}
- logDone("events - image untag, delete is logged")
}
-func TestEventsImagePull(t *testing.T) {
- since := daemonTime(t).Unix()
- testRequires(t, Network)
-
- defer deleteImages("hello-world")
+func (s *DockerSuite) TestEventsImagePull(c *check.C) {
+ since := daemonTime(c).Unix()
+ testRequires(c, Network)
pullCmd := exec.Command(dockerBinary, "pull", "hello-world")
if out, _, err := runCommandWithOutput(pullCmd); err != nil {
- t.Fatalf("pulling the hello-world image from has failed: %s, %v", out, err)
+ c.Fatalf("pulling the hello-world image from has failed: %s, %v", out, err)
}
eventsCmd := exec.Command(dockerBinary, "events",
fmt.Sprintf("--since=%d", since),
- fmt.Sprintf("--until=%d", daemonTime(t).Unix()))
+ fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
out, _, _ := runCommandWithOutput(eventsCmd)
events := strings.Split(strings.TrimSpace(out), "\n")
event := strings.TrimSpace(events[len(events)-1])
if !strings.HasSuffix(event, "hello-world:latest: pull") {
- t.Fatalf("Missing pull event - got:%q", event)
+ c.Fatalf("Missing pull event - got:%q", event)
}
- logDone("events - image pull is logged")
}
-func TestEventsImageImport(t *testing.T) {
- defer deleteAllContainers()
- since := daemonTime(t).Unix()
+func (s *DockerSuite) TestEventsImageImport(c *check.C) {
+ since := daemonTime(c).Unix()
+
+ id := make(chan string)
+ eventImport := make(chan struct{})
+ eventsCmd := exec.Command(dockerBinary, "events", "--since", strconv.FormatInt(since, 10))
+ stdout, err := eventsCmd.StdoutPipe()
+ if err != nil {
+ c.Fatal(err)
+ }
+ if err := eventsCmd.Start(); err != nil {
+ c.Fatal(err)
+ }
+ defer eventsCmd.Process.Kill()
+
+ go func() {
+ containerID := <-id
+
+ matchImport := regexp.MustCompile(containerID + `: import$`)
+ scanner := bufio.NewScanner(stdout)
+ for scanner.Scan() {
+ if matchImport.MatchString(scanner.Text()) {
+ close(eventImport)
+ }
+ }
+ }()
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal("failed to create a container", out, err)
+ c.Fatal("failed to create a container", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -225,25 +257,20 @@ func TestEventsImageImport(t *testing.T) {
exec.Command(dockerBinary, "import", "-"),
)
if err != nil {
- t.Errorf("import failed with errors: %v, output: %q", err, out)
+ c.Errorf("import failed with errors: %v, output: %q", err, out)
}
+ newContainerID := strings.TrimSpace(out)
+ id <- newContainerID
- eventsCmd := exec.Command(dockerBinary, "events",
- fmt.Sprintf("--since=%d", since),
- fmt.Sprintf("--until=%d", daemonTime(t).Unix()))
- out, _, _ = runCommandWithOutput(eventsCmd)
-
- events := strings.Split(strings.TrimSpace(out), "\n")
- event := strings.TrimSpace(events[len(events)-1])
-
- if !strings.HasSuffix(event, ": import") {
- t.Fatalf("Missing import event - got:%q", event)
+ select {
+ case <-time.After(5 * time.Second):
+ c.Fatal("failed to observe image import in timely fashion")
+ case <-eventImport:
+ // ignore, done
}
-
- logDone("events - image import is logged")
}
-func TestEventsFilters(t *testing.T) {
+func (s *DockerSuite) TestEventsFilters(c *check.C) {
parseEvents := func(out, match string) {
events := strings.Split(out, "\n")
events = events[:len(events)-1]
@@ -251,67 +278,65 @@ func TestEventsFilters(t *testing.T) {
eventFields := strings.Fields(event)
eventName := eventFields[len(eventFields)-1]
if ok, err := regexp.MatchString(match, eventName); err != nil || !ok {
- t.Fatalf("event should match %s, got %#v, err: %v", match, eventFields, err)
+ c.Fatalf("event should match %s, got %#v, err: %v", match, eventFields, err)
}
}
}
- since := daemonTime(t).Unix()
+ since := daemonTime(c).Unix()
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", "busybox", "true"))
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", "busybox", "true"))
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
- out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "events", fmt.Sprintf("--since=%d", since), fmt.Sprintf("--until=%d", daemonTime(t).Unix()), "--filter", "event=die"))
+ out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "events", fmt.Sprintf("--since=%d", since), fmt.Sprintf("--until=%d", daemonTime(c).Unix()), "--filter", "event=die"))
if err != nil {
- t.Fatalf("Failed to get events: %s", err)
+ c.Fatalf("Failed to get events: %s", err)
}
parseEvents(out, "die")
- out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "events", fmt.Sprintf("--since=%d", since), fmt.Sprintf("--until=%d", daemonTime(t).Unix()), "--filter", "event=die", "--filter", "event=start"))
+ out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "events", fmt.Sprintf("--since=%d", since), fmt.Sprintf("--until=%d", daemonTime(c).Unix()), "--filter", "event=die", "--filter", "event=start"))
if err != nil {
- t.Fatalf("Failed to get events: %s", err)
+ c.Fatalf("Failed to get events: %s", err)
}
parseEvents(out, "((die)|(start))")
// make sure we at least got 2 start events
count := strings.Count(out, "start")
if count < 2 {
- t.Fatalf("should have had 2 start events but had %d, out: %s", count, out)
+ c.Fatalf("should have had 2 start events but had %d, out: %s", count, out)
}
- logDone("events - filters")
}
-func TestEventsFilterImageName(t *testing.T) {
- since := daemonTime(t).Unix()
- defer deleteAllContainers()
+func (s *DockerSuite) TestEventsFilterImageName(c *check.C) {
+ since := daemonTime(c).Unix()
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--name", "container_1", "-d", "busybox:latest", "true"))
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
container1 := strings.TrimSpace(out)
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "--name", "container_2", "-d", "busybox", "true"))
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
container2 := strings.TrimSpace(out)
- s := "busybox"
- eventsCmd := exec.Command(dockerBinary, "events", fmt.Sprintf("--since=%d", since), fmt.Sprintf("--until=%d", daemonTime(t).Unix()), "--filter", fmt.Sprintf("image=%s", s))
+ name := "busybox"
+ eventsCmd := exec.Command(dockerBinary, "events", fmt.Sprintf("--since=%d", since), fmt.Sprintf("--until=%d", daemonTime(c).Unix()), "--filter", fmt.Sprintf("image=%s", name))
out, _, err = runCommandWithOutput(eventsCmd)
if err != nil {
- t.Fatalf("Failed to get events, error: %s(%s)", err, out)
+ c.Fatalf("Failed to get events, error: %s(%s)", err, out)
}
events := strings.Split(out, "\n")
events = events[:len(events)-1]
if len(events) == 0 {
- t.Fatalf("Expected events but found none for the image busybox:latest")
+ c.Fatalf("Expected events but found none for the image busybox:latest")
}
count1 := 0
count2 := 0
@@ -324,27 +349,28 @@ func TestEventsFilterImageName(t *testing.T) {
}
}
if count1 == 0 || count2 == 0 {
- t.Fatalf("Expected events from each container but got %d from %s and %d from %s", count1, container1, count2, container2)
+ c.Fatalf("Expected events from each container but got %d from %s and %d from %s", count1, container1, count2, container2)
}
- logDone("events - filters using image")
}
-func TestEventsFilterContainer(t *testing.T) {
- defer deleteAllContainers()
- since := fmt.Sprintf("%d", daemonTime(t).Unix())
+func (s *DockerSuite) TestEventsFilterContainer(c *check.C) {
+ since := fmt.Sprintf("%d", daemonTime(c).Unix())
nameID := make(map[string]string)
for _, name := range []string{"container_1", "container_2"} {
- out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", name, "busybox", "true"))
+ out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--name", name, "busybox", "true"))
if err != nil {
- t.Fatal(err)
+ c.Fatalf("Error: %v, Output: %s", err, out)
}
- nameID[name] = strings.TrimSpace(out)
- waitInspect(name, "{{.State.Runing }}", "false", 5)
+ id, err := inspectField(name, "Id")
+ if err != nil {
+ c.Fatal(err)
+ }
+ nameID[name] = id
}
- until := fmt.Sprintf("%d", daemonTime(t).Unix())
+ until := fmt.Sprintf("%d", daemonTime(c).Unix())
checkEvents := func(id string, events []string) error {
if len(events) != 3 { // create, start, die
@@ -370,57 +396,49 @@ func TestEventsFilterContainer(t *testing.T) {
eventsCmd := exec.Command(dockerBinary, "events", "--since", since, "--until", until, "--filter", "container="+name)
out, _, err := runCommandWithOutput(eventsCmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
events := strings.Split(strings.TrimSuffix(out, "\n"), "\n")
if err := checkEvents(ID, events); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// filter by ID's
eventsCmd = exec.Command(dockerBinary, "events", "--since", since, "--until", until, "--filter", "container="+ID)
out, _, err = runCommandWithOutput(eventsCmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
events = strings.Split(strings.TrimSuffix(out, "\n"), "\n")
if err := checkEvents(ID, events); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
}
- logDone("events - filters using container name")
}
-func TestEventsStreaming(t *testing.T) {
- start := daemonTime(t).Unix()
+func (s *DockerSuite) TestEventsStreaming(c *check.C) {
+ start := daemonTime(c).Unix()
- finish := make(chan struct{})
- defer close(finish)
id := make(chan string)
eventCreate := make(chan struct{})
eventStart := make(chan struct{})
eventDie := make(chan struct{})
eventDestroy := make(chan struct{})
- go func() {
- eventsCmd := exec.Command(dockerBinary, "events", "--since", strconv.FormatInt(start, 10))
- stdout, err := eventsCmd.StdoutPipe()
- if err != nil {
- t.Fatal(err)
- }
- err = eventsCmd.Start()
- if err != nil {
- t.Fatalf("failed to start 'docker events': %s", err)
- }
-
- go func() {
- <-finish
- eventsCmd.Process.Kill()
- }()
+ eventsCmd := exec.Command(dockerBinary, "events", "--since", strconv.FormatInt(start, 10))
+ stdout, err := eventsCmd.StdoutPipe()
+ if err != nil {
+ c.Fatal(err)
+ }
+ if err := eventsCmd.Start(); err != nil {
+ c.Fatalf("failed to start 'docker events': %s", err)
+ }
+ defer eventsCmd.Process.Kill()
+ go func() {
containerID := <-id
matchCreate := regexp.MustCompile(containerID + `: \(from busybox:latest\) create$`)
@@ -441,38 +459,33 @@ func TestEventsStreaming(t *testing.T) {
close(eventDestroy)
}
}
-
- err = eventsCmd.Wait()
- if err != nil && !IsKilled(err) {
- t.Fatalf("docker events had bad exit status: %s", err)
- }
}()
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox:latest", "true")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
id <- cleanedContainerID
select {
case <-time.After(5 * time.Second):
- t.Fatal("failed to observe container create in timely fashion")
+ c.Fatal("failed to observe container create in timely fashion")
case <-eventCreate:
// ignore, done
}
select {
case <-time.After(5 * time.Second):
- t.Fatal("failed to observe container start in timely fashion")
+ c.Fatal("failed to observe container start in timely fashion")
case <-eventStart:
// ignore, done
}
select {
case <-time.After(5 * time.Second):
- t.Fatal("failed to observe container die in timely fashion")
+ c.Fatal("failed to observe container die in timely fashion")
case <-eventDie:
// ignore, done
}
@@ -480,15 +493,13 @@ func TestEventsStreaming(t *testing.T) {
rmCmd := exec.Command(dockerBinary, "rm", cleanedContainerID)
out, _, err = runCommandWithOutput(rmCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
select {
case <-time.After(5 * time.Second):
- t.Fatal("failed to observe container destroy in timely fashion")
+ c.Fatal("failed to observe container destroy in timely fashion")
case <-eventDestroy:
// ignore, done
}
-
- logDone("events - streamed to stdout")
}
diff --git a/integration-cli/docker_cli_events_unix_test.go b/integration-cli/docker_cli_events_unix_test.go
index 4e54283501213..1a08f2b3c0182 100644
--- a/integration-cli/docker_cli_events_unix_test.go
+++ b/integration-cli/docker_cli_events_unix_test.go
@@ -8,48 +8,46 @@ import (
"io/ioutil"
"os"
"os/exec"
- "testing"
"unicode"
+ "github.com/go-check/check"
"github.com/kr/pty"
)
// #5979
-func TestEventsRedirectStdout(t *testing.T) {
- since := daemonTime(t).Unix()
- dockerCmd(t, "run", "busybox", "true")
- defer deleteAllContainers()
+func (s *DockerSuite) TestEventsRedirectStdout(c *check.C) {
+ since := daemonTime(c).Unix()
+ dockerCmd(c, "run", "busybox", "true")
file, err := ioutil.TempFile("", "")
if err != nil {
- t.Fatalf("could not create temp file: %v", err)
+ c.Fatalf("could not create temp file: %v", err)
}
defer os.Remove(file.Name())
- command := fmt.Sprintf("%s events --since=%d --until=%d > %s", dockerBinary, since, daemonTime(t).Unix(), file.Name())
+ command := fmt.Sprintf("%s events --since=%d --until=%d > %s", dockerBinary, since, daemonTime(c).Unix(), file.Name())
_, tty, err := pty.Open()
if err != nil {
- t.Fatalf("Could not open pty: %v", err)
+ c.Fatalf("Could not open pty: %v", err)
}
cmd := exec.Command("sh", "-c", command)
cmd.Stdin = tty
cmd.Stdout = tty
cmd.Stderr = tty
if err := cmd.Run(); err != nil {
- t.Fatalf("run err for command %q: %v", command, err)
+ c.Fatalf("run err for command %q: %v", command, err)
}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
- for _, c := range scanner.Text() {
- if unicode.IsControl(c) {
- t.Fatalf("found control character %v", []byte(string(c)))
+ for _, ch := range scanner.Text() {
+ if unicode.IsControl(ch) {
+ c.Fatalf("found control character %v", []byte(string(ch)))
}
}
}
if err := scanner.Err(); err != nil {
- t.Fatalf("Scan err for command %q: %v", command, err)
+ c.Fatalf("Scan err for command %q: %v", command, err)
}
- logDone("events - redirect stdout")
}
diff --git a/integration-cli/docker_cli_exec_test.go b/integration-cli/docker_cli_exec_test.go
index 9fcee32a7a4cb..4b36d7b532142 100644
--- a/integration-cli/docker_cli_exec_test.go
+++ b/integration-cli/docker_cli_exec_test.go
@@ -12,224 +12,170 @@ import (
"sort"
"strings"
"sync"
- "testing"
"time"
+
+ "github.com/go-check/check"
)
-func TestExec(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestExec(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "sh", "-c", "echo test > /tmp/file && top")
if out, _, _, err := runCommandWithStdoutStderr(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
execCmd := exec.Command(dockerBinary, "exec", "testing", "cat", "/tmp/file")
out, _, err := runCommandWithOutput(execCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
out = strings.Trim(out, "\r\n")
if expected := "test"; out != expected {
- t.Errorf("container exec should've printed %q but printed %q", expected, out)
+ c.Errorf("container exec should've printed %q but printed %q", expected, out)
}
- logDone("exec - basic test")
}
-func TestExecInteractiveStdinClose(t *testing.T) {
- defer deleteAllContainers()
- out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-itd", "busybox", "/bin/cat"))
- if err != nil {
- t.Fatal(err)
- }
-
- contId := strings.TrimSpace(out)
-
- returnchan := make(chan struct{})
-
- go func() {
- var err error
- cmd := exec.Command(dockerBinary, "exec", "-i", contId, "/bin/ls", "/")
- cmd.Stdin = os.Stdin
- if err != nil {
- t.Fatal(err)
- }
-
- out, err := cmd.CombinedOutput()
- if err != nil {
- t.Fatal(err, string(out))
- }
-
- if string(out) == "" {
- t.Fatalf("Output was empty, likely blocked by standard input")
- }
-
- returnchan <- struct{}{}
- }()
-
- select {
- case <-returnchan:
- case <-time.After(10 * time.Second):
- t.Fatal("timed out running docker exec")
- }
-
- logDone("exec - interactive mode closes stdin after execution")
-}
-
-func TestExecInteractive(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestExecInteractive(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "sh", "-c", "echo test > /tmp/file && top")
if out, _, _, err := runCommandWithStdoutStderr(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
execCmd := exec.Command(dockerBinary, "exec", "-i", "testing", "sh")
stdin, err := execCmd.StdinPipe()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
stdout, err := execCmd.StdoutPipe()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err := execCmd.Start(); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := stdin.Write([]byte("cat /tmp/file\n")); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
r := bufio.NewReader(stdout)
line, err := r.ReadString('\n')
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
line = strings.TrimSpace(line)
if line != "test" {
- t.Fatalf("Output should be 'test', got '%q'", line)
+ c.Fatalf("Output should be 'test', got '%q'", line)
}
if err := stdin.Close(); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- finish := make(chan struct{})
+ errChan := make(chan error)
go func() {
- if err := execCmd.Wait(); err != nil {
- t.Fatal(err)
- }
- close(finish)
+ errChan <- execCmd.Wait()
+ close(errChan)
}()
select {
- case <-finish:
+ case err := <-errChan:
+ c.Assert(err, check.IsNil)
case <-time.After(1 * time.Second):
- t.Fatal("docker exec failed to exit on stdin close")
+ c.Fatal("docker exec failed to exit on stdin close")
}
- logDone("exec - Interactive test")
}
-func TestExecAfterContainerRestart(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestExecAfterContainerRestart(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
runCmd = exec.Command(dockerBinary, "restart", cleanedContainerID)
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
runCmd = exec.Command(dockerBinary, "exec", cleanedContainerID, "echo", "hello")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
outStr := strings.TrimSpace(out)
if outStr != "hello" {
- t.Errorf("container should've printed hello, instead printed %q", outStr)
+ c.Errorf("container should've printed hello, instead printed %q", outStr)
}
- logDone("exec - exec running container after container restart")
}
-func TestExecAfterDaemonRestart(t *testing.T) {
- testRequires(t, SameHostDaemon)
- defer deleteAllContainers()
+func (s *DockerDaemonSuite) TestExecAfterDaemonRestart(c *check.C) {
+ testRequires(c, SameHostDaemon)
- d := NewDaemon(t)
- if err := d.StartWithBusybox(); err != nil {
- t.Fatalf("Could not start daemon with busybox: %v", err)
+ if err := s.d.StartWithBusybox(); err != nil {
+ c.Fatalf("Could not start daemon with busybox: %v", err)
}
- defer d.Stop()
- if out, err := d.Cmd("run", "-d", "--name", "top", "-p", "80", "busybox:latest", "top"); err != nil {
- t.Fatalf("Could not run top: err=%v\n%s", err, out)
+ if out, err := s.d.Cmd("run", "-d", "--name", "top", "-p", "80", "busybox:latest", "top"); err != nil {
+ c.Fatalf("Could not run top: err=%v\n%s", err, out)
}
- if err := d.Restart(); err != nil {
- t.Fatalf("Could not restart daemon: %v", err)
+ if err := s.d.Restart(); err != nil {
+ c.Fatalf("Could not restart daemon: %v", err)
}
- if out, err := d.Cmd("start", "top"); err != nil {
- t.Fatalf("Could not start top after daemon restart: err=%v\n%s", err, out)
+ if out, err := s.d.Cmd("start", "top"); err != nil {
+ c.Fatalf("Could not start top after daemon restart: err=%v\n%s", err, out)
}
- out, err := d.Cmd("exec", "top", "echo", "hello")
+ out, err := s.d.Cmd("exec", "top", "echo", "hello")
if err != nil {
- t.Fatalf("Could not exec on container top: err=%v\n%s", err, out)
+ c.Fatalf("Could not exec on container top: err=%v\n%s", err, out)
}
outStr := strings.TrimSpace(string(out))
if outStr != "hello" {
- t.Errorf("container should've printed hello, instead printed %q", outStr)
+ c.Errorf("container should've printed hello, instead printed %q", outStr)
}
-
- logDone("exec - exec running container after daemon restart")
}
// Regression test for #9155, #9044
-func TestExecEnv(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestExecEnv(c *check.C) {
runCmd := exec.Command(dockerBinary, "run",
"-e", "LALA=value1",
"-e", "LALA=value2",
"-d", "--name", "testing", "busybox", "top")
if out, _, _, err := runCommandWithStdoutStderr(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
execCmd := exec.Command(dockerBinary, "exec", "testing", "env")
out, _, err := runCommandWithOutput(execCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if strings.Contains(out, "LALA=value1") ||
!strings.Contains(out, "LALA=value2") ||
!strings.Contains(out, "HOME=/root") {
- t.Errorf("exec env(%q), expect %q, %q", out, "LALA=value2", "HOME=/root")
+ c.Errorf("exec env(%q), expect %q, %q", out, "LALA=value2", "HOME=/root")
}
- logDone("exec - exec inherits correct env")
}
-func TestExecExitStatus(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestExecExitStatus(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "top", "busybox", "top")
if out, _, _, err := runCommandWithStdoutStderr(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
// Test normal (non-detached) case first
@@ -237,20 +183,18 @@ func TestExecExitStatus(t *testing.T) {
ec, _ := runCommand(cmd)
if ec != 23 {
- t.Fatalf("Should have had an ExitCode of 23, not: %d", ec)
+ c.Fatalf("Should have had an ExitCode of 23, not: %d", ec)
}
- logDone("exec - exec non-zero ExitStatus")
}
-func TestExecPausedContainer(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestExecPausedContainer(c *check.C) {
defer unpauseAllContainers()
runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "top")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
ContainerID := strings.TrimSpace(out)
@@ -258,172 +202,172 @@ func TestExecPausedContainer(t *testing.T) {
pausedCmd := exec.Command(dockerBinary, "pause", "testing")
out, _, _, err = runCommandWithStdoutStderr(pausedCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
execCmd := exec.Command(dockerBinary, "exec", "-i", "-t", ContainerID, "echo", "hello")
out, _, err = runCommandWithOutput(execCmd)
if err == nil {
- t.Fatal("container should fail to exec new command if it is paused")
+ c.Fatal("container should fail to exec new command if it is paused")
}
expected := ContainerID + " is paused, unpause the container before exec"
if !strings.Contains(out, expected) {
- t.Fatal("container should not exec new command if it is paused")
+ c.Fatal("container should not exec new command if it is paused")
}
- logDone("exec - exec should not exec a pause container")
}
// regression test for #9476
-func TestExecTtyCloseStdin(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestExecTtyCloseStdin(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-d", "-it", "--name", "exec_tty_stdin", "busybox")
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cmd = exec.Command(dockerBinary, "exec", "-i", "exec_tty_stdin", "cat")
stdinRw, err := cmd.StdinPipe()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
stdinRw.Write([]byte("test"))
stdinRw.Close()
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cmd = exec.Command(dockerBinary, "top", "exec_tty_stdin")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
outArr := strings.Split(out, "\n")
if len(outArr) > 3 || strings.Contains(out, "nsenter-exec") {
// This is the really bad part
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "rm", "-f", "exec_tty_stdin")); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
- t.Fatalf("exec process left running\n\t %s", out)
+ c.Fatalf("exec process left running\n\t %s", out)
}
- logDone("exec - stdin is closed properly with tty enabled")
}
-func TestExecTtyWithoutStdin(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestExecTtyWithoutStdin(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-d", "-ti", "busybox")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to start container: %v (%v)", out, err)
+ c.Fatalf("failed to start container: %v (%v)", out, err)
}
id := strings.TrimSpace(out)
if err := waitRun(id); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer func() {
cmd := exec.Command(dockerBinary, "kill", id)
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatalf("failed to kill container: %v (%v)", out, err)
+ c.Fatalf("failed to kill container: %v (%v)", out, err)
}
}()
- done := make(chan struct{})
+ errChan := make(chan error)
go func() {
- defer close(done)
+ defer close(errChan)
cmd := exec.Command(dockerBinary, "exec", "-ti", id, "true")
if _, err := cmd.StdinPipe(); err != nil {
- t.Fatal(err)
+ errChan <- err
+ return
}
expected := "cannot enable tty mode"
if out, _, err := runCommandWithOutput(cmd); err == nil {
- t.Fatal("exec should have failed")
+ errChan <- fmt.Errorf("exec should have failed")
+ return
} else if !strings.Contains(out, expected) {
- t.Fatalf("exec failed with error %q: expected %q", out, expected)
+ errChan <- fmt.Errorf("exec failed with error %q: expected %q", out, expected)
+ return
}
}()
select {
- case <-done:
+ case err := <-errChan:
+ c.Assert(err, check.IsNil)
case <-time.After(3 * time.Second):
- t.Fatal("exec is running but should have failed")
+ c.Fatal("exec is running but should have failed")
}
- logDone("exec - forbid piped stdin to tty enabled container")
}
-func TestExecParseError(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestExecParseError(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "top", "busybox", "top")
if out, _, err := runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
// Test normal (non-detached) case first
cmd := exec.Command(dockerBinary, "exec", "top")
if _, stderr, code, err := runCommandWithStdoutStderr(cmd); err == nil || !strings.Contains(stderr, "See '"+dockerBinary+" exec --help'") || code == 0 {
- t.Fatalf("Should have thrown error & point to help: %s", stderr)
+ c.Fatalf("Should have thrown error & point to help: %s", stderr)
}
- logDone("exec - error on parseExec should point to help")
}
-func TestExecStopNotHanging(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestExecStopNotHanging(c *check.C) {
if out, err := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "top").CombinedOutput(); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if err := exec.Command(dockerBinary, "exec", "testing", "top").Start(); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
+ }
+
+ type dstop struct {
+ out []byte
+ err error
}
- wait := make(chan struct{})
+ ch := make(chan dstop)
go func() {
- if out, err := exec.Command(dockerBinary, "stop", "testing").CombinedOutput(); err != nil {
- t.Fatal(out, err)
- }
- close(wait)
+ out, err := exec.Command(dockerBinary, "stop", "testing").CombinedOutput()
+ ch <- dstop{out, err}
+ close(ch)
}()
select {
case <-time.After(3 * time.Second):
- t.Fatal("Container stop timed out")
- case <-wait:
+ c.Fatal("Container stop timed out")
+ case s := <-ch:
+ c.Assert(s.err, check.IsNil)
}
- logDone("exec - container with exec not hanging on stop")
}
-func TestExecCgroup(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestExecCgroup(c *check.C) {
var cmd *exec.Cmd
cmd = exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "top")
_, err := runCommand(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "exec", "testing", "cat", "/proc/1/cgroup")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
containerCgroups := sort.StringSlice(strings.Split(string(out), "\n"))
var wg sync.WaitGroup
- var s sync.Mutex
+ var mu sync.Mutex
execCgroups := []sort.StringSlice{}
+ errChan := make(chan error)
// exec a few times concurrently to get consistent failure
for i := 0; i < 5; i++ {
wg.Add(1)
@@ -431,17 +375,23 @@ func TestExecCgroup(t *testing.T) {
cmd := exec.Command(dockerBinary, "exec", "testing", "cat", "/proc/self/cgroup")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(out, err)
+ errChan <- err
+ return
}
cg := sort.StringSlice(strings.Split(string(out), "\n"))
- s.Lock()
+ mu.Lock()
execCgroups = append(execCgroups, cg)
- s.Unlock()
+ mu.Unlock()
wg.Done()
}()
}
wg.Wait()
+ close(errChan)
+
+ for err := range errChan {
+ c.Assert(err, check.IsNil)
+ }
for _, cg := range execCgroups {
if !reflect.DeepEqual(cg, containerCgroups) {
@@ -454,86 +404,81 @@ func TestExecCgroup(t *testing.T) {
for _, name := range containerCgroups {
fmt.Printf(" %s\n", name)
}
- t.Fatal("cgroups mismatched")
+ c.Fatal("cgroups mismatched")
}
}
- logDone("exec - exec has the container cgroups")
}
-func TestInspectExecID(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestInspectExecID(c *check.C) {
out, exitCode, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "busybox", "top"))
if exitCode != 0 || err != nil {
- t.Fatalf("failed to run container: %s, %v", out, err)
+ c.Fatalf("failed to run container: %s, %v", out, err)
}
id := strings.TrimSuffix(out, "\n")
out, err = inspectField(id, "ExecIDs")
if err != nil {
- t.Fatalf("failed to inspect container: %s, %v", out, err)
+ c.Fatalf("failed to inspect container: %s, %v", out, err)
}
- if out != "" {
- t.Fatalf("ExecIDs should be empty, got: %s", out)
+ if out != "[]" {
+ c.Fatalf("ExecIDs should be empty, got: %s", out)
}
exitCode, err = runCommand(exec.Command(dockerBinary, "exec", "-d", id, "ls", "/"))
if exitCode != 0 || err != nil {
- t.Fatalf("failed to exec in container: %s, %v", out, err)
+ c.Fatalf("failed to exec in container: %s, %v", out, err)
}
out, err = inspectField(id, "ExecIDs")
if err != nil {
- t.Fatalf("failed to inspect container: %s, %v", out, err)
+ c.Fatalf("failed to inspect container: %s, %v", out, err)
}
out = strings.TrimSuffix(out, "\n")
if out == "[]" || out == "" {
- t.Fatalf("ExecIDs should not be empty, got: %s", out)
+ c.Fatalf("ExecIDs should not be empty, got: %s", out)
}
- logDone("inspect - inspect a container with ExecIDs")
}
-func TestLinksPingLinkedContainersOnRename(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestLinksPingLinkedContainersOnRename(c *check.C) {
var out string
- out, _, _ = dockerCmd(t, "run", "-d", "--name", "container1", "busybox", "top")
+ out, _ = dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
idA := strings.TrimSpace(out)
if idA == "" {
- t.Fatal(out, "id should not be nil")
+ c.Fatal(out, "id should not be nil")
}
- out, _, _ = dockerCmd(t, "run", "-d", "--link", "container1:alias1", "--name", "container2", "busybox", "top")
+ out, _ = dockerCmd(c, "run", "-d", "--link", "container1:alias1", "--name", "container2", "busybox", "top")
idB := strings.TrimSpace(out)
if idB == "" {
- t.Fatal(out, "id should not be nil")
+ c.Fatal(out, "id should not be nil")
}
execCmd := exec.Command(dockerBinary, "exec", "container2", "ping", "-c", "1", "alias1", "-W", "1")
out, _, err := runCommandWithOutput(execCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
- dockerCmd(t, "rename", "container1", "container_new")
+ dockerCmd(c, "rename", "container1", "container_new")
execCmd = exec.Command(dockerBinary, "exec", "container2", "ping", "-c", "1", "alias1", "-W", "1")
out, _, err = runCommandWithOutput(execCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
- logDone("links - ping linked container upon rename")
}
-func TestRunExecDir(t *testing.T) {
- testRequires(t, SameHostDaemon)
+func (s *DockerSuite) TestRunExecDir(c *check.C) {
+ testRequires(c, SameHostDaemon)
cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
id := strings.TrimSpace(out)
execDir := filepath.Join(execDriverPath, id)
@@ -542,92 +487,90 @@ func TestRunExecDir(t *testing.T) {
{
fi, err := os.Stat(execDir)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !fi.IsDir() {
- t.Fatalf("%q must be a directory", execDir)
+ c.Fatalf("%q must be a directory", execDir)
}
fi, err = os.Stat(stateFile)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
}
stopCmd := exec.Command(dockerBinary, "stop", id)
out, _, err = runCommandWithOutput(stopCmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
{
_, err := os.Stat(execDir)
if err == nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err == nil {
- t.Fatalf("Exec directory %q exists for removed container!", execDir)
+ c.Fatalf("Exec directory %q exists for removed container!", execDir)
}
if !os.IsNotExist(err) {
- t.Fatalf("Error should be about non-existing, got %s", err)
+ c.Fatalf("Error should be about non-existing, got %s", err)
}
}
startCmd := exec.Command(dockerBinary, "start", id)
out, _, err = runCommandWithOutput(startCmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
{
fi, err := os.Stat(execDir)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !fi.IsDir() {
- t.Fatalf("%q must be a directory", execDir)
+ c.Fatalf("%q must be a directory", execDir)
}
fi, err = os.Stat(stateFile)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
}
rmCmd := exec.Command(dockerBinary, "rm", "-f", id)
out, _, err = runCommandWithOutput(rmCmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
{
_, err := os.Stat(execDir)
if err == nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err == nil {
- t.Fatalf("Exec directory %q is exists for removed container!", execDir)
+ c.Fatalf("Exec directory %q is exists for removed container!", execDir)
}
if !os.IsNotExist(err) {
- t.Fatalf("Error should be about non-existing, got %s", err)
+ c.Fatalf("Error should be about non-existing, got %s", err)
}
}
- logDone("run - check execdriver dir behavior")
}
-func TestRunMutableNetworkFiles(t *testing.T) {
- testRequires(t, SameHostDaemon)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunMutableNetworkFiles(c *check.C) {
+ testRequires(c, SameHostDaemon)
for _, fn := range []string{"resolv.conf", "hosts"} {
deleteAllContainers()
content, err := runCommandAndReadContainerFile(fn, exec.Command(dockerBinary, "run", "-d", "--name", "c1", "busybox", "sh", "-c", fmt.Sprintf("echo success >/etc/%s && top", fn)))
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if strings.TrimSpace(string(content)) != "success" {
- t.Fatal("Content was not what was modified in the container", string(content))
+ c.Fatal("Content was not what was modified in the container", string(content))
}
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", "c2", "busybox", "top"))
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
contID := strings.TrimSpace(out)
@@ -636,32 +579,83 @@ func TestRunMutableNetworkFiles(t *testing.T) {
f, err := os.OpenFile(netFilePath, os.O_WRONLY|os.O_SYNC|os.O_APPEND, 0644)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := f.Seek(0, 0); err != nil {
f.Close()
- t.Fatal(err)
+ c.Fatal(err)
}
if err := f.Truncate(0); err != nil {
f.Close()
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := f.Write([]byte("success2\n")); err != nil {
f.Close()
- t.Fatal(err)
+ c.Fatal(err)
}
f.Close()
res, err := exec.Command(dockerBinary, "exec", contID, "cat", "/etc/"+fn).CombinedOutput()
if err != nil {
- t.Fatalf("Output: %s, error: %s", res, err)
+ c.Fatalf("Output: %s, error: %s", res, err)
}
if string(res) != "success2\n" {
- t.Fatalf("Expected content of %s: %q, got: %q", fn, "success2\n", res)
+ c.Fatalf("Expected content of %s: %q, got: %q", fn, "success2\n", res)
}
}
- logDone("run - mutable network files")
+}
+
+func (s *DockerSuite) TestExecWithUser(c *check.C) {
+
+ runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "parent", "busybox", "top")
+ if out, _, err := runCommandWithOutput(runCmd); err != nil {
+ c.Fatal(out, err)
+ }
+
+ cmd := exec.Command(dockerBinary, "exec", "-u", "1", "parent", "id")
+ out, _, err := runCommandWithOutput(cmd)
+ if err != nil {
+ c.Fatal(err, out)
+ }
+ if !strings.Contains(out, "uid=1(daemon) gid=1(daemon)") {
+ c.Fatalf("exec with user by id expected daemon user got %s", out)
+ }
+
+ cmd = exec.Command(dockerBinary, "exec", "-u", "root", "parent", "id")
+ out, _, err = runCommandWithOutput(cmd)
+ if err != nil {
+ c.Fatal(err, out)
+ }
+ if !strings.Contains(out, "uid=0(root) gid=0(root)") {
+ c.Fatalf("exec with user by root expected root user got %s", out)
+ }
+
+}
+
+func (s *DockerSuite) TestExecWithPrivileged(c *check.C) {
+
+ runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "parent", "--cap-drop=ALL", "busybox", "top")
+ if out, _, err := runCommandWithOutput(runCmd); err != nil {
+ c.Fatal(out, err)
+ }
+
+ cmd := exec.Command(dockerBinary, "exec", "parent", "sh", "-c", "mknod /tmp/sda b 8 0")
+ out, _, err := runCommandWithOutput(cmd)
+ if err == nil || !strings.Contains(out, "Operation not permitted") {
+ c.Fatalf("exec mknod in --cap-drop=ALL container without --privileged should failed")
+ }
+
+ cmd = exec.Command(dockerBinary, "exec", "--privileged", "parent", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
+ out, _, err = runCommandWithOutput(cmd)
+ if err != nil {
+ c.Fatal(err, out)
+ }
+
+ if actual := strings.TrimSpace(out); actual != "ok" {
+ c.Fatalf("exec mknod in --cap-drop=ALL container with --privileged failed: %v, output: %q", err, out)
+ }
+
}
diff --git a/integration-cli/docker_cli_exec_unix_test.go b/integration-cli/docker_cli_exec_unix_test.go
new file mode 100644
index 0000000000000..bee44b9902593
--- /dev/null
+++ b/integration-cli/docker_cli_exec_unix_test.go
@@ -0,0 +1,47 @@
+// +build !windows,!test_no_exec
+
+package main
+
+import (
+ "bytes"
+ "io"
+ "os/exec"
+ "strings"
+ "time"
+
+ "github.com/go-check/check"
+ "github.com/kr/pty"
+)
+
+// regression test for #12546
+func (s *DockerSuite) TestExecInteractiveStdinClose(c *check.C) {
+ out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-itd", "busybox", "/bin/cat"))
+ if err != nil {
+ c.Fatal(err)
+ }
+ contId := strings.TrimSpace(out)
+
+ cmd := exec.Command(dockerBinary, "exec", "-i", contId, "echo", "-n", "hello")
+ p, err := pty.Start(cmd)
+ if err != nil {
+ c.Fatal(err)
+ }
+
+ b := bytes.NewBuffer(nil)
+ go io.Copy(b, p)
+
+ ch := make(chan error)
+ go func() { ch <- cmd.Wait() }()
+
+ select {
+ case err := <-ch:
+ if err != nil {
+ c.Errorf("cmd finished with error %v", err)
+ }
+ if output := b.String(); strings.TrimSpace(output) != "hello" {
+ c.Fatalf("Unexpected output %s", output)
+ }
+ case <-time.After(1 * time.Second):
+ c.Fatal("timed out running docker exec")
+ }
+}
diff --git a/integration-cli/docker_cli_export_import_test.go b/integration-cli/docker_cli_export_import_test.go
index 2d03179ac68b0..3370a96761cab 100644
--- a/integration-cli/docker_cli_export_import_test.go
+++ b/integration-cli/docker_cli_export_import_test.go
@@ -4,94 +4,87 @@ import (
"os"
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
// export an image and try to import it into a new one
-func TestExportContainerAndImportImage(t *testing.T) {
- runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
+func (s *DockerSuite) TestExportContainerAndImportImage(c *check.C) {
+ containerID := "testexportcontainerandimportimage"
+
+ runCmd := exec.Command(dockerBinary, "run", "-d", "--name", containerID, "busybox", "true")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal("failed to create a container", out, err)
+ c.Fatal("failed to create a container", out, err)
}
- cleanedContainerID := strings.TrimSpace(out)
-
- inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
+ inspectCmd := exec.Command(dockerBinary, "inspect", containerID)
out, _, err = runCommandWithOutput(inspectCmd)
if err != nil {
- t.Fatalf("output should've been a container id: %s %s ", cleanedContainerID, err)
+ c.Fatalf("output should've been a container id: %s %s ", containerID, err)
}
- exportCmd := exec.Command(dockerBinary, "export", cleanedContainerID)
+ exportCmd := exec.Command(dockerBinary, "export", containerID)
if out, _, err = runCommandWithOutput(exportCmd); err != nil {
- t.Fatalf("failed to export container: %s, %v", out, err)
+ c.Fatalf("failed to export container: %s, %v", out, err)
}
importCmd := exec.Command(dockerBinary, "import", "-", "repo/testexp:v1")
importCmd.Stdin = strings.NewReader(out)
out, _, err = runCommandWithOutput(importCmd)
if err != nil {
- t.Fatalf("failed to import image: %s, %v", out, err)
+ c.Fatalf("failed to import image: %s, %v", out, err)
}
cleanedImageID := strings.TrimSpace(out)
inspectCmd = exec.Command(dockerBinary, "inspect", cleanedImageID)
if out, _, err = runCommandWithOutput(inspectCmd); err != nil {
- t.Fatalf("output should've been an image id: %s, %v", out, err)
+ c.Fatalf("output should've been an image id: %s, %v", out, err)
}
- deleteContainer(cleanedContainerID)
- deleteImages("repo/testexp:v1")
-
- logDone("export - export/import a container/image")
}
// Used to test output flag in the export command
-func TestExportContainerWithOutputAndImportImage(t *testing.T) {
- runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
+func (s *DockerSuite) TestExportContainerWithOutputAndImportImage(c *check.C) {
+ containerID := "testexportcontainerwithoutputandimportimage"
+
+ runCmd := exec.Command(dockerBinary, "run", "-d", "--name", containerID, "busybox", "true")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal("failed to create a container", out, err)
+ c.Fatal("failed to create a container", out, err)
}
- cleanedContainerID := strings.TrimSpace(out)
-
- inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
+ inspectCmd := exec.Command(dockerBinary, "inspect", containerID)
out, _, err = runCommandWithOutput(inspectCmd)
if err != nil {
- t.Fatalf("output should've been a container id: %s %s ", cleanedContainerID, err)
+ c.Fatalf("output should've been a container id: %s %s ", containerID, err)
}
- exportCmd := exec.Command(dockerBinary, "export", "--output=testexp.tar", cleanedContainerID)
+ defer os.Remove("testexp.tar")
+
+ exportCmd := exec.Command(dockerBinary, "export", "--output=testexp.tar", containerID)
if out, _, err = runCommandWithOutput(exportCmd); err != nil {
- t.Fatalf("failed to export container: %s, %v", out, err)
+ c.Fatalf("failed to export container: %s, %v", out, err)
}
out, _, err = runCommandWithOutput(exec.Command("cat", "testexp.tar"))
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
importCmd := exec.Command(dockerBinary, "import", "-", "repo/testexp:v1")
importCmd.Stdin = strings.NewReader(out)
out, _, err = runCommandWithOutput(importCmd)
if err != nil {
- t.Fatalf("failed to import image: %s, %v", out, err)
+ c.Fatalf("failed to import image: %s, %v", out, err)
}
cleanedImageID := strings.TrimSpace(out)
inspectCmd = exec.Command(dockerBinary, "inspect", cleanedImageID)
if out, _, err = runCommandWithOutput(inspectCmd); err != nil {
- t.Fatalf("output should've been an image id: %s, %v", out, err)
+ c.Fatalf("output should've been an image id: %s, %v", out, err)
}
- deleteContainer(cleanedContainerID)
- deleteImages("repo/testexp:v1")
-
- os.Remove("/tmp/testexp.tar")
-
- logDone("export - export/import a container/image with output flag")
}
diff --git a/integration-cli/docker_cli_help_test.go b/integration-cli/docker_cli_help_test.go
index 8fc5cd1aab4eb..d6903e4fb9a3f 100644
--- a/integration-cli/docker_cli_help_test.go
+++ b/integration-cli/docker_cli_help_test.go
@@ -5,13 +5,13 @@ import (
"os/exec"
"runtime"
"strings"
- "testing"
"unicode"
"github.com/docker/docker/pkg/homedir"
+ "github.com/go-check/check"
)
-func TestHelpTextVerify(t *testing.T) {
+func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
// Make sure main help text fits within 80 chars and that
// on non-windows system we use ~ when possible (to shorten things).
// Test for HOME set to its default value and set to "/" on linux
@@ -51,26 +51,26 @@ func TestHelpTextVerify(t *testing.T) {
helpCmd.Env = newEnvs
out, ec, err := runCommandWithOutput(helpCmd)
if err != nil || ec != 0 {
- t.Fatalf("docker help should have worked\nout:%s\nec:%d", out, ec)
+ c.Fatalf("docker help should have worked\nout:%s\nec:%d", out, ec)
}
lines := strings.Split(out, "\n")
for _, line := range lines {
if len(line) > 80 {
- t.Fatalf("Line is too long(%d chars):\n%s", len(line), line)
+ c.Fatalf("Line is too long(%d chars):\n%s", len(line), line)
}
// All lines should not end with a space
if strings.HasSuffix(line, " ") {
- t.Fatalf("Line should not end with a space: %s", line)
+ c.Fatalf("Line should not end with a space: %s", line)
}
if scanForHome && strings.Contains(line, `=`+home) {
- t.Fatalf("Line should use '%q' instead of %q:\n%s", homedir.GetShortcutString(), home, line)
+ c.Fatalf("Line should use '%q' instead of %q:\n%s", homedir.GetShortcutString(), home, line)
}
if runtime.GOOS != "windows" {
i := strings.Index(line, homedir.GetShortcutString())
if i >= 0 && i != len(line)-1 && line[i+1] != '/' {
- t.Fatalf("Main help should not have used home shortcut:\n%s", line)
+ c.Fatalf("Main help should not have used home shortcut:\n%s", line)
}
}
}
@@ -82,11 +82,11 @@ func TestHelpTextVerify(t *testing.T) {
helpCmd.Env = newEnvs
out, ec, err = runCommandWithOutput(helpCmd)
if err != nil || ec != 0 {
- t.Fatalf("docker help should have worked\nout:%s\nec:%d", out, ec)
+ c.Fatalf("docker help should have worked\nout:%s\nec:%d", out, ec)
}
i := strings.Index(out, "Commands:")
if i < 0 {
- t.Fatalf("Missing 'Commands:' in:\n%s", out)
+ c.Fatalf("Missing 'Commands:' in:\n%s", out)
}
// Grab all chars starting at "Commands:"
@@ -106,39 +106,39 @@ func TestHelpTextVerify(t *testing.T) {
helpCmd.Env = newEnvs
out, ec, err := runCommandWithOutput(helpCmd)
if err != nil || ec != 0 {
- t.Fatalf("Error on %q help: %s\nexit code:%d", cmd, out, ec)
+ c.Fatalf("Error on %q help: %s\nexit code:%d", cmd, out, ec)
}
lines := strings.Split(out, "\n")
for _, line := range lines {
if len(line) > 80 {
- t.Fatalf("Help for %q is too long(%d chars):\n%s", cmd,
+ c.Fatalf("Help for %q is too long(%d chars):\n%s", cmd,
len(line), line)
}
if scanForHome && strings.Contains(line, `"`+home) {
- t.Fatalf("Help for %q should use ~ instead of %q on:\n%s",
+ c.Fatalf("Help for %q should use ~ instead of %q on:\n%s",
cmd, home, line)
}
i := strings.Index(line, "~")
if i >= 0 && i != len(line)-1 && line[i+1] != '/' {
- t.Fatalf("Help for %q should not have used ~:\n%s", cmd, line)
+ c.Fatalf("Help for %q should not have used ~:\n%s", cmd, line)
}
// If a line starts with 4 spaces then assume someone
// added a multi-line description for an option and we need
// to flag it
if strings.HasPrefix(line, " ") {
- t.Fatalf("Help for %q should not have a multi-line option: %s", cmd, line)
+ c.Fatalf("Help for %q should not have a multi-line option: %s", cmd, line)
}
// Options should NOT end with a period
if strings.HasPrefix(line, " -") && strings.HasSuffix(line, ".") {
- t.Fatalf("Help for %q should not end with a period: %s", cmd, line)
+ c.Fatalf("Help for %q should not end with a period: %s", cmd, line)
}
// Options should NOT end with a space
if strings.HasSuffix(line, " ") {
- t.Fatalf("Help for %q should not end with a space: %s", cmd, line)
+ c.Fatalf("Help for %q should not end with a space: %s", cmd, line)
}
}
@@ -146,10 +146,9 @@ func TestHelpTextVerify(t *testing.T) {
expected := 39
if len(cmds) != expected {
- t.Fatalf("Wrong # of cmds(%d), it should be: %d\nThe list:\n%q",
+ c.Fatalf("Wrong # of cmds(%d), it should be: %d\nThe list:\n%q",
len(cmds), expected, cmds)
}
}
- logDone("help - verify text")
}
diff --git a/integration-cli/docker_cli_history_test.go b/integration-cli/docker_cli_history_test.go
index ecb0a3a07ec06..d229f1a8c58f8 100644
--- a/integration-cli/docker_cli_history_test.go
+++ b/integration-cli/docker_cli_history_test.go
@@ -3,15 +3,17 @@ package main
import (
"fmt"
"os/exec"
+ "regexp"
+ "strconv"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
// This is a heisen-test. Because the created timestamp of images and the behavior of
// sort is not predictable it doesn't always fail.
-func TestBuildHistory(t *testing.T) {
+func (s *DockerSuite) TestBuildHistory(c *check.C) {
name := "testbuildhistory"
- defer deleteImages(name)
_, err := buildImage(name, `FROM busybox
RUN echo "A"
RUN echo "B"
@@ -42,12 +44,12 @@ RUN echo "Z"`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
out, exitCode, err := runCommandWithOutput(exec.Command(dockerBinary, "history", "testbuildhistory"))
if err != nil || exitCode != 0 {
- t.Fatalf("failed to get image history: %s, %v", out, err)
+ c.Fatalf("failed to get image history: %s, %v", out, err)
}
actualValues := strings.Split(out, "\n")[1:27]
@@ -58,27 +60,101 @@ RUN echo "Z"`,
actualValue := actualValues[i]
if !strings.Contains(actualValue, echoValue) {
- t.Fatalf("Expected layer \"%s\", but was: %s", expectedValues[i], actualValue)
+ c.Fatalf("Expected layer \"%s\", but was: %s", expectedValues[i], actualValue)
}
}
- logDone("history - build history")
}
-func TestHistoryExistentImage(t *testing.T) {
+func (s *DockerSuite) TestHistoryExistentImage(c *check.C) {
historyCmd := exec.Command(dockerBinary, "history", "busybox")
_, exitCode, err := runCommandWithOutput(historyCmd)
if err != nil || exitCode != 0 {
- t.Fatal("failed to get image history")
+ c.Fatal("failed to get image history")
}
- logDone("history - history on existent image must pass")
}
-func TestHistoryNonExistentImage(t *testing.T) {
+func (s *DockerSuite) TestHistoryNonExistentImage(c *check.C) {
historyCmd := exec.Command(dockerBinary, "history", "testHistoryNonExistentImage")
_, exitCode, err := runCommandWithOutput(historyCmd)
if err == nil || exitCode == 0 {
- t.Fatal("history on a non-existent image didn't result in a non-zero exit status")
+ c.Fatal("history on a non-existent image didn't result in a non-zero exit status")
+ }
+}
+
+func (s *DockerSuite) TestHistoryImageWithComment(c *check.C) {
+ name := "testhistoryimagewithcomment"
+
+ // make a image through docker commit [ -m messages ]
+ //runCmd := exec.Command(dockerBinary, "run", "-i", "-a", "stdin", "busybox", "echo", "foo")
+ runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "true")
+ out, _, err := runCommandWithOutput(runCmd)
+ if err != nil {
+ c.Fatalf("failed to run container: %s, %v", out, err)
+ }
+
+ waitCmd := exec.Command(dockerBinary, "wait", name)
+ if out, _, err := runCommandWithOutput(waitCmd); err != nil {
+ c.Fatalf("error thrown while waiting for container: %s, %v", out, err)
+ }
+
+ comment := "This_is_a_comment"
+
+ commitCmd := exec.Command(dockerBinary, "commit", "-m="+comment, name, name)
+ if out, _, err := runCommandWithOutput(commitCmd); err != nil {
+ c.Fatalf("failed to commit container to image: %s, %v", out, err)
+ }
+
+ // test docker history to check comment messages
+ historyCmd := exec.Command(dockerBinary, "history", name)
+ out, exitCode, err := runCommandWithOutput(historyCmd)
+ if err != nil || exitCode != 0 {
+ c.Fatalf("failed to get image history: %s, %v", out, err)
+ }
+
+ outputTabs := strings.Fields(strings.Split(out, "\n")[1])
+ //outputTabs := regexp.MustCompile(" +").Split(outputLine, -1)
+ actualValue := outputTabs[len(outputTabs)-1]
+
+ if !strings.Contains(actualValue, comment) {
+ c.Fatalf("Expected comments %q, but found %q", comment, actualValue)
+ }
+
+}
+
+func (s *DockerSuite) TestHistoryHumanOptionFalse(c *check.C) {
+ out, _, _ := runCommandWithOutput(exec.Command(dockerBinary, "history", "--human=false", "busybox"))
+ lines := strings.Split(out, "\n")
+ sizeColumnRegex, _ := regexp.Compile("SIZE +")
+ indices := sizeColumnRegex.FindStringIndex(lines[0])
+ startIndex := indices[0]
+ endIndex := indices[1]
+ for i := 1; i < len(lines)-1; i++ {
+ if endIndex > len(lines[i]) {
+ endIndex = len(lines[i])
+ }
+ sizeString := lines[i][startIndex:endIndex]
+ if _, err := strconv.Atoi(strings.TrimSpace(sizeString)); err != nil {
+ c.Fatalf("The size '%s' was not an Integer", sizeString)
+ }
+ }
+}
+
+func (s *DockerSuite) TestHistoryHumanOptionTrue(c *check.C) {
+ out, _, _ := runCommandWithOutput(exec.Command(dockerBinary, "history", "--human=true", "busybox"))
+ lines := strings.Split(out, "\n")
+ sizeColumnRegex, _ := regexp.Compile("SIZE +")
+ humanSizeRegex, _ := regexp.Compile("^\\d+.*B$") // Matches human sizes like 10 MB, 3.2 KB, etc
+ indices := sizeColumnRegex.FindStringIndex(lines[0])
+ startIndex := indices[0]
+ endIndex := indices[1]
+ for i := 1; i < len(lines)-1; i++ {
+ if endIndex > len(lines[i]) {
+ endIndex = len(lines[i])
+ }
+ sizeString := lines[i][startIndex:endIndex]
+ if matchSuccess := humanSizeRegex.MatchString(strings.TrimSpace(sizeString)); !matchSuccess {
+ c.Fatalf("The size '%s' was not in human format", sizeString)
+ }
}
- logDone("history - history on non-existent image must pass")
}
diff --git a/integration-cli/docker_cli_images_test.go b/integration-cli/docker_cli_images_test.go
index 28b091efdf82c..0ab6462509340 100644
--- a/integration-cli/docker_cli_images_test.go
+++ b/integration-cli/docker_cli_images_test.go
@@ -6,137 +6,124 @@ import (
"reflect"
"sort"
"strings"
- "testing"
"time"
"github.com/docker/docker/pkg/stringid"
+ "github.com/go-check/check"
)
-func TestImagesEnsureImageIsListed(t *testing.T) {
+func (s *DockerSuite) TestImagesEnsureImageIsListed(c *check.C) {
imagesCmd := exec.Command(dockerBinary, "images")
out, _, err := runCommandWithOutput(imagesCmd)
if err != nil {
- t.Fatalf("listing images failed with errors: %s, %v", out, err)
+ c.Fatalf("listing images failed with errors: %s, %v", out, err)
}
if !strings.Contains(out, "busybox") {
- t.Fatal("images should've listed busybox")
+ c.Fatal("images should've listed busybox")
}
- logDone("images - busybox should be listed")
}
-func TestImagesOrderedByCreationDate(t *testing.T) {
- defer deleteImages("order:test_a")
- defer deleteImages("order:test_c")
- defer deleteImages("order:test_b")
+func (s *DockerSuite) TestImagesOrderedByCreationDate(c *check.C) {
id1, err := buildImage("order:test_a",
`FROM scratch
MAINTAINER dockerio1`, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
time.Sleep(time.Second)
id2, err := buildImage("order:test_c",
`FROM scratch
MAINTAINER dockerio2`, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
time.Sleep(time.Second)
id3, err := buildImage("order:test_b",
`FROM scratch
MAINTAINER dockerio3`, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "images", "-q", "--no-trunc"))
if err != nil {
- t.Fatalf("listing images failed with errors: %s, %v", out, err)
+ c.Fatalf("listing images failed with errors: %s, %v", out, err)
}
imgs := strings.Split(out, "\n")
if imgs[0] != id3 {
- t.Fatalf("First image must be %s, got %s", id3, imgs[0])
+ c.Fatalf("First image must be %s, got %s", id3, imgs[0])
}
if imgs[1] != id2 {
- t.Fatalf("Second image must be %s, got %s", id2, imgs[1])
+ c.Fatalf("Second image must be %s, got %s", id2, imgs[1])
}
if imgs[2] != id1 {
- t.Fatalf("Third image must be %s, got %s", id1, imgs[2])
+ c.Fatalf("Third image must be %s, got %s", id1, imgs[2])
}
- logDone("images - ordering by creation date")
}
-func TestImagesErrorWithInvalidFilterNameTest(t *testing.T) {
+func (s *DockerSuite) TestImagesErrorWithInvalidFilterNameTest(c *check.C) {
imagesCmd := exec.Command(dockerBinary, "images", "-f", "FOO=123")
out, _, err := runCommandWithOutput(imagesCmd)
if !strings.Contains(out, "Invalid filter") {
- t.Fatalf("error should occur when listing images with invalid filter name FOO, %s, %v", out, err)
+ c.Fatalf("error should occur when listing images with invalid filter name FOO, %s, %v", out, err)
}
- logDone("images - invalid filter name check working")
}
-func TestImagesFilterLabel(t *testing.T) {
+func (s *DockerSuite) TestImagesFilterLabel(c *check.C) {
imageName1 := "images_filter_test1"
imageName2 := "images_filter_test2"
imageName3 := "images_filter_test3"
- defer deleteAllContainers()
- defer deleteImages(imageName1)
- defer deleteImages(imageName2)
- defer deleteImages(imageName3)
image1ID, err := buildImage(imageName1,
`FROM scratch
LABEL match me`, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
image2ID, err := buildImage(imageName2,
`FROM scratch
LABEL match="me too"`, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
image3ID, err := buildImage(imageName3,
`FROM scratch
LABEL nomatch me`, true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd := exec.Command(dockerBinary, "images", "--no-trunc", "-q", "-f", "label=match")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
out = strings.TrimSpace(out)
if (!strings.Contains(out, image1ID) && !strings.Contains(out, image2ID)) || strings.Contains(out, image3ID) {
- t.Fatalf("Expected ids %s,%s got %s", image1ID, image2ID, out)
+ c.Fatalf("Expected ids %s,%s got %s", image1ID, image2ID, out)
}
cmd = exec.Command(dockerBinary, "images", "--no-trunc", "-q", "-f", "label=match=me too")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
out = strings.TrimSpace(out)
if out != image2ID {
- t.Fatalf("Expected %s got %s", image2ID, out)
+ c.Fatalf("Expected %s got %s", image2ID, out)
}
- logDone("images - filter label")
}
-func TestImagesFilterWhiteSpaceTrimmingAndLowerCasingWorking(t *testing.T) {
+func (s *DockerSuite) TestImagesFilterSpaceTrimCase(c *check.C) {
imageName := "images_filter_test"
- defer deleteAllContainers()
- defer deleteImages(imageName)
buildImage(imageName,
`FROM scratch
RUN touch /test/foo
@@ -156,7 +143,7 @@ func TestImagesFilterWhiteSpaceTrimmingAndLowerCasingWorking(t *testing.T) {
cmd := exec.Command(dockerBinary, "images", "-q", "-f", filter)
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
listing := strings.Split(out, "\n")
sort.Strings(listing)
@@ -172,50 +159,45 @@ func TestImagesFilterWhiteSpaceTrimmingAndLowerCasingWorking(t *testing.T) {
}
fmt.Print("")
}
- t.Fatalf("All output must be the same")
+ c.Fatalf("All output must be the same")
}
}
- logDone("images - white space trimming and lower casing")
}
-func TestImagesEnsureDanglingImageOnlyListedOnce(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestImagesEnsureDanglingImageOnlyListedOnce(c *check.C) {
// create container 1
- c := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
- out, _, err := runCommandWithOutput(c)
+ cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
+ out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error running busybox: %s, %v", out, err)
+ c.Fatalf("error running busybox: %s, %v", out, err)
}
containerId1 := strings.TrimSpace(out)
// tag as foobox
- c = exec.Command(dockerBinary, "commit", containerId1, "foobox")
- out, _, err = runCommandWithOutput(c)
+ cmd = exec.Command(dockerBinary, "commit", containerId1, "foobox")
+ out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error tagging foobox: %s", err)
+ c.Fatalf("error tagging foobox: %s", err)
}
imageId := stringid.TruncateID(strings.TrimSpace(out))
- defer deleteImages(imageId)
// overwrite the tag, making the previous image dangling
- c = exec.Command(dockerBinary, "tag", "-f", "busybox", "foobox")
- out, _, err = runCommandWithOutput(c)
+ cmd = exec.Command(dockerBinary, "tag", "-f", "busybox", "foobox")
+ out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("error tagging foobox: %s", err)
+ c.Fatalf("error tagging foobox: %s", err)
}
- defer deleteImages("foobox")
- c = exec.Command(dockerBinary, "images", "-q", "-f", "dangling=true")
- out, _, err = runCommandWithOutput(c)
+ cmd = exec.Command(dockerBinary, "images", "-q", "-f", "dangling=true")
+ out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("listing images failed with errors: %s, %v", out, err)
+ c.Fatalf("listing images failed with errors: %s, %v", out, err)
}
if e, a := 1, strings.Count(out, imageId); e != a {
- t.Fatalf("expected 1 dangling image, got %d: %s", a, out)
+ c.Fatalf("expected 1 dangling image, got %d: %s", a, out)
}
- logDone("images - dangling image only listed once")
}
diff --git a/integration-cli/docker_cli_import_test.go b/integration-cli/docker_cli_import_test.go
index 087d08bd55b59..201dbaa580e7f 100644
--- a/integration-cli/docker_cli_import_test.go
+++ b/integration-cli/docker_cli_import_test.go
@@ -3,41 +3,39 @@ package main
import (
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
-func TestImportDisplay(t *testing.T) {
+func (s *DockerSuite) TestImportDisplay(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal("failed to create a container", out, err)
+ c.Fatal("failed to create a container", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
- defer deleteContainer(cleanedContainerID)
out, _, err = runCommandPipelineWithOutput(
exec.Command(dockerBinary, "export", cleanedContainerID),
exec.Command(dockerBinary, "import", "-"),
)
if err != nil {
- t.Errorf("import failed with errors: %v, output: %q", err, out)
+ c.Errorf("import failed with errors: %v, output: %q", err, out)
}
if n := strings.Count(out, "\n"); n != 1 {
- t.Fatalf("display is messed up: %d '\\n' instead of 1:\n%s", n, out)
+ c.Fatalf("display is messed up: %d '\\n' instead of 1:\n%s", n, out)
}
image := strings.TrimSpace(out)
- defer deleteImages(image)
runCmd = exec.Command(dockerBinary, "run", "--rm", image, "true")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal("failed to create a container", out, err)
+ c.Fatal("failed to create a container", out, err)
}
if out != "" {
- t.Fatalf("command output should've been nothing, was %q", out)
+ c.Fatalf("command output should've been nothing, was %q", out)
}
- logDone("import - display is fine, imported image runs")
}
diff --git a/integration-cli/docker_cli_info_test.go b/integration-cli/docker_cli_info_test.go
index e6b79f01f769a..a7a931e8524a3 100644
--- a/integration-cli/docker_cli_info_test.go
+++ b/integration-cli/docker_cli_info_test.go
@@ -3,15 +3,16 @@ package main
import (
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
// ensure docker info succeeds
-func TestInfoEnsureSucceeds(t *testing.T) {
+func (s *DockerSuite) TestInfoEnsureSucceeds(c *check.C) {
versionCmd := exec.Command(dockerBinary, "info")
out, exitCode, err := runCommandWithOutput(versionCmd)
if err != nil || exitCode != 0 {
- t.Fatalf("failed to execute docker info: %s, %v", out, err)
+ c.Fatalf("failed to execute docker info: %s, %v", out, err)
}
// always shown fields
@@ -29,9 +30,8 @@ func TestInfoEnsureSucceeds(t *testing.T) {
for _, linePrefix := range stringsToCheck {
if !strings.Contains(out, linePrefix) {
- t.Errorf("couldn't find string %v in output", linePrefix)
+ c.Errorf("couldn't find string %v in output", linePrefix)
}
}
- logDone("info - verify that it works")
}
diff --git a/integration-cli/docker_cli_inspect_test.go b/integration-cli/docker_cli_inspect_test.go
index cf42217ac882a..58c61a9d0f8d5 100644
--- a/integration-cli/docker_cli_inspect_test.go
+++ b/integration-cli/docker_cli_inspect_test.go
@@ -1,23 +1,100 @@
package main
import (
+ "fmt"
"os/exec"
+ "strconv"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
-func TestInspectImage(t *testing.T) {
+func (s *DockerSuite) TestInspectImage(c *check.C) {
imageTest := "emptyfs"
imageTestID := "511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158"
imagesCmd := exec.Command(dockerBinary, "inspect", "--format='{{.Id}}'", imageTest)
out, exitCode, err := runCommandWithOutput(imagesCmd)
if exitCode != 0 || err != nil {
- t.Fatalf("failed to inspect image: %s, %v", out, err)
+ c.Fatalf("failed to inspect image: %s, %v", out, err)
}
if id := strings.TrimSuffix(out, "\n"); id != imageTestID {
- t.Fatalf("Expected id: %s for image: %s but received id: %s", imageTestID, imageTest, id)
+ c.Fatalf("Expected id: %s for image: %s but received id: %s", imageTestID, imageTest, id)
+ }
+
+}
+
+func (s *DockerSuite) TestInspectInt64(c *check.C) {
+ runCmd := exec.Command(dockerBinary, "run", "-d", "-m=300M", "busybox", "true")
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ if err != nil {
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
+ }
+
+ out = strings.TrimSpace(out)
+
+ inspectCmd := exec.Command(dockerBinary, "inspect", "-f", "{{.HostConfig.Memory}}", out)
+ inspectOut, _, err := runCommandWithOutput(inspectCmd)
+ if err != nil {
+ c.Fatalf("failed to inspect container: %v, output: %q", err, inspectOut)
+ }
+
+ if strings.TrimSpace(inspectOut) != "314572800" {
+ c.Fatalf("inspect got wrong value, got: %q, expected: 314572800", inspectOut)
+ }
+}
+
+func (s *DockerSuite) TestInspectImageFilterInt(c *check.C) {
+ imageTest := "emptyfs"
+ imagesCmd := exec.Command(dockerBinary, "inspect", "--format='{{.Size}}'", imageTest)
+ out, exitCode, err := runCommandWithOutput(imagesCmd)
+ if exitCode != 0 || err != nil {
+ c.Fatalf("failed to inspect image: %s, %v", out, err)
+ }
+ size, err := strconv.Atoi(strings.TrimSuffix(out, "\n"))
+ if err != nil {
+ c.Fatalf("failed to inspect size of the image: %s, %v", out, err)
+ }
+
+ //now see if the size turns out to be the same
+ formatStr := fmt.Sprintf("--format='{{eq .Size %d}}'", size)
+ imagesCmd = exec.Command(dockerBinary, "inspect", formatStr, imageTest)
+ out, exitCode, err = runCommandWithOutput(imagesCmd)
+ if exitCode != 0 || err != nil {
+ c.Fatalf("failed to inspect image: %s, %v", out, err)
+ }
+ if result, err := strconv.ParseBool(strings.TrimSuffix(out, "\n")); err != nil || !result {
+ c.Fatalf("Expected size: %d for image: %s but received size: %s", size, imageTest, strings.TrimSuffix(out, "\n"))
}
+}
- logDone("inspect - inspect an image")
+func (s *DockerSuite) TestInspectContainerFilterInt(c *check.C) {
+ runCmd := exec.Command("bash", "-c", `echo "blahblah" | docker run -i -a stdin busybox cat`)
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ if err != nil {
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
+ }
+
+ id := strings.TrimSpace(out)
+
+ runCmd = exec.Command(dockerBinary, "inspect", "--format='{{.State.ExitCode}}'", id)
+ out, _, err = runCommandWithOutput(runCmd)
+ if err != nil {
+ c.Fatalf("failed to inspect container: %s, %v", out, err)
+ }
+ exitCode, err := strconv.Atoi(strings.TrimSuffix(out, "\n"))
+ if err != nil {
+ c.Fatalf("failed to inspect exitcode of the container: %s, %v", out, err)
+ }
+
+ //now get the exit code to verify
+ formatStr := fmt.Sprintf("--format='{{eq .State.ExitCode %d}}'", exitCode)
+ runCmd = exec.Command(dockerBinary, "inspect", formatStr, id)
+ out, _, err = runCommandWithOutput(runCmd)
+ if err != nil {
+ c.Fatalf("failed to inspect container: %s, %v", out, err)
+ }
+ if result, err := strconv.ParseBool(strings.TrimSuffix(out, "\n")); err != nil || !result {
+ c.Fatalf("Expected exitcode: %d for container: %s", exitCode, id)
+ }
}
diff --git a/integration-cli/docker_cli_kill_test.go b/integration-cli/docker_cli_kill_test.go
index cd86c0c567667..d08709671da30 100644
--- a/integration-cli/docker_cli_kill_test.go
+++ b/integration-cli/docker_cli_kill_test.go
@@ -3,73 +3,72 @@ package main
import (
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
-func TestKillContainer(t *testing.T) {
+func (s *DockerSuite) TestKillContainer(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
if out, _, err = runCommandWithOutput(inspectCmd); err != nil {
- t.Fatalf("out should've been a container id: %s, %v", out, err)
+ c.Fatalf("out should've been a container id: %s, %v", out, err)
}
killCmd := exec.Command(dockerBinary, "kill", cleanedContainerID)
if out, _, err = runCommandWithOutput(killCmd); err != nil {
- t.Fatalf("failed to kill container: %s, %v", out, err)
+ c.Fatalf("failed to kill container: %s, %v", out, err)
}
listRunningContainersCmd := exec.Command(dockerBinary, "ps", "-q")
out, _, err = runCommandWithOutput(listRunningContainersCmd)
if err != nil {
- t.Fatalf("failed to list running containers: %s, %v", out, err)
+ c.Fatalf("failed to list running containers: %s, %v", out, err)
}
if strings.Contains(out, cleanedContainerID) {
- t.Fatal("killed container is still running")
+ c.Fatal("killed container is still running")
}
deleteContainer(cleanedContainerID)
- logDone("kill - kill container running top")
}
-func TestKillDifferentUserContainer(t *testing.T) {
+func (s *DockerSuite) TestKillDifferentUserContainer(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-u", "daemon", "-d", "busybox", "top")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
if out, _, err = runCommandWithOutput(inspectCmd); err != nil {
- t.Fatalf("out should've been a container id: %s, %v", out, err)
+ c.Fatalf("out should've been a container id: %s, %v", out, err)
}
killCmd := exec.Command(dockerBinary, "kill", cleanedContainerID)
if out, _, err = runCommandWithOutput(killCmd); err != nil {
- t.Fatalf("failed to kill container: %s, %v", out, err)
+ c.Fatalf("failed to kill container: %s, %v", out, err)
}
listRunningContainersCmd := exec.Command(dockerBinary, "ps", "-q")
out, _, err = runCommandWithOutput(listRunningContainersCmd)
if err != nil {
- t.Fatalf("failed to list running containers: %s, %v", out, err)
+ c.Fatalf("failed to list running containers: %s, %v", out, err)
}
if strings.Contains(out, cleanedContainerID) {
- t.Fatal("killed container is still running")
+ c.Fatal("killed container is still running")
}
deleteContainer(cleanedContainerID)
- logDone("kill - kill container running top from a different user")
}
diff --git a/integration-cli/docker_cli_links_test.go b/integration-cli/docker_cli_links_test.go
index 04718c23f0bed..6bb173c10cc20 100644
--- a/integration-cli/docker_cli_links_test.go
+++ b/integration-cli/docker_cli_links_test.go
@@ -8,89 +8,81 @@ import (
"reflect"
"regexp"
"strings"
- "testing"
"time"
"github.com/docker/docker/pkg/iptables"
+ "github.com/go-check/check"
)
-func TestLinksEtcHostsRegularFile(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestLinksEtcHostsRegularFile(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "--net=host", "busybox", "ls", "-la", "/etc/hosts")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if !strings.HasPrefix(out, "-") {
- t.Errorf("/etc/hosts should be a regular file")
+ c.Errorf("/etc/hosts should be a regular file")
}
- logDone("link - /etc/hosts is a regular file")
}
-func TestLinksEtcHostsContentMatch(t *testing.T) {
- testRequires(t, SameHostDaemon)
- defer deleteAllContainers()
+func (s *DockerSuite) TestLinksEtcHostsContentMatch(c *check.C) {
+ testRequires(c, SameHostDaemon)
runCmd := exec.Command(dockerBinary, "run", "--net=host", "busybox", "cat", "/etc/hosts")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
hosts, err := ioutil.ReadFile("/etc/hosts")
if os.IsNotExist(err) {
- t.Skip("/etc/hosts does not exist, skip this test")
+ c.Skip("/etc/hosts does not exist, skip this test")
}
if out != string(hosts) {
- t.Errorf("container")
+ c.Errorf("container")
}
- logDone("link - /etc/hosts matches hosts copy")
}
-func TestLinksPingUnlinkedContainers(t *testing.T) {
+func (s *DockerSuite) TestLinksPingUnlinkedContainers(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "--rm", "busybox", "sh", "-c", "ping -c 1 alias1 -W 1 && ping -c 1 alias2 -W 1")
exitCode, err := runCommand(runCmd)
if exitCode == 0 {
- t.Fatal("run ping did not fail")
+ c.Fatal("run ping did not fail")
} else if exitCode != 1 {
- t.Fatalf("run ping failed with errors: %v", err)
+ c.Fatalf("run ping failed with errors: %v", err)
}
- logDone("links - ping unlinked container")
}
// Test for appropriate error when calling --link with an invalid target container
-func TestLinksInvalidContainerTarget(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestLinksInvalidContainerTarget(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "--link", "bogus:alias", "busybox", "true")
out, _, err := runCommandWithOutput(runCmd)
if err == nil {
- t.Fatal("an invalid container target should produce an error")
+ c.Fatal("an invalid container target should produce an error")
}
if !strings.Contains(out, "Could not get container") {
- t.Fatalf("error output expected 'Could not get container', but got %q instead; err: %v", out, err)
+ c.Fatalf("error output expected 'Could not get container', but got %q instead; err: %v", out, err)
}
- logDone("links - linking to non-existent container should not work")
}
-func TestLinksPingLinkedContainers(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestLinksPingLinkedContainers(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "container1", "--hostname", "fred", "busybox", "top")
if _, err := runCommand(runCmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
runCmd = exec.Command(dockerBinary, "run", "-d", "--name", "container2", "--hostname", "wilma", "busybox", "top")
if _, err := runCommand(runCmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
runArgs := []string{"run", "--rm", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "sh", "-c"}
@@ -98,74 +90,68 @@ func TestLinksPingLinkedContainers(t *testing.T) {
// test ping by alias, ping by name, and ping by hostname
// 1. Ping by alias
- dockerCmd(t, append(runArgs, fmt.Sprintf(pingCmd, "alias1", "alias2"))...)
+ dockerCmd(c, append(runArgs, fmt.Sprintf(pingCmd, "alias1", "alias2"))...)
// 2. Ping by container name
- dockerCmd(t, append(runArgs, fmt.Sprintf(pingCmd, "container1", "container2"))...)
+ dockerCmd(c, append(runArgs, fmt.Sprintf(pingCmd, "container1", "container2"))...)
// 3. Ping by hostname
- dockerCmd(t, append(runArgs, fmt.Sprintf(pingCmd, "fred", "wilma"))...)
+ dockerCmd(c, append(runArgs, fmt.Sprintf(pingCmd, "fred", "wilma"))...)
- logDone("links - ping linked container")
}
-func TestLinksPingLinkedContainersAfterRename(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestLinksPingLinkedContainersAfterRename(c *check.C) {
- out, _, _ := dockerCmd(t, "run", "-d", "--name", "container1", "busybox", "top")
+ out, _ := dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
idA := strings.TrimSpace(out)
- out, _, _ = dockerCmd(t, "run", "-d", "--name", "container2", "busybox", "top")
+ out, _ = dockerCmd(c, "run", "-d", "--name", "container2", "busybox", "top")
idB := strings.TrimSpace(out)
- dockerCmd(t, "rename", "container1", "container_new")
- dockerCmd(t, "run", "--rm", "--link", "container_new:alias1", "--link", "container2:alias2", "busybox", "sh", "-c", "ping -c 1 alias1 -W 1 && ping -c 1 alias2 -W 1")
- dockerCmd(t, "kill", idA)
- dockerCmd(t, "kill", idB)
+ dockerCmd(c, "rename", "container1", "container_new")
+ dockerCmd(c, "run", "--rm", "--link", "container_new:alias1", "--link", "container2:alias2", "busybox", "sh", "-c", "ping -c 1 alias1 -W 1 && ping -c 1 alias2 -W 1")
+ dockerCmd(c, "kill", idA)
+ dockerCmd(c, "kill", idB)
- logDone("links - ping linked container after rename")
}
-func TestLinksIpTablesRulesWhenLinkAndUnlink(t *testing.T) {
- testRequires(t, SameHostDaemon)
- defer deleteAllContainers()
+func (s *DockerSuite) TestLinksIpTablesRulesWhenLinkAndUnlink(c *check.C) {
+ testRequires(c, SameHostDaemon)
- dockerCmd(t, "run", "-d", "--name", "child", "--publish", "8080:80", "busybox", "top")
- dockerCmd(t, "run", "-d", "--name", "parent", "--link", "child:http", "busybox", "top")
+ dockerCmd(c, "run", "-d", "--name", "child", "--publish", "8080:80", "busybox", "top")
+ dockerCmd(c, "run", "-d", "--name", "parent", "--link", "child:http", "busybox", "top")
- childIP := findContainerIP(t, "child")
- parentIP := findContainerIP(t, "parent")
+ childIP := findContainerIP(c, "child")
+ parentIP := findContainerIP(c, "parent")
sourceRule := []string{"-i", "docker0", "-o", "docker0", "-p", "tcp", "-s", childIP, "--sport", "80", "-d", parentIP, "-j", "ACCEPT"}
destinationRule := []string{"-i", "docker0", "-o", "docker0", "-p", "tcp", "-s", parentIP, "--dport", "80", "-d", childIP, "-j", "ACCEPT"}
if !iptables.Exists("filter", "DOCKER", sourceRule...) || !iptables.Exists("filter", "DOCKER", destinationRule...) {
- t.Fatal("Iptables rules not found")
+ c.Fatal("Iptables rules not found")
}
- dockerCmd(t, "rm", "--link", "parent/http")
+ dockerCmd(c, "rm", "--link", "parent/http")
if iptables.Exists("filter", "DOCKER", sourceRule...) || iptables.Exists("filter", "DOCKER", destinationRule...) {
- t.Fatal("Iptables rules should be removed when unlink")
+ c.Fatal("Iptables rules should be removed when unlink")
}
- dockerCmd(t, "kill", "child")
- dockerCmd(t, "kill", "parent")
+ dockerCmd(c, "kill", "child")
+ dockerCmd(c, "kill", "parent")
- logDone("link - verify iptables when link and unlink")
}
-func TestLinksInspectLinksStarted(t *testing.T) {
+func (s *DockerSuite) TestLinksInspectLinksStarted(c *check.C) {
var (
expected = map[string]struct{}{"/container1:/testinspectlink/alias1": {}, "/container2:/testinspectlink/alias2": {}}
result []string
)
- defer deleteAllContainers()
- dockerCmd(t, "run", "-d", "--name", "container1", "busybox", "top")
- dockerCmd(t, "run", "-d", "--name", "container2", "busybox", "top")
- dockerCmd(t, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "top")
+ dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
+ dockerCmd(c, "run", "-d", "--name", "container2", "busybox", "top")
+ dockerCmd(c, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "top")
links, err := inspectFieldJSON("testinspectlink", "HostConfig.Links")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
err = unmarshalJSON([]byte(links), &result)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
output := convertSliceOfStringsToMap(result)
@@ -173,28 +159,26 @@ func TestLinksInspectLinksStarted(t *testing.T) {
equal := reflect.DeepEqual(output, expected)
if !equal {
- t.Fatalf("Links %s, expected %s", result, expected)
+ c.Fatalf("Links %s, expected %s", result, expected)
}
- logDone("link - links in started container inspect")
}
-func TestLinksInspectLinksStopped(t *testing.T) {
+func (s *DockerSuite) TestLinksInspectLinksStopped(c *check.C) {
var (
expected = map[string]struct{}{"/container1:/testinspectlink/alias1": {}, "/container2:/testinspectlink/alias2": {}}
result []string
)
- defer deleteAllContainers()
- dockerCmd(t, "run", "-d", "--name", "container1", "busybox", "top")
- dockerCmd(t, "run", "-d", "--name", "container2", "busybox", "top")
- dockerCmd(t, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "true")
+ dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
+ dockerCmd(c, "run", "-d", "--name", "container2", "busybox", "top")
+ dockerCmd(c, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "true")
links, err := inspectFieldJSON("testinspectlink", "HostConfig.Links")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
err = unmarshalJSON([]byte(links), &result)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
output := convertSliceOfStringsToMap(result)
@@ -202,47 +186,42 @@ func TestLinksInspectLinksStopped(t *testing.T) {
equal := reflect.DeepEqual(output, expected)
if !equal {
- t.Fatalf("Links %s, but expected %s", result, expected)
+ c.Fatalf("Links %s, but expected %s", result, expected)
}
- logDone("link - links in stopped container inspect")
}
-func TestLinksNotStartedParentNotFail(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestLinksNotStartedParentNotFail(c *check.C) {
runCmd := exec.Command(dockerBinary, "create", "--name=first", "busybox", "top")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
runCmd = exec.Command(dockerBinary, "create", "--name=second", "--link=first:first", "busybox", "top")
out, _, _, err = runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
runCmd = exec.Command(dockerBinary, "start", "first")
out, _, _, err = runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
- logDone("link - container start successfully updating stopped parent links")
}
-func TestLinksHostsFilesInject(t *testing.T) {
- testRequires(t, SameHostDaemon, ExecSupport)
-
- defer deleteAllContainers()
+func (s *DockerSuite) TestLinksHostsFilesInject(c *check.C) {
+ testRequires(c, SameHostDaemon, ExecSupport)
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-itd", "--name", "one", "busybox", "top"))
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
idOne := strings.TrimSpace(out)
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "-itd", "--name", "two", "--link", "one:onetwo", "busybox", "top"))
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
idTwo := strings.TrimSpace(out)
@@ -251,89 +230,104 @@ func TestLinksHostsFilesInject(t *testing.T) {
contentOne, err := readContainerFileWithExec(idOne, "/etc/hosts")
if err != nil {
- t.Fatal(err, string(contentOne))
+ c.Fatal(err, string(contentOne))
}
contentTwo, err := readContainerFileWithExec(idTwo, "/etc/hosts")
if err != nil {
- t.Fatal(err, string(contentTwo))
+ c.Fatal(err, string(contentTwo))
}
if !strings.Contains(string(contentTwo), "onetwo") {
- t.Fatal("Host is not present in updated hosts file", string(contentTwo))
+ c.Fatal("Host is not present in updated hosts file", string(contentTwo))
}
- logDone("link - ensure containers hosts files are updated with the link alias.")
}
-func TestLinksNetworkHostContainer(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestLinksNetworkHostContainer(c *check.C) {
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--net", "host", "--name", "host_container", "busybox", "top"))
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "--name", "should_fail", "--link", "host_container:tester", "busybox", "true"))
if err == nil || !strings.Contains(out, "--net=host can't be used with links. This would result in undefined behavior.") {
- t.Fatalf("Running container linking to a container with --net host should have failed: %s", out)
+ c.Fatalf("Running container linking to a container with --net host should have failed: %s", out)
}
- logDone("link - error thrown when linking to container with --net host")
}
-func TestLinksUpdateOnRestart(t *testing.T) {
- testRequires(t, SameHostDaemon, ExecSupport)
-
- defer deleteAllContainers()
+func (s *DockerSuite) TestLinksUpdateOnRestart(c *check.C) {
+ testRequires(c, SameHostDaemon, ExecSupport)
if out, err := exec.Command(dockerBinary, "run", "-d", "--name", "one", "busybox", "top").CombinedOutput(); err != nil {
- t.Fatal(err, string(out))
+ c.Fatal(err, string(out))
}
out, err := exec.Command(dockerBinary, "run", "-d", "--name", "two", "--link", "one:onetwo", "--link", "one:one", "busybox", "top").CombinedOutput()
if err != nil {
- t.Fatal(err, string(out))
+ c.Fatal(err, string(out))
}
id := strings.TrimSpace(string(out))
realIP, err := inspectField("one", "NetworkSettings.IPAddress")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
content, err := readContainerFileWithExec(id, "/etc/hosts")
if err != nil {
- t.Fatal(err, string(content))
+ c.Fatal(err, string(content))
}
getIP := func(hosts []byte, hostname string) string {
re := regexp.MustCompile(fmt.Sprintf(`(\S*)\t%s`, regexp.QuoteMeta(hostname)))
matches := re.FindSubmatch(hosts)
if matches == nil {
- t.Fatalf("Hostname %s have no matches in hosts", hostname)
+ c.Fatalf("Hostname %s have no matches in hosts", hostname)
}
return string(matches[1])
}
if ip := getIP(content, "one"); ip != realIP {
- t.Fatalf("For 'one' alias expected IP: %s, got: %s", realIP, ip)
+ c.Fatalf("For 'one' alias expected IP: %s, got: %s", realIP, ip)
}
if ip := getIP(content, "onetwo"); ip != realIP {
- t.Fatalf("For 'onetwo' alias expected IP: %s, got: %s", realIP, ip)
+ c.Fatalf("For 'onetwo' alias expected IP: %s, got: %s", realIP, ip)
}
if out, err := exec.Command(dockerBinary, "restart", "one").CombinedOutput(); err != nil {
- t.Fatal(err, string(out))
+ c.Fatal(err, string(out))
}
realIP, err = inspectField("one", "NetworkSettings.IPAddress")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
content, err = readContainerFileWithExec(id, "/etc/hosts")
if err != nil {
- t.Fatal(err, string(content))
+ c.Fatal(err, string(content))
}
if ip := getIP(content, "one"); ip != realIP {
- t.Fatalf("For 'one' alias expected IP: %s, got: %s", realIP, ip)
+ c.Fatalf("For 'one' alias expected IP: %s, got: %s", realIP, ip)
}
if ip := getIP(content, "onetwo"); ip != realIP {
- t.Fatalf("For 'onetwo' alias expected IP: %s, got: %s", realIP, ip)
+ c.Fatalf("For 'onetwo' alias expected IP: %s, got: %s", realIP, ip)
+ }
+}
+
+func (s *DockerSuite) TestLinksEnvs(c *check.C) {
+ runCmd := exec.Command(dockerBinary, "run", "-d", "-e", "e1=", "-e", "e2=v2", "-e", "e3=v3=v3", "--name=first", "busybox", "top")
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ if err != nil {
+ c.Fatalf("Run of first failed: %s\n%s", out, err)
+ }
+
+ runCmd = exec.Command(dockerBinary, "run", "--name=second", "--link=first:first", "busybox", "env")
+
+ out, stde, rc, err := runCommandWithStdoutStderr(runCmd)
+ if err != nil || rc != 0 {
+ c.Fatalf("run of 2nd failed: rc: %d, out: %s\n err: %s", rc, out, stde)
+ }
+
+ if !strings.Contains(out, "FIRST_ENV_e1=\n") ||
+ !strings.Contains(out, "FIRST_ENV_e2=v2") ||
+ !strings.Contains(out, "FIRST_ENV_e3=v3=v3") {
+ c.Fatalf("Incorrect output: %s", out)
}
- logDone("link - ensure containers hosts files are updated on restart")
}
diff --git a/integration-cli/docker_cli_login_test.go b/integration-cli/docker_cli_login_test.go
index 9bf90f3adcd0b..3b4431d2d2fbc 100644
--- a/integration-cli/docker_cli_login_test.go
+++ b/integration-cli/docker_cli_login_test.go
@@ -3,10 +3,11 @@ package main
import (
"bytes"
"os/exec"
- "testing"
+
+ "github.com/go-check/check"
)
-func TestLoginWithoutTTY(t *testing.T) {
+func (s *DockerSuite) TestLoginWithoutTTY(c *check.C) {
cmd := exec.Command(dockerBinary, "login")
// Send to stdin so the process does not get the TTY
@@ -14,8 +15,7 @@ func TestLoginWithoutTTY(t *testing.T) {
// run the command and block until it's done
if err := cmd.Run(); err == nil {
- t.Fatal("Expected non nil err when loginning in & TTY not available")
+ c.Fatal("Expected non nil err when loginning in & TTY not available")
}
- logDone("login - login without TTY")
}
diff --git a/integration-cli/docker_cli_logs_test.go b/integration-cli/docker_cli_logs_test.go
index c236ef0859df8..0a3e1af981841 100644
--- a/integration-cli/docker_cli_logs_test.go
+++ b/integration-cli/docker_cli_logs_test.go
@@ -5,19 +5,19 @@ import (
"os/exec"
"regexp"
"strings"
- "testing"
"time"
"github.com/docker/docker/pkg/timeutils"
+ "github.com/go-check/check"
)
// This used to work, it test a log of PageSize-1 (gh#4851)
-func TestLogsContainerSmallerThanPage(t *testing.T) {
+func (s *DockerSuite) TestLogsContainerSmallerThanPage(c *check.C) {
testLen := 32767
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("run failed with errors: %s, %v", out, err)
+ c.Fatalf("run failed with errors: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -26,25 +26,24 @@ func TestLogsContainerSmallerThanPage(t *testing.T) {
logsCmd := exec.Command(dockerBinary, "logs", cleanedContainerID)
out, _, _, err = runCommandWithStdoutStderr(logsCmd)
if err != nil {
- t.Fatalf("failed to log container: %s, %v", out, err)
+ c.Fatalf("failed to log container: %s, %v", out, err)
}
if len(out) != testLen+1 {
- t.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
+ c.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
}
deleteContainer(cleanedContainerID)
- logDone("logs - logs container running echo smaller than page size")
}
// Regression test: When going over the PageSize, it used to panic (gh#4851)
-func TestLogsContainerBiggerThanPage(t *testing.T) {
+func (s *DockerSuite) TestLogsContainerBiggerThanPage(c *check.C) {
testLen := 32768
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("run failed with errors: %s, %v", out, err)
+ c.Fatalf("run failed with errors: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -53,25 +52,24 @@ func TestLogsContainerBiggerThanPage(t *testing.T) {
logsCmd := exec.Command(dockerBinary, "logs", cleanedContainerID)
out, _, _, err = runCommandWithStdoutStderr(logsCmd)
if err != nil {
- t.Fatalf("failed to log container: %s, %v", out, err)
+ c.Fatalf("failed to log container: %s, %v", out, err)
}
if len(out) != testLen+1 {
- t.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
+ c.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
}
deleteContainer(cleanedContainerID)
- logDone("logs - logs container running echo bigger than page size")
}
// Regression test: When going much over the PageSize, it used to block (gh#4851)
-func TestLogsContainerMuchBiggerThanPage(t *testing.T) {
+func (s *DockerSuite) TestLogsContainerMuchBiggerThanPage(c *check.C) {
testLen := 33000
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("run failed with errors: %s, %v", out, err)
+ c.Fatalf("run failed with errors: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -80,25 +78,24 @@ func TestLogsContainerMuchBiggerThanPage(t *testing.T) {
logsCmd := exec.Command(dockerBinary, "logs", cleanedContainerID)
out, _, _, err = runCommandWithStdoutStderr(logsCmd)
if err != nil {
- t.Fatalf("failed to log container: %s, %v", out, err)
+ c.Fatalf("failed to log container: %s, %v", out, err)
}
if len(out) != testLen+1 {
- t.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
+ c.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
}
deleteContainer(cleanedContainerID)
- logDone("logs - logs container running echo much bigger than page size")
}
-func TestLogsTimestamps(t *testing.T) {
+func (s *DockerSuite) TestLogsTimestamps(c *check.C) {
testLen := 100
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo =; done;", testLen))
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("run failed with errors: %s, %v", out, err)
+ c.Fatalf("run failed with errors: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -107,13 +104,13 @@ func TestLogsTimestamps(t *testing.T) {
logsCmd := exec.Command(dockerBinary, "logs", "-t", cleanedContainerID)
out, _, _, err = runCommandWithStdoutStderr(logsCmd)
if err != nil {
- t.Fatalf("failed to log container: %s, %v", out, err)
+ c.Fatalf("failed to log container: %s, %v", out, err)
}
lines := strings.Split(out, "\n")
if len(lines) != testLen+1 {
- t.Fatalf("Expected log %d lines, received %d\n", testLen+1, len(lines))
+ c.Fatalf("Expected log %d lines, received %d\n", testLen+1, len(lines))
}
ts := regexp.MustCompile(`^.* `)
@@ -122,26 +119,25 @@ func TestLogsTimestamps(t *testing.T) {
if l != "" {
_, err := time.Parse(timeutils.RFC3339NanoFixed+" ", ts.FindString(l))
if err != nil {
- t.Fatalf("Failed to parse timestamp from %v: %v", l, err)
+ c.Fatalf("Failed to parse timestamp from %v: %v", l, err)
}
if l[29] != 'Z' { // ensure we have padded 0's
- t.Fatalf("Timestamp isn't padded properly: %s", l)
+ c.Fatalf("Timestamp isn't padded properly: %s", l)
}
}
}
deleteContainer(cleanedContainerID)
- logDone("logs - logs with timestamps")
}
-func TestLogsSeparateStderr(t *testing.T) {
+func (s *DockerSuite) TestLogsSeparateStderr(c *check.C) {
msg := "stderr_log"
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("echo %s 1>&2", msg))
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("run failed with errors: %s, %v", out, err)
+ c.Fatalf("run failed with errors: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -150,30 +146,29 @@ func TestLogsSeparateStderr(t *testing.T) {
logsCmd := exec.Command(dockerBinary, "logs", cleanedContainerID)
stdout, stderr, _, err := runCommandWithStdoutStderr(logsCmd)
if err != nil {
- t.Fatalf("failed to log container: %s, %v", out, err)
+ c.Fatalf("failed to log container: %s, %v", out, err)
}
if stdout != "" {
- t.Fatalf("Expected empty stdout stream, got %v", stdout)
+ c.Fatalf("Expected empty stdout stream, got %v", stdout)
}
stderr = strings.TrimSpace(stderr)
if stderr != msg {
- t.Fatalf("Expected %v in stderr stream, got %v", msg, stderr)
+ c.Fatalf("Expected %v in stderr stream, got %v", msg, stderr)
}
deleteContainer(cleanedContainerID)
- logDone("logs - separate stderr (without pseudo-tty)")
}
-func TestLogsStderrInStdout(t *testing.T) {
+func (s *DockerSuite) TestLogsStderrInStdout(c *check.C) {
msg := "stderr_log"
runCmd := exec.Command(dockerBinary, "run", "-d", "-t", "busybox", "sh", "-c", fmt.Sprintf("echo %s 1>&2", msg))
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("run failed with errors: %s, %v", out, err)
+ c.Fatalf("run failed with errors: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -182,30 +177,29 @@ func TestLogsStderrInStdout(t *testing.T) {
logsCmd := exec.Command(dockerBinary, "logs", cleanedContainerID)
stdout, stderr, _, err := runCommandWithStdoutStderr(logsCmd)
if err != nil {
- t.Fatalf("failed to log container: %s, %v", out, err)
+ c.Fatalf("failed to log container: %s, %v", out, err)
}
if stderr != "" {
- t.Fatalf("Expected empty stderr stream, got %v", stdout)
+ c.Fatalf("Expected empty stderr stream, got %v", stdout)
}
stdout = strings.TrimSpace(stdout)
if stdout != msg {
- t.Fatalf("Expected %v in stdout stream, got %v", msg, stdout)
+ c.Fatalf("Expected %v in stdout stream, got %v", msg, stdout)
}
deleteContainer(cleanedContainerID)
- logDone("logs - stderr in stdout (with pseudo-tty)")
}
-func TestLogsTail(t *testing.T) {
+func (s *DockerSuite) TestLogsTail(c *check.C) {
testLen := 100
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo =; done;", testLen))
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("run failed with errors: %s, %v", out, err)
+ c.Fatalf("run failed with errors: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -214,49 +208,48 @@ func TestLogsTail(t *testing.T) {
logsCmd := exec.Command(dockerBinary, "logs", "--tail", "5", cleanedContainerID)
out, _, _, err = runCommandWithStdoutStderr(logsCmd)
if err != nil {
- t.Fatalf("failed to log container: %s, %v", out, err)
+ c.Fatalf("failed to log container: %s, %v", out, err)
}
lines := strings.Split(out, "\n")
if len(lines) != 6 {
- t.Fatalf("Expected log %d lines, received %d\n", 6, len(lines))
+ c.Fatalf("Expected log %d lines, received %d\n", 6, len(lines))
}
logsCmd = exec.Command(dockerBinary, "logs", "--tail", "all", cleanedContainerID)
out, _, _, err = runCommandWithStdoutStderr(logsCmd)
if err != nil {
- t.Fatalf("failed to log container: %s, %v", out, err)
+ c.Fatalf("failed to log container: %s, %v", out, err)
}
lines = strings.Split(out, "\n")
if len(lines) != testLen+1 {
- t.Fatalf("Expected log %d lines, received %d\n", testLen+1, len(lines))
+ c.Fatalf("Expected log %d lines, received %d\n", testLen+1, len(lines))
}
logsCmd = exec.Command(dockerBinary, "logs", "--tail", "random", cleanedContainerID)
out, _, _, err = runCommandWithStdoutStderr(logsCmd)
if err != nil {
- t.Fatalf("failed to log container: %s, %v", out, err)
+ c.Fatalf("failed to log container: %s, %v", out, err)
}
lines = strings.Split(out, "\n")
if len(lines) != testLen+1 {
- t.Fatalf("Expected log %d lines, received %d\n", testLen+1, len(lines))
+ c.Fatalf("Expected log %d lines, received %d\n", testLen+1, len(lines))
}
deleteContainer(cleanedContainerID)
- logDone("logs - logs tail")
}
-func TestLogsFollowStopped(t *testing.T) {
+func (s *DockerSuite) TestLogsFollowStopped(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "echo", "hello")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("run failed with errors: %s, %v", out, err)
+ c.Fatalf("run failed with errors: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -264,38 +257,35 @@ func TestLogsFollowStopped(t *testing.T) {
logsCmd := exec.Command(dockerBinary, "logs", "-f", cleanedContainerID)
if err := logsCmd.Start(); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- c := make(chan struct{})
+ errChan := make(chan error)
go func() {
- if err := logsCmd.Wait(); err != nil {
- t.Fatal(err)
- }
- close(c)
+ errChan <- logsCmd.Wait()
+ close(errChan)
}()
select {
- case <-c:
+ case err := <-errChan:
+ c.Assert(err, check.IsNil)
case <-time.After(1 * time.Second):
- t.Fatal("Following logs is hanged")
+ c.Fatal("Following logs is hanged")
}
deleteContainer(cleanedContainerID)
- logDone("logs - logs follow stopped container")
}
// Regression test for #8832
-func TestLogsFollowSlowStdoutConsumer(t *testing.T) {
+func (s *DockerSuite) TestLogsFollowSlowStdoutConsumer(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "/bin/sh", "-c", `usleep 200000;yes X | head -c 200000`)
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("run failed with errors: %s, %v", out, err)
+ c.Fatalf("run failed with errors: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
- defer deleteContainer(cleanedContainerID)
stopSlowRead := make(chan bool)
@@ -307,31 +297,24 @@ func TestLogsFollowSlowStdoutConsumer(t *testing.T) {
logCmd := exec.Command(dockerBinary, "logs", "-f", cleanedContainerID)
stdout, err := logCmd.StdoutPipe()
- if err != nil {
- t.Fatal(err)
- }
+ c.Assert(err, check.IsNil)
if err := logCmd.Start(); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// First read slowly
bytes1, err := consumeWithSpeed(stdout, 10, 50*time.Millisecond, stopSlowRead)
- if err != nil {
- t.Fatal(err)
- }
+ c.Assert(err, check.IsNil)
// After the container has finished we can continue reading fast
bytes2, err := consumeWithSpeed(stdout, 32*1024, 0, nil)
- if err != nil {
- t.Fatal(err)
- }
+ c.Assert(err, check.IsNil)
actual := bytes1 + bytes2
expected := 200000
if actual != expected {
- t.Fatalf("Invalid bytes read: %d, expected %d", actual, expected)
+ c.Fatalf("Invalid bytes read: %d, expected %d", actual, expected)
}
- logDone("logs - follow slow consumer")
}
diff --git a/integration-cli/docker_cli_nat_test.go b/integration-cli/docker_cli_nat_test.go
index 35bd378e4ed09..875b6540ab095 100644
--- a/integration-cli/docker_cli_nat_test.go
+++ b/integration-cli/docker_cli_nat_test.go
@@ -5,32 +5,32 @@ import (
"net"
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
-func TestNetworkNat(t *testing.T) {
- testRequires(t, SameHostDaemon, NativeExecDriver)
- defer deleteAllContainers()
+func (s *DockerSuite) TestNetworkNat(c *check.C) {
+ testRequires(c, SameHostDaemon, NativeExecDriver)
iface, err := net.InterfaceByName("eth0")
if err != nil {
- t.Skipf("Test not running with `make test`. Interface eth0 not found: %s", err)
+ c.Skip(fmt.Sprintf("Test not running with `make test`. Interface eth0 not found: %v", err))
}
ifaceAddrs, err := iface.Addrs()
if err != nil || len(ifaceAddrs) == 0 {
- t.Fatalf("Error retrieving addresses for eth0: %v (%d addresses)", err, len(ifaceAddrs))
+ c.Fatalf("Error retrieving addresses for eth0: %v (%d addresses)", err, len(ifaceAddrs))
}
ifaceIP, _, err := net.ParseCIDR(ifaceAddrs[0].String())
if err != nil {
- t.Fatalf("Error retrieving the up for eth0: %s", err)
+ c.Fatalf("Error retrieving the up for eth0: %s", err)
}
runCmd := exec.Command(dockerBinary, "run", "-dt", "-p", "8080:8080", "busybox", "nc", "-lp", "8080")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -38,25 +38,24 @@ func TestNetworkNat(t *testing.T) {
runCmd = exec.Command(dockerBinary, "run", "busybox", "sh", "-c", fmt.Sprintf("echo hello world | nc -w 30 %s 8080", ifaceIP))
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
runCmd = exec.Command(dockerBinary, "logs", cleanedContainerID)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("failed to retrieve logs for container: %s, %v", out, err)
+ c.Fatalf("failed to retrieve logs for container: %s, %v", out, err)
}
out = strings.Trim(out, "\r\n")
if expected := "hello world"; out != expected {
- t.Fatalf("Unexpected output. Expected: %q, received: %q for iface %s", expected, out, ifaceIP)
+ c.Fatalf("Unexpected output. Expected: %q, received: %q for iface %s", expected, out, ifaceIP)
}
killCmd := exec.Command(dockerBinary, "kill", cleanedContainerID)
if out, _, err = runCommandWithOutput(killCmd); err != nil {
- t.Fatalf("failed to kill container: %s, %v", out, err)
+ c.Fatalf("failed to kill container: %s, %v", out, err)
}
- logDone("network - make sure nat works through the host")
}
diff --git a/integration-cli/docker_cli_pause_test.go b/integration-cli/docker_cli_pause_test.go
index 41147b206291e..0256fb92bd379 100644
--- a/integration-cli/docker_cli_pause_test.go
+++ b/integration-cli/docker_cli_pause_test.go
@@ -4,78 +4,76 @@ import (
"fmt"
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
-func TestPause(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestPause(c *check.C) {
defer unpauseAllContainers()
name := "testeventpause"
- out, _, _ := dockerCmd(t, "images", "-q")
+ out, _ := dockerCmd(c, "images", "-q")
image := strings.Split(out, "\n")[0]
- dockerCmd(t, "run", "-d", "--name", name, image, "top")
+ dockerCmd(c, "run", "-d", "--name", name, image, "top")
- dockerCmd(t, "pause", name)
+ dockerCmd(c, "pause", name)
pausedContainers, err := getSliceOfPausedContainers()
if err != nil {
- t.Fatalf("error thrown while checking if containers were paused: %v", err)
+ c.Fatalf("error thrown while checking if containers were paused: %v", err)
}
if len(pausedContainers) != 1 {
- t.Fatalf("there should be one paused container and not %d", len(pausedContainers))
+ c.Fatalf("there should be one paused container and not %d", len(pausedContainers))
}
- dockerCmd(t, "unpause", name)
+ dockerCmd(c, "unpause", name)
- eventsCmd := exec.Command(dockerBinary, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(t).Unix()))
+ eventsCmd := exec.Command(dockerBinary, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
out, _, _ = runCommandWithOutput(eventsCmd)
events := strings.Split(out, "\n")
if len(events) <= 1 {
- t.Fatalf("Missing expected event")
+ c.Fatalf("Missing expected event")
}
pauseEvent := strings.Fields(events[len(events)-3])
unpauseEvent := strings.Fields(events[len(events)-2])
if pauseEvent[len(pauseEvent)-1] != "pause" {
- t.Fatalf("event should be pause, not %#v", pauseEvent)
+ c.Fatalf("event should be pause, not %#v", pauseEvent)
}
if unpauseEvent[len(unpauseEvent)-1] != "unpause" {
- t.Fatalf("event should be unpause, not %#v", unpauseEvent)
+ c.Fatalf("event should be unpause, not %#v", unpauseEvent)
}
- logDone("pause - pause/unpause is logged")
}
-func TestPauseMultipleContainers(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestPauseMultipleContainers(c *check.C) {
defer unpauseAllContainers()
containers := []string{
"testpausewithmorecontainers1",
"testpausewithmorecontainers2",
}
- out, _, _ := dockerCmd(t, "images", "-q")
+ out, _ := dockerCmd(c, "images", "-q")
image := strings.Split(out, "\n")[0]
for _, name := range containers {
- dockerCmd(t, "run", "-d", "--name", name, image, "top")
+ dockerCmd(c, "run", "-d", "--name", name, image, "top")
}
- dockerCmd(t, append([]string{"pause"}, containers...)...)
+ dockerCmd(c, append([]string{"pause"}, containers...)...)
pausedContainers, err := getSliceOfPausedContainers()
if err != nil {
- t.Fatalf("error thrown while checking if containers were paused: %v", err)
+ c.Fatalf("error thrown while checking if containers were paused: %v", err)
}
if len(pausedContainers) != len(containers) {
- t.Fatalf("there should be %d paused container and not %d", len(containers), len(pausedContainers))
+ c.Fatalf("there should be %d paused container and not %d", len(containers), len(pausedContainers))
}
- dockerCmd(t, append([]string{"unpause"}, containers...)...)
+ dockerCmd(c, append([]string{"unpause"}, containers...)...)
- eventsCmd := exec.Command(dockerBinary, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(t).Unix()))
+ eventsCmd := exec.Command(dockerBinary, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
out, _, _ = runCommandWithOutput(eventsCmd)
events := strings.Split(out, "\n")
if len(events) <= len(containers)*3-2 {
- t.Fatalf("Missing expected event")
+ c.Fatalf("Missing expected event")
}
pauseEvents := make([][]string, len(containers))
@@ -87,14 +85,13 @@ func TestPauseMultipleContainers(t *testing.T) {
for _, pauseEvent := range pauseEvents {
if pauseEvent[len(pauseEvent)-1] != "pause" {
- t.Fatalf("event should be pause, not %#v", pauseEvent)
+ c.Fatalf("event should be pause, not %#v", pauseEvent)
}
}
for _, unpauseEvent := range unpauseEvents {
if unpauseEvent[len(unpauseEvent)-1] != "unpause" {
- t.Fatalf("event should be unpause, not %#v", unpauseEvent)
+ c.Fatalf("event should be unpause, not %#v", unpauseEvent)
}
}
- logDone("pause - multi pause/unpause is logged")
}
diff --git a/integration-cli/docker_cli_port_test.go b/integration-cli/docker_cli_port_test.go
index 91c1ee30098e2..f0cb6639648c5 100644
--- a/integration-cli/docker_cli_port_test.go
+++ b/integration-cli/docker_cli_port_test.go
@@ -1,45 +1,46 @@
package main
import (
+ "net"
"os/exec"
"sort"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
-func TestPortList(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestPortList(c *check.C) {
// one port
runCmd := exec.Command(dockerBinary, "run", "-d", "-p", "9876:80", "busybox", "top")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
firstID := strings.TrimSpace(out)
runCmd = exec.Command(dockerBinary, "port", firstID, "80")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
- if !assertPortList(t, out, []string{"0.0.0.0:9876"}) {
- t.Error("Port list is not correct")
+ if !assertPortList(c, out, []string{"0.0.0.0:9876"}) {
+ c.Error("Port list is not correct")
}
runCmd = exec.Command(dockerBinary, "port", firstID)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
- if !assertPortList(t, out, []string{"80/tcp -> 0.0.0.0:9876"}) {
- t.Error("Port list is not correct")
+ if !assertPortList(c, out, []string{"80/tcp -> 0.0.0.0:9876"}) {
+ c.Error("Port list is not correct")
}
runCmd = exec.Command(dockerBinary, "rm", "-f", firstID)
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
// three port
@@ -50,36 +51,36 @@ func TestPortList(t *testing.T) {
"busybox", "top")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
ID := strings.TrimSpace(out)
runCmd = exec.Command(dockerBinary, "port", ID, "80")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
- if !assertPortList(t, out, []string{"0.0.0.0:9876"}) {
- t.Error("Port list is not correct")
+ if !assertPortList(c, out, []string{"0.0.0.0:9876"}) {
+ c.Error("Port list is not correct")
}
runCmd = exec.Command(dockerBinary, "port", ID)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
- if !assertPortList(t, out, []string{
+ if !assertPortList(c, out, []string{
"80/tcp -> 0.0.0.0:9876",
"81/tcp -> 0.0.0.0:9877",
"82/tcp -> 0.0.0.0:9878"}) {
- t.Error("Port list is not correct")
+ c.Error("Port list is not correct")
}
runCmd = exec.Command(dockerBinary, "rm", "-f", ID)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
// more and one port mapped to the same container port
@@ -91,46 +92,45 @@ func TestPortList(t *testing.T) {
"busybox", "top")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
ID = strings.TrimSpace(out)
runCmd = exec.Command(dockerBinary, "port", ID, "80")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
- if !assertPortList(t, out, []string{"0.0.0.0:9876", "0.0.0.0:9999"}) {
- t.Error("Port list is not correct")
+ if !assertPortList(c, out, []string{"0.0.0.0:9876", "0.0.0.0:9999"}) {
+ c.Error("Port list is not correct")
}
runCmd = exec.Command(dockerBinary, "port", ID)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
- if !assertPortList(t, out, []string{
+ if !assertPortList(c, out, []string{
"80/tcp -> 0.0.0.0:9876",
"80/tcp -> 0.0.0.0:9999",
"81/tcp -> 0.0.0.0:9877",
"82/tcp -> 0.0.0.0:9878"}) {
- t.Error("Port list is not correct\n", out)
+ c.Error("Port list is not correct\n", out)
}
runCmd = exec.Command(dockerBinary, "rm", "-f", ID)
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
- logDone("port - test port list")
}
-func assertPortList(t *testing.T, out string, expected []string) bool {
+func assertPortList(c *check.C, out string, expected []string) bool {
//lines := strings.Split(out, "\n")
lines := strings.Split(strings.Trim(out, "\n "), "\n")
if len(lines) != len(expected) {
- t.Errorf("different size lists %s, %d, %d", out, len(lines), len(expected))
+ c.Errorf("different size lists %s, %d, %d", out, len(lines), len(expected))
return false
}
sort.Strings(lines)
@@ -138,10 +138,86 @@ func assertPortList(t *testing.T, out string, expected []string) bool {
for i := 0; i < len(expected); i++ {
if lines[i] != expected[i] {
- t.Error("|" + lines[i] + "!=" + expected[i] + "|")
+ c.Error("|" + lines[i] + "!=" + expected[i] + "|")
return false
}
}
return true
}
+
+func (s *DockerSuite) TestPortHostBinding(c *check.C) {
+ runCmd := exec.Command(dockerBinary, "run", "-d", "-p", "9876:80", "busybox",
+ "nc", "-l", "-p", "80")
+ out, _, err := runCommandWithOutput(runCmd)
+ if err != nil {
+ c.Fatal(out, err)
+ }
+ firstID := strings.TrimSpace(out)
+
+ runCmd = exec.Command(dockerBinary, "port", firstID, "80")
+ out, _, err = runCommandWithOutput(runCmd)
+ if err != nil {
+ c.Fatal(out, err)
+ }
+
+ if !assertPortList(c, out, []string{"0.0.0.0:9876"}) {
+ c.Error("Port list is not correct")
+ }
+
+ runCmd = exec.Command(dockerBinary, "run", "--net=host", "busybox",
+ "nc", "localhost", "9876")
+ if out, _, err = runCommandWithOutput(runCmd); err != nil {
+ c.Fatal(out, err)
+ }
+
+ runCmd = exec.Command(dockerBinary, "rm", "-f", firstID)
+ if out, _, err = runCommandWithOutput(runCmd); err != nil {
+ c.Fatal(out, err)
+ }
+
+ runCmd = exec.Command(dockerBinary, "run", "--net=host", "busybox",
+ "nc", "localhost", "9876")
+ if out, _, err = runCommandWithOutput(runCmd); err == nil {
+ c.Error("Port is still bound after the Container is removed")
+ }
+}
+
+func (s *DockerSuite) TestPortExposeHostBinding(c *check.C) {
+ runCmd := exec.Command(dockerBinary, "run", "-d", "-P", "--expose", "80", "busybox",
+ "nc", "-l", "-p", "80")
+ out, _, err := runCommandWithOutput(runCmd)
+ if err != nil {
+ c.Fatal(out, err)
+ }
+ firstID := strings.TrimSpace(out)
+
+ runCmd = exec.Command(dockerBinary, "port", firstID, "80")
+ out, _, err = runCommandWithOutput(runCmd)
+ if err != nil {
+ c.Fatal(out, err)
+ }
+
+ _, exposedPort, err := net.SplitHostPort(out)
+
+ if err != nil {
+ c.Fatal(out, err)
+ }
+
+ runCmd = exec.Command(dockerBinary, "run", "--net=host", "busybox",
+ "nc", "localhost", strings.TrimSpace(exposedPort))
+ if out, _, err = runCommandWithOutput(runCmd); err != nil {
+ c.Fatal(out, err)
+ }
+
+ runCmd = exec.Command(dockerBinary, "rm", "-f", firstID)
+ if out, _, err = runCommandWithOutput(runCmd); err != nil {
+ c.Fatal(out, err)
+ }
+
+ runCmd = exec.Command(dockerBinary, "run", "--net=host", "busybox",
+ "nc", "localhost", strings.TrimSpace(exposedPort))
+ if out, _, err = runCommandWithOutput(runCmd); err == nil {
+ c.Error("Port is still bound after the Container is removed")
+ }
+}
diff --git a/integration-cli/docker_cli_proxy_test.go b/integration-cli/docker_cli_proxy_test.go
index b39dd5634d37e..8b55c67d81445 100644
--- a/integration-cli/docker_cli_proxy_test.go
+++ b/integration-cli/docker_cli_proxy_test.go
@@ -4,30 +4,30 @@ import (
"net"
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
-func TestCliProxyDisableProxyUnixSock(t *testing.T) {
- testRequires(t, SameHostDaemon) // test is valid when DOCKER_HOST=unix://..
+func (s *DockerSuite) TestCliProxyDisableProxyUnixSock(c *check.C) {
+ testRequires(c, SameHostDaemon) // test is valid when DOCKER_HOST=unix://..
cmd := exec.Command(dockerBinary, "info")
cmd.Env = appendBaseEnv([]string{"HTTP_PROXY=http://127.0.0.1:9999"})
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
- logDone("cli proxy - HTTP_PROXY is not used when connecting to unix sock")
}
// Can't use localhost here since go has a special case to not use proxy if connecting to localhost
-// See http://golang.org/pkg/net/http/#ProxyFromEnvironment
-func TestCliProxyProxyTCPSock(t *testing.T) {
- testRequires(t, SameHostDaemon)
+// See https://golang.org/pkg/net/http/#ProxyFromEnvironment
+func (s *DockerDaemonSuite) TestCliProxyProxyTCPSock(c *check.C) {
+ testRequires(c, SameHostDaemon)
// get the IP to use to connect since we can't use localhost
addrs, err := net.InterfaceAddrs()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
var ip string
for _, addr := range addrs {
@@ -40,25 +40,23 @@ func TestCliProxyProxyTCPSock(t *testing.T) {
}
if ip == "" {
- t.Fatal("could not find ip to connect to")
+ c.Fatal("could not find ip to connect to")
}
- d := NewDaemon(t)
- if err := d.Start("-H", "tcp://"+ip+":2375"); err != nil {
- t.Fatal(err)
+ if err := s.d.Start("-H", "tcp://"+ip+":2375"); err != nil {
+ c.Fatal(err)
}
cmd := exec.Command(dockerBinary, "info")
cmd.Env = []string{"DOCKER_HOST=tcp://" + ip + ":2375", "HTTP_PROXY=127.0.0.1:9999"}
if out, _, err := runCommandWithOutput(cmd); err == nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
// Test with no_proxy
cmd.Env = append(cmd.Env, "NO_PROXY="+ip)
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "info")); err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
- logDone("cli proxy - HTTP_PROXY is used for TCP sock")
}
diff --git a/integration-cli/docker_cli_ps_test.go b/integration-cli/docker_cli_ps_test.go
index deb426fce624e..bb34575fbaf48 100644
--- a/integration-cli/docker_cli_ps_test.go
+++ b/integration-cli/docker_cli_ps_test.go
@@ -6,24 +6,24 @@ import (
"reflect"
"strconv"
"strings"
- "testing"
"time"
+
+ "github.com/go-check/check"
)
-func TestPsListContainers(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestPsListContainers(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
firstID := strings.TrimSpace(out)
runCmd = exec.Command(dockerBinary, "run", "-d", "busybox", "top")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
secondID := strings.TrimSpace(out)
@@ -31,53 +31,53 @@ func TestPsListContainers(t *testing.T) {
runCmd = exec.Command(dockerBinary, "run", "-d", "busybox", "true")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
thirdID := strings.TrimSpace(out)
runCmd = exec.Command(dockerBinary, "run", "-d", "busybox", "top")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
fourthID := strings.TrimSpace(out)
// make sure the second is running
if err := waitRun(secondID); err != nil {
- t.Fatalf("waiting for container failed: %v", err)
+ c.Fatalf("waiting for container failed: %v", err)
}
// make sure third one is not running
runCmd = exec.Command(dockerBinary, "wait", thirdID)
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
// make sure the forth is running
if err := waitRun(fourthID); err != nil {
- t.Fatalf("waiting for container failed: %v", err)
+ c.Fatalf("waiting for container failed: %v", err)
}
// all
runCmd = exec.Command(dockerBinary, "ps", "-a")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if !assertContainerList(out, []string{fourthID, thirdID, secondID, firstID}) {
- t.Errorf("Container list is not in the correct order: %s", out)
+ c.Errorf("Container list is not in the correct order: %s", out)
}
// running
runCmd = exec.Command(dockerBinary, "ps")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if !assertContainerList(out, []string{fourthID, secondID, firstID}) {
- t.Errorf("Container list is not in the correct order: %s", out)
+ c.Errorf("Container list is not in the correct order: %s", out)
}
// from here all flag '-a' is ignored
@@ -86,156 +86,155 @@ func TestPsListContainers(t *testing.T) {
runCmd = exec.Command(dockerBinary, "ps", "-n=2", "-a")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
expected := []string{fourthID, thirdID}
if !assertContainerList(out, expected) {
- t.Errorf("Container list is not in the correct order: %s", out)
+ c.Errorf("Container list is not in the correct order: %s", out)
}
runCmd = exec.Command(dockerBinary, "ps", "-n=2")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if !assertContainerList(out, expected) {
- t.Errorf("Container list is not in the correct order: %s", out)
+ c.Errorf("Container list is not in the correct order: %s", out)
}
// since
runCmd = exec.Command(dockerBinary, "ps", "--since", firstID, "-a")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
expected = []string{fourthID, thirdID, secondID}
if !assertContainerList(out, expected) {
- t.Errorf("Container list is not in the correct order: %s", out)
+ c.Errorf("Container list is not in the correct order: %s", out)
}
runCmd = exec.Command(dockerBinary, "ps", "--since", firstID)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if !assertContainerList(out, expected) {
- t.Errorf("Container list is not in the correct order: %s", out)
+ c.Errorf("Container list is not in the correct order: %s", out)
}
// before
runCmd = exec.Command(dockerBinary, "ps", "--before", thirdID, "-a")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
expected = []string{secondID, firstID}
if !assertContainerList(out, expected) {
- t.Errorf("Container list is not in the correct order: %s", out)
+ c.Errorf("Container list is not in the correct order: %s", out)
}
runCmd = exec.Command(dockerBinary, "ps", "--before", thirdID)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if !assertContainerList(out, expected) {
- t.Errorf("Container list is not in the correct order: %s", out)
+ c.Errorf("Container list is not in the correct order: %s", out)
}
// since & before
runCmd = exec.Command(dockerBinary, "ps", "--since", firstID, "--before", fourthID, "-a")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
expected = []string{thirdID, secondID}
if !assertContainerList(out, expected) {
- t.Errorf("Container list is not in the correct order: %s", out)
+ c.Errorf("Container list is not in the correct order: %s", out)
}
runCmd = exec.Command(dockerBinary, "ps", "--since", firstID, "--before", fourthID)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if !assertContainerList(out, expected) {
- t.Errorf("Container list is not in the correct order: %s", out)
+ c.Errorf("Container list is not in the correct order: %s", out)
}
// since & limit
runCmd = exec.Command(dockerBinary, "ps", "--since", firstID, "-n=2", "-a")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
expected = []string{fourthID, thirdID}
if !assertContainerList(out, expected) {
- t.Errorf("Container list is not in the correct order: %s", out)
+ c.Errorf("Container list is not in the correct order: %s", out)
}
runCmd = exec.Command(dockerBinary, "ps", "--since", firstID, "-n=2")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if !assertContainerList(out, expected) {
- t.Errorf("Container list is not in the correct order: %s", out)
+ c.Errorf("Container list is not in the correct order: %s", out)
}
// before & limit
runCmd = exec.Command(dockerBinary, "ps", "--before", fourthID, "-n=1", "-a")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
expected = []string{thirdID}
if !assertContainerList(out, expected) {
- t.Errorf("Container list is not in the correct order: %s", out)
+ c.Errorf("Container list is not in the correct order: %s", out)
}
runCmd = exec.Command(dockerBinary, "ps", "--before", fourthID, "-n=1")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if !assertContainerList(out, expected) {
- t.Errorf("Container list is not in the correct order: %s", out)
+ c.Errorf("Container list is not in the correct order: %s", out)
}
// since & before & limit
runCmd = exec.Command(dockerBinary, "ps", "--since", firstID, "--before", fourthID, "-n=1", "-a")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
expected = []string{thirdID}
if !assertContainerList(out, expected) {
- t.Errorf("Container list is not in the correct order: %s", out)
+ c.Errorf("Container list is not in the correct order: %s", out)
}
runCmd = exec.Command(dockerBinary, "ps", "--since", firstID, "--before", fourthID, "-n=1")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if !assertContainerList(out, expected) {
- t.Errorf("Container list is not in the correct order: %s", out)
+ c.Errorf("Container list is not in the correct order: %s", out)
}
- logDone("ps - test ps options")
}
func assertContainerList(out string, expected []string) bool {
@@ -255,9 +254,7 @@ func assertContainerList(out string, expected []string) bool {
return true
}
-func TestPsListContainersSize(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestPsListContainersSize(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "echo", "hello")
runCommandWithOutput(cmd)
cmd = exec.Command(dockerBinary, "ps", "-s", "-n=1")
@@ -267,18 +264,18 @@ func TestPsListContainersSize(t *testing.T) {
baseFoundsize := baseLines[1][baseSizeIndex:]
baseBytes, err := strconv.Atoi(strings.Split(baseFoundsize, " ")[0])
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
name := "test_size"
runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "sh", "-c", "echo 1 > test")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
id, err := getIDByName(name)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
runCmd = exec.Command(dockerBinary, "ps", "-s", "-n=1")
@@ -290,54 +287,52 @@ func TestPsListContainersSize(t *testing.T) {
select {
case <-wait:
case <-time.After(3 * time.Second):
- t.Fatalf("Calling \"docker ps -s\" timed out!")
+ c.Fatalf("Calling \"docker ps -s\" timed out!")
}
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
lines := strings.Split(strings.Trim(out, "\n "), "\n")
if len(lines) != 2 {
- t.Fatalf("Expected 2 lines for 'ps -s -n=1' output, got %d", len(lines))
+ c.Fatalf("Expected 2 lines for 'ps -s -n=1' output, got %d", len(lines))
}
sizeIndex := strings.Index(lines[0], "SIZE")
idIndex := strings.Index(lines[0], "CONTAINER ID")
foundID := lines[1][idIndex : idIndex+12]
if foundID != id[:12] {
- t.Fatalf("Expected id %s, got %s", id[:12], foundID)
+ c.Fatalf("Expected id %s, got %s", id[:12], foundID)
}
expectedSize := fmt.Sprintf("%d B", (2 + baseBytes))
foundSize := lines[1][sizeIndex:]
if foundSize != expectedSize {
- t.Fatalf("Expected size %q, got %q", expectedSize, foundSize)
+ c.Fatalf("Expected size %q, got %q", expectedSize, foundSize)
}
- logDone("ps - test ps size")
}
-func TestPsListContainersFilterStatus(t *testing.T) {
+func (s *DockerSuite) TestPsListContainersFilterStatus(c *check.C) {
// FIXME: this should test paused, but it makes things hang and its wonky
// this is because paused containers can't be controlled by signals
- defer deleteAllContainers()
// start exited container
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
firstID := strings.TrimSpace(out)
// make sure the exited cintainer is not running
runCmd = exec.Command(dockerBinary, "wait", firstID)
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
// start running container
runCmd = exec.Command(dockerBinary, "run", "-itd", "busybox")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
secondID := strings.TrimSpace(out)
@@ -345,313 +340,298 @@ func TestPsListContainersFilterStatus(t *testing.T) {
runCmd = exec.Command(dockerBinary, "ps", "-q", "--filter=status=exited")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
containerOut := strings.TrimSpace(out)
if containerOut != firstID[:12] {
- t.Fatalf("Expected id %s, got %s for exited filter, output: %q", firstID[:12], containerOut, out)
+ c.Fatalf("Expected id %s, got %s for exited filter, output: %q", firstID[:12], containerOut, out)
}
runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--filter=status=running")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
containerOut = strings.TrimSpace(out)
if containerOut != secondID[:12] {
- t.Fatalf("Expected id %s, got %s for running filter, output: %q", secondID[:12], containerOut, out)
+ c.Fatalf("Expected id %s, got %s for running filter, output: %q", secondID[:12], containerOut, out)
}
- logDone("ps - test ps filter status")
}
-func TestPsListContainersFilterID(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestPsListContainersFilterID(c *check.C) {
// start container
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
firstID := strings.TrimSpace(out)
// start another container
runCmd = exec.Command(dockerBinary, "run", "-d", "busybox", "top")
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
// filter containers by id
runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--filter=id="+firstID)
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
containerOut := strings.TrimSpace(out)
if containerOut != firstID[:12] {
- t.Fatalf("Expected id %s, got %s for exited filter, output: %q", firstID[:12], containerOut, out)
+ c.Fatalf("Expected id %s, got %s for exited filter, output: %q", firstID[:12], containerOut, out)
}
- logDone("ps - test ps filter id")
}
-func TestPsListContainersFilterName(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestPsListContainersFilterName(c *check.C) {
// start container
runCmd := exec.Command(dockerBinary, "run", "-d", "--name=a_name_to_match", "busybox")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
firstID := strings.TrimSpace(out)
// start another container
runCmd = exec.Command(dockerBinary, "run", "-d", "--name=b_name_to_match", "busybox", "top")
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
// filter containers by name
runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--filter=name=a_name_to_match")
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
containerOut := strings.TrimSpace(out)
if containerOut != firstID[:12] {
- t.Fatalf("Expected id %s, got %s for exited filter, output: %q", firstID[:12], containerOut, out)
+ c.Fatalf("Expected id %s, got %s for exited filter, output: %q", firstID[:12], containerOut, out)
}
- logDone("ps - test ps filter name")
}
-func TestPsListContainersFilterLabel(t *testing.T) {
+func (s *DockerSuite) TestPsListContainersFilterLabel(c *check.C) {
// start container
runCmd := exec.Command(dockerBinary, "run", "-d", "-l", "match=me", "-l", "second=tag", "busybox")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
firstID := strings.TrimSpace(out)
// start another container
runCmd = exec.Command(dockerBinary, "run", "-d", "-l", "match=me too", "busybox")
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
secondID := strings.TrimSpace(out)
// start third container
runCmd = exec.Command(dockerBinary, "run", "-d", "-l", "nomatch=me", "busybox")
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
thirdID := strings.TrimSpace(out)
// filter containers by exact match
runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--no-trunc", "--filter=label=match=me")
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
containerOut := strings.TrimSpace(out)
if containerOut != firstID {
- t.Fatalf("Expected id %s, got %s for exited filter, output: %q", firstID, containerOut, out)
+ c.Fatalf("Expected id %s, got %s for exited filter, output: %q", firstID, containerOut, out)
}
// filter containers by two labels
runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--no-trunc", "--filter=label=match=me", "--filter=label=second=tag")
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
containerOut = strings.TrimSpace(out)
if containerOut != firstID {
- t.Fatalf("Expected id %s, got %s for exited filter, output: %q", firstID, containerOut, out)
+ c.Fatalf("Expected id %s, got %s for exited filter, output: %q", firstID, containerOut, out)
}
// filter containers by two labels, but expect not found because of AND behavior
runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--no-trunc", "--filter=label=match=me", "--filter=label=second=tag-no")
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
containerOut = strings.TrimSpace(out)
if containerOut != "" {
- t.Fatalf("Expected nothing, got %s for exited filter, output: %q", containerOut, out)
+ c.Fatalf("Expected nothing, got %s for exited filter, output: %q", containerOut, out)
}
// filter containers by exact key
runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--no-trunc", "--filter=label=match")
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
containerOut = strings.TrimSpace(out)
if (!strings.Contains(containerOut, firstID) || !strings.Contains(containerOut, secondID)) || strings.Contains(containerOut, thirdID) {
- t.Fatalf("Expected ids %s,%s, got %s for exited filter, output: %q", firstID, secondID, containerOut, out)
+ c.Fatalf("Expected ids %s,%s, got %s for exited filter, output: %q", firstID, secondID, containerOut, out)
}
-
- deleteAllContainers()
-
- logDone("ps - test ps filter label")
}
-func TestPsListContainersFilterExited(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestPsListContainersFilterExited(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "top", "busybox", "top")
if out, _, err := runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
runCmd = exec.Command(dockerBinary, "run", "--name", "zero1", "busybox", "true")
if out, _, err := runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
firstZero, err := getIDByName("zero1")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
runCmd = exec.Command(dockerBinary, "run", "--name", "zero2", "busybox", "true")
if out, _, err := runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
secondZero, err := getIDByName("zero2")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
runCmd = exec.Command(dockerBinary, "run", "--name", "nonzero1", "busybox", "false")
if out, _, err := runCommandWithOutput(runCmd); err == nil {
- t.Fatal("Should fail.", out, err)
+ c.Fatal("Should fail.", out, err)
}
firstNonZero, err := getIDByName("nonzero1")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
runCmd = exec.Command(dockerBinary, "run", "--name", "nonzero2", "busybox", "false")
if out, _, err := runCommandWithOutput(runCmd); err == nil {
- t.Fatal("Should fail.", out, err)
+ c.Fatal("Should fail.", out, err)
}
secondNonZero, err := getIDByName("nonzero2")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// filter containers by exited=0
runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--no-trunc", "--filter=exited=0")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
ids := strings.Split(strings.TrimSpace(out), "\n")
if len(ids) != 2 {
- t.Fatalf("Should be 2 zero exited containers got %d: %s", len(ids), out)
+ c.Fatalf("Should be 2 zero exited containers got %d: %s", len(ids), out)
}
if ids[0] != secondZero {
- t.Fatalf("First in list should be %q, got %q", secondZero, ids[0])
+ c.Fatalf("First in list should be %q, got %q", secondZero, ids[0])
}
if ids[1] != firstZero {
- t.Fatalf("Second in list should be %q, got %q", firstZero, ids[1])
+ c.Fatalf("Second in list should be %q, got %q", firstZero, ids[1])
}
runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--no-trunc", "--filter=exited=1")
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
ids = strings.Split(strings.TrimSpace(out), "\n")
if len(ids) != 2 {
- t.Fatalf("Should be 2 zero exited containerst got %d", len(ids))
+ c.Fatalf("Should be 2 zero exited containers got %d", len(ids))
}
if ids[0] != secondNonZero {
- t.Fatalf("First in list should be %q, got %q", secondNonZero, ids[0])
+ c.Fatalf("First in list should be %q, got %q", secondNonZero, ids[0])
}
if ids[1] != firstNonZero {
- t.Fatalf("Second in list should be %q, got %q", firstNonZero, ids[1])
+ c.Fatalf("Second in list should be %q, got %q", firstNonZero, ids[1])
}
- logDone("ps - test ps filter exited")
}
-func TestPsRightTagName(t *testing.T) {
+func (s *DockerSuite) TestPsRightTagName(c *check.C) {
tag := "asybox:shmatest"
- defer deleteAllContainers()
- defer deleteImages(tag)
if out, err := exec.Command(dockerBinary, "tag", "busybox", tag).CombinedOutput(); err != nil {
- t.Fatalf("Failed to tag image: %s, out: %q", err, out)
+ c.Fatalf("Failed to tag image: %s, out: %q", err, out)
}
var id1 string
if out, err := exec.Command(dockerBinary, "run", "-d", "busybox", "top").CombinedOutput(); err != nil {
- t.Fatalf("Failed to run container: %s, out: %q", err, out)
+ c.Fatalf("Failed to run container: %s, out: %q", err, out)
} else {
id1 = strings.TrimSpace(string(out))
}
var id2 string
if out, err := exec.Command(dockerBinary, "run", "-d", tag, "top").CombinedOutput(); err != nil {
- t.Fatalf("Failed to run container: %s, out: %q", err, out)
+ c.Fatalf("Failed to run container: %s, out: %q", err, out)
} else {
id2 = strings.TrimSpace(string(out))
}
var imageID string
if out, err := exec.Command(dockerBinary, "inspect", "-f", "{{.Id}}", "busybox").CombinedOutput(); err != nil {
- t.Fatalf("failed to get the image ID of busybox: %s, %v", out, err)
+ c.Fatalf("failed to get the image ID of busybox: %s, %v", out, err)
} else {
imageID = strings.TrimSpace(string(out))
}
var id3 string
if out, err := exec.Command(dockerBinary, "run", "-d", imageID, "top").CombinedOutput(); err != nil {
- t.Fatalf("Failed to run container: %s, out: %q", err, out)
+ c.Fatalf("Failed to run container: %s, out: %q", err, out)
} else {
id3 = strings.TrimSpace(string(out))
}
out, err := exec.Command(dockerBinary, "ps", "--no-trunc").CombinedOutput()
if err != nil {
- t.Fatalf("Failed to run 'ps': %s, out: %q", err, out)
+ c.Fatalf("Failed to run 'ps': %s, out: %q", err, out)
}
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
// skip header
lines = lines[1:]
if len(lines) != 3 {
- t.Fatalf("There should be 3 running container, got %d", len(lines))
+ c.Fatalf("There should be 3 running container, got %d", len(lines))
}
for _, line := range lines {
f := strings.Fields(line)
switch f[0] {
case id1:
if f[1] != "busybox" {
- t.Fatalf("Expected %s tag for id %s, got %s", "busybox", id1, f[1])
+ c.Fatalf("Expected %s tag for id %s, got %s", "busybox", id1, f[1])
}
case id2:
if f[1] != tag {
- t.Fatalf("Expected %s tag for id %s, got %s", tag, id2, f[1])
+ c.Fatalf("Expected %s tag for id %s, got %s", tag, id2, f[1])
}
case id3:
if f[1] != imageID {
- t.Fatalf("Expected %s imageID for id %s, got %s", tag, id3, f[1])
+ c.Fatalf("Expected %s imageID for id %s, got %s", tag, id3, f[1])
}
default:
- t.Fatalf("Unexpected id %s, expected %s and %s and %s", f[0], id1, id2, id3)
+ c.Fatalf("Unexpected id %s, expected %s and %s and %s", f[0], id1, id2, id3)
}
}
- logDone("ps - right tags for containers")
}
-func TestPsLinkedWithNoTrunc(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestPsLinkedWithNoTrunc(c *check.C) {
if out, err := exec.Command(dockerBinary, "run", "--name=first", "-d", "busybox", "top").CombinedOutput(); err != nil {
- t.Fatalf("Output: %s, err: %s", out, err)
+ c.Fatalf("Output: %s, err: %s", out, err)
}
if out, err := exec.Command(dockerBinary, "run", "--name=second", "--link=first:first", "-d", "busybox", "top").CombinedOutput(); err != nil {
- t.Fatalf("Output: %s, err: %s", out, err)
+ c.Fatalf("Output: %s, err: %s", out, err)
}
out, err := exec.Command(dockerBinary, "ps", "--no-trunc").CombinedOutput()
if err != nil {
- t.Fatalf("Output: %s, err: %s", out, err)
+ c.Fatalf("Output: %s, err: %s", out, err)
}
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
// strip header
@@ -663,28 +643,26 @@ func TestPsLinkedWithNoTrunc(t *testing.T) {
names = append(names, fields[len(fields)-1])
}
if !reflect.DeepEqual(expected, names) {
- t.Fatalf("Expected array: %v, got: %v", expected, names)
+ c.Fatalf("Expected array: %v, got: %v", expected, names)
}
}
-func TestPsGroupPortRange(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestPsGroupPortRange(c *check.C) {
portRange := "3800-3900"
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", "porttest", "-p", portRange+":"+portRange, "busybox", "top"))
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "ps"))
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
// check that the port range is in the output
if !strings.Contains(string(out), portRange) {
- t.Fatalf("docker ps output should have had the port range %q: %s", portRange, string(out))
+ c.Fatalf("docker ps output should have had the port range %q: %s", portRange, string(out))
}
- logDone("ps - port range")
}
diff --git a/integration-cli/docker_cli_pull_test.go b/integration-cli/docker_cli_pull_test.go
index 6e5ddb84083aa..a3ded8f038da8 100644
--- a/integration-cli/docker_cli_pull_test.go
+++ b/integration-cli/docker_cli_pull_test.go
@@ -4,15 +4,13 @@ import (
"fmt"
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
// See issue docker/docker#8141
-func TestPullImageWithAliases(t *testing.T) {
- defer setupRegistry(t)()
-
+func (s *DockerRegistrySuite) TestPullImageWithAliases(c *check.C) {
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
- defer deleteImages(repoName)
repos := []string{}
for _, tag := range []string{"recent", "fresh"} {
@@ -22,93 +20,91 @@ func TestPullImageWithAliases(t *testing.T) {
// Tag and push the same image multiple times.
for _, repo := range repos {
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "tag", "busybox", repo)); err != nil {
- t.Fatalf("Failed to tag image %v: error %v, output %q", repos, err, out)
+ c.Fatalf("Failed to tag image %v: error %v, output %q", repos, err, out)
}
- defer deleteImages(repo)
if out, err := exec.Command(dockerBinary, "push", repo).CombinedOutput(); err != nil {
- t.Fatalf("Failed to push image %v: error %v, output %q", repo, err, string(out))
+ c.Fatalf("Failed to push image %v: error %v, output %q", repo, err, string(out))
}
}
// Clear local images store.
args := append([]string{"rmi"}, repos...)
if out, err := exec.Command(dockerBinary, args...).CombinedOutput(); err != nil {
- t.Fatalf("Failed to clean images: error %v, output %q", err, string(out))
+ c.Fatalf("Failed to clean images: error %v, output %q", err, string(out))
}
// Pull a single tag and verify it doesn't bring down all aliases.
pullCmd := exec.Command(dockerBinary, "pull", repos[0])
if out, _, err := runCommandWithOutput(pullCmd); err != nil {
- t.Fatalf("Failed to pull %v: error %v, output %q", repoName, err, out)
+ c.Fatalf("Failed to pull %v: error %v, output %q", repoName, err, out)
}
if err := exec.Command(dockerBinary, "inspect", repos[0]).Run(); err != nil {
- t.Fatalf("Image %v was not pulled down", repos[0])
+ c.Fatalf("Image %v was not pulled down", repos[0])
}
for _, repo := range repos[1:] {
if err := exec.Command(dockerBinary, "inspect", repo).Run(); err == nil {
- t.Fatalf("Image %v shouldn't have been pulled down", repo)
+ c.Fatalf("Image %v shouldn't have been pulled down", repo)
}
}
-
- logDone("pull - image with aliases")
}
// pulling library/hello-world should show verified message
-func TestPullVerified(t *testing.T) {
+func (s *DockerSuite) TestPullVerified(c *check.C) {
+ c.Skip("Skipping hub dependent test")
+
// Image must be pulled from central repository to get verified message
// unless keychain is manually updated to contain the daemon's sign key.
verifiedName := "hello-world"
- defer deleteImages(verifiedName)
// pull it
expected := "The image you are pulling has been verified"
pullCmd := exec.Command(dockerBinary, "pull", verifiedName)
if out, exitCode, err := runCommandWithOutput(pullCmd); err != nil || !strings.Contains(out, expected) {
if err != nil || exitCode != 0 {
- t.Skipf("pulling the '%s' image from the registry has failed: %s", verifiedName, err)
+ c.Skip(fmt.Sprintf("pulling the '%s' image from the registry has failed: %v", verifiedName, err))
}
- t.Fatalf("pulling a verified image failed. expected: %s\ngot: %s, %v", expected, out, err)
+ c.Fatalf("pulling a verified image failed. expected: %s\ngot: %s, %v", expected, out, err)
}
// pull it again
pullCmd = exec.Command(dockerBinary, "pull", verifiedName)
if out, exitCode, err := runCommandWithOutput(pullCmd); err != nil || strings.Contains(out, expected) {
if err != nil || exitCode != 0 {
- t.Skipf("pulling the '%s' image from the registry has failed: %s", verifiedName, err)
+ c.Skip(fmt.Sprintf("pulling the '%s' image from the registry has failed: %v", verifiedName, err))
}
- t.Fatalf("pulling a verified image failed. unexpected verify message\ngot: %s, %v", out, err)
+ c.Fatalf("pulling a verified image failed. unexpected verify message\ngot: %s, %v", out, err)
}
- logDone("pull - pull verified")
}
// pulling an image from the central registry should work
-func TestPullImageFromCentralRegistry(t *testing.T) {
- testRequires(t, Network)
-
- defer deleteImages("hello-world")
+func (s *DockerSuite) TestPullImageFromCentralRegistry(c *check.C) {
+ testRequires(c, Network)
pullCmd := exec.Command(dockerBinary, "pull", "hello-world")
if out, _, err := runCommandWithOutput(pullCmd); err != nil {
- t.Fatalf("pulling the hello-world image from the registry has failed: %s, %v", out, err)
+ c.Fatalf("pulling the hello-world image from the registry has failed: %s, %v", out, err)
}
- logDone("pull - pull hello-world")
}
// pulling a non-existing image from the central registry should return a non-zero exit code
-func TestPullNonExistingImage(t *testing.T) {
- pullCmd := exec.Command(dockerBinary, "pull", "fooblahblah1234")
- if out, _, err := runCommandWithOutput(pullCmd); err == nil {
- t.Fatalf("expected non-zero exit status when pulling non-existing image: %s", out)
+func (s *DockerSuite) TestPullNonExistingImage(c *check.C) {
+ testRequires(c, Network)
+
+ name := "sadfsadfasdf"
+ pullCmd := exec.Command(dockerBinary, "pull", name)
+ out, _, err := runCommandWithOutput(pullCmd)
+
+ if err == nil || !strings.Contains(out, fmt.Sprintf("Error: image library/%s:latest not found", name)) {
+ c.Fatalf("expected non-zero exit status when pulling non-existing image: %s", out)
}
- logDone("pull - pull fooblahblah1234 (non-existing image)")
}
// pulling an image from the central registry using official names should work
// ensure all pulls result in the same image
-func TestPullImageOfficialNames(t *testing.T) {
- testRequires(t, Network)
+func (s *DockerSuite) TestPullImageOfficialNames(c *check.C) {
+ testRequires(c, Network)
names := []string{
"docker.io/hello-world",
@@ -121,7 +117,7 @@ func TestPullImageOfficialNames(t *testing.T) {
pullCmd := exec.Command(dockerBinary, "pull", name)
out, exitCode, err := runCommandWithOutput(pullCmd)
if err != nil || exitCode != 0 {
- t.Errorf("pulling the '%s' image from the registry has failed: %s", name, err)
+ c.Errorf("pulling the '%s' image from the registry has failed: %s", name, err)
continue
}
@@ -129,10 +125,28 @@ func TestPullImageOfficialNames(t *testing.T) {
imagesCmd := exec.Command(dockerBinary, "images")
out, _, err = runCommandWithOutput(imagesCmd)
if err != nil {
- t.Errorf("listing images failed with errors: %v", err)
+ c.Errorf("listing images failed with errors: %v", err)
} else if strings.Contains(out, name) {
- t.Errorf("images should not have listed '%s'", name)
+ c.Errorf("images should not have listed '%s'", name)
}
}
- logDone("pull - pull official names")
+}
+
+func (s *DockerSuite) TestPullScratchNotAllowed(c *check.C) {
+ testRequires(c, Network)
+
+ pullCmd := exec.Command(dockerBinary, "pull", "scratch")
+ out, exitCode, err := runCommandWithOutput(pullCmd)
+ if err == nil {
+ c.Fatal("expected pull of scratch to fail, but it didn't")
+ }
+ if exitCode != 1 {
+ c.Fatalf("pulling scratch expected exit code 1, got %d", exitCode)
+ }
+ if strings.Contains(out, "Pulling repository scratch") {
+ c.Fatalf("pulling scratch should not have begun: %s", out)
+ }
+ if !strings.Contains(out, "'scratch' is a reserved name") {
+ c.Fatalf("unexpected output pulling scratch: %s", out)
+ }
}
diff --git a/integration-cli/docker_cli_push_test.go b/integration-cli/docker_cli_push_test.go
index f1274ba706e55..69a05ed821c78 100644
--- a/integration-cli/docker_cli_push_test.go
+++ b/integration-cli/docker_cli_push_test.go
@@ -6,153 +6,135 @@ import (
"os"
"os/exec"
"strings"
- "testing"
"time"
"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
+ "github.com/go-check/check"
)
// pulling an image from the central registry should work
-func TestPushBusyboxImage(t *testing.T) {
- defer setupRegistry(t)()
-
+func (s *DockerRegistrySuite) TestPushBusyboxImage(c *check.C) {
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
// tag the image to upload it to the private registry
tagCmd := exec.Command(dockerBinary, "tag", "busybox", repoName)
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
- t.Fatalf("image tagging failed: %s, %v", out, err)
+ c.Fatalf("image tagging failed: %s, %v", out, err)
}
- defer deleteImages(repoName)
pushCmd := exec.Command(dockerBinary, "push", repoName)
if out, _, err := runCommandWithOutput(pushCmd); err != nil {
- t.Fatalf("pushing the image to the private registry has failed: %s, %v", out, err)
+ c.Fatalf("pushing the image to the private registry has failed: %s, %v", out, err)
}
- logDone("push - busybox to private registry")
}
// pushing an image without a prefix should throw an error
-func TestPushUnprefixedRepo(t *testing.T) {
+func (s *DockerSuite) TestPushUnprefixedRepo(c *check.C) {
pushCmd := exec.Command(dockerBinary, "push", "busybox")
if out, _, err := runCommandWithOutput(pushCmd); err == nil {
- t.Fatalf("pushing an unprefixed repo didn't result in a non-zero exit status: %s", out)
+ c.Fatalf("pushing an unprefixed repo didn't result in a non-zero exit status: %s", out)
}
- logDone("push - unprefixed busybox repo must not pass")
}
-func TestPushUntagged(t *testing.T) {
- defer setupRegistry(t)()
-
+func (s *DockerRegistrySuite) TestPushUntagged(c *check.C) {
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
expected := "Repository does not exist"
pushCmd := exec.Command(dockerBinary, "push", repoName)
if out, _, err := runCommandWithOutput(pushCmd); err == nil {
- t.Fatalf("pushing the image to the private registry should have failed: outuput %q", out)
+ c.Fatalf("pushing the image to the private registry should have failed: output %q", out)
} else if !strings.Contains(out, expected) {
- t.Fatalf("pushing the image failed with an unexpected message: expected %q, got %q", expected, out)
+ c.Fatalf("pushing the image failed with an unexpected message: expected %q, got %q", expected, out)
}
- logDone("push - untagged image")
}
-func TestPushBadTag(t *testing.T) {
- defer setupRegistry(t)()
-
+func (s *DockerRegistrySuite) TestPushBadTag(c *check.C) {
repoName := fmt.Sprintf("%v/dockercli/busybox:latest", privateRegistryURL)
expected := "does not exist"
pushCmd := exec.Command(dockerBinary, "push", repoName)
if out, _, err := runCommandWithOutput(pushCmd); err == nil {
- t.Fatalf("pushing the image to the private registry should have failed: outuput %q", out)
+ c.Fatalf("pushing the image to the private registry should have failed: output %q", out)
} else if !strings.Contains(out, expected) {
- t.Fatalf("pushing the image failed with an unexpected message: expected %q, got %q", expected, out)
+ c.Fatalf("pushing the image failed with an unexpected message: expected %q, got %q", expected, out)
}
- logDone("push - image with bad tag")
}
-func TestPushMultipleTags(t *testing.T) {
- defer setupRegistry(t)()
-
+func (s *DockerRegistrySuite) TestPushMultipleTags(c *check.C) {
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
repoTag1 := fmt.Sprintf("%v/dockercli/busybox:t1", privateRegistryURL)
repoTag2 := fmt.Sprintf("%v/dockercli/busybox:t2", privateRegistryURL)
- // tag the image to upload it tot he private registry
+ // tag the image and upload it to the private registry
tagCmd1 := exec.Command(dockerBinary, "tag", "busybox", repoTag1)
if out, _, err := runCommandWithOutput(tagCmd1); err != nil {
- t.Fatalf("image tagging failed: %s, %v", out, err)
+ c.Fatalf("image tagging failed: %s, %v", out, err)
}
- defer deleteImages(repoTag1)
tagCmd2 := exec.Command(dockerBinary, "tag", "busybox", repoTag2)
if out, _, err := runCommandWithOutput(tagCmd2); err != nil {
- t.Fatalf("image tagging failed: %s, %v", out, err)
+ c.Fatalf("image tagging failed: %s, %v", out, err)
}
- defer deleteImages(repoTag2)
pushCmd := exec.Command(dockerBinary, "push", repoName)
if out, _, err := runCommandWithOutput(pushCmd); err != nil {
- t.Fatalf("pushing the image to the private registry has failed: %s, %v", out, err)
+ c.Fatalf("pushing the image to the private registry has failed: %s, %v", out, err)
}
- logDone("push - multiple tags to private registry")
}
-func TestPushInterrupt(t *testing.T) {
- defer setupRegistry(t)()
-
+func (s *DockerRegistrySuite) TestPushInterrupt(c *check.C) {
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
- // tag the image to upload it tot he private registry
- tagCmd := exec.Command(dockerBinary, "tag", "busybox", repoName)
- if out, _, err := runCommandWithOutput(tagCmd); err != nil {
- t.Fatalf("image tagging failed: %s, %v", out, err)
+ // tag the image and upload it to the private registry
+ if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "tag", "busybox", repoName)); err != nil {
+ c.Fatalf("image tagging failed: %s, %v", out, err)
}
- defer deleteImages(repoName)
pushCmd := exec.Command(dockerBinary, "push", repoName)
if err := pushCmd.Start(); err != nil {
- t.Fatalf("Failed to start pushing to private registry: %v", err)
+ c.Fatalf("Failed to start pushing to private registry: %v", err)
}
// Interrupt push (yes, we have no idea at what point it will get killed).
time.Sleep(200 * time.Millisecond)
if err := pushCmd.Process.Kill(); err != nil {
- t.Fatalf("Failed to kill push process: %v", err)
+ c.Fatalf("Failed to kill push process: %v", err)
}
- // Try agin
- pushCmd = exec.Command(dockerBinary, "push", repoName)
- if err := pushCmd.Start(); err != nil {
- t.Fatalf("Failed to start pushing to private registry: %v", err)
+ if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "push", repoName)); err == nil {
+ str := string(out)
+ if !strings.Contains(str, "already in progress") {
+ c.Fatalf("Push should be continued on daemon side, but seems ok: %v, %s", err, out)
+ }
+ }
+ // now wait until all this pushes will complete
+ // if it failed with timeout - there would be some error,
+ // so no logic about it here
+ for exec.Command(dockerBinary, "push", repoName).Run() != nil {
}
-
- logDone("push - interrupted")
}
-func TestPushEmptyLayer(t *testing.T) {
- defer setupRegistry(t)()
+func (s *DockerRegistrySuite) TestPushEmptyLayer(c *check.C) {
repoName := fmt.Sprintf("%v/dockercli/emptylayer", privateRegistryURL)
emptyTarball, err := ioutil.TempFile("", "empty_tarball")
if err != nil {
- t.Fatalf("Unable to create test file: %v", err)
+ c.Fatalf("Unable to create test file: %v", err)
}
tw := tar.NewWriter(emptyTarball)
err = tw.Close()
if err != nil {
- t.Fatalf("Error creating empty tarball: %v", err)
+ c.Fatalf("Error creating empty tarball: %v", err)
}
freader, err := os.Open(emptyTarball.Name())
if err != nil {
- t.Fatalf("Could not open test tarball: %v", err)
+ c.Fatalf("Could not open test tarball: %v", err)
}
importCmd := exec.Command(dockerBinary, "import", "-", repoName)
importCmd.Stdin = freader
out, _, err := runCommandWithOutput(importCmd)
if err != nil {
- t.Errorf("import failed with errors: %v, output: %q", err, out)
+ c.Errorf("import failed with errors: %v, output: %q", err, out)
}
// Now verify we can push it
pushCmd := exec.Command(dockerBinary, "push", repoName)
if out, _, err := runCommandWithOutput(pushCmd); err != nil {
- t.Fatalf("pushing the image to the private registry has failed: %s, %v", out, err)
+ c.Fatalf("pushing the image to the private registry has failed: %s, %v", out, err)
}
- logDone("push - empty layer config to private registry")
}
diff --git a/integration-cli/docker_cli_rename_test.go b/integration-cli/docker_cli_rename_test.go
index ed24d971d5de6..156ea6eeb3065 100644
--- a/integration-cli/docker_cli_rename_test.go
+++ b/integration-cli/docker_cli_rename_test.go
@@ -3,16 +3,16 @@ package main
import (
"os/exec"
"strings"
- "testing"
-)
-func TestRenameStoppedContainer(t *testing.T) {
- defer deleteAllContainers()
+ "github.com/docker/docker/pkg/stringid"
+ "github.com/go-check/check"
+)
+func (s *DockerSuite) TestRenameStoppedContainer(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "--name", "first_name", "-d", "busybox", "sh")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf(out, err)
+ c.Fatalf(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -20,102 +20,93 @@ func TestRenameStoppedContainer(t *testing.T) {
runCmd = exec.Command(dockerBinary, "wait", cleanedContainerID)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf(out, err)
+ c.Fatalf(out, err)
}
name, err := inspectField(cleanedContainerID, "Name")
- runCmd = exec.Command(dockerBinary, "rename", "first_name", "new_name")
+ newName := "new_name" + stringid.GenerateRandomID()
+ runCmd = exec.Command(dockerBinary, "rename", "first_name", newName)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf(out, err)
+ c.Fatalf(out, err)
}
name, err = inspectField(cleanedContainerID, "Name")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- if name != "/new_name" {
- t.Fatal("Failed to rename container ", name)
+ if name != "/"+newName {
+ c.Fatal("Failed to rename container ", name)
}
- logDone("rename - stopped container")
}
-func TestRenameRunningContainer(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRenameRunningContainer(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "--name", "first_name", "-d", "busybox", "sh")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf(out, err)
+ c.Fatalf(out, err)
}
+ newName := "new_name" + stringid.GenerateRandomID()
cleanedContainerID := strings.TrimSpace(out)
- runCmd = exec.Command(dockerBinary, "rename", "first_name", "new_name")
+ runCmd = exec.Command(dockerBinary, "rename", "first_name", newName)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf(out, err)
+ c.Fatalf(out, err)
}
name, err := inspectField(cleanedContainerID, "Name")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- if name != "/new_name" {
- t.Fatal("Failed to rename container ")
+ if name != "/"+newName {
+ c.Fatal("Failed to rename container ")
}
-
- logDone("rename - running container")
}
-func TestRenameCheckNames(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRenameCheckNames(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "--name", "first_name", "-d", "busybox", "sh")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf(out, err)
+ c.Fatalf(out, err)
}
- runCmd = exec.Command(dockerBinary, "rename", "first_name", "new_name")
+ newName := "new_name" + stringid.GenerateRandomID()
+ runCmd = exec.Command(dockerBinary, "rename", "first_name", newName)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf(out, err)
+ c.Fatalf(out, err)
}
- name, err := inspectField("new_name", "Name")
+ name, err := inspectField(newName, "Name")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- if name != "/new_name" {
- t.Fatal("Failed to rename container ")
+ if name != "/"+newName {
+ c.Fatal("Failed to rename container ")
}
name, err = inspectField("first_name", "Name")
if err == nil && !strings.Contains(err.Error(), "No such image or container: first_name") {
- t.Fatal(err)
+ c.Fatal(err)
}
-
- logDone("rename - old name released")
}
-func TestRenameInvalidName(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRenameInvalidName(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "--name", "myname", "-d", "busybox", "top")
if out, _, err := runCommandWithOutput(runCmd); err != nil {
- t.Fatalf(out, err)
+ c.Fatalf(out, err)
}
runCmd = exec.Command(dockerBinary, "rename", "myname", "new:invalid")
if out, _, err := runCommandWithOutput(runCmd); err == nil || !strings.Contains(out, "Invalid container name") {
- t.Fatalf("Renaming container to invalid name should have failed: %s\n%v", out, err)
+ c.Fatalf("Renaming container to invalid name should have failed: %s\n%v", out, err)
}
runCmd = exec.Command(dockerBinary, "ps", "-a")
if out, _, err := runCommandWithOutput(runCmd); err != nil || !strings.Contains(out, "myname") {
- t.Fatalf("Output of docker ps should have included 'myname': %s\n%v", out, err)
+ c.Fatalf("Output of docker ps should have included 'myname': %s\n%v", out, err)
}
-
- logDone("rename - invalid container name")
}
diff --git a/integration-cli/docker_cli_restart_test.go b/integration-cli/docker_cli_restart_test.go
index dde450dcd0515..2b9d5e2323511 100644
--- a/integration-cli/docker_cli_restart_test.go
+++ b/integration-cli/docker_cli_restart_test.go
@@ -3,61 +3,59 @@ package main
import (
"os/exec"
"strings"
- "testing"
"time"
+
+ "github.com/go-check/check"
)
-func TestRestartStoppedContainer(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRestartStoppedContainer(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "echo", "foobar")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
runCmd = exec.Command(dockerBinary, "wait", cleanedContainerID)
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
runCmd = exec.Command(dockerBinary, "logs", cleanedContainerID)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if out != "foobar\n" {
- t.Errorf("container should've printed 'foobar'")
+ c.Errorf("container should've printed 'foobar'")
}
runCmd = exec.Command(dockerBinary, "restart", cleanedContainerID)
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
runCmd = exec.Command(dockerBinary, "logs", cleanedContainerID)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if out != "foobar\nfoobar\n" {
- t.Errorf("container should've printed 'foobar' twice")
+ c.Errorf("container should've printed 'foobar' twice")
}
- logDone("restart - echo foobar for stopped container")
}
-func TestRestartRunningContainer(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRestartRunningContainer(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", "echo foobar && sleep 30 && echo 'should not print this'")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -67,41 +65,39 @@ func TestRestartRunningContainer(t *testing.T) {
runCmd = exec.Command(dockerBinary, "logs", cleanedContainerID)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if out != "foobar\n" {
- t.Errorf("container should've printed 'foobar'")
+ c.Errorf("container should've printed 'foobar'")
}
runCmd = exec.Command(dockerBinary, "restart", "-t", "1", cleanedContainerID)
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
runCmd = exec.Command(dockerBinary, "logs", cleanedContainerID)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
time.Sleep(1 * time.Second)
if out != "foobar\nfoobar\n" {
- t.Errorf("container should've printed 'foobar' twice")
+ c.Errorf("container should've printed 'foobar' twice")
}
- logDone("restart - echo foobar for running container")
}
// Test that restarting a container with a volume does not create a new volume on restart. Regression test for #819.
-func TestRestartWithVolumes(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRestartWithVolumes(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "-v", "/test", "busybox", "top")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -109,148 +105,139 @@ func TestRestartWithVolumes(t *testing.T) {
runCmd = exec.Command(dockerBinary, "inspect", "--format", "{{ len .Volumes }}", cleanedContainerID)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if out = strings.Trim(out, " \n\r"); out != "1" {
- t.Errorf("expect 1 volume received %s", out)
+ c.Errorf("expect 1 volume received %s", out)
}
runCmd = exec.Command(dockerBinary, "inspect", "--format", "{{ .Volumes }}", cleanedContainerID)
volumes, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(volumes, err)
+ c.Fatal(volumes, err)
}
runCmd = exec.Command(dockerBinary, "restart", cleanedContainerID)
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
runCmd = exec.Command(dockerBinary, "inspect", "--format", "{{ len .Volumes }}", cleanedContainerID)
out, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if out = strings.Trim(out, " \n\r"); out != "1" {
- t.Errorf("expect 1 volume after restart received %s", out)
+ c.Errorf("expect 1 volume after restart received %s", out)
}
runCmd = exec.Command(dockerBinary, "inspect", "--format", "{{ .Volumes }}", cleanedContainerID)
volumesAfterRestart, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(volumesAfterRestart, err)
+ c.Fatal(volumesAfterRestart, err)
}
if volumes != volumesAfterRestart {
volumes = strings.Trim(volumes, " \n\r")
volumesAfterRestart = strings.Trim(volumesAfterRestart, " \n\r")
- t.Errorf("expected volume path: %s Actual path: %s", volumes, volumesAfterRestart)
+ c.Errorf("expected volume path: %s Actual path: %s", volumes, volumesAfterRestart)
}
- logDone("restart - does not create a new volume on restart")
}
-func TestRestartPolicyNO(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRestartPolicyNO(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-d", "--restart=no", "busybox", "false")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
id := strings.TrimSpace(string(out))
name, err := inspectField(id, "HostConfig.RestartPolicy.Name")
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if name != "no" {
- t.Fatalf("Container restart policy name is %s, expected %s", name, "no")
+ c.Fatalf("Container restart policy name is %s, expected %s", name, "no")
}
- logDone("restart - recording restart policy name for --restart=no")
}
-func TestRestartPolicyAlways(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRestartPolicyAlways(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-d", "--restart=always", "busybox", "false")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
id := strings.TrimSpace(string(out))
name, err := inspectField(id, "HostConfig.RestartPolicy.Name")
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if name != "always" {
- t.Fatalf("Container restart policy name is %s, expected %s", name, "always")
+ c.Fatalf("Container restart policy name is %s, expected %s", name, "always")
}
MaximumRetryCount, err := inspectField(id, "HostConfig.RestartPolicy.MaximumRetryCount")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// MaximumRetryCount=0 if the restart policy is always
if MaximumRetryCount != "0" {
- t.Fatalf("Container Maximum Retry Count is %s, expected %s", MaximumRetryCount, "0")
+ c.Fatalf("Container Maximum Retry Count is %s, expected %s", MaximumRetryCount, "0")
}
- logDone("restart - recording restart policy name for --restart=always")
}
-func TestRestartPolicyOnFailure(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRestartPolicyOnFailure(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-d", "--restart=on-failure:1", "busybox", "false")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
id := strings.TrimSpace(string(out))
name, err := inspectField(id, "HostConfig.RestartPolicy.Name")
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if name != "on-failure" {
- t.Fatalf("Container restart policy name is %s, expected %s", name, "on-failure")
+ c.Fatalf("Container restart policy name is %s, expected %s", name, "on-failure")
}
- logDone("restart - recording restart policy name for --restart=on-failure")
}
// a good container with --restart=on-failure:3
// MaximumRetryCount!=0; RestartCount=0
-func TestContainerRestartwithGoodContainer(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestContainerRestartwithGoodContainer(c *check.C) {
out, err := exec.Command(dockerBinary, "run", "-d", "--restart=on-failure:3", "busybox", "true").CombinedOutput()
if err != nil {
- t.Fatal(string(out), err)
+ c.Fatal(string(out), err)
}
id := strings.TrimSpace(string(out))
if err := waitInspect(id, "{{ .State.Restarting }} {{ .State.Running }}", "false false", 5); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
count, err := inspectField(id, "RestartCount")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if count != "0" {
- t.Fatalf("Container was restarted %s times, expected %d", count, 0)
+ c.Fatalf("Container was restarted %s times, expected %d", count, 0)
}
MaximumRetryCount, err := inspectField(id, "HostConfig.RestartPolicy.MaximumRetryCount")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if MaximumRetryCount != "3" {
- t.Fatalf("Container Maximum Retry Count is %s, expected %s", MaximumRetryCount, "3")
+ c.Fatalf("Container Maximum Retry Count is %s, expected %s", MaximumRetryCount, "3")
}
- logDone("restart - for a good container with restart policy, MaximumRetryCount is not 0 and RestartCount is 0")
}
diff --git a/integration-cli/docker_cli_rm_test.go b/integration-cli/docker_cli_rm_test.go
index d01b36d45d2d4..b8d1b843d1502 100644
--- a/integration-cli/docker_cli_rm_test.go
+++ b/integration-cli/docker_cli_rm_test.go
@@ -1,97 +1,82 @@
package main
import (
+ "net/http"
"os"
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
-func TestRmContainerWithRemovedVolume(t *testing.T) {
- testRequires(t, SameHostDaemon)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRmContainerWithRemovedVolume(c *check.C) {
+ testRequires(c, SameHostDaemon)
cmd := exec.Command(dockerBinary, "run", "--name", "losemyvolumes", "-v", "/tmp/testing:/test", "busybox", "true")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err := os.Remove("/tmp/testing"); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "rm", "-v", "losemyvolumes")
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
- logDone("rm - removed volume")
}
-func TestRmContainerWithVolume(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRmContainerWithVolume(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--name", "foo", "-v", "/srv", "busybox", "true")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "rm", "-v", "foo")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("rm - volume")
}
-func TestRmRunningContainer(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRmRunningContainer(c *check.C) {
- createRunningContainer(t, "foo")
+ createRunningContainer(c, "foo")
// Test cannot remove running container
cmd := exec.Command(dockerBinary, "rm", "foo")
if _, err := runCommand(cmd); err == nil {
- t.Fatalf("Expected error, can't rm a running container")
+ c.Fatalf("Expected error, can't rm a running container")
}
- logDone("rm - running container")
}
-func TestRmRunningContainerCheckError409(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRmRunningContainerCheckError409(c *check.C) {
- createRunningContainer(t, "foo")
+ createRunningContainer(c, "foo")
endpoint := "/containers/foo"
- _, err := sockRequest("DELETE", endpoint, nil)
-
- if err == nil {
- t.Fatalf("Expected error, can't rm a running container")
- }
- if !strings.Contains(err.Error(), "409 Conflict") {
- t.Fatalf("Expected error to contain '409 Conflict' but found %s", err)
- }
-
- logDone("rm - running container")
+ status, _, err := sockRequest("DELETE", endpoint, nil)
+ c.Assert(status, check.Equals, http.StatusConflict)
+ c.Assert(err, check.IsNil)
}
-func TestRmForceRemoveRunningContainer(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRmForceRemoveRunningContainer(c *check.C) {
- createRunningContainer(t, "foo")
+ createRunningContainer(c, "foo")
// Stop then remove with -s
cmd := exec.Command(dockerBinary, "rm", "-f", "foo")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("rm - running container with --force=true")
}
-func TestRmContainerOrphaning(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRmContainerOrphaning(c *check.C) {
dockerfile1 := `FROM busybox:latest
ENTRYPOINT ["/bin/true"]`
@@ -102,47 +87,44 @@ func TestRmContainerOrphaning(t *testing.T) {
// build first dockerfile
img1, err := buildImage(img, dockerfile1, true)
- defer deleteImages(img1)
if err != nil {
- t.Fatalf("Could not build image %s: %v", img, err)
+ c.Fatalf("Could not build image %s: %v", img, err)
}
// run container on first image
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", img)); err != nil {
- t.Fatalf("Could not run image %s: %v: %s", img, err, out)
+ c.Fatalf("Could not run image %s: %v: %s", img, err, out)
}
// rebuild dockerfile with a small addition at the end
if _, err := buildImage(img, dockerfile2, true); err != nil {
- t.Fatalf("Could not rebuild image %s: %v", img, err)
+ c.Fatalf("Could not rebuild image %s: %v", img, err)
}
// try to remove the image, should error out.
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "rmi", img)); err == nil {
- t.Fatalf("Expected to error out removing the image, but succeeded: %s", out)
+ c.Fatalf("Expected to error out removing the image, but succeeded: %s", out)
}
// check if we deleted the first image
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "images", "-q", "--no-trunc"))
if err != nil {
- t.Fatalf("%v: %s", err, out)
+ c.Fatalf("%v: %s", err, out)
}
if !strings.Contains(out, img1) {
- t.Fatalf("Orphaned container (could not find %q in docker images): %s", img1, out)
+ c.Fatalf("Orphaned container (could not find %q in docker images): %s", img1, out)
}
- logDone("rm - container orphaning")
}
-func TestRmInvalidContainer(t *testing.T) {
+func (s *DockerSuite) TestRmInvalidContainer(c *check.C) {
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "rm", "unknown")); err == nil {
- t.Fatal("Expected error on rm unknown container, got none")
+ c.Fatal("Expected error on rm unknown container, got none")
} else if !strings.Contains(out, "failed to remove one or more containers") {
- t.Fatalf("Expected output to contain 'failed to remove one or more containers', got %q", out)
+ c.Fatalf("Expected output to contain 'failed to remove one or more containers', got %q", out)
}
- logDone("rm - delete unknown container")
}
-func createRunningContainer(t *testing.T, name string) {
+func createRunningContainer(c *check.C, name string) {
cmd := exec.Command(dockerBinary, "run", "-dt", "--name", name, "busybox", "top")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
}
diff --git a/integration-cli/docker_cli_rmi_test.go b/integration-cli/docker_cli_rmi_test.go
index 277004d2ecca7..9dc2ee297a8d7 100644
--- a/integration-cli/docker_cli_rmi_test.go
+++ b/integration-cli/docker_cli_rmi_test.go
@@ -1,19 +1,21 @@
package main
import (
+ "fmt"
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
-func TestRmiWithContainerFails(t *testing.T) {
+func (s *DockerSuite) TestRmiWithContainerFails(c *check.C) {
errSubstr := "is using it"
// create a container
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("failed to create a container: %s, %v", out, err)
+ c.Fatalf("failed to create a container: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -22,86 +24,125 @@ func TestRmiWithContainerFails(t *testing.T) {
runCmd = exec.Command(dockerBinary, "rmi", "busybox")
out, _, err = runCommandWithOutput(runCmd)
if err == nil {
- t.Fatalf("Container %q is using image, should not be able to rmi: %q", cleanedContainerID, out)
+ c.Fatalf("Container %q is using image, should not be able to rmi: %q", cleanedContainerID, out)
}
if !strings.Contains(out, errSubstr) {
- t.Fatalf("Container %q is using image, error message should contain %q: %v", cleanedContainerID, errSubstr, out)
+ c.Fatalf("Container %q is using image, error message should contain %q: %v", cleanedContainerID, errSubstr, out)
}
// make sure it didn't delete the busybox name
- images, _, _ := dockerCmd(t, "images")
+ images, _ := dockerCmd(c, "images")
if !strings.Contains(images, "busybox") {
- t.Fatalf("The name 'busybox' should not have been removed from images: %q", images)
+ c.Fatalf("The name 'busybox' should not have been removed from images: %q", images)
}
deleteContainer(cleanedContainerID)
- logDone("rmi - container using image while rmi, should not remove image name")
}
-func TestRmiTag(t *testing.T) {
- imagesBefore, _, _ := dockerCmd(t, "images", "-a")
- dockerCmd(t, "tag", "busybox", "utest:tag1")
- dockerCmd(t, "tag", "busybox", "utest/docker:tag2")
- dockerCmd(t, "tag", "busybox", "utest:5000/docker:tag3")
+func (s *DockerSuite) TestRmiTag(c *check.C) {
+ imagesBefore, _ := dockerCmd(c, "images", "-a")
+ dockerCmd(c, "tag", "busybox", "utest:tag1")
+ dockerCmd(c, "tag", "busybox", "utest/docker:tag2")
+ dockerCmd(c, "tag", "busybox", "utest:5000/docker:tag3")
{
- imagesAfter, _, _ := dockerCmd(t, "images", "-a")
+ imagesAfter, _ := dockerCmd(c, "images", "-a")
if strings.Count(imagesAfter, "\n") != strings.Count(imagesBefore, "\n")+3 {
- t.Fatalf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)
+ c.Fatalf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)
}
}
- dockerCmd(t, "rmi", "utest/docker:tag2")
+ dockerCmd(c, "rmi", "utest/docker:tag2")
{
- imagesAfter, _, _ := dockerCmd(t, "images", "-a")
+ imagesAfter, _ := dockerCmd(c, "images", "-a")
if strings.Count(imagesAfter, "\n") != strings.Count(imagesBefore, "\n")+2 {
- t.Fatalf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)
+ c.Fatalf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)
}
}
- dockerCmd(t, "rmi", "utest:5000/docker:tag3")
+ dockerCmd(c, "rmi", "utest:5000/docker:tag3")
{
- imagesAfter, _, _ := dockerCmd(t, "images", "-a")
+ imagesAfter, _ := dockerCmd(c, "images", "-a")
if strings.Count(imagesAfter, "\n") != strings.Count(imagesBefore, "\n")+1 {
- t.Fatalf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)
+ c.Fatalf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)
}
}
- dockerCmd(t, "rmi", "utest:tag1")
+ dockerCmd(c, "rmi", "utest:tag1")
{
- imagesAfter, _, _ := dockerCmd(t, "images", "-a")
+ imagesAfter, _ := dockerCmd(c, "images", "-a")
if strings.Count(imagesAfter, "\n") != strings.Count(imagesBefore, "\n")+0 {
- t.Fatalf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)
+ c.Fatalf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)
+ }
+
+ }
+}
+
+func (s *DockerSuite) TestRmiImgIDForce(c *check.C) {
+ runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir '/busybox-test'")
+ out, _, err := runCommandWithOutput(runCmd)
+ if err != nil {
+ c.Fatalf("failed to create a container:%s, %v", out, err)
+ }
+ containerID := strings.TrimSpace(out)
+ runCmd = exec.Command(dockerBinary, "commit", containerID, "busybox-test")
+ out, _, err = runCommandWithOutput(runCmd)
+ if err != nil {
+ c.Fatalf("failed to commit a new busybox-test:%s, %v", out, err)
+ }
+
+ imagesBefore, _ := dockerCmd(c, "images", "-a")
+ dockerCmd(c, "tag", "busybox-test", "utest:tag1")
+ dockerCmd(c, "tag", "busybox-test", "utest:tag2")
+ dockerCmd(c, "tag", "busybox-test", "utest/docker:tag3")
+ dockerCmd(c, "tag", "busybox-test", "utest:5000/docker:tag4")
+ {
+ imagesAfter, _ := dockerCmd(c, "images", "-a")
+ if strings.Count(imagesAfter, "\n") != strings.Count(imagesBefore, "\n")+4 {
+ c.Fatalf("tag busybox to create 4 more images with same imageID; docker images shows: %q\n", imagesAfter)
+ }
+ }
+ out, _ = dockerCmd(c, "inspect", "-f", "{{.Id}}", "busybox-test")
+ imgID := strings.TrimSpace(out)
+
+ // first checkout without force it fails
+ runCmd = exec.Command(dockerBinary, "rmi", imgID)
+ out, _, err = runCommandWithOutput(runCmd)
+ if err == nil || !strings.Contains(out, fmt.Sprintf("Conflict, cannot delete image %s because it is tagged in multiple repositories, use -f to force", imgID)) {
+ c.Fatalf("rmi tagged in multiple repos should have failed without force:%s, %v", out, err)
+ }
+
+ dockerCmd(c, "rmi", "-f", imgID)
+ {
+ imagesAfter, _ := dockerCmd(c, "images", "-a")
+ if strings.Contains(imagesAfter, imgID[:12]) {
+ c.Fatalf("rmi -f %s failed, image still exists: %q\n\n", imgID, imagesAfter)
}
}
- logDone("rmi - tag,rmi - tagging the same images multiple times then removing tags")
}
-func TestRmiTagWithExistingContainers(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRmiTagWithExistingContainers(c *check.C) {
container := "test-delete-tag"
newtag := "busybox:newtag"
bb := "busybox:latest"
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "tag", bb, newtag)); err != nil {
- t.Fatalf("Could not tag busybox: %v: %s", err, out)
+ c.Fatalf("Could not tag busybox: %v: %s", err, out)
}
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--name", container, bb, "/bin/true")); err != nil {
- t.Fatalf("Could not run busybox: %v: %s", err, out)
+ c.Fatalf("Could not run busybox: %v: %s", err, out)
}
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "rmi", newtag))
if err != nil {
- t.Fatalf("Could not remove tag %s: %v: %s", newtag, err, out)
+ c.Fatalf("Could not remove tag %s: %v: %s", newtag, err, out)
}
if d := strings.Count(out, "Untagged: "); d != 1 {
- t.Fatalf("Expected 1 untagged entry got %d: %q", d, out)
+ c.Fatalf("Expected 1 untagged entry got %d: %q", d, out)
}
- logDone("rmi - delete tag with existing containers")
}
-func TestRmiForceWithExistingContainers(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRmiForceWithExistingContainers(c *check.C) {
image := "busybox-clone"
@@ -110,64 +151,60 @@ func TestRmiForceWithExistingContainers(t *testing.T) {
MAINTAINER foo`)
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatalf("Could not build %s: %s, %v", image, out, err)
+ c.Fatalf("Could not build %s: %s, %v", image, out, err)
}
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--name", "test-force-rmi", image, "/bin/true")); err != nil {
- t.Fatalf("Could not run container: %s, %v", out, err)
+ c.Fatalf("Could not run container: %s, %v", out, err)
}
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "rmi", "-f", image))
if err != nil {
- t.Fatalf("Could not remove image %s: %s, %v", image, out, err)
+ c.Fatalf("Could not remove image %s: %s, %v", image, out, err)
}
- logDone("rmi - force delete with existing containers")
}
-func TestRmiWithMultipleRepositories(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRmiWithMultipleRepositories(c *check.C) {
newRepo := "127.0.0.1:5000/busybox"
oldRepo := "busybox"
newTag := "busybox:test"
cmd := exec.Command(dockerBinary, "tag", oldRepo, newRepo)
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("Could not tag busybox: %v: %s", err, out)
+ c.Fatalf("Could not tag busybox: %v: %s", err, out)
}
cmd = exec.Command(dockerBinary, "run", "--name", "test", oldRepo, "touch", "/home/abcd")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %s", err, out)
+ c.Fatalf("failed to run container: %v, output: %s", err, out)
}
cmd = exec.Command(dockerBinary, "commit", "test", newTag)
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to commit container: %v, output: %s", err, out)
+ c.Fatalf("failed to commit container: %v, output: %s", err, out)
}
cmd = exec.Command(dockerBinary, "rmi", newTag)
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to remove image: %v, output: %s", err, out)
+ c.Fatalf("failed to remove image: %v, output: %s", err, out)
}
if !strings.Contains(out, "Untagged: "+newTag) {
- t.Fatalf("Could not remove image %s: %s, %v", newTag, out, err)
+ c.Fatalf("Could not remove image %s: %s, %v", newTag, out, err)
}
- logDone("rmi - delete a image which its dependency tagged to multiple repositories success")
}
-func TestRmiBlank(t *testing.T) {
+func (s *DockerSuite) TestRmiBlank(c *check.C) {
// try to delete a blank image name
runCmd := exec.Command(dockerBinary, "rmi", "")
out, _, err := runCommandWithOutput(runCmd)
if err == nil {
- t.Fatal("Should have failed to delete '' image")
+ c.Fatal("Should have failed to delete '' image")
}
if strings.Contains(out, "No such image") {
- t.Fatalf("Wrong error message generated: %s", out)
+ c.Fatalf("Wrong error message generated: %s", out)
}
- logDone("rmi - blank image name")
}
diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go
index a5d1e3e07024b..0cf5c31eeeac9 100644
--- a/integration-cli/docker_cli_run_test.go
+++ b/integration-cli/docker_cli_run_test.go
@@ -16,687 +16,593 @@ import (
"strconv"
"strings"
"sync"
- "testing"
"time"
"github.com/docker/docker/nat"
"github.com/docker/docker/pkg/resolvconf"
+ "github.com/go-check/check"
)
// "test123" should be printed by docker run
-func TestRunEchoStdout(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunEchoStdout(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "busybox", "echo", "test123")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
if out != "test123\n" {
- t.Errorf("container should've printed 'test123'")
+ c.Fatalf("container should've printed 'test123'")
}
-
- logDone("run - echo test123")
}
// "test" should be printed
-func TestRunEchoStdoutWithMemoryLimit(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunEchoStdoutWithMemoryLimit(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-m", "16m", "busybox", "echo", "test")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
out = strings.Trim(out, "\r\n")
if expected := "test"; out != expected {
- t.Errorf("container should've printed %q but printed %q", expected, out)
-
+ c.Fatalf("container should've printed %q but printed %q", expected, out)
}
-
- logDone("run - echo with memory limit")
}
// should run without memory swap
-func TestRunWithoutMemoryswapLimit(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunWithoutMemoryswapLimit(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-m", "16m", "--memory-swap", "-1", "busybox", "true")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("failed to run container, output: %q", out)
+ c.Fatalf("failed to run container, output: %q", out)
}
-
- logDone("run - without memory swap limit")
}
// "test" should be printed
-func TestRunEchoStdoutWitCPULimit(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunEchoStdoutWitCPULimit(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-c", "1000", "busybox", "echo", "test")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
if out != "test\n" {
- t.Errorf("container should've printed 'test'")
+ c.Errorf("container should've printed 'test'")
}
-
- logDone("run - echo with CPU limit")
}
// "test" should be printed
-func TestRunEchoStdoutWithCPUAndMemoryLimit(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunEchoStdoutWithCPUAndMemoryLimit(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-c", "1000", "-m", "16m", "busybox", "echo", "test")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
if out != "test\n" {
- t.Errorf("container should've printed 'test', got %q instead", out)
+ c.Errorf("container should've printed 'test', got %q instead", out)
}
-
- logDone("run - echo with CPU and memory limit")
}
// "test" should be printed
-func TestRunEchoNamedContainer(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunEchoStdoutWitCPUQuota(c *check.C) {
+ runCmd := exec.Command(dockerBinary, "run", "--cpu-quota", "8000", "--name", "test", "busybox", "echo", "test")
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ if err != nil {
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
+ }
+ out = strings.TrimSpace(out)
+ if strings.Contains(out, "Your kernel does not support CPU cfs quota") {
+ c.Skip("Your kernel does not support CPU cfs quota, skip this test")
+ }
+ if out != "test" {
+ c.Errorf("container should've printed 'test'")
+ }
+ cmd := exec.Command(dockerBinary, "inspect", "-f", "{{.HostConfig.CpuQuota}}", "test")
+ out, _, err = runCommandWithOutput(cmd)
+ if err != nil {
+ c.Fatalf("failed to inspect container: %s, %v", out, err)
+ }
+ out = strings.TrimSpace(out)
+ if out != "8000" {
+ c.Errorf("setting the CPU CFS quota failed")
+ }
+}
+
+// "test" should be printed
+func (s *DockerSuite) TestRunEchoNamedContainer(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "--name", "testfoonamedcontainer", "busybox", "echo", "test")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
if out != "test\n" {
- t.Errorf("container should've printed 'test'")
+ c.Errorf("container should've printed 'test'")
}
if err := deleteContainer("testfoonamedcontainer"); err != nil {
- t.Errorf("failed to remove the named container: %v", err)
+ c.Errorf("failed to remove the named container: %v", err)
}
-
- logDone("run - echo with named container")
}
// docker run should not leak file descriptors
-func TestRunLeakyFileDescriptors(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunLeakyFileDescriptors(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "busybox", "ls", "-C", "/proc/self/fd")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
// normally, we should only get 0, 1, and 2, but 3 gets created by "ls" when it does "opendir" on the "fd" directory
if out != "0 1 2 3\n" {
- t.Errorf("container should've printed '0 1 2 3', not: %s", out)
+ c.Errorf("container should've printed '0 1 2 3', not: %s", out)
}
-
- logDone("run - check file descriptor leakage")
}
// it should be possible to lookup Google DNS
// this will fail when Internet access is unavailable
-func TestRunLookupGoogleDns(t *testing.T) {
- testRequires(t, Network)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunLookupGoogleDns(c *check.C) {
+ testRequires(c, Network)
out, _, _, err := runCommandWithStdoutStderr(exec.Command(dockerBinary, "run", "busybox", "nslookup", "google.com"))
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
-
- logDone("run - nslookup google.com")
}
// the exit code should be 0
// some versions of lxc might make this test fail
-func TestRunExitCodeZero(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunExitCodeZero(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "busybox", "true")
if out, _, err := runCommandWithOutput(runCmd); err != nil {
- t.Errorf("container should've exited with exit code 0: %s, %v", out, err)
+ c.Errorf("container should've exited with exit code 0: %s, %v", out, err)
}
-
- logDone("run - exit with 0")
}
// the exit code should be 1
// some versions of lxc might make this test fail
-func TestRunExitCodeOne(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunExitCodeOne(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "busybox", "false")
exitCode, err := runCommand(runCmd)
if err != nil && !strings.Contains("exit status 1", fmt.Sprintf("%s", err)) {
- t.Fatal(err)
+ c.Fatal(err)
}
if exitCode != 1 {
- t.Errorf("container should've exited with exit code 1")
+ c.Errorf("container should've exited with exit code 1")
}
-
- logDone("run - exit with 1")
}
// it should be possible to pipe in data via stdin to a process running in a container
// some versions of lxc might make this test fail
-func TestRunStdinPipe(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunStdinPipe(c *check.C) {
runCmd := exec.Command("bash", "-c", `echo "blahblah" | docker run -i -a stdin busybox cat`)
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
out = strings.TrimSpace(out)
inspectCmd := exec.Command(dockerBinary, "inspect", out)
if out, _, err := runCommandWithOutput(inspectCmd); err != nil {
- t.Fatalf("out should've been a container id: %s %v", out, err)
+ c.Fatalf("out should've been a container id: %s %v", out, err)
}
waitCmd := exec.Command(dockerBinary, "wait", out)
if waitOut, _, err := runCommandWithOutput(waitCmd); err != nil {
- t.Fatalf("error thrown while waiting for container: %s, %v", waitOut, err)
+ c.Fatalf("error thrown while waiting for container: %s, %v", waitOut, err)
}
logsCmd := exec.Command(dockerBinary, "logs", out)
logsOut, _, err := runCommandWithOutput(logsCmd)
if err != nil {
- t.Fatalf("error thrown while trying to get container logs: %s, %v", logsOut, err)
+ c.Fatalf("error thrown while trying to get container logs: %s, %v", logsOut, err)
}
containerLogs := strings.TrimSpace(logsOut)
if containerLogs != "blahblah" {
- t.Errorf("logs didn't print the container's logs %s", containerLogs)
+ c.Errorf("logs didn't print the container's logs %s", containerLogs)
}
rmCmd := exec.Command(dockerBinary, "rm", out)
if out, _, err = runCommandWithOutput(rmCmd); err != nil {
- t.Fatalf("rm failed to remove container: %s, %v", out, err)
+ c.Fatalf("rm failed to remove container: %s, %v", out, err)
}
-
- logDone("run - pipe in with -i -a stdin")
}
// the container's ID should be printed when starting a container in detached mode
-func TestRunDetachedContainerIDPrinting(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunDetachedContainerIDPrinting(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
out = strings.TrimSpace(out)
inspectCmd := exec.Command(dockerBinary, "inspect", out)
if inspectOut, _, err := runCommandWithOutput(inspectCmd); err != nil {
- t.Fatalf("out should've been a container id: %s %v", inspectOut, err)
+ c.Fatalf("out should've been a container id: %s %v", inspectOut, err)
}
waitCmd := exec.Command(dockerBinary, "wait", out)
if waitOut, _, err := runCommandWithOutput(waitCmd); err != nil {
- t.Fatalf("error thrown while waiting for container: %s, %v", waitOut, err)
+ c.Fatalf("error thrown while waiting for container: %s, %v", waitOut, err)
}
rmCmd := exec.Command(dockerBinary, "rm", out)
rmOut, _, err := runCommandWithOutput(rmCmd)
if err != nil {
- t.Fatalf("rm failed to remove container: %s, %v", rmOut, err)
+ c.Fatalf("rm failed to remove container: %s, %v", rmOut, err)
}
rmOut = strings.TrimSpace(rmOut)
if rmOut != out {
- t.Errorf("rm didn't print the container ID %s %s", out, rmOut)
+ c.Errorf("rm didn't print the container ID %s %s", out, rmOut)
}
-
- logDone("run - print container ID in detached mode")
}
// the working directory should be set correctly
-func TestRunWorkingDirectory(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunWorkingDirectory(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-w", "/root", "busybox", "pwd")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
out = strings.TrimSpace(out)
if out != "/root" {
- t.Errorf("-w failed to set working directory")
+ c.Errorf("-w failed to set working directory")
}
runCmd = exec.Command(dockerBinary, "run", "--workdir", "/root", "busybox", "pwd")
out, _, _, err = runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
out = strings.TrimSpace(out)
if out != "/root" {
- t.Errorf("--workdir failed to set working directory")
+ c.Errorf("--workdir failed to set working directory")
}
-
- logDone("run - run with working directory set by -w/--workdir")
}
// pinging Google's DNS resolver should fail when we disable the networking
-func TestRunWithoutNetworking(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunWithoutNetworking(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "--net=none", "busybox", "ping", "-c", "1", "8.8.8.8")
out, _, exitCode, err := runCommandWithStdoutStderr(runCmd)
if err != nil && exitCode != 1 {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if exitCode != 1 {
- t.Errorf("--net=none should've disabled the network; the container shouldn't have been able to ping 8.8.8.8")
+ c.Errorf("--net=none should've disabled the network; the container shouldn't have been able to ping 8.8.8.8")
}
runCmd = exec.Command(dockerBinary, "run", "-n=false", "busybox", "ping", "-c", "1", "8.8.8.8")
out, _, exitCode, err = runCommandWithStdoutStderr(runCmd)
if err != nil && exitCode != 1 {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if exitCode != 1 {
- t.Errorf("-n=false should've disabled the network; the container shouldn't have been able to ping 8.8.8.8")
+ c.Errorf("-n=false should've disabled the network; the container shouldn't have been able to ping 8.8.8.8")
}
-
- logDone("run - disable networking with --net=none/-n=false")
}
//test --link use container name to link target
-func TestRunLinksContainerWithContainerName(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunLinksContainerWithContainerName(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-i", "-t", "-d", "--name", "parent", "busybox")
out, _, _, err := runCommandWithStdoutStderr(cmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
cmd = exec.Command(dockerBinary, "inspect", "-f", "{{.NetworkSettings.IPAddress}}", "parent")
ip, _, _, err := runCommandWithStdoutStderr(cmd)
if err != nil {
- t.Fatalf("failed to inspect container: %v, output: %q", err, ip)
+ c.Fatalf("failed to inspect container: %v, output: %q", err, ip)
}
ip = strings.TrimSpace(ip)
cmd = exec.Command(dockerBinary, "run", "--link", "parent:test", "busybox", "/bin/cat", "/etc/hosts")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
if !strings.Contains(out, ip+" test") {
- t.Fatalf("use a container name to link target failed")
+ c.Fatalf("use a container name to link target failed")
}
-
- logDone("run - use a container name to link target work")
}
//test --link use container id to link target
-func TestRunLinksContainerWithContainerId(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunLinksContainerWithContainerId(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-i", "-t", "-d", "busybox")
cID, _, _, err := runCommandWithStdoutStderr(cmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, cID)
+ c.Fatalf("failed to run container: %v, output: %q", err, cID)
}
cID = strings.TrimSpace(cID)
cmd = exec.Command(dockerBinary, "inspect", "-f", "{{.NetworkSettings.IPAddress}}", cID)
ip, _, _, err := runCommandWithStdoutStderr(cmd)
if err != nil {
- t.Fatalf("faild to inspect container: %v, output: %q", err, ip)
+ c.Fatalf("failed to inspect container: %v, output: %q", err, ip)
}
ip = strings.TrimSpace(ip)
cmd = exec.Command(dockerBinary, "run", "--link", cID+":test", "busybox", "/bin/cat", "/etc/hosts")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
if !strings.Contains(out, ip+" test") {
- t.Fatalf("use a container id to link target failed")
+ c.Fatalf("use a container id to link target failed")
}
-
- logDone("run - use a container id to link target work")
}
-func TestRunLinkToContainerNetMode(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunLinkToContainerNetMode(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--name", "test", "-d", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
cmd = exec.Command(dockerBinary, "run", "--name", "parent", "-d", "--net=container:test", "busybox", "top")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
cmd = exec.Command(dockerBinary, "run", "-d", "--link=parent:parent", "busybox", "top")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
cmd = exec.Command(dockerBinary, "run", "--name", "child", "-d", "--net=container:parent", "busybox", "top")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
cmd = exec.Command(dockerBinary, "run", "-d", "--link=child:child", "busybox", "top")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
-
- logDone("run - link to a container which net mode is container success")
}
-func TestRunModeNetContainerHostname(t *testing.T) {
- testRequires(t, ExecSupport)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunModeNetContainerHostname(c *check.C) {
+ testRequires(c, ExecSupport)
cmd := exec.Command(dockerBinary, "run", "-i", "-d", "--name", "parent", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
cmd = exec.Command(dockerBinary, "exec", "parent", "cat", "/etc/hostname")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to exec command: %v, output: %q", err, out)
+ c.Fatalf("failed to exec command: %v, output: %q", err, out)
}
cmd = exec.Command(dockerBinary, "run", "--net=container:parent", "busybox", "cat", "/etc/hostname")
out1, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out1)
+ c.Fatalf("failed to run container: %v, output: %q", err, out1)
}
if out1 != out {
- t.Fatal("containers with shared net namespace should have same hostname")
+ c.Fatal("containers with shared net namespace should have same hostname")
}
-
- logDone("run - containers with shared net namespace have same hostname")
}
// Regression test for #4741
-func TestRunWithVolumesAsFiles(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunWithVolumesAsFiles(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "--name", "test-data", "--volume", "/etc/hosts:/target-file", "busybox", "true")
out, stderr, exitCode, err := runCommandWithStdoutStderr(runCmd)
if err != nil && exitCode != 0 {
- t.Fatal("1", out, stderr, err)
+ c.Fatal("1", out, stderr, err)
}
runCmd = exec.Command(dockerBinary, "run", "--volumes-from", "test-data", "busybox", "cat", "/target-file")
out, stderr, exitCode, err = runCommandWithStdoutStderr(runCmd)
if err != nil && exitCode != 0 {
- t.Fatal("2", out, stderr, err)
+ c.Fatal("2", out, stderr, err)
}
-
- logDone("run - regression test for #4741 - volumes from as files")
}
// Regression test for #4979
-func TestRunWithVolumesFromExited(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunWithVolumesFromExited(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "--name", "test-data", "--volume", "/some/dir", "busybox", "touch", "/some/dir/file")
out, stderr, exitCode, err := runCommandWithStdoutStderr(runCmd)
if err != nil && exitCode != 0 {
- t.Fatal("1", out, stderr, err)
+ c.Fatal("1", out, stderr, err)
}
runCmd = exec.Command(dockerBinary, "run", "--volumes-from", "test-data", "busybox", "cat", "/some/dir/file")
out, stderr, exitCode, err = runCommandWithStdoutStderr(runCmd)
if err != nil && exitCode != 0 {
- t.Fatal("2", out, stderr, err)
+ c.Fatal("2", out, stderr, err)
}
-
- logDone("run - regression test for #4979 - volumes-from on exited container")
}
// Volume path is a symlink which also exists on the host, and the host side is a file not a dir
// But the volume call is just a normal volume, not a bind mount
-func TestRunCreateVolumesInSymlinkDir(t *testing.T) {
- testRequires(t, SameHostDaemon)
- testRequires(t, NativeExecDriver)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunCreateVolumesInSymlinkDir(c *check.C) {
+ testRequires(c, SameHostDaemon)
+ testRequires(c, NativeExecDriver)
name := "test-volume-symlink"
dir, err := ioutil.TempDir("", name)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(dir)
f, err := os.OpenFile(filepath.Join(dir, "test"), os.O_CREATE, 0700)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
f.Close()
dockerFile := fmt.Sprintf("FROM busybox\nRUN mkdir -p %s\nRUN ln -s %s /test", dir, dir)
if _, err := buildImage(name, dockerFile, false); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- defer deleteImages(name)
- if out, _, err := dockerCmd(t, "run", "-v", "/test/test", name); err != nil {
- t.Fatal(err, out)
+ out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-v", "/test/test", name))
+ if err != nil {
+ c.Fatalf("Failed with errors: %s, %v", out, err)
}
-
- logDone("run - create volume in symlink directory")
}
// Regression test for #4830
-func TestRunWithRelativePath(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunWithRelativePath(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-v", "tmp:/other-tmp", "busybox", "true")
if _, _, _, err := runCommandWithStdoutStderr(runCmd); err == nil {
- t.Fatalf("relative path should result in an error")
+ c.Fatalf("relative path should result in an error")
}
-
- logDone("run - volume with relative path")
}
-func TestRunVolumesMountedAsReadonly(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunVolumesMountedAsReadonly(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-v", "/test:/test:ro", "busybox", "touch", "/test/somefile")
if code, err := runCommand(cmd); err == nil || code == 0 {
- t.Fatalf("run should fail because volume is ro: exit code %d", code)
+ c.Fatalf("run should fail because volume is ro: exit code %d", code)
}
-
- logDone("run - volumes as readonly mount")
}
-func TestRunVolumesFromInReadonlyMode(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunVolumesFromInReadonlyMode(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--name", "parent", "-v", "/test", "busybox", "true")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent:ro", "busybox", "touch", "/test/file")
if code, err := runCommand(cmd); err == nil || code == 0 {
- t.Fatalf("run should fail because volume is ro: exit code %d", code)
+ c.Fatalf("run should fail because volume is ro: exit code %d", code)
}
-
- logDone("run - volumes from as readonly mount")
}
// Regression test for #1201
-func TestRunVolumesFromInReadWriteMode(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunVolumesFromInReadWriteMode(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--name", "parent", "-v", "/test", "busybox", "true")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent:rw", "busybox", "touch", "/test/file")
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatalf("running --volumes-from parent:rw failed with output: %q\nerror: %v", out, err)
+ c.Fatalf("running --volumes-from parent:rw failed with output: %q\nerror: %v", out, err)
}
cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent:bar", "busybox", "touch", "/test/file")
if out, _, err := runCommandWithOutput(cmd); err == nil || !strings.Contains(out, "invalid mode for volumes-from: bar") {
- t.Fatalf("running --volumes-from foo:bar should have failed with invalid mount mode: %q", out)
+ c.Fatalf("running --volumes-from foo:bar should have failed with invalid mount mode: %q", out)
}
cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent", "busybox", "touch", "/test/file")
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatalf("running --volumes-from parent failed with output: %q\nerror: %v", out, err)
+ c.Fatalf("running --volumes-from parent failed with output: %q\nerror: %v", out, err)
}
-
- logDone("run - volumes from as read write mount")
}
-func TestVolumesFromGetsProperMode(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestVolumesFromGetsProperMode(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--name", "parent", "-v", "/test:/test:ro", "busybox", "true")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- // Expect this "rw" mode to be be ignored since the inheritted volume is "ro"
+ // Expect this "rw" mode to be be ignored since the inherited volume is "ro"
cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent:rw", "busybox", "touch", "/test/file")
if _, err := runCommand(cmd); err == nil {
- t.Fatal("Expected volumes-from to inherit read-only volume even when passing in `rw`")
+ c.Fatal("Expected volumes-from to inherit read-only volume even when passing in `rw`")
}
cmd = exec.Command(dockerBinary, "run", "--name", "parent2", "-v", "/test:/test:ro", "busybox", "true")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// Expect this to be read-only since both are "ro"
cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent2:ro", "busybox", "touch", "/test/file")
if _, err := runCommand(cmd); err == nil {
- t.Fatal("Expected volumes-from to inherit read-only volume even when passing in `ro`")
+ c.Fatal("Expected volumes-from to inherit read-only volume even when passing in `ro`")
}
-
- logDone("run - volumes from ignores `rw` if inherrited volume is `ro`")
}
// Test for GH#10618
-func TestRunNoDupVolumes(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunNoDupVolumes(c *check.C) {
mountstr1 := randomUnixTmpDirPath("test1") + ":/someplace"
mountstr2 := randomUnixTmpDirPath("test2") + ":/someplace"
cmd := exec.Command(dockerBinary, "run", "-v", mountstr1, "-v", mountstr2, "busybox", "true")
if out, _, err := runCommandWithOutput(cmd); err == nil {
- t.Fatal("Expected error about duplicate volume definitions")
+ c.Fatal("Expected error about duplicate volume definitions")
} else {
if !strings.Contains(out, "Duplicate volume") {
- t.Fatalf("Expected 'duplicate volume' error, got %v", err)
+ c.Fatalf("Expected 'duplicate volume' error, got %v", err)
}
}
-
- logDone("run - don't allow multiple (bind) volumes on the same container target")
}
// Test for #1351
-func TestRunApplyVolumesFromBeforeVolumes(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunApplyVolumesFromBeforeVolumes(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--name", "parent", "-v", "/test", "busybox", "touch", "/test/foo")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent", "-v", "/test", "busybox", "cat", "/test/foo")
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
-
- logDone("run - volumes from mounted first")
}
-func TestRunMultipleVolumesFrom(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunMultipleVolumesFrom(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--name", "parent1", "-v", "/test", "busybox", "touch", "/test/foo")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "run", "--name", "parent2", "-v", "/other", "busybox", "touch", "/other/bar")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent1", "--volumes-from", "parent2",
"busybox", "sh", "-c", "cat /test/foo && cat /other/bar")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
-
- logDone("run - multiple volumes from")
}
// this tests verifies the ID format for the container
-func TestRunVerifyContainerID(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunVerifyContainerID(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
out, exit, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if exit != 0 {
- t.Fatalf("expected exit code 0 received %d", exit)
+ c.Fatalf("expected exit code 0 received %d", exit)
}
match, err := regexp.MatchString("^[0-9a-f]{64}$", strings.TrimSuffix(out, "\n"))
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !match {
- t.Fatalf("Invalid container ID: %s", out)
+ c.Fatalf("Invalid container ID: %s", out)
}
-
- logDone("run - verify container ID")
}
// Test that creating a container with a volume doesn't crash. Regression test for #995.
-func TestRunCreateVolume(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunCreateVolume(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-v", "/var/lib/data", "busybox", "true")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
-
- logDone("run - create docker managed volume")
}
// Test that creating a volume with a symlink in its path works correctly. Test for #5152.
// Note that this bug happens only with symlinks with a target that starts with '/'.
-func TestRunCreateVolumeWithSymlink(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunCreateVolumeWithSymlink(c *check.C) {
image := "docker-test-createvolumewithsymlink"
- defer deleteImages(image)
buildCmd := exec.Command(dockerBinary, "build", "-t", image, "-")
buildCmd.Stdin = strings.NewReader(`FROM busybox
@@ -704,43 +610,38 @@ func TestRunCreateVolumeWithSymlink(t *testing.T) {
buildCmd.Dir = workingDirectory
err := buildCmd.Run()
if err != nil {
- t.Fatalf("could not build '%s': %v", image, err)
+ c.Fatalf("could not build '%s': %v", image, err)
}
cmd := exec.Command(dockerBinary, "run", "-v", "/bar/foo", "--name", "test-createvolumewithsymlink", image, "sh", "-c", "mount | grep -q /home/foo")
exitCode, err := runCommand(cmd)
if err != nil || exitCode != 0 {
- t.Fatalf("[run] err: %v, exitcode: %d", err, exitCode)
+ c.Fatalf("[run] err: %v, exitcode: %d", err, exitCode)
}
var volPath string
cmd = exec.Command(dockerBinary, "inspect", "-f", "{{range .Volumes}}{{.}}{{end}}", "test-createvolumewithsymlink")
volPath, exitCode, err = runCommandWithOutput(cmd)
if err != nil || exitCode != 0 {
- t.Fatalf("[inspect] err: %v, exitcode: %d", err, exitCode)
+ c.Fatalf("[inspect] err: %v, exitcode: %d", err, exitCode)
}
cmd = exec.Command(dockerBinary, "rm", "-v", "test-createvolumewithsymlink")
exitCode, err = runCommand(cmd)
if err != nil || exitCode != 0 {
- t.Fatalf("[rm] err: %v, exitcode: %d", err, exitCode)
+ c.Fatalf("[rm] err: %v, exitcode: %d", err, exitCode)
}
f, err := os.Open(volPath)
defer f.Close()
if !os.IsNotExist(err) {
- t.Fatalf("[open] (expecting 'file does not exist' error) err: %v, volPath: %s", err, volPath)
+ c.Fatalf("[open] (expecting 'file does not exist' error) err: %v, volPath: %s", err, volPath)
}
-
- logDone("run - create volume with symlink")
}
// Tests that a volume path that has a symlink exists in a container mounting it with `--volumes-from`.
-func TestRunVolumesFromSymlinkPath(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunVolumesFromSymlinkPath(c *check.C) {
name := "docker-test-volumesfromsymlinkpath"
- defer deleteImages(name)
buildCmd := exec.Command(dockerBinary, "build", "-t", name, "-")
buildCmd.Stdin = strings.NewReader(`FROM busybox
@@ -749,166 +650,131 @@ func TestRunVolumesFromSymlinkPath(t *testing.T) {
buildCmd.Dir = workingDirectory
err := buildCmd.Run()
if err != nil {
- t.Fatalf("could not build 'docker-test-volumesfromsymlinkpath': %v", err)
+ c.Fatalf("could not build 'docker-test-volumesfromsymlinkpath': %v", err)
}
cmd := exec.Command(dockerBinary, "run", "--name", "test-volumesfromsymlinkpath", name)
exitCode, err := runCommand(cmd)
if err != nil || exitCode != 0 {
- t.Fatalf("[run] (volume) err: %v, exitcode: %d", err, exitCode)
+ c.Fatalf("[run] (volume) err: %v, exitcode: %d", err, exitCode)
}
cmd = exec.Command(dockerBinary, "run", "--volumes-from", "test-volumesfromsymlinkpath", "busybox", "sh", "-c", "ls /foo | grep -q bar")
exitCode, err = runCommand(cmd)
if err != nil || exitCode != 0 {
- t.Fatalf("[run] err: %v, exitcode: %d", err, exitCode)
+ c.Fatalf("[run] err: %v, exitcode: %d", err, exitCode)
}
-
- logDone("run - volumes-from symlink path")
}
-func TestRunExitCode(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunExitCode(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "busybox", "/bin/sh", "-c", "exit 72")
exit, err := runCommand(cmd)
if err == nil {
- t.Fatal("should not have a non nil error")
+ c.Fatal("should not have a non nil error")
}
if exit != 72 {
- t.Fatalf("expected exit code 72 received %d", exit)
+ c.Fatalf("expected exit code 72 received %d", exit)
}
-
- logDone("run - correct exit code")
}
-func TestRunUserDefaultsToRoot(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunUserDefaultsToRoot(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "busybox", "id")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if !strings.Contains(out, "uid=0(root) gid=0(root)") {
- t.Fatalf("expected root user got %s", out)
+ c.Fatalf("expected root user got %s", out)
}
-
- logDone("run - default user")
}
-func TestRunUserByName(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunUserByName(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-u", "root", "busybox", "id")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if !strings.Contains(out, "uid=0(root) gid=0(root)") {
- t.Fatalf("expected root user got %s", out)
+ c.Fatalf("expected root user got %s", out)
}
-
- logDone("run - user by name")
}
-func TestRunUserByID(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunUserByID(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-u", "1", "busybox", "id")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if !strings.Contains(out, "uid=1(daemon) gid=1(daemon)") {
- t.Fatalf("expected daemon user got %s", out)
+ c.Fatalf("expected daemon user got %s", out)
}
-
- logDone("run - user by id")
}
-func TestRunUserByIDBig(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunUserByIDBig(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-u", "2147483648", "busybox", "id")
out, _, err := runCommandWithOutput(cmd)
if err == nil {
- t.Fatal("No error, but must be.", out)
+ c.Fatal("No error, but must be.", out)
}
if !strings.Contains(out, "Uids and gids must be in range") {
- t.Fatalf("expected error about uids range, got %s", out)
+ c.Fatalf("expected error about uids range, got %s", out)
}
-
- logDone("run - user by id, id too big")
}
-func TestRunUserByIDNegative(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunUserByIDNegative(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-u", "-1", "busybox", "id")
out, _, err := runCommandWithOutput(cmd)
if err == nil {
- t.Fatal("No error, but must be.", out)
+ c.Fatal("No error, but must be.", out)
}
if !strings.Contains(out, "Uids and gids must be in range") {
- t.Fatalf("expected error about uids range, got %s", out)
+ c.Fatalf("expected error about uids range, got %s", out)
}
-
- logDone("run - user by id, id negative")
}
-func TestRunUserByIDZero(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunUserByIDZero(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-u", "0", "busybox", "id")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if !strings.Contains(out, "uid=0(root) gid=0(root) groups=10(wheel)") {
- t.Fatalf("expected daemon user got %s", out)
+ c.Fatalf("expected daemon user got %s", out)
}
-
- logDone("run - user by id, zero uid")
}
-func TestRunUserNotFound(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunUserNotFound(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-u", "notme", "busybox", "id")
_, err := runCommand(cmd)
if err == nil {
- t.Fatal("unknown user should cause container to fail")
+ c.Fatal("unknown user should cause container to fail")
}
-
- logDone("run - user not found")
}
-func TestRunTwoConcurrentContainers(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunTwoConcurrentContainers(c *check.C) {
group := sync.WaitGroup{}
group.Add(2)
+ errChan := make(chan error, 2)
for i := 0; i < 2; i++ {
go func() {
defer group.Done()
cmd := exec.Command(dockerBinary, "run", "busybox", "sleep", "2")
- if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
- }
+ _, err := runCommand(cmd)
+ errChan <- err
}()
}
group.Wait()
+ close(errChan)
- logDone("run - two concurrent containers")
+ for err := range errChan {
+ c.Assert(err, check.IsNil)
+ }
}
-func TestRunEnvironment(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunEnvironment(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-h", "testing", "-e=FALSE=true", "-e=TRUE", "-e=TRICKY", "-e=HOME=", "busybox", "env")
cmd.Env = append(os.Environ(),
"TRUE=false",
@@ -917,7 +783,7 @@ func TestRunEnvironment(t *testing.T) {
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
actualEnvLxc := strings.Split(strings.TrimSpace(out), "\n")
@@ -941,29 +807,26 @@ func TestRunEnvironment(t *testing.T) {
}
sort.Strings(goodEnv)
if len(goodEnv) != len(actualEnv) {
- t.Fatalf("Wrong environment: should be %d variables, not: %q\n", len(goodEnv), strings.Join(actualEnv, ", "))
+ c.Fatalf("Wrong environment: should be %d variables, not: %q\n", len(goodEnv), strings.Join(actualEnv, ", "))
}
for i := range goodEnv {
if actualEnv[i] != goodEnv[i] {
- t.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i])
+ c.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i])
}
}
-
- logDone("run - verify environment")
}
-func TestRunEnvironmentErase(t *testing.T) {
+func (s *DockerSuite) TestRunEnvironmentErase(c *check.C) {
// Test to make sure that when we use -e on env vars that are
// not set in our local env that they're removed (if present) in
// the container
- defer deleteAllContainers()
cmd := exec.Command(dockerBinary, "run", "-e", "FOO", "-e", "HOSTNAME", "busybox", "env")
cmd.Env = appendBaseEnv([]string{})
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
actualEnvLxc := strings.Split(strings.TrimSpace(out), "\n")
@@ -981,28 +844,25 @@ func TestRunEnvironmentErase(t *testing.T) {
}
sort.Strings(goodEnv)
if len(goodEnv) != len(actualEnv) {
- t.Fatalf("Wrong environment: should be %d variables, not: %q\n", len(goodEnv), strings.Join(actualEnv, ", "))
+ c.Fatalf("Wrong environment: should be %d variables, not: %q\n", len(goodEnv), strings.Join(actualEnv, ", "))
}
for i := range goodEnv {
if actualEnv[i] != goodEnv[i] {
- t.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i])
+ c.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i])
}
}
-
- logDone("run - verify environment erase")
}
-func TestRunEnvironmentOverride(t *testing.T) {
+func (s *DockerSuite) TestRunEnvironmentOverride(c *check.C) {
// Test to make sure that when we use -e on env vars that are
// already in the env that we're overriding them
- defer deleteAllContainers()
cmd := exec.Command(dockerBinary, "run", "-e", "HOSTNAME", "-e", "HOME=/root2", "busybox", "env")
cmd.Env = appendBaseEnv([]string{"HOSTNAME=bar"})
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
actualEnvLxc := strings.Split(strings.TrimSpace(out), "\n")
@@ -1021,60 +881,47 @@ func TestRunEnvironmentOverride(t *testing.T) {
}
sort.Strings(goodEnv)
if len(goodEnv) != len(actualEnv) {
- t.Fatalf("Wrong environment: should be %d variables, not: %q\n", len(goodEnv), strings.Join(actualEnv, ", "))
+ c.Fatalf("Wrong environment: should be %d variables, not: %q\n", len(goodEnv), strings.Join(actualEnv, ", "))
}
for i := range goodEnv {
if actualEnv[i] != goodEnv[i] {
- t.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i])
+ c.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i])
}
}
-
- logDone("run - verify environment override")
}
-func TestRunContainerNetwork(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunContainerNetwork(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "busybox", "ping", "-c", "1", "127.0.0.1")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
-
- logDone("run - test container network via ping")
}
// Issue #4681
-func TestRunLoopbackWhenNetworkDisabled(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunLoopbackWhenNetworkDisabled(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--net=none", "busybox", "ping", "-c", "1", "127.0.0.1")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
-
- logDone("run - test container loopback when networking disabled")
}
-func TestRunNetHostNotAllowedWithLinks(t *testing.T) {
- defer deleteAllContainers()
-
- _, _, err := dockerCmd(t, "run", "--name", "linked", "busybox", "true")
+func (s *DockerSuite) TestRunNetHostNotAllowedWithLinks(c *check.C) {
+ out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--name", "linked", "busybox", "true"))
+ if err != nil {
+ c.Fatalf("Failed with errors: %s, %v", out, err)
+ }
cmd := exec.Command(dockerBinary, "run", "--net=host", "--link", "linked:linked", "busybox", "true")
_, _, err = runCommandWithOutput(cmd)
if err == nil {
- t.Fatal("Expected error")
+ c.Fatal("Expected error")
}
-
- logDone("run - don't allow --net=host to be used with links")
}
-func TestRunLoopbackOnlyExistsWhenNetworkingDisabled(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunLoopbackOnlyExistsWhenNetworkingDisabled(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--net=none", "busybox", "ip", "-o", "-4", "a", "show", "up")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
var (
@@ -1089,14 +936,12 @@ func TestRunLoopbackOnlyExistsWhenNetworkingDisabled(t *testing.T) {
}
if count != 1 {
- t.Fatalf("Wrong interface count in container %d", count)
+ c.Fatalf("Wrong interface count in container %d", count)
}
if !strings.HasPrefix(out, "1: lo") {
- t.Fatalf("Wrong interface in test container: expected [1: lo], got %s", out)
+ c.Fatalf("Wrong interface in test container: expected [1: lo], got %s", out)
}
-
- logDone("run - test loopback only exists when networking disabled")
}
// #7851 hostname outside container shows FQDN, inside only shortname
@@ -1104,293 +949,220 @@ func TestRunLoopbackOnlyExistsWhenNetworkingDisabled(t *testing.T) {
// and use "--net=host" (as the original issue submitter did), as the same
// codepath is executed with "docker run -h ". Both were manually
// tested, but this testcase takes the simpler path of using "run -h .."
-func TestRunFullHostnameSet(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunFullHostnameSet(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-h", "foo.bar.baz", "busybox", "hostname")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actual := strings.Trim(out, "\r\n"); actual != "foo.bar.baz" {
- t.Fatalf("expected hostname 'foo.bar.baz', received %s", actual)
+ c.Fatalf("expected hostname 'foo.bar.baz', received %s", actual)
}
-
- logDone("run - test fully qualified hostname set with -h")
}
-func TestRunPrivilegedCanMknod(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunPrivilegedCanMknod(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--privileged", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if actual := strings.Trim(out, "\r\n"); actual != "ok" {
- t.Fatalf("expected output ok received %s", actual)
+ c.Fatalf("expected output ok received %s", actual)
}
-
- logDone("run - test privileged can mknod")
}
-func TestRunUnPrivilegedCanMknod(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunUnPrivilegedCanMknod(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if actual := strings.Trim(out, "\r\n"); actual != "ok" {
- t.Fatalf("expected output ok received %s", actual)
+ c.Fatalf("expected output ok received %s", actual)
}
-
- logDone("run - test un-privileged can mknod")
}
-func TestRunCapDropInvalid(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunCapDropInvalid(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--cap-drop=CHPASS", "busybox", "ls")
out, _, err := runCommandWithOutput(cmd)
if err == nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
-
- logDone("run - test --cap-drop=CHPASS invalid")
}
-func TestRunCapDropCannotMknod(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunCapDropCannotMknod(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--cap-drop=MKNOD", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
out, _, err := runCommandWithOutput(cmd)
if err == nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actual := strings.Trim(out, "\r\n"); actual == "ok" {
- t.Fatalf("expected output not ok received %s", actual)
+ c.Fatalf("expected output not ok received %s", actual)
}
-
- logDone("run - test --cap-drop=MKNOD cannot mknod")
}
-func TestRunCapDropCannotMknodLowerCase(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunCapDropCannotMknodLowerCase(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--cap-drop=mknod", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
out, _, err := runCommandWithOutput(cmd)
if err == nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actual := strings.Trim(out, "\r\n"); actual == "ok" {
- t.Fatalf("expected output not ok received %s", actual)
+ c.Fatalf("expected output not ok received %s", actual)
}
-
- logDone("run - test --cap-drop=mknod cannot mknod lowercase")
}
-func TestRunCapDropALLCannotMknod(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunCapDropALLCannotMknod(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--cap-drop=ALL", "--cap-add=SETGID", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
out, _, err := runCommandWithOutput(cmd)
if err == nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actual := strings.Trim(out, "\r\n"); actual == "ok" {
- t.Fatalf("expected output not ok received %s", actual)
+ c.Fatalf("expected output not ok received %s", actual)
}
-
- logDone("run - test --cap-drop=ALL cannot mknod")
}
-func TestRunCapDropALLAddMknodCanMknod(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunCapDropALLAddMknodCanMknod(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--cap-drop=ALL", "--cap-add=MKNOD", "--cap-add=SETGID", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actual := strings.Trim(out, "\r\n"); actual != "ok" {
- t.Fatalf("expected output ok received %s", actual)
+ c.Fatalf("expected output ok received %s", actual)
}
-
- logDone("run - test --cap-drop=ALL --cap-add=MKNOD can mknod")
}
-func TestRunCapAddInvalid(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunCapAddInvalid(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--cap-add=CHPASS", "busybox", "ls")
out, _, err := runCommandWithOutput(cmd)
if err == nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
-
- logDone("run - test --cap-add=CHPASS invalid")
}
-func TestRunCapAddCanDownInterface(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunCapAddCanDownInterface(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--cap-add=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actual := strings.Trim(out, "\r\n"); actual != "ok" {
- t.Fatalf("expected output ok received %s", actual)
+ c.Fatalf("expected output ok received %s", actual)
}
-
- logDone("run - test --cap-add=NET_ADMIN can set eth0 down")
}
-func TestRunCapAddALLCanDownInterface(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunCapAddALLCanDownInterface(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--cap-add=ALL", "busybox", "sh", "-c", "ip link set eth0 down && echo ok")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actual := strings.Trim(out, "\r\n"); actual != "ok" {
- t.Fatalf("expected output ok received %s", actual)
+ c.Fatalf("expected output ok received %s", actual)
}
-
- logDone("run - test --cap-add=ALL can set eth0 down")
}
-func TestRunCapAddALLDropNetAdminCanDownInterface(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunCapAddALLDropNetAdminCanDownInterface(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--cap-add=ALL", "--cap-drop=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok")
out, _, err := runCommandWithOutput(cmd)
if err == nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actual := strings.Trim(out, "\r\n"); actual == "ok" {
- t.Fatalf("expected output not ok received %s", actual)
+ c.Fatalf("expected output not ok received %s", actual)
}
-
- logDone("run - test --cap-add=ALL --cap-drop=NET_ADMIN cannot set eth0 down")
}
-func TestRunPrivilegedCanMount(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunPrivilegedCanMount(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--privileged", "busybox", "sh", "-c", "mount -t tmpfs none /tmp && echo ok")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if actual := strings.Trim(out, "\r\n"); actual != "ok" {
- t.Fatalf("expected output ok received %s", actual)
+ c.Fatalf("expected output ok received %s", actual)
}
-
- logDone("run - test privileged can mount")
}
-func TestRunUnPrivilegedCannotMount(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunUnPrivilegedCannotMount(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "mount -t tmpfs none /tmp && echo ok")
out, _, err := runCommandWithOutput(cmd)
if err == nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actual := strings.Trim(out, "\r\n"); actual == "ok" {
- t.Fatalf("expected output not ok received %s", actual)
+ c.Fatalf("expected output not ok received %s", actual)
}
-
- logDone("run - test un-privileged cannot mount")
}
-func TestRunSysNotWritableInNonPrivilegedContainers(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunSysNotWritableInNonPrivilegedContainers(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "busybox", "touch", "/sys/kernel/profiling")
if code, err := runCommand(cmd); err == nil || code == 0 {
- t.Fatal("sys should not be writable in a non privileged container")
+ c.Fatal("sys should not be writable in a non privileged container")
}
-
- logDone("run - sys not writable in non privileged container")
}
-func TestRunSysWritableInPrivilegedContainers(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunSysWritableInPrivilegedContainers(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--privileged", "busybox", "touch", "/sys/kernel/profiling")
if code, err := runCommand(cmd); err != nil || code != 0 {
- t.Fatalf("sys should be writable in privileged container")
+ c.Fatalf("sys should be writable in privileged container")
}
-
- logDone("run - sys writable in privileged container")
}
-func TestRunProcNotWritableInNonPrivilegedContainers(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunProcNotWritableInNonPrivilegedContainers(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "busybox", "touch", "/proc/sysrq-trigger")
if code, err := runCommand(cmd); err == nil || code == 0 {
- t.Fatal("proc should not be writable in a non privileged container")
+ c.Fatal("proc should not be writable in a non privileged container")
}
-
- logDone("run - proc not writable in non privileged container")
}
-func TestRunProcWritableInPrivilegedContainers(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunProcWritableInPrivilegedContainers(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--privileged", "busybox", "touch", "/proc/sysrq-trigger")
if code, err := runCommand(cmd); err != nil || code != 0 {
- t.Fatalf("proc should be writable in privileged container")
+ c.Fatalf("proc should be writable in privileged container")
}
- logDone("run - proc writable in privileged container")
}
-func TestRunWithCpuset(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunWithCpuset(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--cpuset", "0", "busybox", "true")
if code, err := runCommand(cmd); err != nil || code != 0 {
- t.Fatalf("container should run successfuly with cpuset of 0: %s", err)
+ c.Fatalf("container should run successfully with cpuset of 0: %s", err)
}
-
- logDone("run - cpuset 0")
}
-func TestRunWithCpusetCpus(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunWithCpusetCpus(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--cpuset-cpus", "0", "busybox", "true")
if code, err := runCommand(cmd); err != nil || code != 0 {
- t.Fatalf("container should run successfuly with cpuset-cpus of 0: %s", err)
+ c.Fatalf("container should run successfully with cpuset-cpus of 0: %s", err)
}
-
- logDone("run - cpuset-cpus 0")
}
-func TestRunDeviceNumbers(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunWithCpusetMems(c *check.C) {
+ cmd := exec.Command(dockerBinary, "run", "--cpuset-mems", "0", "busybox", "true")
+ if code, err := runCommand(cmd); err != nil || code != 0 {
+ c.Fatalf("container should run successfully with cpuset-mems of 0: %s", err)
+ }
+}
+func (s *DockerSuite) TestRunDeviceNumbers(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "ls -l /dev/null")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
deviceLineFields := strings.Fields(out)
deviceLineFields[6] = ""
@@ -1399,137 +1171,107 @@ func TestRunDeviceNumbers(t *testing.T) {
expected := []string{"crw-rw-rw-", "1", "root", "root", "1,", "3", "", "", "", "/dev/null"}
if !(reflect.DeepEqual(deviceLineFields, expected)) {
- t.Fatalf("expected output\ncrw-rw-rw- 1 root root 1, 3 May 24 13:29 /dev/null\n received\n %s\n", out)
+ c.Fatalf("expected output\ncrw-rw-rw- 1 root root 1, 3 May 24 13:29 /dev/null\n received\n %s\n", out)
}
-
- logDone("run - test device numbers")
}
-func TestRunThatCharacterDevicesActLikeCharacterDevices(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunThatCharacterDevicesActLikeCharacterDevices(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "dd if=/dev/zero of=/zero bs=1k count=5 2> /dev/null ; du -h /zero")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actual := strings.Trim(out, "\r\n"); actual[0] == '0' {
- t.Fatalf("expected a new file called /zero to be create that is greater than 0 bytes long, but du says: %s", actual)
+ c.Fatalf("expected a new file called /zero to be create that is greater than 0 bytes long, but du says: %s", actual)
}
-
- logDone("run - test that character devices work.")
}
-func TestRunUnprivilegedWithChroot(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunUnprivilegedWithChroot(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "busybox", "chroot", "/", "true")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
-
- logDone("run - unprivileged with chroot")
}
-func TestRunAddingOptionalDevices(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunAddingOptionalDevices(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--device", "/dev/zero:/dev/nulo", "busybox", "sh", "-c", "ls /dev/nulo")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actual := strings.Trim(out, "\r\n"); actual != "/dev/nulo" {
- t.Fatalf("expected output /dev/nulo, received %s", actual)
+ c.Fatalf("expected output /dev/nulo, received %s", actual)
}
-
- logDone("run - test --device argument")
}
-func TestRunModeHostname(t *testing.T) {
- testRequires(t, SameHostDaemon)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunModeHostname(c *check.C) {
+ testRequires(c, SameHostDaemon)
cmd := exec.Command(dockerBinary, "run", "-h=testhostname", "busybox", "cat", "/etc/hostname")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actual := strings.Trim(out, "\r\n"); actual != "testhostname" {
- t.Fatalf("expected 'testhostname', but says: %q", actual)
+ c.Fatalf("expected 'testhostname', but says: %q", actual)
}
cmd = exec.Command(dockerBinary, "run", "--net=host", "busybox", "cat", "/etc/hostname")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
hostname, err := os.Hostname()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if actual := strings.Trim(out, "\r\n"); actual != hostname {
- t.Fatalf("expected %q, but says: %q", hostname, actual)
+ c.Fatalf("expected %q, but says: %q", hostname, actual)
}
-
- logDone("run - hostname and several network modes")
}
-func TestRunRootWorkdir(t *testing.T) {
- defer deleteAllContainers()
-
- s, _, err := dockerCmd(t, "run", "--workdir", "/", "busybox", "pwd")
+func (s *DockerSuite) TestRunRootWorkdir(c *check.C) {
+ out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--workdir", "/", "busybox", "pwd"))
if err != nil {
- t.Fatal(s, err)
+ c.Fatalf("Failed with errors: %s, %v", out, err)
}
- if s != "/\n" {
- t.Fatalf("pwd returned %q (expected /\\n)", s)
+ if out != "/\n" {
+ c.Fatalf("pwd returned %q (expected /\\n)", s)
}
-
- logDone("run - workdir /")
}
-func TestRunAllowBindMountingRoot(t *testing.T) {
- defer deleteAllContainers()
-
- s, _, err := dockerCmd(t, "run", "-v", "/:/host", "busybox", "ls", "/host")
+func (s *DockerSuite) TestRunAllowBindMountingRoot(c *check.C) {
+ out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-v", "/:/host", "busybox", "ls", "/host"))
if err != nil {
- t.Fatal(s, err)
+ c.Fatalf("Failed with errors: %s, %v", out, err)
}
-
- logDone("run - bind mount / as volume")
}
-func TestRunDisallowBindMountingRootToRoot(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunDisallowBindMountingRootToRoot(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-v", "/:/", "busybox", "ls", "/host")
out, _, err := runCommandWithOutput(cmd)
if err == nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
-
- logDone("run - bind mount /:/ as volume should not work")
}
// Verify that a container gets default DNS when only localhost resolvers exist
-func TestRunDnsDefaultOptions(t *testing.T) {
- defer deleteAllContainers()
- testRequires(t, SameHostDaemon)
+func (s *DockerSuite) TestRunDnsDefaultOptions(c *check.C) {
+ testRequires(c, SameHostDaemon)
// preserve original resolv.conf for restoring after test
origResolvConf, err := ioutil.ReadFile("/etc/resolv.conf")
if os.IsNotExist(err) {
- t.Fatalf("/etc/resolv.conf does not exist")
+ c.Fatalf("/etc/resolv.conf does not exist")
}
// defer restored original conf
defer func() {
if err := ioutil.WriteFile("/etc/resolv.conf", origResolvConf, 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
}()
@@ -1538,14 +1280,14 @@ func TestRunDnsDefaultOptions(t *testing.T) {
// GetNameservers(), leading to a replacement of nameservers with the default set
tmpResolvConf := []byte("nameserver 127.0.0.1\n#nameserver 127.0.2.1\nnameserver ::1")
if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd := exec.Command(dockerBinary, "run", "busybox", "cat", "/etc/resolv.conf")
actual, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, actual)
+ c.Fatal(err, actual)
}
// check that the actual defaults are appended to the commented out
@@ -1553,54 +1295,47 @@ func TestRunDnsDefaultOptions(t *testing.T) {
// NOTE: if we ever change the defaults from google dns, this will break
expected := "#nameserver 127.0.2.1\n\nnameserver 8.8.8.8\nnameserver 8.8.4.4"
if actual != expected {
- t.Fatalf("expected resolv.conf be: %q, but was: %q", expected, actual)
+ c.Fatalf("expected resolv.conf be: %q, but was: %q", expected, actual)
}
-
- logDone("run - dns default options")
}
-func TestRunDnsOptions(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunDnsOptions(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--dns=127.0.0.1", "--dns-search=mydomain", "busybox", "cat", "/etc/resolv.conf")
out, stderr, _, err := runCommandWithStdoutStderr(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
// The client will get a warning on stderr when setting DNS to a localhost address; verify this:
if !strings.Contains(stderr, "Localhost DNS setting") {
- t.Fatalf("Expected warning on stderr about localhost resolver, but got %q", stderr)
+ c.Fatalf("Expected warning on stderr about localhost resolver, but got %q", stderr)
}
actual := strings.Replace(strings.Trim(out, "\r\n"), "\n", " ", -1)
if actual != "nameserver 127.0.0.1 search mydomain" {
- t.Fatalf("expected 'nameserver 127.0.0.1 search mydomain', but says: %q", actual)
+ c.Fatalf("expected 'nameserver 127.0.0.1 search mydomain', but says: %q", actual)
}
cmd = exec.Command(dockerBinary, "run", "--dns=127.0.0.1", "--dns-search=.", "busybox", "cat", "/etc/resolv.conf")
out, _, _, err = runCommandWithStdoutStderr(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
actual = strings.Replace(strings.Trim(strings.Trim(out, "\r\n"), " "), "\n", " ", -1)
if actual != "nameserver 127.0.0.1" {
- t.Fatalf("expected 'nameserver 127.0.0.1', but says: %q", actual)
+ c.Fatalf("expected 'nameserver 127.0.0.1', but says: %q", actual)
}
-
- logDone("run - dns options")
}
-func TestRunDnsOptionsBasedOnHostResolvConf(t *testing.T) {
- defer deleteAllContainers()
- testRequires(t, SameHostDaemon)
+func (s *DockerSuite) TestRunDnsOptionsBasedOnHostResolvConf(c *check.C) {
+ testRequires(c, SameHostDaemon)
origResolvConf, err := ioutil.ReadFile("/etc/resolv.conf")
if os.IsNotExist(err) {
- t.Fatalf("/etc/resolv.conf does not exist")
+ c.Fatalf("/etc/resolv.conf does not exist")
}
hostNamservers := resolvconf.GetNameservers(origResolvConf)
@@ -1609,58 +1344,58 @@ func TestRunDnsOptionsBasedOnHostResolvConf(t *testing.T) {
var out string
cmd := exec.Command(dockerBinary, "run", "--dns=127.0.0.1", "busybox", "cat", "/etc/resolv.conf")
if out, _, _, err = runCommandWithStdoutStderr(cmd); err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actualNameservers := resolvconf.GetNameservers([]byte(out)); string(actualNameservers[0]) != "127.0.0.1" {
- t.Fatalf("expected '127.0.0.1', but says: %q", string(actualNameservers[0]))
+ c.Fatalf("expected '127.0.0.1', but says: %q", string(actualNameservers[0]))
}
actualSearch := resolvconf.GetSearchDomains([]byte(out))
if len(actualSearch) != len(hostSearch) {
- t.Fatalf("expected %q search domain(s), but it has: %q", len(hostSearch), len(actualSearch))
+ c.Fatalf("expected %q search domain(s), but it has: %q", len(hostSearch), len(actualSearch))
}
for i := range actualSearch {
if actualSearch[i] != hostSearch[i] {
- t.Fatalf("expected %q domain, but says: %q", actualSearch[i], hostSearch[i])
+ c.Fatalf("expected %q domain, but says: %q", actualSearch[i], hostSearch[i])
}
}
cmd = exec.Command(dockerBinary, "run", "--dns-search=mydomain", "busybox", "cat", "/etc/resolv.conf")
if out, _, err = runCommandWithOutput(cmd); err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
actualNameservers := resolvconf.GetNameservers([]byte(out))
if len(actualNameservers) != len(hostNamservers) {
- t.Fatalf("expected %q nameserver(s), but it has: %q", len(hostNamservers), len(actualNameservers))
+ c.Fatalf("expected %q nameserver(s), but it has: %q", len(hostNamservers), len(actualNameservers))
}
for i := range actualNameservers {
if actualNameservers[i] != hostNamservers[i] {
- t.Fatalf("expected %q nameserver, but says: %q", actualNameservers[i], hostNamservers[i])
+ c.Fatalf("expected %q nameserver, but says: %q", actualNameservers[i], hostNamservers[i])
}
}
if actualSearch = resolvconf.GetSearchDomains([]byte(out)); string(actualSearch[0]) != "mydomain" {
- t.Fatalf("expected 'mydomain', but says: %q", string(actualSearch[0]))
+ c.Fatalf("expected 'mydomain', but says: %q", string(actualSearch[0]))
}
// test with file
tmpResolvConf := []byte("search example.com\nnameserver 12.34.56.78\nnameserver 127.0.0.1")
if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// put the old resolvconf back
defer func() {
if err := ioutil.WriteFile("/etc/resolv.conf", origResolvConf, 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
}()
resolvConf, err := ioutil.ReadFile("/etc/resolv.conf")
if os.IsNotExist(err) {
- t.Fatalf("/etc/resolv.conf does not exist")
+ c.Fatalf("/etc/resolv.conf does not exist")
}
hostNamservers = resolvconf.GetNameservers(resolvConf)
@@ -1669,35 +1404,32 @@ func TestRunDnsOptionsBasedOnHostResolvConf(t *testing.T) {
cmd = exec.Command(dockerBinary, "run", "busybox", "cat", "/etc/resolv.conf")
if out, _, err = runCommandWithOutput(cmd); err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actualNameservers = resolvconf.GetNameservers([]byte(out)); string(actualNameservers[0]) != "12.34.56.78" || len(actualNameservers) != 1 {
- t.Fatalf("expected '12.34.56.78', but has: %v", actualNameservers)
+ c.Fatalf("expected '12.34.56.78', but has: %v", actualNameservers)
}
actualSearch = resolvconf.GetSearchDomains([]byte(out))
if len(actualSearch) != len(hostSearch) {
- t.Fatalf("expected %q search domain(s), but it has: %q", len(hostSearch), len(actualSearch))
+ c.Fatalf("expected %q search domain(s), but it has: %q", len(hostSearch), len(actualSearch))
}
for i := range actualSearch {
if actualSearch[i] != hostSearch[i] {
- t.Fatalf("expected %q domain, but says: %q", actualSearch[i], hostSearch[i])
+ c.Fatalf("expected %q domain, but says: %q", actualSearch[i], hostSearch[i])
}
}
- defer deleteAllContainers()
-
- logDone("run - dns options based on host resolv.conf")
}
// Test the file watch notifier on docker host's /etc/resolv.conf
// A go-routine is responsible for auto-updating containers which are
// stopped and have an unmodified copy of resolv.conf, as well as
// marking running containers as requiring an update on next restart
-func TestRunResolvconfUpdater(t *testing.T) {
+func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
// Because overlay doesn't support inotify properly, we need to skip
// this test if the docker daemon has Storage Driver == overlay
- testRequires(t, SameHostDaemon, NotOverlay)
+ testRequires(c, SameHostDaemon, NotOverlay)
tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78")
tmpLocalhostResolvConf := []byte("nameserver 127.0.0.1")
@@ -1705,97 +1437,96 @@ func TestRunResolvconfUpdater(t *testing.T) {
//take a copy of resolv.conf for restoring after test completes
resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// This test case is meant to test monitoring resolv.conf when it is
- // a regular file not a bind mount. So we unmount resolv.conf and replace
+ // a regular file not a bind mounc. So we unmount resolv.conf and replace
// it with a file containing the original settings.
cmd := exec.Command("umount", "/etc/resolv.conf")
if _, err = runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
//cleanup
defer func() {
- deleteAllContainers()
if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
}()
//1. test that a non-running container gets an updated resolv.conf
cmd = exec.Command(dockerBinary, "run", "--name='first'", "busybox", "true")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
containerID1, err := getIDByName("first")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// replace resolv.conf with our temporary copy
bytesResolvConf := []byte(tmpResolvConf)
if err := ioutil.WriteFile("/etc/resolv.conf", bytesResolvConf, 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
time.Sleep(time.Second / 2)
// check for update in container
containerResolv, err := readContainerFile(containerID1, "resolv.conf")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !bytes.Equal(containerResolv, bytesResolvConf) {
- t.Fatalf("Stopped container does not have updated resolv.conf; expected %q, got %q", tmpResolvConf, string(containerResolv))
+ c.Fatalf("Stopped container does not have updated resolv.conf; expected %q, got %q", tmpResolvConf, string(containerResolv))
}
//2. test that a non-running container does not receive resolv.conf updates
// if it modified the container copy of the starting point resolv.conf
cmd = exec.Command(dockerBinary, "run", "--name='second'", "busybox", "sh", "-c", "echo 'search mylittlepony.com' >>/etc/resolv.conf")
if _, err = runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
containerID2, err := getIDByName("second")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
containerResolvHashBefore, err := readContainerFile(containerID2, "resolv.conf.hash")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
//make a change to resolv.conf (in this case replacing our tmp copy with orig copy)
if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
time.Sleep(time.Second / 2)
containerResolvHashAfter, err := readContainerFile(containerID2, "resolv.conf.hash")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !bytes.Equal(containerResolvHashBefore, containerResolvHashAfter) {
- t.Fatalf("Stopped container with modified resolv.conf should not have been updated; expected hash: %v, new hash: %v", containerResolvHashBefore, containerResolvHashAfter)
+ c.Fatalf("Stopped container with modified resolv.conf should not have been updated; expected hash: %v, new hash: %v", containerResolvHashBefore, containerResolvHashAfter)
}
//3. test that a running container's resolv.conf is not modified while running
cmd = exec.Command(dockerBinary, "run", "-d", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
runningContainerID := strings.TrimSpace(out)
containerResolvHashBefore, err = readContainerFile(runningContainerID, "resolv.conf.hash")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// replace resolv.conf
if err := ioutil.WriteFile("/etc/resolv.conf", bytesResolvConf, 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// make sure the updater has time to run to validate we really aren't
@@ -1803,27 +1534,27 @@ func TestRunResolvconfUpdater(t *testing.T) {
time.Sleep(time.Second / 2)
containerResolvHashAfter, err = readContainerFile(runningContainerID, "resolv.conf.hash")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !bytes.Equal(containerResolvHashBefore, containerResolvHashAfter) {
- t.Fatalf("Running container's resolv.conf should not be updated; expected hash: %v, new hash: %v", containerResolvHashBefore, containerResolvHashAfter)
+ c.Fatalf("Running container's resolv.conf should not be updated; expected hash: %v, new hash: %v", containerResolvHashBefore, containerResolvHashAfter)
}
//4. test that a running container's resolv.conf is updated upon restart
// (the above container is still running..)
cmd = exec.Command(dockerBinary, "restart", runningContainerID)
if _, err = runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// check for update in container
containerResolv, err = readContainerFile(runningContainerID, "resolv.conf")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !bytes.Equal(containerResolv, bytesResolvConf) {
- t.Fatalf("Restarted container should have updated resolv.conf; expected %q, got %q", tmpResolvConf, string(containerResolv))
+ c.Fatalf("Restarted container should have updated resolv.conf; expected %q, got %q", tmpResolvConf, string(containerResolv))
}
//5. test that additions of a localhost resolver are cleaned from
@@ -1832,7 +1563,7 @@ func TestRunResolvconfUpdater(t *testing.T) {
// replace resolv.conf with a localhost-only nameserver copy
bytesResolvConf = []byte(tmpLocalhostResolvConf)
if err = ioutil.WriteFile("/etc/resolv.conf", bytesResolvConf, 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
time.Sleep(time.Second / 2)
@@ -1840,12 +1571,12 @@ func TestRunResolvconfUpdater(t *testing.T) {
// after the cleanup of resolv.conf found only a localhost nameserver:
containerResolv, err = readContainerFile(containerID1, "resolv.conf")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
expected := "\nnameserver 8.8.8.8\nnameserver 8.8.4.4"
if !bytes.Equal(containerResolv, []byte(expected)) {
- t.Fatalf("Container does not have cleaned/replaced DNS in resolv.conf; expected %q, got %q", expected, string(containerResolv))
+ c.Fatalf("Container does not have cleaned/replaced DNS in resolv.conf; expected %q, got %q", expected, string(containerResolv))
}
//6. Test that replacing (as opposed to modifying) resolv.conf triggers an update
@@ -1853,194 +1584,170 @@ func TestRunResolvconfUpdater(t *testing.T) {
// Restore the original resolv.conf
if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// Run the container so it picks up the old settings
cmd = exec.Command(dockerBinary, "run", "--name='third'", "busybox", "true")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
containerID3, err := getIDByName("third")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// Create a modified resolv.conf.aside and override resolv.conf with it
bytesResolvConf = []byte(tmpResolvConf)
if err := ioutil.WriteFile("/etc/resolv.conf.aside", bytesResolvConf, 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
err = os.Rename("/etc/resolv.conf.aside", "/etc/resolv.conf")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
time.Sleep(time.Second / 2)
// check for update in container
containerResolv, err = readContainerFile(containerID3, "resolv.conf")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !bytes.Equal(containerResolv, bytesResolvConf) {
- t.Fatalf("Stopped container does not have updated resolv.conf; expected\n%q\n got\n%q", tmpResolvConf, string(containerResolv))
+ c.Fatalf("Stopped container does not have updated resolv.conf; expected\n%q\n got\n%q", tmpResolvConf, string(containerResolv))
}
//cleanup, restore original resolv.conf happens in defer func()
- logDone("run - resolv.conf updater")
}
-func TestRunAddHost(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunAddHost(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--add-host=extra:86.75.30.9", "busybox", "grep", "extra", "/etc/hosts")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
actual := strings.Trim(out, "\r\n")
if actual != "86.75.30.9\textra" {
- t.Fatalf("expected '86.75.30.9\textra', but says: %q", actual)
+ c.Fatalf("expected '86.75.30.9\textra', but says: %q", actual)
}
-
- logDone("run - add-host option")
}
// Regression test for #6983
-func TestRunAttachStdErrOnlyTTYMode(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunAttachStdErrOnlyTTYMode(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-t", "-a", "stderr", "busybox", "true")
exitCode, err := runCommand(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
} else if exitCode != 0 {
- t.Fatalf("Container should have exited with error code 0")
+ c.Fatalf("Container should have exited with error code 0")
}
-
- logDone("run - Attach stderr only with -t")
}
// Regression test for #6983
-func TestRunAttachStdOutOnlyTTYMode(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunAttachStdOutOnlyTTYMode(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-t", "-a", "stdout", "busybox", "true")
exitCode, err := runCommand(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
} else if exitCode != 0 {
- t.Fatalf("Container should have exited with error code 0")
+ c.Fatalf("Container should have exited with error code 0")
}
-
- logDone("run - Attach stdout only with -t")
}
// Regression test for #6983
-func TestRunAttachStdOutAndErrTTYMode(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunAttachStdOutAndErrTTYMode(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-t", "-a", "stdout", "-a", "stderr", "busybox", "true")
exitCode, err := runCommand(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
} else if exitCode != 0 {
- t.Fatalf("Container should have exited with error code 0")
+ c.Fatalf("Container should have exited with error code 0")
}
-
- logDone("run - Attach stderr and stdout with -t")
}
// Test for #10388 - this will run the same test as TestRunAttachStdOutAndErrTTYMode
// but using --attach instead of -a to make sure we read the flag correctly
-func TestRunAttachWithDettach(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunAttachWithDettach(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-d", "--attach", "stdout", "busybox", "true")
_, stderr, _, err := runCommandWithStdoutStderr(cmd)
if err == nil {
- t.Fatal("Container should have exited with error code different than 0")
+ c.Fatal("Container should have exited with error code different than 0")
} else if !strings.Contains(stderr, "Conflicting options: -a and -d") {
- t.Fatal("Should have been returned an error with conflicting options -a and -d")
+ c.Fatal("Should have been returned an error with conflicting options -a and -d")
}
-
- logDone("run - Attach stdout with -d")
}
-func TestRunState(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunState(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
id := strings.TrimSpace(out)
state, err := inspectField(id, "State.Running")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if state != "true" {
- t.Fatal("Container state is 'not running'")
+ c.Fatal("Container state is 'not running'")
}
pid1, err := inspectField(id, "State.Pid")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if pid1 == "0" {
- t.Fatal("Container state Pid 0")
+ c.Fatal("Container state Pid 0")
}
cmd = exec.Command(dockerBinary, "stop", id)
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
state, err = inspectField(id, "State.Running")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if state != "false" {
- t.Fatal("Container state is 'running'")
+ c.Fatal("Container state is 'running'")
}
pid2, err := inspectField(id, "State.Pid")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if pid2 == pid1 {
- t.Fatalf("Container state Pid %s, but expected %s", pid2, pid1)
+ c.Fatalf("Container state Pid %s, but expected %s", pid2, pid1)
}
cmd = exec.Command(dockerBinary, "start", id)
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
state, err = inspectField(id, "State.Running")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if state != "true" {
- t.Fatal("Container state is 'not running'")
+ c.Fatal("Container state is 'not running'")
}
pid3, err := inspectField(id, "State.Pid")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if pid3 == pid1 {
- t.Fatalf("Container state Pid %s, but expected %s", pid2, pid1)
+ c.Fatalf("Container state Pid %s, but expected %s", pid2, pid1)
}
- logDone("run - test container state.")
}
// Test for #1737
-func TestRunCopyVolumeUidGid(t *testing.T) {
+func (s *DockerSuite) TestRunCopyVolumeUidGid(c *check.C) {
name := "testrunvolumesuidgid"
- defer deleteImages(name)
- defer deleteAllContainers()
_, err := buildImage(name,
`FROM busybox
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
@@ -2048,178 +1755,160 @@ func TestRunCopyVolumeUidGid(t *testing.T) {
RUN mkdir -p /hello && touch /hello/test && chown dockerio.dockerio /hello`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// Test that the uid and gid is copied from the image to the volume
cmd := exec.Command(dockerBinary, "run", "--rm", "-v", "/hello", name, "sh", "-c", "ls -l / | grep hello | awk '{print $3\":\"$4}'")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
out = strings.TrimSpace(out)
if out != "dockerio:dockerio" {
- t.Fatalf("Wrong /hello ownership: %s, expected dockerio:dockerio", out)
+ c.Fatalf("Wrong /hello ownership: %s, expected dockerio:dockerio", out)
}
-
- logDone("run - copy uid/gid for volume")
}
// Test for #1582
-func TestRunCopyVolumeContent(t *testing.T) {
+func (s *DockerSuite) TestRunCopyVolumeContent(c *check.C) {
name := "testruncopyvolumecontent"
- defer deleteImages(name)
- defer deleteAllContainers()
_, err := buildImage(name,
`FROM busybox
RUN mkdir -p /hello/local && echo hello > /hello/local/world`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// Test that the content is copied from the image to the volume
cmd := exec.Command(dockerBinary, "run", "--rm", "-v", "/hello", name, "find", "/hello")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if !(strings.Contains(out, "/hello/local/world") && strings.Contains(out, "/hello/local")) {
- t.Fatal("Container failed to transfer content to volume")
+ c.Fatal("Container failed to transfer content to volume")
}
- logDone("run - copy volume content")
}
-func TestRunCleanupCmdOnEntrypoint(t *testing.T) {
+func (s *DockerSuite) TestRunCleanupCmdOnEntrypoint(c *check.C) {
name := "testrunmdcleanuponentrypoint"
- defer deleteImages(name)
- defer deleteAllContainers()
if _, err := buildImage(name,
`FROM busybox
ENTRYPOINT ["echo"]
CMD ["testingpoint"]`,
true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
runCmd := exec.Command(dockerBinary, "run", "--entrypoint", "whoami", name)
out, exit, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("Error: %v, out: %q", err, out)
+ c.Fatalf("Error: %v, out: %q", err, out)
}
if exit != 0 {
- t.Fatalf("expected exit code 0 received %d, out: %q", exit, out)
+ c.Fatalf("expected exit code 0 received %d, out: %q", exit, out)
}
out = strings.TrimSpace(out)
if out != "root" {
- t.Fatalf("Expected output root, got %q", out)
+ c.Fatalf("Expected output root, got %q", out)
}
- logDone("run - cleanup cmd on --entrypoint")
}
// TestRunWorkdirExistsAndIsFile checks that if 'docker run -w' with existing file can be detected
-func TestRunWorkdirExistsAndIsFile(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunWorkdirExistsAndIsFile(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-w", "/bin/cat", "busybox")
out, exit, err := runCommandWithOutput(runCmd)
if !(err != nil && exit == 1 && strings.Contains(out, "Cannot mkdir: /bin/cat is not a directory")) {
- t.Fatalf("Docker must complains about making dir, but we got out: %s, exit: %d, err: %s", out, exit, err)
+ c.Fatalf("Docker must complains about making dir, but we got out: %s, exit: %d, err: %s", out, exit, err)
}
- logDone("run - error on existing file for workdir")
}
-func TestRunExitOnStdinClose(t *testing.T) {
+func (s *DockerSuite) TestRunExitOnStdinClose(c *check.C) {
name := "testrunexitonstdinclose"
- defer deleteAllContainers()
runCmd := exec.Command(dockerBinary, "run", "--name", name, "-i", "busybox", "/bin/cat")
stdin, err := runCmd.StdinPipe()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
stdout, err := runCmd.StdoutPipe()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err := runCmd.Start(); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if _, err := stdin.Write([]byte("hello\n")); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
r := bufio.NewReader(stdout)
line, err := r.ReadString('\n')
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
line = strings.TrimSpace(line)
if line != "hello" {
- t.Fatalf("Output should be 'hello', got '%q'", line)
+ c.Fatalf("Output should be 'hello', got '%q'", line)
}
if err := stdin.Close(); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- finish := make(chan struct{})
+ finish := make(chan error)
go func() {
- if err := runCmd.Wait(); err != nil {
- t.Fatal(err)
- }
+ finish <- runCmd.Wait()
close(finish)
}()
select {
- case <-finish:
+ case err := <-finish:
+ c.Assert(err, check.IsNil)
case <-time.After(1 * time.Second):
- t.Fatal("docker run failed to exit on stdin close")
+ c.Fatal("docker run failed to exit on stdin close")
}
state, err := inspectField(name, "State.Running")
- if err != nil {
- t.Fatal(err)
- }
+ c.Assert(err, check.IsNil)
+
if state != "false" {
- t.Fatal("Container must be stopped after stdin closing")
+ c.Fatal("Container must be stopped after stdin closing")
}
- logDone("run - exit on stdin closing")
}
// Test for #2267
-func TestRunWriteHostsFileAndNotCommit(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunWriteHostsFileAndNotCommit(c *check.C) {
name := "writehosts"
cmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "sh", "-c", "echo test2267 >> /etc/hosts && cat /etc/hosts")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if !strings.Contains(out, "test2267") {
- t.Fatal("/etc/hosts should contain 'test2267'")
+ c.Fatal("/etc/hosts should contain 'test2267'")
}
cmd = exec.Command(dockerBinary, "diff", name)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
- if len(strings.Trim(out, "\r\n")) != 0 && !eqToBaseDiff(out, t) {
- t.Fatal("diff should be empty")
+ if len(strings.Trim(out, "\r\n")) != 0 && !eqToBaseDiff(out, c) {
+ c.Fatal("diff should be empty")
}
-
- logDone("run - write to /etc/hosts and not commited")
}
-func eqToBaseDiff(out string, t *testing.T) bool {
+func eqToBaseDiff(out string, c *check.C) bool {
cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "echo", "hello")
out1, _, err := runCommandWithOutput(cmd)
cID := strings.TrimSpace(out1)
cmd = exec.Command(dockerBinary, "diff", cID)
baseDiff, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, baseDiff)
+ c.Fatal(err, baseDiff)
}
baseArr := strings.Split(baseDiff, "\n")
sort.Strings(baseArr)
@@ -2243,346 +1932,299 @@ func sliceEq(a, b []string) bool {
}
// Test for #2267
-func TestRunWriteHostnameFileAndNotCommit(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunWriteHostnameFileAndNotCommit(c *check.C) {
name := "writehostname"
cmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "sh", "-c", "echo test2267 >> /etc/hostname && cat /etc/hostname")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if !strings.Contains(out, "test2267") {
- t.Fatal("/etc/hostname should contain 'test2267'")
+ c.Fatal("/etc/hostname should contain 'test2267'")
}
cmd = exec.Command(dockerBinary, "diff", name)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
- if len(strings.Trim(out, "\r\n")) != 0 && !eqToBaseDiff(out, t) {
- t.Fatal("diff should be empty")
+ if len(strings.Trim(out, "\r\n")) != 0 && !eqToBaseDiff(out, c) {
+ c.Fatal("diff should be empty")
}
-
- logDone("run - write to /etc/hostname and not commited")
}
// Test for #2267
-func TestRunWriteResolvFileAndNotCommit(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunWriteResolvFileAndNotCommit(c *check.C) {
name := "writeresolv"
cmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "sh", "-c", "echo test2267 >> /etc/resolv.conf && cat /etc/resolv.conf")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if !strings.Contains(out, "test2267") {
- t.Fatal("/etc/resolv.conf should contain 'test2267'")
+ c.Fatal("/etc/resolv.conf should contain 'test2267'")
}
cmd = exec.Command(dockerBinary, "diff", name)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
- if len(strings.Trim(out, "\r\n")) != 0 && !eqToBaseDiff(out, t) {
- t.Fatal("diff should be empty")
+ if len(strings.Trim(out, "\r\n")) != 0 && !eqToBaseDiff(out, c) {
+ c.Fatal("diff should be empty")
}
-
- logDone("run - write to /etc/resolv.conf and not commited")
}
-func TestRunWithBadDevice(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunWithBadDevice(c *check.C) {
name := "baddevice"
cmd := exec.Command(dockerBinary, "run", "--name", name, "--device", "/etc", "busybox", "true")
out, _, err := runCommandWithOutput(cmd)
if err == nil {
- t.Fatal("Run should fail with bad device")
+ c.Fatal("Run should fail with bad device")
}
expected := `\"/etc\": not a device node`
if !strings.Contains(out, expected) {
- t.Fatalf("Output should contain %q, actual out: %q", expected, out)
+ c.Fatalf("Output should contain %q, actual out: %q", expected, out)
}
- logDone("run - error with bad device")
}
-func TestRunEntrypoint(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunEntrypoint(c *check.C) {
name := "entrypoint"
cmd := exec.Command(dockerBinary, "run", "--name", name, "--entrypoint", "/bin/echo", "busybox", "-n", "foobar")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
expected := "foobar"
if out != expected {
- t.Fatalf("Output should be %q, actual out: %q", expected, out)
+ c.Fatalf("Output should be %q, actual out: %q", expected, out)
}
- logDone("run - entrypoint")
}
-func TestRunBindMounts(t *testing.T) {
- testRequires(t, SameHostDaemon)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunBindMounts(c *check.C) {
+ testRequires(c, SameHostDaemon)
tmpDir, err := ioutil.TempDir("", "docker-test-container")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(tmpDir)
- writeFile(path.Join(tmpDir, "touch-me"), "", t)
+ writeFile(path.Join(tmpDir, "touch-me"), "", c)
// Test reading from a read-only bind mount
cmd := exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s:/tmp:ro", tmpDir), "busybox", "ls", "/tmp")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if !strings.Contains(out, "touch-me") {
- t.Fatal("Container failed to read from bind mount")
+ c.Fatal("Container failed to read from bind mount")
}
// test writing to bind mount
cmd = exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s:/tmp:rw", tmpDir), "busybox", "touch", "/tmp/holla")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
- readFile(path.Join(tmpDir, "holla"), t) // Will fail if the file doesn't exist
+ readFile(path.Join(tmpDir, "holla"), c) // Will fail if the file doesn't exist
// test mounting to an illegal destination directory
cmd = exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s:.", tmpDir), "busybox", "ls", ".")
_, err = runCommand(cmd)
if err == nil {
- t.Fatal("Container bind mounted illegal directory")
+ c.Fatal("Container bind mounted illegal directory")
}
// test mount a file
cmd = exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s/holla:/tmp/holla:rw", tmpDir), "busybox", "sh", "-c", "echo -n 'yotta' > /tmp/holla")
_, err = runCommand(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
- content := readFile(path.Join(tmpDir, "holla"), t) // Will fail if the file doesn't exist
+ content := readFile(path.Join(tmpDir, "holla"), c) // Will fail if the file doesn't exist
expected := "yotta"
if content != expected {
- t.Fatalf("Output should be %q, actual out: %q", expected, content)
+ c.Fatalf("Output should be %q, actual out: %q", expected, content)
}
-
- logDone("run - bind mounts")
}
// Ensure that CIDFile gets deleted if it's empty
// Perform this test by making `docker run` fail
-func TestRunCidFileCleanupIfEmpty(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunCidFileCleanupIfEmpty(c *check.C) {
tmpDir, err := ioutil.TempDir("", "TestRunCidFile")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(tmpDir)
tmpCidFile := path.Join(tmpDir, "cid")
cmd := exec.Command(dockerBinary, "run", "--cidfile", tmpCidFile, "emptyfs")
out, _, err := runCommandWithOutput(cmd)
if err == nil {
- t.Fatalf("Run without command must fail. out=%s", out)
+ c.Fatalf("Run without command must fail. out=%s", out)
} else if !strings.Contains(out, "No command specified") {
- t.Fatalf("Run without command failed with wrong output. out=%s\nerr=%v", out, err)
+ c.Fatalf("Run without command failed with wrong output. out=%s\nerr=%v", out, err)
}
if _, err := os.Stat(tmpCidFile); err == nil {
- t.Fatalf("empty CIDFile %q should've been deleted", tmpCidFile)
+ c.Fatalf("empty CIDFile %q should've been deleted", tmpCidFile)
}
- logDone("run - cleanup empty cidfile on error")
}
// #2098 - Docker cidFiles only contain short version of the containerId
-//sudo docker run --cidfile /tmp/docker_test.cid ubuntu echo "test"
+//sudo docker run --cidfile /tmp/docker_tesc.cid ubuntu echo "test"
// TestRunCidFile tests that run --cidfile returns the longid
-func TestRunCidFileCheckIDLength(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunCidFileCheckIDLength(c *check.C) {
tmpDir, err := ioutil.TempDir("", "TestRunCidFile")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
tmpCidFile := path.Join(tmpDir, "cid")
defer os.RemoveAll(tmpDir)
cmd := exec.Command(dockerBinary, "run", "-d", "--cidfile", tmpCidFile, "busybox", "true")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id := strings.TrimSpace(out)
buffer, err := ioutil.ReadFile(tmpCidFile)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cid := string(buffer)
if len(cid) != 64 {
- t.Fatalf("--cidfile should be a long id, not %q", id)
+ c.Fatalf("--cidfile should be a long id, not %q", id)
}
if cid != id {
- t.Fatalf("cid must be equal to %s, got %s", id, cid)
+ c.Fatalf("cid must be equal to %s, got %s", id, cid)
}
-
- logDone("run - cidfile contains long id")
}
-func TestRunNetworkNotInitializedNoneMode(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunNetworkNotInitializedNoneMode(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-d", "--net=none", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id := strings.TrimSpace(out)
res, err := inspectField(id, "NetworkSettings.IPAddress")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if res != "" {
- t.Fatalf("For 'none' mode network must not be initialized, but container got IP: %s", res)
+ c.Fatalf("For 'none' mode network must not be initialized, but container got IP: %s", res)
}
-
- logDone("run - network must not be initialized in 'none' mode")
}
-func TestRunSetMacAddress(t *testing.T) {
+func (s *DockerSuite) TestRunSetMacAddress(c *check.C) {
mac := "12:34:56:78:9a:bc"
- defer deleteAllContainers()
cmd := exec.Command(dockerBinary, "run", "-i", "--rm", fmt.Sprintf("--mac-address=%s", mac), "busybox", "/bin/sh", "-c", "ip link show eth0 | tail -1 | awk '{print $2}'")
out, ec, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("exec failed:\nexit code=%v\noutput=%s", ec, out)
+ c.Fatalf("exec failed:\nexit code=%v\noutput=%s", ec, out)
}
actualMac := strings.TrimSpace(out)
if actualMac != mac {
- t.Fatalf("Set MAC address with --mac-address failed. The container has an incorrect MAC address: %q, expected: %q", actualMac, mac)
+ c.Fatalf("Set MAC address with --mac-address failed. The container has an incorrect MAC address: %q, expected: %q", actualMac, mac)
}
-
- logDone("run - setting MAC address with --mac-address")
}
-func TestRunInspectMacAddress(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunInspectMacAddress(c *check.C) {
mac := "12:34:56:78:9a:bc"
cmd := exec.Command(dockerBinary, "run", "-d", "--mac-address="+mac, "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id := strings.TrimSpace(out)
inspectedMac, err := inspectField(id, "NetworkSettings.MacAddress")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if inspectedMac != mac {
- t.Fatalf("docker inspect outputs wrong MAC address: %q, should be: %q", inspectedMac, mac)
+ c.Fatalf("docker inspect outputs wrong MAC address: %q, should be: %q", inspectedMac, mac)
}
-
- logDone("run - inspecting MAC address")
}
// test docker run use a invalid mac address
-func TestRunWithInvalidMacAddress(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunWithInvalidMacAddress(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "--mac-address", "92:d0:c6:0a:29", "busybox")
out, _, err := runCommandWithOutput(runCmd)
//use a invalid mac address should with a error out
if err == nil || !strings.Contains(out, "is not a valid mac address") {
- t.Fatalf("run with an invalid --mac-address should with error out")
+ c.Fatalf("run with an invalid --mac-address should with error out")
}
-
- logDone("run - can't use an invalid mac address")
}
-func TestRunDeallocatePortOnMissingIptablesRule(t *testing.T) {
- defer deleteAllContainers()
- testRequires(t, SameHostDaemon)
+func (s *DockerSuite) TestRunDeallocatePortOnMissingIptablesRule(c *check.C) {
+ testRequires(c, SameHostDaemon)
cmd := exec.Command(dockerBinary, "run", "-d", "-p", "23:23", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id := strings.TrimSpace(out)
ip, err := inspectField(id, "NetworkSettings.IPAddress")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
iptCmd := exec.Command("iptables", "-D", "DOCKER", "-d", fmt.Sprintf("%s/32", ip),
"!", "-i", "docker0", "-o", "docker0", "-p", "tcp", "-m", "tcp", "--dport", "23", "-j", "ACCEPT")
out, _, err = runCommandWithOutput(iptCmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if err := deleteContainer(id); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "run", "-d", "-p", "23:23", "busybox", "top")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
-
- logDone("run - port should be deallocated even on iptables error")
}
-func TestRunPortInUse(t *testing.T) {
- defer deleteAllContainers()
- testRequires(t, SameHostDaemon)
+func (s *DockerSuite) TestRunPortInUse(c *check.C) {
+ testRequires(c, SameHostDaemon)
port := "1234"
l, err := net.Listen("tcp", ":"+port)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer l.Close()
cmd := exec.Command(dockerBinary, "run", "-d", "-p", port+":80", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if err == nil {
- t.Fatalf("Binding on used port must fail")
+ c.Fatalf("Binding on used port must fail")
}
if !strings.Contains(out, "address already in use") {
- t.Fatalf("Out must be about \"address already in use\", got %s", out)
+ c.Fatalf("Out must be about \"address already in use\", got %s", out)
}
-
- logDone("run - error out if port already in use")
}
// https://github.com/docker/docker/issues/8428
-func TestRunPortProxy(t *testing.T) {
- testRequires(t, SameHostDaemon)
-
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunPortProxy(c *check.C) {
+ testRequires(c, SameHostDaemon)
port := "12345"
cmd := exec.Command(dockerBinary, "run", "-d", "-p", port+":80", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("Failed to run and bind port %s, output: %s, error: %s", port, out, err)
+ c.Fatalf("Failed to run and bind port %s, output: %s, error: %s", port, out, err)
}
- // connect for 10 times here. This will trigger 10 EPIPES in the child
+ // connett for 10 times here. This will trigger 10 EPIPES in the child
// process and kill it when it writes to a closed stdout/stderr
for i := 0; i < 10; i++ {
net.Dial("tcp", fmt.Sprintf("0.0.0.0:%s", port))
@@ -2591,343 +2233,305 @@ func TestRunPortProxy(t *testing.T) {
listPs := exec.Command("sh", "-c", "ps ax | grep docker")
out, _, err = runCommandWithOutput(listPs)
if err != nil {
- t.Errorf("list docker process failed with output %s, error %s", out, err)
+ c.Errorf("list docker process failed with output %s, error %s", out, err)
}
if strings.Contains(out, "docker ") {
- t.Errorf("Unexpected defunct docker process")
+ c.Errorf("Unexpected defunct docker process")
}
if !strings.Contains(out, "docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 12345") {
- t.Errorf("Failed to find docker-proxy process, got %s", out)
+ c.Errorf("Failed to find docker-proxy process, got %s", out)
}
-
- logDone("run - proxy should work with unavailable port")
}
// Regression test for #7792
-func TestRunMountOrdering(t *testing.T) {
- defer deleteAllContainers()
- testRequires(t, SameHostDaemon)
+func (s *DockerSuite) TestRunMountOrdering(c *check.C) {
+ testRequires(c, SameHostDaemon)
tmpDir, err := ioutil.TempDir("", "docker_nested_mount_test")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(tmpDir)
tmpDir2, err := ioutil.TempDir("", "docker_nested_mount_test2")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(tmpDir2)
- // Create a temporary tmpfs mount.
+ // Create a temporary tmpfs mounc.
fooDir := filepath.Join(tmpDir, "foo")
if err := os.MkdirAll(filepath.Join(tmpDir, "foo"), 0755); err != nil {
- t.Fatalf("failed to mkdir at %s - %s", fooDir, err)
+ c.Fatalf("failed to mkdir at %s - %s", fooDir, err)
}
if err := ioutil.WriteFile(fmt.Sprintf("%s/touch-me", fooDir), []byte{}, 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err := ioutil.WriteFile(fmt.Sprintf("%s/touch-me", tmpDir), []byte{}, 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if err := ioutil.WriteFile(fmt.Sprintf("%s/touch-me", tmpDir2), []byte{}, 0644); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd := exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s:/tmp", tmpDir), "-v", fmt.Sprintf("%s:/tmp/foo", fooDir), "-v", fmt.Sprintf("%s:/tmp/tmp2", tmpDir2), "-v", fmt.Sprintf("%s:/tmp/tmp2/foo", fooDir), "busybox:latest", "sh", "-c", "ls /tmp/touch-me && ls /tmp/foo/touch-me && ls /tmp/tmp2/touch-me && ls /tmp/tmp2/foo/touch-me")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
-
- logDone("run - volumes are mounted in the correct order")
}
// Regression test for https://github.com/docker/docker/issues/8259
-func TestRunReuseBindVolumeThatIsSymlink(t *testing.T) {
- defer deleteAllContainers()
- testRequires(t, SameHostDaemon)
+func (s *DockerSuite) TestRunReuseBindVolumeThatIsSymlink(c *check.C) {
+ testRequires(c, SameHostDaemon)
tmpDir, err := ioutil.TempDir(os.TempDir(), "testlink")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(tmpDir)
linkPath := os.TempDir() + "/testlink2"
if err := os.Symlink(tmpDir, linkPath); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(linkPath)
// Create first container
cmd := exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s:/tmp/test", linkPath), "busybox", "ls", "-lh", "/tmp/test")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// Create second container with same symlinked path
// This will fail if the referenced issue is hit with a "Volume exists" error
cmd = exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s:/tmp/test", linkPath), "busybox", "ls", "-lh", "/tmp/test")
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
-
- logDone("run - can remount old bindmount volume")
}
//GH#10604: Test an "/etc" volume doesn't overlay special bind mounts in container
-func TestRunCreateVolumeEtc(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunCreateVolumeEtc(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "--dns=127.0.0.1", "-v", "/etc", "busybox", "cat", "/etc/resolv.conf")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
if !strings.Contains(out, "nameserver 127.0.0.1") {
- t.Fatal("/etc volume mount hides /etc/resolv.conf")
+ c.Fatal("/etc volume mount hides /etc/resolv.conf")
}
cmd = exec.Command(dockerBinary, "run", "-h=test123", "-v", "/etc", "busybox", "cat", "/etc/hostname")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
if !strings.Contains(out, "test123") {
- t.Fatal("/etc volume mount hides /etc/hostname")
+ c.Fatal("/etc volume mount hides /etc/hostname")
}
cmd = exec.Command(dockerBinary, "run", "--add-host=test:192.168.0.1", "-v", "/etc", "busybox", "cat", "/etc/hosts")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
out = strings.Replace(out, "\n", " ", -1)
if !strings.Contains(out, "192.168.0.1\ttest") || !strings.Contains(out, "127.0.0.1\tlocalhost") {
- t.Fatal("/etc volume mount hides /etc/hosts")
+ c.Fatal("/etc volume mount hides /etc/hosts")
}
-
- logDone("run - verify /etc volume doesn't hide special bind mounts")
}
-func TestVolumesNoCopyData(t *testing.T) {
- defer deleteImages("dataimage")
- defer deleteAllContainers()
+func (s *DockerSuite) TestVolumesNoCopyData(c *check.C) {
if _, err := buildImage("dataimage",
`FROM busybox
RUN mkdir -p /foo
RUN touch /foo/bar`,
true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd := exec.Command(dockerBinary, "run", "--name", "test", "-v", "/foo", "busybox")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "run", "--volumes-from", "test", "dataimage", "ls", "-lh", "/foo/bar")
if out, _, err := runCommandWithOutput(cmd); err == nil || !strings.Contains(out, "No such file or directory") {
- t.Fatalf("Data was copied on volumes-from but shouldn't be:\n%q", out)
+ c.Fatalf("Data was copied on volumes-from but shouldn't be:\n%q", out)
}
tmpDir := randomUnixTmpDirPath("docker_test_bind_mount_copy_data")
cmd = exec.Command(dockerBinary, "run", "-v", tmpDir+":/foo", "dataimage", "ls", "-lh", "/foo/bar")
if out, _, err := runCommandWithOutput(cmd); err == nil || !strings.Contains(out, "No such file or directory") {
- t.Fatalf("Data was copied on bind-mount but shouldn't be:\n%q", out)
+ c.Fatalf("Data was copied on bind-mount but shouldn't be:\n%q", out)
}
-
- logDone("run - volumes do not copy data for volumes-from and bindmounts")
}
-func TestRunVolumesNotRecreatedOnStart(t *testing.T) {
- testRequires(t, SameHostDaemon)
+func (s *DockerSuite) TestRunVolumesNotRecreatedOnStart(c *check.C) {
+ testRequires(c, SameHostDaemon)
// Clear out any remnants from other tests
- deleteAllContainers()
info, err := ioutil.ReadDir(volumesConfigPath)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if len(info) > 0 {
for _, f := range info {
if err := os.RemoveAll(volumesConfigPath + "/" + f.Name()); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
}
}
- defer deleteAllContainers()
cmd := exec.Command(dockerBinary, "run", "-v", "/foo", "--name", "lone_starr", "busybox")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "start", "lone_starr")
if _, err := runCommand(cmd); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
info, err = ioutil.ReadDir(volumesConfigPath)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if len(info) != 1 {
- t.Fatalf("Expected only 1 volume have %v", len(info))
+ c.Fatalf("Expected only 1 volume have %v", len(info))
}
-
- logDone("run - volumes not recreated on start")
}
-func TestRunNoOutputFromPullInStdout(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunNoOutputFromPullInStdout(c *check.C) {
// just run with unknown image
cmd := exec.Command(dockerBinary, "run", "asdfsg")
stdout := bytes.NewBuffer(nil)
cmd.Stdout = stdout
if err := cmd.Run(); err == nil {
- t.Fatal("Run with unknown image should fail")
+ c.Fatal("Run with unknown image should fail")
}
if stdout.Len() != 0 {
- t.Fatalf("Stdout contains output from pull: %s", stdout)
+ c.Fatalf("Stdout contains output from pull: %s", stdout)
}
- logDone("run - no output from pull in stdout")
}
-func TestRunVolumesCleanPaths(t *testing.T) {
+func (s *DockerSuite) TestRunVolumesCleanPaths(c *check.C) {
if _, err := buildImage("run_volumes_clean_paths",
`FROM busybox
VOLUME /foo/`,
true); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- defer deleteImages("run_volumes_clean_paths")
- defer deleteAllContainers()
cmd := exec.Command(dockerBinary, "run", "-v", "/foo", "-v", "/bar/", "--name", "dark_helmet", "run_volumes_clean_paths")
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
out, err := inspectFieldMap("dark_helmet", "Volumes", "/foo/")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- if out != "" {
- t.Fatalf("Found unexpected volume entry for '/foo/' in volumes\n%q", out)
+ if out != "" {
+ c.Fatalf("Found unexpected volume entry for '/foo/' in volumes\n%q", out)
}
out, err = inspectFieldMap("dark_helmet", "Volumes", "/foo")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !strings.Contains(out, volumesStoragePath) {
- t.Fatalf("Volume was not defined for /foo\n%q", out)
+ c.Fatalf("Volume was not defined for /foo\n%q", out)
}
out, err = inspectFieldMap("dark_helmet", "Volumes", "/bar/")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- if out != "" {
- t.Fatalf("Found unexpected volume entry for '/bar/' in volumes\n%q", out)
+ if out != "" {
+ c.Fatalf("Found unexpected volume entry for '/bar/' in volumes\n%q", out)
}
out, err = inspectFieldMap("dark_helmet", "Volumes", "/bar")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if !strings.Contains(out, volumesStoragePath) {
- t.Fatalf("Volume was not defined for /bar\n%q", out)
+ c.Fatalf("Volume was not defined for /bar\n%q", out)
}
-
- logDone("run - volume paths are cleaned")
}
// Regression test for #3631
-func TestRunSlowStdoutConsumer(t *testing.T) {
- defer deleteAllContainers()
-
- c := exec.Command(dockerBinary, "run", "--rm", "busybox", "/bin/sh", "-c", "dd if=/dev/zero of=/dev/stdout bs=1024 count=2000 | catv")
+func (s *DockerSuite) TestRunSlowStdoutConsumer(c *check.C) {
+ cont := exec.Command(dockerBinary, "run", "--rm", "busybox", "/bin/sh", "-c", "dd if=/dev/zero of=/dev/stdout bs=1024 count=2000 | catv")
- stdout, err := c.StdoutPipe()
+ stdout, err := cont.StdoutPipe()
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- if err := c.Start(); err != nil {
- t.Fatal(err)
+ if err := cont.Start(); err != nil {
+ c.Fatal(err)
}
n, err := consumeWithSpeed(stdout, 10000, 5*time.Millisecond, nil)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
expected := 2 * 1024 * 2000
if n != expected {
- t.Fatalf("Expected %d, got %d", expected, n)
+ c.Fatalf("Expected %d, got %d", expected, n)
}
-
- logDone("run - slow consumer")
}
-func TestRunAllowPortRangeThroughExpose(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunAllowPortRangeThroughExpose(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-d", "--expose", "3000-3003", "-P", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
id := strings.TrimSpace(out)
portstr, err := inspectFieldJSON(id, "NetworkSettings.Ports")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
var ports nat.PortMap
if err = unmarshalJSON([]byte(portstr), &ports); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
for port, binding := range ports {
portnum, _ := strconv.Atoi(strings.Split(string(port), "/")[0])
if portnum < 3000 || portnum > 3003 {
- t.Fatalf("Port %d is out of range ", portnum)
+ c.Fatalf("Port %d is out of range ", portnum)
}
if binding == nil || len(binding) != 1 || len(binding[0].HostPort) == 0 {
- t.Fatalf("Port is not mapped for the port %d", port)
+ c.Fatalf("Port is not mapped for the port %d", port)
}
}
if err := deleteContainer(id); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
- logDone("run - allow port range through --expose flag")
}
// test docker run expose a invalid port
-func TestRunExposePort(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunExposePort(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "--expose", "80000", "busybox")
out, _, err := runCommandWithOutput(runCmd)
//expose a invalid port should with a error out
if err == nil || !strings.Contains(out, "Invalid range format for --expose") {
- t.Fatalf("run --expose a invalid port should with error out")
+ c.Fatalf("run --expose a invalid port should with error out")
}
-
- logDone("run - can't expose a invalid port")
}
-func TestRunUnknownCommand(t *testing.T) {
- testRequires(t, NativeExecDriver)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunUnknownCommand(c *check.C) {
+ testRequires(c, NativeExecDriver)
runCmd := exec.Command(dockerBinary, "create", "busybox", "/bin/nada")
cID, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("Failed to create container: %v, output: %q", err, cID)
+ c.Fatalf("Failed to create container: %v, output: %q", err, cID)
}
cID = strings.TrimSpace(cID)
@@ -2939,176 +2543,167 @@ func TestRunUnknownCommand(t *testing.T) {
rc = strings.TrimSpace(rc)
if err2 != nil {
- t.Fatalf("Error getting status of container: %v", err2)
+ c.Fatalf("Error getting status of container: %v", err2)
}
if rc == "0" {
- t.Fatalf("ExitCode(%v) cannot be 0", rc)
+ c.Fatalf("ExitCode(%v) cannot be 0", rc)
}
-
- logDone("run - Unknown Command")
}
-func TestRunModeIpcHost(t *testing.T) {
- testRequires(t, SameHostDaemon)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunModeIpcHost(c *check.C) {
+ testRequires(c, SameHostDaemon)
hostIpc, err := os.Readlink("/proc/1/ns/ipc")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd := exec.Command(dockerBinary, "run", "--ipc=host", "busybox", "readlink", "/proc/self/ns/ipc")
out2, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out2)
+ c.Fatal(err, out2)
}
out2 = strings.Trim(out2, "\n")
if hostIpc != out2 {
- t.Fatalf("IPC different with --ipc=host %s != %s\n", hostIpc, out2)
+ c.Fatalf("IPC different with --ipc=host %s != %s\n", hostIpc, out2)
}
cmd = exec.Command(dockerBinary, "run", "busybox", "readlink", "/proc/self/ns/ipc")
out2, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out2)
+ c.Fatal(err, out2)
}
out2 = strings.Trim(out2, "\n")
if hostIpc == out2 {
- t.Fatalf("IPC should be different without --ipc=host %s == %s\n", hostIpc, out2)
+ c.Fatalf("IPC should be different without --ipc=host %s == %s\n", hostIpc, out2)
}
-
- logDone("run - ipc host mode")
}
-func TestRunModeIpcContainer(t *testing.T) {
- defer deleteAllContainers()
- testRequires(t, SameHostDaemon)
+func (s *DockerSuite) TestRunModeIpcContainer(c *check.C) {
+ testRequires(c, SameHostDaemon)
cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
id := strings.TrimSpace(out)
state, err := inspectField(id, "State.Running")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if state != "true" {
- t.Fatal("Container state is 'not running'")
+ c.Fatal("Container state is 'not running'")
}
pid1, err := inspectField(id, "State.Pid")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
parentContainerIpc, err := os.Readlink(fmt.Sprintf("/proc/%s/ns/ipc", pid1))
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "run", fmt.Sprintf("--ipc=container:%s", id), "busybox", "readlink", "/proc/self/ns/ipc")
out2, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out2)
+ c.Fatal(err, out2)
}
out2 = strings.Trim(out2, "\n")
if parentContainerIpc != out2 {
- t.Fatalf("IPC different with --ipc=container:%s %s != %s\n", id, parentContainerIpc, out2)
+ c.Fatalf("IPC different with --ipc=container:%s %s != %s\n", id, parentContainerIpc, out2)
}
-
- logDone("run - ipc container mode")
}
-func TestRunModeIpcContainerNotExists(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunModeIpcContainerNotExists(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-d", "--ipc", "container:abcd1234", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if !strings.Contains(out, "abcd1234") || err == nil {
- t.Fatalf("run IPC from a non exists container should with correct error out")
+ c.Fatalf("run IPC from a non exists container should with correct error out")
}
-
- logDone("run - ipc from a non exists container failed with correct error out")
}
-func TestContainerNetworkMode(t *testing.T) {
- defer deleteAllContainers()
- testRequires(t, SameHostDaemon)
+func (s *DockerSuite) TestContainerNetworkMode(c *check.C) {
+ testRequires(c, SameHostDaemon)
cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
id := strings.TrimSpace(out)
if err := waitRun(id); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
pid1, err := inspectField(id, "State.Pid")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
parentContainerNet, err := os.Readlink(fmt.Sprintf("/proc/%s/ns/net", pid1))
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd = exec.Command(dockerBinary, "run", fmt.Sprintf("--net=container:%s", id), "busybox", "readlink", "/proc/self/ns/net")
out2, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out2)
+ c.Fatal(err, out2)
}
out2 = strings.Trim(out2, "\n")
if parentContainerNet != out2 {
- t.Fatalf("NET different with --net=container:%s %s != %s\n", id, parentContainerNet, out2)
+ c.Fatalf("NET different with --net=container:%s %s != %s\n", id, parentContainerNet, out2)
}
+}
- logDone("run - container shared network namespace")
+func (s *DockerSuite) TestContainerNetworkModeToSelf(c *check.C) {
+ cmd := exec.Command(dockerBinary, "run", "--name=me", "--net=container:me", "busybox", "true")
+ out, _, err := runCommandWithOutput(cmd)
+ if err == nil || !strings.Contains(out, "cannot join own network") {
+ c.Fatalf("using container net mode to self should result in an error")
+ }
}
-func TestRunModePidHost(t *testing.T) {
- testRequires(t, NativeExecDriver, SameHostDaemon)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunModePidHost(c *check.C) {
+ testRequires(c, NativeExecDriver, SameHostDaemon)
hostPid, err := os.Readlink("/proc/1/ns/pid")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd := exec.Command(dockerBinary, "run", "--pid=host", "busybox", "readlink", "/proc/self/ns/pid")
out2, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out2)
+ c.Fatal(err, out2)
}
out2 = strings.Trim(out2, "\n")
if hostPid != out2 {
- t.Fatalf("PID different with --pid=host %s != %s\n", hostPid, out2)
+ c.Fatalf("PID different with --pid=host %s != %s\n", hostPid, out2)
}
cmd = exec.Command(dockerBinary, "run", "busybox", "readlink", "/proc/self/ns/pid")
out2, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out2)
+ c.Fatal(err, out2)
}
out2 = strings.Trim(out2, "\n")
if hostPid == out2 {
- t.Fatalf("PID should be different without --pid=host %s == %s\n", hostPid, out2)
+ c.Fatalf("PID should be different without --pid=host %s == %s\n", hostPid, out2)
}
-
- logDone("run - pid host mode")
}
-func TestRunTLSverify(t *testing.T) {
+func (s *DockerSuite) TestRunTLSverify(c *check.C) {
cmd := exec.Command(dockerBinary, "ps")
out, ec, err := runCommandWithOutput(cmd)
if err != nil || ec != 0 {
- t.Fatalf("Should have worked: %v:\n%v", err, out)
+ c.Fatalf("Should have worked: %v:\n%v", err, out)
}
// Regardless of whether we specify true or false we need to
@@ -3117,354 +2712,333 @@ func TestRunTLSverify(t *testing.T) {
cmd = exec.Command(dockerBinary, "--tlsverify=false", "ps")
out, ec, err = runCommandWithOutput(cmd)
if err == nil || ec == 0 || !strings.Contains(out, "trying to connect") {
- t.Fatalf("Should have failed: \nec:%v\nout:%v\nerr:%v", ec, out, err)
+ c.Fatalf("Should have failed: \net:%v\nout:%v\nerr:%v", ec, out, err)
}
cmd = exec.Command(dockerBinary, "--tlsverify=true", "ps")
out, ec, err = runCommandWithOutput(cmd)
if err == nil || ec == 0 || !strings.Contains(out, "cert") {
- t.Fatalf("Should have failed: \nec:%v\nout:%v\nerr:%v", ec, out, err)
+ c.Fatalf("Should have failed: \net:%v\nout:%v\nerr:%v", ec, out, err)
}
-
- logDone("run - verify tls is set for --tlsverify")
}
-func TestRunPortFromDockerRangeInUse(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunPortFromDockerRangeInUse(c *check.C) {
// first find allocator current position
cmd := exec.Command(dockerBinary, "run", "-d", "-p", ":80", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
id := strings.TrimSpace(out)
cmd = exec.Command(dockerBinary, "port", id)
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
out = strings.TrimSpace(out)
if out == "" {
- t.Fatal("docker port command output is empty")
+ c.Fatal("docker port command output is empty")
}
out = strings.Split(out, ":")[1]
lastPort, err := strconv.Atoi(out)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
port := lastPort + 1
l, err := net.Listen("tcp", ":"+strconv.Itoa(port))
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer l.Close()
cmd = exec.Command(dockerBinary, "run", "-d", "-p", ":80", "busybox", "top")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf(out, err)
+ c.Fatalf(out, err)
}
id = strings.TrimSpace(out)
cmd = exec.Command(dockerBinary, "port", id)
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
-
- logDone("run - find another port if port from autorange already bound")
}
-func TestRunTtyWithPipe(t *testing.T) {
- defer deleteAllContainers()
-
- done := make(chan struct{})
+func (s *DockerSuite) TestRunTtyWithPipe(c *check.C) {
+ errChan := make(chan error)
go func() {
- defer close(done)
+ defer close(errChan)
cmd := exec.Command(dockerBinary, "run", "-ti", "busybox", "true")
if _, err := cmd.StdinPipe(); err != nil {
- t.Fatal(err)
+ errChan <- err
+ return
}
expected := "cannot enable tty mode"
if out, _, err := runCommandWithOutput(cmd); err == nil {
- t.Fatal("run should have failed")
+ errChan <- fmt.Errorf("run should have failed")
+ return
} else if !strings.Contains(out, expected) {
- t.Fatalf("run failed with error %q: expected %q", out, expected)
+ errChan <- fmt.Errorf("run failed with error %q: expected %q", out, expected)
+ return
}
}()
select {
- case <-done:
+ case err := <-errChan:
+ c.Assert(err, check.IsNil)
case <-time.After(3 * time.Second):
- t.Fatal("container is running but should have failed")
+ c.Fatal("container is running but should have failed")
}
-
- logDone("run - forbid piped stdin with tty")
}
-func TestRunNonLocalMacAddress(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunNonLocalMacAddress(c *check.C) {
addr := "00:16:3E:08:00:50"
cmd := exec.Command(dockerBinary, "run", "--mac-address", addr, "busybox", "ifconfig")
if out, _, err := runCommandWithOutput(cmd); err != nil || !strings.Contains(out, addr) {
- t.Fatalf("Output should have contained %q: %s, %v", addr, out, err)
+ c.Fatalf("Output should have contained %q: %s, %v", addr, out, err)
}
-
- logDone("run - use non-local mac-address")
}
-func TestRunNetHost(t *testing.T) {
- testRequires(t, SameHostDaemon)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunNetHost(c *check.C) {
+ testRequires(c, SameHostDaemon)
hostNet, err := os.Readlink("/proc/1/ns/net")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd := exec.Command(dockerBinary, "run", "--net=host", "busybox", "readlink", "/proc/self/ns/net")
out2, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out2)
+ c.Fatal(err, out2)
}
out2 = strings.Trim(out2, "\n")
if hostNet != out2 {
- t.Fatalf("Net namespace different with --net=host %s != %s\n", hostNet, out2)
+ c.Fatalf("Net namespace different with --net=host %s != %s\n", hostNet, out2)
}
cmd = exec.Command(dockerBinary, "run", "busybox", "readlink", "/proc/self/ns/net")
out2, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out2)
+ c.Fatal(err, out2)
}
out2 = strings.Trim(out2, "\n")
if hostNet == out2 {
- t.Fatalf("Net namespace should be different without --net=host %s == %s\n", hostNet, out2)
+ c.Fatalf("Net namespace should be different without --net=host %s == %s\n", hostNet, out2)
}
-
- logDone("run - net host mode")
}
-func TestRunNetContainerWhichHost(t *testing.T) {
- testRequires(t, SameHostDaemon)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunNetContainerWhichHost(c *check.C) {
+ testRequires(c, SameHostDaemon)
hostNet, err := os.Readlink("/proc/1/ns/net")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
cmd := exec.Command(dockerBinary, "run", "-d", "--net=host", "--name=test", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
cmd = exec.Command(dockerBinary, "run", "--net=container:test", "busybox", "readlink", "/proc/self/ns/net")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
out = strings.Trim(out, "\n")
if hostNet != out {
- t.Fatalf("Container should have host network namespace")
+ c.Fatalf("Container should have host network namespace")
}
-
- logDone("run - net container mode, where container in host mode")
}
-func TestRunAllowPortRangeThroughPublish(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunAllowPortRangeThroughPublish(c *check.C) {
cmd := exec.Command(dockerBinary, "run", "-d", "--expose", "3000-3003", "-p", "3000-3003", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
id := strings.TrimSpace(out)
portstr, err := inspectFieldJSON(id, "NetworkSettings.Ports")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
var ports nat.PortMap
err = unmarshalJSON([]byte(portstr), &ports)
for port, binding := range ports {
portnum, _ := strconv.Atoi(strings.Split(string(port), "/")[0])
if portnum < 3000 || portnum > 3003 {
- t.Fatalf("Port %d is out of range ", portnum)
+ c.Fatalf("Port %d is out of range ", portnum)
}
if binding == nil || len(binding) != 1 || len(binding[0].HostPort) == 0 {
- t.Fatal("Port is not mapped for the port "+port, out)
+ c.Fatal("Port is not mapped for the port "+port, out)
}
}
- logDone("run - allow port range through --expose flag")
}
-func TestRunOOMExitCode(t *testing.T) {
- defer deleteAllContainers()
-
- done := make(chan struct{})
+func (s *DockerSuite) TestRunOOMExitCode(c *check.C) {
+ errChan := make(chan error)
go func() {
- defer close(done)
-
+ defer close(errChan)
runCmd := exec.Command(dockerBinary, "run", "-m", "4MB", "busybox", "sh", "-c", "x=a; while true; do x=$x$x$x$x; done")
out, exitCode, _ := runCommandWithOutput(runCmd)
if expected := 137; exitCode != expected {
- t.Fatalf("wrong exit code for OOM container: expected %d, got %d (output: %q)", expected, exitCode, out)
+ errChan <- fmt.Errorf("wrong exit code for OOM container: expected %d, got %d (output: %q)", expected, exitCode, out)
}
}()
select {
- case <-done:
+ case err := <-errChan:
+ c.Assert(err, check.IsNil)
case <-time.After(30 * time.Second):
- t.Fatal("Timeout waiting for container to die on OOM")
+ c.Fatal("Timeout waiting for container to die on OOM")
}
-
- logDone("run - exit code on oom")
}
-func TestRunSetDefaultRestartPolicy(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunSetDefaultRestartPolicy(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "test", "busybox", "top")
if out, _, err := runCommandWithOutput(runCmd); err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
cmd := exec.Command(dockerBinary, "inspect", "-f", "{{.HostConfig.RestartPolicy.Name}}", "test")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatalf("failed to inspect container: %v, output: %q", err, out)
+ c.Fatalf("failed to inspect container: %v, output: %q", err, out)
}
out = strings.Trim(out, "\r\n")
if out != "no" {
- t.Fatalf("Set default restart policy failed")
+ c.Fatalf("Set default restart policy failed")
}
-
- logDone("run - set default restart policy success")
}
-func TestRunRestartMaxRetries(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunRestartMaxRetries(c *check.C) {
out, err := exec.Command(dockerBinary, "run", "-d", "--restart=on-failure:3", "busybox", "false").CombinedOutput()
if err != nil {
- t.Fatal(string(out), err)
+ c.Fatal(string(out), err)
}
id := strings.TrimSpace(string(out))
- if err := waitInspect(id, "{{ .State.Restarting }} {{ .State.Running }}", "false false", 5); err != nil {
- t.Fatal(err)
+ if err := waitInspect(id, "{{ .State.Restarting }} {{ .State.Running }}", "false false", 10); err != nil {
+ c.Fatal(err)
}
count, err := inspectField(id, "RestartCount")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if count != "3" {
- t.Fatalf("Container was restarted %s times, expected %d", count, 3)
+ c.Fatalf("Container was restarted %s times, expected %d", count, 3)
}
MaximumRetryCount, err := inspectField(id, "HostConfig.RestartPolicy.MaximumRetryCount")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if MaximumRetryCount != "3" {
- t.Fatalf("Container Maximum Retry Count is %s, expected %s", MaximumRetryCount, "3")
+ c.Fatalf("Container Maximum Retry Count is %s, expected %s", MaximumRetryCount, "3")
}
- logDone("run - test max-retries for --restart")
}
-func TestRunContainerWithWritableRootfs(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunContainerWithWritableRootfs(c *check.C) {
out, err := exec.Command(dockerBinary, "run", "--rm", "busybox", "touch", "/file").CombinedOutput()
if err != nil {
- t.Fatal(string(out), err)
+ c.Fatal(string(out), err)
}
- logDone("run - writable rootfs")
}
-func TestRunContainerWithReadonlyRootfs(t *testing.T) {
- testRequires(t, NativeExecDriver)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunContainerWithReadonlyRootfs(c *check.C) {
+ testRequires(c, NativeExecDriver)
out, err := exec.Command(dockerBinary, "run", "--read-only", "--rm", "busybox", "touch", "/file").CombinedOutput()
if err == nil {
- t.Fatal("expected container to error on run with read only error")
+ c.Fatal("expected container to error on run with read only error")
}
expected := "Read-only file system"
if !strings.Contains(string(out), expected) {
- t.Fatalf("expected output from failure to contain %s but contains %s", expected, out)
+ c.Fatalf("expected output from failure to contain %s but contains %s", expected, out)
}
- logDone("run - read only rootfs")
}
-func TestRunVolumesFromRestartAfterRemoved(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunVolumesFromRestartAfterRemoved(c *check.C) {
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", "voltest", "-v", "/foo", "busybox"))
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", "restarter", "--volumes-from", "voltest", "busybox", "top"))
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
// Remove the main volume container and restart the consuming container
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "rm", "-f", "voltest"))
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
// This should not fail since the volumes-from were already applied
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "restart", "restarter"))
if err != nil {
- t.Fatalf("expected container to restart successfully: %v\n%s", err, out)
+ c.Fatalf("expected container to restart successfully: %v\n%s", err, out)
}
-
- logDone("run - can restart a volumes-from container after producer is removed")
}
// run container with --rm should remove container if exit code != 0
-func TestRunContainerWithRmFlagExitCodeNotEqualToZero(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunContainerWithRmFlagExitCodeNotEqualToZero(c *check.C) {
name := "flowers"
runCmd := exec.Command(dockerBinary, "run", "--name", name, "--rm", "busybox", "ls", "/notexists")
out, _, err := runCommandWithOutput(runCmd)
if err == nil {
- t.Fatal("Expected docker run to fail", out, err)
+ c.Fatal("Expected docker run to fail", out, err)
}
out, err = getAllContainers()
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if out != "" {
- t.Fatal("Expected not to have containers", out)
+ c.Fatal("Expected not to have containers", out)
}
-
- logDone("run - container is removed if run with --rm and exit code != 0")
}
-func TestRunContainerWithRmFlagCannotStartContainer(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunContainerWithRmFlagCannotStartContainer(c *check.C) {
name := "sparkles"
runCmd := exec.Command(dockerBinary, "run", "--name", name, "--rm", "busybox", "commandNotFound")
out, _, err := runCommandWithOutput(runCmd)
if err == nil {
- t.Fatal("Expected docker run to fail", out, err)
+ c.Fatal("Expected docker run to fail", out, err)
}
out, err = getAllContainers()
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
if out != "" {
- t.Fatal("Expected not to have containers", out)
+ c.Fatal("Expected not to have containers", out)
}
+}
- logDone("run - container is removed if run with --rm and cannot start")
+func (s *DockerSuite) TestRunPidHostWithChildIsKillable(c *check.C) {
+ name := "ibuildthecloud"
+ if out, err := exec.Command(dockerBinary, "run", "-d", "--pid=host", "--name", name, "busybox", "sh", "-c", "sleep 30; echo hi").CombinedOutput(); err != nil {
+ c.Fatal(err, out)
+ }
+ time.Sleep(1 * time.Second)
+ errchan := make(chan error)
+ go func() {
+ if out, err := exec.Command(dockerBinary, "kill", name).CombinedOutput(); err != nil {
+ errchan <- fmt.Errorf("%v:\n%s", err, out)
+ }
+ close(errchan)
+ }()
+ select {
+ case err := <-errchan:
+ c.Assert(err, check.IsNil)
+ case <-time.After(5 * time.Second):
+ c.Fatal("Kill container timed out")
+ }
}
diff --git a/integration-cli/docker_cli_run_unix_test.go b/integration-cli/docker_cli_run_unix_test.go
index 026f8279efba8..59b623162de44 100644
--- a/integration-cli/docker_cli_run_unix_test.go
+++ b/integration-cli/docker_cli_run_unix_test.go
@@ -3,6 +3,7 @@
package main
import (
+ "bufio"
"fmt"
"io/ioutil"
"os"
@@ -10,58 +11,52 @@ import (
"path"
"path/filepath"
"strings"
- "testing"
"time"
"github.com/docker/docker/pkg/mount"
+ "github.com/go-check/check"
"github.com/kr/pty"
)
// #6509
-func TestRunRedirectStdout(t *testing.T) {
-
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunRedirectStdout(c *check.C) {
checkRedirect := func(command string) {
_, tty, err := pty.Open()
if err != nil {
- t.Fatalf("Could not open pty: %v", err)
+ c.Fatalf("Could not open pty: %v", err)
}
cmd := exec.Command("sh", "-c", command)
cmd.Stdin = tty
cmd.Stdout = tty
cmd.Stderr = tty
- ch := make(chan struct{})
if err := cmd.Start(); err != nil {
- t.Fatalf("start err: %v", err)
+ c.Fatalf("start err: %v", err)
}
+ ch := make(chan error)
go func() {
- if err := cmd.Wait(); err != nil {
- t.Fatalf("wait err=%v", err)
- }
+ ch <- cmd.Wait()
close(ch)
}()
select {
case <-time.After(10 * time.Second):
- t.Fatal("command timeout")
- case <-ch:
+ c.Fatal("command timeout")
+ case err := <-ch:
+ if err != nil {
+ c.Fatalf("wait err=%v", err)
+ }
}
}
checkRedirect(dockerBinary + " run -i busybox cat /etc/passwd | grep -q root")
checkRedirect(dockerBinary + " run busybox cat /etc/passwd | grep -q root")
-
- logDone("run - redirect stdout")
}
// Test recursive bind mount works by default
-func TestRunWithVolumesIsRecursive(t *testing.T) {
- defer deleteAllContainers()
-
+func (s *DockerSuite) TestRunWithVolumesIsRecursive(c *check.C) {
tmpDir, err := ioutil.TempDir("", "docker_recursive_mount_test")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer os.RemoveAll(tmpDir)
@@ -69,68 +64,62 @@ func TestRunWithVolumesIsRecursive(t *testing.T) {
// Create a temporary tmpfs mount.
tmpfsDir := filepath.Join(tmpDir, "tmpfs")
if err := os.MkdirAll(tmpfsDir, 0777); err != nil {
- t.Fatalf("failed to mkdir at %s - %s", tmpfsDir, err)
+ c.Fatalf("failed to mkdir at %s - %s", tmpfsDir, err)
}
if err := mount.Mount("tmpfs", tmpfsDir, "tmpfs", ""); err != nil {
- t.Fatalf("failed to create a tmpfs mount at %s - %s", tmpfsDir, err)
+ c.Fatalf("failed to create a tmpfs mount at %s - %s", tmpfsDir, err)
}
f, err := ioutil.TempFile(tmpfsDir, "touch-me")
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
defer f.Close()
runCmd := exec.Command(dockerBinary, "run", "--name", "test-data", "--volume", fmt.Sprintf("%s:/tmp:ro", tmpDir), "busybox:latest", "ls", "/tmp/tmpfs")
out, stderr, exitCode, err := runCommandWithStdoutStderr(runCmd)
if err != nil && exitCode != 0 {
- t.Fatal(out, stderr, err)
+ c.Fatal(out, stderr, err)
}
if !strings.Contains(out, filepath.Base(f.Name())) {
- t.Fatal("Recursive bind mount test failed. Expected file not found")
+ c.Fatal("Recursive bind mount test failed. Expected file not found")
}
-
- logDone("run - volumes are bind mounted recursively")
}
-func TestRunWithUlimits(t *testing.T) {
- testRequires(t, NativeExecDriver)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunWithUlimits(c *check.C) {
+ testRequires(c, NativeExecDriver)
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--name=testulimits", "--ulimit", "nofile=42", "busybox", "/bin/sh", "-c", "ulimit -n"))
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
ul := strings.TrimSpace(out)
if ul != "42" {
- t.Fatalf("expected `ulimit -n` to be 42, got %s", ul)
+ c.Fatalf("expected `ulimit -n` to be 42, got %s", ul)
}
-
- logDone("run - ulimits are set")
}
-func TestRunContainerWithCgroupParent(t *testing.T) {
- testRequires(t, NativeExecDriver)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunContainerWithCgroupParent(c *check.C) {
+ testRequires(c, NativeExecDriver)
cgroupParent := "test"
data, err := ioutil.ReadFile("/proc/self/cgroup")
if err != nil {
- t.Fatalf("failed to read '/proc/self/cgroup - %v", err)
+ c.Fatalf("failed to read '/proc/self/cgroup - %v", err)
}
selfCgroupPaths := parseCgroupPaths(string(data))
selfCpuCgroup, found := selfCgroupPaths["memory"]
if !found {
- t.Fatalf("unable to find self cpu cgroup path. CgroupsPath: %v", selfCgroupPaths)
+ c.Fatalf("unable to find self cpu cgroup path. CgroupsPath: %v", selfCgroupPaths)
}
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--cgroup-parent", cgroupParent, "--rm", "busybox", "cat", "/proc/self/cgroup"))
if err != nil {
- t.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err)
+ c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err)
}
cgroupPaths := parseCgroupPaths(string(out))
if len(cgroupPaths) == 0 {
- t.Fatalf("unexpected output - %q", string(out))
+ c.Fatalf("unexpected output - %q", string(out))
}
found = false
expectedCgroupPrefix := path.Join(selfCpuCgroup, cgroupParent)
@@ -141,24 +130,22 @@ func TestRunContainerWithCgroupParent(t *testing.T) {
}
}
if !found {
- t.Fatalf("unexpected cgroup paths. Expected at least one cgroup path to have prefix %q. Cgroup Paths: %v", expectedCgroupPrefix, cgroupPaths)
+ c.Fatalf("unexpected cgroup paths. Expected at least one cgroup path to have prefix %q. Cgroup Paths: %v", expectedCgroupPrefix, cgroupPaths)
}
- logDone("run - cgroup parent")
}
-func TestRunContainerWithCgroupParentAbsPath(t *testing.T) {
- testRequires(t, NativeExecDriver)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunContainerWithCgroupParentAbsPath(c *check.C) {
+ testRequires(c, NativeExecDriver)
cgroupParent := "/cgroup-parent/test"
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--cgroup-parent", cgroupParent, "--rm", "busybox", "cat", "/proc/self/cgroup"))
if err != nil {
- t.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err)
+ c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err)
}
cgroupPaths := parseCgroupPaths(string(out))
if len(cgroupPaths) == 0 {
- t.Fatalf("unexpected output - %q", string(out))
+ c.Fatalf("unexpected output - %q", string(out))
}
found := false
for _, path := range cgroupPaths {
@@ -168,36 +155,98 @@ func TestRunContainerWithCgroupParentAbsPath(t *testing.T) {
}
}
if !found {
- t.Fatalf("unexpected cgroup paths. Expected at least one cgroup path to have prefix %q. Cgroup Paths: %v", cgroupParent, cgroupPaths)
+ c.Fatalf("unexpected cgroup paths. Expected at least one cgroup path to have prefix %q. Cgroup Paths: %v", cgroupParent, cgroupPaths)
}
-
- logDone("run - cgroup parent with absolute cgroup path")
}
-func TestRunDeviceDirectory(t *testing.T) {
- testRequires(t, NativeExecDriver)
- defer deleteAllContainers()
+func (s *DockerSuite) TestRunDeviceDirectory(c *check.C) {
+ testRequires(c, NativeExecDriver)
cmd := exec.Command(dockerBinary, "run", "--device", "/dev/snd:/dev/snd", "busybox", "sh", "-c", "ls /dev/snd/")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actual := strings.Trim(out, "\r\n"); !strings.Contains(out, "timer") {
- t.Fatalf("expected output /dev/snd/timer, received %s", actual)
+ c.Fatalf("expected output /dev/snd/timer, received %s", actual)
}
cmd = exec.Command(dockerBinary, "run", "--device", "/dev/snd:/dev/othersnd", "busybox", "sh", "-c", "ls /dev/othersnd/")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
if actual := strings.Trim(out, "\r\n"); !strings.Contains(out, "seq") {
- t.Fatalf("expected output /dev/othersnd/seq, received %s", actual)
+ c.Fatalf("expected output /dev/othersnd/seq, received %s", actual)
+ }
+}
+
+// TestRunDetach checks attaching and detaching with the escape sequence.
+func (s *DockerSuite) TestRunAttachDetach(c *check.C) {
+ name := "attach-detach"
+ cmd := exec.Command(dockerBinary, "run", "--name", name, "-it", "busybox", "cat")
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ c.Fatal(err)
+ }
+ cpty, tty, err := pty.Open()
+ if err != nil {
+ c.Fatal(err)
+ }
+ defer cpty.Close()
+ cmd.Stdin = tty
+ if err := cmd.Start(); err != nil {
+ c.Fatal(err)
+ }
+ if err := waitRun(name); err != nil {
+ c.Fatal(err)
}
- logDone("run - test --device directory mounts all internal devices")
+ if _, err := cpty.Write([]byte("hello\n")); err != nil {
+ c.Fatal(err)
+ }
+
+ out, err := bufio.NewReader(stdout).ReadString('\n')
+ if err != nil {
+ c.Fatal(err)
+ }
+ if strings.TrimSpace(out) != "hello" {
+ c.Fatalf("expected 'hello', got %q", out)
+ }
+
+ // escape sequence
+ if _, err := cpty.Write([]byte{16}); err != nil {
+ c.Fatal(err)
+ }
+ time.Sleep(100 * time.Millisecond)
+ if _, err := cpty.Write([]byte{17}); err != nil {
+ c.Fatal(err)
+ }
+
+ ch := make(chan struct{})
+ go func() {
+ cmd.Wait()
+ ch <- struct{}{}
+ }()
+
+ running, err := inspectField(name, "State.Running")
+ if err != nil {
+ c.Fatal(err)
+ }
+ if running != "true" {
+ c.Fatal("expected container to still be running")
+ }
+
+ go func() {
+ exec.Command(dockerBinary, "kill", name).Run()
+ }()
+
+ select {
+ case <-ch:
+ case <-time.After(10 * time.Millisecond):
+ c.Fatal("timed out waiting for container to exit")
+ }
}
diff --git a/integration-cli/docker_cli_save_load_test.go b/integration-cli/docker_cli_save_load_test.go
index c7bfb945d38ea..f83f6645ac616 100644
--- a/integration-cli/docker_cli_save_load_test.go
+++ b/integration-cli/docker_cli_save_load_test.go
@@ -9,15 +9,16 @@ import (
"reflect"
"sort"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
// save a repo using gz compression and try to load it using stdout
-func TestSaveXzAndLoadRepoStdout(t *testing.T) {
+func (s *DockerSuite) TestSaveXzAndLoadRepoStdout(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("failed to create a container: %v %v", out, err)
+ c.Fatalf("failed to create a container: %v %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -27,19 +28,19 @@ func TestSaveXzAndLoadRepoStdout(t *testing.T) {
inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
out, _, err = runCommandWithOutput(inspectCmd)
if err != nil {
- t.Fatalf("output should've been a container id: %v %v", cleanedContainerID, err)
+ c.Fatalf("output should've been a container id: %v %v", cleanedContainerID, err)
}
commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, repoName)
out, _, err = runCommandWithOutput(commitCmd)
if err != nil {
- t.Fatalf("failed to commit container: %v %v", out, err)
+ c.Fatalf("failed to commit container: %v %v", out, err)
}
inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
before, _, err := runCommandWithOutput(inspectCmd)
if err != nil {
- t.Fatalf("the repo should exist before saving it: %v %v", before, err)
+ c.Fatalf("the repo should exist before saving it: %v %v", before, err)
}
repoTarball, _, err := runCommandPipelineWithOutput(
@@ -47,7 +48,7 @@ func TestSaveXzAndLoadRepoStdout(t *testing.T) {
exec.Command("xz", "-c"),
exec.Command("gzip", "-c"))
if err != nil {
- t.Fatalf("failed to save repo: %v %v", out, err)
+ c.Fatalf("failed to save repo: %v %v", out, err)
}
deleteImages(repoName)
@@ -55,26 +56,25 @@ func TestSaveXzAndLoadRepoStdout(t *testing.T) {
loadCmd.Stdin = strings.NewReader(repoTarball)
out, _, err = runCommandWithOutput(loadCmd)
if err == nil {
- t.Fatalf("expected error, but succeeded with no error and output: %v", out)
+ c.Fatalf("expected error, but succeeded with no error and output: %v", out)
}
inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
after, _, err := runCommandWithOutput(inspectCmd)
if err == nil {
- t.Fatalf("the repo should not exist: %v", after)
+ c.Fatalf("the repo should not exist: %v", after)
}
deleteImages(repoName)
- logDone("load - save a repo with xz compression & load it using stdout")
}
// save a repo using xz+gz compression and try to load it using stdout
-func TestSaveXzGzAndLoadRepoStdout(t *testing.T) {
+func (s *DockerSuite) TestSaveXzGzAndLoadRepoStdout(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("failed to create a container: %v %v", out, err)
+ c.Fatalf("failed to create a container: %v %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -84,19 +84,19 @@ func TestSaveXzGzAndLoadRepoStdout(t *testing.T) {
inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
out, _, err = runCommandWithOutput(inspectCmd)
if err != nil {
- t.Fatalf("output should've been a container id: %v %v", cleanedContainerID, err)
+ c.Fatalf("output should've been a container id: %v %v", cleanedContainerID, err)
}
commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, repoName)
out, _, err = runCommandWithOutput(commitCmd)
if err != nil {
- t.Fatalf("failed to commit container: %v %v", out, err)
+ c.Fatalf("failed to commit container: %v %v", out, err)
}
inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
before, _, err := runCommandWithOutput(inspectCmd)
if err != nil {
- t.Fatalf("the repo should exist before saving it: %v %v", before, err)
+ c.Fatalf("the repo should exist before saving it: %v %v", before, err)
}
out, _, err = runCommandPipelineWithOutput(
@@ -104,7 +104,7 @@ func TestSaveXzGzAndLoadRepoStdout(t *testing.T) {
exec.Command("xz", "-c"),
exec.Command("gzip", "-c"))
if err != nil {
- t.Fatalf("failed to save repo: %v %v", out, err)
+ c.Fatalf("failed to save repo: %v %v", out, err)
}
deleteImages(repoName)
@@ -113,34 +113,32 @@ func TestSaveXzGzAndLoadRepoStdout(t *testing.T) {
loadCmd.Stdin = strings.NewReader(out)
out, _, err = runCommandWithOutput(loadCmd)
if err == nil {
- t.Fatalf("expected error, but succeeded with no error and output: %v", out)
+ c.Fatalf("expected error, but succeeded with no error and output: %v", out)
}
inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
after, _, err := runCommandWithOutput(inspectCmd)
if err == nil {
- t.Fatalf("the repo should not exist: %v", after)
+ c.Fatalf("the repo should not exist: %v", after)
}
deleteContainer(cleanedContainerID)
deleteImages(repoName)
- logDone("load - save a repo with xz+gz compression & load it using stdout")
}
-func TestSaveSingleTag(t *testing.T) {
+func (s *DockerSuite) TestSaveSingleTag(c *check.C) {
repoName := "foobar-save-single-tag-test"
tagCmd := exec.Command(dockerBinary, "tag", "busybox:latest", fmt.Sprintf("%v:latest", repoName))
- defer deleteImages(repoName)
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
- t.Fatalf("failed to tag repo: %s, %v", out, err)
+ c.Fatalf("failed to tag repo: %s, %v", out, err)
}
idCmd := exec.Command(dockerBinary, "images", "-q", "--no-trunc", repoName)
out, _, err := runCommandWithOutput(idCmd)
if err != nil {
- t.Fatalf("failed to get repo ID: %s, %v", out, err)
+ c.Fatalf("failed to get repo ID: %s, %v", out, err)
}
cleanedImageID := strings.TrimSpace(out)
@@ -149,25 +147,23 @@ func TestSaveSingleTag(t *testing.T) {
exec.Command("tar", "t"),
exec.Command("grep", "-E", fmt.Sprintf("(^repositories$|%v)", cleanedImageID)))
if err != nil {
- t.Fatalf("failed to save repo with image ID and 'repositories' file: %s, %v", out, err)
+ c.Fatalf("failed to save repo with image ID and 'repositories' file: %s, %v", out, err)
}
- logDone("save - save a specific image:tag")
}
-func TestSaveImageId(t *testing.T) {
+func (s *DockerSuite) TestSaveImageId(c *check.C) {
repoName := "foobar-save-image-id-test"
tagCmd := exec.Command(dockerBinary, "tag", "emptyfs:latest", fmt.Sprintf("%v:latest", repoName))
- defer deleteImages(repoName)
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
- t.Fatalf("failed to tag repo: %s, %v", out, err)
+ c.Fatalf("failed to tag repo: %s, %v", out, err)
}
idLongCmd := exec.Command(dockerBinary, "images", "-q", "--no-trunc", repoName)
out, _, err := runCommandWithOutput(idLongCmd)
if err != nil {
- t.Fatalf("failed to get repo ID: %s, %v", out, err)
+ c.Fatalf("failed to get repo ID: %s, %v", out, err)
}
cleanedLongImageID := strings.TrimSpace(out)
@@ -175,7 +171,7 @@ func TestSaveImageId(t *testing.T) {
idShortCmd := exec.Command(dockerBinary, "images", "-q", repoName)
out, _, err = runCommandWithOutput(idShortCmd)
if err != nil {
- t.Fatalf("failed to get repo short ID: %s, %v", out, err)
+ c.Fatalf("failed to get repo short ID: %s, %v", out, err)
}
cleanedShortImageID := strings.TrimSpace(out)
@@ -184,19 +180,19 @@ func TestSaveImageId(t *testing.T) {
tarCmd := exec.Command("tar", "t")
tarCmd.Stdin, err = saveCmd.StdoutPipe()
if err != nil {
- t.Fatalf("cannot set stdout pipe for tar: %v", err)
+ c.Fatalf("cannot set stdout pipe for tar: %v", err)
}
grepCmd := exec.Command("grep", cleanedLongImageID)
grepCmd.Stdin, err = tarCmd.StdoutPipe()
if err != nil {
- t.Fatalf("cannot set stdout pipe for grep: %v", err)
+ c.Fatalf("cannot set stdout pipe for grep: %v", err)
}
if err = tarCmd.Start(); err != nil {
- t.Fatalf("tar failed with error: %v", err)
+ c.Fatalf("tar failed with error: %v", err)
}
if err = saveCmd.Start(); err != nil {
- t.Fatalf("docker save failed with error: %v", err)
+ c.Fatalf("docker save failed with error: %v", err)
}
defer saveCmd.Wait()
defer tarCmd.Wait()
@@ -204,40 +200,38 @@ func TestSaveImageId(t *testing.T) {
out, _, err = runCommandWithOutput(grepCmd)
if err != nil {
- t.Fatalf("failed to save repo with image ID: %s, %v", out, err)
+ c.Fatalf("failed to save repo with image ID: %s, %v", out, err)
}
- logDone("save - save a image by ID")
}
// save a repo and try to load it using flags
-func TestSaveAndLoadRepoFlags(t *testing.T) {
+func (s *DockerSuite) TestSaveAndLoadRepoFlags(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("failed to create a container: %s, %v", out, err)
+ c.Fatalf("failed to create a container: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
- defer deleteContainer(cleanedContainerID)
repoName := "foobar-save-load-test"
inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
if out, _, err = runCommandWithOutput(inspectCmd); err != nil {
- t.Fatalf("output should've been a container id: %s, %v", out, err)
+ c.Fatalf("output should've been a container id: %s, %v", out, err)
}
commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, repoName)
deleteImages(repoName)
if out, _, err = runCommandWithOutput(commitCmd); err != nil {
- t.Fatalf("failed to commit container: %s, %v", out, err)
+ c.Fatalf("failed to commit container: %s, %v", out, err)
}
inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
before, _, err := runCommandWithOutput(inspectCmd)
if err != nil {
- t.Fatalf("the repo should exist before saving it: %s, %v", before, err)
+ c.Fatalf("the repo should exist before saving it: %s, %v", before, err)
}
@@ -245,39 +239,36 @@ func TestSaveAndLoadRepoFlags(t *testing.T) {
exec.Command(dockerBinary, "save", repoName),
exec.Command(dockerBinary, "load"))
if err != nil {
- t.Fatalf("failed to save and load repo: %s, %v", out, err)
+ c.Fatalf("failed to save and load repo: %s, %v", out, err)
}
inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
after, _, err := runCommandWithOutput(inspectCmd)
if err != nil {
- t.Fatalf("the repo should exist after loading it: %s, %v", after, err)
+ c.Fatalf("the repo should exist after loading it: %s, %v", after, err)
}
if before != after {
- t.Fatalf("inspect is not the same after a save / load")
+ c.Fatalf("inspect is not the same after a save / load")
}
- logDone("save - save a repo using -o && load a repo using -i")
}
-func TestSaveMultipleNames(t *testing.T) {
+func (s *DockerSuite) TestSaveMultipleNames(c *check.C) {
repoName := "foobar-save-multi-name-test"
// Make one image
tagCmd := exec.Command(dockerBinary, "tag", "emptyfs:latest", fmt.Sprintf("%v-one:latest", repoName))
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
- t.Fatalf("failed to tag repo: %s, %v", out, err)
+ c.Fatalf("failed to tag repo: %s, %v", out, err)
}
- defer deleteImages(repoName + "-one")
// Make two images
tagCmd = exec.Command(dockerBinary, "tag", "emptyfs:latest", fmt.Sprintf("%v-two:latest", repoName))
out, _, err := runCommandWithOutput(tagCmd)
if err != nil {
- t.Fatalf("failed to tag repo: %s, %v", out, err)
+ c.Fatalf("failed to tag repo: %s, %v", out, err)
}
- defer deleteImages(repoName + "-two")
out, _, err = runCommandPipelineWithOutput(
exec.Command(dockerBinary, "save", fmt.Sprintf("%v-one", repoName), fmt.Sprintf("%v-two:latest", repoName)),
@@ -285,13 +276,12 @@ func TestSaveMultipleNames(t *testing.T) {
exec.Command("grep", "-q", "-E", "(-one|-two)"),
)
if err != nil {
- t.Fatalf("failed to save multiple repos: %s, %v", out, err)
+ c.Fatalf("failed to save multiple repos: %s, %v", out, err)
}
- logDone("save - save by multiple names")
}
-func TestSaveRepoWithMultipleImages(t *testing.T) {
+func (s *DockerSuite) TestSaveRepoWithMultipleImages(c *check.C) {
makeImage := func(from string, tag string) string {
runCmd := exec.Command(dockerBinary, "run", "-d", from, "true")
@@ -300,14 +290,13 @@ func TestSaveRepoWithMultipleImages(t *testing.T) {
err error
)
if out, _, err = runCommandWithOutput(runCmd); err != nil {
- t.Fatalf("failed to create a container: %v %v", out, err)
+ c.Fatalf("failed to create a container: %v %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
- defer deleteContainer(cleanedContainerID)
commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, tag)
if out, _, err = runCommandWithOutput(commitCmd); err != nil {
- t.Fatalf("failed to commit container: %v %v", out, err)
+ c.Fatalf("failed to commit container: %v %v", out, err)
}
imageID := strings.TrimSpace(out)
return imageID
@@ -318,9 +307,7 @@ func TestSaveRepoWithMultipleImages(t *testing.T) {
tagBar := repoName + ":bar"
idFoo := makeImage("busybox:latest", tagFoo)
- defer deleteImages(idFoo)
idBar := makeImage("busybox:latest", tagBar)
- defer deleteImages(idBar)
deleteImages(repoName)
@@ -331,14 +318,14 @@ func TestSaveRepoWithMultipleImages(t *testing.T) {
exec.Command("grep", "VERSION"),
exec.Command("cut", "-d", "/", "-f1"))
if err != nil {
- t.Fatalf("failed to save multiple images: %s, %v", out, err)
+ c.Fatalf("failed to save multiple images: %s, %v", out, err)
}
actual := strings.Split(strings.TrimSpace(out), "\n")
// make the list of expected layers
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "history", "-q", "--no-trunc", "busybox:latest"))
if err != nil {
- t.Fatalf("failed to get history: %s, %v", out, err)
+ c.Fatalf("failed to get history: %s, %v", out, err)
}
expected := append(strings.Split(strings.TrimSpace(out), "\n"), idFoo, idBar)
@@ -346,46 +333,44 @@ func TestSaveRepoWithMultipleImages(t *testing.T) {
sort.Strings(actual)
sort.Strings(expected)
if !reflect.DeepEqual(expected, actual) {
- t.Fatalf("achive does not contains the right layers: got %v, expected %v", actual, expected)
+ c.Fatalf("archive does not contains the right layers: got %v, expected %v", actual, expected)
}
- logDone("save - save repository with multiple images")
}
// Issue #6722 #5892 ensure directories are included in changes
-func TestSaveDirectoryPermissions(t *testing.T) {
+func (s *DockerSuite) TestSaveDirectoryPermissions(c *check.C) {
layerEntries := []string{"opt/", "opt/a/", "opt/a/b/", "opt/a/b/c"}
layerEntriesAUFS := []string{"./", ".wh..wh.aufs", ".wh..wh.orph/", ".wh..wh.plnk/", "opt/", "opt/a/", "opt/a/b/", "opt/a/b/c"}
name := "save-directory-permissions"
tmpDir, err := ioutil.TempDir("", "save-layers-with-directories")
if err != nil {
- t.Errorf("failed to create temporary directory: %s", err)
+ c.Errorf("failed to create temporary directory: %s", err)
}
extractionDirectory := filepath.Join(tmpDir, "image-extraction-dir")
os.Mkdir(extractionDirectory, 0777)
defer os.RemoveAll(tmpDir)
- defer deleteImages(name)
_, err = buildImage(name,
`FROM busybox
RUN adduser -D user && mkdir -p /opt/a/b && chown -R user:user /opt/a
RUN touch /opt/a/b/c && chown user:user /opt/a/b/c`,
true)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
if out, _, err := runCommandPipelineWithOutput(
exec.Command(dockerBinary, "save", name),
exec.Command("tar", "-xf", "-", "-C", extractionDirectory),
); err != nil {
- t.Errorf("failed to save and extract image: %s", out)
+ c.Errorf("failed to save and extract image: %s", out)
}
dirs, err := ioutil.ReadDir(extractionDirectory)
if err != nil {
- t.Errorf("failed to get a listing of the layer directories: %s", err)
+ c.Errorf("failed to get a listing of the layer directories: %s", err)
}
found := false
@@ -396,7 +381,7 @@ func TestSaveDirectoryPermissions(t *testing.T) {
f, err := os.Open(layerPath)
if err != nil {
- t.Fatalf("failed to open %s: %s", layerPath, err)
+ c.Fatalf("failed to open %s: %s", layerPath, err)
}
entries, err := ListTar(f)
@@ -406,7 +391,7 @@ func TestSaveDirectoryPermissions(t *testing.T) {
}
}
if err != nil {
- t.Fatalf("encountered error while listing tar entries: %s", err)
+ c.Fatalf("encountered error while listing tar entries: %s", err)
}
if reflect.DeepEqual(entriesSansDev, layerEntries) || reflect.DeepEqual(entriesSansDev, layerEntriesAUFS) {
@@ -417,8 +402,7 @@ func TestSaveDirectoryPermissions(t *testing.T) {
}
if !found {
- t.Fatalf("failed to find the layer with the right content listing")
+ c.Fatalf("failed to find the layer with the right content listing")
}
- logDone("save - ensure directories exist in exported layers")
}
diff --git a/integration-cli/docker_cli_save_load_unix_test.go b/integration-cli/docker_cli_save_load_unix_test.go
index 7eb948d7aec33..658666d6b806e 100644
--- a/integration-cli/docker_cli_save_load_unix_test.go
+++ b/integration-cli/docker_cli_save_load_unix_test.go
@@ -8,17 +8,17 @@ import (
"os"
"os/exec"
"strings"
- "testing"
"github.com/docker/docker/vendor/src/github.com/kr/pty"
+ "github.com/go-check/check"
)
// save a repo and try to load it using stdout
-func TestSaveAndLoadRepoStdout(t *testing.T) {
+func (s *DockerSuite) TestSaveAndLoadRepoStdout(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("failed to create a container: %s, %v", out, err)
+ c.Fatalf("failed to create a container: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -27,25 +27,25 @@ func TestSaveAndLoadRepoStdout(t *testing.T) {
inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
if out, _, err = runCommandWithOutput(inspectCmd); err != nil {
- t.Fatalf("output should've been a container id: %s, %v", out, err)
+ c.Fatalf("output should've been a container id: %s, %v", out, err)
}
commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, repoName)
if out, _, err = runCommandWithOutput(commitCmd); err != nil {
- t.Fatalf("failed to commit container: %s, %v", out, err)
+ c.Fatalf("failed to commit container: %s, %v", out, err)
}
inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
before, _, err := runCommandWithOutput(inspectCmd)
if err != nil {
- t.Fatalf("the repo should exist before saving it: %s, %v", before, err)
+ c.Fatalf("the repo should exist before saving it: %s, %v", before, err)
}
saveCmdTemplate := `%v save %v > /tmp/foobar-save-load-test.tar`
saveCmdFinal := fmt.Sprintf(saveCmdTemplate, dockerBinary, repoName)
saveCmd := exec.Command("bash", "-c", saveCmdFinal)
if out, _, err = runCommandWithOutput(saveCmd); err != nil {
- t.Fatalf("failed to save repo: %s, %v", out, err)
+ c.Fatalf("failed to save repo: %s, %v", out, err)
}
deleteImages(repoName)
@@ -53,17 +53,17 @@ func TestSaveAndLoadRepoStdout(t *testing.T) {
loadCmdFinal := `cat /tmp/foobar-save-load-test.tar | docker load`
loadCmd := exec.Command("bash", "-c", loadCmdFinal)
if out, _, err = runCommandWithOutput(loadCmd); err != nil {
- t.Fatalf("failed to load repo: %s, %v", out, err)
+ c.Fatalf("failed to load repo: %s, %v", out, err)
}
inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
after, _, err := runCommandWithOutput(inspectCmd)
if err != nil {
- t.Fatalf("the repo should exist after loading it: %s %v", after, err)
+ c.Fatalf("the repo should exist after loading it: %s %v", after, err)
}
if before != after {
- t.Fatalf("inspect is not the same after a save / load")
+ c.Fatalf("inspect is not the same after a save / load")
}
deleteContainer(cleanedContainerID)
@@ -73,29 +73,28 @@ func TestSaveAndLoadRepoStdout(t *testing.T) {
pty, tty, err := pty.Open()
if err != nil {
- t.Fatalf("Could not open pty: %v", err)
+ c.Fatalf("Could not open pty: %v", err)
}
cmd := exec.Command(dockerBinary, "save", repoName)
cmd.Stdin = tty
cmd.Stdout = tty
cmd.Stderr = tty
if err := cmd.Start(); err != nil {
- t.Fatalf("start err: %v", err)
+ c.Fatalf("start err: %v", err)
}
if err := cmd.Wait(); err == nil {
- t.Fatal("did not break writing to a TTY")
+ c.Fatal("did not break writing to a TTY")
}
buf := make([]byte, 1024)
n, err := pty.Read(buf)
if err != nil {
- t.Fatal("could not read tty output")
+ c.Fatal("could not read tty output")
}
if !bytes.Contains(buf[:n], []byte("Cowardly refusing")) {
- t.Fatal("help output is not being yielded", out)
+ c.Fatal("help output is not being yielded", out)
}
- logDone("save - save/load a repo using stdout")
}
diff --git a/integration-cli/docker_cli_search_test.go b/integration-cli/docker_cli_search_test.go
index a3546103f39e5..c5ecdd03b9c11 100644
--- a/integration-cli/docker_cli_search_test.go
+++ b/integration-cli/docker_cli_search_test.go
@@ -3,45 +3,93 @@ package main
import (
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
// search for repos named "registry" on the central registry
-func TestSearchOnCentralRegistry(t *testing.T) {
- testRequires(t, Network)
+func (s *DockerSuite) TestSearchOnCentralRegistry(c *check.C) {
+ testRequires(c, Network)
searchCmd := exec.Command(dockerBinary, "search", "busybox")
out, exitCode, err := runCommandWithOutput(searchCmd)
if err != nil || exitCode != 0 {
- t.Fatalf("failed to search on the central registry: %s, %v", out, err)
+ c.Fatalf("failed to search on the central registry: %s, %v", out, err)
}
if !strings.Contains(out, "Busybox base image.") {
- t.Fatal("couldn't find any repository named (or containing) 'Busybox base image.'")
+ c.Fatal("couldn't find any repository named (or containing) 'Busybox base image.'")
}
- logDone("search - search for repositories named (or containing) 'Busybox base image.'")
}
-func TestSearchStarsOptionWithWrongParameter(t *testing.T) {
+func (s *DockerSuite) TestSearchStarsOptionWithWrongParameter(c *check.C) {
searchCmdStarsChars := exec.Command(dockerBinary, "search", "--stars=a", "busybox")
out, exitCode, err := runCommandWithOutput(searchCmdStarsChars)
if err == nil || exitCode == 0 {
- t.Fatalf("Should not get right information: %s, %v", out, err)
+ c.Fatalf("Should not get right information: %s, %v", out, err)
}
if !strings.Contains(out, "invalid value") {
- t.Fatal("couldn't find the invalid value warning")
+ c.Fatal("couldn't find the invalid value warning")
}
searchCmdStarsNegativeNumber := exec.Command(dockerBinary, "search", "-s=-1", "busybox")
out, exitCode, err = runCommandWithOutput(searchCmdStarsNegativeNumber)
if err == nil || exitCode == 0 {
- t.Fatalf("Should not get right information: %s, %v", out, err)
+ c.Fatalf("Should not get right information: %s, %v", out, err)
}
if !strings.Contains(out, "invalid value") {
- t.Fatal("couldn't find the invalid value warning")
+ c.Fatal("couldn't find the invalid value warning")
+ }
+
+}
+
+func (s *DockerSuite) TestSearchCmdOptions(c *check.C) {
+ testRequires(c, Network)
+ searchCmdhelp := exec.Command(dockerBinary, "search", "--help")
+ out, exitCode, err := runCommandWithOutput(searchCmdhelp)
+ if err != nil || exitCode != 0 {
+ c.Fatalf("failed to get search help information: %s, %v", out, err)
+ }
+
+ if !strings.Contains(out, "Usage: docker search [OPTIONS] TERM") {
+ c.Fatalf("failed to show docker search usage: %s, %v", out, err)
+ }
+
+ searchCmd := exec.Command(dockerBinary, "search", "busybox")
+ outSearchCmd, exitCode, err := runCommandWithOutput(searchCmd)
+ if err != nil || exitCode != 0 {
+ c.Fatalf("failed to search on the central registry: %s, %v", outSearchCmd, err)
+ }
+
+ searchCmdautomated := exec.Command(dockerBinary, "search", "--automated=true", "busybox")
+ outSearchCmdautomated, exitCode, err := runCommandWithOutput(searchCmdautomated) //The busybox is a busybox base image, not an AUTOMATED image.
+ if err != nil || exitCode != 0 {
+ c.Fatalf("failed to search with automated=true on the central registry: %s, %v", outSearchCmdautomated, err)
+ }
+
+ outSearchCmdautomatedSlice := strings.Split(outSearchCmdautomated, "\n")
+ for i := range outSearchCmdautomatedSlice {
+ if strings.HasPrefix(outSearchCmdautomatedSlice[i], "busybox ") {
+ c.Fatalf("The busybox is not an AUTOMATED image: %s, %v", out, err)
+ }
+ }
+
+ searchCmdStars := exec.Command(dockerBinary, "search", "-s=2", "busybox")
+ outSearchCmdStars, exitCode, err := runCommandWithOutput(searchCmdStars)
+ if err != nil || exitCode != 0 {
+ c.Fatalf("failed to search with stars=2 on the central registry: %s, %v", outSearchCmdStars, err)
+ }
+
+ if strings.Count(outSearchCmdStars, "[OK]") > strings.Count(outSearchCmd, "[OK]") {
+ c.Fatalf("The quantity of images with stars should be less than that of all images: %s, %v", outSearchCmdStars, err)
+ }
+
+ searchCmdOptions := exec.Command(dockerBinary, "search", "--stars=2", "--automated=true", "--no-trunc=true", "busybox")
+ out, exitCode, err = runCommandWithOutput(searchCmdOptions)
+ if err != nil || exitCode != 0 {
+ c.Fatalf("failed to search with stars&automated&no-trunc options on the central registry: %s, %v", out, err)
}
- logDone("search - Verify search with wrong parameter.")
}
diff --git a/integration-cli/docker_cli_start_test.go b/integration-cli/docker_cli_start_test.go
index 25b23e888f4b1..fddc8c97bbf0d 100644
--- a/integration-cli/docker_cli_start_test.go
+++ b/integration-cli/docker_cli_start_test.go
@@ -4,49 +4,48 @@ import (
"fmt"
"os/exec"
"strings"
- "testing"
"time"
+
+ "github.com/go-check/check"
)
// Regression test for https://github.com/docker/docker/issues/7843
-func TestStartAttachReturnsOnError(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestStartAttachReturnsOnError(c *check.C) {
- dockerCmd(t, "run", "-d", "--name", "test", "busybox")
- dockerCmd(t, "wait", "test")
+ dockerCmd(c, "run", "-d", "--name", "test", "busybox")
+ dockerCmd(c, "wait", "test")
// Expect this to fail because the above container is stopped, this is what we want
if _, err := runCommand(exec.Command(dockerBinary, "run", "-d", "--name", "test2", "--link", "test:test", "busybox")); err == nil {
- t.Fatal("Expected error but got none")
+ c.Fatal("Expected error but got none")
}
- ch := make(chan struct{})
+ ch := make(chan error)
go func() {
// Attempt to start attached to the container that won't start
// This should return an error immediately since the container can't be started
if _, err := runCommand(exec.Command(dockerBinary, "start", "-a", "test2")); err == nil {
- t.Fatal("Expected error but got none")
+ ch <- fmt.Errorf("Expected error but got none")
}
close(ch)
}()
select {
- case <-ch:
+ case err := <-ch:
+ c.Assert(err, check.IsNil)
case <-time.After(time.Second):
- t.Fatalf("Attach did not exit properly")
+ c.Fatalf("Attach did not exit properly")
}
- logDone("start - error on start with attach exits")
}
// gh#8555: Exit code should be passed through when using start -a
-func TestStartAttachCorrectExitCode(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestStartAttachCorrectExitCode(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", "sleep 2; exit 1")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
out = strings.TrimSpace(out)
@@ -54,203 +53,191 @@ func TestStartAttachCorrectExitCode(t *testing.T) {
// make sure the container has exited before trying the "start -a"
waitCmd := exec.Command(dockerBinary, "wait", out)
if _, _, err = runCommandWithOutput(waitCmd); err != nil {
- t.Fatalf("Failed to wait on container: %v", err)
+ c.Fatalf("Failed to wait on container: %v", err)
}
startCmd := exec.Command(dockerBinary, "start", "-a", out)
startOut, exitCode, err := runCommandWithOutput(startCmd)
if err != nil && !strings.Contains("exit status 1", fmt.Sprintf("%s", err)) {
- t.Fatalf("start command failed unexpectedly with error: %v, output: %q", err, startOut)
+ c.Fatalf("start command failed unexpectedly with error: %v, output: %q", err, startOut)
}
if exitCode != 1 {
- t.Fatalf("start -a did not respond with proper exit code: expected 1, got %d", exitCode)
+ c.Fatalf("start -a did not respond with proper exit code: expected 1, got %d", exitCode)
}
- logDone("start - correct exit code returned with -a")
}
-func TestStartSilentAttach(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestStartAttachSilent(c *check.C) {
name := "teststartattachcorrectexitcode"
runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "echo", "test")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
- t.Fatalf("failed to run container: %v, output: %q", err, out)
+ c.Fatalf("failed to run container: %v, output: %q", err, out)
}
// make sure the container has exited before trying the "start -a"
waitCmd := exec.Command(dockerBinary, "wait", name)
if _, _, err = runCommandWithOutput(waitCmd); err != nil {
- t.Fatalf("wait command failed with error: %v", err)
+ c.Fatalf("wait command failed with error: %v", err)
}
startCmd := exec.Command(dockerBinary, "start", "-a", name)
startOut, _, err := runCommandWithOutput(startCmd)
if err != nil {
- t.Fatalf("start command failed unexpectedly with error: %v, output: %q", err, startOut)
+ c.Fatalf("start command failed unexpectedly with error: %v, output: %q", err, startOut)
}
if expected := "test\n"; startOut != expected {
- t.Fatalf("start -a produced unexpected output: expected %q, got %q", expected, startOut)
+ c.Fatalf("start -a produced unexpected output: expected %q, got %q", expected, startOut)
}
- logDone("start - don't echo container ID when attaching")
}
-func TestStartRecordError(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestStartRecordError(c *check.C) {
// when container runs successfully, we should not have state.Error
- dockerCmd(t, "run", "-d", "-p", "9999:9999", "--name", "test", "busybox", "top")
+ dockerCmd(c, "run", "-d", "-p", "9999:9999", "--name", "test", "busybox", "top")
stateErr, err := inspectField("test", "State.Error")
if err != nil {
- t.Fatalf("Failed to inspect %q state's error, got error %q", "test", err)
+ c.Fatalf("Failed to inspect %q state's error, got error %q", "test", err)
}
if stateErr != "" {
- t.Fatalf("Expected to not have state error but got state.Error(%q)", stateErr)
+ c.Fatalf("Expected to not have state error but got state.Error(%q)", stateErr)
}
// Expect this to fail and records error because of ports conflict
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", "test2", "-p", "9999:9999", "busybox", "top"))
if err == nil {
- t.Fatalf("Expected error but got none, output %q", out)
+ c.Fatalf("Expected error but got none, output %q", out)
}
stateErr, err = inspectField("test2", "State.Error")
if err != nil {
- t.Fatalf("Failed to inspect %q state's error, got error %q", "test2", err)
+ c.Fatalf("Failed to inspect %q state's error, got error %q", "test2", err)
}
expected := "port is already allocated"
if stateErr == "" || !strings.Contains(stateErr, expected) {
- t.Fatalf("State.Error(%q) does not include %q", stateErr, expected)
+ c.Fatalf("State.Error(%q) does not include %q", stateErr, expected)
}
// Expect the conflict to be resolved when we stop the initial container
- dockerCmd(t, "stop", "test")
- dockerCmd(t, "start", "test2")
+ dockerCmd(c, "stop", "test")
+ dockerCmd(c, "start", "test2")
stateErr, err = inspectField("test2", "State.Error")
if err != nil {
- t.Fatalf("Failed to inspect %q state's error, got error %q", "test", err)
+ c.Fatalf("Failed to inspect %q state's error, got error %q", "test", err)
}
if stateErr != "" {
- t.Fatalf("Expected to not have state error but got state.Error(%q)", stateErr)
+ c.Fatalf("Expected to not have state error but got state.Error(%q)", stateErr)
}
- logDone("start - set state error when start is unsuccessful")
}
// gh#8726: a failed Start() breaks --volumes-from on subsequent Start()'s
-func TestStartVolumesFromFailsCleanly(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestStartVolumesFromFailsCleanly(c *check.C) {
// Create the first data volume
- dockerCmd(t, "run", "-d", "--name", "data_before", "-v", "/foo", "busybox")
+ dockerCmd(c, "run", "-d", "--name", "data_before", "-v", "/foo", "busybox")
// Expect this to fail because the data test after contaienr doesn't exist yet
if _, err := runCommand(exec.Command(dockerBinary, "run", "-d", "--name", "consumer", "--volumes-from", "data_before", "--volumes-from", "data_after", "busybox")); err == nil {
- t.Fatal("Expected error but got none")
+ c.Fatal("Expected error but got none")
}
// Create the second data volume
- dockerCmd(t, "run", "-d", "--name", "data_after", "-v", "/bar", "busybox")
+ dockerCmd(c, "run", "-d", "--name", "data_after", "-v", "/bar", "busybox")
// Now, all the volumes should be there
- dockerCmd(t, "start", "consumer")
+ dockerCmd(c, "start", "consumer")
// Check that we have the volumes we want
- out, _, _ := dockerCmd(t, "inspect", "--format='{{ len .Volumes }}'", "consumer")
+ out, _ := dockerCmd(c, "inspect", "--format='{{ len .Volumes }}'", "consumer")
nVolumes := strings.Trim(out, " \r\n'")
if nVolumes != "2" {
- t.Fatalf("Missing volumes: expected 2, got %s", nVolumes)
+ c.Fatalf("Missing volumes: expected 2, got %s", nVolumes)
}
- logDone("start - missing containers in --volumes-from did not affect subsequent runs")
}
-func TestStartPausedContainer(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestStartPausedContainer(c *check.C) {
defer unpauseAllContainers()
runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "top")
if out, _, err := runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
runCmd = exec.Command(dockerBinary, "pause", "testing")
if out, _, err := runCommandWithOutput(runCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
runCmd = exec.Command(dockerBinary, "start", "testing")
if out, _, err := runCommandWithOutput(runCmd); err == nil || !strings.Contains(out, "Cannot start a paused container, try unpause instead.") {
- t.Fatalf("an error should have been shown that you cannot start paused container: %s\n%v", out, err)
+ c.Fatalf("an error should have been shown that you cannot start paused container: %s\n%v", out, err)
}
- logDone("start - error should show if trying to start paused container")
}
-func TestStartMultipleContainers(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestStartMultipleContainers(c *check.C) {
// run a container named 'parent' and create two container link to `parent`
cmd := exec.Command(dockerBinary, "run", "-d", "--name", "parent", "busybox", "top")
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
for _, container := range []string{"child_first", "child_second"} {
cmd = exec.Command(dockerBinary, "create", "--name", container, "--link", "parent:parent", "busybox", "top")
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
}
// stop 'parent' container
cmd = exec.Command(dockerBinary, "stop", "parent")
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
cmd = exec.Command(dockerBinary, "inspect", "-f", "{{.State.Running}}", "parent")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
out = strings.Trim(out, "\r\n")
if out != "false" {
- t.Fatal("Container should be stopped")
+ c.Fatal("Container should be stopped")
}
- // start all the three containers, container `child_first` start first which should be faild
+ // start all the three containers, container `child_first` start first which should be failed
// container 'parent' start second and then start container 'child_second'
cmd = exec.Command(dockerBinary, "start", "child_first", "parent", "child_second")
out, _, err = runCommandWithOutput(cmd)
if !strings.Contains(out, "Cannot start container child_first") || err == nil {
- t.Fatal("Expected error but got none")
+ c.Fatal("Expected error but got none")
}
for container, expected := range map[string]string{"parent": "true", "child_first": "false", "child_second": "true"} {
cmd = exec.Command(dockerBinary, "inspect", "-f", "{{.State.Running}}", container)
out, _, err = runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
out = strings.Trim(out, "\r\n")
if out != expected {
- t.Fatal("Container running state wrong")
+ c.Fatal("Container running state wrong")
}
}
- logDone("start - start multiple containers continue on one failed")
}
-func TestStartAttachMultipleContainers(t *testing.T) {
+func (s *DockerSuite) TestStartAttachMultipleContainers(c *check.C) {
var cmd *exec.Cmd
- defer deleteAllContainers()
// run multiple containers to test
for _, container := range []string{"test1", "test2", "test3"} {
cmd = exec.Command(dockerBinary, "run", "-d", "--name", container, "busybox", "top")
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
}
@@ -258,7 +245,7 @@ func TestStartAttachMultipleContainers(t *testing.T) {
for _, container := range []string{"test1", "test2", "test3"} {
cmd = exec.Command(dockerBinary, "stop", container)
if out, _, err := runCommandWithOutput(cmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
}
@@ -267,7 +254,7 @@ func TestStartAttachMultipleContainers(t *testing.T) {
cmd = exec.Command(dockerBinary, "start", option, "test1", "test2", "test3")
out, _, err := runCommandWithOutput(cmd)
if !strings.Contains(out, "You cannot start and attach multiple containers at once.") || err == nil {
- t.Fatal("Expected error but got none")
+ c.Fatal("Expected error but got none")
}
}
@@ -276,13 +263,12 @@ func TestStartAttachMultipleContainers(t *testing.T) {
cmd = exec.Command(dockerBinary, "inspect", "-f", "{{.State.Running}}", container)
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
out = strings.Trim(out, "\r\n")
if out != expected {
- t.Fatal("Container running state wrong")
+ c.Fatal("Container running state wrong")
}
}
- logDone("start - error on start and attach multiple containers at once")
}
diff --git a/integration-cli/docker_cli_tag_test.go b/integration-cli/docker_cli_tag_test.go
index 8a5d322713534..35225f9c1e5ec 100644
--- a/integration-cli/docker_cli_tag_test.go
+++ b/integration-cli/docker_cli_tag_test.go
@@ -3,48 +3,40 @@ package main
import (
"os/exec"
"strings"
- "testing"
"github.com/docker/docker/pkg/stringutils"
+ "github.com/go-check/check"
)
// tagging a named image in a new unprefixed repo should work
-func TestTagUnprefixedRepoByName(t *testing.T) {
+func (s *DockerSuite) TestTagUnprefixedRepoByName(c *check.C) {
if err := pullImageIfNotExist("busybox:latest"); err != nil {
- t.Fatal("couldn't find the busybox:latest image locally and failed to pull it")
+ c.Fatal("couldn't find the busybox:latest image locally and failed to pull it")
}
tagCmd := exec.Command(dockerBinary, "tag", "busybox:latest", "testfoobarbaz")
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
-
- deleteImages("testfoobarbaz")
-
- logDone("tag - busybox -> testfoobarbaz")
}
// tagging an image by ID in a new unprefixed repo should work
-func TestTagUnprefixedRepoByID(t *testing.T) {
+func (s *DockerSuite) TestTagUnprefixedRepoByID(c *check.C) {
getIDCmd := exec.Command(dockerBinary, "inspect", "-f", "{{.Id}}", "busybox")
out, _, err := runCommandWithOutput(getIDCmd)
if err != nil {
- t.Fatalf("failed to get the image ID of busybox: %s, %v", out, err)
+ c.Fatalf("failed to get the image ID of busybox: %s, %v", out, err)
}
cleanedImageID := strings.TrimSpace(out)
tagCmd := exec.Command(dockerBinary, "tag", cleanedImageID, "testfoobarbaz")
if out, _, err = runCommandWithOutput(tagCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
-
- deleteImages("testfoobarbaz")
-
- logDone("tag - busybox's image ID -> testfoobarbaz")
}
// ensure we don't allow the use of invalid repository names; these tag operations should fail
-func TestTagInvalidUnprefixedRepo(t *testing.T) {
+func (s *DockerSuite) TestTagInvalidUnprefixedRepo(c *check.C) {
invalidRepos := []string{"fo$z$", "Foo@3cc", "Foo$3", "Foo*3", "Fo^3", "Foo!3", "F)xcz(", "fo%asd"}
@@ -52,14 +44,13 @@ func TestTagInvalidUnprefixedRepo(t *testing.T) {
tagCmd := exec.Command(dockerBinary, "tag", "busybox", repo)
_, _, err := runCommandWithOutput(tagCmd)
if err == nil {
- t.Fatalf("tag busybox %v should have failed", repo)
+ c.Fatalf("tag busybox %v should have failed", repo)
}
}
- logDone("tag - busybox invalid repo names --> must not work")
}
// ensure we don't allow the use of invalid tags; these tag operations should fail
-func TestTagInvalidPrefixedRepo(t *testing.T) {
+func (s *DockerSuite) TestTagInvalidPrefixedRepo(c *check.C) {
longTag := stringutils.GenerateRandomAlphaOnlyString(121)
invalidTags := []string{"repo:fo$z$", "repo:Foo@3cc", "repo:Foo$3", "repo:Foo*3", "repo:Fo^3", "repo:Foo!3", "repo:%goodbye", "repo:#hashtagit", "repo:F)xcz(", "repo:-foo", "repo:..", longTag}
@@ -68,16 +59,15 @@ func TestTagInvalidPrefixedRepo(t *testing.T) {
tagCmd := exec.Command(dockerBinary, "tag", "busybox", repotag)
_, _, err := runCommandWithOutput(tagCmd)
if err == nil {
- t.Fatalf("tag busybox %v should have failed", repotag)
+ c.Fatalf("tag busybox %v should have failed", repotag)
}
}
- logDone("tag - busybox with invalid repo:tagnames --> must not work")
}
// ensure we allow the use of valid tags
-func TestTagValidPrefixedRepo(t *testing.T) {
+func (s *DockerSuite) TestTagValidPrefixedRepo(c *check.C) {
if err := pullImageIfNotExist("busybox:latest"); err != nil {
- t.Fatal("couldn't find the busybox:latest image locally and failed to pull it")
+ c.Fatal("couldn't find the busybox:latest image locally and failed to pull it")
}
validRepos := []string{"fooo/bar", "fooaa/test", "foooo:t"}
@@ -86,56 +76,49 @@ func TestTagValidPrefixedRepo(t *testing.T) {
tagCmd := exec.Command(dockerBinary, "tag", "busybox:latest", repo)
_, _, err := runCommandWithOutput(tagCmd)
if err != nil {
- t.Errorf("tag busybox %v should have worked: %s", repo, err)
+ c.Errorf("tag busybox %v should have worked: %s", repo, err)
continue
}
deleteImages(repo)
}
- logDone("tag - tag valid prefixed repo")
}
// tag an image with an existed tag name without -f option should fail
-func TestTagExistedNameWithoutForce(t *testing.T) {
+func (s *DockerSuite) TestTagExistedNameWithoutForce(c *check.C) {
if err := pullImageIfNotExist("busybox:latest"); err != nil {
- t.Fatal("couldn't find the busybox:latest image locally and failed to pull it")
+ c.Fatal("couldn't find the busybox:latest image locally and failed to pull it")
}
tagCmd := exec.Command(dockerBinary, "tag", "busybox:latest", "busybox:test")
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
tagCmd = exec.Command(dockerBinary, "tag", "busybox:latest", "busybox:test")
out, _, err := runCommandWithOutput(tagCmd)
if err == nil || !strings.Contains(out, "Conflict: Tag test is already set to image") {
- t.Fatal("tag busybox busybox:test should have failed,because busybox:test is existed")
+ c.Fatal("tag busybox busybox:test should have failed,because busybox:test is existed")
}
- deleteImages("busybox:test")
-
- logDone("tag - busybox with an existed tag name without -f option --> must not work")
}
// tag an image with an existed tag name with -f option should work
-func TestTagExistedNameWithForce(t *testing.T) {
+func (s *DockerSuite) TestTagExistedNameWithForce(c *check.C) {
if err := pullImageIfNotExist("busybox:latest"); err != nil {
- t.Fatal("couldn't find the busybox:latest image locally and failed to pull it")
+ c.Fatal("couldn't find the busybox:latest image locally and failed to pull it")
}
tagCmd := exec.Command(dockerBinary, "tag", "busybox:latest", "busybox:test")
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
tagCmd = exec.Command(dockerBinary, "tag", "-f", "busybox:latest", "busybox:test")
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
- deleteImages("busybox:test")
-
- logDone("tag - busybox with an existed tag name with -f option work")
}
// ensure tagging using official names works
// ensure all tags result in the same name
-func TestTagOfficialNames(t *testing.T) {
+func (s *DockerSuite) TestTagOfficialNames(c *check.C) {
names := []string{
"docker.io/busybox",
"index.docker.io/busybox",
@@ -148,7 +131,7 @@ func TestTagOfficialNames(t *testing.T) {
tagCmd := exec.Command(dockerBinary, "tag", "-f", "busybox:latest", name+":latest")
out, exitCode, err := runCommandWithOutput(tagCmd)
if err != nil || exitCode != 0 {
- t.Errorf("tag busybox %v should have worked: %s, %s", name, err, out)
+ c.Errorf("tag busybox %v should have worked: %s, %s", name, err, out)
continue
}
@@ -156,9 +139,9 @@ func TestTagOfficialNames(t *testing.T) {
imagesCmd := exec.Command(dockerBinary, "images")
out, _, err = runCommandWithOutput(imagesCmd)
if err != nil {
- t.Errorf("listing images failed with errors: %v, %s", err, out)
+ c.Errorf("listing images failed with errors: %v, %s", err, out)
} else if strings.Contains(out, name) {
- t.Errorf("images should not have listed '%s'", name)
+ c.Errorf("images should not have listed '%s'", name)
deleteImages(name + ":latest")
}
}
@@ -167,10 +150,9 @@ func TestTagOfficialNames(t *testing.T) {
tagCmd := exec.Command(dockerBinary, "tag", "-f", name+":latest", "fooo/bar:latest")
_, exitCode, err := runCommandWithOutput(tagCmd)
if err != nil || exitCode != 0 {
- t.Errorf("tag %v fooo/bar should have worked: %s", name, err)
+ c.Errorf("tag %v fooo/bar should have worked: %s", name, err)
continue
}
deleteImages("fooo/bar:latest")
}
- logDone("tag - tag official names")
}
diff --git a/integration-cli/docker_cli_top_test.go b/integration-cli/docker_cli_top_test.go
index b5dca0be983fd..f941a42cd0515 100644
--- a/integration-cli/docker_cli_top_test.go
+++ b/integration-cli/docker_cli_top_test.go
@@ -3,37 +3,36 @@ package main
import (
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
-func TestTopMultipleArgs(t *testing.T) {
+func (s *DockerSuite) TestTopMultipleArgs(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-i", "-d", "busybox", "top")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("failed to start the container: %s, %v", out, err)
+ c.Fatalf("failed to start the container: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
- defer deleteContainer(cleanedContainerID)
topCmd := exec.Command(dockerBinary, "top", cleanedContainerID, "-o", "pid")
out, _, err = runCommandWithOutput(topCmd)
if err != nil {
- t.Fatalf("failed to run top: %s, %v", out, err)
+ c.Fatalf("failed to run top: %s, %v", out, err)
}
if !strings.Contains(out, "PID") {
- t.Fatalf("did not see PID after top -o pid: %s", out)
+ c.Fatalf("did not see PID after top -o pid: %s", out)
}
- logDone("top - multiple arguments")
}
-func TestTopNonPrivileged(t *testing.T) {
+func (s *DockerSuite) TestTopNonPrivileged(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-i", "-d", "busybox", "top")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("failed to start the container: %s, %v", out, err)
+ c.Fatalf("failed to start the container: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -41,38 +40,37 @@ func TestTopNonPrivileged(t *testing.T) {
topCmd := exec.Command(dockerBinary, "top", cleanedContainerID)
out1, _, err := runCommandWithOutput(topCmd)
if err != nil {
- t.Fatalf("failed to run top: %s, %v", out1, err)
+ c.Fatalf("failed to run top: %s, %v", out1, err)
}
topCmd = exec.Command(dockerBinary, "top", cleanedContainerID)
out2, _, err := runCommandWithOutput(topCmd)
if err != nil {
- t.Fatalf("failed to run top: %s, %v", out2, err)
+ c.Fatalf("failed to run top: %s, %v", out2, err)
}
killCmd := exec.Command(dockerBinary, "kill", cleanedContainerID)
if out, _, err = runCommandWithOutput(killCmd); err != nil {
- t.Fatalf("failed to kill container: %s, %v", out, err)
+ c.Fatalf("failed to kill container: %s, %v", out, err)
}
deleteContainer(cleanedContainerID)
if !strings.Contains(out1, "top") && !strings.Contains(out2, "top") {
- t.Fatal("top should've listed `top` in the process list, but failed twice")
+ c.Fatal("top should've listed `top` in the process list, but failed twice")
} else if !strings.Contains(out1, "top") {
- t.Fatal("top should've listed `top` in the process list, but failed the first time")
+ c.Fatal("top should've listed `top` in the process list, but failed the first time")
} else if !strings.Contains(out2, "top") {
- t.Fatal("top should've listed `top` in the process list, but failed the second itime")
+ c.Fatal("top should've listed `top` in the process list, but failed the second itime")
}
- logDone("top - top process should be listed in non privileged mode")
}
-func TestTopPrivileged(t *testing.T) {
+func (s *DockerSuite) TestTopPrivileged(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "--privileged", "-i", "-d", "busybox", "top")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatalf("failed to start the container: %s, %v", out, err)
+ c.Fatalf("failed to start the container: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
@@ -80,29 +78,28 @@ func TestTopPrivileged(t *testing.T) {
topCmd := exec.Command(dockerBinary, "top", cleanedContainerID)
out1, _, err := runCommandWithOutput(topCmd)
if err != nil {
- t.Fatalf("failed to run top: %s, %v", out1, err)
+ c.Fatalf("failed to run top: %s, %v", out1, err)
}
topCmd = exec.Command(dockerBinary, "top", cleanedContainerID)
out2, _, err := runCommandWithOutput(topCmd)
if err != nil {
- t.Fatalf("failed to run top: %s, %v", out2, err)
+ c.Fatalf("failed to run top: %s, %v", out2, err)
}
killCmd := exec.Command(dockerBinary, "kill", cleanedContainerID)
if out, _, err = runCommandWithOutput(killCmd); err != nil {
- t.Fatalf("failed to kill container: %s, %v", out, err)
+ c.Fatalf("failed to kill container: %s, %v", out, err)
}
deleteContainer(cleanedContainerID)
if !strings.Contains(out1, "top") && !strings.Contains(out2, "top") {
- t.Fatal("top should've listed `top` in the process list, but failed twice")
+ c.Fatal("top should've listed `top` in the process list, but failed twice")
} else if !strings.Contains(out1, "top") {
- t.Fatal("top should've listed `top` in the process list, but failed the first time")
+ c.Fatal("top should've listed `top` in the process list, but failed the first time")
} else if !strings.Contains(out2, "top") {
- t.Fatal("top should've listed `top` in the process list, but failed the second itime")
+ c.Fatal("top should've listed `top` in the process list, but failed the second itime")
}
- logDone("top - top process should be listed in privileged mode")
}
diff --git a/integration-cli/docker_cli_version_test.go b/integration-cli/docker_cli_version_test.go
index ceaeba8e209ff..3616da988f0a7 100644
--- a/integration-cli/docker_cli_version_test.go
+++ b/integration-cli/docker_cli_version_test.go
@@ -3,15 +3,16 @@ package main
import (
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
// ensure docker version works
-func TestVersionEnsureSucceeds(t *testing.T) {
+func (s *DockerSuite) TestVersionEnsureSucceeds(c *check.C) {
versionCmd := exec.Command(dockerBinary, "version")
out, _, err := runCommandWithOutput(versionCmd)
if err != nil {
- t.Fatalf("failed to execute docker version: %s, %v", out, err)
+ c.Fatalf("failed to execute docker version: %s, %v", out, err)
}
stringsToCheck := []string{
@@ -29,9 +30,8 @@ func TestVersionEnsureSucceeds(t *testing.T) {
for _, linePrefix := range stringsToCheck {
if !strings.Contains(out, linePrefix) {
- t.Errorf("couldn't find string %v in output", linePrefix)
+ c.Errorf("couldn't find string %v in output", linePrefix)
}
}
- logDone("version - verify that it works and that the output is properly formatted")
}
diff --git a/integration-cli/docker_cli_wait_test.go b/integration-cli/docker_cli_wait_test.go
index cc0e778ea3ec6..21f04faf0f8cd 100644
--- a/integration-cli/docker_cli_wait_test.go
+++ b/integration-cli/docker_cli_wait_test.go
@@ -3,18 +3,18 @@ package main
import (
"os/exec"
"strings"
- "testing"
"time"
+
+ "github.com/go-check/check"
)
// non-blocking wait with 0 exit code
-func TestWaitNonBlockedExitZero(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestWaitNonBlockedExitZero(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", "true")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
containerID := strings.TrimSpace(out)
@@ -23,13 +23,13 @@ func TestWaitNonBlockedExitZero(t *testing.T) {
runCmd = exec.Command(dockerBinary, "inspect", "--format='{{.State.Running}}'", containerID)
status, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(status, err)
+ c.Fatal(status, err)
}
status = strings.TrimSpace(status)
time.Sleep(time.Second)
if i >= 60 {
- t.Fatal("Container should have stopped by now")
+ c.Fatal("Container should have stopped by now")
}
}
@@ -37,41 +37,47 @@ func TestWaitNonBlockedExitZero(t *testing.T) {
out, _, err = runCommandWithOutput(runCmd)
if err != nil || strings.TrimSpace(out) != "0" {
- t.Fatal("failed to set up container", out, err)
+ c.Fatal("failed to set up container", out, err)
}
- logDone("wait - non-blocking wait with 0 exit code")
}
// blocking wait with 0 exit code
-func TestWaitBlockedExitZero(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestWaitBlockedExitZero(c *check.C) {
+ out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "trap 'exit 0' SIGTERM; while true; do sleep 0.01; done")
+ containerID := strings.TrimSpace(out)
- runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", "sleep 10")
- out, _, err := runCommandWithOutput(runCmd)
- if err != nil {
- t.Fatal(out, err)
+ if err := waitRun(containerID); err != nil {
+ c.Fatal(err)
}
- containerID := strings.TrimSpace(out)
- runCmd = exec.Command(dockerBinary, "wait", containerID)
- out, _, err = runCommandWithOutput(runCmd)
+ chWait := make(chan string)
+ go func() {
+ out, _, _ := runCommandWithOutput(exec.Command(dockerBinary, "wait", containerID))
+ chWait <- out
+ }()
- if err != nil || strings.TrimSpace(out) != "0" {
- t.Fatal("failed to set up container", out, err)
+ time.Sleep(100 * time.Millisecond)
+ dockerCmd(c, "stop", containerID)
+
+ select {
+ case status := <-chWait:
+ if strings.TrimSpace(status) != "0" {
+ c.Fatalf("expected exit 0, got %s", status)
+ }
+ case <-time.After(2 * time.Second):
+ c.Fatal("timeout waiting for `docker wait` to exit")
}
- logDone("wait - blocking wait with 0 exit code")
}
// non-blocking wait with random exit code
-func TestWaitNonBlockedExitRandom(t *testing.T) {
- defer deleteAllContainers()
+func (s *DockerSuite) TestWaitNonBlockedExitRandom(c *check.C) {
runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", "exit 99")
out, _, err := runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(out, err)
+ c.Fatal(out, err)
}
containerID := strings.TrimSpace(out)
@@ -80,13 +86,13 @@ func TestWaitNonBlockedExitRandom(t *testing.T) {
runCmd = exec.Command(dockerBinary, "inspect", "--format='{{.State.Running}}'", containerID)
status, _, err = runCommandWithOutput(runCmd)
if err != nil {
- t.Fatal(status, err)
+ c.Fatal(status, err)
}
status = strings.TrimSpace(status)
time.Sleep(time.Second)
if i >= 60 {
- t.Fatal("Container should have stopped by now")
+ c.Fatal("Container should have stopped by now")
}
}
@@ -94,29 +100,37 @@ func TestWaitNonBlockedExitRandom(t *testing.T) {
out, _, err = runCommandWithOutput(runCmd)
if err != nil || strings.TrimSpace(out) != "99" {
- t.Fatal("failed to set up container", out, err)
+ c.Fatal("failed to set up container", out, err)
}
- logDone("wait - non-blocking wait with random exit code")
}
// blocking wait with random exit code
-func TestWaitBlockedExitRandom(t *testing.T) {
- defer deleteAllContainers()
-
- runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", "sleep 10; exit 99")
- out, _, err := runCommandWithOutput(runCmd)
- if err != nil {
- t.Fatal(out, err)
- }
+func (s *DockerSuite) TestWaitBlockedExitRandom(c *check.C) {
+ out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", "trap 'exit 99' SIGTERM; while true; do sleep 0.01; done")
containerID := strings.TrimSpace(out)
+ if err := waitRun(containerID); err != nil {
+ c.Fatal(err)
+ }
+ if err := waitRun(containerID); err != nil {
+ c.Fatal(err)
+ }
- runCmd = exec.Command(dockerBinary, "wait", containerID)
- out, _, err = runCommandWithOutput(runCmd)
+ chWait := make(chan string)
+ go func() {
+ out, _, _ := runCommandWithOutput(exec.Command(dockerBinary, "wait", containerID))
+ chWait <- out
+ }()
- if err != nil || strings.TrimSpace(out) != "99" {
- t.Fatal("failed to set up container", out, err)
- }
+ time.Sleep(100 * time.Millisecond)
+ dockerCmd(c, "stop", containerID)
- logDone("wait - blocking wait with random exit code")
+ select {
+ case status := <-chWait:
+ if strings.TrimSpace(status) != "99" {
+ c.Fatalf("expected exit 99, got %s", status)
+ }
+ case <-time.After(2 * time.Second):
+ c.Fatal("timeout waiting for `docker wait` to exit")
+ }
}
diff --git a/integration-cli/docker_utils.go b/integration-cli/docker_utils.go
index 843a07a20ef7f..8386bb59ff962 100644
--- a/integration-cli/docker_utils.go
+++ b/integration-cli/docker_utils.go
@@ -18,16 +18,17 @@ import (
"path/filepath"
"strconv"
"strings"
- "testing"
"time"
- "github.com/docker/docker/api"
+ "github.com/docker/docker/opts"
+ "github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/stringutils"
+ "github.com/go-check/check"
)
// Daemon represents a Docker daemon for the testing framework.
type Daemon struct {
- t *testing.T
+ c *check.C
logFile *os.File
folder string
stdin io.WriteCloser
@@ -41,24 +42,24 @@ type Daemon struct {
// NewDaemon returns a Daemon instance to be used for testing.
// This will create a directory such as daemon123456789 in the folder specified by $DEST.
// The daemon will not automatically start.
-func NewDaemon(t *testing.T) *Daemon {
+func NewDaemon(c *check.C) *Daemon {
dest := os.Getenv("DEST")
if dest == "" {
- t.Fatal("Please set the DEST environment variable")
+ c.Fatal("Please set the DEST environment variable")
}
dir := filepath.Join(dest, fmt.Sprintf("daemon%d", time.Now().UnixNano()%100000000))
daemonFolder, err := filepath.Abs(dir)
if err != nil {
- t.Fatalf("Could not make %q an absolute path: %v", dir, err)
+ c.Fatalf("Could not make %q an absolute path: %v", dir, err)
}
if err := os.MkdirAll(filepath.Join(daemonFolder, "graph"), 0600); err != nil {
- t.Fatalf("Could not create %s/graph directory", daemonFolder)
+ c.Fatalf("Could not create %s/graph directory", daemonFolder)
}
return &Daemon{
- t: t,
+ c: c,
folder: daemonFolder,
storageDriver: os.Getenv("DOCKER_GRAPHDRIVER"),
execDriver: os.Getenv("DOCKER_EXECDRIVER"),
@@ -70,7 +71,7 @@ func NewDaemon(t *testing.T) *Daemon {
func (d *Daemon) Start(arg ...string) error {
dockerBinary, err := exec.LookPath(dockerBinary)
if err != nil {
- d.t.Fatalf("could not find docker binary in $PATH: %v", err)
+ d.c.Fatalf("could not find docker binary in $PATH: %v", err)
}
args := []string{
@@ -104,7 +105,7 @@ func (d *Daemon) Start(arg ...string) error {
d.logFile, err = os.OpenFile(filepath.Join(d.folder, "docker.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
if err != nil {
- d.t.Fatalf("Could not create %s/docker.log: %v", d.folder, err)
+ d.c.Fatalf("Could not create %s/docker.log: %v", d.folder, err)
}
d.cmd.Stdout = d.logFile
@@ -118,7 +119,7 @@ func (d *Daemon) Start(arg ...string) error {
go func() {
wait <- d.cmd.Wait()
- d.t.Log("exiting daemon")
+ d.c.Log("exiting daemon")
close(wait)
}()
@@ -128,7 +129,7 @@ func (d *Daemon) Start(arg ...string) error {
// make sure daemon is ready to receive requests
startTime := time.Now().Unix()
for {
- d.t.Log("waiting for daemon to start")
+ d.c.Log("waiting for daemon to start")
if time.Now().Unix()-startTime > 5 {
// After 5 seconds, give up
return errors.New("Daemon exited and never started")
@@ -147,7 +148,7 @@ func (d *Daemon) Start(arg ...string) error {
req, err := http.NewRequest("GET", "/_ping", nil)
if err != nil {
- d.t.Fatalf("could not create new request: %v", err)
+ d.c.Fatalf("could not create new request: %v", err)
}
resp, err := client.Do(req)
@@ -155,10 +156,10 @@ func (d *Daemon) Start(arg ...string) error {
continue
}
if resp.StatusCode != http.StatusOK {
- d.t.Logf("received status != 200 OK: %s", resp.Status)
+ d.c.Logf("received status != 200 OK: %s", resp.Status)
}
- d.t.Log("daemon started")
+ d.c.Log("daemon started")
return nil
}
}
@@ -185,7 +186,7 @@ func (d *Daemon) StartWithBusybox(arg ...string) error {
return fmt.Errorf("could not load busybox image: %v", err)
}
if err := os.Remove(bb); err != nil {
- d.t.Logf("Could not remove %s: %v", bb, err)
+ d.c.Logf("Could not remove %s: %v", bb, err)
}
return nil
}
@@ -217,7 +218,7 @@ out1:
return err
case <-time.After(15 * time.Second):
// time for stopping jobs and run onShutdown hooks
- d.t.Log("timeout")
+ d.c.Log("timeout")
break out1
}
}
@@ -230,10 +231,10 @@ out2:
case <-tick:
i++
if i > 4 {
- d.t.Logf("tried to interrupt daemon for %d times, now try to kill it", i)
+ d.c.Logf("tried to interrupt daemon for %d times, now try to kill it", i)
break out2
}
- d.t.Logf("Attempt #%d: daemon is still running with pid %d", i, d.cmd.Process.Pid)
+ d.c.Logf("Attempt #%d: daemon is still running with pid %d", i, d.cmd.Process.Pid)
if err := d.cmd.Process.Signal(os.Interrupt); err != nil {
return fmt.Errorf("could not send signal: %v", err)
}
@@ -241,7 +242,7 @@ out2:
}
if err := d.cmd.Process.Kill(); err != nil {
- d.t.Logf("Could not kill daemon: %v", err)
+ d.c.Logf("Could not kill daemon: %v", err)
return err
}
@@ -268,12 +269,20 @@ func (d *Daemon) Cmd(name string, arg ...string) (string, error) {
return string(b), err
}
+func (d *Daemon) CmdWithArgs(daemonArgs []string, name string, arg ...string) (string, error) {
+ args := append(daemonArgs, name)
+ args = append(args, arg...)
+ c := exec.Command(dockerBinary, args...)
+ b, err := c.CombinedOutput()
+ return string(b), err
+}
+
func (d *Daemon) LogfileName() string {
return d.logFile.Name()
}
func daemonHost() string {
- daemonUrlStr := "unix://" + api.DEFAULTUNIXSOCKET
+ daemonUrlStr := "unix://" + opts.DefaultUnixSocket
if daemonHostVar := os.Getenv("DOCKER_HOST"); daemonHostVar != "" {
daemonUrlStr = daemonHostVar
}
@@ -298,52 +307,61 @@ func sockConn(timeout time.Duration) (net.Conn, error) {
}
}
-func sockRequest(method, endpoint string, data interface{}) ([]byte, error) {
+func sockRequest(method, endpoint string, data interface{}) (int, []byte, error) {
jsonData := bytes.NewBuffer(nil)
if err := json.NewEncoder(jsonData).Encode(data); err != nil {
- return nil, err
+ return -1, nil, err
}
- return sockRequestRaw(method, endpoint, jsonData, "application/json")
+ res, body, err := sockRequestRaw(method, endpoint, jsonData, "application/json")
+ if err != nil {
+ b, _ := ioutil.ReadAll(body)
+ return -1, b, err
+ }
+ var b []byte
+ b, err = readBody(body)
+ return res.StatusCode, b, err
}
-func sockRequestRaw(method, endpoint string, data io.Reader, ct string) ([]byte, error) {
+func sockRequestRaw(method, endpoint string, data io.Reader, ct string) (*http.Response, io.ReadCloser, error) {
c, err := sockConn(time.Duration(10 * time.Second))
if err != nil {
- return nil, fmt.Errorf("could not dial docker daemon: %v", err)
+ return nil, nil, fmt.Errorf("could not dial docker daemon: %v", err)
}
client := httputil.NewClientConn(c, nil)
- defer client.Close()
req, err := http.NewRequest(method, endpoint, data)
if err != nil {
- return nil, fmt.Errorf("could not create new request: %v", err)
+ client.Close()
+ return nil, nil, fmt.Errorf("could not create new request: %v", err)
}
- if ct == "" {
- ct = "application/json"
+ if ct != "" {
+ req.Header.Set("Content-Type", ct)
}
- req.Header.Set("Content-Type", ct)
resp, err := client.Do(req)
if err != nil {
- return nil, fmt.Errorf("could not perform request: %v", err)
- }
- defer resp.Body.Close()
- if resp.StatusCode != http.StatusOK {
- body, _ := ioutil.ReadAll(resp.Body)
- return body, fmt.Errorf("received status != 200 OK: %s", resp.Status)
+ client.Close()
+ return nil, nil, fmt.Errorf("could not perform request: %v", err)
}
+ body := ioutils.NewReadCloserWrapper(resp.Body, func() error {
+ defer client.Close()
+ return resp.Body.Close()
+ })
+
+ return resp, body, nil
+}
- return ioutil.ReadAll(resp.Body)
+func readBody(b io.ReadCloser) ([]byte, error) {
+ defer b.Close()
+ return ioutil.ReadAll(b)
}
func deleteContainer(container string) error {
container = strings.TrimSpace(strings.Replace(container, "\n", " ", -1))
- killArgs := strings.Split(fmt.Sprintf("kill %v", container), " ")
- runCommand(exec.Command(dockerBinary, killArgs...))
- rmArgs := strings.Split(fmt.Sprintf("rm -v %v", container), " ")
+ rmArgs := strings.Split(fmt.Sprintf("rm -fv %v", container), " ")
exitCode, err := runCommand(exec.Command(dockerBinary, rmArgs...))
// set error manually if not set
if exitCode != 0 && err == nil {
@@ -376,6 +394,58 @@ func deleteAllContainers() error {
return nil
}
+var protectedImages = map[string]struct{}{}
+
+func init() {
+ out, err := exec.Command(dockerBinary, "images").CombinedOutput()
+ if err != nil {
+ panic(err)
+ }
+ lines := strings.Split(string(out), "\n")[1:]
+ for _, l := range lines {
+ if l == "" {
+ continue
+ }
+ fields := strings.Fields(l)
+ imgTag := fields[0] + ":" + fields[1]
+ // just for case if we have dangling images in tested daemon
+ if imgTag != ":" {
+ protectedImages[imgTag] = struct{}{}
+ }
+ }
+}
+
+func deleteAllImages() error {
+ out, err := exec.Command(dockerBinary, "images").CombinedOutput()
+ if err != nil {
+ return err
+ }
+ lines := strings.Split(string(out), "\n")[1:]
+ var imgs []string
+ for _, l := range lines {
+ if l == "" {
+ continue
+ }
+ fields := strings.Fields(l)
+ imgTag := fields[0] + ":" + fields[1]
+ if _, ok := protectedImages[imgTag]; !ok {
+ if fields[0] == "" {
+ imgs = append(imgs, fields[2])
+ continue
+ }
+ imgs = append(imgs, imgTag)
+ }
+ }
+ if len(imgs) == 0 {
+ return nil
+ }
+ args := append([]string{"rmi", "-f"}, imgs...)
+ if err := exec.Command(dockerBinary, args...).Run(); err != nil {
+ return err
+ }
+ return nil
+}
+
func getPausedContainers() (string, error) {
getPausedContainersCmd := exec.Command(dockerBinary, "ps", "-f", "status=paused", "-q", "-a")
out, exitCode, err := runCommandWithOutput(getPausedContainersCmd)
@@ -389,6 +459,9 @@ func getPausedContainers() (string, error) {
func getSliceOfPausedContainers() ([]string, error) {
out, err := getPausedContainers()
if err == nil {
+ if len(out) == 0 {
+ return nil, err
+ }
slice := strings.Split(strings.TrimSpace(out), "\n")
return slice, err
}
@@ -426,8 +499,7 @@ func unpauseAllContainers() error {
}
func deleteImages(images ...string) error {
- args := make([]string, 1, 2)
- args[0] = "rmi"
+ args := []string{"rmi", "-f"}
args = append(args, images...)
rmiCmd := exec.Command(dockerBinary, args...)
exitCode, err := runCommand(rmiCmd)
@@ -435,7 +507,6 @@ func deleteImages(images ...string) error {
if exitCode != 0 && err == nil {
err = fmt.Errorf("failed to remove image: `docker rmi` exit is non-zero")
}
-
return err
}
@@ -460,12 +531,12 @@ func pullImageIfNotExist(image string) (err error) {
return
}
-func dockerCmd(t *testing.T, args ...string) (string, int, error) {
+func dockerCmd(c *check.C, args ...string) (string, int) {
out, status, err := runCommandWithOutput(exec.Command(dockerBinary, args...))
if err != nil {
- t.Fatalf("%q failed with errors: %s, %v", strings.Join(args, " "), out, err)
+ c.Fatalf("%q failed with errors: %s, %v", strings.Join(args, " "), out, err)
}
- return out, status, err
+ return out, status
}
// execute a docker command with a timeout
@@ -478,7 +549,7 @@ func dockerCmdWithTimeout(timeout time.Duration, args ...string) (string, int, e
}
// execute a docker command in a directory
-func dockerCmdInDir(t *testing.T, path string, args ...string) (string, int, error) {
+func dockerCmdInDir(c *check.C, path string, args ...string) (string, int, error) {
dockerCommand := exec.Command(dockerBinary, args...)
dockerCommand.Dir = path
out, status, err := runCommandWithOutput(dockerCommand)
@@ -499,11 +570,11 @@ func dockerCmdInDirWithTimeout(timeout time.Duration, path string, args ...strin
return out, status, err
}
-func findContainerIP(t *testing.T, id string) string {
+func findContainerIP(c *check.C, id string) string {
cmd := exec.Command(dockerBinary, "inspect", "--format='{{ .NetworkSettings.IPAddress }}'", id)
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- t.Fatal(err, out)
+ c.Fatal(err, out)
}
return strings.Trim(out, " \r\n'")
@@ -761,14 +832,14 @@ func getIDByName(name string) (string, error) {
// getContainerState returns the exit code of the container
// and true if it's running
// the exit code should be ignored if it's running
-func getContainerState(t *testing.T, id string) (int, bool, error) {
+func getContainerState(c *check.C, id string) (int, bool, error) {
var (
exitStatus int
running bool
)
- out, exitCode, err := dockerCmd(t, "inspect", "--format={{.State.Running}} {{.State.ExitCode}}", id)
- if err != nil || exitCode != 0 {
- return 0, false, fmt.Errorf("%q doesn't exist: %s", id, err)
+ out, exitCode := dockerCmd(c, "inspect", "--format={{.State.Running}} {{.State.ExitCode}}", id)
+ if exitCode != 0 {
+ return 0, false, fmt.Errorf("%q doesn't exist: %s", id, out)
}
out = strings.Trim(out, "\n")
@@ -967,28 +1038,28 @@ func fakeGIT(name string, files map[string]string, enforceLocalServer bool) (*Fa
// Write `content` to the file at path `dst`, creating it if necessary,
// as well as any missing directories.
// The file is truncated if it already exists.
-// Call t.Fatal() at the first error.
-func writeFile(dst, content string, t *testing.T) {
+// Call c.Fatal() at the first error.
+func writeFile(dst, content string, c *check.C) {
// Create subdirectories if necessary
if err := os.MkdirAll(path.Dir(dst), 0700); err != nil && !os.IsExist(err) {
- t.Fatal(err)
+ c.Fatal(err)
}
f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0700)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// Write content (truncate if it exists)
if _, err := io.Copy(f, strings.NewReader(content)); err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
}
// Return the contents of file at path `src`.
-// Call t.Fatal() at the first error (including if the file doesn't exist)
-func readFile(src string, t *testing.T) (content string) {
+// Call c.Fatal() at the first error (including if the file doesn't exist)
+func readFile(src string, c *check.C) (content string) {
data, err := ioutil.ReadFile(src)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
return string(data)
@@ -1033,36 +1104,35 @@ func readContainerFileWithExec(containerId, filename string) ([]byte, error) {
}
// daemonTime provides the current time on the daemon host
-func daemonTime(t *testing.T) time.Time {
+func daemonTime(c *check.C) time.Time {
if isLocalDaemon {
return time.Now()
}
- body, err := sockRequest("GET", "/info", nil)
- if err != nil {
- t.Fatalf("daemonTime: failed to get /info: %v", err)
- }
+ status, body, err := sockRequest("GET", "/info", nil)
+ c.Assert(status, check.Equals, http.StatusOK)
+ c.Assert(err, check.IsNil)
type infoJSON struct {
SystemTime string
}
var info infoJSON
if err = json.Unmarshal(body, &info); err != nil {
- t.Fatalf("unable to unmarshal /info response: %v", err)
+ c.Fatalf("unable to unmarshal /info response: %v", err)
}
dt, err := time.Parse(time.RFC3339Nano, info.SystemTime)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
return dt
}
-func setupRegistry(t *testing.T) func() {
- testRequires(t, RegistryHosting)
- reg, err := newTestRegistryV2(t)
+func setupRegistry(c *check.C) *testRegistryV2 {
+ testRequires(c, RegistryHosting)
+ reg, err := newTestRegistryV2(c)
if err != nil {
- t.Fatal(err)
+ c.Fatal(err)
}
// Wait for registry to be ready to serve requests.
@@ -1074,10 +1144,9 @@ func setupRegistry(t *testing.T) func() {
}
if err != nil {
- t.Fatal("Timeout waiting for test registry to become available")
+ c.Fatal("Timeout waiting for test registry to become available")
}
-
- return func() { reg.Close() }
+ return reg
}
// appendBaseEnv appends the minimum set of environment variables to exec the
diff --git a/integration/fixtures/https/ca.pem b/integration-cli/fixtures/https/ca.pem
similarity index 100%
rename from integration/fixtures/https/ca.pem
rename to integration-cli/fixtures/https/ca.pem
diff --git a/integration/fixtures/https/client-cert.pem b/integration-cli/fixtures/https/client-cert.pem
similarity index 100%
rename from integration/fixtures/https/client-cert.pem
rename to integration-cli/fixtures/https/client-cert.pem
diff --git a/integration/fixtures/https/client-key.pem b/integration-cli/fixtures/https/client-key.pem
similarity index 100%
rename from integration/fixtures/https/client-key.pem
rename to integration-cli/fixtures/https/client-key.pem
diff --git a/integration/fixtures/https/client-rogue-cert.pem b/integration-cli/fixtures/https/client-rogue-cert.pem
similarity index 100%
rename from integration/fixtures/https/client-rogue-cert.pem
rename to integration-cli/fixtures/https/client-rogue-cert.pem
diff --git a/integration/fixtures/https/client-rogue-key.pem b/integration-cli/fixtures/https/client-rogue-key.pem
similarity index 100%
rename from integration/fixtures/https/client-rogue-key.pem
rename to integration-cli/fixtures/https/client-rogue-key.pem
diff --git a/integration/fixtures/https/server-cert.pem b/integration-cli/fixtures/https/server-cert.pem
similarity index 100%
rename from integration/fixtures/https/server-cert.pem
rename to integration-cli/fixtures/https/server-cert.pem
diff --git a/integration/fixtures/https/server-key.pem b/integration-cli/fixtures/https/server-key.pem
similarity index 100%
rename from integration/fixtures/https/server-key.pem
rename to integration-cli/fixtures/https/server-key.pem
diff --git a/integration/fixtures/https/server-rogue-cert.pem b/integration-cli/fixtures/https/server-rogue-cert.pem
similarity index 100%
rename from integration/fixtures/https/server-rogue-cert.pem
rename to integration-cli/fixtures/https/server-rogue-cert.pem
diff --git a/integration/fixtures/https/server-rogue-key.pem b/integration-cli/fixtures/https/server-rogue-key.pem
similarity index 100%
rename from integration/fixtures/https/server-rogue-key.pem
rename to integration-cli/fixtures/https/server-rogue-key.pem
diff --git a/integration-cli/registry.go b/integration-cli/registry.go
index 8290e710fd631..2801eacb5f514 100644
--- a/integration-cli/registry.go
+++ b/integration-cli/registry.go
@@ -7,7 +7,8 @@ import (
"os"
"os/exec"
"path/filepath"
- "testing"
+
+ "github.com/go-check/check"
)
const v2binary = "registry-v2"
@@ -17,7 +18,7 @@ type testRegistryV2 struct {
dir string
}
-func newTestRegistryV2(t *testing.T) (*testRegistryV2, error) {
+func newTestRegistryV2(c *check.C) (*testRegistryV2, error) {
template := `version: 0.1
loglevel: debug
storage:
@@ -43,7 +44,7 @@ http:
if err := cmd.Start(); err != nil {
os.RemoveAll(tmp)
if os.IsNotExist(err) {
- t.Skip()
+ c.Skip(err.Error())
}
return nil, err
}
diff --git a/integration-cli/requirements.go b/integration-cli/requirements.go
index cdd9991873947..cc451bd886481 100644
--- a/integration-cli/requirements.go
+++ b/integration-cli/requirements.go
@@ -7,7 +7,8 @@ import (
"net/http"
"os/exec"
"strings"
- "testing"
+
+ "github.com/go-check/check"
)
type TestCondition func() bool
@@ -57,8 +58,8 @@ var (
func() bool {
if daemonExecDriver == "" {
// get daemon info
- body, err := sockRequest("GET", "/info", nil)
- if err != nil {
+ status, body, err := sockRequest("GET", "/info", nil)
+ if err != nil || status != http.StatusOK {
log.Fatalf("sockRequest failed for /info: %v", err)
}
@@ -92,10 +93,10 @@ var (
// testRequires checks if the environment satisfies the requirements
// for the test to run or skips the tests.
-func testRequires(t *testing.T, requirements ...TestRequirement) {
+func testRequires(c *check.C, requirements ...TestRequirement) {
for _, r := range requirements {
if !r.Condition() {
- t.Skip(r.SkipMessage)
+ c.Skip(r.SkipMessage)
}
}
}
diff --git a/integration-cli/utils.go b/integration-cli/utils.go
index 536f6984e22ab..f0de79ea8f071 100644
--- a/integration-cli/utils.go
+++ b/integration-cli/utils.go
@@ -143,6 +143,7 @@ func runCommandPipelineWithOutput(cmds ...*exec.Cmd) (output string, exitCode in
if i > 0 {
prevCmd := cmds[i-1]
cmd.Stdin, err = prevCmd.StdoutPipe()
+
if err != nil {
return "", 0, fmt.Errorf("cannot set stdout pipe for %s: %v", cmd.Path, err)
}
@@ -167,13 +168,8 @@ func runCommandPipelineWithOutput(cmds ...*exec.Cmd) (output string, exitCode in
return runCommandWithOutput(cmds[len(cmds)-1])
}
-func logDone(message string) {
- fmt.Printf("[PASSED]: %.69s\n", message)
-}
-
func unmarshalJSON(data []byte, result interface{}) error {
- err := json.Unmarshal(data, result)
- if err != nil {
+ if err := json.Unmarshal(data, result); err != nil {
return err
}
@@ -213,7 +209,16 @@ func waitInspect(name, expr, expected string, timeout int) error {
cmd := exec.Command(dockerBinary, "inspect", "-f", expr, name)
out, _, err := runCommandWithOutput(cmd)
if err != nil {
- return fmt.Errorf("error executing docker inspect: %v", err)
+ if !strings.Contains(out, "No such") {
+ return fmt.Errorf("error executing docker inspect: %v\n%s", err, out)
+ }
+ select {
+ case <-after:
+ return err
+ default:
+ time.Sleep(10 * time.Millisecond)
+ continue
+ }
}
out = strings.TrimSpace(out)
diff --git a/integration/api_test.go b/integration/api_test.go
index 98e683d0040ac..e45fa97e8288e 100644
--- a/integration/api_test.go
+++ b/integration/api_test.go
@@ -4,337 +4,22 @@ import (
"bufio"
"bytes"
"encoding/json"
- "fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
- "strings"
"testing"
"time"
"github.com/docker/docker/api"
"github.com/docker/docker/api/server"
"github.com/docker/docker/api/types"
- "github.com/docker/docker/builder"
"github.com/docker/docker/engine"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
)
-func TestSaveImageAndThenLoad(t *testing.T) {
- eng := NewTestEngine(t)
- defer mkDaemonFromEngine(eng, t).Nuke()
-
- // save image
- r := httptest.NewRecorder()
- req, err := http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
- if err != nil {
- t.Fatal(err)
- }
- server.ServeRequest(eng, api.APIVERSION, r, req)
- if r.Code != http.StatusOK {
- t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
- }
- tarball := r.Body
-
- // delete the image
- r = httptest.NewRecorder()
- req, err = http.NewRequest("DELETE", "/images/"+unitTestImageID, nil)
- if err != nil {
- t.Fatal(err)
- }
- server.ServeRequest(eng, api.APIVERSION, r, req)
- if r.Code != http.StatusOK {
- t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
- }
-
- // make sure there is no image
- r = httptest.NewRecorder()
- req, err = http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
- if err != nil {
- t.Fatal(err)
- }
- server.ServeRequest(eng, api.APIVERSION, r, req)
- if r.Code != http.StatusNotFound {
- t.Fatalf("%d NotFound expected, received %d\n", http.StatusNotFound, r.Code)
- }
-
- // load the image
- r = httptest.NewRecorder()
- req, err = http.NewRequest("POST", "/images/load", tarball)
- if err != nil {
- t.Fatal(err)
- }
- server.ServeRequest(eng, api.APIVERSION, r, req)
- if r.Code != http.StatusOK {
- t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
- }
-
- // finally make sure the image is there
- r = httptest.NewRecorder()
- req, err = http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
- if err != nil {
- t.Fatal(err)
- }
- server.ServeRequest(eng, api.APIVERSION, r, req)
- if r.Code != http.StatusOK {
- t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
- }
-}
-
-func TestGetContainersTop(t *testing.T) {
- eng := NewTestEngine(t)
- defer mkDaemonFromEngine(eng, t).Nuke()
-
- containerID := createTestContainer(eng,
- &runconfig.Config{
- Image: unitTestImageID,
- Cmd: []string{"/bin/sh", "-c", "cat"},
- OpenStdin: true,
- },
- t,
- )
- defer func() {
- // Make sure the process dies before destroying daemon
- containerKill(eng, containerID, t)
- containerWait(eng, containerID, t)
- }()
-
- startContainer(eng, containerID, t)
-
- setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
- for {
- if containerRunning(eng, containerID, t) {
- break
- }
- time.Sleep(10 * time.Millisecond)
- }
- })
-
- if !containerRunning(eng, containerID, t) {
- t.Fatalf("Container should be running")
- }
-
- // Make sure sh spawn up cat
- setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
- in, out := containerAttach(eng, containerID, t)
- if err := assertPipe("hello\n", "hello", out, in, 150); err != nil {
- t.Fatal(err)
- }
- })
-
- r := httptest.NewRecorder()
- req, err := http.NewRequest("GET", "/containers/"+containerID+"/top?ps_args=aux", nil)
- if err != nil {
- t.Fatal(err)
- }
- server.ServeRequest(eng, api.APIVERSION, r, req)
- assertHttpNotError(r, t)
- var procs engine.Env
- if err := procs.Decode(r.Body); err != nil {
- t.Fatal(err)
- }
-
- if len(procs.GetList("Titles")) != 11 {
- t.Fatalf("Expected 11 titles, found %d.", len(procs.GetList("Titles")))
- }
- if procs.GetList("Titles")[0] != "USER" || procs.GetList("Titles")[10] != "COMMAND" {
- t.Fatalf("Expected Titles[0] to be USER and Titles[10] to be COMMAND, found %s and %s.", procs.GetList("Titles")[0], procs.GetList("Titles")[10])
- }
- processes := [][]string{}
- if err := procs.GetJson("Processes", &processes); err != nil {
- t.Fatal(err)
- }
- if len(processes) != 2 {
- t.Fatalf("Expected 2 processes, found %d.", len(processes))
- }
- if processes[0][10] != "/bin/sh -c cat" {
- t.Fatalf("Expected `/bin/sh -c cat`, found %s.", processes[0][10])
- }
- if processes[1][10] != "/bin/sh -c cat" {
- t.Fatalf("Expected `/bin/sh -c cat`, found %s.", processes[1][10])
- }
-}
-
-func TestPostCommit(t *testing.T) {
- eng := NewTestEngine(t)
- b := &builder.BuilderJob{Engine: eng}
- b.Install()
- defer mkDaemonFromEngine(eng, t).Nuke()
-
- // Create a container and remove a file
- containerID := createTestContainer(eng,
- &runconfig.Config{
- Image: unitTestImageID,
- Cmd: []string{"touch", "/test"},
- },
- t,
- )
-
- containerRun(eng, containerID, t)
-
- req, err := http.NewRequest("POST", "/commit?repo=testrepo&testtag=tag&container="+containerID, bytes.NewReader([]byte{}))
- if err != nil {
- t.Fatal(err)
- }
-
- r := httptest.NewRecorder()
- server.ServeRequest(eng, api.APIVERSION, r, req)
- assertHttpNotError(r, t)
- if r.Code != http.StatusCreated {
- t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
- }
-
- var env engine.Env
- if err := env.Decode(r.Body); err != nil {
- t.Fatal(err)
- }
- if err := eng.Job("image_inspect", env.Get("Id")).Run(); err != nil {
- t.Fatalf("The image has not been committed")
- }
-}
-
-func TestPostContainersCreate(t *testing.T) {
- eng := NewTestEngine(t)
- defer mkDaemonFromEngine(eng, t).Nuke()
-
- configJSON, err := json.Marshal(&runconfig.Config{
- Image: unitTestImageID,
- Memory: 33554432,
- Cmd: []string{"touch", "/test"},
- })
- if err != nil {
- t.Fatal(err)
- }
-
- req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJSON))
- if err != nil {
- t.Fatal(err)
- }
-
- req.Header.Set("Content-Type", "application/json")
-
- r := httptest.NewRecorder()
- server.ServeRequest(eng, api.APIVERSION, r, req)
- assertHttpNotError(r, t)
- if r.Code != http.StatusCreated {
- t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
- }
-
- var apiRun engine.Env
- if err := apiRun.Decode(r.Body); err != nil {
- t.Fatal(err)
- }
- containerID := apiRun.Get("Id")
-
- containerAssertExists(eng, containerID, t)
- containerRun(eng, containerID, t)
-
- if !containerFileExists(eng, containerID, "test", t) {
- t.Fatal("Test file was not created")
- }
-}
-
-func TestPostJsonVerify(t *testing.T) {
- eng := NewTestEngine(t)
- defer mkDaemonFromEngine(eng, t).Nuke()
-
- configJSON, err := json.Marshal(&runconfig.Config{
- Image: unitTestImageID,
- Memory: 33554432,
- Cmd: []string{"touch", "/test"},
- })
- if err != nil {
- t.Fatal(err)
- }
-
- req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJSON))
- if err != nil {
- t.Fatal(err)
- }
-
- r := httptest.NewRecorder()
-
- server.ServeRequest(eng, api.APIVERSION, r, req)
-
- // Don't add Content-Type header
- // req.Header.Set("Content-Type", "application/json")
-
- server.ServeRequest(eng, api.APIVERSION, r, req)
- if r.Code != http.StatusInternalServerError || !strings.Contains(((*r.Body).String()), "application/json") {
- t.Fatal("Create should have failed due to no Content-Type header - got:", r)
- }
-
- // Now add header but with wrong type and retest
- req.Header.Set("Content-Type", "application/xml")
-
- server.ServeRequest(eng, api.APIVERSION, r, req)
- if r.Code != http.StatusInternalServerError || !strings.Contains(((*r.Body).String()), "application/json") {
- t.Fatal("Create should have failed due to wrong Content-Type header - got:", r)
- }
-}
-
-// Issue 7941 - test to make sure a "null" in JSON is just ignored.
-// W/o this fix a null in JSON would be parsed into a string var as "null"
-func TestPostCreateNull(t *testing.T) {
- eng := NewTestEngine(t)
- daemon := mkDaemonFromEngine(eng, t)
- defer daemon.Nuke()
-
- configStr := fmt.Sprintf(`{
- "Hostname":"",
- "Domainname":"",
- "Memory":0,
- "MemorySwap":0,
- "CpuShares":0,
- "Cpuset":null,
- "AttachStdin":true,
- "AttachStdout":true,
- "AttachStderr":true,
- "PortSpecs":null,
- "ExposedPorts":{},
- "Tty":true,
- "OpenStdin":true,
- "StdinOnce":true,
- "Env":[],
- "Cmd":"ls",
- "Image":"%s",
- "Volumes":{},
- "WorkingDir":"",
- "Entrypoint":null,
- "NetworkDisabled":false,
- "OnBuild":null}`, unitTestImageID)
-
- req, err := http.NewRequest("POST", "/containers/create", strings.NewReader(configStr))
- if err != nil {
- t.Fatal(err)
- }
-
- req.Header.Set("Content-Type", "application/json")
-
- r := httptest.NewRecorder()
- server.ServeRequest(eng, api.APIVERSION, r, req)
- assertHttpNotError(r, t)
- if r.Code != http.StatusCreated {
- t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
- }
-
- var apiRun engine.Env
- if err := apiRun.Decode(r.Body); err != nil {
- t.Fatal(err)
- }
- containerID := apiRun.Get("Id")
-
- containerAssertExists(eng, containerID, t)
-
- c, _ := daemon.Get(containerID)
- if c.Config.Cpuset != "" {
- t.Fatalf("Cpuset should have been empty - instead its:" + c.Config.Cpuset)
- }
-}
-
func TestPostContainersKill(t *testing.T) {
eng := NewTestEngine(t)
defer mkDaemonFromEngine(eng, t).Nuke()
@@ -342,7 +27,7 @@ func TestPostContainersKill(t *testing.T) {
containerID := createTestContainer(eng,
&runconfig.Config{
Image: unitTestImageID,
- Cmd: []string{"/bin/cat"},
+ Cmd: runconfig.NewCommand("/bin/cat"),
OpenStdin: true,
},
t,
@@ -379,7 +64,7 @@ func TestPostContainersRestart(t *testing.T) {
containerID := createTestContainer(eng,
&runconfig.Config{
Image: unitTestImageID,
- Cmd: []string{"/bin/top"},
+ Cmd: runconfig.NewCommand("/bin/top"),
OpenStdin: true,
},
t,
@@ -423,7 +108,7 @@ func TestPostContainersStart(t *testing.T) {
eng,
&runconfig.Config{
Image: unitTestImageID,
- Cmd: []string{"/bin/cat"},
+ Cmd: runconfig.NewCommand("/bin/cat"),
OpenStdin: true,
},
t,
@@ -473,7 +158,7 @@ func TestPostContainersStop(t *testing.T) {
containerID := createTestContainer(eng,
&runconfig.Config{
Image: unitTestImageID,
- Cmd: []string{"/bin/top"},
+ Cmd: runconfig.NewCommand("/bin/top"),
OpenStdin: true,
},
t,
@@ -525,7 +210,7 @@ func TestPostContainersWait(t *testing.T) {
containerID := createTestContainer(eng,
&runconfig.Config{
Image: unitTestImageID,
- Cmd: []string{"/bin/sleep", "1"},
+ Cmd: runconfig.NewCommand("/bin/sleep", "1"),
OpenStdin: true,
},
t,
@@ -561,7 +246,7 @@ func TestPostContainersAttach(t *testing.T) {
containerID := createTestContainer(eng,
&runconfig.Config{
Image: unitTestImageID,
- Cmd: []string{"/bin/cat"},
+ Cmd: runconfig.NewCommand("/bin/cat"),
OpenStdin: true,
},
t,
@@ -637,7 +322,7 @@ func TestPostContainersAttachStderr(t *testing.T) {
containerID := createTestContainer(eng,
&runconfig.Config{
Image: unitTestImageID,
- Cmd: []string{"/bin/sh", "-c", "/bin/cat >&2"},
+ Cmd: runconfig.NewCommand("/bin/sh", "-c", "/bin/cat >&2"),
OpenStdin: true,
},
t,
@@ -749,7 +434,7 @@ func TestGetEnabledCors(t *testing.T) {
t.Errorf("Expected header Access-Control-Allow-Headers to be \"Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth\", %s found.", allowHeaders)
}
if allowMethods != "GET, POST, DELETE, PUT, OPTIONS" {
- t.Errorf("Expected hearder Access-Control-Allow-Methods to be \"GET, POST, DELETE, PUT, OPTIONS\", %s found.", allowMethods)
+ t.Errorf("Expected header Access-Control-Allow-Methods to be \"GET, POST, DELETE, PUT, OPTIONS\", %s found.", allowMethods)
}
}
@@ -761,7 +446,8 @@ func TestDeleteImages(t *testing.T) {
initialImages := getImages(eng, t, true, "")
- if err := eng.Job("tag", unitTestImageName, "test", "test").Run(); err != nil {
+ d := getDaemon(eng)
+ if err := d.Repositories().Tag("test", "test", unitTestImageName, true); err != nil {
t.Fatal(err)
}
@@ -818,7 +504,7 @@ func TestPostContainersCopy(t *testing.T) {
containerID := createTestContainer(eng,
&runconfig.Config{
Image: unitTestImageID,
- Cmd: []string{"touch", "/test.txt"},
+ Cmd: runconfig.NewCommand("touch", "/test.txt"),
},
t,
)
@@ -932,7 +618,7 @@ func TestConstainersStartChunkedEncodingHostConfig(t *testing.T) {
req.Header.Add("Content-Type", "application/json")
// This is a cheat to make the http request do chunked encoding
// Otherwise (just setting the Content-Encoding to chunked) net/http will overwrite
- // http://golang.org/src/pkg/net/http/request.go?s=11980:12172
+ // https://golang.org/src/pkg/net/http/request.go?s=11980:12172
req.ContentLength = -1
server.ServeRequest(eng, api.APIVERSION, r, req)
assertHttpNotError(r, t)
@@ -962,7 +648,7 @@ func TestConstainersStartChunkedEncodingHostConfig(t *testing.T) {
}
if c.HostConfig.Binds[0] != "/tmp:/foo" {
- t.Fatal("Chunked encoding not properly handled, execpted binds to be /tmp:/foo, got:", c.HostConfig.Binds[0])
+ t.Fatal("Chunked encoding not properly handled, expected binds to be /tmp:/foo, got:", c.HostConfig.Binds[0])
}
}
diff --git a/integration/commands_test.go b/integration/commands_test.go
deleted file mode 100644
index 97a927b8bf3b6..0000000000000
--- a/integration/commands_test.go
+++ /dev/null
@@ -1,436 +0,0 @@
-package docker
-
-import (
- "bufio"
- "fmt"
- "io"
- "io/ioutil"
- "strings"
- "testing"
- "time"
-
- "github.com/Sirupsen/logrus"
- "github.com/docker/docker/api/client"
- "github.com/docker/docker/daemon"
- "github.com/docker/docker/pkg/stringid"
- "github.com/docker/docker/pkg/term"
- "github.com/kr/pty"
-)
-
-func closeWrap(args ...io.Closer) error {
- e := false
- ret := fmt.Errorf("Error closing elements")
- for _, c := range args {
- if err := c.Close(); err != nil {
- e = true
- ret = fmt.Errorf("%s\n%s", ret, err)
- }
- }
- if e {
- return ret
- }
- return nil
-}
-
-func setRaw(t *testing.T, c *daemon.Container) *term.State {
- pty, err := c.GetPtyMaster()
- if err != nil {
- t.Fatal(err)
- }
- state, err := term.MakeRaw(pty.Fd())
- if err != nil {
- t.Fatal(err)
- }
- return state
-}
-
-func unsetRaw(t *testing.T, c *daemon.Container, state *term.State) {
- pty, err := c.GetPtyMaster()
- if err != nil {
- t.Fatal(err)
- }
- term.RestoreTerminal(pty.Fd(), state)
-}
-
-func waitContainerStart(t *testing.T, timeout time.Duration) *daemon.Container {
- var container *daemon.Container
-
- setTimeout(t, "Waiting for the container to be started timed out", timeout, func() {
- for {
- l := globalDaemon.List()
- if len(l) == 1 && l[0].IsRunning() {
- container = l[0]
- break
- }
- time.Sleep(10 * time.Millisecond)
- }
- })
-
- if container == nil {
- t.Fatal("An error occured while waiting for the container to start")
- }
-
- return container
-}
-
-func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
- c := make(chan bool)
-
- // Make sure we are not too long
- go func() {
- time.Sleep(d)
- c <- true
- }()
- go func() {
- f()
- c <- false
- }()
- if <-c && msg != "" {
- t.Fatal(msg)
- }
-}
-
-func expectPipe(expected string, r io.Reader) error {
- o, err := bufio.NewReader(r).ReadString('\n')
- if err != nil {
- return err
- }
- if strings.Trim(o, " \r\n") != expected {
- return fmt.Errorf("Unexpected output. Expected [%s], received [%s]", expected, o)
- }
- return nil
-}
-
-func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error {
- for i := 0; i < count; i++ {
- if _, err := w.Write([]byte(input)); err != nil {
- return err
- }
- if err := expectPipe(output, r); err != nil {
- return err
- }
- }
- return nil
-}
-
-// TestRunDetach checks attaching and detaching with the escape sequence.
-func TestRunDetach(t *testing.T) {
- stdout, stdoutPipe := io.Pipe()
- cpty, tty, err := pty.Open()
- if err != nil {
- t.Fatal(err)
- }
-
- cli := client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
- defer cleanup(globalEngine, t)
-
- ch := make(chan struct{})
- go func() {
- defer close(ch)
- cli.CmdRun("-i", "-t", unitTestImageID, "cat")
- }()
-
- container := waitContainerStart(t, 10*time.Second)
-
- state := setRaw(t, container)
- defer unsetRaw(t, container, state)
-
- setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
- if err := assertPipe("hello\n", "hello", stdout, cpty, 150); err != nil {
- t.Fatal(err)
- }
- })
-
- setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
- cpty.Write([]byte{16})
- time.Sleep(100 * time.Millisecond)
- cpty.Write([]byte{17})
- })
-
- // wait for CmdRun to return
- setTimeout(t, "Waiting for CmdRun timed out", 15*time.Second, func() {
- <-ch
- })
- closeWrap(cpty, stdout, stdoutPipe)
-
- time.Sleep(500 * time.Millisecond)
- if !container.IsRunning() {
- t.Fatal("The detached container should be still running")
- }
-
- setTimeout(t, "Waiting for container to die timed out", 20*time.Second, func() {
- container.Kill()
- })
-}
-
-// TestAttachDetach checks that attach in tty mode can be detached using the long container ID
-func TestAttachDetach(t *testing.T) {
- stdout, stdoutPipe := io.Pipe()
- cpty, tty, err := pty.Open()
- if err != nil {
- t.Fatal(err)
- }
-
- cli := client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
- defer cleanup(globalEngine, t)
-
- ch := make(chan struct{})
- go func() {
- defer close(ch)
- if err := cli.CmdRun("-i", "-t", "-d", unitTestImageID, "cat"); err != nil {
- t.Fatal(err)
- }
- }()
-
- container := waitContainerStart(t, 10*time.Second)
-
- setTimeout(t, "Reading container's id timed out", 10*time.Second, func() {
- buf := make([]byte, 1024)
- n, err := stdout.Read(buf)
- if err != nil {
- t.Fatal(err)
- }
-
- if strings.Trim(string(buf[:n]), " \r\n") != container.ID {
- t.Fatalf("Wrong ID received. Expect %s, received %s", container.ID, buf[:n])
- }
- })
- setTimeout(t, "Starting container timed out", 10*time.Second, func() {
- <-ch
- })
-
- state := setRaw(t, container)
- defer unsetRaw(t, container, state)
-
- stdout, stdoutPipe = io.Pipe()
- cpty, tty, err = pty.Open()
- if err != nil {
- t.Fatal(err)
- }
-
- cli = client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
-
- ch = make(chan struct{})
- go func() {
- defer close(ch)
- if err := cli.CmdAttach(container.ID); err != nil {
- if err != io.ErrClosedPipe {
- t.Fatal(err)
- }
- }
- }()
-
- setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
- if err := assertPipe("hello\n", "hello", stdout, cpty, 150); err != nil {
- if err != io.ErrClosedPipe {
- t.Fatal(err)
- }
- }
- })
-
- setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
- cpty.Write([]byte{16})
- time.Sleep(100 * time.Millisecond)
- cpty.Write([]byte{17})
- })
-
- // wait for CmdRun to return
- setTimeout(t, "Waiting for CmdAttach timed out", 15*time.Second, func() {
- <-ch
- })
-
- closeWrap(cpty, stdout, stdoutPipe)
-
- time.Sleep(500 * time.Millisecond)
- if !container.IsRunning() {
- t.Fatal("The detached container should be still running")
- }
-
- setTimeout(t, "Waiting for container to die timedout", 5*time.Second, func() {
- container.Kill()
- })
-}
-
-// TestAttachDetachTruncatedID checks that attach in tty mode can be detached
-func TestAttachDetachTruncatedID(t *testing.T) {
- stdout, stdoutPipe := io.Pipe()
- cpty, tty, err := pty.Open()
- if err != nil {
- t.Fatal(err)
- }
-
- cli := client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
- defer cleanup(globalEngine, t)
-
- // Discard the CmdRun output
- go stdout.Read(make([]byte, 1024))
- setTimeout(t, "Starting container timed out", 2*time.Second, func() {
- if err := cli.CmdRun("-i", "-t", "-d", unitTestImageID, "cat"); err != nil {
- t.Fatal(err)
- }
- })
-
- container := waitContainerStart(t, 10*time.Second)
-
- state := setRaw(t, container)
- defer unsetRaw(t, container, state)
-
- stdout, stdoutPipe = io.Pipe()
- cpty, tty, err = pty.Open()
- if err != nil {
- t.Fatal(err)
- }
-
- cli = client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
-
- ch := make(chan struct{})
- go func() {
- defer close(ch)
- if err := cli.CmdAttach(stringid.TruncateID(container.ID)); err != nil {
- if err != io.ErrClosedPipe {
- t.Fatal(err)
- }
- }
- }()
-
- setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
- if err := assertPipe("hello\n", "hello", stdout, cpty, 150); err != nil {
- if err != io.ErrClosedPipe {
- t.Fatal(err)
- }
- }
- })
-
- setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
- cpty.Write([]byte{16})
- time.Sleep(100 * time.Millisecond)
- cpty.Write([]byte{17})
- })
-
- // wait for CmdRun to return
- setTimeout(t, "Waiting for CmdAttach timed out", 15*time.Second, func() {
- <-ch
- })
- closeWrap(cpty, stdout, stdoutPipe)
-
- time.Sleep(500 * time.Millisecond)
- if !container.IsRunning() {
- t.Fatal("The detached container should be still running")
- }
-
- setTimeout(t, "Waiting for container to die timedout", 5*time.Second, func() {
- container.Kill()
- })
-}
-
-// Expected behaviour, the process stays alive when the client disconnects
-func TestAttachDisconnect(t *testing.T) {
- stdout, stdoutPipe := io.Pipe()
- cpty, tty, err := pty.Open()
- if err != nil {
- t.Fatal(err)
- }
-
- cli := client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
- defer cleanup(globalEngine, t)
-
- go func() {
- // Start a process in daemon mode
- if err := cli.CmdRun("-d", "-i", unitTestImageID, "/bin/cat"); err != nil {
- logrus.Debugf("Error CmdRun: %s", err)
- }
- }()
-
- setTimeout(t, "Waiting for CmdRun timed out", 10*time.Second, func() {
- if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
- t.Fatal(err)
- }
- })
-
- setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
- for {
- l := globalDaemon.List()
- if len(l) == 1 && l[0].IsRunning() {
- break
- }
- time.Sleep(10 * time.Millisecond)
- }
- })
-
- container := globalDaemon.List()[0]
-
- // Attach to it
- c1 := make(chan struct{})
- go func() {
- // We're simulating a disconnect so the return value doesn't matter. What matters is the
- // fact that CmdAttach returns.
- cli.CmdAttach(container.ID)
- close(c1)
- }()
-
- setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
- if err := assertPipe("hello\n", "hello", stdout, cpty, 150); err != nil {
- t.Fatal(err)
- }
- })
- // Close pipes (client disconnects)
- if err := closeWrap(cpty, stdout, stdoutPipe); err != nil {
- t.Fatal(err)
- }
-
- // Wait for attach to finish, the client disconnected, therefore, Attach finished his job
- setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
- <-c1
- })
-
- // We closed stdin, expect /bin/cat to still be running
- // Wait a little bit to make sure container.monitor() did his thing
- _, err = container.WaitStop(500 * time.Millisecond)
- if err == nil || !container.IsRunning() {
- t.Fatalf("/bin/cat is not running after closing stdin")
- }
-
- // Try to avoid the timeout in destroy. Best effort, don't check error
- cStdin := container.StdinPipe()
- cStdin.Close()
- container.WaitStop(-1 * time.Second)
-}
-
-// Expected behaviour: container gets deleted automatically after exit
-func TestRunAutoRemove(t *testing.T) {
- t.Skip("Fixme. Skipping test for now, race condition")
- stdout, stdoutPipe := io.Pipe()
-
- cli := client.NewDockerCli(nil, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
- defer cleanup(globalEngine, t)
-
- c := make(chan struct{})
- go func() {
- defer close(c)
- if err := cli.CmdRun("--rm", unitTestImageID, "hostname"); err != nil {
- t.Fatal(err)
- }
- }()
-
- var temporaryContainerID string
- setTimeout(t, "Reading command output time out", 2*time.Second, func() {
- cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
- if err != nil {
- t.Fatal(err)
- }
- temporaryContainerID = cmdOutput
- if err := closeWrap(stdout, stdoutPipe); err != nil {
- t.Fatal(err)
- }
- })
-
- setTimeout(t, "CmdRun timed out", 10*time.Second, func() {
- <-c
- })
-
- time.Sleep(500 * time.Millisecond)
-
- if len(globalDaemon.List()) > 0 {
- t.Fatalf("failed to remove container automatically: container %s still exists", temporaryContainerID)
- }
-}
diff --git a/integration/container_test.go b/integration/container_test.go
index b6cbfd096103a..9256e9997f2a4 100644
--- a/integration/container_test.go
+++ b/integration/container_test.go
@@ -14,7 +14,7 @@ func TestRestartStdin(t *testing.T) {
defer nuke(daemon)
container, _, err := daemon.Create(&runconfig.Config{
Image: GetTestImage(daemon).ID,
- Cmd: []string{"cat"},
+ Cmd: runconfig.NewCommand("cat"),
OpenStdin: true,
},
@@ -79,7 +79,7 @@ func TestStdin(t *testing.T) {
defer nuke(daemon)
container, _, err := daemon.Create(&runconfig.Config{
Image: GetTestImage(daemon).ID,
- Cmd: []string{"cat"},
+ Cmd: runconfig.NewCommand("cat"),
OpenStdin: true,
},
@@ -119,7 +119,7 @@ func TestTty(t *testing.T) {
defer nuke(daemon)
container, _, err := daemon.Create(&runconfig.Config{
Image: GetTestImage(daemon).ID,
- Cmd: []string{"cat"},
+ Cmd: runconfig.NewCommand("cat"),
OpenStdin: true,
},
@@ -160,7 +160,7 @@ func BenchmarkRunSequential(b *testing.B) {
for i := 0; i < b.N; i++ {
container, _, err := daemon.Create(&runconfig.Config{
Image: GetTestImage(daemon).ID,
- Cmd: []string{"echo", "-n", "foo"},
+ Cmd: runconfig.NewCommand("echo", "-n", "foo"),
},
&runconfig.HostConfig{},
"",
@@ -194,7 +194,7 @@ func BenchmarkRunParallel(b *testing.B) {
go func(i int, complete chan error) {
container, _, err := daemon.Create(&runconfig.Config{
Image: GetTestImage(daemon).ID,
- Cmd: []string{"echo", "-n", "foo"},
+ Cmd: runconfig.NewCommand("echo", "-n", "foo"),
},
&runconfig.HostConfig{},
"",
@@ -213,7 +213,7 @@ func BenchmarkRunParallel(b *testing.B) {
return
}
// if string(output) != "foo" {
- // complete <- fmt.Errorf("Unexecpted output: %v", string(output))
+ // complete <- fmt.Errorf("Unexpected output: %v", string(output))
// }
if err := daemon.Rm(container); err != nil {
complete <- err
diff --git a/integration/https_test.go b/integration/https_test.go
deleted file mode 100644
index 17d69345a9529..0000000000000
--- a/integration/https_test.go
+++ /dev/null
@@ -1,84 +0,0 @@
-package docker
-
-import (
- "crypto/tls"
- "crypto/x509"
- "io/ioutil"
- "strings"
- "testing"
- "time"
-
- "github.com/docker/docker/api/client"
-)
-
-const (
- errBadCertificate = "remote error: bad certificate"
- errCaUnknown = "x509: certificate signed by unknown authority"
-)
-
-func getTlsConfig(certFile, keyFile string, t *testing.T) *tls.Config {
- certPool := x509.NewCertPool()
- file, err := ioutil.ReadFile("fixtures/https/ca.pem")
- if err != nil {
- t.Fatal(err)
- }
- certPool.AppendCertsFromPEM(file)
-
- cert, err := tls.LoadX509KeyPair("fixtures/https/"+certFile, "fixtures/https/"+keyFile)
- if err != nil {
- t.Fatalf("Couldn't load X509 key pair: %s", err)
- }
- tlsConfig := &tls.Config{
- RootCAs: certPool,
- Certificates: []tls.Certificate{cert},
- }
- return tlsConfig
-}
-
-// TestHttpsInfo connects via two-way authenticated HTTPS to the info endpoint
-func TestHttpsInfo(t *testing.T) {
- cli := client.NewDockerCli(nil, ioutil.Discard, ioutil.Discard, "", testDaemonProto,
- testDaemonHttpsAddr, getTlsConfig("client-cert.pem", "client-key.pem", t))
-
- setTimeout(t, "Reading command output time out", 10*time.Second, func() {
- if err := cli.CmdInfo(); err != nil {
- t.Fatal(err)
- }
- })
-}
-
-// TestHttpsInfoRogueCert connects via two-way authenticated HTTPS to the info endpoint
-// by using a rogue client certificate and checks that it fails with the expected error.
-func TestHttpsInfoRogueCert(t *testing.T) {
- cli := client.NewDockerCli(nil, ioutil.Discard, ioutil.Discard, "", testDaemonProto,
- testDaemonHttpsAddr, getTlsConfig("client-rogue-cert.pem", "client-rogue-key.pem", t))
-
- setTimeout(t, "Reading command output time out", 10*time.Second, func() {
- err := cli.CmdInfo()
- if err == nil {
- t.Fatal("Expected error but got nil")
- }
- if !strings.Contains(err.Error(), errBadCertificate) {
- t.Fatalf("Expected error: %s, got instead: %s", errBadCertificate, err)
- }
- })
-}
-
-// TestHttpsInfoRogueServerCert connects via two-way authenticated HTTPS to the info endpoint
-// which provides a rogue server certificate and checks that it fails with the expected error
-func TestHttpsInfoRogueServerCert(t *testing.T) {
- cli := client.NewDockerCli(nil, ioutil.Discard, ioutil.Discard, "", testDaemonProto,
- testDaemonRogueHttpsAddr, getTlsConfig("client-cert.pem", "client-key.pem", t))
-
- setTimeout(t, "Reading command output time out", 10*time.Second, func() {
- err := cli.CmdInfo()
- if err == nil {
- t.Fatal("Expected error but got nil")
- }
-
- if !strings.Contains(err.Error(), errCaUnknown) {
- t.Fatalf("Expected error: %s, got instead: %s", errCaUnknown, err)
- }
-
- })
-}
diff --git a/integration/runtime_test.go b/integration/runtime_test.go
index b5e404d59dfe2..a2f22072c36b8 100644
--- a/integration/runtime_test.go
+++ b/integration/runtime_test.go
@@ -17,12 +17,15 @@ import (
"time"
"github.com/Sirupsen/logrus"
+ apiserver "github.com/docker/docker/api/server"
+ "github.com/docker/docker/cliconfig"
"github.com/docker/docker/daemon"
"github.com/docker/docker/daemon/execdriver"
"github.com/docker/docker/engine"
"github.com/docker/docker/graph"
"github.com/docker/docker/image"
"github.com/docker/docker/nat"
+ "github.com/docker/docker/pkg/fileutils"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/reexec"
"github.com/docker/docker/pkg/stringid"
@@ -45,9 +48,7 @@ const (
)
var (
- // FIXME: globalDaemon is deprecated by globalEngine. All tests should be converted.
globalDaemon *daemon.Daemon
- globalEngine *engine.Engine
globalHttpsEngine *engine.Engine
globalRogueHttpsEngine *engine.Engine
startFds int
@@ -119,21 +120,28 @@ func init() {
// Create the "global daemon" with a long-running daemons for integration tests
spawnGlobalDaemon()
- spawnLegitHttpsDaemon()
- spawnRogueHttpsDaemon()
- startFds, startGoroutines = utils.GetTotalUsedFds(), runtime.NumGoroutine()
+ startFds, startGoroutines = fileutils.GetTotalUsedFds(), runtime.NumGoroutine()
}
func setupBaseImage() {
eng := newTestEngine(std_log.New(os.Stderr, "", 0), false, unitTestStoreBase)
- job := eng.Job("image_inspect", unitTestImageName)
- img, _ := job.Stdout.AddEnv()
+ d := getDaemon(eng)
+
+ _, err := d.Repositories().Lookup(unitTestImageName)
// If the unit test is not found, try to download it.
- if err := job.Run(); err != nil || img.Get("Id") != unitTestImageID {
+ if err != nil {
+ // seems like we can just ignore the error here...
+ // there was a check of imgId from job stdout against unittestid but
+ // if there was an error how could the imgid from the job
+ // be compared?! it's obvious it's different, am I totally wrong?
+
// Retrieve the Image
- job = eng.Job("pull", unitTestImageName)
- job.Stdout.Add(ioutils.NopWriteCloser(os.Stdout))
- if err := job.Run(); err != nil {
+ imagePullConfig := &graph.ImagePullConfig{
+ Parallel: true,
+ OutStream: ioutils.NopWriteCloser(os.Stdout),
+ AuthConfig: &cliconfig.AuthConfig{},
+ }
+ if err := d.Repositories().Pull(unitTestImageName, "", imagePullConfig); err != nil {
logrus.Fatalf("Unable to pull the test image: %s", err)
}
}
@@ -146,9 +154,10 @@ func spawnGlobalDaemon() {
}
t := std_log.New(os.Stderr, "", 0)
eng := NewTestEngine(t)
- globalEngine = eng
globalDaemon = mkDaemonFromEngine(eng, t)
+ serverConfig := &apiserver.ServerConfig{Logging: true}
+ api := apiserver.New(serverConfig, eng)
// Spawn a Daemon
go func() {
logrus.Debugf("Spawning global daemon for integration tests")
@@ -156,75 +165,17 @@ func spawnGlobalDaemon() {
Scheme: testDaemonProto,
Host: testDaemonAddr,
}
- job := eng.Job("serveapi", listenURL.String())
- job.SetenvBool("Logging", true)
- if err := job.Run(); err != nil {
- logrus.Fatalf("Unable to spawn the test daemon: %s", err)
- }
- }()
-
- // Give some time to ListenAndServer to actually start
- // FIXME: use inmem transports instead of tcp
- time.Sleep(time.Second)
-
- if err := eng.Job("acceptconnections").Run(); err != nil {
- logrus.Fatalf("Unable to accept connections for test api: %s", err)
- }
-}
-
-func spawnLegitHttpsDaemon() {
- if globalHttpsEngine != nil {
- return
- }
- globalHttpsEngine = spawnHttpsDaemon(testDaemonHttpsAddr, "fixtures/https/ca.pem",
- "fixtures/https/server-cert.pem", "fixtures/https/server-key.pem")
-}
-
-func spawnRogueHttpsDaemon() {
- if globalRogueHttpsEngine != nil {
- return
- }
- globalRogueHttpsEngine = spawnHttpsDaemon(testDaemonRogueHttpsAddr, "fixtures/https/ca.pem",
- "fixtures/https/server-rogue-cert.pem", "fixtures/https/server-rogue-key.pem")
-}
-func spawnHttpsDaemon(addr, cacert, cert, key string) *engine.Engine {
- t := std_log.New(os.Stderr, "", 0)
- root, err := newTestDirectory(unitTestStoreBase)
- if err != nil {
- t.Fatal(err)
- }
- // FIXME: here we don't use NewTestEngine because it configures the daemon with Autorestart=false,
- // and we want to set it to true.
-
- eng := newTestEngine(t, true, root)
-
- // Spawn a Daemon
- go func() {
- logrus.Debugf("Spawning https daemon for integration tests")
- listenURL := &url.URL{
- Scheme: testDaemonHttpsProto,
- Host: addr,
- }
- job := eng.Job("serveapi", listenURL.String())
- job.SetenvBool("Logging", true)
- job.SetenvBool("Tls", true)
- job.SetenvBool("TlsVerify", true)
- job.Setenv("TlsCa", cacert)
- job.Setenv("TlsCert", cert)
- job.Setenv("TlsKey", key)
- if err := job.Run(); err != nil {
+ if err := api.ServeApi([]string{listenURL.String()}); err != nil {
logrus.Fatalf("Unable to spawn the test daemon: %s", err)
}
}()
// Give some time to ListenAndServer to actually start
+ // FIXME: use inmem transports instead of tcp
time.Sleep(time.Second)
- if err := eng.Job("acceptconnections").Run(); err != nil {
- logrus.Fatalf("Unable to accept connections for test api: %s", err)
- }
- return eng
+ api.AcceptConnections(getDaemon(eng))
}
// FIXME: test that ImagePull(json=true) send correct json output
@@ -254,7 +205,7 @@ func TestDaemonCreate(t *testing.T) {
container, _, err := daemon.Create(&runconfig.Config{
Image: GetTestImage(daemon).ID,
- Cmd: []string{"ls", "-al"},
+ Cmd: runconfig.NewCommand("ls", "-al"),
},
&runconfig.HostConfig{},
"",
@@ -295,15 +246,16 @@ func TestDaemonCreate(t *testing.T) {
}
// Test that conflict error displays correct details
+ cmd := runconfig.NewCommand("ls", "-al")
testContainer, _, _ := daemon.Create(
&runconfig.Config{
Image: GetTestImage(daemon).ID,
- Cmd: []string{"ls", "-al"},
+ Cmd: cmd,
},
&runconfig.HostConfig{},
"conflictname",
)
- if _, _, err := daemon.Create(&runconfig.Config{Image: GetTestImage(daemon).ID, Cmd: []string{"ls", "-al"}}, &runconfig.HostConfig{}, testContainer.Name); err == nil || !strings.Contains(err.Error(), stringid.TruncateID(testContainer.ID)) {
+ if _, _, err := daemon.Create(&runconfig.Config{Image: GetTestImage(daemon).ID, Cmd: cmd}, &runconfig.HostConfig{}, testContainer.Name); err == nil || !strings.Contains(err.Error(), stringid.TruncateID(testContainer.ID)) {
t.Fatalf("Name conflict error doesn't include the correct short id. Message was: %v", err)
}
@@ -315,7 +267,7 @@ func TestDaemonCreate(t *testing.T) {
if _, _, err := daemon.Create(
&runconfig.Config{
Image: GetTestImage(daemon).ID,
- Cmd: []string{},
+ Cmd: runconfig.NewCommand(),
},
&runconfig.HostConfig{},
"",
@@ -325,7 +277,7 @@ func TestDaemonCreate(t *testing.T) {
config := &runconfig.Config{
Image: GetTestImage(daemon).ID,
- Cmd: []string{"/bin/ls"},
+ Cmd: runconfig.NewCommand("/bin/ls"),
PortSpecs: []string{"80"},
}
container, _, err = daemon.Create(config, &runconfig.HostConfig{}, "")
@@ -338,7 +290,7 @@ func TestDaemonCreate(t *testing.T) {
// test expose 80:8000
container, warnings, err := daemon.Create(&runconfig.Config{
Image: GetTestImage(daemon).ID,
- Cmd: []string{"ls", "-al"},
+ Cmd: runconfig.NewCommand("ls", "-al"),
PortSpecs: []string{"80:8000"},
},
&runconfig.HostConfig{},
@@ -358,7 +310,7 @@ func TestDestroy(t *testing.T) {
container, _, err := daemon.Create(&runconfig.Config{
Image: GetTestImage(daemon).ID,
- Cmd: []string{"ls", "-al"},
+ Cmd: runconfig.NewCommand("ls", "-al"),
},
&runconfig.HostConfig{},
"")
@@ -421,14 +373,13 @@ func TestGet(t *testing.T) {
func startEchoServerContainer(t *testing.T, proto string) (*daemon.Daemon, *daemon.Container, string) {
var (
- err error
- id string
- outputBuffer = bytes.NewBuffer(nil)
- strPort string
- eng = NewTestEngine(t)
- daemon = mkDaemonFromEngine(eng, t)
- port = 5554
- p nat.Port
+ err error
+ id string
+ strPort string
+ eng = NewTestEngine(t)
+ daemon = mkDaemonFromEngine(eng, t)
+ port = 5554
+ p nat.Port
)
defer func() {
if err != nil {
@@ -451,16 +402,14 @@ func startEchoServerContainer(t *testing.T, proto string) (*daemon.Daemon, *daem
p = nat.Port(fmt.Sprintf("%s/%s", strPort, proto))
ep[p] = struct{}{}
- jobCreate := eng.Job("create")
- jobCreate.Setenv("Image", unitTestImageID)
- jobCreate.SetenvList("Cmd", []string{"sh", "-c", cmd})
- jobCreate.SetenvList("PortSpecs", []string{fmt.Sprintf("%s/%s", strPort, proto)})
- jobCreate.SetenvJson("ExposedPorts", ep)
- jobCreate.Stdout.Add(outputBuffer)
- if err := jobCreate.Run(); err != nil {
- t.Fatal(err)
+ c := &runconfig.Config{
+ Image: unitTestImageID,
+ Cmd: runconfig.NewCommand("sh", "-c", cmd),
+ PortSpecs: []string{fmt.Sprintf("%s/%s", strPort, proto)},
+ ExposedPorts: ep,
}
- id = engine.Tail(outputBuffer, 1)
+
+ id, _, err = daemon.ContainerCreate(unitTestImageID, c, &runconfig.HostConfig{})
// FIXME: this relies on the undocumented behavior of daemon.Create
// which will return a nil error AND container if the exposed ports
// are invalid. That behavior should be fixed!
@@ -471,15 +420,7 @@ func startEchoServerContainer(t *testing.T, proto string) (*daemon.Daemon, *daem
}
- jobStart := eng.Job("start", id)
- portBindings := make(map[nat.Port][]nat.PortBinding)
- portBindings[p] = []nat.PortBinding{
- {},
- }
- if err := jobStart.SetenvJson("PortsBindings", portBindings); err != nil {
- t.Fatal(err)
- }
- if err := jobStart.Run(); err != nil {
+ if err := daemon.ContainerStart(id, &runconfig.HostConfig{}); err != nil {
t.Fatal(err)
}
@@ -730,20 +671,15 @@ func TestContainerNameValidation(t *testing.T) {
t.Fatal(err)
}
- var outputBuffer = bytes.NewBuffer(nil)
- job := eng.Job("create", test.Name)
- if err := job.ImportEnv(config); err != nil {
- t.Fatal(err)
- }
- job.Stdout.Add(outputBuffer)
- if err := job.Run(); err != nil {
+ containerId, _, err := daemon.ContainerCreate(test.Name, config, &runconfig.HostConfig{})
+ if err != nil {
if !test.Valid {
continue
}
t.Fatal(err)
}
- container, err := daemon.Get(engine.Tail(outputBuffer, 1))
+ container, err := daemon.Get(containerId)
if err != nil {
t.Fatal(err)
}
@@ -758,7 +694,6 @@ func TestContainerNameValidation(t *testing.T) {
t.Fatalf("Container /%s has ID %s instead of %s", test.Name, c.ID, container.ID)
}
}
-
}
func TestLinkChildContainer(t *testing.T) {
@@ -875,7 +810,7 @@ func TestDestroyWithInitLayer(t *testing.T) {
container, _, err := daemon.Create(&runconfig.Config{
Image: GetTestImage(daemon).ID,
- Cmd: []string{"ls", "-al"},
+ Cmd: runconfig.NewCommand("ls", "-al"),
},
&runconfig.HostConfig{},
"")
@@ -902,7 +837,7 @@ func TestDestroyWithInitLayer(t *testing.T) {
// Make sure that the container does not exist in the driver
if _, err := driver.Get(container.ID, ""); err == nil {
- t.Fatal("Conttainer should not exist in the driver")
+ t.Fatal("Container should not exist in the driver")
}
// Make sure that the init layer is removed from the driver
diff --git a/integration/server_test.go b/integration/server_test.go
deleted file mode 100644
index b2c4dd80a4004..0000000000000
--- a/integration/server_test.go
+++ /dev/null
@@ -1,214 +0,0 @@
-package docker
-
-import (
- "bytes"
- "testing"
- "time"
-
- "github.com/docker/docker/builder"
- "github.com/docker/docker/daemon"
- "github.com/docker/docker/engine"
-)
-
-func TestCreateNumberHostname(t *testing.T) {
- eng := NewTestEngine(t)
- defer mkDaemonFromEngine(eng, t).Nuke()
-
- config, _, _, err := parseRun([]string{"-h", "web.0", unitTestImageID, "echo test"})
- if err != nil {
- t.Fatal(err)
- }
-
- createTestContainer(eng, config, t)
-}
-
-func TestCommit(t *testing.T) {
- eng := NewTestEngine(t)
- b := &builder.BuilderJob{Engine: eng}
- b.Install()
- defer mkDaemonFromEngine(eng, t).Nuke()
-
- config, _, _, err := parseRun([]string{unitTestImageID, "/bin/cat"})
- if err != nil {
- t.Fatal(err)
- }
-
- id := createTestContainer(eng, config, t)
-
- job := eng.Job("commit", id)
- job.Setenv("repo", "testrepo")
- job.Setenv("tag", "testtag")
- job.SetenvJson("config", config)
- if err := job.Run(); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestMergeConfigOnCommit(t *testing.T) {
- eng := NewTestEngine(t)
- b := &builder.BuilderJob{Engine: eng}
- b.Install()
- runtime := mkDaemonFromEngine(eng, t)
- defer runtime.Nuke()
-
- container1, _, _ := mkContainer(runtime, []string{"-e", "FOO=bar", unitTestImageID, "echo test > /tmp/foo"}, t)
- defer runtime.Rm(container1)
-
- config, _, _, err := parseRun([]string{container1.ID, "cat /tmp/foo"})
- if err != nil {
- t.Error(err)
- }
-
- job := eng.Job("commit", container1.ID)
- job.Setenv("repo", "testrepo")
- job.Setenv("tag", "testtag")
- job.SetenvJson("config", config)
- var outputBuffer = bytes.NewBuffer(nil)
- job.Stdout.Add(outputBuffer)
- if err := job.Run(); err != nil {
- t.Error(err)
- }
-
- container2, _, _ := mkContainer(runtime, []string{engine.Tail(outputBuffer, 1)}, t)
- defer runtime.Rm(container2)
-
- job = eng.Job("container_inspect", container1.Name)
- baseContainer, _ := job.Stdout.AddEnv()
- if err := job.Run(); err != nil {
- t.Error(err)
- }
-
- job = eng.Job("container_inspect", container2.Name)
- commitContainer, _ := job.Stdout.AddEnv()
- if err := job.Run(); err != nil {
- t.Error(err)
- }
-
- baseConfig := baseContainer.GetSubEnv("Config")
- commitConfig := commitContainer.GetSubEnv("Config")
-
- if commitConfig.Get("Env") != baseConfig.Get("Env") {
- t.Fatalf("Env config in committed container should be %v, was %v",
- baseConfig.Get("Env"), commitConfig.Get("Env"))
- }
-
- if baseConfig.Get("Cmd") != "[\"echo test \\u003e /tmp/foo\"]" {
- t.Fatalf("Cmd in base container should be [\"echo test \\u003e /tmp/foo\"], was %s",
- baseConfig.Get("Cmd"))
- }
-
- if commitConfig.Get("Cmd") != "[\"cat /tmp/foo\"]" {
- t.Fatalf("Cmd in committed container should be [\"cat /tmp/foo\"], was %s",
- commitConfig.Get("Cmd"))
- }
-}
-
-func TestRestartKillWait(t *testing.T) {
- eng := NewTestEngine(t)
- runtime := mkDaemonFromEngine(eng, t)
- defer runtime.Nuke()
-
- config, hostConfig, _, err := parseRun([]string{"-i", unitTestImageID, "/bin/cat"})
- if err != nil {
- t.Fatal(err)
- }
-
- id := createTestContainer(eng, config, t)
-
- containers, err := runtime.Containers(&daemon.ContainersConfig{All: true})
-
- if err != nil {
- t.Errorf("Error getting containers1: %q", err)
- }
-
- if len(containers) != 1 {
- t.Errorf("Expected 1 container, %v found", len(containers))
- }
-
- job := eng.Job("start", id)
- if err := job.ImportEnv(hostConfig); err != nil {
- t.Fatal(err)
- }
- if err := job.Run(); err != nil {
- t.Fatal(err)
- }
- job = eng.Job("kill", id)
- if err := job.Run(); err != nil {
- t.Fatal(err)
- }
-
- eng = newTestEngine(t, false, runtime.Config().Root)
- runtime = mkDaemonFromEngine(eng, t)
-
- containers, err = runtime.Containers(&daemon.ContainersConfig{All: true})
-
- if err != nil {
- t.Errorf("Error getting containers1: %q", err)
- }
- if len(containers) != 1 {
- t.Errorf("Expected 1 container, %v found", len(containers))
- }
-
- setTimeout(t, "Waiting on stopped container timedout", 5*time.Second, func() {
- job = eng.Job("wait", containers[0].ID)
- if err := job.Run(); err != nil {
- t.Fatal(err)
- }
- })
-}
-
-func TestRunWithTooLowMemoryLimit(t *testing.T) {
- eng := NewTestEngine(t)
- defer mkDaemonFromEngine(eng, t).Nuke()
-
- // Try to create a container with a memory limit of 1 byte less than the minimum allowed limit.
- job := eng.Job("create")
- job.Setenv("Image", unitTestImageID)
- job.Setenv("Memory", "524287")
- job.Setenv("CpuShares", "1000")
- job.SetenvList("Cmd", []string{"/bin/cat"})
- if err := job.Run(); err == nil {
- t.Errorf("Memory limit is smaller than the allowed limit. Container creation should've failed!")
- }
-}
-
-func TestImagesFilter(t *testing.T) {
- eng := NewTestEngine(t)
- defer nuke(mkDaemonFromEngine(eng, t))
-
- if err := eng.Job("tag", unitTestImageName, "utest", "tag1").Run(); err != nil {
- t.Fatal(err)
- }
-
- if err := eng.Job("tag", unitTestImageName, "utest/docker", "tag2").Run(); err != nil {
- t.Fatal(err)
- }
-
- if err := eng.Job("tag", unitTestImageName, "utest:5000/docker", "tag3").Run(); err != nil {
- t.Fatal(err)
- }
-
- images := getImages(eng, t, false, "utest*/*")
-
- if len(images[0].RepoTags) != 2 {
- t.Fatal("incorrect number of matches returned")
- }
-
- images = getImages(eng, t, false, "utest")
-
- if len(images[0].RepoTags) != 1 {
- t.Fatal("incorrect number of matches returned")
- }
-
- images = getImages(eng, t, false, "utest*")
-
- if len(images[0].RepoTags) != 1 {
- t.Fatal("incorrect number of matches returned")
- }
-
- images = getImages(eng, t, false, "*5000*/*")
-
- if len(images[0].RepoTags) != 1 {
- t.Fatal("incorrect number of matches returned")
- }
-}
diff --git a/integration/utils.go b/integration/utils.go
new file mode 100644
index 0000000000000..62e02e9bb141f
--- /dev/null
+++ b/integration/utils.go
@@ -0,0 +1,88 @@
+package docker
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/docker/docker/daemon"
+)
+
+func closeWrap(args ...io.Closer) error {
+ e := false
+ ret := fmt.Errorf("Error closing elements")
+ for _, c := range args {
+ if err := c.Close(); err != nil {
+ e = true
+ ret = fmt.Errorf("%s\n%s", ret, err)
+ }
+ }
+ if e {
+ return ret
+ }
+ return nil
+}
+
+func waitContainerStart(t *testing.T, timeout time.Duration) *daemon.Container {
+ var container *daemon.Container
+
+ setTimeout(t, "Waiting for the container to be started timed out", timeout, func() {
+ for {
+ l := globalDaemon.List()
+ if len(l) == 1 && l[0].IsRunning() {
+ container = l[0]
+ break
+ }
+ time.Sleep(10 * time.Millisecond)
+ }
+ })
+
+ if container == nil {
+ t.Fatal("An error occurred while waiting for the container to start")
+ }
+
+ return container
+}
+
+func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
+ c := make(chan bool)
+
+ // Make sure we are not too long
+ go func() {
+ time.Sleep(d)
+ c <- true
+ }()
+ go func() {
+ f()
+ c <- false
+ }()
+ if <-c && msg != "" {
+ t.Fatal(msg)
+ }
+}
+
+func expectPipe(expected string, r io.Reader) error {
+ o, err := bufio.NewReader(r).ReadString('\n')
+ if err != nil {
+ return err
+ }
+ if strings.Trim(o, " \r\n") != expected {
+ return fmt.Errorf("Unexpected output. Expected [%s], received [%s]", expected, o)
+ }
+ return nil
+}
+
+func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error {
+ for i := 0; i < count; i++ {
+ if _, err := w.Write([]byte(input)); err != nil {
+ return err
+ }
+ if err := expectPipe(output, r); err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/integration/utils_test.go b/integration/utils_test.go
index 5c9a61b607110..9479d4296cd81 100644
--- a/integration/utils_test.go
+++ b/integration/utils_test.go
@@ -17,7 +17,6 @@ import (
"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
"github.com/docker/docker/api/types"
- "github.com/docker/docker/builtins"
"github.com/docker/docker/daemon"
"github.com/docker/docker/daemon/networkdriver/bridge"
"github.com/docker/docker/engine"
@@ -44,16 +43,11 @@ func mkDaemon(f Fataler) *daemon.Daemon {
}
func createNamedTestContainer(eng *engine.Engine, config *runconfig.Config, f Fataler, name string) (shortId string) {
- job := eng.Job("create", name)
- if err := job.ImportEnv(config); err != nil {
- f.Fatal(err)
- }
- var outputBuffer = bytes.NewBuffer(nil)
- job.Stdout.Add(outputBuffer)
- if err := job.Run(); err != nil {
+ containerId, _, err := getDaemon(eng).ContainerCreate(name, config, &runconfig.HostConfig{})
+ if err != nil {
f.Fatal(err)
}
- return engine.Tail(outputBuffer, 1)
+ return containerId
}
func createTestContainer(eng *engine.Engine, config *runconfig.Config, f Fataler) (shortId string) {
@@ -61,8 +55,7 @@ func createTestContainer(eng *engine.Engine, config *runconfig.Config, f Fataler
}
func startContainer(eng *engine.Engine, id string, t Fataler) {
- job := eng.Job("start", id)
- if err := job.Run(); err != nil {
+ if err := getDaemon(eng).ContainerStart(id, &runconfig.HostConfig{}); err != nil {
t.Fatal(err)
}
}
@@ -105,7 +98,7 @@ func containerWaitTimeout(eng *engine.Engine, id string, t Fataler) error {
}
func containerKill(eng *engine.Engine, id string, t Fataler) {
- if err := eng.Job("kill", id).Run(); err != nil {
+ if err := getDaemon(eng).ContainerKill(id, 0); err != nil {
t.Fatal(err)
}
}
@@ -176,10 +169,6 @@ func newTestEngine(t Fataler, autorestart bool, root string) *engine.Engine {
eng := engine.New()
eng.Logging = false
- // Load default plugins
- if err := builtins.Register(eng); err != nil {
- t.Fatal(err)
- }
// (This is manually copied and modified from main() until we have a more generic plugin system)
cfg := &daemon.Config{
diff --git a/integration/z_final_test.go b/integration/z_final_test.go
index 13cd0c3fd4f0a..d6ef2884f2518 100644
--- a/integration/z_final_test.go
+++ b/integration/z_final_test.go
@@ -1,13 +1,14 @@
package docker
import (
- "github.com/docker/docker/utils"
"runtime"
"testing"
+
+ "github.com/docker/docker/pkg/fileutils"
)
func displayFdGoroutines(t *testing.T) {
- t.Logf("File Descriptors: %d, Goroutines: %d", utils.GetTotalUsedFds(), runtime.NumGoroutine())
+ t.Logf("File Descriptors: %d, Goroutines: %d", fileutils.GetTotalUsedFds(), runtime.NumGoroutine())
}
func TestFinal(t *testing.T) {
diff --git a/links/links.go b/links/links.go
index 0e5e806e57be3..935bff4ae3911 100644
--- a/links/links.go
+++ b/links/links.go
@@ -6,8 +6,8 @@ import (
"strings"
"github.com/docker/docker/daemon/networkdriver/bridge"
- "github.com/docker/docker/engine"
"github.com/docker/docker/nat"
+ "github.com/docker/docker/pkg/iptables"
)
type Link struct {
@@ -17,10 +17,9 @@ type Link struct {
ChildEnvironment []string
Ports []nat.Port
IsEnabled bool
- eng *engine.Engine
}
-func NewLink(parentIP, childIP, name string, env []string, exposedPorts map[nat.Port]struct{}, eng *engine.Engine) (*Link, error) {
+func NewLink(parentIP, childIP, name string, env []string, exposedPorts map[nat.Port]struct{}) (*Link, error) {
var (
i int
@@ -38,7 +37,6 @@ func NewLink(parentIP, childIP, name string, env []string, exposedPorts map[nat.
ParentIP: parentIP,
ChildEnvironment: env,
Ports: ports,
- eng: eng,
}
return l, nil
@@ -109,8 +107,8 @@ func (l *Link) ToEnv() []string {
if l.ChildEnvironment != nil {
for _, v := range l.ChildEnvironment {
- parts := strings.Split(v, "=")
- if len(parts) != 2 {
+ parts := strings.SplitN(v, "=", 2)
+ if len(parts) < 2 {
continue
}
// Ignore a few variables that are added during docker build (and not really relevant to linked containers)
@@ -146,6 +144,8 @@ func (l *Link) Enable() error {
if err := l.toggle("-A", false); err != nil {
return err
}
+ // call this on Firewalld reload
+ iptables.OnReloaded(func() { l.toggle("-I", false) })
l.IsEnabled = true
return nil
}
@@ -155,7 +155,8 @@ func (l *Link) Disable() {
// exist in iptables
// -D == iptables delete flag
l.toggle("-D", true)
-
+ // call this on Firewalld reload
+ iptables.OnReloaded(func() { l.toggle("-D", true) })
l.IsEnabled = false
}
diff --git a/links/links_test.go b/links/links_test.go
index ba548fc5b3922..e639e2c42e557 100644
--- a/links/links_test.go
+++ b/links/links_test.go
@@ -2,16 +2,17 @@ package links
import (
"fmt"
- "github.com/docker/docker/nat"
"strings"
"testing"
+
+ "github.com/docker/docker/nat"
)
func TestLinkNaming(t *testing.T) {
ports := make(nat.PortSet)
ports[nat.Port("6379/tcp")] = struct{}{}
- link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker-1", nil, ports, nil)
+ link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker-1", nil, ports)
if err != nil {
t.Fatal(err)
}
@@ -41,7 +42,7 @@ func TestLinkNew(t *testing.T) {
ports := make(nat.PortSet)
ports[nat.Port("6379/tcp")] = struct{}{}
- link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", nil, ports, nil)
+ link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", nil, ports)
if err != nil {
t.Fatal(err)
}
@@ -72,7 +73,7 @@ func TestLinkEnv(t *testing.T) {
ports := make(nat.PortSet)
ports[nat.Port("6379/tcp")] = struct{}{}
- link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", []string{"PASSWORD=gordon"}, ports, nil)
+ link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", []string{"PASSWORD=gordon"}, ports)
if err != nil {
t.Fatal(err)
}
@@ -115,7 +116,7 @@ func TestLinkMultipleEnv(t *testing.T) {
ports[nat.Port("6380/tcp")] = struct{}{}
ports[nat.Port("6381/tcp")] = struct{}{}
- link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", []string{"PASSWORD=gordon"}, ports, nil)
+ link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", []string{"PASSWORD=gordon"}, ports)
if err != nil {
t.Fatal(err)
}
@@ -164,7 +165,7 @@ func TestLinkPortRangeEnv(t *testing.T) {
ports[nat.Port("6380/tcp")] = struct{}{}
ports[nat.Port("6381/tcp")] = struct{}{}
- link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", []string{"PASSWORD=gordon"}, ports, nil)
+ link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", []string{"PASSWORD=gordon"}, ports)
if err != nil {
t.Fatal(err)
}
diff --git a/opts/opts.go b/opts/opts.go
index df9decf61fa0c..d2c32f13c7229 100644
--- a/opts/opts.go
+++ b/opts/opts.go
@@ -8,16 +8,16 @@ import (
"regexp"
"strings"
- "github.com/docker/docker/api"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/ulimit"
- "github.com/docker/docker/utils"
)
var (
- alphaRegexp = regexp.MustCompile(`[a-zA-Z]`)
- domainRegexp = regexp.MustCompile(`^(:?(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]))(:?\.(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])))*)\.?\s*$`)
+ alphaRegexp = regexp.MustCompile(`[a-zA-Z]`)
+ domainRegexp = regexp.MustCompile(`^(:?(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]))(:?\.(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])))*)\.?\s*$`)
+ DefaultHTTPHost = "127.0.0.1" // Default HTTP Host used if only port is provided to -H flag e.g. docker -d -H tcp://:8080
+ DefaultUnixSocket = "/var/run/docker.sock" // Docker daemon by default always listens on the default unix socket
)
func ListVar(values *[]string, names []string, usage string) {
@@ -25,7 +25,7 @@ func ListVar(values *[]string, names []string, usage string) {
}
func HostListVar(values *[]string, names []string, usage string) {
- flag.Var(newListOptsRef(values, api.ValidateHost), names, usage)
+ flag.Var(newListOptsRef(values, ValidateHost), names, usage)
}
func IPListVar(values *[]string, names []string, usage string) {
@@ -174,7 +174,7 @@ func ValidateEnv(val string) (string, error) {
if len(arr) > 1 {
return val, nil
}
- if !utils.DoesEnvExist(val) {
+ if !doesEnvExist(val) {
return val, nil
}
return fmt.Sprintf("%s=%s", val, os.Getenv(val)), nil
@@ -234,3 +234,21 @@ func ValidateLabel(val string) (string, error) {
}
return val, nil
}
+
+func ValidateHost(val string) (string, error) {
+ host, err := parsers.ParseHost(DefaultHTTPHost, DefaultUnixSocket, val)
+ if err != nil {
+ return val, err
+ }
+ return host, nil
+}
+
+func doesEnvExist(name string) bool {
+ for _, entry := range os.Environ() {
+ parts := strings.SplitN(entry, "=", 2)
+ if parts[0] == name {
+ return true
+ }
+ }
+ return false
+}
diff --git a/pkg/archive/archive.go b/pkg/archive/archive.go
index 7082cd9088277..4d8d260087595 100644
--- a/pkg/archive/archive.go
+++ b/pkg/archive/archive.go
@@ -388,25 +388,16 @@ func Tar(path string, compression Compression) (io.ReadCloser, error) {
return TarWithOptions(path, &TarOptions{Compression: compression})
}
-func escapeName(name string) string {
- escaped := make([]byte, 0)
- for i, c := range []byte(name) {
- if i == 0 && c == '/' {
- continue
- }
- // all printable chars except "-" which is 0x2d
- if (0x20 <= c && c <= 0x7E) && c != 0x2d {
- escaped = append(escaped, c)
- } else {
- escaped = append(escaped, fmt.Sprintf("\\%03o", c)...)
- }
- }
- return string(escaped)
-}
-
// TarWithOptions creates an archive from the directory at `path`, only including files whose relative
// paths are included in `options.IncludeFiles` (if non-nil) or not in `options.ExcludePatterns`.
func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) {
+
+ patterns, patDirs, exceptions, err := fileutils.CleanPatterns(options.ExcludePatterns)
+
+ if err != nil {
+ return nil, err
+ }
+
pipeReader, pipeWriter := io.Pipe()
compressWriter, err := CompressStream(pipeWriter, options.Compression)
@@ -457,7 +448,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
// is asking for that file no matter what - which is true
// for some files, like .dockerignore and Dockerfile (sometimes)
if include != relFilePath {
- skip, err = fileutils.Matches(relFilePath, options.ExcludePatterns)
+ skip, err = fileutils.OptimizedMatches(relFilePath, patterns, patDirs)
if err != nil {
logrus.Debugf("Error matching %s", relFilePath, err)
return err
@@ -465,7 +456,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
}
if skip {
- if f.IsDir() {
+ if !exceptions && f.IsDir() {
return filepath.SkipDir
}
return nil
diff --git a/pkg/archive/archive_test.go b/pkg/archive/archive_test.go
index c127b307e2bc0..ae9b5a8cd2520 100644
--- a/pkg/archive/archive_test.go
+++ b/pkg/archive/archive_test.go
@@ -14,9 +14,150 @@ import (
"testing"
"time"
+ "github.com/docker/docker/pkg/system"
"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
)
+func TestIsArchiveNilHeader(t *testing.T) {
+ out := IsArchive(nil)
+ if out {
+ t.Fatalf("isArchive should return false as nil is not a valid archive header")
+ }
+}
+
+func TestIsArchiveInvalidHeader(t *testing.T) {
+ header := []byte{0x00, 0x01, 0x02}
+ out := IsArchive(header)
+ if out {
+ t.Fatalf("isArchive should return false as %s is not a valid archive header", header)
+ }
+}
+
+func TestIsArchiveBzip2(t *testing.T) {
+ header := []byte{0x42, 0x5A, 0x68}
+ out := IsArchive(header)
+ if !out {
+ t.Fatalf("isArchive should return true as %s is a bz2 header", header)
+ }
+}
+
+func TestIsArchive7zip(t *testing.T) {
+ header := []byte{0x50, 0x4b, 0x03, 0x04}
+ out := IsArchive(header)
+ if out {
+ t.Fatalf("isArchive should return false as %s is a 7z header and it is not supported", header)
+ }
+}
+
+func TestDecompressStreamGzip(t *testing.T) {
+ cmd := exec.Command("/bin/sh", "-c", "touch /tmp/archive && gzip -f /tmp/archive")
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Fail to create an archive file for test : %s.", output)
+ }
+ archive, err := os.Open("/tmp/archive.gz")
+ _, err = DecompressStream(archive)
+ if err != nil {
+ t.Fatalf("Failed to decompress a gzip file.")
+ }
+}
+
+func TestDecompressStreamBzip2(t *testing.T) {
+ cmd := exec.Command("/bin/sh", "-c", "touch /tmp/archive && bzip2 -f /tmp/archive")
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Fail to create an archive file for test : %s.", output)
+ }
+ archive, err := os.Open("/tmp/archive.bz2")
+ _, err = DecompressStream(archive)
+ if err != nil {
+ t.Fatalf("Failed to decompress a bzip2 file.")
+ }
+}
+
+func TestDecompressStreamXz(t *testing.T) {
+ cmd := exec.Command("/bin/sh", "-c", "touch /tmp/archive && xz -f /tmp/archive")
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Fail to create an archive file for test : %s.", output)
+ }
+ archive, err := os.Open("/tmp/archive.xz")
+ _, err = DecompressStream(archive)
+ if err != nil {
+ t.Fatalf("Failed to decompress a xz file.")
+ }
+}
+
+func TestCompressStreamXzUnsuported(t *testing.T) {
+ dest, err := os.Create("/tmp/dest")
+ if err != nil {
+ t.Fatalf("Fail to create the destination file")
+ }
+ _, err = CompressStream(dest, Xz)
+ if err == nil {
+ t.Fatalf("Should fail as xz is unsupported for compression format.")
+ }
+}
+
+func TestCompressStreamBzip2Unsupported(t *testing.T) {
+ dest, err := os.Create("/tmp/dest")
+ if err != nil {
+ t.Fatalf("Fail to create the destination file")
+ }
+ _, err = CompressStream(dest, Xz)
+ if err == nil {
+ t.Fatalf("Should fail as xz is unsupported for compression format.")
+ }
+}
+
+func TestCompressStreamInvalid(t *testing.T) {
+ dest, err := os.Create("/tmp/dest")
+ if err != nil {
+ t.Fatalf("Fail to create the destination file")
+ }
+ _, err = CompressStream(dest, -1)
+ if err == nil {
+ t.Fatalf("Should fail as xz is unsupported for compression format.")
+ }
+}
+
+func TestExtensionInvalid(t *testing.T) {
+ compression := Compression(-1)
+ output := compression.Extension()
+ if output != "" {
+ t.Fatalf("The extension of an invalid compression should be an empty string.")
+ }
+}
+
+func TestExtensionUncompressed(t *testing.T) {
+ compression := Uncompressed
+ output := compression.Extension()
+ if output != "tar" {
+ t.Fatalf("The extension of a uncompressed archive should be 'tar'.")
+ }
+}
+func TestExtensionBzip2(t *testing.T) {
+ compression := Bzip2
+ output := compression.Extension()
+ if output != "tar.bz2" {
+ t.Fatalf("The extension of a bzip2 archive should be 'tar.bz2'")
+ }
+}
+func TestExtensionGzip(t *testing.T) {
+ compression := Gzip
+ output := compression.Extension()
+ if output != "tar.gz" {
+ t.Fatalf("The extension of a bzip2 archive should be 'tar.gz'")
+ }
+}
+func TestExtensionXz(t *testing.T) {
+ compression := Xz
+ output := compression.Extension()
+ if output != "tar.xz" {
+ t.Fatalf("The extension of a bzip2 archive should be 'tar.xz'")
+ }
+}
+
func TestCmdStreamLargeStderr(t *testing.T) {
cmd := exec.Command("/bin/sh", "-c", "dd if=/dev/zero bs=1k count=1000 of=/dev/stderr; echo hello")
out, err := CmdStream(cmd, nil)
@@ -66,6 +207,315 @@ func TestCmdStreamGood(t *testing.T) {
}
}
+func TestUntarPathWithInvalidDest(t *testing.T) {
+ tempFolder, err := ioutil.TempDir("", "docker-archive-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tempFolder)
+ invalidDestFolder := path.Join(tempFolder, "invalidDest")
+ // Create a src file
+ srcFile := path.Join(tempFolder, "src")
+ _, err = os.Create(srcFile)
+ if err != nil {
+ t.Fatalf("Fail to create the source file")
+ }
+ err = UntarPath(srcFile, invalidDestFolder)
+ if err == nil {
+ t.Fatalf("UntarPath with invalid destination path should throw an error.")
+ }
+}
+
+func TestUntarPathWithInvalidSrc(t *testing.T) {
+ dest, err := ioutil.TempDir("", "docker-archive-test")
+ if err != nil {
+ t.Fatalf("Fail to create the destination file")
+ }
+ defer os.RemoveAll(dest)
+ err = UntarPath("/invalid/path", dest)
+ if err == nil {
+ t.Fatalf("UntarPath with invalid src path should throw an error.")
+ }
+}
+
+func TestUntarPath(t *testing.T) {
+ tmpFolder, err := ioutil.TempDir("", "docker-archive-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpFolder)
+ srcFile := path.Join(tmpFolder, "src")
+ tarFile := path.Join(tmpFolder, "src.tar")
+ os.Create(path.Join(tmpFolder, "src"))
+ cmd := exec.Command("/bin/sh", "-c", "tar cf "+tarFile+" "+srcFile)
+ _, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Fatal(err)
+ }
+ destFolder := path.Join(tmpFolder, "dest")
+ err = os.MkdirAll(destFolder, 0740)
+ if err != nil {
+ t.Fatalf("Fail to create the destination file")
+ }
+ err = UntarPath(tarFile, destFolder)
+ if err != nil {
+ t.Fatalf("UntarPath shouldn't throw an error, %s.", err)
+ }
+ expectedFile := path.Join(destFolder, srcFile)
+ _, err = os.Stat(expectedFile)
+ if err != nil {
+ t.Fatalf("Destination folder should contain the source file but did not.")
+ }
+}
+
+// Do the same test as above but with the destination as file, it should fail
+func TestUntarPathWithDestinationFile(t *testing.T) {
+ tmpFolder, err := ioutil.TempDir("", "docker-archive-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpFolder)
+ srcFile := path.Join(tmpFolder, "src")
+ tarFile := path.Join(tmpFolder, "src.tar")
+ os.Create(path.Join(tmpFolder, "src"))
+ cmd := exec.Command("/bin/sh", "-c", "tar cf "+tarFile+" "+srcFile)
+ _, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Fatal(err)
+ }
+ destFile := path.Join(tmpFolder, "dest")
+ _, err = os.Create(destFile)
+ if err != nil {
+ t.Fatalf("Fail to create the destination file")
+ }
+ err = UntarPath(tarFile, destFile)
+ if err == nil {
+ t.Fatalf("UntarPath should throw an error if the destination if a file")
+ }
+}
+
+// Do the same test as above but with the destination folder already exists
+// and the destination file is a directory
+// It's working, see https://github.com/docker/docker/issues/10040
+func TestUntarPathWithDestinationSrcFileAsFolder(t *testing.T) {
+ tmpFolder, err := ioutil.TempDir("", "docker-archive-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpFolder)
+ srcFile := path.Join(tmpFolder, "src")
+ tarFile := path.Join(tmpFolder, "src.tar")
+ os.Create(srcFile)
+ cmd := exec.Command("/bin/sh", "-c", "tar cf "+tarFile+" "+srcFile)
+ _, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Fatal(err)
+ }
+ destFolder := path.Join(tmpFolder, "dest")
+ err = os.MkdirAll(destFolder, 0740)
+ if err != nil {
+ t.Fatalf("Fail to create the destination folder")
+ }
+ // Let's create a folder that will has the same path as the extracted file (from tar)
+ destSrcFileAsFolder := path.Join(destFolder, srcFile)
+ err = os.MkdirAll(destSrcFileAsFolder, 0740)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = UntarPath(tarFile, destFolder)
+ if err != nil {
+ t.Fatalf("UntarPath should throw not throw an error if the extracted file already exists and is a folder")
+ }
+}
+
+func TestCopyWithTarInvalidSrc(t *testing.T) {
+ tempFolder, err := ioutil.TempDir("", "docker-archive-test")
+ if err != nil {
+ t.Fatal(nil)
+ }
+ destFolder := path.Join(tempFolder, "dest")
+ invalidSrc := path.Join(tempFolder, "doesnotexists")
+ err = os.MkdirAll(destFolder, 0740)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = CopyWithTar(invalidSrc, destFolder)
+ if err == nil {
+ t.Fatalf("archiver.CopyWithTar with invalid src path should throw an error.")
+ }
+}
+
+func TestCopyWithTarInexistentDestWillCreateIt(t *testing.T) {
+ tempFolder, err := ioutil.TempDir("", "docker-archive-test")
+ if err != nil {
+ t.Fatal(nil)
+ }
+ srcFolder := path.Join(tempFolder, "src")
+ inexistentDestFolder := path.Join(tempFolder, "doesnotexists")
+ err = os.MkdirAll(srcFolder, 0740)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = CopyWithTar(srcFolder, inexistentDestFolder)
+ if err != nil {
+ t.Fatalf("CopyWithTar with an inexistent folder shouldn't fail.")
+ }
+ _, err = os.Stat(inexistentDestFolder)
+ if err != nil {
+ t.Fatalf("CopyWithTar with an inexistent folder should create it.")
+ }
+}
+
+// Test CopyWithTar with a file as src
+func TestCopyWithTarSrcFile(t *testing.T) {
+ folder, err := ioutil.TempDir("", "docker-archive-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(folder)
+ dest := path.Join(folder, "dest")
+ srcFolder := path.Join(folder, "src")
+ src := path.Join(folder, path.Join("src", "src"))
+ err = os.MkdirAll(srcFolder, 0740)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = os.MkdirAll(dest, 0740)
+ if err != nil {
+ t.Fatal(err)
+ }
+ ioutil.WriteFile(src, []byte("content"), 0777)
+ err = CopyWithTar(src, dest)
+ if err != nil {
+ t.Fatalf("archiver.CopyWithTar shouldn't throw an error, %s.", err)
+ }
+ _, err = os.Stat(dest)
+ // FIXME Check the content
+ if err != nil {
+ t.Fatalf("Destination file should be the same as the source.")
+ }
+}
+
+// Test CopyWithTar with a folder as src
+func TestCopyWithTarSrcFolder(t *testing.T) {
+ folder, err := ioutil.TempDir("", "docker-archive-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(folder)
+ dest := path.Join(folder, "dest")
+ src := path.Join(folder, path.Join("src", "folder"))
+ err = os.MkdirAll(src, 0740)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = os.MkdirAll(dest, 0740)
+ if err != nil {
+ t.Fatal(err)
+ }
+ ioutil.WriteFile(path.Join(src, "file"), []byte("content"), 0777)
+ err = CopyWithTar(src, dest)
+ if err != nil {
+ t.Fatalf("archiver.CopyWithTar shouldn't throw an error, %s.", err)
+ }
+ _, err = os.Stat(dest)
+ // FIXME Check the content (the file inside)
+ if err != nil {
+ t.Fatalf("Destination folder should contain the source file but did not.")
+ }
+}
+
+func TestCopyFileWithTarInvalidSrc(t *testing.T) {
+ tempFolder, err := ioutil.TempDir("", "docker-archive-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tempFolder)
+ destFolder := path.Join(tempFolder, "dest")
+ err = os.MkdirAll(destFolder, 0740)
+ if err != nil {
+ t.Fatal(err)
+ }
+ invalidFile := path.Join(tempFolder, "doesnotexists")
+ err = CopyFileWithTar(invalidFile, destFolder)
+ if err == nil {
+ t.Fatalf("archiver.CopyWithTar with invalid src path should throw an error.")
+ }
+}
+
+func TestCopyFileWithTarInexistentDestWillCreateIt(t *testing.T) {
+ tempFolder, err := ioutil.TempDir("", "docker-archive-test")
+ if err != nil {
+ t.Fatal(nil)
+ }
+ defer os.RemoveAll(tempFolder)
+ srcFile := path.Join(tempFolder, "src")
+ inexistentDestFolder := path.Join(tempFolder, "doesnotexists")
+ _, err = os.Create(srcFile)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = CopyFileWithTar(srcFile, inexistentDestFolder)
+ if err != nil {
+ t.Fatalf("CopyWithTar with an inexistent folder shouldn't fail.")
+ }
+ _, err = os.Stat(inexistentDestFolder)
+ if err != nil {
+ t.Fatalf("CopyWithTar with an inexistent folder should create it.")
+ }
+ // FIXME Test the src file and content
+}
+
+func TestCopyFileWithTarSrcFolder(t *testing.T) {
+ folder, err := ioutil.TempDir("", "docker-archive-copyfilewithtar-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(folder)
+ dest := path.Join(folder, "dest")
+ src := path.Join(folder, "srcfolder")
+ err = os.MkdirAll(src, 0740)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = os.MkdirAll(dest, 0740)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = CopyFileWithTar(src, dest)
+ if err == nil {
+ t.Fatalf("CopyFileWithTar should throw an error with a folder.")
+ }
+}
+
+func TestCopyFileWithTarSrcFile(t *testing.T) {
+ folder, err := ioutil.TempDir("", "docker-archive-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(folder)
+ dest := path.Join(folder, "dest")
+ srcFolder := path.Join(folder, "src")
+ src := path.Join(folder, path.Join("src", "src"))
+ err = os.MkdirAll(srcFolder, 0740)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = os.MkdirAll(dest, 0740)
+ if err != nil {
+ t.Fatal(err)
+ }
+ ioutil.WriteFile(src, []byte("content"), 0777)
+ err = CopyWithTar(src, dest+"/")
+ if err != nil {
+ t.Fatalf("archiver.CopyFileWithTar shouldn't throw an error, %s.", err)
+ }
+ _, err = os.Stat(dest)
+ if err != nil {
+ t.Fatalf("Destination folder should contain the source file but did not.")
+ }
+}
+
func TestTarFiles(t *testing.T) {
// try without hardlinks
if err := checkNoChanges(1000, false); err != nil {
@@ -179,11 +629,56 @@ func TestTarUntar(t *testing.T) {
}
}
+func TestTarUntarWithXattr(t *testing.T) {
+ origin, err := ioutil.TempDir("", "docker-test-untar-origin")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(origin)
+ if err := ioutil.WriteFile(path.Join(origin, "1"), []byte("hello world"), 0700); err != nil {
+ t.Fatal(err)
+ }
+ if err := ioutil.WriteFile(path.Join(origin, "2"), []byte("welcome!"), 0700); err != nil {
+ t.Fatal(err)
+ }
+ if err := ioutil.WriteFile(path.Join(origin, "3"), []byte("will be ignored"), 0700); err != nil {
+ t.Fatal(err)
+ }
+ if err := system.Lsetxattr(path.Join(origin, "2"), "security.capability", []byte{0x00}, 0); err != nil {
+ t.Fatal(err)
+ }
+
+ for _, c := range []Compression{
+ Uncompressed,
+ Gzip,
+ } {
+ changes, err := tarUntar(t, origin, &TarOptions{
+ Compression: c,
+ ExcludePatterns: []string{"3"},
+ })
+
+ if err != nil {
+ t.Fatalf("Error tar/untar for compression %s: %s", c.Extension(), err)
+ }
+
+ if len(changes) != 1 || changes[0].Path != "/3" {
+ t.Fatalf("Unexpected differences after tarUntar: %v", changes)
+ }
+ capability, _ := system.Lgetxattr(path.Join(origin, "2"), "security.capability")
+ if capability == nil && capability[0] != 0x00 {
+ t.Fatalf("Untar should have kept the 'security.capability' xattr.")
+ }
+ }
+}
+
func TestTarWithOptions(t *testing.T) {
origin, err := ioutil.TempDir("", "docker-test-untar-origin")
if err != nil {
t.Fatal(err)
}
+ if _, err := ioutil.TempDir(origin, "folder"); err != nil {
+ t.Fatal(err)
+ }
defer os.RemoveAll(origin)
if err := ioutil.WriteFile(path.Join(origin, "1"), []byte("hello world"), 0700); err != nil {
t.Fatal(err)
@@ -196,8 +691,11 @@ func TestTarWithOptions(t *testing.T) {
opts *TarOptions
numChanges int
}{
- {&TarOptions{IncludeFiles: []string{"1"}}, 1},
+ {&TarOptions{IncludeFiles: []string{"1"}}, 2},
{&TarOptions{ExcludePatterns: []string{"2"}}, 1},
+ {&TarOptions{ExcludePatterns: []string{"1", "folder*"}}, 2},
+ {&TarOptions{IncludeFiles: []string{"1", "1"}}, 2},
+ {&TarOptions{Name: "test", IncludeFiles: []string{"1"}}, 4},
}
for _, testCase := range cases {
changes, err := tarUntar(t, origin, testCase.opts)
@@ -256,6 +754,58 @@ func TestUntarUstarGnuConflict(t *testing.T) {
}
}
+func TestTarWithBlockCharFifo(t *testing.T) {
+ origin, err := ioutil.TempDir("", "docker-test-tar-hardlink")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(origin)
+ if err := ioutil.WriteFile(path.Join(origin, "1"), []byte("hello world"), 0700); err != nil {
+ t.Fatal(err)
+ }
+ if err := system.Mknod(path.Join(origin, "2"), syscall.S_IFBLK, int(system.Mkdev(int64(12), int64(5)))); err != nil {
+ t.Fatal(err)
+ }
+ if err := system.Mknod(path.Join(origin, "3"), syscall.S_IFCHR, int(system.Mkdev(int64(12), int64(5)))); err != nil {
+ t.Fatal(err)
+ }
+ if err := system.Mknod(path.Join(origin, "4"), syscall.S_IFIFO, int(system.Mkdev(int64(12), int64(5)))); err != nil {
+ t.Fatal(err)
+ }
+
+ dest, err := ioutil.TempDir("", "docker-test-tar-hardlink-dest")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dest)
+
+ // we'll do this in two steps to separate failure
+ fh, err := Tar(origin, Uncompressed)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // ensure we can read the whole thing with no error, before writing back out
+ buf, err := ioutil.ReadAll(fh)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ bRdr := bytes.NewReader(buf)
+ err = Untar(bRdr, dest, &TarOptions{Compression: Uncompressed})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ changes, err := ChangesDirs(origin, dest)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(changes) > 0 {
+ t.Fatalf("Tar with special device (block, char, fifo) should keep them (recreate them when untar) : %v", changes)
+ }
+}
+
func TestTarWithHardLink(t *testing.T) {
origin, err := ioutil.TempDir("", "docker-test-tar-hardlink")
if err != nil {
diff --git a/pkg/archive/archive_windows_test.go b/pkg/archive/archive_windows_test.go
index b33e0fb0055a5..72bc71e06b413 100644
--- a/pkg/archive/archive_windows_test.go
+++ b/pkg/archive/archive_windows_test.go
@@ -20,7 +20,7 @@ func TestCanonicalTarNameForPath(t *testing.T) {
if out, err := CanonicalTarNameForPath(v.in); err != nil && !v.shouldFail {
t.Fatalf("cannot get canonical name for path: %s: %v", v.in, err)
} else if v.shouldFail && err == nil {
- t.Fatalf("canonical path call should have pailed with error. in=%s out=%s", v.in, out)
+ t.Fatalf("canonical path call should have failed with error. in=%s out=%s", v.in, out)
} else if !v.shouldFail && out != v.expected {
t.Fatalf("wrong canonical tar name. expected:%s got:%s", v.expected, out)
}
diff --git a/pkg/archive/changes_test.go b/pkg/archive/changes_test.go
index 53ec575b67ab3..290b2dd40222d 100644
--- a/pkg/archive/changes_test.go
+++ b/pkg/archive/changes_test.go
@@ -6,6 +6,7 @@ import (
"os/exec"
"path"
"sort"
+ "syscall"
"testing"
"time"
)
@@ -91,17 +92,130 @@ func createSampleDir(t *testing.T, root string) {
}
}
+func TestChangeString(t *testing.T) {
+ modifiyChange := Change{"change", ChangeModify}
+ toString := modifiyChange.String()
+ if toString != "C change" {
+ t.Fatalf("String() of a change with ChangeModifiy Kind should have been %s but was %s", "C change", toString)
+ }
+ addChange := Change{"change", ChangeAdd}
+ toString = addChange.String()
+ if toString != "A change" {
+ t.Fatalf("String() of a change with ChangeAdd Kind should have been %s but was %s", "A change", toString)
+ }
+ deleteChange := Change{"change", ChangeDelete}
+ toString = deleteChange.String()
+ if toString != "D change" {
+ t.Fatalf("String() of a change with ChangeDelete Kind should have been %s but was %s", "D change", toString)
+ }
+}
+
+func TestChangesWithNoChanges(t *testing.T) {
+ rwLayer, err := ioutil.TempDir("", "docker-changes-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(rwLayer)
+ layer, err := ioutil.TempDir("", "docker-changes-test-layer")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(layer)
+ createSampleDir(t, layer)
+ changes, err := Changes([]string{layer}, rwLayer)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(changes) != 0 {
+ t.Fatalf("Changes with no difference should have detect no changes, but detected %d", len(changes))
+ }
+}
+
+func TestChangesWithChanges(t *testing.T) {
+ rwLayer, err := ioutil.TempDir("", "docker-changes-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(rwLayer)
+ // Create a folder
+ dir1 := path.Join(rwLayer, "dir1")
+ os.MkdirAll(dir1, 0740)
+ deletedFile := path.Join(dir1, ".wh.file1-2")
+ ioutil.WriteFile(deletedFile, []byte{}, 0600)
+ modifiedFile := path.Join(dir1, "file1-1")
+ ioutil.WriteFile(modifiedFile, []byte{0x00}, 01444)
+ // Let's add a subfolder for a newFile
+ subfolder := path.Join(dir1, "subfolder")
+ os.MkdirAll(subfolder, 0740)
+ newFile := path.Join(subfolder, "newFile")
+ ioutil.WriteFile(newFile, []byte{}, 0740)
+ // Let's create folders that with have the role of layers with the same data
+ layer, err := ioutil.TempDir("", "docker-changes-test-layer")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(layer)
+ createSampleDir(t, layer)
+ os.MkdirAll(path.Join(layer, "dir1/subfolder"), 0740)
+
+ // Let's modify modtime for dir1 to be sure it's the same for the two layer (to not having false positive)
+ fi, err := os.Stat(dir1)
+ if err != nil {
+ return
+ }
+ mtime := fi.ModTime()
+ stat := fi.Sys().(*syscall.Stat_t)
+ atime := time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
+
+ layerDir1 := path.Join(layer, "dir1")
+ os.Chtimes(layerDir1, atime, mtime)
+
+ changes, err := Changes([]string{layer}, rwLayer)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ sort.Sort(changesByPath(changes))
+
+ expectedChanges := []Change{
+ {"/dir1/file1-1", ChangeModify},
+ {"/dir1/file1-2", ChangeDelete},
+ {"/dir1/subfolder", ChangeModify},
+ {"/dir1/subfolder/newFile", ChangeAdd},
+ }
+
+ for i := 0; i < max(len(changes), len(expectedChanges)); i++ {
+ if i >= len(expectedChanges) {
+ t.Fatalf("unexpected change %s\n", changes[i].String())
+ }
+ if i >= len(changes) {
+ t.Fatalf("no change for expected change %s\n", expectedChanges[i].String())
+ }
+ if changes[i].Path == expectedChanges[i].Path {
+ if changes[i] != expectedChanges[i] {
+ t.Fatalf("Wrong change for %s, expected %s, got %s\n", changes[i].Path, changes[i].String(), expectedChanges[i].String())
+ }
+ } else if changes[i].Path < expectedChanges[i].Path {
+ t.Fatalf("unexpected change %s\n", changes[i].String())
+ } else {
+ t.Fatalf("no change for expected change %s != %s\n", expectedChanges[i].String(), changes[i].String())
+ }
+ }
+}
+
// Create an directory, copy it, make sure we report no changes between the two
func TestChangesDirsEmpty(t *testing.T) {
src, err := ioutil.TempDir("", "docker-changes-test")
if err != nil {
t.Fatal(err)
}
+ defer os.RemoveAll(src)
createSampleDir(t, src)
dst := src + "-copy"
if err := copyDir(src, dst); err != nil {
t.Fatal(err)
}
+ defer os.RemoveAll(dst)
changes, err := ChangesDirs(dst, src)
if err != nil {
t.Fatal(err)
@@ -291,3 +405,41 @@ func TestApplyLayer(t *testing.T) {
t.Fatalf("Unexpected differences after reapplying mutation: %v", changes2)
}
}
+
+func TestChangesSizeWithNoChanges(t *testing.T) {
+ size := ChangesSize("/tmp", nil)
+ if size != 0 {
+ t.Fatalf("ChangesSizes with no changes should be 0, was %d", size)
+ }
+}
+
+func TestChangesSizeWithOnlyDeleteChanges(t *testing.T) {
+ changes := []Change{
+ {Path: "deletedPath", Kind: ChangeDelete},
+ }
+ size := ChangesSize("/tmp", changes)
+ if size != 0 {
+ t.Fatalf("ChangesSizes with only delete changes should be 0, was %d", size)
+ }
+}
+
+func TestChangesSize(t *testing.T) {
+ parentPath, err := ioutil.TempDir("", "docker-changes-test")
+ defer os.RemoveAll(parentPath)
+ addition := path.Join(parentPath, "addition")
+ if err := ioutil.WriteFile(addition, []byte{0x01, 0x01, 0x01}, 0744); err != nil {
+ t.Fatal(err)
+ }
+ modification := path.Join(parentPath, "modification")
+ if err = ioutil.WriteFile(modification, []byte{0x01, 0x01, 0x01}, 0744); err != nil {
+ t.Fatal(err)
+ }
+ changes := []Change{
+ {Path: "addition", Kind: ChangeAdd},
+ {Path: "modification", Kind: ChangeModify},
+ }
+ size := ChangesSize(parentPath, changes)
+ if size != 6 {
+ t.Fatalf("ChangesSizes with only delete changes should be 0, was %d", size)
+ }
+}
diff --git a/pkg/archive/wrap_test.go b/pkg/archive/wrap_test.go
new file mode 100644
index 0000000000000..46ab36697a75b
--- /dev/null
+++ b/pkg/archive/wrap_test.go
@@ -0,0 +1,98 @@
+package archive
+
+import (
+ "archive/tar"
+ "bytes"
+ "io"
+ "testing"
+)
+
+func TestGenerateEmptyFile(t *testing.T) {
+ archive, err := Generate("emptyFile")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if archive == nil {
+ t.Fatal("The generated archive should not be nil.")
+ }
+
+ expectedFiles := [][]string{
+ {"emptyFile", ""},
+ }
+
+ tr := tar.NewReader(archive)
+ actualFiles := make([][]string, 0, 10)
+ i := 0
+ for {
+ hdr, err := tr.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ buf := new(bytes.Buffer)
+ buf.ReadFrom(tr)
+ content := buf.String()
+ actualFiles = append(actualFiles, []string{hdr.Name, content})
+ i++
+ }
+ if len(actualFiles) != len(expectedFiles) {
+ t.Fatalf("Number of expected file %d, got %d.", len(expectedFiles), len(actualFiles))
+ }
+ for i := 0; i < len(expectedFiles); i++ {
+ actual := actualFiles[i]
+ expected := expectedFiles[i]
+ if actual[0] != expected[0] {
+ t.Fatalf("Expected name '%s', Actual name '%s'", expected[0], actual[0])
+ }
+ if actual[1] != expected[1] {
+ t.Fatalf("Expected content '%s', Actual content '%s'", expected[1], actual[1])
+ }
+ }
+}
+
+func TestGenerateWithContent(t *testing.T) {
+ archive, err := Generate("file", "content")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if archive == nil {
+ t.Fatal("The generated archive should not be nil.")
+ }
+
+ expectedFiles := [][]string{
+ {"file", "content"},
+ }
+
+ tr := tar.NewReader(archive)
+ actualFiles := make([][]string, 0, 10)
+ i := 0
+ for {
+ hdr, err := tr.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ buf := new(bytes.Buffer)
+ buf.ReadFrom(tr)
+ content := buf.String()
+ actualFiles = append(actualFiles, []string{hdr.Name, content})
+ i++
+ }
+ if len(actualFiles) != len(expectedFiles) {
+ t.Fatalf("Number of expected file %d, got %d.", len(expectedFiles), len(actualFiles))
+ }
+ for i := 0; i < len(expectedFiles); i++ {
+ actual := actualFiles[i]
+ expected := expectedFiles[i]
+ if actual[0] != expected[0] {
+ t.Fatalf("Expected name '%s', Actual name '%s'", expected[0], actual[0])
+ }
+ if actual[1] != expected[1] {
+ t.Fatalf("Expected content '%s', Actual content '%s'", expected[1], actual[1])
+ }
+ }
+}
diff --git a/pkg/chrootarchive/archive.go b/pkg/chrootarchive/archive.go
index 17d3739d1ac86..49d19175d7d12 100644
--- a/pkg/chrootarchive/archive.go
+++ b/pkg/chrootarchive/archive.go
@@ -1,6 +1,7 @@
package chrootarchive
import (
+ "bytes"
"encoding/json"
"flag"
"fmt"
@@ -29,7 +30,8 @@ func untar() {
var options *archive.TarOptions
- if err := json.Unmarshal([]byte(os.Getenv("OPT")), &options); err != nil {
+ //read the options from the pipe "ExtraFiles"
+ if err := json.NewDecoder(os.NewFile(3, "options")).Decode(&options); err != nil {
fatal(err)
}
@@ -62,28 +64,39 @@ func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error
}
}
- // We can't pass the exclude list directly via cmd line
- // because we easily overrun the shell max argument list length
- // when the full image list is passed (e.g. when this is used
- // by `docker load`). Instead we will add the JSON marshalled
- // and placed in the env, which has significantly larger
- // max size
- data, err := json.Marshal(options)
- if err != nil {
- return fmt.Errorf("Untar json encode: %v", err)
- }
decompressedArchive, err := archive.DecompressStream(tarArchive)
if err != nil {
return err
}
defer decompressedArchive.Close()
+ // We can't pass a potentially large exclude list directly via cmd line
+ // because we easily overrun the kernel's max argument/environment size
+ // when the full image list is passed (e.g. when this is used by
+ // `docker load`). We will marshall the options via a pipe to the
+ // child
+ r, w, err := os.Pipe()
+ if err != nil {
+ return fmt.Errorf("Untar pipe failure: %v", err)
+ }
cmd := reexec.Command("docker-untar", dest)
cmd.Stdin = decompressedArchive
- cmd.Env = append(cmd.Env, fmt.Sprintf("OPT=%s", data))
- out, err := cmd.CombinedOutput()
- if err != nil {
- return fmt.Errorf("Untar %s %s", err, out)
+ cmd.ExtraFiles = append(cmd.ExtraFiles, r)
+ output := bytes.NewBuffer(nil)
+ cmd.Stdout = output
+ cmd.Stderr = output
+
+ if err := cmd.Start(); err != nil {
+ return fmt.Errorf("Untar error on re-exec cmd: %v", err)
+ }
+ //write the options to the pipe for the untar exec to read
+ if err := json.NewEncoder(w).Encode(options); err != nil {
+ return fmt.Errorf("Untar json encode to pipe failed: %v", err)
+ }
+ w.Close()
+
+ if err := cmd.Wait(); err != nil {
+ return fmt.Errorf("Untar re-exec error: %v: output: %s", err, output)
}
return nil
}
diff --git a/pkg/chrootarchive/archive_test.go b/pkg/chrootarchive/archive_test.go
index 45397d38fe7da..f9b5b09707ae6 100644
--- a/pkg/chrootarchive/archive_test.go
+++ b/pkg/chrootarchive/archive_test.go
@@ -3,11 +3,13 @@ package chrootarchive
import (
"bytes"
"fmt"
+ "hash/crc32"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
+ "strings"
"testing"
"time"
@@ -48,6 +50,42 @@ func TestChrootTarUntar(t *testing.T) {
}
}
+// gh#10426: Verify the fix for having a huge excludes list (like on `docker load` with large # of
+// local images)
+func TestChrootUntarWithHugeExcludesList(t *testing.T) {
+ tmpdir, err := ioutil.TempDir("", "docker-TestChrootUntarHugeExcludes")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+ src := filepath.Join(tmpdir, "src")
+ if err := os.MkdirAll(src, 0700); err != nil {
+ t.Fatal(err)
+ }
+ if err := ioutil.WriteFile(filepath.Join(src, "toto"), []byte("hello toto"), 0644); err != nil {
+ t.Fatal(err)
+ }
+ stream, err := archive.Tar(src, archive.Uncompressed)
+ if err != nil {
+ t.Fatal(err)
+ }
+ dest := filepath.Join(tmpdir, "dest")
+ if err := os.MkdirAll(dest, 0700); err != nil {
+ t.Fatal(err)
+ }
+ options := &archive.TarOptions{}
+ //65534 entries of 64-byte strings ~= 4MB of environment space which should overflow
+ //on most systems when passed via environment or command line arguments
+ excludes := make([]string, 65534, 65534)
+ for i := 0; i < 65534; i++ {
+ excludes[i] = strings.Repeat(string(i), 64)
+ }
+ options.ExcludePatterns = excludes
+ if err := Untar(stream, dest, options); err != nil {
+ t.Fatal(err)
+ }
+}
+
func TestChrootUntarEmptyArchive(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-TestChrootUntarEmptyArchive")
if err != nil {
@@ -59,15 +97,15 @@ func TestChrootUntarEmptyArchive(t *testing.T) {
}
}
-func prepareSourceDirectory(numberOfFiles int, targetPath string, makeLinks bool) (int, error) {
+func prepareSourceDirectory(numberOfFiles int, targetPath string, makeSymLinks bool) (int, error) {
fileData := []byte("fooo")
for n := 0; n < numberOfFiles; n++ {
fileName := fmt.Sprintf("file-%d", n)
if err := ioutil.WriteFile(path.Join(targetPath, fileName), fileData, 0700); err != nil {
return 0, err
}
- if makeLinks {
- if err := os.Link(path.Join(targetPath, fileName), path.Join(targetPath, fileName+"-link")); err != nil {
+ if makeSymLinks {
+ if err := os.Symlink(path.Join(targetPath, fileName), path.Join(targetPath, fileName+"-link")); err != nil {
return 0, err
}
}
@@ -76,8 +114,44 @@ func prepareSourceDirectory(numberOfFiles int, targetPath string, makeLinks bool
return totalSize, nil
}
-func TestChrootTarUntarWithSoftLink(t *testing.T) {
- tmpdir, err := ioutil.TempDir("", "docker-TestChrootTarUntarWithSoftLink")
+func getHash(filename string) (uint32, error) {
+ stream, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return 0, err
+ }
+ hash := crc32.NewIEEE()
+ hash.Write(stream)
+ return hash.Sum32(), nil
+}
+
+func compareDirectories(src string, dest string) error {
+ changes, err := archive.ChangesDirs(dest, src)
+ if err != nil {
+ return err
+ }
+ if len(changes) > 0 {
+ return fmt.Errorf("Unexpected differences after untar: %v", changes)
+ }
+ return nil
+}
+
+func compareFiles(src string, dest string) error {
+ srcHash, err := getHash(src)
+ if err != nil {
+ return err
+ }
+ destHash, err := getHash(dest)
+ if err != nil {
+ return err
+ }
+ if srcHash != destHash {
+ return fmt.Errorf("%s is different from %s", src, dest)
+ }
+ return nil
+}
+
+func TestChrootTarUntarWithSymlink(t *testing.T) {
+ tmpdir, err := ioutil.TempDir("", "docker-TestChrootTarUntarWithSymlink")
if err != nil {
t.Fatal(err)
}
@@ -93,6 +167,9 @@ func TestChrootTarUntarWithSoftLink(t *testing.T) {
if err := TarUntar(src, dest); err != nil {
t.Fatal(err)
}
+ if err := compareDirectories(src, dest); err != nil {
+ t.Fatal(err)
+ }
}
func TestChrootCopyWithTar(t *testing.T) {
@@ -108,19 +185,35 @@ func TestChrootCopyWithTar(t *testing.T) {
if _, err := prepareSourceDirectory(10, src, true); err != nil {
t.Fatal(err)
}
- dest := filepath.Join(tmpdir, "dest")
+
// Copy directory
+ dest := filepath.Join(tmpdir, "dest")
if err := CopyWithTar(src, dest); err != nil {
t.Fatal(err)
}
+ if err := compareDirectories(src, dest); err != nil {
+ t.Fatal(err)
+ }
+
// Copy file
srcfile := filepath.Join(src, "file-1")
- if err := CopyWithTar(srcfile, dest); err != nil {
+ dest = filepath.Join(tmpdir, "destFile")
+ destfile := filepath.Join(dest, "file-1")
+ if err := CopyWithTar(srcfile, destfile); err != nil {
t.Fatal(err)
}
+ if err := compareFiles(srcfile, destfile); err != nil {
+ t.Fatal(err)
+ }
+
// Copy symbolic link
- linkfile := filepath.Join(src, "file-1-link")
- if err := CopyWithTar(linkfile, dest); err != nil {
+ srcLinkfile := filepath.Join(src, "file-1-link")
+ dest = filepath.Join(tmpdir, "destSymlink")
+ destLinkfile := filepath.Join(dest, "file-1-link")
+ if err := CopyWithTar(srcLinkfile, destLinkfile); err != nil {
+ t.Fatal(err)
+ }
+ if err := compareFiles(srcLinkfile, destLinkfile); err != nil {
t.Fatal(err)
}
}
@@ -138,19 +231,32 @@ func TestChrootCopyFileWithTar(t *testing.T) {
if _, err := prepareSourceDirectory(10, src, true); err != nil {
t.Fatal(err)
}
- dest := filepath.Join(tmpdir, "dest")
+
// Copy directory
+ dest := filepath.Join(tmpdir, "dest")
if err := CopyFileWithTar(src, dest); err == nil {
t.Fatal("Expected error on copying directory")
}
+
// Copy file
srcfile := filepath.Join(src, "file-1")
- if err := CopyFileWithTar(srcfile, dest); err != nil {
+ dest = filepath.Join(tmpdir, "destFile")
+ destfile := filepath.Join(dest, "file-1")
+ if err := CopyFileWithTar(srcfile, destfile); err != nil {
+ t.Fatal(err)
+ }
+ if err := compareFiles(srcfile, destfile); err != nil {
t.Fatal(err)
}
+
// Copy symbolic link
- linkfile := filepath.Join(src, "file-1-link")
- if err := CopyFileWithTar(linkfile, dest); err != nil {
+ srcLinkfile := filepath.Join(src, "file-1-link")
+ dest = filepath.Join(tmpdir, "destSymlink")
+ destLinkfile := filepath.Join(dest, "file-1-link")
+ if err := CopyFileWithTar(srcLinkfile, destLinkfile); err != nil {
+ t.Fatal(err)
+ }
+ if err := compareFiles(srcLinkfile, destLinkfile); err != nil {
t.Fatal(err)
}
}
@@ -188,6 +294,9 @@ func TestChrootUntarPath(t *testing.T) {
if err := UntarPath(tarfile, dest); err != nil {
t.Fatal(err)
}
+ if err := compareDirectories(src, dest); err != nil {
+ t.Fatal(err)
+ }
}
type slowEmptyTarReader struct {
diff --git a/pkg/etchosts/etchosts.go b/pkg/etchosts/etchosts.go
index d7edef27f64ad..bef4a480cb07e 100644
--- a/pkg/etchosts/etchosts.go
+++ b/pkg/etchosts/etchosts.go
@@ -8,16 +8,19 @@ import (
"regexp"
)
+// Structure for a single host record
type Record struct {
Hosts string
IP string
}
+// Writes record to file and returns bytes written or error
func (r Record) WriteTo(w io.Writer) (int64, error) {
n, err := fmt.Fprintf(w, "%s\t%s\n", r.IP, r.Hosts)
return int64(n), err
}
+// Default hosts config records slice
var defaultContent = []Record{
{Hosts: "localhost", IP: "127.0.0.1"},
{Hosts: "localhost ip6-localhost ip6-loopback", IP: "::1"},
@@ -27,9 +30,14 @@ var defaultContent = []Record{
{Hosts: "ip6-allrouters", IP: "ff02::2"},
}
+// Build function
+// path is path to host file string required
+// IP, hostname, and domainname set main record leave empty for no master record
+// extraContent is an array of extra host records.
func Build(path, IP, hostname, domainname string, extraContent []Record) error {
content := bytes.NewBuffer(nil)
if IP != "" {
+ //set main record
var mainRec Record
mainRec.IP = IP
if domainname != "" {
@@ -41,13 +49,13 @@ func Build(path, IP, hostname, domainname string, extraContent []Record) error {
return err
}
}
-
+ // Write defaultContent slice to buffer
for _, r := range defaultContent {
if _, err := r.WriteTo(content); err != nil {
return err
}
}
-
+ // Write extra content from function arguments
for _, r := range extraContent {
if _, err := r.WriteTo(content); err != nil {
return err
@@ -57,6 +65,10 @@ func Build(path, IP, hostname, domainname string, extraContent []Record) error {
return ioutil.WriteFile(path, content.Bytes(), 0644)
}
+// Update all IP addresses where hostname matches.
+// path is path to host file
+// IP is new IP address
+// hostname is hostname to search for to replace IP
func Update(path, IP, hostname string) error {
old, err := ioutil.ReadFile(path)
if err != nil {
diff --git a/pkg/fileutils/fileutils.go b/pkg/fileutils/fileutils.go
index 432529765104a..fdafb53c7fefa 100644
--- a/pkg/fileutils/fileutils.go
+++ b/pkg/fileutils/fileutils.go
@@ -1,27 +1,170 @@
package fileutils
import (
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
"path/filepath"
+ "strings"
"github.com/Sirupsen/logrus"
)
-// Matches returns true if relFilePath matches any of the patterns
-func Matches(relFilePath string, patterns []string) (bool, error) {
- for _, exclude := range patterns {
- matched, err := filepath.Match(exclude, relFilePath)
+func Exclusion(pattern string) bool {
+ return pattern[0] == '!'
+}
+
+func Empty(pattern string) bool {
+ return pattern == ""
+}
+
+// Cleanpatterns takes a slice of patterns returns a new
+// slice of patterns cleaned with filepath.Clean, stripped
+// of any empty patterns and lets the caller know whether the
+// slice contains any exception patterns (prefixed with !).
+func CleanPatterns(patterns []string) ([]string, [][]string, bool, error) {
+ // Loop over exclusion patterns and:
+ // 1. Clean them up.
+ // 2. Indicate whether we are dealing with any exception rules.
+ // 3. Error if we see a single exclusion marker on it's own (!).
+ cleanedPatterns := []string{}
+ patternDirs := [][]string{}
+ exceptions := false
+ for _, pattern := range patterns {
+ // Eliminate leading and trailing whitespace.
+ pattern = strings.TrimSpace(pattern)
+ if Empty(pattern) {
+ continue
+ }
+ if Exclusion(pattern) {
+ if len(pattern) == 1 {
+ logrus.Errorf("Illegal exclusion pattern: %s", pattern)
+ return nil, nil, false, errors.New("Illegal exclusion pattern: !")
+ }
+ exceptions = true
+ }
+ pattern = filepath.Clean(pattern)
+ cleanedPatterns = append(cleanedPatterns, pattern)
+ if Exclusion(pattern) {
+ pattern = pattern[1:]
+ }
+ patternDirs = append(patternDirs, strings.Split(pattern, "/"))
+ }
+
+ return cleanedPatterns, patternDirs, exceptions, nil
+}
+
+// Matches returns true if file matches any of the patterns
+// and isn't excluded by any of the subsequent patterns.
+func Matches(file string, patterns []string) (bool, error) {
+ file = filepath.Clean(file)
+
+ if file == "." {
+ // Don't let them exclude everything, kind of silly.
+ return false, nil
+ }
+
+ patterns, patDirs, _, err := CleanPatterns(patterns)
+ if err != nil {
+ return false, err
+ }
+
+ return OptimizedMatches(file, patterns, patDirs)
+}
+
+// Matches is basically the same as fileutils.Matches() but optimized for archive.go.
+// It will assume that the inputs have been preprocessed and therefore the function
+// doen't need to do as much error checking and clean-up. This was done to avoid
+// repeating these steps on each file being checked during the archive process.
+// The more generic fileutils.Matches() can't make these assumptions.
+func OptimizedMatches(file string, patterns []string, patDirs [][]string) (bool, error) {
+ matched := false
+ parentPath := filepath.Dir(file)
+ parentPathDirs := strings.Split(parentPath, "/")
+
+ for i, pattern := range patterns {
+ negative := false
+
+ if Exclusion(pattern) {
+ negative = true
+ pattern = pattern[1:]
+ }
+
+ match, err := filepath.Match(pattern, file)
if err != nil {
- logrus.Errorf("Error matching: %s (pattern: %s)", relFilePath, exclude)
+ logrus.Errorf("Error matching: %s (pattern: %s)", file, pattern)
return false, err
}
- if matched {
- if filepath.Clean(relFilePath) == "." {
- logrus.Errorf("Can't exclude whole path, excluding pattern: %s", exclude)
- continue
+
+ if !match && parentPath != "." {
+ // Check to see if the pattern matches one of our parent dirs.
+ if len(patDirs[i]) <= len(parentPathDirs) {
+ match, _ = filepath.Match(strings.Join(patDirs[i], "/"),
+ strings.Join(parentPathDirs[:len(patDirs[i])], "/"))
}
- logrus.Debugf("Skipping excluded path: %s", relFilePath)
- return true, nil
}
+
+ if match {
+ matched = !negative
+ }
+ }
+
+ if matched {
+ logrus.Debugf("Skipping excluded path: %s", file)
+ }
+ return matched, nil
+}
+
+func CopyFile(src, dst string) (int64, error) {
+ cleanSrc := filepath.Clean(src)
+ cleanDst := filepath.Clean(dst)
+ if cleanSrc == cleanDst {
+ return 0, nil
+ }
+ sf, err := os.Open(cleanSrc)
+ if err != nil {
+ return 0, err
+ }
+ defer sf.Close()
+ if err := os.Remove(cleanDst); err != nil && !os.IsNotExist(err) {
+ return 0, err
+ }
+ df, err := os.Create(cleanDst)
+ if err != nil {
+ return 0, err
+ }
+ defer df.Close()
+ return io.Copy(df, sf)
+}
+
+func GetTotalUsedFds() int {
+ if fds, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil {
+ logrus.Errorf("Error opening /proc/%d/fd: %s", os.Getpid(), err)
+ } else {
+ return len(fds)
+ }
+ return -1
+}
+
+// ReadSymlinkedDirectory returns the target directory of a symlink.
+// The target of the symbolic link may not be a file.
+func ReadSymlinkedDirectory(path string) (string, error) {
+ var realPath string
+ var err error
+ if realPath, err = filepath.Abs(path); err != nil {
+ return "", fmt.Errorf("unable to get absolute path for %s: %s", path, err)
+ }
+ if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
+ return "", fmt.Errorf("failed to canonicalise path for %s: %s", path, err)
+ }
+ realPathInfo, err := os.Stat(realPath)
+ if err != nil {
+ return "", fmt.Errorf("failed to stat target '%s' of '%s': %s", realPath, path, err)
+ }
+ if !realPathInfo.Mode().IsDir() {
+ return "", fmt.Errorf("canonical path points to a file '%s'", realPath)
}
- return false, nil
+ return realPath, nil
}
diff --git a/pkg/fileutils/fileutils_test.go b/pkg/fileutils/fileutils_test.go
new file mode 100644
index 0000000000000..ef931684c1281
--- /dev/null
+++ b/pkg/fileutils/fileutils_test.go
@@ -0,0 +1,357 @@
+package fileutils
+
+import (
+ "io/ioutil"
+ "os"
+ "path"
+ "testing"
+)
+
+// CopyFile with invalid src
+func TestCopyFileWithInvalidSrc(t *testing.T) {
+ tempFolder, err := ioutil.TempDir("", "docker-fileutils-test")
+ defer os.RemoveAll(tempFolder)
+ if err != nil {
+ t.Fatal(err)
+ }
+ bytes, err := CopyFile("/invalid/file/path", path.Join(tempFolder, "dest"))
+ if err == nil {
+ t.Fatal("Should have fail to copy an invalid src file")
+ }
+ if bytes != 0 {
+ t.Fatal("Should have written 0 bytes")
+ }
+
+}
+
+// CopyFile with invalid dest
+func TestCopyFileWithInvalidDest(t *testing.T) {
+ tempFolder, err := ioutil.TempDir("", "docker-fileutils-test")
+ defer os.RemoveAll(tempFolder)
+ if err != nil {
+ t.Fatal(err)
+ }
+ src := path.Join(tempFolder, "file")
+ err = ioutil.WriteFile(src, []byte("content"), 0740)
+ if err != nil {
+ t.Fatal(err)
+ }
+ bytes, err := CopyFile(src, path.Join(tempFolder, "/invalid/dest/path"))
+ if err == nil {
+ t.Fatal("Should have fail to copy an invalid src file")
+ }
+ if bytes != 0 {
+ t.Fatal("Should have written 0 bytes")
+ }
+
+}
+
+// CopyFile with same src and dest
+func TestCopyFileWithSameSrcAndDest(t *testing.T) {
+ tempFolder, err := ioutil.TempDir("", "docker-fileutils-test")
+ defer os.RemoveAll(tempFolder)
+ if err != nil {
+ t.Fatal(err)
+ }
+ file := path.Join(tempFolder, "file")
+ err = ioutil.WriteFile(file, []byte("content"), 0740)
+ if err != nil {
+ t.Fatal(err)
+ }
+ bytes, err := CopyFile(file, file)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if bytes != 0 {
+ t.Fatal("Should have written 0 bytes as it is the same file.")
+ }
+}
+
+// CopyFile with same src and dest but path is different and not clean
+func TestCopyFileWithSameSrcAndDestWithPathNameDifferent(t *testing.T) {
+ tempFolder, err := ioutil.TempDir("", "docker-fileutils-test")
+ defer os.RemoveAll(tempFolder)
+ if err != nil {
+ t.Fatal(err)
+ }
+ testFolder := path.Join(tempFolder, "test")
+ err = os.MkdirAll(testFolder, 0740)
+ if err != nil {
+ t.Fatal(err)
+ }
+ file := path.Join(testFolder, "file")
+ sameFile := testFolder + "/../test/file"
+ err = ioutil.WriteFile(file, []byte("content"), 0740)
+ if err != nil {
+ t.Fatal(err)
+ }
+ bytes, err := CopyFile(file, sameFile)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if bytes != 0 {
+ t.Fatal("Should have written 0 bytes as it is the same file.")
+ }
+}
+
+func TestCopyFile(t *testing.T) {
+ tempFolder, err := ioutil.TempDir("", "docker-fileutils-test")
+ defer os.RemoveAll(tempFolder)
+ if err != nil {
+ t.Fatal(err)
+ }
+ src := path.Join(tempFolder, "src")
+ dest := path.Join(tempFolder, "dest")
+ ioutil.WriteFile(src, []byte("content"), 0777)
+ ioutil.WriteFile(dest, []byte("destContent"), 0777)
+ bytes, err := CopyFile(src, dest)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if bytes != 7 {
+ t.Fatalf("Should have written %d bytes but wrote %d", 7, bytes)
+ }
+ actual, err := ioutil.ReadFile(dest)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(actual) != "content" {
+ t.Fatalf("Dest content was '%s', expected '%s'", string(actual), "content")
+ }
+}
+
+// Reading a symlink to a directory must return the directory
+func TestReadSymlinkedDirectoryExistingDirectory(t *testing.T) {
+ var err error
+ if err = os.Mkdir("/tmp/testReadSymlinkToExistingDirectory", 0777); err != nil {
+ t.Errorf("failed to create directory: %s", err)
+ }
+
+ if err = os.Symlink("/tmp/testReadSymlinkToExistingDirectory", "/tmp/dirLinkTest"); err != nil {
+ t.Errorf("failed to create symlink: %s", err)
+ }
+
+ var path string
+ if path, err = ReadSymlinkedDirectory("/tmp/dirLinkTest"); err != nil {
+ t.Fatalf("failed to read symlink to directory: %s", err)
+ }
+
+ if path != "/tmp/testReadSymlinkToExistingDirectory" {
+ t.Fatalf("symlink returned unexpected directory: %s", path)
+ }
+
+ if err = os.Remove("/tmp/testReadSymlinkToExistingDirectory"); err != nil {
+ t.Errorf("failed to remove temporary directory: %s", err)
+ }
+
+ if err = os.Remove("/tmp/dirLinkTest"); err != nil {
+ t.Errorf("failed to remove symlink: %s", err)
+ }
+}
+
+// Reading a non-existing symlink must fail
+func TestReadSymlinkedDirectoryNonExistingSymlink(t *testing.T) {
+ var path string
+ var err error
+ if path, err = ReadSymlinkedDirectory("/tmp/test/foo/Non/ExistingPath"); err == nil {
+ t.Fatalf("error expected for non-existing symlink")
+ }
+
+ if path != "" {
+ t.Fatalf("expected empty path, but '%s' was returned", path)
+ }
+}
+
+// Reading a symlink to a file must fail
+func TestReadSymlinkedDirectoryToFile(t *testing.T) {
+ var err error
+ var file *os.File
+
+ if file, err = os.Create("/tmp/testReadSymlinkToFile"); err != nil {
+ t.Fatalf("failed to create file: %s", err)
+ }
+
+ file.Close()
+
+ if err = os.Symlink("/tmp/testReadSymlinkToFile", "/tmp/fileLinkTest"); err != nil {
+ t.Errorf("failed to create symlink: %s", err)
+ }
+
+ var path string
+ if path, err = ReadSymlinkedDirectory("/tmp/fileLinkTest"); err == nil {
+ t.Fatalf("ReadSymlinkedDirectory on a symlink to a file should've failed")
+ }
+
+ if path != "" {
+ t.Fatalf("path should've been empty: %s", path)
+ }
+
+ if err = os.Remove("/tmp/testReadSymlinkToFile"); err != nil {
+ t.Errorf("failed to remove file: %s", err)
+ }
+
+ if err = os.Remove("/tmp/fileLinkTest"); err != nil {
+ t.Errorf("failed to remove symlink: %s", err)
+ }
+}
+
+func TestWildcardMatches(t *testing.T) {
+ match, _ := Matches("fileutils.go", []string{"*"})
+ if match != true {
+ t.Errorf("failed to get a wildcard match, got %v", match)
+ }
+}
+
+// A simple pattern match should return true.
+func TestPatternMatches(t *testing.T) {
+ match, _ := Matches("fileutils.go", []string{"*.go"})
+ if match != true {
+ t.Errorf("failed to get a match, got %v", match)
+ }
+}
+
+// An exclusion followed by an inclusion should return true.
+func TestExclusionPatternMatchesPatternBefore(t *testing.T) {
+ match, _ := Matches("fileutils.go", []string{"!fileutils.go", "*.go"})
+ if match != true {
+ t.Errorf("failed to get true match on exclusion pattern, got %v", match)
+ }
+}
+
+// A folder pattern followed by an exception should return false.
+func TestPatternMatchesFolderExclusions(t *testing.T) {
+ match, _ := Matches("docs/README.md", []string{"docs", "!docs/README.md"})
+ if match != false {
+ t.Errorf("failed to get a false match on exclusion pattern, got %v", match)
+ }
+}
+
+// A folder pattern followed by an exception should return false.
+func TestPatternMatchesFolderWithSlashExclusions(t *testing.T) {
+ match, _ := Matches("docs/README.md", []string{"docs/", "!docs/README.md"})
+ if match != false {
+ t.Errorf("failed to get a false match on exclusion pattern, got %v", match)
+ }
+}
+
+// A folder pattern followed by an exception should return false.
+func TestPatternMatchesFolderWildcardExclusions(t *testing.T) {
+ match, _ := Matches("docs/README.md", []string{"docs/*", "!docs/README.md"})
+ if match != false {
+ t.Errorf("failed to get a false match on exclusion pattern, got %v", match)
+ }
+}
+
+// A pattern followed by an exclusion should return false.
+func TestExclusionPatternMatchesPatternAfter(t *testing.T) {
+ match, _ := Matches("fileutils.go", []string{"*.go", "!fileutils.go"})
+ if match != false {
+ t.Errorf("failed to get false match on exclusion pattern, got %v", match)
+ }
+}
+
+// A filename evaluating to . should return false.
+func TestExclusionPatternMatchesWholeDirectory(t *testing.T) {
+ match, _ := Matches(".", []string{"*.go"})
+ if match != false {
+ t.Errorf("failed to get false match on ., got %v", match)
+ }
+}
+
+// A single ! pattern should return an error.
+func TestSingleExclamationError(t *testing.T) {
+ _, err := Matches("fileutils.go", []string{"!"})
+ if err == nil {
+ t.Errorf("failed to get an error for a single exclamation point, got %v", err)
+ }
+}
+
+// A string preceded with a ! should return true from Exclusion.
+func TestExclusion(t *testing.T) {
+ exclusion := Exclusion("!")
+ if !exclusion {
+ t.Errorf("failed to get true for a single !, got %v", exclusion)
+ }
+}
+
+// Matches with no patterns
+func TestMatchesWithNoPatterns(t *testing.T) {
+ matches, err := Matches("/any/path/there", []string{})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if matches {
+ t.Fatalf("Should not have match anything")
+ }
+}
+
+// Matches with malformed patterns
+func TestMatchesWithMalformedPatterns(t *testing.T) {
+ matches, err := Matches("/any/path/there", []string{"["})
+ if err == nil {
+ t.Fatal("Should have failed because of a malformed syntax in the pattern")
+ }
+ if matches {
+ t.Fatalf("Should not have match anything")
+ }
+}
+
+// An empty string should return true from Empty.
+func TestEmpty(t *testing.T) {
+ empty := Empty("")
+ if !empty {
+ t.Errorf("failed to get true for an empty string, got %v", empty)
+ }
+}
+
+func TestCleanPatterns(t *testing.T) {
+ cleaned, _, _, _ := CleanPatterns([]string{"docs", "config"})
+ if len(cleaned) != 2 {
+ t.Errorf("expected 2 element slice, got %v", len(cleaned))
+ }
+}
+
+func TestCleanPatternsStripEmptyPatterns(t *testing.T) {
+ cleaned, _, _, _ := CleanPatterns([]string{"docs", "config", ""})
+ if len(cleaned) != 2 {
+ t.Errorf("expected 2 element slice, got %v", len(cleaned))
+ }
+}
+
+func TestCleanPatternsExceptionFlag(t *testing.T) {
+ _, _, exceptions, _ := CleanPatterns([]string{"docs", "!docs/README.md"})
+ if !exceptions {
+ t.Errorf("expected exceptions to be true, got %v", exceptions)
+ }
+}
+
+func TestCleanPatternsLeadingSpaceTrimmed(t *testing.T) {
+ _, _, exceptions, _ := CleanPatterns([]string{"docs", " !docs/README.md"})
+ if !exceptions {
+ t.Errorf("expected exceptions to be true, got %v", exceptions)
+ }
+}
+
+func TestCleanPatternsTrailingSpaceTrimmed(t *testing.T) {
+ _, _, exceptions, _ := CleanPatterns([]string{"docs", "!docs/README.md "})
+ if !exceptions {
+ t.Errorf("expected exceptions to be true, got %v", exceptions)
+ }
+}
+
+func TestCleanPatternsErrorSingleException(t *testing.T) {
+ _, _, _, err := CleanPatterns([]string{"!"})
+ if err == nil {
+ t.Errorf("expected error on single exclamation point, got %v", err)
+ }
+}
+
+func TestCleanPatternsFolderSplit(t *testing.T) {
+ _, dirs, _, _ := CleanPatterns([]string{"docs/config/CONFIG.md"})
+ if dirs[0][0] != "docs" {
+ t.Errorf("expected first element in dirs slice to be docs, got %v", dirs[0][1])
+ }
+ if dirs[0][1] != "config" {
+ t.Errorf("expected first element in dirs slice to be config, got %v", dirs[0][1])
+ }
+}
diff --git a/pkg/graphdb/graphdb.go b/pkg/graphdb/graphdb.go
index c6f13eda27248..b9433dbddcb50 100644
--- a/pkg/graphdb/graphdb.go
+++ b/pkg/graphdb/graphdb.go
@@ -378,12 +378,22 @@ func (db *Database) Purge(id string) (int, error) {
tx.Rollback()
return -1, err
}
-
changes, err := rows.RowsAffected()
if err != nil {
return -1, err
}
+ // Clear who's using this id as parent
+ refs, err := tx.Exec("DELETE FROM edge WHERE parent_id = ?;", id)
+ if err != nil {
+ tx.Rollback()
+ return -1, err
+ }
+ refsCount, err := refs.RowsAffected()
+ if err != nil {
+ return -1, err
+ }
+
// Delete entity
if _, err := tx.Exec("DELETE FROM entity where id = ?;", id); err != nil {
tx.Rollback()
@@ -394,7 +404,7 @@ func (db *Database) Purge(id string) (int, error) {
return -1, err
}
- return int(changes), nil
+ return int(changes + refsCount), nil
}
// Rename an edge for a given path
diff --git a/pkg/graphdb/graphdb_test.go b/pkg/graphdb/graphdb_test.go
index f22828560c235..1cd223bd9cd89 100644
--- a/pkg/graphdb/graphdb_test.go
+++ b/pkg/graphdb/graphdb_test.go
@@ -52,7 +52,7 @@ func TestGetRootEntity(t *testing.T) {
t.Fatal("Entity should not be nil")
}
if e.ID() != "0" {
- t.Fatalf("Enity id should be 0, got %s", e.ID())
+ t.Fatalf("Entity id should be 0, got %s", e.ID())
}
}
@@ -74,7 +74,7 @@ func TestSetDuplicateEntity(t *testing.T) {
t.Fatal(err)
}
if _, err := db.Set("/foo", "43"); err == nil {
- t.Fatalf("Creating an entry with a duplciate path did not cause an error")
+ t.Fatalf("Creating an entry with a duplicate path did not cause an error")
}
}
@@ -472,8 +472,8 @@ func TestPurgeId(t *testing.T) {
db.Set("/webapp", "1")
- if db.Refs("1") != 1 {
- t.Fatal("Expect reference count to be 1")
+ if c := db.Refs("1"); c != 1 {
+ t.Fatalf("Expect reference count to be 1, got %d", c)
}
db.Set("/db", "2")
@@ -484,7 +484,45 @@ func TestPurgeId(t *testing.T) {
t.Fatal(err)
}
if count != 2 {
- t.Fatal("Expected 2 references to be removed")
+ t.Fatalf("Expected 2 references to be removed, got %d", count)
+ }
+}
+
+// Regression test https://github.com/docker/docker/issues/12334
+func TestPurgeIdRefPaths(t *testing.T) {
+ db, dbpath := newTestDb(t)
+ defer destroyTestDb(dbpath)
+
+ db.Set("/webapp", "1")
+ db.Set("/db", "2")
+
+ db.Set("/db/webapp", "1")
+
+ if c := db.Refs("1"); c != 2 {
+ t.Fatalf("Expected 2 reference for webapp, got %d", c)
+ }
+ if c := db.Refs("2"); c != 1 {
+ t.Fatalf("Expected 1 reference for db, got %d", c)
+ }
+
+ if rp := db.RefPaths("2"); len(rp) != 1 {
+ t.Fatalf("Expected 1 reference path for db, got %d", len(rp))
+ }
+
+ count, err := db.Purge("2")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if count != 2 {
+ t.Fatalf("Expected 2 rows to be removed, got %d", count)
+ }
+
+ if c := db.Refs("2"); c != 0 {
+ t.Fatalf("Expected 0 reference for db, got %d", c)
+ }
+ if c := db.Refs("1"); c != 1 {
+ t.Fatalf("Expected 1 reference for webapp, got %d", c)
}
}
diff --git a/pkg/httputils/httputils.go b/pkg/httputils/httputils.go
new file mode 100644
index 0000000000000..1c922240e6f45
--- /dev/null
+++ b/pkg/httputils/httputils.go
@@ -0,0 +1,26 @@
+package httputils
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/docker/docker/pkg/jsonmessage"
+)
+
+// Request a given URL and return an io.Reader
+func Download(url string) (resp *http.Response, err error) {
+ if resp, err = http.Get(url); err != nil {
+ return nil, err
+ }
+ if resp.StatusCode >= 400 {
+ return nil, fmt.Errorf("Got HTTP status code >= 400: %s", resp.Status)
+ }
+ return resp, nil
+}
+
+func NewHTTPRequestError(msg string, res *http.Response) error {
+ return &jsonmessage.JSONError{
+ Message: msg,
+ Code: res.StatusCode,
+ }
+}
diff --git a/pkg/ioutils/readers.go b/pkg/ioutils/readers.go
index 58ff1af639cca..0e542cbad35ae 100644
--- a/pkg/ioutils/readers.go
+++ b/pkg/ioutils/readers.go
@@ -3,6 +3,8 @@ package ioutils
import (
"bytes"
"crypto/rand"
+ "crypto/sha256"
+ "encoding/hex"
"io"
"math/big"
"sync"
@@ -215,3 +217,11 @@ func (r *bufReader) Close() error {
}
return closer.Close()
}
+
+func HashData(src io.Reader) (string, error) {
+ h := sha256.New()
+ if _, err := io.Copy(h, src); err != nil {
+ return "", err
+ }
+ return "sha256:" + hex.EncodeToString(h.Sum(nil)), nil
+}
diff --git a/pkg/ioutils/writers.go b/pkg/ioutils/writers.go
index c0b3608fe6f36..43fdc44ea9686 100644
--- a/pkg/ioutils/writers.go
+++ b/pkg/ioutils/writers.go
@@ -37,3 +37,24 @@ func NewWriteCloserWrapper(r io.Writer, closer func() error) io.WriteCloser {
closer: closer,
}
}
+
+// Wrap a concrete io.Writer and hold a count of the number
+// of bytes written to the writer during a "session".
+// This can be convenient when write return is masked
+// (e.g., json.Encoder.Encode())
+type WriteCounter struct {
+ Count int64
+ Writer io.Writer
+}
+
+func NewWriteCounter(w io.Writer) *WriteCounter {
+ return &WriteCounter{
+ Writer: w,
+ }
+}
+
+func (wc *WriteCounter) Write(p []byte) (count int, err error) {
+ count, err = wc.Writer.Write(p)
+ wc.Count += int64(count)
+ return
+}
diff --git a/pkg/ioutils/writers_test.go b/pkg/ioutils/writers_test.go
new file mode 100644
index 0000000000000..80d7f7f795452
--- /dev/null
+++ b/pkg/ioutils/writers_test.go
@@ -0,0 +1,41 @@
+package ioutils
+
+import (
+ "bytes"
+ "strings"
+ "testing"
+)
+
+func TestNopWriter(t *testing.T) {
+ nw := &NopWriter{}
+ l, err := nw.Write([]byte{'c'})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if l != 1 {
+ t.Fatalf("Expected 1 got %d", l)
+ }
+}
+
+func TestWriteCounter(t *testing.T) {
+ dummy1 := "This is a dummy string."
+ dummy2 := "This is another dummy string."
+ totalLength := int64(len(dummy1) + len(dummy2))
+
+ reader1 := strings.NewReader(dummy1)
+ reader2 := strings.NewReader(dummy2)
+
+ var buffer bytes.Buffer
+ wc := NewWriteCounter(&buffer)
+
+ reader1.WriteTo(wc)
+ reader2.WriteTo(wc)
+
+ if wc.Count != totalLength {
+ t.Errorf("Wrong count: %d vs. %d", wc.Count, totalLength)
+ }
+
+ if buffer.String() != dummy1+dummy2 {
+ t.Error("Wrong message written")
+ }
+}
diff --git a/pkg/iptables/firewalld.go b/pkg/iptables/firewalld.go
new file mode 100644
index 0000000000000..3087794131467
--- /dev/null
+++ b/pkg/iptables/firewalld.go
@@ -0,0 +1,163 @@
+package iptables
+
+import (
+ "fmt"
+ "github.com/Sirupsen/logrus"
+ "github.com/godbus/dbus"
+ "strings"
+)
+
+type IPV string
+
+const (
+ Iptables IPV = "ipv4"
+ Ip6tables IPV = "ipv6"
+ Ebtables IPV = "eb"
+)
+const (
+ dbusInterface = "org.fedoraproject.FirewallD1"
+ dbusPath = "/org/fedoraproject/FirewallD1"
+)
+
+// Conn is a connection to firewalld dbus endpoint.
+type Conn struct {
+ sysconn *dbus.Conn
+ sysobj *dbus.Object
+ signal chan *dbus.Signal
+}
+
+var (
+ connection *Conn
+ firewalldRunning bool // is Firewalld service running
+ onReloaded []*func() // callbacks when Firewalld has been reloaded
+)
+
+func FirewalldInit() {
+ var err error
+
+ connection, err = newConnection()
+
+ if err != nil {
+ logrus.Errorf("Failed to connect to D-Bus system bus: %s", err)
+ }
+
+ firewalldRunning = checkRunning()
+}
+
+// New() establishes a connection to the system bus.
+func newConnection() (*Conn, error) {
+ c := new(Conn)
+ if err := c.initConnection(); err != nil {
+ return nil, err
+ }
+
+ return c, nil
+}
+
+// Innitialize D-Bus connection.
+func (c *Conn) initConnection() error {
+ var err error
+
+ c.sysconn, err = dbus.SystemBus()
+ if err != nil {
+ return err
+ }
+
+ // This never fails, even if the service is not running atm.
+ c.sysobj = c.sysconn.Object(dbusInterface, dbus.ObjectPath(dbusPath))
+
+ rule := fmt.Sprintf("type='signal',path='%s',interface='%s',sender='%s',member='Reloaded'",
+ dbusPath, dbusInterface, dbusInterface)
+ c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, rule)
+
+ rule = fmt.Sprintf("type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged',path='/org/freedesktop/DBus',sender='org.freedesktop.DBus',arg0='%s'",
+ dbusInterface)
+ c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, rule)
+
+ c.signal = make(chan *dbus.Signal, 10)
+ c.sysconn.Signal(c.signal)
+ go signalHandler()
+
+ return nil
+}
+
+func signalHandler() {
+ if connection != nil {
+ for signal := range connection.signal {
+ if strings.Contains(signal.Name, "NameOwnerChanged") {
+ firewalldRunning = checkRunning()
+ dbusConnectionChanged(signal.Body)
+ } else if strings.Contains(signal.Name, "Reloaded") {
+ reloaded()
+ }
+ }
+ }
+}
+
+func dbusConnectionChanged(args []interface{}) {
+ name := args[0].(string)
+ old_owner := args[1].(string)
+ new_owner := args[2].(string)
+
+ if name != dbusInterface {
+ return
+ }
+
+ if len(new_owner) > 0 {
+ connectionEstablished()
+ } else if len(old_owner) > 0 {
+ connectionLost()
+ }
+}
+
+func connectionEstablished() {
+ reloaded()
+}
+
+func connectionLost() {
+ // Doesn't do anything for now. Libvirt also doesn't react to this.
+}
+
+// call all callbacks
+func reloaded() {
+ for _, pf := range onReloaded {
+ (*pf)()
+ }
+}
+
+// add callback
+func OnReloaded(callback func()) {
+ for _, pf := range onReloaded {
+ if pf == &callback {
+ return
+ }
+ }
+ onReloaded = append(onReloaded, &callback)
+}
+
+// Call some remote method to see whether the service is actually running.
+func checkRunning() bool {
+ var zone string
+ var err error
+
+ if connection != nil {
+ err = connection.sysobj.Call(dbusInterface+".getDefaultZone", 0).Store(&zone)
+ logrus.Infof("Firewalld running: %t", err == nil)
+ return err == nil
+ }
+ logrus.Info("Firewalld not running")
+ return false
+}
+
+// Firewalld's passthrough method simply passes args through to iptables/ip6tables
+func Passthrough(ipv IPV, args ...string) ([]byte, error) {
+ var output string
+
+ logrus.Debugf("Firewalld passthrough: %s, %s", ipv, args)
+ err := connection.sysobj.Call(dbusInterface+".direct.passthrough", 0, ipv, args).Store(&output)
+ if output != "" {
+ logrus.Debugf("passthrough output: %s", output)
+ }
+
+ return []byte(output), err
+}
diff --git a/pkg/iptables/firewalld_test.go b/pkg/iptables/firewalld_test.go
new file mode 100644
index 0000000000000..3896007d646b3
--- /dev/null
+++ b/pkg/iptables/firewalld_test.go
@@ -0,0 +1,78 @@
+package iptables
+
+import (
+ "net"
+ "strconv"
+ "testing"
+)
+
+func TestFirewalldInit(t *testing.T) {
+ FirewalldInit()
+}
+
+func TestReloaded(t *testing.T) {
+ var err error
+ var fwdChain *Chain
+
+ fwdChain, err = NewChain("FWD", "lo", Filter)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer fwdChain.Remove()
+
+ // copy-pasted from iptables_test:TestLink
+ ip1 := net.ParseIP("192.168.1.1")
+ ip2 := net.ParseIP("192.168.1.2")
+ port := 1234
+ proto := "tcp"
+
+ err = fwdChain.Link(Append, ip1, ip2, port, proto)
+ if err != nil {
+ t.Fatal(err)
+ } else {
+ // to be re-called again later
+ OnReloaded(func() { fwdChain.Link(Append, ip1, ip2, port, proto) })
+ }
+
+ rule1 := []string{
+ "-i", fwdChain.Bridge,
+ "-o", fwdChain.Bridge,
+ "-p", proto,
+ "-s", ip1.String(),
+ "-d", ip2.String(),
+ "--dport", strconv.Itoa(port),
+ "-j", "ACCEPT"}
+
+ if !Exists(fwdChain.Table, fwdChain.Name, rule1...) {
+ t.Fatalf("rule1 does not exist")
+ }
+
+ // flush all rules
+ fwdChain.Remove()
+
+ reloaded()
+
+ // make sure the rules have been recreated
+ if !Exists(fwdChain.Table, fwdChain.Name, rule1...) {
+ t.Fatalf("rule1 hasn't been recreated")
+ }
+}
+
+func TestPassthrough(t *testing.T) {
+ rule1 := []string{
+ "-i", "lo",
+ "-p", "udp",
+ "--dport", "123",
+ "-j", "ACCEPT"}
+
+ if firewalldRunning {
+ _, err := Passthrough(Iptables, append([]string{"-A"}, rule1...)...)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !Exists(Filter, "INPUT", rule1...) {
+ t.Fatalf("rule1 does not exist")
+ }
+ }
+
+}
diff --git a/pkg/iptables/iptables.go b/pkg/iptables/iptables.go
index f8b3aa769d28e..0cfcca7502231 100644
--- a/pkg/iptables/iptables.go
+++ b/pkg/iptables/iptables.go
@@ -41,7 +41,7 @@ type ChainError struct {
Output []byte
}
-func (e *ChainError) Error() string {
+func (e ChainError) Error() string {
return fmt.Sprintf("Error iptables %s: %s", e.Chain, string(e.Output))
}
@@ -142,7 +142,7 @@ func (c *Chain) Forward(action Action, ip net.IP, port int, proto, destAddr stri
"--to-destination", net.JoinHostPort(destAddr, strconv.Itoa(destPort))); err != nil {
return err
} else if len(output) != 0 {
- return &ChainError{Chain: "FORWARD", Output: output}
+ return ChainError{Chain: "FORWARD", Output: output}
}
if output, err := Raw("-t", string(Filter), string(action), c.Name,
@@ -154,7 +154,7 @@ func (c *Chain) Forward(action Action, ip net.IP, port int, proto, destAddr stri
"-j", "ACCEPT"); err != nil {
return err
} else if len(output) != 0 {
- return &ChainError{Chain: "FORWARD", Output: output}
+ return ChainError{Chain: "FORWARD", Output: output}
}
if output, err := Raw("-t", string(Nat), string(action), "POSTROUTING",
@@ -165,7 +165,7 @@ func (c *Chain) Forward(action Action, ip net.IP, port int, proto, destAddr stri
"-j", "MASQUERADE"); err != nil {
return err
} else if len(output) != 0 {
- return &ChainError{Chain: "FORWARD", Output: output}
+ return ChainError{Chain: "FORWARD", Output: output}
}
return nil
@@ -208,7 +208,7 @@ func (c *Chain) Prerouting(action Action, args ...string) error {
if output, err := Raw(append(a, "-j", c.Name)...); err != nil {
return err
} else if len(output) != 0 {
- return &ChainError{Chain: "PREROUTING", Output: output}
+ return ChainError{Chain: "PREROUTING", Output: output}
}
return nil
}
@@ -222,7 +222,7 @@ func (c *Chain) Output(action Action, args ...string) error {
if output, err := Raw(append(a, "-j", c.Name)...); err != nil {
return err
} else if len(output) != 0 {
- return &ChainError{Chain: "OUTPUT", Output: output}
+ return ChainError{Chain: "OUTPUT", Output: output}
}
return nil
}
@@ -275,6 +275,13 @@ func Exists(table Table, chain string, rule ...string) bool {
// Call 'iptables' system command, passing supplied arguments
func Raw(args ...string) ([]byte, error) {
+ if firewalldRunning {
+ output, err := Passthrough(Iptables, args...)
+ if err == nil || !strings.Contains(err.Error(), "was not provided by any .service files") {
+ return output, err
+ }
+
+ }
if err := initCheck(); err != nil {
return nil, err
diff --git a/pkg/jsonlog/jsonlog_marshalling.go b/pkg/jsonlog/jsonlog_marshalling.go
index 6244eb01a4fc2..abaa8a73baab6 100644
--- a/pkg/jsonlog/jsonlog_marshalling.go
+++ b/pkg/jsonlog/jsonlog_marshalling.go
@@ -65,8 +65,7 @@ import (
func (mj *JSONLog) MarshalJSON() ([]byte, error) {
var buf bytes.Buffer
buf.Grow(1024)
- err := mj.MarshalJSONBuf(&buf)
- if err != nil {
+ if err := mj.MarshalJSONBuf(&buf); err != nil {
return nil, err
}
return buf.Bytes(), nil
diff --git a/pkg/listenbuffer/buffer.go b/pkg/listenbuffer/buffer.go
index 6e3656d2c4fa8..97d622c15fda4 100644
--- a/pkg/listenbuffer/buffer.go
+++ b/pkg/listenbuffer/buffer.go
@@ -32,7 +32,7 @@ import "net"
// NewListenBuffer returns a net.Listener listening on addr with the protocol
// passed. The channel passed is used to activate the listenbuffer when the
// caller is ready to accept connections.
-func NewListenBuffer(proto, addr string, activate chan struct{}) (net.Listener, error) {
+func NewListenBuffer(proto, addr string, activate <-chan struct{}) (net.Listener, error) {
wrapped, err := net.Listen(proto, addr)
if err != nil {
return nil, err
@@ -46,9 +46,9 @@ func NewListenBuffer(proto, addr string, activate chan struct{}) (net.Listener,
// defaultListener is the buffered wrapper around the net.Listener
type defaultListener struct {
- wrapped net.Listener // The net.Listener wrapped by listenbuffer
- ready bool // Whether the listenbuffer has been activated
- activate chan struct{} // Channel to control activation of the listenbuffer
+ wrapped net.Listener // The net.Listener wrapped by listenbuffer
+ ready bool // Whether the listenbuffer has been activated
+ activate <-chan struct{} // Channel to control activation of the listenbuffer
}
// Close closes the wrapped socket.
diff --git a/pkg/mflag/flag.go b/pkg/mflag/flag.go
index f2da1cd1b91aa..f0d20d99b06c3 100644
--- a/pkg/mflag/flag.go
+++ b/pkg/mflag/flag.go
@@ -486,8 +486,7 @@ func (f *FlagSet) Set(name, value string) error {
if !ok {
return fmt.Errorf("no such flag -%v", name)
}
- err := flag.Value.Set(value)
- if err != nil {
+ if err := flag.Value.Set(value); err != nil {
return err
}
if f.actual == nil {
diff --git a/pkg/namesgenerator/names-generator.go b/pkg/namesgenerator/names-generator.go
index 40d4e5374c801..1087ece992653 100644
--- a/pkg/namesgenerator/names-generator.go
+++ b/pkg/namesgenerator/names-generator.go
@@ -308,19 +308,19 @@ var (
// Ada Yonath - an Israeli crystallographer, the first woman from the Middle East to win a Nobel prize in the sciences. https://en.wikipedia.org/wiki/Ada_Yonath
"yonath",
}
+
+ rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
)
func GetRandomName(retry int) string {
- rand.Seed(time.Now().UnixNano())
-
begin:
- name := fmt.Sprintf("%s_%s", left[rand.Intn(len(left))], right[rand.Intn(len(right))])
+ name := fmt.Sprintf("%s_%s", left[rnd.Intn(len(left))], right[rnd.Intn(len(right))])
if name == "boring_wozniak" /* Steve Wozniak is not boring */ {
goto begin
}
if retry > 0 {
- name = fmt.Sprintf("%s%d", name, rand.Intn(10))
+ name = fmt.Sprintf("%s%d", name, rnd.Intn(10))
}
return name
}
diff --git a/pkg/parsers/filters/parse.go b/pkg/parsers/filters/parse.go
index 9c056bb3cf34a..df5486d515801 100644
--- a/pkg/parsers/filters/parse.go
+++ b/pkg/parsers/filters/parse.go
@@ -58,8 +58,7 @@ func FromParam(p string) (Args, error) {
if len(p) == 0 {
return args, nil
}
- err := json.Unmarshal([]byte(p), &args)
- if err != nil {
+ if err := json.NewDecoder(strings.NewReader(p)).Decode(&args); err != nil {
return nil, err
}
return args, nil
diff --git a/pkg/pools/pools.go b/pkg/pools/pools.go
index 5338a0cfb2561..f366fa67a773c 100644
--- a/pkg/pools/pools.go
+++ b/pkg/pools/pools.go
@@ -1,5 +1,3 @@
-// +build go1.3
-
// Package pools provides a collection of pools which provide various
// data types with buffers. These can be used to lower the number of
// memory allocations and reuse buffers.
diff --git a/pkg/pools/pools_nopool.go b/pkg/pools/pools_nopool.go
deleted file mode 100644
index 48903c2396a27..0000000000000
--- a/pkg/pools/pools_nopool.go
+++ /dev/null
@@ -1,73 +0,0 @@
-// +build !go1.3
-
-package pools
-
-import (
- "bufio"
- "io"
-
- "github.com/docker/docker/pkg/ioutils"
-)
-
-var (
- BufioReader32KPool *BufioReaderPool
- BufioWriter32KPool *BufioWriterPool
-)
-
-const buffer32K = 32 * 1024
-
-type BufioReaderPool struct {
- size int
-}
-
-func init() {
- BufioReader32KPool = newBufioReaderPoolWithSize(buffer32K)
- BufioWriter32KPool = newBufioWriterPoolWithSize(buffer32K)
-}
-
-func newBufioReaderPoolWithSize(size int) *BufioReaderPool {
- return &BufioReaderPool{size: size}
-}
-
-func (bufPool *BufioReaderPool) Get(r io.Reader) *bufio.Reader {
- return bufio.NewReaderSize(r, bufPool.size)
-}
-
-func (bufPool *BufioReaderPool) Put(b *bufio.Reader) {
- b.Reset(nil)
-}
-
-func (bufPool *BufioReaderPool) NewReadCloserWrapper(buf *bufio.Reader, r io.Reader) io.ReadCloser {
- return ioutils.NewReadCloserWrapper(r, func() error {
- if readCloser, ok := r.(io.ReadCloser); ok {
- return readCloser.Close()
- }
- return nil
- })
-}
-
-type BufioWriterPool struct {
- size int
-}
-
-func newBufioWriterPoolWithSize(size int) *BufioWriterPool {
- return &BufioWriterPool{size: size}
-}
-
-func (bufPool *BufioWriterPool) Get(w io.Writer) *bufio.Writer {
- return bufio.NewWriterSize(w, bufPool.size)
-}
-
-func (bufPool *BufioWriterPool) Put(b *bufio.Writer) {
- b.Reset(nil)
-}
-
-func (bufPool *BufioWriterPool) NewWriteCloserWrapper(buf *bufio.Writer, w io.Writer) io.WriteCloser {
- return ioutils.NewWriteCloserWrapper(w, func() error {
- buf.Flush()
- if writeCloser, ok := w.(io.WriteCloser); ok {
- return writeCloser.Close()
- }
- return nil
- })
-}
diff --git a/pkg/requestdecorator/requestdecorator_test.go b/pkg/requestdecorator/requestdecorator_test.go
index b2c1fb3b97215..ed61135467bd6 100644
--- a/pkg/requestdecorator/requestdecorator_test.go
+++ b/pkg/requestdecorator/requestdecorator_test.go
@@ -1,45 +1,11 @@
package requestdecorator
import (
- "encoding/base64"
"net/http"
"strings"
"testing"
)
-// The following 2 functions are here for 1.3.3 support
-// After we drop 1.3.3 support we can use the functions supported
-// in go v1.4.0 +
-// BasicAuth returns the username and password provided in the request's
-// Authorization header, if the request uses HTTP Basic Authentication.
-// See RFC 2617, Section 2.
-func basicAuth(r *http.Request) (username, password string, ok bool) {
- auth := r.Header.Get("Authorization")
- if auth == "" {
- return
- }
- return parseBasicAuth(auth)
-}
-
-// parseBasicAuth parses an HTTP Basic Authentication string.
-// "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true).
-func parseBasicAuth(auth string) (username, password string, ok bool) {
- const prefix = "Basic "
- if !strings.HasPrefix(auth, prefix) {
- return
- }
- c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
- if err != nil {
- return
- }
- cs := string(c)
- s := strings.IndexByte(cs, ':')
- if s < 0 {
- return
- }
- return cs[:s], cs[s+1:], true
-}
-
func TestUAVersionInfo(t *testing.T) {
uavi := NewUAVersionInfo("foo", "bar")
if !uavi.isValid() {
@@ -147,7 +113,7 @@ func TestAuthDecorator(t *testing.T) {
t.Fatal(err)
}
- username, password, ok := basicAuth(reqDecorated)
+ username, password, ok := reqDecorated.BasicAuth()
if !ok {
t.Fatalf("Cannot retrieve basic auth info from request")
}
@@ -180,8 +146,8 @@ func TestRequestFactory(t *testing.T) {
requestFactory := NewRequestFactory(ad, uad)
- if dlen := len(requestFactory.GetDecorators()); dlen != 2 {
- t.Fatalf("Expected to have two decorators, got %d", dlen)
+ if l := len(requestFactory.GetDecorators()); l != 2 {
+ t.Fatalf("Expected to have two decorators, got %d", l)
}
req, err := requestFactory.NewRequest("GET", "/test", strings.NewReader("test"))
@@ -189,7 +155,7 @@ func TestRequestFactory(t *testing.T) {
t.Fatal(err)
}
- username, password, ok := basicAuth(req)
+ username, password, ok := req.BasicAuth()
if !ok {
t.Fatalf("Cannot retrieve basic auth info from request")
}
@@ -209,8 +175,8 @@ func TestRequestFactoryNewRequestWithDecorators(t *testing.T) {
requestFactory := NewRequestFactory(ad)
- if dlen := len(requestFactory.GetDecorators()); dlen != 1 {
- t.Fatalf("Expected to have one decorators, got %d", dlen)
+ if l := len(requestFactory.GetDecorators()); l != 1 {
+ t.Fatalf("Expected to have one decorators, got %d", l)
}
ad2 := NewAuthDecorator("test2", "password2")
@@ -220,7 +186,7 @@ func TestRequestFactoryNewRequestWithDecorators(t *testing.T) {
t.Fatal(err)
}
- username, password, ok := basicAuth(req)
+ username, password, ok := req.BasicAuth()
if !ok {
t.Fatalf("Cannot retrieve basic auth info from request")
}
@@ -235,15 +201,15 @@ func TestRequestFactoryNewRequestWithDecorators(t *testing.T) {
func TestRequestFactoryAddDecorator(t *testing.T) {
requestFactory := NewRequestFactory()
- if dlen := len(requestFactory.GetDecorators()); dlen != 0 {
- t.Fatalf("Expected to have zero decorators, got %d", dlen)
+ if l := len(requestFactory.GetDecorators()); l != 0 {
+ t.Fatalf("Expected to have zero decorators, got %d", l)
}
ad := NewAuthDecorator("test", "password")
requestFactory.AddDecorator(ad)
- if dlen := len(requestFactory.GetDecorators()); dlen != 1 {
- t.Fatalf("Expected to have one decorators, got %d", dlen)
+ if l := len(requestFactory.GetDecorators()); l != 1 {
+ t.Fatalf("Expected to have one decorators, got %d", l)
}
}
diff --git a/pkg/resolvconf/resolvconf.go b/pkg/resolvconf/resolvconf.go
index d7d53e16d010f..5707b16b7fbf5 100644
--- a/pkg/resolvconf/resolvconf.go
+++ b/pkg/resolvconf/resolvconf.go
@@ -9,7 +9,7 @@ import (
"sync"
"github.com/Sirupsen/logrus"
- "github.com/docker/docker/utils"
+ "github.com/docker/docker/pkg/ioutils"
)
var (
@@ -59,7 +59,7 @@ func GetIfChanged() ([]byte, string, error) {
if err != nil {
return nil, "", err
}
- newHash, err := utils.HashData(bytes.NewReader(resolv))
+ newHash, err := ioutils.HashData(bytes.NewReader(resolv))
if err != nil {
return nil, "", err
}
diff --git a/pkg/stdcopy/stdcopy.go b/pkg/stdcopy/stdcopy.go
index ccf1d9dbabad0..dbb74e5a20876 100644
--- a/pkg/stdcopy/stdcopy.go
+++ b/pkg/stdcopy/stdcopy.go
@@ -52,12 +52,8 @@ func (w *StdWriter) Write(buf []byte) (n int, err error) {
// and written to the underlying `w` stream.
// This allows multiple write streams (e.g. stdout and stderr) to be muxed into a single connection.
// `t` indicates the id of the stream to encapsulate.
-// It can be utils.Stdin, utils.Stdout, utils.Stderr.
+// It can be stdcopy.Stdin, stdcopy.Stdout, stdcopy.Stderr.
func NewStdWriter(w io.Writer, t StdType) *StdWriter {
- if len(t) != StdWriterPrefixLen {
- return nil
- }
-
return &StdWriter{
Writer: w,
prefix: t,
diff --git a/pkg/stdcopy/stdcopy_test.go b/pkg/stdcopy/stdcopy_test.go
index 14e6ed3115ce7..a9fd73a49eddc 100644
--- a/pkg/stdcopy/stdcopy_test.go
+++ b/pkg/stdcopy/stdcopy_test.go
@@ -3,9 +3,74 @@ package stdcopy
import (
"bytes"
"io/ioutil"
+ "strings"
"testing"
)
+func TestNewStdWriter(t *testing.T) {
+ writer := NewStdWriter(ioutil.Discard, Stdout)
+ if writer == nil {
+ t.Fatalf("NewStdWriter with an invalid StdType should not return nil.")
+ }
+}
+
+func TestWriteWithUnitializedStdWriter(t *testing.T) {
+ writer := StdWriter{
+ Writer: nil,
+ prefix: Stdout,
+ sizeBuf: make([]byte, 4),
+ }
+ n, err := writer.Write([]byte("Something here"))
+ if n != 0 || err == nil {
+ t.Fatalf("Should fail when given an uncomplete or uninitialized StdWriter")
+ }
+}
+
+func TestWriteWithNilBytes(t *testing.T) {
+ writer := NewStdWriter(ioutil.Discard, Stdout)
+ n, err := writer.Write(nil)
+ if err != nil {
+ t.Fatalf("Shouldn't have fail when given no data")
+ }
+ if n > 0 {
+ t.Fatalf("Write should have written 0 byte, but has written %d", n)
+ }
+}
+
+func TestWrite(t *testing.T) {
+ writer := NewStdWriter(ioutil.Discard, Stdout)
+ data := []byte("Test StdWrite.Write")
+ n, err := writer.Write(data)
+ if err != nil {
+ t.Fatalf("Error while writing with StdWrite")
+ }
+ if n != len(data) {
+ t.Fatalf("Write should have writen %d byte but wrote %d.", len(data), n)
+ }
+}
+
+func TestStdCopyWithInvalidInputHeader(t *testing.T) {
+ dstOut := NewStdWriter(ioutil.Discard, Stdout)
+ dstErr := NewStdWriter(ioutil.Discard, Stderr)
+ src := strings.NewReader("Invalid input")
+ _, err := StdCopy(dstOut, dstErr, src)
+ if err == nil {
+ t.Fatal("StdCopy with invalid input header should fail.")
+ }
+}
+
+func TestStdCopyWithCorruptedPrefix(t *testing.T) {
+ data := []byte{0x01, 0x02, 0x03}
+ src := bytes.NewReader(data)
+ written, err := StdCopy(nil, nil, src)
+ if err != nil {
+ t.Fatalf("StdCopy should not return an error with corrupted prefix.")
+ }
+ if written != 0 {
+ t.Fatalf("StdCopy should have written 0, but has written %d", written)
+ }
+}
+
func BenchmarkWrite(b *testing.B) {
w := NewStdWriter(ioutil.Discard, Stdout)
data := []byte("Test line for testing stdwriter performance\n")
diff --git a/pkg/streamformatter/streamformatter.go b/pkg/streamformatter/streamformatter.go
index 383e7adf9e882..90f2b695d3d93 100644
--- a/pkg/streamformatter/streamformatter.go
+++ b/pkg/streamformatter/streamformatter.go
@@ -3,8 +3,9 @@ package streamformatter
import (
"encoding/json"
"fmt"
- "github.com/docker/docker/pkg/jsonmessage"
"io"
+
+ "github.com/docker/docker/pkg/jsonmessage"
)
type StreamFormatter struct {
diff --git a/pkg/streamformatter/streamformatter_test.go b/pkg/streamformatter/streamformatter_test.go
index edc432e900710..1dee05aa6c590 100644
--- a/pkg/streamformatter/streamformatter_test.go
+++ b/pkg/streamformatter/streamformatter_test.go
@@ -3,9 +3,10 @@ package streamformatter
import (
"encoding/json"
"errors"
- "github.com/docker/docker/pkg/jsonmessage"
"reflect"
"testing"
+
+ "github.com/docker/docker/pkg/jsonmessage"
)
func TestFormatStream(t *testing.T) {
diff --git a/pkg/stringutils/stringutils.go b/pkg/stringutils/stringutils.go
index bcb0ece57cd2c..e3ebf5d1ed82b 100644
--- a/pkg/stringutils/stringutils.go
+++ b/pkg/stringutils/stringutils.go
@@ -1,23 +1,12 @@
package stringutils
import (
- "crypto/rand"
- "encoding/hex"
- "io"
+ "bytes"
mathrand "math/rand"
+ "strings"
"time"
)
-// Generate 32 chars random string
-func GenerateRandomString() string {
- id := make([]byte, 32)
-
- if _, err := io.ReadFull(rand.Reader, id); err != nil {
- panic(err) // This shouldn't happen
- }
- return hex.EncodeToString(id)
-}
-
// Generate alpha only random stirng with length n
func GenerateRandomAlphaOnlyString(n int) string {
// make a really long string
@@ -41,3 +30,57 @@ func GenerateRandomAsciiString(n int) string {
}
return string(res)
}
+
+// Truncate a string to maxlen
+func Truncate(s string, maxlen int) string {
+ if len(s) <= maxlen {
+ return s
+ }
+ return s[:maxlen]
+}
+
+// Test wheather a string is contained in a slice of strings or not.
+// Comparison is case insensitive
+func InSlice(slice []string, s string) bool {
+ for _, ss := range slice {
+ if strings.ToLower(s) == strings.ToLower(ss) {
+ return true
+ }
+ }
+ return false
+}
+
+func quote(word string, buf *bytes.Buffer) {
+ // Bail out early for "simple" strings
+ if word != "" && !strings.ContainsAny(word, "\\'\"`${[|&;<>()~*?! \t\n") {
+ buf.WriteString(word)
+ return
+ }
+
+ buf.WriteString("'")
+
+ for i := 0; i < len(word); i++ {
+ b := word[i]
+ if b == '\'' {
+ // Replace literal ' with a close ', a \', and a open '
+ buf.WriteString("'\\''")
+ } else {
+ buf.WriteByte(b)
+ }
+ }
+
+ buf.WriteString("'")
+}
+
+// Take a list of strings and escape them so they will be handled right
+// when passed as arguments to an program via a shell
+func ShellQuoteArguments(args []string) string {
+ var buf bytes.Buffer
+ for i, arg := range args {
+ if i != 0 {
+ buf.WriteByte(' ')
+ }
+ quote(arg, &buf)
+ }
+ return buf.String()
+}
diff --git a/pkg/stringutils/stringutils_test.go b/pkg/stringutils/stringutils_test.go
index 60b848ff5a09f..8dcb4696bb749 100644
--- a/pkg/stringutils/stringutils_test.go
+++ b/pkg/stringutils/stringutils_test.go
@@ -2,18 +2,19 @@ package stringutils
import "testing"
-func TestRandomString(t *testing.T) {
- str := GenerateRandomString()
- if len(str) != 64 {
- t.Fatalf("Id returned is incorrect: %s", str)
+func testLengthHelper(generator func(int) string, t *testing.T) {
+ expectedLength := 20
+ s := generator(expectedLength)
+ if len(s) != expectedLength {
+ t.Fatalf("Length of %s was %d but expected length %d", s, len(s), expectedLength)
}
}
-func TestRandomStringUniqueness(t *testing.T) {
+func testUniquenessHelper(generator func(int) string, t *testing.T) {
repeats := 25
set := make(map[string]struct{}, repeats)
for i := 0; i < repeats; i = i + 1 {
- str := GenerateRandomString()
+ str := generator(64)
if len(str) != 64 {
t.Fatalf("Id returned is incorrect: %s", str)
}
@@ -23,3 +24,64 @@ func TestRandomStringUniqueness(t *testing.T) {
set[str] = struct{}{}
}
}
+
+func isASCII(s string) bool {
+ for _, c := range s {
+ if c > 127 {
+ return false
+ }
+ }
+ return true
+}
+
+func TestGenerateRandomAlphaOnlyStringLength(t *testing.T) {
+ testLengthHelper(GenerateRandomAlphaOnlyString, t)
+}
+
+func TestGenerateRandomAlphaOnlyStringUniqueness(t *testing.T) {
+ testUniquenessHelper(GenerateRandomAlphaOnlyString, t)
+}
+
+func TestGenerateRandomAsciiStringLength(t *testing.T) {
+ testLengthHelper(GenerateRandomAsciiString, t)
+}
+
+func TestGenerateRandomAsciiStringUniqueness(t *testing.T) {
+ testUniquenessHelper(GenerateRandomAsciiString, t)
+}
+
+func TestGenerateRandomAsciiStringIsAscii(t *testing.T) {
+ str := GenerateRandomAsciiString(64)
+ if !isASCII(str) {
+ t.Fatalf("%s contained non-ascii characters", str)
+ }
+}
+
+func TestTruncate(t *testing.T) {
+ str := "teststring"
+ newstr := Truncate(str, 4)
+ if newstr != "test" {
+ t.Fatalf("Expected test, got %s", newstr)
+ }
+ newstr = Truncate(str, 20)
+ if newstr != "teststring" {
+ t.Fatalf("Expected teststring, got %s", newstr)
+ }
+}
+
+func TestInSlice(t *testing.T) {
+ slice := []string{"test", "in", "slice"}
+
+ test := InSlice(slice, "test")
+ if !test {
+ t.Fatalf("Expected string test to be in slice")
+ }
+ test = InSlice(slice, "SLICE")
+ if !test {
+ t.Fatalf("Expected string SLICE to be in slice")
+ }
+ test = InSlice(slice, "notinslice")
+ if test {
+ t.Fatalf("Expected string notinslice not to be in slice")
+ }
+}
diff --git a/pkg/sysinfo/sysinfo.go b/pkg/sysinfo/sysinfo.go
index 16839bcb4cc16..195a03e9a8ed8 100644
--- a/pkg/sysinfo/sysinfo.go
+++ b/pkg/sysinfo/sysinfo.go
@@ -13,6 +13,7 @@ import (
type SysInfo struct {
MemoryLimit bool
SwapLimit bool
+ CpuCfsQuota bool
IPv4ForwardingDisabled bool
AppArmor bool
}
@@ -22,20 +23,28 @@ func New(quiet bool) *SysInfo {
sysInfo := &SysInfo{}
if cgroupMemoryMountpoint, err := cgroups.FindCgroupMountpoint("memory"); err != nil {
if !quiet {
- logrus.Warnf("%s", err)
+ logrus.Warnf("Your kernel does not support cgroup memory limit: %v", err)
}
} else {
- _, err1 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.limit_in_bytes"))
- _, err2 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.soft_limit_in_bytes"))
- sysInfo.MemoryLimit = err1 == nil && err2 == nil
- if !sysInfo.MemoryLimit && !quiet {
- logrus.Warnf("Your kernel does not support cgroup memory limit.")
- }
+ // If memory cgroup is mounted, MemoryLimit is always enabled.
+ sysInfo.MemoryLimit = true
- _, err = ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.memsw.limit_in_bytes"))
- sysInfo.SwapLimit = err == nil
+ _, err1 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.memsw.limit_in_bytes"))
+ sysInfo.SwapLimit = err1 == nil
if !sysInfo.SwapLimit && !quiet {
- logrus.Warnf("Your kernel does not support cgroup swap limit.")
+ logrus.Warn("Your kernel does not support swap memory limit.")
+ }
+ }
+
+ if cgroupCpuMountpoint, err := cgroups.FindCgroupMountpoint("cpu"); err != nil {
+ if !quiet {
+ logrus.Warnf("%v", err)
+ }
+ } else {
+ _, err1 := ioutil.ReadFile(path.Join(cgroupCpuMountpoint, "cpu.cfs_quota_us"))
+ sysInfo.CpuCfsQuota = err1 == nil
+ if !sysInfo.CpuCfsQuota && !quiet {
+ logrus.Warn("Your kernel does not support cgroup cfs quotas")
}
}
@@ -45,5 +54,11 @@ func New(quiet bool) *SysInfo {
} else {
sysInfo.AppArmor = true
}
+
+ // Check if Devices cgroup is mounted, it is hard requirement for container security.
+ if _, err := cgroups.FindCgroupMountpoint("devices"); err != nil {
+ logrus.Fatalf("Error mounting devices cgroup: %v", err)
+ }
+
return sysInfo
}
diff --git a/pkg/system/lstat.go b/pkg/system/lstat.go
index a966cd4881b2b..d0e43b3709784 100644
--- a/pkg/system/lstat.go
+++ b/pkg/system/lstat.go
@@ -12,8 +12,7 @@ import (
// Throws an error if the file does not exist
func Lstat(path string) (*Stat_t, error) {
s := &syscall.Stat_t{}
- err := syscall.Lstat(path, s)
- if err != nil {
+ if err := syscall.Lstat(path, s); err != nil {
return nil, err
}
return fromStatT(s)
diff --git a/pkg/system/stat_linux.go b/pkg/system/stat_linux.go
index 928ba89e698d4..3899b3e0eeac7 100644
--- a/pkg/system/stat_linux.go
+++ b/pkg/system/stat_linux.go
@@ -20,8 +20,7 @@ func fromStatT(s *syscall.Stat_t) (*Stat_t, error) {
// Throws an error if the file does not exist
func Stat(path string) (*Stat_t, error) {
s := &syscall.Stat_t{}
- err := syscall.Stat(path, s)
- if err != nil {
+ if err := syscall.Stat(path, s); err != nil {
return nil, err
}
return fromStatT(s)
diff --git a/pkg/term/tc_linux_cgo.go b/pkg/term/tc_linux_cgo.go
index ae9516c99cf80..d47cf59b8dff7 100644
--- a/pkg/term/tc_linux_cgo.go
+++ b/pkg/term/tc_linux_cgo.go
@@ -24,6 +24,7 @@ func MakeRaw(fd uintptr) (*State, error) {
newState := oldState.termios
C.cfmakeraw((*C.struct_termios)(unsafe.Pointer(&newState)))
+ newState.Oflag = newState.Oflag | C.OPOST
if err := tcset(fd, &newState); err != 0 {
return nil, err
}
diff --git a/pkg/term/term_windows.go b/pkg/term/term_windows.go
index 5b637928faece..f46c9c8acf01b 100644
--- a/pkg/term/term_windows.go
+++ b/pkg/term/term_windows.go
@@ -5,6 +5,7 @@ import (
"io"
"os"
+ "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/term/winconsole"
)
@@ -57,6 +58,7 @@ func GetWinsize(fd uintptr) (*Winsize, error) {
// SetWinsize sets the size of the given terminal connected to the passed file descriptor.
func SetWinsize(fd uintptr, ws *Winsize) error {
// TODO(azlinux): Implement SetWinsize
+ logrus.Debugf("[windows] SetWinsize: WARNING -- Unsupported method invoked")
return nil
}
@@ -120,11 +122,10 @@ func MakeRaw(fd uintptr) (*State, error) {
mode &^= winconsole.ENABLE_ECHO_INPUT
mode &^= winconsole.ENABLE_LINE_INPUT
mode &^= winconsole.ENABLE_MOUSE_INPUT
- // TODO(azlinux): Enable window input to handle window resizing
- mode |= winconsole.ENABLE_WINDOW_INPUT
+ mode &^= winconsole.ENABLE_WINDOW_INPUT
+ mode &^= winconsole.ENABLE_PROCESSED_INPUT
// Enable these modes
- mode |= winconsole.ENABLE_PROCESSED_INPUT
mode |= winconsole.ENABLE_EXTENDED_FLAGS
mode |= winconsole.ENABLE_INSERT_MODE
mode |= winconsole.ENABLE_QUICK_EDIT_MODE
diff --git a/pkg/term/winconsole/console_windows.go b/pkg/term/winconsole/console_windows.go
index bebf6d7c11cac..ce40a93167f96 100644
--- a/pkg/term/winconsole/console_windows.go
+++ b/pkg/term/winconsole/console_windows.go
@@ -12,6 +12,8 @@ import (
"sync"
"syscall"
"unsafe"
+
+ "github.com/Sirupsen/logrus"
)
const (
@@ -410,25 +412,25 @@ func getNumberOfChars(fromCoord COORD, toCoord COORD, screenSize COORD) uint32 {
var buffer []CHAR_INFO
-func clearDisplayRect(handle uintptr, fillChar rune, attributes WORD, fromCoord COORD, toCoord COORD, windowSize COORD) (uint32, error) {
+func clearDisplayRect(handle uintptr, attributes WORD, fromCoord COORD, toCoord COORD) (uint32, error) {
var writeRegion SMALL_RECT
- writeRegion.Top = fromCoord.Y
writeRegion.Left = fromCoord.X
+ writeRegion.Top = fromCoord.Y
writeRegion.Right = toCoord.X
writeRegion.Bottom = toCoord.Y
// allocate and initialize buffer
width := toCoord.X - fromCoord.X + 1
height := toCoord.Y - fromCoord.Y + 1
- size := width * height
+ size := uint32(width) * uint32(height)
if size > 0 {
- for i := 0; i < int(size); i++ {
- buffer[i].UnicodeChar = WCHAR(fillChar)
- buffer[i].Attributes = attributes
+ buffer := make([]CHAR_INFO, size)
+ for i := range buffer {
+ buffer[i] = CHAR_INFO{WCHAR(' '), attributes}
}
// Write to buffer
- r, err := writeConsoleOutput(handle, buffer[:size], windowSize, COORD{X: 0, Y: 0}, &writeRegion)
+ r, err := writeConsoleOutput(handle, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, &writeRegion)
if !r {
if err != nil {
return 0, err
@@ -439,18 +441,18 @@ func clearDisplayRect(handle uintptr, fillChar rune, attributes WORD, fromCoord
return uint32(size), nil
}
-func clearDisplayRange(handle uintptr, fillChar rune, attributes WORD, fromCoord COORD, toCoord COORD, windowSize COORD) (uint32, error) {
+func clearDisplayRange(handle uintptr, attributes WORD, fromCoord COORD, toCoord COORD) (uint32, error) {
nw := uint32(0)
// start and end on same line
if fromCoord.Y == toCoord.Y {
- return clearDisplayRect(handle, fillChar, attributes, fromCoord, toCoord, windowSize)
+ return clearDisplayRect(handle, attributes, fromCoord, toCoord)
}
// TODO(azlinux): if full screen, optimize
// spans more than one line
if fromCoord.Y < toCoord.Y {
// from start position till end of line for first line
- n, err := clearDisplayRect(handle, fillChar, attributes, fromCoord, COORD{X: windowSize.X - 1, Y: fromCoord.Y}, windowSize)
+ n, err := clearDisplayRect(handle, attributes, fromCoord, COORD{X: toCoord.X, Y: fromCoord.Y})
if err != nil {
return nw, err
}
@@ -458,14 +460,14 @@ func clearDisplayRange(handle uintptr, fillChar rune, attributes WORD, fromCoord
// lines between
linesBetween := toCoord.Y - fromCoord.Y - 1
if linesBetween > 0 {
- n, err = clearDisplayRect(handle, fillChar, attributes, COORD{X: 0, Y: fromCoord.Y + 1}, COORD{X: windowSize.X - 1, Y: toCoord.Y - 1}, windowSize)
+ n, err = clearDisplayRect(handle, attributes, COORD{X: 0, Y: fromCoord.Y + 1}, COORD{X: toCoord.X, Y: toCoord.Y - 1})
if err != nil {
return nw, err
}
nw += n
}
// lines at end
- n, err = clearDisplayRect(handle, fillChar, attributes, COORD{X: 0, Y: toCoord.Y}, toCoord, windowSize)
+ n, err = clearDisplayRect(handle, attributes, COORD{X: 0, Y: toCoord.Y}, toCoord)
if err != nil {
return nw, err
}
@@ -593,6 +595,7 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
n = len(command)
parsedCommand := parseAnsiCommand(command)
+ logrus.Debugf("[windows] HandleOutputCommand: %v", parsedCommand)
// console settings changes need to happen in atomic way
term.outMutex.Lock()
@@ -648,6 +651,7 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
column = int16(screenBufferInfo.Window.Right) + 1
}
// The numbers are not 0 based, but 1 based
+ logrus.Debugf("[windows] HandleOutputCommmand: Moving cursor to (%v,%v)", column-1, line-1)
if err := setConsoleCursorPosition(handle, false, column-1, line-1); err != nil {
return n, err
}
@@ -715,9 +719,9 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
switch value {
case 0:
start = screenBufferInfo.CursorPosition
- // end of the screen
- end.X = screenBufferInfo.MaximumWindowSize.X - 1
- end.Y = screenBufferInfo.MaximumWindowSize.Y - 1
+ // end of the buffer
+ end.X = screenBufferInfo.Size.X - 1
+ end.Y = screenBufferInfo.Size.Y - 1
// cursor
cursor = screenBufferInfo.CursorPosition
case 1:
@@ -733,20 +737,21 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
// start of the screen
start.X = 0
start.Y = 0
- // end of the screen
- end.X = screenBufferInfo.MaximumWindowSize.X - 1
- end.Y = screenBufferInfo.MaximumWindowSize.Y - 1
+ // end of the buffer
+ end.X = screenBufferInfo.Size.X - 1
+ end.Y = screenBufferInfo.Size.Y - 1
// cursor
cursor.X = 0
cursor.Y = 0
}
- if _, err := clearDisplayRange(uintptr(handle), ' ', term.screenBufferInfo.Attributes, start, end, screenBufferInfo.MaximumWindowSize); err != nil {
+ if _, err := clearDisplayRange(uintptr(handle), term.screenBufferInfo.Attributes, start, end); err != nil {
return n, err
}
// remember the the cursor position is 1 based
if err := setConsoleCursorPosition(handle, false, int16(cursor.X), int16(cursor.Y)); err != nil {
return n, err
}
+
case "K":
// [K
// Clears all characters from the cursor position to the end of the line (including the character at the cursor position).
@@ -766,7 +771,7 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
// start is where cursor is
start = screenBufferInfo.CursorPosition
// end of line
- end.X = screenBufferInfo.MaximumWindowSize.X - 1
+ end.X = screenBufferInfo.Size.X - 1
end.Y = screenBufferInfo.CursorPosition.Y
// cursor remains the same
cursor = screenBufferInfo.CursorPosition
@@ -782,15 +787,15 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
case 2:
// start of the line
start.X = 0
- start.Y = screenBufferInfo.MaximumWindowSize.Y - 1
+ start.Y = screenBufferInfo.CursorPosition.Y - 1
// end of the line
- end.X = screenBufferInfo.MaximumWindowSize.X - 1
- end.Y = screenBufferInfo.MaximumWindowSize.Y - 1
+ end.X = screenBufferInfo.Size.X - 1
+ end.Y = screenBufferInfo.CursorPosition.Y - 1
// cursor
cursor.X = 0
- cursor.Y = screenBufferInfo.MaximumWindowSize.Y - 1
+ cursor.Y = screenBufferInfo.CursorPosition.Y - 1
}
- if _, err := clearDisplayRange(uintptr(handle), ' ', term.screenBufferInfo.Attributes, start, end, screenBufferInfo.MaximumWindowSize); err != nil {
+ if _, err := clearDisplayRange(uintptr(handle), term.screenBufferInfo.Attributes, start, end); err != nil {
return n, err
}
// remember the the cursor position is 1 based
@@ -1037,8 +1042,7 @@ func (term *WindowsTerminal) HandleInputSequence(fd uintptr, command []byte) (n
}
func marshal(c COORD) uintptr {
- // works only on intel-endian machines
- return uintptr(uint32(uint32(uint16(c.Y))<<16 | uint32(uint16(c.X))))
+ return uintptr(*((*DWORD)(unsafe.Pointer(&c))))
}
// IsConsole returns true if the given file descriptor is a terminal.
diff --git a/pkg/term/winconsole/console_windows_test.go b/pkg/term/winconsole/console_windows_test.go
index ee9d96834b854..edb5d6f66123a 100644
--- a/pkg/term/winconsole/console_windows_test.go
+++ b/pkg/term/winconsole/console_windows_test.go
@@ -18,7 +18,7 @@ func helpsTestParseInt16OrDefault(t *testing.T, expectedValue int16, shouldFail
t.Errorf(format, args)
}
if expectedValue != value {
- t.Errorf("The value returned does not macth expected\n\tExpected:%v\n\t:Actual%v", expectedValue, value)
+ t.Errorf("The value returned does not match expected\n\tExpected:%v\n\t:Actual%v", expectedValue, value)
t.Errorf(format, args)
}
}
diff --git a/pkg/term/winconsole/term_emulator.go b/pkg/term/winconsole/term_emulator.go
index 8c9f34284d885..2d5edc0390e5f 100644
--- a/pkg/term/winconsole/term_emulator.go
+++ b/pkg/term/winconsole/term_emulator.go
@@ -1,6 +1,7 @@
package winconsole
import (
+ "fmt"
"io"
"strconv"
"strings"
@@ -206,6 +207,21 @@ func (c *ansiCommand) getParam(index int) string {
return ""
}
+func (ac *ansiCommand) String() string {
+ return fmt.Sprintf("0x%v \"%v\" (\"%v\")",
+ bytesToHex(ac.CommandBytes),
+ ac.Command,
+ strings.Join(ac.Parameters, "\",\""))
+}
+
+func bytesToHex(b []byte) string {
+ hex := make([]string, len(b))
+ for i, ch := range b {
+ hex[i] = fmt.Sprintf("%X", ch)
+ }
+ return strings.Join(hex, "")
+}
+
func parseInt16OrDefault(s string, defaultValue int16) (n int16, err error) {
if s == "" {
return defaultValue, nil
diff --git a/pkg/term/winconsole/term_emulator_test.go b/pkg/term/winconsole/term_emulator_test.go
index 65de5a79338e1..94104ff51f2f9 100644
--- a/pkg/term/winconsole/term_emulator_test.go
+++ b/pkg/term/winconsole/term_emulator_test.go
@@ -138,7 +138,7 @@ func TestAssertEqualBytesNegative(t *testing.T) {
AssertBytesEqual(t, []byte{1, 2, 3}, []byte{1, 1, 1}, "content mismatch")
}*/
-// Checks that the calls recieved
+// Checks that the calls received
func assertHandlerOutput(t *testing.T, mock *mockTerminal, plainText string, commands ...string) {
text := make([]byte, 0, 3*len(plainText))
cmdIndex := 0
diff --git a/pkg/timeoutconn/timeoutconn.go b/pkg/timeoutconn/timeoutconn.go
index 3a554559a4a97..d9534b5da7500 100644
--- a/pkg/timeoutconn/timeoutconn.go
+++ b/pkg/timeoutconn/timeoutconn.go
@@ -17,8 +17,7 @@ type conn struct {
func (c *conn) Read(b []byte) (int, error) {
if c.timeout > 0 {
- err := c.Conn.SetReadDeadline(time.Now().Add(c.timeout))
- if err != nil {
+ if err := c.Conn.SetReadDeadline(time.Now().Add(c.timeout)); err != nil {
return 0, err
}
}
diff --git a/project/GOVERNANCE.md b/project/GOVERNANCE.md
index 52a8bf05d6cb8..6ae7baf743017 100644
--- a/project/GOVERNANCE.md
+++ b/project/GOVERNANCE.md
@@ -4,7 +4,7 @@ In the spirit of openness, Docker created a Governance Advisory Board, and commi
All output from the meetings should be considered proposals only, and are subject to the review and approval of the community and the project leadership.
The materials from the first Docker Governance Advisory Board meeting, held on October 28, 2014, are available at
-[Google Docs Folder](http://goo.gl/Alfj8r)
+[Google Docs Folder](https://goo.gl/Alfj8r)
These include:
diff --git a/project/PACKAGERS.md b/project/PACKAGERS.md
index 5704b0a2b29c4..d321a900d683d 100644
--- a/project/PACKAGERS.md
+++ b/project/PACKAGERS.md
@@ -45,9 +45,9 @@ need to package Docker your way, without denaturing it in the process.
To build Docker, you will need the following:
* A recent version of Git and Mercurial
-* Go version 1.3 or later
+* Go version 1.4 or later
* A clean checkout of the source added to a valid [Go
- workspace](http://golang.org/doc/code.html#Workspaces) under the path
+ workspace](https://golang.org/doc/code.html#Workspaces) under the path
*src/github.com/docker/docker* (unless you plan to use `AUTO_GOPATH`,
explained in more detail below)
@@ -237,9 +237,9 @@ are as follows (in order):
installed at "/usr/bin/docker", then "/usr/bin/dockerinit" will be the first
place this file is searched for)
* "/usr/libexec/docker/dockerinit" or "/usr/local/libexec/docker/dockerinit"
- ([FHS 3.0 Draft](http://www.linuxbase.org/betaspecs/fhs/fhs.html#usrlibexec))
+ ([FHS 3.0 Draft](https://www.linuxbase.org/betaspecs/fhs/fhs.html#usrlibexec))
* "/usr/lib/docker/dockerinit" or "/usr/local/lib/docker/dockerinit" ([FHS
- 2.3](http://refspecs.linuxfoundation.org/FHS_2.3/fhs-2.3.html#USRLIBLIBRARIESFORPROGRAMMINGANDPA))
+ 2.3](https://refspecs.linuxfoundation.org/FHS_2.3/fhs-2.3.html#USRLIBLIBRARIESFORPROGRAMMINGANDPA))
If (and please, only if) one of the paths above is insufficient due to distro
policy or similar issues, you may use the `DOCKER_INITPATH` environment variable
diff --git a/project/RELEASE-CHECKLIST.md b/project/RELEASE-CHECKLIST.md
index 10af71c81d2ec..d2b9650805f72 100644
--- a/project/RELEASE-CHECKLIST.md
+++ b/project/RELEASE-CHECKLIST.md
@@ -49,7 +49,17 @@ git cherry-pick
...
```
-### 2. Update CHANGELOG.md
+### 2. Bump the API version on master
+
+We don't want to stop contributions to master just because we are releasing. At
+the same time, now that the release branch exists, we don't want API changes to
+go to the now frozen API version.
+
+Create a new entry in `docs/sources/reference/api/` by copying the latest and
+bumping the version number (in both the file's name and content), and submit
+this in a PR against master.
+
+### 3. Update CHANGELOG.md
You can run this command for reference with git 2.0:
@@ -124,7 +134,7 @@ git log --format='%aN <%aE>' v0.7.0...bump_v0.8.0 | sort -uf
Obviously, you'll need to adjust version numbers as necessary. If you just need
a count, add a simple `| wc -l`.
-### 3. Change the contents of the VERSION file
+### 4. Change the contents of the VERSION file
Before the big thing, you'll want to make successive release candidates and get
people to test. The release candidate number `N` should be part of the version:
@@ -134,7 +144,7 @@ export RC_VERSION=${VERSION}-rcN
echo ${RC_VERSION#v} > VERSION
```
-### 4. Test the docs
+### 5. Test the docs
Make sure that your tree includes documentation for any modified or
new features, syntax or semantic changes.
@@ -145,7 +155,7 @@ To test locally:
make docs
```
-To make a shared test at http://beta-docs.docker.io:
+To make a shared test at https://beta-docs.docker.io:
(You will need the `awsconfig` file added to the `docs/` dir)
@@ -153,7 +163,7 @@ To make a shared test at http://beta-docs.docker.io:
make AWS_S3_BUCKET=beta-docs.docker.io BUILD_ROOT=yes docs-release
```
-### 5. Commit and create a pull request to the "release" branch
+### 6. Commit and create a pull request to the "release" branch
```bash
git add VERSION CHANGELOG.md
@@ -166,7 +176,7 @@ That last command will give you the proper link to visit to ensure that you
open the PR against the "release" branch instead of accidentally against
"master" (like so many brave souls before you already have).
-### 6. Publish release candidate binaries
+### 7. Publish release candidate binaries
To run this you will need access to the release credentials. Get them from the
Core maintainers.
@@ -219,7 +229,7 @@ We recommend announcing the release candidate on:
- The [docker-maintainers](https://groups.google.com/a/dockerproject.org/forum/#!forum/maintainers) group
- Any social media that can bring some attention to the release candidate
-### 7. Iterate on successive release candidates
+### 8. Iterate on successive release candidates
Spend several days along with the community explicitly investing time and
resources to try and break Docker in every possible way, documenting any
@@ -269,7 +279,7 @@ git push -f $GITHUBUSER bump_$VERSION
Repeat step 6 to tag the code, publish new binaries, announce availability, and
get help testing.
-### 8. Finalize the bump branch
+### 9. Finalize the bump branch
When you're happy with the quality of a release candidate, you can move on and
create the real thing.
@@ -285,9 +295,9 @@ git commit --amend
You will then repeat step 6 to publish the binaries to test
-### 9. Get 2 other maintainers to validate the pull request
+### 10. Get 2 other maintainers to validate the pull request
-### 10. Publish final binaries
+### 11. Publish final binaries
Once they're tested and reasonably believed to be working, run against
get.docker.com:
@@ -303,7 +313,7 @@ docker run \
hack/release.sh
```
-### 9. Apply tag
+### 12. Apply tag
It's very important that we don't make the tag until after the official
release is uploaded to get.docker.com!
@@ -313,12 +323,12 @@ git tag -a $VERSION -m $VERSION bump_$VERSION
git push origin $VERSION
```
-### 10. Go to github to merge the `bump_$VERSION` branch into release
+### 13. Go to github to merge the `bump_$VERSION` branch into release
Don't forget to push that pretty blue button to delete the leftover
branch afterwards!
-### 11. Update the docs branch
+### 14. Update the docs branch
If this is a MAJOR.MINOR.0 release, you need to make an branch for the previous release's
documentation:
@@ -341,7 +351,7 @@ git push -f origin docs
make AWS_S3_BUCKET=docs.docker.com BUILD_ROOT=yes DISTRIBUTION_ID=C2K6......FL2F docs-release
```
-The docs will appear on http://docs.docker.com/ (though there may be cached
+The docs will appear on https://docs.docker.com/ (though there may be cached
versions, so its worth checking http://docs.docker.com.s3-website-us-east-1.amazonaws.com/).
For more information about documentation releases, see `docs/README.md`.
@@ -350,7 +360,7 @@ distributed CDN system) is flushed. The `make docs-release` command will do this
_if_ the `DISTRIBUTION_ID` is set correctly - this will take at least 15 minutes to run
and you can check its progress with the CDN Cloudfront Chrome addin.
-### 12. Create a new pull request to merge your bump commit back into master
+### 15. Create a new pull request to merge your bump commit back into master
```bash
git checkout master
@@ -364,17 +374,14 @@ echo "https://github.com/$GITHUBUSER/docker/compare/docker:master...$GITHUBUSER:
Again, get two maintainers to validate, then merge, then push that pretty
blue button to delete your branch.
-### 13. Update the API docs and VERSION files
+### 16. Update the VERSION files
Now that version X.Y.Z is out, time to start working on the next! Update the
content of the `VERSION` file to be the next minor (incrementing Y) and add the
`-dev` suffix. For example, after 1.5.0 release, the `VERSION` file gets
updated to `1.6.0-dev` (as in "1.6.0 in the making").
-Also create a new entry in `docs/sources/reference/api/` by copying the latest
-and bumping the version number (in both the file's name and content).
-
-### 14. Rejoice and Evangelize!
+### 17. Rejoice and Evangelize!
Congratulations! You're done.
diff --git a/project/TOOLS.md b/project/TOOLS.md
index f057ccd2befd9..79bd28374d244 100644
--- a/project/TOOLS.md
+++ b/project/TOOLS.md
@@ -14,11 +14,11 @@ we run Docker in Docker to test.
Leeroy is a Go application which integrates Jenkins with
GitHub pull requests. Leeroy uses
-[GitHub hooks](http://developer.github.com/v3/repos/hooks/)
+[GitHub hooks](https://developer.github.com/v3/repos/hooks/)
to listen for pull request notifications and starts jobs on your Jenkins
server. Using the Jenkins [notification plugin][jnp], Leeroy updates the
pull request using GitHub's
-[status API](http://developer.github.com/v3/repos/statuses/)
+[status API](https://developer.github.com/v3/repos/statuses/)
with pending, success, failure, or error statuses.
The leeroy repository is maintained at
diff --git a/registry/auth.go b/registry/auth.go
index 51b781dd92a81..1ac1ca984e3da 100644
--- a/registry/auth.go
+++ b/registry/auth.go
@@ -1,46 +1,21 @@
package registry
import (
- "encoding/base64"
"encoding/json"
- "errors"
"fmt"
"io/ioutil"
"net/http"
- "os"
- "path"
"strings"
"sync"
"time"
"github.com/Sirupsen/logrus"
+ "github.com/docker/docker/cliconfig"
"github.com/docker/docker/pkg/requestdecorator"
)
-const (
- // Where we store the config file
- CONFIGFILE = ".dockercfg"
-)
-
-var (
- ErrConfigFileMissing = errors.New("The Auth config file is missing")
-)
-
-type AuthConfig struct {
- Username string `json:"username,omitempty"`
- Password string `json:"password,omitempty"`
- Auth string `json:"auth"`
- Email string `json:"email"`
- ServerAddress string `json:"serveraddress,omitempty"`
-}
-
-type ConfigFile struct {
- Configs map[string]AuthConfig `json:"configs,omitempty"`
- rootPath string
-}
-
type RequestAuthorization struct {
- authConfig *AuthConfig
+ authConfig *cliconfig.AuthConfig
registryEndpoint *Endpoint
resource string
scope string
@@ -51,7 +26,7 @@ type RequestAuthorization struct {
tokenExpiration time.Time
}
-func NewRequestAuthorization(authConfig *AuthConfig, registryEndpoint *Endpoint, resource, scope string, actions []string) *RequestAuthorization {
+func NewRequestAuthorization(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint, resource, scope string, actions []string) *RequestAuthorization {
return &RequestAuthorization{
authConfig: authConfig,
registryEndpoint: registryEndpoint,
@@ -116,116 +91,8 @@ func (auth *RequestAuthorization) Authorize(req *http.Request) error {
return nil
}
-// create a base64 encoded auth string to store in config
-func encodeAuth(authConfig *AuthConfig) string {
- authStr := authConfig.Username + ":" + authConfig.Password
- msg := []byte(authStr)
- encoded := make([]byte, base64.StdEncoding.EncodedLen(len(msg)))
- base64.StdEncoding.Encode(encoded, msg)
- return string(encoded)
-}
-
-// decode the auth string
-func decodeAuth(authStr string) (string, string, error) {
- decLen := base64.StdEncoding.DecodedLen(len(authStr))
- decoded := make([]byte, decLen)
- authByte := []byte(authStr)
- n, err := base64.StdEncoding.Decode(decoded, authByte)
- if err != nil {
- return "", "", err
- }
- if n > decLen {
- return "", "", fmt.Errorf("Something went wrong decoding auth config")
- }
- arr := strings.SplitN(string(decoded), ":", 2)
- if len(arr) != 2 {
- return "", "", fmt.Errorf("Invalid auth configuration file")
- }
- password := strings.Trim(arr[1], "\x00")
- return arr[0], password, nil
-}
-
-// load up the auth config information and return values
-// FIXME: use the internal golang config parser
-func LoadConfig(rootPath string) (*ConfigFile, error) {
- configFile := ConfigFile{Configs: make(map[string]AuthConfig), rootPath: rootPath}
- confFile := path.Join(rootPath, CONFIGFILE)
- if _, err := os.Stat(confFile); err != nil {
- return &configFile, nil //missing file is not an error
- }
- b, err := ioutil.ReadFile(confFile)
- if err != nil {
- return &configFile, err
- }
-
- if err := json.Unmarshal(b, &configFile.Configs); err != nil {
- arr := strings.Split(string(b), "\n")
- if len(arr) < 2 {
- return &configFile, fmt.Errorf("The Auth config file is empty")
- }
- authConfig := AuthConfig{}
- origAuth := strings.Split(arr[0], " = ")
- if len(origAuth) != 2 {
- return &configFile, fmt.Errorf("Invalid Auth config file")
- }
- authConfig.Username, authConfig.Password, err = decodeAuth(origAuth[1])
- if err != nil {
- return &configFile, err
- }
- origEmail := strings.Split(arr[1], " = ")
- if len(origEmail) != 2 {
- return &configFile, fmt.Errorf("Invalid Auth config file")
- }
- authConfig.Email = origEmail[1]
- authConfig.ServerAddress = IndexServerAddress()
- // *TODO: Switch to using IndexServerName() instead?
- configFile.Configs[IndexServerAddress()] = authConfig
- } else {
- for k, authConfig := range configFile.Configs {
- authConfig.Username, authConfig.Password, err = decodeAuth(authConfig.Auth)
- if err != nil {
- return &configFile, err
- }
- authConfig.Auth = ""
- authConfig.ServerAddress = k
- configFile.Configs[k] = authConfig
- }
- }
- return &configFile, nil
-}
-
-// save the auth config
-func SaveConfig(configFile *ConfigFile) error {
- confFile := path.Join(configFile.rootPath, CONFIGFILE)
- if len(configFile.Configs) == 0 {
- os.Remove(confFile)
- return nil
- }
-
- configs := make(map[string]AuthConfig, len(configFile.Configs))
- for k, authConfig := range configFile.Configs {
- authCopy := authConfig
-
- authCopy.Auth = encodeAuth(&authCopy)
- authCopy.Username = ""
- authCopy.Password = ""
- authCopy.ServerAddress = ""
- configs[k] = authCopy
- }
-
- b, err := json.MarshalIndent(configs, "", "\t")
- if err != nil {
- return err
- }
- err = ioutil.WriteFile(confFile, b, 0600)
- if err != nil {
- return err
- }
- return nil
-}
-
// Login tries to register/login to the registry server.
-func Login(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *requestdecorator.RequestFactory) (string, error) {
+func Login(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint, factory *requestdecorator.RequestFactory) (string, error) {
// Separates the v2 registry login logic from the v1 logic.
if registryEndpoint.Version == APIVersion2 {
return loginV2(authConfig, registryEndpoint, factory)
@@ -234,7 +101,7 @@ func Login(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *requestd
}
// loginV1 tries to register/login to the v1 registry server.
-func loginV1(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *requestdecorator.RequestFactory) (string, error) {
+func loginV1(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint, factory *requestdecorator.RequestFactory) (string, error) {
var (
status string
reqBody []byte
@@ -347,7 +214,7 @@ func loginV1(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *reques
// now, users should create their account through other means like directly from a web page
// served by the v2 registry service provider. Whether this will be supported in the future
// is to be determined.
-func loginV2(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *requestdecorator.RequestFactory) (string, error) {
+func loginV2(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint, factory *requestdecorator.RequestFactory) (string, error) {
logrus.Debugf("attempting v2 login to registry endpoint %s", registryEndpoint)
var (
err error
@@ -380,7 +247,7 @@ func loginV2(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *reques
return "", fmt.Errorf("no successful auth challenge for %s - errors: %s", registryEndpoint, allErrors)
}
-func tryV2BasicAuthLogin(authConfig *AuthConfig, params map[string]string, registryEndpoint *Endpoint, client *http.Client, factory *requestdecorator.RequestFactory) error {
+func tryV2BasicAuthLogin(authConfig *cliconfig.AuthConfig, params map[string]string, registryEndpoint *Endpoint, client *http.Client, factory *requestdecorator.RequestFactory) error {
req, err := factory.NewRequest("GET", registryEndpoint.Path(""), nil)
if err != nil {
return err
@@ -401,7 +268,7 @@ func tryV2BasicAuthLogin(authConfig *AuthConfig, params map[string]string, regis
return nil
}
-func tryV2TokenAuthLogin(authConfig *AuthConfig, params map[string]string, registryEndpoint *Endpoint, client *http.Client, factory *requestdecorator.RequestFactory) error {
+func tryV2TokenAuthLogin(authConfig *cliconfig.AuthConfig, params map[string]string, registryEndpoint *Endpoint, client *http.Client, factory *requestdecorator.RequestFactory) error {
token, err := getToken(authConfig.Username, authConfig.Password, params, registryEndpoint, client, factory)
if err != nil {
return err
@@ -428,10 +295,10 @@ func tryV2TokenAuthLogin(authConfig *AuthConfig, params map[string]string, regis
}
// this method matches a auth configuration to a server address or a url
-func (config *ConfigFile) ResolveAuthConfig(index *IndexInfo) AuthConfig {
+func ResolveAuthConfig(config *cliconfig.ConfigFile, index *IndexInfo) cliconfig.AuthConfig {
configKey := index.GetAuthConfigKey()
// First try the happy case
- if c, found := config.Configs[configKey]; found || index.Official {
+ if c, found := config.AuthConfigs[configKey]; found || index.Official {
return c
}
@@ -450,12 +317,12 @@ func (config *ConfigFile) ResolveAuthConfig(index *IndexInfo) AuthConfig {
// Maybe they have a legacy config file, we will iterate the keys converting
// them to the new format and testing
- for registry, config := range config.Configs {
+ for registry, ac := range config.AuthConfigs {
if configKey == convertToHostname(registry) {
- return config
+ return ac
}
}
// When all else fails, return an empty auth config
- return AuthConfig{}
+ return cliconfig.AuthConfig{}
}
diff --git a/registry/auth_test.go b/registry/auth_test.go
index 9cc299aabe958..71b963a1f1ee7 100644
--- a/registry/auth_test.go
+++ b/registry/auth_test.go
@@ -3,15 +3,18 @@ package registry
import (
"io/ioutil"
"os"
+ "path/filepath"
"testing"
+
+ "github.com/docker/docker/cliconfig"
)
func TestEncodeAuth(t *testing.T) {
- newAuthConfig := &AuthConfig{Username: "ken", Password: "test", Email: "test@example.com"}
- authStr := encodeAuth(newAuthConfig)
- decAuthConfig := &AuthConfig{}
+ newAuthConfig := &cliconfig.AuthConfig{Username: "ken", Password: "test", Email: "test@example.com"}
+ authStr := cliconfig.EncodeAuth(newAuthConfig)
+ decAuthConfig := &cliconfig.AuthConfig{}
var err error
- decAuthConfig.Username, decAuthConfig.Password, err = decodeAuth(authStr)
+ decAuthConfig.Username, decAuthConfig.Password, err = cliconfig.DecodeAuth(authStr)
if err != nil {
t.Fatal(err)
}
@@ -26,18 +29,16 @@ func TestEncodeAuth(t *testing.T) {
}
}
-func setupTempConfigFile() (*ConfigFile, error) {
+func setupTempConfigFile() (*cliconfig.ConfigFile, error) {
root, err := ioutil.TempDir("", "docker-test-auth")
if err != nil {
return nil, err
}
- configFile := &ConfigFile{
- rootPath: root,
- Configs: make(map[string]AuthConfig),
- }
+ root = filepath.Join(root, cliconfig.CONFIGFILE)
+ configFile := cliconfig.NewConfigFile(root)
for _, registry := range []string{"testIndex", IndexServerAddress()} {
- configFile.Configs[registry] = AuthConfig{
+ configFile.AuthConfigs[registry] = cliconfig.AuthConfig{
Username: "docker-user",
Password: "docker-pass",
Email: "docker@docker.io",
@@ -52,14 +53,14 @@ func TestSameAuthDataPostSave(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- defer os.RemoveAll(configFile.rootPath)
+ defer os.RemoveAll(configFile.Filename())
- err = SaveConfig(configFile)
+ err = configFile.Save()
if err != nil {
t.Fatal(err)
}
- authConfig := configFile.Configs["testIndex"]
+ authConfig := configFile.AuthConfigs["testIndex"]
if authConfig.Username != "docker-user" {
t.Fail()
}
@@ -79,9 +80,9 @@ func TestResolveAuthConfigIndexServer(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- defer os.RemoveAll(configFile.rootPath)
+ defer os.RemoveAll(configFile.Filename())
- indexConfig := configFile.Configs[IndexServerAddress()]
+ indexConfig := configFile.AuthConfigs[IndexServerAddress()]
officialIndex := &IndexInfo{
Official: true,
@@ -90,10 +91,10 @@ func TestResolveAuthConfigIndexServer(t *testing.T) {
Official: false,
}
- resolved := configFile.ResolveAuthConfig(officialIndex)
+ resolved := ResolveAuthConfig(configFile, officialIndex)
assertEqual(t, resolved, indexConfig, "Expected ResolveAuthConfig to return IndexServerAddress()")
- resolved = configFile.ResolveAuthConfig(privateIndex)
+ resolved = ResolveAuthConfig(configFile, privateIndex)
assertNotEqual(t, resolved, indexConfig, "Expected ResolveAuthConfig to not return IndexServerAddress()")
}
@@ -102,26 +103,26 @@ func TestResolveAuthConfigFullURL(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- defer os.RemoveAll(configFile.rootPath)
+ defer os.RemoveAll(configFile.Filename())
- registryAuth := AuthConfig{
+ registryAuth := cliconfig.AuthConfig{
Username: "foo-user",
Password: "foo-pass",
Email: "foo@example.com",
}
- localAuth := AuthConfig{
+ localAuth := cliconfig.AuthConfig{
Username: "bar-user",
Password: "bar-pass",
Email: "bar@example.com",
}
- officialAuth := AuthConfig{
+ officialAuth := cliconfig.AuthConfig{
Username: "baz-user",
Password: "baz-pass",
Email: "baz@example.com",
}
- configFile.Configs[IndexServerAddress()] = officialAuth
+ configFile.AuthConfigs[IndexServerAddress()] = officialAuth
- expectedAuths := map[string]AuthConfig{
+ expectedAuths := map[string]cliconfig.AuthConfig{
"registry.example.com": registryAuth,
"localhost:8000": localAuth,
"registry.com": localAuth,
@@ -157,13 +158,13 @@ func TestResolveAuthConfigFullURL(t *testing.T) {
Name: configKey,
}
for _, registry := range registries {
- configFile.Configs[registry] = configured
- resolved := configFile.ResolveAuthConfig(index)
+ configFile.AuthConfigs[registry] = configured
+ resolved := ResolveAuthConfig(configFile, index)
if resolved.Email != configured.Email {
t.Errorf("%s -> %q != %q\n", registry, resolved.Email, configured.Email)
}
- delete(configFile.Configs, registry)
- resolved = configFile.ResolveAuthConfig(index)
+ delete(configFile.AuthConfigs, registry)
+ resolved = ResolveAuthConfig(configFile, index)
if resolved.Email == configured.Email {
t.Errorf("%s -> %q == %q\n", registry, resolved.Email, configured.Email)
}
diff --git a/registry/config.go b/registry/config.go
index 3515836d187af..a0a978cc72832 100644
--- a/registry/config.go
+++ b/registry/config.go
@@ -9,9 +9,9 @@ import (
"regexp"
"strings"
+ "github.com/docker/docker/image"
"github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag"
- "github.com/docker/docker/utils"
)
// Options holds command line options.
@@ -213,7 +213,7 @@ func validateRemoteName(remoteName string) error {
name = nameParts[0]
// the repository name must not be a valid image ID
- if err := utils.ValidateID(name); err == nil {
+ if err := image.ValidateID(name); err == nil {
return fmt.Errorf("Invalid repository name (%s), cannot specify 64-byte hexadecimal strings", name)
}
} else {
diff --git a/registry/endpoint.go b/registry/endpoint.go
index 69a718e12f5c9..84b11a987bda8 100644
--- a/registry/endpoint.go
+++ b/registry/endpoint.go
@@ -11,8 +11,8 @@ import (
"strings"
"github.com/Sirupsen/logrus"
+ "github.com/docker/distribution/registry/api/v2"
"github.com/docker/docker/pkg/requestdecorator"
- "github.com/docker/docker/registry/v2"
)
// for mocking in unit tests
diff --git a/registry/registry_test.go b/registry/registry_test.go
index a066de9f8e6ea..3f63eb6e257fa 100644
--- a/registry/registry_test.go
+++ b/registry/registry_test.go
@@ -7,6 +7,7 @@ import (
"strings"
"testing"
+ "github.com/docker/docker/cliconfig"
"github.com/docker/docker/pkg/requestdecorator"
)
@@ -20,7 +21,7 @@ const (
)
func spawnTestRegistrySession(t *testing.T) *Session {
- authConfig := &AuthConfig{}
+ authConfig := &cliconfig.AuthConfig{}
endpoint, err := NewEndpoint(makeIndex("/v1/"))
if err != nil {
t.Fatal(err)
@@ -33,7 +34,7 @@ func spawnTestRegistrySession(t *testing.T) *Session {
}
func TestPublicSession(t *testing.T) {
- authConfig := &AuthConfig{}
+ authConfig := &cliconfig.AuthConfig{}
getSessionDecorators := func(index *IndexInfo) int {
endpoint, err := NewEndpoint(index)
@@ -735,7 +736,7 @@ func TestSearchRepositories(t *testing.T) {
}
assertEqual(t, results.NumResults, 1, "Expected 1 search results")
assertEqual(t, results.Query, "fakequery", "Expected 'fakequery' as query")
- assertEqual(t, results.Results[0].StarCount, 42, "Expected 'fakeimage' a ot hae 42 stars")
+ assertEqual(t, results.Results[0].StarCount, 42, "Expected 'fakeimage' to have 42 stars")
}
func TestValidRemoteName(t *testing.T) {
diff --git a/registry/service.go b/registry/service.go
index cf29732f4903c..87fc1d076f621 100644
--- a/registry/service.go
+++ b/registry/service.go
@@ -1,5 +1,7 @@
package registry
+import "github.com/docker/docker/cliconfig"
+
type Service struct {
Config *ServiceConfig
}
@@ -15,7 +17,7 @@ func NewService(options *Options) *Service {
// Auth contacts the public registry with the provided credentials,
// and returns OK if authentication was sucessful.
// It can be used to verify the validity of a client's credentials.
-func (s *Service) Auth(authConfig *AuthConfig) (string, error) {
+func (s *Service) Auth(authConfig *cliconfig.AuthConfig) (string, error) {
addr := authConfig.ServerAddress
if addr == "" {
// Use the official registry address if not specified.
@@ -35,7 +37,7 @@ func (s *Service) Auth(authConfig *AuthConfig) (string, error) {
// Search queries the public registry for images matching the specified
// search terms, and returns the results.
-func (s *Service) Search(term string, authConfig *AuthConfig, headers map[string][]string) (*SearchResults, error) {
+func (s *Service) Search(term string, authConfig *cliconfig.AuthConfig, headers map[string][]string) (*SearchResults, error) {
repoInfo, err := s.ResolveRepository(term)
if err != nil {
return nil, err
diff --git a/registry/session.go b/registry/session.go
index 4682a5074cd15..e65f82cd6103e 100644
--- a/registry/session.go
+++ b/registry/session.go
@@ -18,21 +18,21 @@ import (
"time"
"github.com/Sirupsen/logrus"
+ "github.com/docker/docker/cliconfig"
"github.com/docker/docker/pkg/httputils"
"github.com/docker/docker/pkg/requestdecorator"
"github.com/docker/docker/pkg/tarsum"
- "github.com/docker/docker/utils"
)
type Session struct {
- authConfig *AuthConfig
+ authConfig *cliconfig.AuthConfig
reqFactory *requestdecorator.RequestFactory
indexEndpoint *Endpoint
jar *cookiejar.Jar
timeout TimeoutType
}
-func NewSession(authConfig *AuthConfig, factory *requestdecorator.RequestFactory, endpoint *Endpoint, timeout bool) (r *Session, err error) {
+func NewSession(authConfig *cliconfig.AuthConfig, factory *requestdecorator.RequestFactory, endpoint *Endpoint, timeout bool) (r *Session, err error) {
r = &Session{
authConfig: authConfig,
indexEndpoint: endpoint,
@@ -54,7 +54,7 @@ func NewSession(authConfig *AuthConfig, factory *requestdecorator.RequestFactory
if err != nil {
return nil, err
}
- if info.Standalone {
+ if info.Standalone && authConfig != nil && factory != nil {
logrus.Debugf("Endpoint %s is eligible for private registry. Enabling decorator.", r.indexEndpoint.String())
dec := requestdecorator.NewAuthDecorator(authConfig.Username, authConfig.Password)
factory.AddDecorator(dec)
@@ -86,7 +86,7 @@ func (r *Session) GetRemoteHistory(imgID, registry string, token []string) ([]st
if res.StatusCode == 401 {
return nil, errLoginRequired
}
- return nil, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch remote history for %s", res.StatusCode, imgID), res)
+ return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch remote history for %s", res.StatusCode, imgID), res)
}
jsonString, err := ioutil.ReadAll(res.Body)
@@ -115,7 +115,7 @@ func (r *Session) LookupRemoteImage(imgID, registry string, token []string) erro
}
res.Body.Close()
if res.StatusCode != 200 {
- return utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d", res.StatusCode), res)
+ return httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d", res.StatusCode), res)
}
return nil
}
@@ -134,7 +134,7 @@ func (r *Session) GetRemoteImageJSON(imgID, registry string, token []string) ([]
}
defer res.Body.Close()
if res.StatusCode != 200 {
- return nil, -1, utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d", res.StatusCode), res)
+ return nil, -1, httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d", res.StatusCode), res)
}
// if the size header is not present, then set it to '-1'
imageSize := -1
@@ -223,11 +223,12 @@ func (r *Session) GetRemoteTags(registries []string, repository string, token []
logrus.Debugf("Got status code %d from %s", res.StatusCode, endpoint)
defer res.Body.Close()
- if res.StatusCode != 200 && res.StatusCode != 404 {
- continue
- } else if res.StatusCode == 404 {
+ if res.StatusCode == 404 {
return nil, fmt.Errorf("Repository not found")
}
+ if res.StatusCode != 200 {
+ continue
+ }
result := make(map[string]string)
if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
@@ -282,13 +283,13 @@ func (r *Session) GetRepositoryData(remote string) (*RepositoryData, error) {
// TODO: Right now we're ignoring checksums in the response body.
// In the future, we need to use them to check image validity.
if res.StatusCode == 404 {
- return nil, utils.NewHTTPRequestError(fmt.Sprintf("HTTP code: %d", res.StatusCode), res)
+ return nil, httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code: %d", res.StatusCode), res)
} else if res.StatusCode != 200 {
errBody, err := ioutil.ReadAll(res.Body)
if err != nil {
logrus.Debugf("Error reading response body: %s", err)
}
- return nil, utils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to pull repository %s: %q", res.StatusCode, remote, errBody), res)
+ return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to pull repository %s: %q", res.StatusCode, remote, errBody), res)
}
var tokens []string
@@ -379,12 +380,12 @@ func (r *Session) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regist
}
defer res.Body.Close()
if res.StatusCode == 401 && strings.HasPrefix(registry, "http://") {
- return utils.NewHTTPRequestError("HTTP code 401, Docker will not send auth headers over HTTP.", res)
+ return httputils.NewHTTPRequestError("HTTP code 401, Docker will not send auth headers over HTTP.", res)
}
if res.StatusCode != 200 {
errBody, err := ioutil.ReadAll(res.Body)
if err != nil {
- return utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res)
+ return httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res)
}
var jsonBody map[string]string
if err := json.Unmarshal(errBody, &jsonBody); err != nil {
@@ -392,7 +393,7 @@ func (r *Session) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regist
} else if jsonBody["error"] == "Image already exists" {
return ErrAlreadyExists
}
- return utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata: %q", res.StatusCode, errBody), res)
+ return httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata: %q", res.StatusCode, errBody), res)
}
return nil
}
@@ -432,9 +433,9 @@ func (r *Session) PushImageLayerRegistry(imgID string, layer io.Reader, registry
if res.StatusCode != 200 {
errBody, err := ioutil.ReadAll(res.Body)
if err != nil {
- return "", "", utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res)
+ return "", "", httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res)
}
- return "", "", utils.NewHTTPRequestError(fmt.Sprintf("Received HTTP code %d while uploading layer: %q", res.StatusCode, errBody), res)
+ return "", "", httputils.NewHTTPRequestError(fmt.Sprintf("Received HTTP code %d while uploading layer: %q", res.StatusCode, errBody), res)
}
checksumPayload = "sha256:" + hex.EncodeToString(h.Sum(nil))
@@ -461,7 +462,7 @@ func (r *Session) PushRegistryTag(remote, revision, tag, registry string, token
}
res.Body.Close()
if res.StatusCode != 200 && res.StatusCode != 201 {
- return utils.NewHTTPRequestError(fmt.Sprintf("Internal server error: %d trying to push tag %s on %s", res.StatusCode, tag, remote), res)
+ return httputils.NewHTTPRequestError(fmt.Sprintf("Internal server error: %d trying to push tag %s on %s", res.StatusCode, tag, remote), res)
}
return nil
}
@@ -523,23 +524,21 @@ func (r *Session) PushImageJSONIndex(remote string, imgList []*ImgData, validate
if err != nil {
logrus.Debugf("Error reading response body: %s", err)
}
- return nil, utils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push repository %s: %q", res.StatusCode, remote, errBody), res)
+ return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push repository %s: %q", res.StatusCode, remote, errBody), res)
}
- if res.Header.Get("X-Docker-Token") != "" {
- tokens = res.Header["X-Docker-Token"]
- logrus.Debugf("Auth token: %v", tokens)
- } else {
+ if res.Header.Get("X-Docker-Token") == "" {
return nil, fmt.Errorf("Index response didn't contain an access token")
}
+ tokens = res.Header["X-Docker-Token"]
+ logrus.Debugf("Auth token: %v", tokens)
- if res.Header.Get("X-Docker-Endpoints") != "" {
- endpoints, err = buildEndpointsList(res.Header["X-Docker-Endpoints"], r.indexEndpoint.VersionString(1))
- if err != nil {
- return nil, err
- }
- } else {
+ if res.Header.Get("X-Docker-Endpoints") == "" {
return nil, fmt.Errorf("Index response didn't contain any endpoints")
}
+ endpoints, err = buildEndpointsList(res.Header["X-Docker-Endpoints"], r.indexEndpoint.VersionString(1))
+ if err != nil {
+ return nil, err
+ }
}
if validate {
if res.StatusCode != 204 {
@@ -547,7 +546,7 @@ func (r *Session) PushImageJSONIndex(remote string, imgList []*ImgData, validate
if err != nil {
logrus.Debugf("Error reading response body: %s", err)
}
- return nil, utils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push checksums %s: %q", res.StatusCode, remote, errBody), res)
+ return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push checksums %s: %q", res.StatusCode, remote, errBody), res)
}
}
@@ -595,19 +594,18 @@ func (r *Session) SearchRepositories(term string) (*SearchResults, error) {
}
defer res.Body.Close()
if res.StatusCode != 200 {
- return nil, utils.NewHTTPRequestError(fmt.Sprintf("Unexpected status code %d", res.StatusCode), res)
+ return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Unexpected status code %d", res.StatusCode), res)
}
result := new(SearchResults)
- err = json.NewDecoder(res.Body).Decode(result)
- return result, err
+ return result, json.NewDecoder(res.Body).Decode(result)
}
-func (r *Session) GetAuthConfig(withPasswd bool) *AuthConfig {
+func (r *Session) GetAuthConfig(withPasswd bool) *cliconfig.AuthConfig {
password := ""
if withPasswd {
password = r.authConfig.Password
}
- return &AuthConfig{
+ return &cliconfig.AuthConfig{
Username: r.authConfig.Username,
Password: password,
Email: r.authConfig.Email,
diff --git a/registry/session_v2.go b/registry/session_v2.go
index a01c8b9ab2441..4188e505bda51 100644
--- a/registry/session_v2.go
+++ b/registry/session_v2.go
@@ -11,8 +11,8 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/distribution/digest"
- "github.com/docker/docker/registry/v2"
- "github.com/docker/docker/utils"
+ "github.com/docker/distribution/registry/api/v2"
+ "github.com/docker/docker/pkg/httputils"
)
const DockerDigestHeader = "Docker-Content-Digest"
@@ -95,7 +95,7 @@ func (r *Session) GetV2ImageManifest(ep *Endpoint, imageName, tagName string, au
} else if res.StatusCode == 404 {
return nil, "", ErrDoesNotExist
}
- return nil, "", utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch for %s:%s", res.StatusCode, imageName, tagName), res)
+ return nil, "", httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch for %s:%s", res.StatusCode, imageName, tagName), res)
}
manifestBytes, err := ioutil.ReadAll(res.Body)
@@ -109,8 +109,8 @@ func (r *Session) GetV2ImageManifest(ep *Endpoint, imageName, tagName string, au
// - Succeeded to head image blob (already exists)
// - Failed with no error (continue to Push the Blob)
// - Failed with error
-func (r *Session) HeadV2ImageBlob(ep *Endpoint, imageName, sumType, sum string, auth *RequestAuthorization) (bool, error) {
- routeURL, err := getV2Builder(ep).BuildBlobURL(imageName, sumType+":"+sum)
+func (r *Session) HeadV2ImageBlob(ep *Endpoint, imageName string, dgst digest.Digest, auth *RequestAuthorization) (bool, error) {
+ routeURL, err := getV2Builder(ep).BuildBlobURL(imageName, dgst)
if err != nil {
return false, err
}
@@ -141,11 +141,11 @@ func (r *Session) HeadV2ImageBlob(ep *Endpoint, imageName, sumType, sum string,
return false, nil
}
- return false, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying head request for %s - %s:%s", res.StatusCode, imageName, sumType, sum), res)
+ return false, httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying head request for %s - %s", res.StatusCode, imageName, dgst), res)
}
-func (r *Session) GetV2ImageBlob(ep *Endpoint, imageName, sumType, sum string, blobWrtr io.Writer, auth *RequestAuthorization) error {
- routeURL, err := getV2Builder(ep).BuildBlobURL(imageName, sumType+":"+sum)
+func (r *Session) GetV2ImageBlob(ep *Endpoint, imageName string, dgst digest.Digest, blobWrtr io.Writer, auth *RequestAuthorization) error {
+ routeURL, err := getV2Builder(ep).BuildBlobURL(imageName, dgst)
if err != nil {
return err
}
@@ -168,15 +168,15 @@ func (r *Session) GetV2ImageBlob(ep *Endpoint, imageName, sumType, sum string, b
if res.StatusCode == 401 {
return errLoginRequired
}
- return utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to pull %s blob", res.StatusCode, imageName), res)
+ return httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to pull %s blob", res.StatusCode, imageName), res)
}
_, err = io.Copy(blobWrtr, res.Body)
return err
}
-func (r *Session) GetV2ImageBlobReader(ep *Endpoint, imageName, sumType, sum string, auth *RequestAuthorization) (io.ReadCloser, int64, error) {
- routeURL, err := getV2Builder(ep).BuildBlobURL(imageName, sumType+":"+sum)
+func (r *Session) GetV2ImageBlobReader(ep *Endpoint, imageName string, dgst digest.Digest, auth *RequestAuthorization) (io.ReadCloser, int64, error) {
+ routeURL, err := getV2Builder(ep).BuildBlobURL(imageName, dgst)
if err != nil {
return nil, 0, err
}
@@ -198,7 +198,7 @@ func (r *Session) GetV2ImageBlobReader(ep *Endpoint, imageName, sumType, sum str
if res.StatusCode == 401 {
return nil, 0, errLoginRequired
}
- return nil, 0, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to pull %s blob - %s:%s", res.StatusCode, imageName, sumType, sum), res)
+ return nil, 0, httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to pull %s blob - %s", res.StatusCode, imageName, dgst), res)
}
lenStr := res.Header.Get("Content-Length")
l, err := strconv.ParseInt(lenStr, 10, 64)
@@ -212,7 +212,7 @@ func (r *Session) GetV2ImageBlobReader(ep *Endpoint, imageName, sumType, sum str
// Push the image to the server for storage.
// 'layer' is an uncompressed reader of the blob to be pushed.
// The server will generate it's own checksum calculation.
-func (r *Session) PutV2ImageBlob(ep *Endpoint, imageName, sumType, sumStr string, blobRdr io.Reader, auth *RequestAuthorization) error {
+func (r *Session) PutV2ImageBlob(ep *Endpoint, imageName string, dgst digest.Digest, blobRdr io.Reader, auth *RequestAuthorization) error {
location, err := r.initiateBlobUpload(ep, imageName, auth)
if err != nil {
return err
@@ -225,7 +225,7 @@ func (r *Session) PutV2ImageBlob(ep *Endpoint, imageName, sumType, sumStr string
return err
}
queryParams := req.URL.Query()
- queryParams.Add("digest", sumType+":"+sumStr)
+ queryParams.Add("digest", dgst.String())
req.URL.RawQuery = queryParams.Encode()
if err := auth.Authorize(req); err != nil {
return err
@@ -245,7 +245,7 @@ func (r *Session) PutV2ImageBlob(ep *Endpoint, imageName, sumType, sumStr string
return err
}
logrus.Debugf("Unexpected response from server: %q %#v", errBody, res.Header)
- return utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s blob - %s:%s", res.StatusCode, imageName, sumType, sumStr), res)
+ return httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s blob - %s", res.StatusCode, imageName, dgst), res)
}
return nil
@@ -286,7 +286,7 @@ func (r *Session) initiateBlobUpload(ep *Endpoint, imageName string, auth *Reque
}
logrus.Debugf("Unexpected response from server: %q %#v", errBody, res.Header)
- return "", utils.NewHTTPRequestError(fmt.Sprintf("Server error: unexpected %d response status trying to initiate upload of %s", res.StatusCode, imageName), res)
+ return "", httputils.NewHTTPRequestError(fmt.Sprintf("Server error: unexpected %d response status trying to initiate upload of %s", res.StatusCode, imageName), res)
}
if location = res.Header.Get("Location"); location == "" {
@@ -328,7 +328,7 @@ func (r *Session) PutV2ImageManifest(ep *Endpoint, imageName, tagName string, si
return "", err
}
logrus.Debugf("Unexpected response from server: %q %#v", errBody, res.Header)
- return "", utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s:%s manifest", res.StatusCode, imageName, tagName), res)
+ return "", httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s:%s manifest", res.StatusCode, imageName, tagName), res)
}
hdrDigest, err := digest.ParseDigest(res.Header.Get(DockerDigestHeader))
@@ -384,13 +384,11 @@ func (r *Session) GetV2RemoteTags(ep *Endpoint, imageName string, auth *RequestA
} else if res.StatusCode == 404 {
return nil, ErrDoesNotExist
}
- return nil, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch for %s", res.StatusCode, imageName), res)
+ return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch for %s", res.StatusCode, imageName), res)
}
- decoder := json.NewDecoder(res.Body)
var remote remoteTags
- err = decoder.Decode(&remote)
- if err != nil {
+ if err := json.NewDecoder(res.Body).Decode(&remote); err != nil {
return nil, fmt.Errorf("Error while decoding the http response: %s", err)
}
return remote.Tags, nil
diff --git a/registry/v2/descriptors.go b/registry/v2/descriptors.go
deleted file mode 100644
index 68d182411d9c1..0000000000000
--- a/registry/v2/descriptors.go
+++ /dev/null
@@ -1,144 +0,0 @@
-package v2
-
-import "net/http"
-
-// TODO(stevvooe): Add route descriptors for each named route, along with
-// accepted methods, parameters, returned status codes and error codes.
-
-// ErrorDescriptor provides relevant information about a given error code.
-type ErrorDescriptor struct {
- // Code is the error code that this descriptor describes.
- Code ErrorCode
-
- // Value provides a unique, string key, often captilized with
- // underscores, to identify the error code. This value is used as the
- // keyed value when serializing api errors.
- Value string
-
- // Message is a short, human readable decription of the error condition
- // included in API responses.
- Message string
-
- // Description provides a complete account of the errors purpose, suitable
- // for use in documentation.
- Description string
-
- // HTTPStatusCodes provides a list of status under which this error
- // condition may arise. If it is empty, the error condition may be seen
- // for any status code.
- HTTPStatusCodes []int
-}
-
-// ErrorDescriptors provides a list of HTTP API Error codes that may be
-// encountered when interacting with the registry API.
-var ErrorDescriptors = []ErrorDescriptor{
- {
- Code: ErrorCodeUnknown,
- Value: "UNKNOWN",
- Message: "unknown error",
- Description: `Generic error returned when the error does not have an
- API classification.`,
- },
- {
- Code: ErrorCodeDigestInvalid,
- Value: "DIGEST_INVALID",
- Message: "provided digest did not match uploaded content",
- Description: `When a blob is uploaded, the registry will check that
- the content matches the digest provided by the client. The error may
- include a detail structure with the key "digest", including the
- invalid digest string. This error may also be returned when a manifest
- includes an invalid layer digest.`,
- HTTPStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
- },
- {
- Code: ErrorCodeSizeInvalid,
- Value: "SIZE_INVALID",
- Message: "provided length did not match content length",
- Description: `When a layer is uploaded, the provided size will be
- checked against the uploaded content. If they do not match, this error
- will be returned.`,
- HTTPStatusCodes: []int{http.StatusBadRequest},
- },
- {
- Code: ErrorCodeNameInvalid,
- Value: "NAME_INVALID",
- Message: "manifest name did not match URI",
- Description: `During a manifest upload, if the name in the manifest
- does not match the uri name, this error will be returned.`,
- HTTPStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
- },
- {
- Code: ErrorCodeTagInvalid,
- Value: "TAG_INVALID",
- Message: "manifest tag did not match URI",
- Description: `During a manifest upload, if the tag in the manifest
- does not match the uri tag, this error will be returned.`,
- HTTPStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
- },
- {
- Code: ErrorCodeNameUnknown,
- Value: "NAME_UNKNOWN",
- Message: "repository name not known to registry",
- Description: `This is returned if the name used during an operation is
- unknown to the registry.`,
- HTTPStatusCodes: []int{http.StatusNotFound},
- },
- {
- Code: ErrorCodeManifestUnknown,
- Value: "MANIFEST_UNKNOWN",
- Message: "manifest unknown",
- Description: `This error is returned when the manifest, identified by
- name and tag is unknown to the repository.`,
- HTTPStatusCodes: []int{http.StatusNotFound},
- },
- {
- Code: ErrorCodeManifestInvalid,
- Value: "MANIFEST_INVALID",
- Message: "manifest invalid",
- Description: `During upload, manifests undergo several checks ensuring
- validity. If those checks fail, this error may be returned, unless a
- more specific error is included. The detail will contain information
- the failed validation.`,
- HTTPStatusCodes: []int{http.StatusBadRequest},
- },
- {
- Code: ErrorCodeManifestUnverified,
- Value: "MANIFEST_UNVERIFIED",
- Message: "manifest failed signature verification",
- Description: `During manifest upload, if the manifest fails signature
- verification, this error will be returned.`,
- HTTPStatusCodes: []int{http.StatusBadRequest},
- },
- {
- Code: ErrorCodeBlobUnknown,
- Value: "BLOB_UNKNOWN",
- Message: "blob unknown to registry",
- Description: `This error may be returned when a blob is unknown to the
- registry in a specified repository. This can be returned with a
- standard get or if a manifest references an unknown layer during
- upload.`,
- HTTPStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
- },
-
- {
- Code: ErrorCodeBlobUploadUnknown,
- Value: "BLOB_UPLOAD_UNKNOWN",
- Message: "blob upload unknown to registry",
- Description: `If a blob upload has been cancelled or was never
- started, this error code may be returned.`,
- HTTPStatusCodes: []int{http.StatusNotFound},
- },
-}
-
-var errorCodeToDescriptors map[ErrorCode]ErrorDescriptor
-var idToDescriptors map[string]ErrorDescriptor
-
-func init() {
- errorCodeToDescriptors = make(map[ErrorCode]ErrorDescriptor, len(ErrorDescriptors))
- idToDescriptors = make(map[string]ErrorDescriptor, len(ErrorDescriptors))
-
- for _, descriptor := range ErrorDescriptors {
- errorCodeToDescriptors[descriptor.Code] = descriptor
- idToDescriptors[descriptor.Value] = descriptor
- }
-}
diff --git a/registry/v2/regexp.go b/registry/v2/regexp.go
deleted file mode 100644
index 07484dcd69538..0000000000000
--- a/registry/v2/regexp.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package v2
-
-import "regexp"
-
-// This file defines regular expressions for use in route definition. These
-// are also defined in the registry code base. Until they are in a common,
-// shared location, and exported, they must be repeated here.
-
-// RepositoryNameComponentRegexp restricts registtry path components names to
-// start with at least two letters or numbers, with following parts able to
-// separated by one period, dash or underscore.
-var RepositoryNameComponentRegexp = regexp.MustCompile(`[a-z0-9]+(?:[._-][a-z0-9]+)*`)
-
-// RepositoryNameRegexp builds on RepositoryNameComponentRegexp to allow 1 to
-// 5 path components, separated by a forward slash.
-var RepositoryNameRegexp = regexp.MustCompile(`(?:` + RepositoryNameComponentRegexp.String() + `/){0,4}` + RepositoryNameComponentRegexp.String())
-
-// TagNameRegexp matches valid tag names. From docker/docker:graph/tags.go.
-var TagNameRegexp = regexp.MustCompile(`[\w][\w.-]{0,127}`)
-
-// DigestRegexp matches valid digest types.
-var DigestRegexp = regexp.MustCompile(`[a-zA-Z0-9-_+.]+:[a-zA-Z0-9-_+.=]+`)
diff --git a/registry/v2/routes.go b/registry/v2/routes.go
deleted file mode 100644
index de0a38fb815a5..0000000000000
--- a/registry/v2/routes.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package v2
-
-import "github.com/gorilla/mux"
-
-// The following are definitions of the name under which all V2 routes are
-// registered. These symbols can be used to look up a route based on the name.
-const (
- RouteNameBase = "base"
- RouteNameManifest = "manifest"
- RouteNameTags = "tags"
- RouteNameBlob = "blob"
- RouteNameBlobUpload = "blob-upload"
- RouteNameBlobUploadChunk = "blob-upload-chunk"
-)
-
-var allEndpoints = []string{
- RouteNameManifest,
- RouteNameTags,
- RouteNameBlob,
- RouteNameBlobUpload,
- RouteNameBlobUploadChunk,
-}
-
-// Router builds a gorilla router with named routes for the various API
-// methods. This can be used directly by both server implementations and
-// clients.
-func Router() *mux.Router {
- router := mux.NewRouter().
- StrictSlash(true)
-
- // GET /v2/ Check Check that the registry implements API version 2(.1)
- router.
- Path("/v2/").
- Name(RouteNameBase)
-
- // GET /v2//manifest/ Image Manifest Fetch the image manifest identified by name and reference where reference can be a tag or digest.
- // PUT /v2//manifest/ Image Manifest Upload the image manifest identified by name and reference where reference can be a tag or digest.
- // DELETE /v2//manifest/ Image Manifest Delete the image identified by name and reference where reference can be a tag or digest.
- router.
- Path("/v2/{name:" + RepositoryNameRegexp.String() + "}/manifests/{reference:" + TagNameRegexp.String() + "|" + DigestRegexp.String() + "}").
- Name(RouteNameManifest)
-
- // GET /v2//tags/list Tags Fetch the tags under the repository identified by name.
- router.
- Path("/v2/{name:" + RepositoryNameRegexp.String() + "}/tags/list").
- Name(RouteNameTags)
-
- // GET /v2//blob/ Layer Fetch the blob identified by digest.
- router.
- Path("/v2/{name:" + RepositoryNameRegexp.String() + "}/blobs/{digest:[a-zA-Z0-9-_+.]+:[a-zA-Z0-9-_+.=]+}").
- Name(RouteNameBlob)
-
- // POST /v2//blob/upload/ Layer Upload Initiate an upload of the layer identified by tarsum.
- router.
- Path("/v2/{name:" + RepositoryNameRegexp.String() + "}/blobs/uploads/").
- Name(RouteNameBlobUpload)
-
- // GET /v2//blob/upload/ Layer Upload Get the status of the upload identified by tarsum and uuid.
- // PUT /v2//blob/upload/ Layer Upload Upload all or a chunk of the upload identified by tarsum and uuid.
- // DELETE /v2//blob/upload/ Layer Upload Cancel the upload identified by layer and uuid
- router.
- Path("/v2/{name:" + RepositoryNameRegexp.String() + "}/blobs/uploads/{uuid}").
- Name(RouteNameBlobUploadChunk)
-
- return router
-}
diff --git a/registry/v2/urls_test.go b/registry/v2/urls_test.go
deleted file mode 100644
index f30c96c0affdf..0000000000000
--- a/registry/v2/urls_test.go
+++ /dev/null
@@ -1,113 +0,0 @@
-package v2
-
-import (
- "net/url"
- "testing"
-)
-
-type urlBuilderTestCase struct {
- description string
- expectedPath string
- build func() (string, error)
-}
-
-// TestURLBuilder tests the various url building functions, ensuring they are
-// returning the expected values.
-func TestURLBuilder(t *testing.T) {
- var (
- urlBuilder *URLBuilder
- err error
- )
-
- testCases := []urlBuilderTestCase{
- {
- description: "test base url",
- expectedPath: "/v2/",
- build: func() (string, error) {
- return urlBuilder.BuildBaseURL()
- },
- },
- {
- description: "test tags url",
- expectedPath: "/v2/foo/bar/tags/list",
- build: func() (string, error) {
- return urlBuilder.BuildTagsURL("foo/bar")
- },
- },
- {
- description: "test manifest url",
- expectedPath: "/v2/foo/bar/manifests/tag",
- build: func() (string, error) {
- return urlBuilder.BuildManifestURL("foo/bar", "tag")
- },
- },
- {
- description: "build blob url",
- expectedPath: "/v2/foo/bar/blobs/tarsum.v1+sha256:abcdef0123456789",
- build: func() (string, error) {
- return urlBuilder.BuildBlobURL("foo/bar", "tarsum.v1+sha256:abcdef0123456789")
- },
- },
- {
- description: "build blob upload url",
- expectedPath: "/v2/foo/bar/blobs/uploads/",
- build: func() (string, error) {
- return urlBuilder.BuildBlobUploadURL("foo/bar")
- },
- },
- {
- description: "build blob upload url with digest and size",
- expectedPath: "/v2/foo/bar/blobs/uploads/?digest=tarsum.v1%2Bsha256%3Aabcdef0123456789&size=10000",
- build: func() (string, error) {
- return urlBuilder.BuildBlobUploadURL("foo/bar", url.Values{
- "size": []string{"10000"},
- "digest": []string{"tarsum.v1+sha256:abcdef0123456789"},
- })
- },
- },
- {
- description: "build blob upload chunk url",
- expectedPath: "/v2/foo/bar/blobs/uploads/uuid-part",
- build: func() (string, error) {
- return urlBuilder.BuildBlobUploadChunkURL("foo/bar", "uuid-part")
- },
- },
- {
- description: "build blob upload chunk url with digest and size",
- expectedPath: "/v2/foo/bar/blobs/uploads/uuid-part?digest=tarsum.v1%2Bsha256%3Aabcdef0123456789&size=10000",
- build: func() (string, error) {
- return urlBuilder.BuildBlobUploadChunkURL("foo/bar", "uuid-part", url.Values{
- "size": []string{"10000"},
- "digest": []string{"tarsum.v1+sha256:abcdef0123456789"},
- })
- },
- },
- }
-
- roots := []string{
- "http://example.com",
- "https://example.com",
- "http://localhost:5000",
- "https://localhost:5443",
- }
-
- for _, root := range roots {
- urlBuilder, err = NewURLBuilderFromString(root)
- if err != nil {
- t.Fatalf("unexpected error creating urlbuilder: %v", err)
- }
-
- for _, testCase := range testCases {
- url, err := testCase.build()
- if err != nil {
- t.Fatalf("%s: error building url: %v", testCase.description, err)
- }
-
- expectedURL := root + testCase.expectedPath
-
- if url != expectedURL {
- t.Fatalf("%s: %q != %q", testCase.description, url, expectedURL)
- }
- }
- }
-}
diff --git a/runconfig/compare.go b/runconfig/compare.go
index 60a21a79c0b16..1d969e9be88e7 100644
--- a/runconfig/compare.go
+++ b/runconfig/compare.go
@@ -10,25 +10,25 @@ func Compare(a, b *Config) bool {
if a.AttachStdout != b.AttachStdout ||
a.AttachStderr != b.AttachStderr ||
a.User != b.User ||
- a.Memory != b.Memory ||
- a.MemorySwap != b.MemorySwap ||
- a.CpuShares != b.CpuShares ||
a.OpenStdin != b.OpenStdin ||
a.Tty != b.Tty {
return false
}
- if len(a.Cmd) != len(b.Cmd) ||
+
+ if a.Cmd.Len() != b.Cmd.Len() ||
len(a.Env) != len(b.Env) ||
len(a.Labels) != len(b.Labels) ||
len(a.PortSpecs) != len(b.PortSpecs) ||
len(a.ExposedPorts) != len(b.ExposedPorts) ||
- len(a.Entrypoint) != len(b.Entrypoint) ||
+ a.Entrypoint.Len() != b.Entrypoint.Len() ||
len(a.Volumes) != len(b.Volumes) {
return false
}
- for i := 0; i < len(a.Cmd); i++ {
- if a.Cmd[i] != b.Cmd[i] {
+ aCmd := a.Cmd.Slice()
+ bCmd := b.Cmd.Slice()
+ for i := 0; i < len(aCmd); i++ {
+ if aCmd[i] != bCmd[i] {
return false
}
}
@@ -52,8 +52,11 @@ func Compare(a, b *Config) bool {
return false
}
}
- for i := 0; i < len(a.Entrypoint); i++ {
- if a.Entrypoint[i] != b.Entrypoint[i] {
+
+ aEntrypoint := a.Entrypoint.Slice()
+ bEntrypoint := b.Entrypoint.Slice()
+ for i := 0; i < len(aEntrypoint); i++ {
+ if aEntrypoint[i] != bEntrypoint[i] {
return false
}
}
diff --git a/runconfig/config.go b/runconfig/config.go
index 45255e9b01ebd..844958be2c3ca 100644
--- a/runconfig/config.go
+++ b/runconfig/config.go
@@ -1,10 +1,103 @@
package runconfig
import (
- "github.com/docker/docker/engine"
+ "encoding/json"
+ "io"
+
"github.com/docker/docker/nat"
)
+// Entrypoint encapsulates the container entrypoint.
+// It might be represented as a string or an array of strings.
+// We need to override the json decoder to accept both options.
+// The JSON decoder will fail if the api sends an string and
+// we try to decode it into an array of string.
+type Entrypoint struct {
+ parts []string
+}
+
+func (e *Entrypoint) MarshalJSON() ([]byte, error) {
+ if e == nil {
+ return []byte{}, nil
+ }
+ return json.Marshal(e.Slice())
+}
+
+// UnmarshalJSON decoded the entrypoint whether it's a string or an array of strings.
+func (e *Entrypoint) UnmarshalJSON(b []byte) error {
+ if len(b) == 0 {
+ return nil
+ }
+
+ p := make([]string, 0, 1)
+ if err := json.Unmarshal(b, &p); err != nil {
+ p = append(p, string(b))
+ }
+ e.parts = p
+ return nil
+}
+
+func (e *Entrypoint) Len() int {
+ if e == nil {
+ return 0
+ }
+ return len(e.parts)
+}
+
+func (e *Entrypoint) Slice() []string {
+ if e == nil {
+ return nil
+ }
+ return e.parts
+}
+
+func NewEntrypoint(parts ...string) *Entrypoint {
+ return &Entrypoint{parts}
+}
+
+type Command struct {
+ parts []string
+}
+
+func (e *Command) MarshalJSON() ([]byte, error) {
+ if e == nil {
+ return []byte{}, nil
+ }
+ return json.Marshal(e.Slice())
+}
+
+// UnmarshalJSON decoded the entrypoint whether it's a string or an array of strings.
+func (e *Command) UnmarshalJSON(b []byte) error {
+ if len(b) == 0 {
+ return nil
+ }
+
+ p := make([]string, 0, 1)
+ if err := json.Unmarshal(b, &p); err != nil {
+ p = append(p, string(b))
+ }
+ e.parts = p
+ return nil
+}
+
+func (e *Command) Len() int {
+ if e == nil {
+ return 0
+ }
+ return len(e.parts)
+}
+
+func (e *Command) Slice() []string {
+ if e == nil {
+ return nil
+ }
+ return e.parts
+}
+
+func NewCommand(parts ...string) *Command {
+ return &Command{parts}
+}
+
// Note: the Config structure should hold only portable information about the container.
// Here, "portable" means "independent from the host we are running on".
// Non-portable information *should* appear in HostConfig.
@@ -12,10 +105,6 @@ type Config struct {
Hostname string
Domainname string
User string
- Memory int64 // FIXME: we keep it for backward compatibility, it has been moved to hostConfig.
- MemorySwap int64 // FIXME: it has been moved to hostConfig.
- CpuShares int64 // FIXME: it has been moved to hostConfig.
- Cpuset string // FIXME: it has been moved to hostConfig and renamed to CpusetCpus.
AttachStdin bool
AttachStdout bool
AttachStderr bool
@@ -25,53 +114,37 @@ type Config struct {
OpenStdin bool // Open stdin
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
Env []string
- Cmd []string
+ Cmd *Command
Image string // Name of the image as it was passed by the operator (eg. could be symbolic)
Volumes map[string]struct{}
WorkingDir string
- Entrypoint []string
+ Entrypoint *Entrypoint
NetworkDisabled bool
MacAddress string
OnBuild []string
Labels map[string]string
}
-func ContainerConfigFromJob(job *engine.Job) *Config {
- config := &Config{
- Hostname: job.Getenv("Hostname"),
- Domainname: job.Getenv("Domainname"),
- User: job.Getenv("User"),
- Memory: job.GetenvInt64("Memory"),
- MemorySwap: job.GetenvInt64("MemorySwap"),
- CpuShares: job.GetenvInt64("CpuShares"),
- Cpuset: job.Getenv("Cpuset"),
- AttachStdin: job.GetenvBool("AttachStdin"),
- AttachStdout: job.GetenvBool("AttachStdout"),
- AttachStderr: job.GetenvBool("AttachStderr"),
- Tty: job.GetenvBool("Tty"),
- OpenStdin: job.GetenvBool("OpenStdin"),
- StdinOnce: job.GetenvBool("StdinOnce"),
- Image: job.Getenv("Image"),
- WorkingDir: job.Getenv("WorkingDir"),
- NetworkDisabled: job.GetenvBool("NetworkDisabled"),
- MacAddress: job.Getenv("MacAddress"),
- }
- job.GetenvJson("ExposedPorts", &config.ExposedPorts)
- job.GetenvJson("Volumes", &config.Volumes)
- if PortSpecs := job.GetenvList("PortSpecs"); PortSpecs != nil {
- config.PortSpecs = PortSpecs
- }
- if Env := job.GetenvList("Env"); Env != nil {
- config.Env = Env
- }
- if Cmd := job.GetenvList("Cmd"); Cmd != nil {
- config.Cmd = Cmd
+type ContainerConfigWrapper struct {
+ *Config
+ *hostConfigWrapper
+}
+
+func (c ContainerConfigWrapper) HostConfig() *HostConfig {
+ if c.hostConfigWrapper == nil {
+ return new(HostConfig)
}
- job.GetenvJson("Labels", &config.Labels)
+ return c.hostConfigWrapper.GetHostConfig()
+}
- if Entrypoint := job.GetenvList("Entrypoint"); Entrypoint != nil {
- config.Entrypoint = Entrypoint
+func DecodeContainerConfig(src io.Reader) (*Config, *HostConfig, error) {
+ decoder := json.NewDecoder(src)
+
+ var w ContainerConfigWrapper
+ if err := decoder.Decode(&w); err != nil {
+ return nil, nil, err
}
- return config
+
+ return w.Config, w.HostConfig(), nil
}
diff --git a/runconfig/config_test.go b/runconfig/config_test.go
index accbd9107e316..87fc6c6aaca34 100644
--- a/runconfig/config_test.go
+++ b/runconfig/config_test.go
@@ -1,7 +1,9 @@
package runconfig
import (
+ "bytes"
"fmt"
+ "io/ioutil"
"strings"
"testing"
@@ -102,7 +104,7 @@ func TestParseRunVolumes(t *testing.T) {
if config, hostConfig := mustParse(t, "-v /tmp -v /var"); hostConfig.Binds != nil {
t.Fatalf("Error parsing volume flags, `-v /tmp -v /var` should not mount-bind anything. Received %v", hostConfig.Binds)
} else if _, exists := config.Volumes["/tmp"]; !exists {
- t.Fatalf("Error parsing volume flags, `-v /tmp` is missing from volumes. Recevied %v", config.Volumes)
+ t.Fatalf("Error parsing volume flags, `-v /tmp` is missing from volumes. Received %v", config.Volumes)
} else if _, exists := config.Volumes["/var"]; !exists {
t.Fatalf("Error parsing volume flags, `-v /var` is missing from volumes. Received %v", config.Volumes)
}
@@ -260,5 +262,39 @@ func TestMerge(t *testing.T) {
t.Fatalf("Expected %q or %q or %q or %q, found %s", 0, 1111, 2222, 3333, portSpecs)
}
}
+}
+
+func TestDecodeContainerConfig(t *testing.T) {
+ fixtures := []struct {
+ file string
+ entrypoint *Entrypoint
+ }{
+ {"fixtures/container_config_1_14.json", NewEntrypoint()},
+ {"fixtures/container_config_1_17.json", NewEntrypoint("bash")},
+ {"fixtures/container_config_1_19.json", NewEntrypoint("bash")},
+ }
+
+ for _, f := range fixtures {
+ b, err := ioutil.ReadFile(f.file)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ c, h, err := DecodeContainerConfig(bytes.NewReader(b))
+ if err != nil {
+ t.Fatal(fmt.Errorf("Error parsing %s: %v", f, err))
+ }
+
+ if c.Image != "ubuntu" {
+ t.Fatalf("Expected ubuntu image, found %s\n", c.Image)
+ }
+ if c.Entrypoint.Len() != f.entrypoint.Len() {
+ t.Fatalf("Expected %v, found %v\n", f.entrypoint, c.Entrypoint)
+ }
+
+ if h.Memory != 1000 {
+ t.Fatalf("Expected memory to be 1000, found %d\n", h.Memory)
+ }
+ }
}
diff --git a/runconfig/exec.go b/runconfig/exec.go
index 1bcdad1599b94..8fe05be1bb3d3 100644
--- a/runconfig/exec.go
+++ b/runconfig/exec.go
@@ -1,9 +1,6 @@
package runconfig
import (
- "fmt"
-
- "github.com/docker/docker/engine"
flag "github.com/docker/docker/pkg/mflag"
)
@@ -19,34 +16,15 @@ type ExecConfig struct {
Cmd []string
}
-func ExecConfigFromJob(job *engine.Job) (*ExecConfig, error) {
- execConfig := &ExecConfig{
- // TODO(vishh): Expose 'User' once it is supported.
- //User: job.Getenv("User"),
- // TODO(vishh): Expose 'Privileged' once it is supported.
- //Privileged: job.GetenvBool("Privileged"),
- Tty: job.GetenvBool("Tty"),
- AttachStdin: job.GetenvBool("AttachStdin"),
- AttachStderr: job.GetenvBool("AttachStderr"),
- AttachStdout: job.GetenvBool("AttachStdout"),
- }
- cmd := job.GetenvList("Cmd")
- if len(cmd) == 0 {
- return nil, fmt.Errorf("No exec command specified")
- }
-
- execConfig.Cmd = cmd
-
- return execConfig, nil
-}
-
func ParseExec(cmd *flag.FlagSet, args []string) (*ExecConfig, error) {
var (
- flStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached")
- flTty = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY")
- flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run command in the background")
- execCmd []string
- container string
+ flStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached")
+ flTty = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY")
+ flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run command in the background")
+ flUser = cmd.String([]string{"u", "-user"}, "", "Username or UID (format: [:])")
+ flPrivileged = cmd.Bool([]string{"-privileged"}, false, "Give extended privileges to the command")
+ execCmd []string
+ container string
)
cmd.Require(flag.Min, 2)
if err := cmd.ParseFlags(args, true); err != nil {
@@ -57,10 +35,8 @@ func ParseExec(cmd *flag.FlagSet, args []string) (*ExecConfig, error) {
execCmd = parsedArgs[1:]
execConfig := &ExecConfig{
- // TODO(vishh): Expose '-u' flag once it is supported.
- User: "",
- // TODO(vishh): Expose '-p' flag once it is supported.
- Privileged: false,
+ User: *flUser,
+ Privileged: *flPrivileged,
Tty: *flTty,
Cmd: execCmd,
Container: container,
diff --git a/runconfig/fixtures/container_config_1_14.json b/runconfig/fixtures/container_config_1_14.json
new file mode 100644
index 0000000000000..b08334c0950e4
--- /dev/null
+++ b/runconfig/fixtures/container_config_1_14.json
@@ -0,0 +1,30 @@
+{
+ "Hostname":"",
+ "Domainname": "",
+ "User":"",
+ "Memory": 1000,
+ "MemorySwap":0,
+ "CpuShares": 512,
+ "Cpuset": "0,1",
+ "AttachStdin":false,
+ "AttachStdout":true,
+ "AttachStderr":true,
+ "PortSpecs":null,
+ "Tty":false,
+ "OpenStdin":false,
+ "StdinOnce":false,
+ "Env":null,
+ "Cmd":[
+ "bash"
+ ],
+ "Image":"ubuntu",
+ "Volumes":{
+ "/tmp": {}
+ },
+ "WorkingDir":"",
+ "NetworkDisabled": false,
+ "ExposedPorts":{
+ "22/tcp": {}
+ },
+ "RestartPolicy": { "Name": "always" }
+}
diff --git a/runconfig/fixtures/container_config_1_17.json b/runconfig/fixtures/container_config_1_17.json
new file mode 100644
index 0000000000000..60fc6e25e20d9
--- /dev/null
+++ b/runconfig/fixtures/container_config_1_17.json
@@ -0,0 +1,49 @@
+{
+ "Hostname": "",
+ "Domainname": "",
+ "User": "",
+ "Memory": 1000,
+ "MemorySwap": 0,
+ "CpuShares": 512,
+ "Cpuset": "0,1",
+ "AttachStdin": false,
+ "AttachStdout": true,
+ "AttachStderr": true,
+ "Tty": false,
+ "OpenStdin": false,
+ "StdinOnce": false,
+ "Env": null,
+ "Cmd": [
+ "date"
+ ],
+ "Entrypoint": "bash",
+ "Image": "ubuntu",
+ "Volumes": {
+ "/tmp": {}
+ },
+ "WorkingDir": "",
+ "NetworkDisabled": false,
+ "MacAddress": "12:34:56:78:9a:bc",
+ "ExposedPorts": {
+ "22/tcp": {}
+ },
+ "SecurityOpt": [""],
+ "HostConfig": {
+ "Binds": ["/tmp:/tmp"],
+ "Links": ["redis3:redis"],
+ "LxcConf": {"lxc.utsname":"docker"},
+ "PortBindings": { "22/tcp": [{ "HostPort": "11022" }] },
+ "PublishAllPorts": false,
+ "Privileged": false,
+ "ReadonlyRootfs": false,
+ "Dns": ["8.8.8.8"],
+ "DnsSearch": [""],
+ "ExtraHosts": null,
+ "VolumesFrom": ["parent", "other:ro"],
+ "CapAdd": ["NET_ADMIN"],
+ "CapDrop": ["MKNOD"],
+ "RestartPolicy": { "Name": "", "MaximumRetryCount": 0 },
+ "NetworkMode": "bridge",
+ "Devices": []
+ }
+}
diff --git a/runconfig/fixtures/container_config_1_19.json b/runconfig/fixtures/container_config_1_19.json
new file mode 100644
index 0000000000000..9a3ce205b3694
--- /dev/null
+++ b/runconfig/fixtures/container_config_1_19.json
@@ -0,0 +1,57 @@
+{
+ "Hostname": "",
+ "Domainname": "",
+ "User": "",
+ "AttachStdin": false,
+ "AttachStdout": true,
+ "AttachStderr": true,
+ "Tty": false,
+ "OpenStdin": false,
+ "StdinOnce": false,
+ "Env": null,
+ "Cmd": [
+ "date"
+ ],
+ "Entrypoint": "bash",
+ "Image": "ubuntu",
+ "Labels": {
+ "com.example.vendor": "Acme",
+ "com.example.license": "GPL",
+ "com.example.version": "1.0"
+ },
+ "Volumes": {
+ "/tmp": {}
+ },
+ "WorkingDir": "",
+ "NetworkDisabled": false,
+ "MacAddress": "12:34:56:78:9a:bc",
+ "ExposedPorts": {
+ "22/tcp": {}
+ },
+ "HostConfig": {
+ "Binds": ["/tmp:/tmp"],
+ "Links": ["redis3:redis"],
+ "LxcConf": {"lxc.utsname":"docker"},
+ "Memory": 1000,
+ "MemorySwap": 0,
+ "CpuShares": 512,
+ "CpusetCpus": "0,1",
+ "PortBindings": { "22/tcp": [{ "HostPort": "11022" }] },
+ "PublishAllPorts": false,
+ "Privileged": false,
+ "ReadonlyRootfs": false,
+ "Dns": ["8.8.8.8"],
+ "DnsSearch": [""],
+ "ExtraHosts": null,
+ "VolumesFrom": ["parent", "other:ro"],
+ "CapAdd": ["NET_ADMIN"],
+ "CapDrop": ["MKNOD"],
+ "RestartPolicy": { "Name": "", "MaximumRetryCount": 0 },
+ "NetworkMode": "bridge",
+ "Devices": [],
+ "Ulimits": [{}],
+ "LogConfig": { "Type": "json-file", "Config": {} },
+ "SecurityOpt": [""],
+ "CgroupParent": ""
+ }
+}
diff --git a/runconfig/hostconfig.go b/runconfig/hostconfig.go
index 84d636b5c4beb..171671b6efddd 100644
--- a/runconfig/hostconfig.go
+++ b/runconfig/hostconfig.go
@@ -1,14 +1,19 @@
package runconfig
import (
+ "encoding/json"
+ "io"
"strings"
- "github.com/docker/docker/engine"
"github.com/docker/docker/nat"
"github.com/docker/docker/pkg/ulimit"
- "github.com/docker/docker/utils"
)
+type KeyValuePair struct {
+ Key string
+ Value string
+}
+
type NetworkMode string
// IsPrivate indicates whether container use it's private network stack
@@ -104,14 +109,65 @@ type LogConfig struct {
Config map[string]string
}
+type LxcConfig struct {
+ values []KeyValuePair
+}
+
+func (c *LxcConfig) MarshalJSON() ([]byte, error) {
+ if c == nil {
+ return []byte{}, nil
+ }
+ return json.Marshal(c.Slice())
+}
+
+func (c *LxcConfig) UnmarshalJSON(b []byte) error {
+ if len(b) == 0 {
+ return nil
+ }
+
+ var kv []KeyValuePair
+ if err := json.Unmarshal(b, &kv); err != nil {
+ var h map[string]string
+ if err := json.Unmarshal(b, &h); err != nil {
+ return err
+ }
+ for k, v := range h {
+ kv = append(kv, KeyValuePair{k, v})
+ }
+ }
+ c.values = kv
+
+ return nil
+}
+
+func (c *LxcConfig) Len() int {
+ if c == nil {
+ return 0
+ }
+ return len(c.values)
+}
+
+func (c *LxcConfig) Slice() []KeyValuePair {
+ if c == nil {
+ return nil
+ }
+ return c.values
+}
+
+func NewLxcConfig(values []KeyValuePair) *LxcConfig {
+ return &LxcConfig{values}
+}
+
type HostConfig struct {
Binds []string
ContainerIDFile string
- LxcConf []utils.KeyValuePair
+ LxcConf *LxcConfig
Memory int64 // Memory limit (in bytes)
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to disable swap
CpuShares int64 // CPU shares (relative weight vs. other containers)
CpusetCpus string // CpusetCpus 0-2, 0,1
+ CpusetMems string // CpusetMems 0-2, 0,1
+ CpuQuota int64
Privileged bool
PortBindings nat.PortMap
Links []string
@@ -134,96 +190,55 @@ type HostConfig struct {
CgroupParent string // Parent cgroup.
}
-// This is used by the create command when you want to set both the
-// Config and the HostConfig in the same call
-type ConfigAndHostConfig struct {
- Config
- HostConfig HostConfig
+func MergeConfigs(config *Config, hostConfig *HostConfig) *ContainerConfigWrapper {
+ return &ContainerConfigWrapper{
+ config,
+ &hostConfigWrapper{InnerHostConfig: hostConfig},
+ }
}
-func MergeConfigs(config *Config, hostConfig *HostConfig) *ConfigAndHostConfig {
- return &ConfigAndHostConfig{
- *config,
- *hostConfig,
- }
+type hostConfigWrapper struct {
+ InnerHostConfig *HostConfig `json:"HostConfig,omitempty"`
+ Cpuset string `json:",omitempty"` // Deprecated. Exported for backwards compatibility.
+
+ *HostConfig // Deprecated. Exported to read attrubutes from json that are not in the inner host config structure.
}
-func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
- if job.EnvExists("HostConfig") {
- hostConfig := HostConfig{}
- job.GetenvJson("HostConfig", &hostConfig)
+func (w hostConfigWrapper) GetHostConfig() *HostConfig {
+ hc := w.HostConfig
- // FIXME: These are for backward compatibility, if people use these
- // options with `HostConfig`, we should still make them workable.
- if job.EnvExists("Memory") && hostConfig.Memory == 0 {
- hostConfig.Memory = job.GetenvInt64("Memory")
- }
- if job.EnvExists("MemorySwap") && hostConfig.MemorySwap == 0 {
- hostConfig.MemorySwap = job.GetenvInt64("MemorySwap")
+ if hc == nil && w.InnerHostConfig != nil {
+ hc = w.InnerHostConfig
+ } else if w.InnerHostConfig != nil {
+ if hc.Memory != 0 && w.InnerHostConfig.Memory == 0 {
+ w.InnerHostConfig.Memory = hc.Memory
}
- if job.EnvExists("CpuShares") && hostConfig.CpuShares == 0 {
- hostConfig.CpuShares = job.GetenvInt64("CpuShares")
+ if hc.MemorySwap != 0 && w.InnerHostConfig.MemorySwap == 0 {
+ w.InnerHostConfig.MemorySwap = hc.MemorySwap
}
- if job.EnvExists("Cpuset") && hostConfig.CpusetCpus == "" {
- hostConfig.CpusetCpus = job.Getenv("Cpuset")
+ if hc.CpuShares != 0 && w.InnerHostConfig.CpuShares == 0 {
+ w.InnerHostConfig.CpuShares = hc.CpuShares
}
- return &hostConfig
+ hc = w.InnerHostConfig
}
- hostConfig := &HostConfig{
- ContainerIDFile: job.Getenv("ContainerIDFile"),
- Memory: job.GetenvInt64("Memory"),
- MemorySwap: job.GetenvInt64("MemorySwap"),
- CpuShares: job.GetenvInt64("CpuShares"),
- CpusetCpus: job.Getenv("CpusetCpus"),
- Privileged: job.GetenvBool("Privileged"),
- PublishAllPorts: job.GetenvBool("PublishAllPorts"),
- NetworkMode: NetworkMode(job.Getenv("NetworkMode")),
- IpcMode: IpcMode(job.Getenv("IpcMode")),
- PidMode: PidMode(job.Getenv("PidMode")),
- ReadonlyRootfs: job.GetenvBool("ReadonlyRootfs"),
- CgroupParent: job.Getenv("CgroupParent"),
+ if hc != nil && w.Cpuset != "" && hc.CpusetCpus == "" {
+ hc.CpusetCpus = w.Cpuset
}
- // FIXME: This is for backward compatibility, if people use `Cpuset`
- // in json, make it workable, we will only pass hostConfig.CpusetCpus
- // to execDriver.
- if job.EnvExists("Cpuset") && hostConfig.CpusetCpus == "" {
- hostConfig.CpusetCpus = job.Getenv("Cpuset")
- }
+ return hc
+}
- job.GetenvJson("LxcConf", &hostConfig.LxcConf)
- job.GetenvJson("PortBindings", &hostConfig.PortBindings)
- job.GetenvJson("Devices", &hostConfig.Devices)
- job.GetenvJson("RestartPolicy", &hostConfig.RestartPolicy)
- job.GetenvJson("Ulimits", &hostConfig.Ulimits)
- job.GetenvJson("LogConfig", &hostConfig.LogConfig)
- hostConfig.SecurityOpt = job.GetenvList("SecurityOpt")
- if Binds := job.GetenvList("Binds"); Binds != nil {
- hostConfig.Binds = Binds
- }
- if Links := job.GetenvList("Links"); Links != nil {
- hostConfig.Links = Links
- }
- if Dns := job.GetenvList("Dns"); Dns != nil {
- hostConfig.Dns = Dns
- }
- if DnsSearch := job.GetenvList("DnsSearch"); DnsSearch != nil {
- hostConfig.DnsSearch = DnsSearch
- }
- if ExtraHosts := job.GetenvList("ExtraHosts"); ExtraHosts != nil {
- hostConfig.ExtraHosts = ExtraHosts
- }
- if VolumesFrom := job.GetenvList("VolumesFrom"); VolumesFrom != nil {
- hostConfig.VolumesFrom = VolumesFrom
- }
- if CapAdd := job.GetenvList("CapAdd"); CapAdd != nil {
- hostConfig.CapAdd = CapAdd
- }
- if CapDrop := job.GetenvList("CapDrop"); CapDrop != nil {
- hostConfig.CapDrop = CapDrop
+func DecodeHostConfig(src io.Reader) (*HostConfig, error) {
+ decoder := json.NewDecoder(src)
+
+ var w hostConfigWrapper
+ if err := decoder.Decode(&w); err != nil {
+ return nil, err
}
- return hostConfig
+ hc := w.GetHostConfig()
+
+ return hc, nil
}
diff --git a/runconfig/merge.go b/runconfig/merge.go
index 68d3d6ee125e5..9c9a3b4367553 100644
--- a/runconfig/merge.go
+++ b/runconfig/merge.go
@@ -11,15 +11,6 @@ func Merge(userConf, imageConf *Config) error {
if userConf.User == "" {
userConf.User = imageConf.User
}
- if userConf.Memory == 0 {
- userConf.Memory = imageConf.Memory
- }
- if userConf.MemorySwap == 0 {
- userConf.MemorySwap = imageConf.MemorySwap
- }
- if userConf.CpuShares == 0 {
- userConf.CpuShares = imageConf.CpuShares
- }
if len(userConf.ExposedPorts) == 0 {
userConf.ExposedPorts = imageConf.ExposedPorts
} else if imageConf.ExposedPorts != nil {
@@ -50,7 +41,7 @@ func Merge(userConf, imageConf *Config) error {
}
if len(imageConf.PortSpecs) > 0 {
// FIXME: I think we can safely remove this. Leaving it for now for the sake of reverse-compat paranoia.
- logrus.Debugf("Migrating image port specs to containter: %s", strings.Join(imageConf.PortSpecs, ", "))
+ logrus.Debugf("Migrating image port specs to container: %s", strings.Join(imageConf.PortSpecs, ", "))
if userConf.ExposedPorts == nil {
userConf.ExposedPorts = make(nat.PortSet)
}
@@ -94,8 +85,8 @@ func Merge(userConf, imageConf *Config) error {
userConf.Labels = imageConf.Labels
}
- if len(userConf.Entrypoint) == 0 {
- if len(userConf.Cmd) == 0 {
+ if userConf.Entrypoint.Len() == 0 {
+ if userConf.Cmd.Len() == 0 {
userConf.Cmd = imageConf.Cmd
}
diff --git a/runconfig/parse.go b/runconfig/parse.go
index 1fb36e4ace539..47feac866a636 100644
--- a/runconfig/parse.go
+++ b/runconfig/parse.go
@@ -12,7 +12,6 @@ import (
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/ulimit"
"github.com/docker/docker/pkg/units"
- "github.com/docker/docker/utils"
)
var (
@@ -65,6 +64,8 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
flWorkingDir = cmd.String([]string{"w", "-workdir"}, "", "Working directory inside the container")
flCpuShares = cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
flCpusetCpus = cmd.String([]string{"#-cpuset", "-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)")
+ flCpusetMems = cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)")
+ flCpuQuota = cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) quota")
flNetMode = cmd.String([]string{"-net"}, "bridge", "Set the Network mode for the container")
flMacAddress = cmd.String([]string{"-mac-address"}, "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)")
flIpcMode = cmd.String([]string{"-ipc"}, "", "IPC namespace to use")
@@ -186,21 +187,22 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
var (
parsedArgs = cmd.Args()
- runCmd []string
- entrypoint []string
+ runCmd *Command
+ entrypoint *Entrypoint
image = cmd.Arg(0)
)
if len(parsedArgs) > 1 {
- runCmd = parsedArgs[1:]
+ runCmd = NewCommand(parsedArgs[1:]...)
}
if *flEntrypoint != "" {
- entrypoint = []string{*flEntrypoint}
+ entrypoint = NewEntrypoint(*flEntrypoint)
}
- lxcConf, err := parseKeyValueOpts(flLxcOpts)
+ lc, err := parseKeyValueOpts(flLxcOpts)
if err != nil {
return nil, nil, cmd, err
}
+ lxcConf := NewLxcConfig(lc)
var (
domainname string
@@ -275,7 +277,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
return nil, nil, cmd, fmt.Errorf("--net: invalid net mode: %v", err)
}
- restartPolicy, err := parseRestartPolicy(*flRestartPolicy)
+ restartPolicy, err := ParseRestartPolicy(*flRestartPolicy)
if err != nil {
return nil, nil, cmd, err
}
@@ -289,10 +291,6 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
Tty: *flTty,
NetworkDisabled: !*flNetwork,
OpenStdin: *flStdin,
- Memory: flMemory, // FIXME: for backward compatibility
- MemorySwap: MemorySwap, // FIXME: for backward compatibility
- CpuShares: *flCpuShares, // FIXME: for backward compatibility
- Cpuset: *flCpusetCpus, // FIXME: for backward compatibility
AttachStdin: attachStdin,
AttachStdout: attachStdout,
AttachStderr: attachStderr,
@@ -314,6 +312,8 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
MemorySwap: MemorySwap,
CpuShares: *flCpuShares,
CpusetCpus: *flCpusetCpus,
+ CpusetMems: *flCpusetMems,
+ CpuQuota: *flCpuQuota,
Privileged: *flPrivileged,
PortBindings: portBindings,
Links: flLinks.GetAll(),
@@ -374,8 +374,8 @@ func convertKVStringsToMap(values []string) map[string]string {
return result
}
-// parseRestartPolicy returns the parsed policy or an error indicating what is incorrect
-func parseRestartPolicy(policy string) (RestartPolicy, error) {
+// ParseRestartPolicy returns the parsed policy or an error indicating what is incorrect
+func ParseRestartPolicy(policy string) (RestartPolicy, error) {
p := RestartPolicy{}
if policy == "" {
@@ -430,14 +430,14 @@ func parseDriverOpts(opts opts.ListOpts) (map[string][]string, error) {
return out, nil
}
-func parseKeyValueOpts(opts opts.ListOpts) ([]utils.KeyValuePair, error) {
- out := make([]utils.KeyValuePair, opts.Len())
+func parseKeyValueOpts(opts opts.ListOpts) ([]KeyValuePair, error) {
+ out := make([]KeyValuePair, opts.Len())
for i, o := range opts.GetAll() {
k, v, err := parsers.ParseKeyValueOpt(o)
if err != nil {
return nil, err
}
- out[i] = utils.KeyValuePair{Key: k, Value: v}
+ out[i] = KeyValuePair{Key: k, Value: v}
}
return out, nil
}
diff --git a/trust/service.go b/trust/service.go
index 12b9645667025..6a804faf5297b 100644
--- a/trust/service.go
+++ b/trust/service.go
@@ -5,70 +5,49 @@ import (
"time"
"github.com/Sirupsen/logrus"
- "github.com/docker/docker/engine"
"github.com/docker/libtrust"
)
-func (t *TrustStore) Install(eng *engine.Engine) error {
- for name, handler := range map[string]engine.Handler{
- "trust_key_check": t.CmdCheckKey,
- "trust_update_base": t.CmdUpdateBase,
- } {
- if err := eng.Register(name, handler); err != nil {
- return fmt.Errorf("Could not register %q: %v", name, err)
- }
- }
- return nil
-}
+type NotVerifiedError string
-func (t *TrustStore) CmdCheckKey(job *engine.Job) error {
- if n := len(job.Args); n != 1 {
- return fmt.Errorf("Usage: %s NAMESPACE", job.Name)
- }
- var (
- namespace = job.Args[0]
- keyBytes = job.Getenv("PublicKey")
- )
+func (e NotVerifiedError) Error() string {
+ return string(e)
+}
- if keyBytes == "" {
- return fmt.Errorf("Missing PublicKey")
+func (t *TrustStore) CheckKey(ns string, key []byte, perm uint16) (bool, error) {
+ if len(key) == 0 {
+ return false, fmt.Errorf("Missing PublicKey")
}
- pk, err := libtrust.UnmarshalPublicKeyJWK([]byte(keyBytes))
+ pk, err := libtrust.UnmarshalPublicKeyJWK(key)
if err != nil {
- return fmt.Errorf("Error unmarshalling public key: %s", err)
+ return false, fmt.Errorf("Error unmarshalling public key: %v", err)
}
- permission := uint16(job.GetenvInt("Permission"))
- if permission == 0 {
- permission = 0x03
+ if perm == 0 {
+ perm = 0x03
}
t.RLock()
defer t.RUnlock()
if t.graph == nil {
- job.Stdout.Write([]byte("no graph"))
- return nil
+ return false, NotVerifiedError("no graph")
}
// Check if any expired grants
- verified, err := t.graph.Verify(pk, namespace, permission)
+ verified, err := t.graph.Verify(pk, ns, perm)
if err != nil {
- return fmt.Errorf("Error verifying key to namespace: %s", namespace)
+ return false, fmt.Errorf("Error verifying key to namespace: %s", ns)
}
if !verified {
- logrus.Debugf("Verification failed for %s using key %s", namespace, pk.KeyID())
- job.Stdout.Write([]byte("not verified"))
- } else if t.expiration.Before(time.Now()) {
- job.Stdout.Write([]byte("expired"))
- } else {
- job.Stdout.Write([]byte("verified"))
+ logrus.Debugf("Verification failed for %s using key %s", ns, pk.KeyID())
+ return false, NotVerifiedError("not verified")
}
-
- return nil
+ if t.expiration.Before(time.Now()) {
+ return false, NotVerifiedError("expired")
+ }
+ return true, nil
}
-func (t *TrustStore) CmdUpdateBase(job *engine.Job) error {
+func (t *TrustStore) UpdateBase() {
t.fetch()
-
- return nil
}
diff --git a/trust/trusts.go b/trust/trusts.go
index c4a2f4158b21f..885127ee5d6f1 100644
--- a/trust/trusts.go
+++ b/trust/trusts.go
@@ -62,8 +62,7 @@ func NewTrustStore(path string) (*TrustStore, error) {
baseEndpoints: endpoints,
}
- err = t.reload()
- if err != nil {
+ if err := t.reload(); err != nil {
return nil, err
}
@@ -170,8 +169,7 @@ func (t *TrustStore) fetch() {
continue
}
// TODO check if value differs
- err = ioutil.WriteFile(path.Join(t.path, bg+".json"), b, 0600)
- if err != nil {
+ if err := ioutil.WriteFile(path.Join(t.path, bg+".json"), b, 0600); err != nil {
logrus.Infof("Error writing trust graph statement: %s", err)
}
fetchCount++
@@ -180,8 +178,7 @@ func (t *TrustStore) fetch() {
if fetchCount > 0 {
go func() {
- err := t.reload()
- if err != nil {
+ if err := t.reload(); err != nil {
logrus.Infof("Reload of trust graph failed: %s", err)
}
}()
diff --git a/utils/git.go b/utils/git.go
new file mode 100644
index 0000000000000..18e002d184210
--- /dev/null
+++ b/utils/git.go
@@ -0,0 +1,47 @@
+package utils
+
+import (
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "os/exec"
+ "strings"
+
+ "github.com/docker/docker/pkg/urlutil"
+)
+
+func GitClone(remoteURL string) (string, error) {
+ if !urlutil.IsGitTransport(remoteURL) {
+ remoteURL = "https://" + remoteURL
+ }
+ root, err := ioutil.TempDir("", "docker-build-git")
+ if err != nil {
+ return "", err
+ }
+
+ clone := cloneArgs(remoteURL, root)
+
+ if output, err := exec.Command("git", clone...).CombinedOutput(); err != nil {
+ return "", fmt.Errorf("Error trying to use git: %s (%s)", err, output)
+ }
+
+ return root, nil
+}
+
+func cloneArgs(remoteURL, root string) []string {
+ args := []string{"clone", "--recursive"}
+ shallow := true
+
+ if strings.HasPrefix(remoteURL, "http") {
+ res, err := http.Head(fmt.Sprintf("%s/info/refs?service=git-upload-pack", remoteURL))
+ if err != nil || res.Header.Get("Content-Type") != "application/x-git-upload-pack-advertisement" {
+ shallow = false
+ }
+ }
+
+ if shallow {
+ args = append(args, "--depth", "1")
+ }
+
+ return append(args, remoteURL, root)
+}
diff --git a/utils/git_test.go b/utils/git_test.go
new file mode 100644
index 0000000000000..a82841ae1167e
--- /dev/null
+++ b/utils/git_test.go
@@ -0,0 +1,56 @@
+package utils
+
+import (
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "reflect"
+ "testing"
+)
+
+func TestCloneArgsSmartHttp(t *testing.T) {
+ mux := http.NewServeMux()
+ server := httptest.NewServer(mux)
+ serverURL, _ := url.Parse(server.URL)
+
+ serverURL.Path = "/repo.git"
+ gitURL := serverURL.String()
+
+ mux.HandleFunc("/repo.git/info/refs", func(w http.ResponseWriter, r *http.Request) {
+ q := r.URL.Query().Get("service")
+ w.Header().Set("Content-Type", fmt.Sprintf("application/x-%s-advertisement", q))
+ })
+
+ args := cloneArgs(gitURL, "/tmp")
+ exp := []string{"clone", "--recursive", "--depth", "1", gitURL, "/tmp"}
+ if !reflect.DeepEqual(args, exp) {
+ t.Fatalf("Expected %v, got %v", exp, args)
+ }
+}
+
+func TestCloneArgsDumbHttp(t *testing.T) {
+ mux := http.NewServeMux()
+ server := httptest.NewServer(mux)
+ serverURL, _ := url.Parse(server.URL)
+
+ serverURL.Path = "/repo.git"
+ gitURL := serverURL.String()
+
+ mux.HandleFunc("/repo.git/info/refs", func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "text/plain")
+ })
+
+ args := cloneArgs(gitURL, "/tmp")
+ exp := []string{"clone", "--recursive", gitURL, "/tmp"}
+ if !reflect.DeepEqual(args, exp) {
+ t.Fatalf("Expected %v, got %v", exp, args)
+ }
+}
+func TestCloneArgsGit(t *testing.T) {
+ args := cloneArgs("git://github.com/docker/docker", "/tmp")
+ exp := []string{"clone", "--recursive", "--depth", "1", "git://github.com/docker/docker", "/tmp"}
+ if !reflect.DeepEqual(args, exp) {
+ t.Fatalf("Expected %v, got %v", exp, args)
+ }
+}
diff --git a/utils/utils.go b/utils/utils.go
index d0e76bf237aee..05dfb757a3bf9 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -2,9 +2,7 @@ package utils
import (
"bufio"
- "bytes"
"crypto/sha1"
- "crypto/sha256"
"encoding/hex"
"fmt"
"io"
@@ -13,47 +11,17 @@ import (
"os"
"os/exec"
"path/filepath"
- "regexp"
"runtime"
"strings"
"sync"
- "github.com/Sirupsen/logrus"
"github.com/docker/docker/autogen/dockerversion"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/fileutils"
"github.com/docker/docker/pkg/ioutils"
- "github.com/docker/docker/pkg/jsonmessage"
- "github.com/docker/docker/pkg/stringutils"
+ "github.com/docker/docker/pkg/stringid"
)
-type KeyValuePair struct {
- Key string
- Value string
-}
-
-var (
- validHex = regexp.MustCompile(`^([a-f0-9]{64})$`)
-)
-
-// Request a given URL and return an io.Reader
-func Download(url string) (resp *http.Response, err error) {
- if resp, err = http.Get(url); err != nil {
- return nil, err
- }
- if resp.StatusCode >= 400 {
- return nil, fmt.Errorf("Got HTTP status code >= 400: %s", resp.Status)
- }
- return resp, nil
-}
-
-func Trunc(s string, maxlen int) string {
- if len(s) <= maxlen {
- return s
- }
- return s[:maxlen]
-}
-
// Figure out the absolute path of our own binary (if it's still around).
func SelfPath() string {
path, err := exec.LookPath(os.Args[0])
@@ -127,12 +95,12 @@ func DockerInitPath(localCopy string) string {
filepath.Join(filepath.Dir(selfPath), "dockerinit"),
// FHS 3.0 Draft: "/usr/libexec includes internal binaries that are not intended to be executed directly by users or shell scripts. Applications may use a single subdirectory under /usr/libexec."
- // http://www.linuxbase.org/betaspecs/fhs/fhs.html#usrlibexec
+ // https://www.linuxbase.org/betaspecs/fhs/fhs.html#usrlibexec
"/usr/libexec/docker/dockerinit",
"/usr/local/libexec/docker/dockerinit",
// FHS 2.3: "/usr/lib includes object files, libraries, and internal binaries that are not intended to be executed directly by users or shell scripts."
- // http://refspecs.linuxfoundation.org/FHS_2.3/fhs-2.3.html#USRLIBLIBRARIESFORPROGRAMMINGANDPA
+ // https://refspecs.linuxfoundation.org/FHS_2.3/fhs-2.3.html#USRLIBLIBRARIESFORPROGRAMMINGANDPA
"/usr/lib/docker/dockerinit",
"/usr/local/lib/docker/dockerinit",
}
@@ -155,84 +123,19 @@ func DockerInitPath(localCopy string) string {
return ""
}
-func GetTotalUsedFds() int {
- if fds, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil {
- logrus.Errorf("Error opening /proc/%d/fd: %s", os.Getpid(), err)
- } else {
- return len(fds)
- }
- return -1
-}
-
-func ValidateID(id string) error {
- if ok := validHex.MatchString(id); !ok {
- err := fmt.Errorf("image ID '%s' is invalid", id)
- return err
- }
- return nil
-}
-
-// Code c/c from io.Copy() modified to handle escape sequence
-func CopyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error) {
- buf := make([]byte, 32*1024)
- for {
- nr, er := src.Read(buf)
- if nr > 0 {
- // ---- Docker addition
- // char 16 is C-p
- if nr == 1 && buf[0] == 16 {
- nr, er = src.Read(buf)
- // char 17 is C-q
- if nr == 1 && buf[0] == 17 {
- if err := src.Close(); err != nil {
- return 0, err
- }
- return 0, nil
- }
- }
- // ---- End of docker
- nw, ew := dst.Write(buf[0:nr])
- if nw > 0 {
- written += int64(nw)
- }
- if ew != nil {
- err = ew
- break
- }
- if nr != nw {
- err = io.ErrShortWrite
- break
- }
- }
- if er == io.EOF {
- break
- }
- if er != nil {
- err = er
- break
- }
- }
- return written, err
-}
-
-func HashData(src io.Reader) (string, error) {
- h := sha256.New()
- if _, err := io.Copy(h, src); err != nil {
- return "", err
- }
- return "sha256:" + hex.EncodeToString(h.Sum(nil)), nil
-}
-
+// FIXME: move to httputils? ioutils?
type WriteFlusher struct {
sync.Mutex
w io.Writer
flusher http.Flusher
+ flushed bool
}
func (wf *WriteFlusher) Write(b []byte) (n int, err error) {
wf.Lock()
defer wf.Unlock()
n, err = wf.w.Write(b)
+ wf.flushed = true
wf.flusher.Flush()
return n, err
}
@@ -241,9 +144,16 @@ func (wf *WriteFlusher) Write(b []byte) (n int, err error) {
func (wf *WriteFlusher) Flush() {
wf.Lock()
defer wf.Unlock()
+ wf.flushed = true
wf.flusher.Flush()
}
+func (wf *WriteFlusher) Flushed() bool {
+ wf.Lock()
+ defer wf.Unlock()
+ return wf.flushed
+}
+
func NewWriteFlusher(w io.Writer) *WriteFlusher {
var flusher http.Flusher
if f, ok := w.(http.Flusher); ok {
@@ -254,58 +164,6 @@ func NewWriteFlusher(w io.Writer) *WriteFlusher {
return &WriteFlusher{w: w, flusher: flusher}
}
-func NewHTTPRequestError(msg string, res *http.Response) error {
- return &jsonmessage.JSONError{
- Message: msg,
- Code: res.StatusCode,
- }
-}
-
-// An StatusError reports an unsuccessful exit by a command.
-type StatusError struct {
- Status string
- StatusCode int
-}
-
-func (e *StatusError) Error() string {
- return fmt.Sprintf("Status: %s, Code: %d", e.Status, e.StatusCode)
-}
-
-func quote(word string, buf *bytes.Buffer) {
- // Bail out early for "simple" strings
- if word != "" && !strings.ContainsAny(word, "\\'\"`${[|&;<>()~*?! \t\n") {
- buf.WriteString(word)
- return
- }
-
- buf.WriteString("'")
-
- for i := 0; i < len(word); i++ {
- b := word[i]
- if b == '\'' {
- // Replace literal ' with a close ', a \', and a open '
- buf.WriteString("'\\''")
- } else {
- buf.WriteByte(b)
- }
- }
-
- buf.WriteString("'")
-}
-
-// Take a list of strings and escape them so they will be handled right
-// when passed as arguments to an program via a shell
-func ShellQuoteArguments(args []string) string {
- var buf bytes.Buffer
- for i, arg := range args {
- if i != 0 {
- buf.WriteByte(' ')
- }
- quote(arg, &buf)
- }
- return buf.String()
-}
-
var globalTestID string
// TestDirectory creates a new temporary directory and returns its path.
@@ -313,7 +171,7 @@ var globalTestID string
// new directory.
func TestDirectory(templateDir string) (dir string, err error) {
if globalTestID == "" {
- globalTestID = stringutils.GenerateRandomString()[:4]
+ globalTestID = stringid.GenerateRandomID()[:4]
}
prefix := fmt.Sprintf("docker-test%s-%s-", globalTestID, GetCallerName(2))
if prefix == "" {
@@ -343,26 +201,6 @@ func GetCallerName(depth int) string {
return callerShortName
}
-func CopyFile(src, dst string) (int64, error) {
- if src == dst {
- return 0, nil
- }
- sf, err := os.Open(src)
- if err != nil {
- return 0, err
- }
- defer sf.Close()
- if err := os.Remove(dst); err != nil && !os.IsNotExist(err) {
- return 0, err
- }
- df, err := os.Create(dst)
- if err != nil {
- return 0, err
- }
- defer df.Close()
- return io.Copy(df, sf)
-}
-
// ReplaceOrAppendValues returns the defaults with the overrides either
// replaced by env key or appended to the list
func ReplaceOrAppendEnvValues(defaults, overrides []string) []string {
@@ -401,37 +239,6 @@ func ReplaceOrAppendEnvValues(defaults, overrides []string) []string {
return defaults
}
-func DoesEnvExist(name string) bool {
- for _, entry := range os.Environ() {
- parts := strings.SplitN(entry, "=", 2)
- if parts[0] == name {
- return true
- }
- }
- return false
-}
-
-// ReadSymlinkedDirectory returns the target directory of a symlink.
-// The target of the symbolic link may not be a file.
-func ReadSymlinkedDirectory(path string) (string, error) {
- var realPath string
- var err error
- if realPath, err = filepath.Abs(path); err != nil {
- return "", fmt.Errorf("unable to get absolute path for %s: %s", path, err)
- }
- if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
- return "", fmt.Errorf("failed to canonicalise path for %s: %s", path, err)
- }
- realPathInfo, err := os.Stat(realPath)
- if err != nil {
- return "", fmt.Errorf("failed to stat target '%s' of '%s': %s", realPath, path, err)
- }
- if !realPathInfo.Mode().IsDir() {
- return "", fmt.Errorf("canonical path points to a file '%s'", realPath)
- }
- return realPath, nil
-}
-
// ValidateContextDirectory checks if all the contents of the directory
// can be read and returns an error if some files can't be read
// symlinks which point to non-existing files don't trigger an error
@@ -476,15 +283,6 @@ func ValidateContextDirectory(srcPath string, excludes []string) error {
})
}
-func StringsContainsNoCase(slice []string, s string) bool {
- for _, ss := range slice {
- if strings.ToLower(s) == strings.ToLower(ss) {
- return true
- }
- }
- return false
-}
-
// Reads a .dockerignore file and returns the list of file patterns
// to ignore. Note this will trim whitespace from each line as well
// as use GO's "clean" func to get the shortest/cleanest path for each.
@@ -516,27 +314,6 @@ func ReadDockerIgnore(path string) ([]string, error) {
return excludes, nil
}
-// Wrap a concrete io.Writer and hold a count of the number
-// of bytes written to the writer during a "session".
-// This can be convenient when write return is masked
-// (e.g., json.Encoder.Encode())
-type WriteCounter struct {
- Count int64
- Writer io.Writer
-}
-
-func NewWriteCounter(w io.Writer) *WriteCounter {
- return &WriteCounter{
- Writer: w,
- }
-}
-
-func (wc *WriteCounter) Write(p []byte) (count int, err error) {
- count, err = wc.Writer.Write(p)
- wc.Count += int64(count)
- return
-}
-
// ImageReference combines `repo` and `ref` and returns a string representing
// the combination. If `ref` is a digest (meaning it's of the form
// :, the returned string is @[. Otherwise,
diff --git a/utils/utils_test.go b/utils/utils_test.go
index 94303a0e96819..2863009423dd5 100644
--- a/utils/utils_test.go
+++ b/utils/utils_test.go
@@ -1,9 +1,10 @@
package utils
import (
- "bytes"
+ "fmt"
+ "io/ioutil"
"os"
- "strings"
+ "path/filepath"
"testing"
)
@@ -25,104 +26,6 @@ func TestReplaceAndAppendEnvVars(t *testing.T) {
}
}
-// Reading a symlink to a directory must return the directory
-func TestReadSymlinkedDirectoryExistingDirectory(t *testing.T) {
- var err error
- if err = os.Mkdir("/tmp/testReadSymlinkToExistingDirectory", 0777); err != nil {
- t.Errorf("failed to create directory: %s", err)
- }
-
- if err = os.Symlink("/tmp/testReadSymlinkToExistingDirectory", "/tmp/dirLinkTest"); err != nil {
- t.Errorf("failed to create symlink: %s", err)
- }
-
- var path string
- if path, err = ReadSymlinkedDirectory("/tmp/dirLinkTest"); err != nil {
- t.Fatalf("failed to read symlink to directory: %s", err)
- }
-
- if path != "/tmp/testReadSymlinkToExistingDirectory" {
- t.Fatalf("symlink returned unexpected directory: %s", path)
- }
-
- if err = os.Remove("/tmp/testReadSymlinkToExistingDirectory"); err != nil {
- t.Errorf("failed to remove temporary directory: %s", err)
- }
-
- if err = os.Remove("/tmp/dirLinkTest"); err != nil {
- t.Errorf("failed to remove symlink: %s", err)
- }
-}
-
-// Reading a non-existing symlink must fail
-func TestReadSymlinkedDirectoryNonExistingSymlink(t *testing.T) {
- var path string
- var err error
- if path, err = ReadSymlinkedDirectory("/tmp/test/foo/Non/ExistingPath"); err == nil {
- t.Fatalf("error expected for non-existing symlink")
- }
-
- if path != "" {
- t.Fatalf("expected empty path, but '%s' was returned", path)
- }
-}
-
-// Reading a symlink to a file must fail
-func TestReadSymlinkedDirectoryToFile(t *testing.T) {
- var err error
- var file *os.File
-
- if file, err = os.Create("/tmp/testReadSymlinkToFile"); err != nil {
- t.Fatalf("failed to create file: %s", err)
- }
-
- file.Close()
-
- if err = os.Symlink("/tmp/testReadSymlinkToFile", "/tmp/fileLinkTest"); err != nil {
- t.Errorf("failed to create symlink: %s", err)
- }
-
- var path string
- if path, err = ReadSymlinkedDirectory("/tmp/fileLinkTest"); err == nil {
- t.Fatalf("ReadSymlinkedDirectory on a symlink to a file should've failed")
- }
-
- if path != "" {
- t.Fatalf("path should've been empty: %s", path)
- }
-
- if err = os.Remove("/tmp/testReadSymlinkToFile"); err != nil {
- t.Errorf("failed to remove file: %s", err)
- }
-
- if err = os.Remove("/tmp/fileLinkTest"); err != nil {
- t.Errorf("failed to remove symlink: %s", err)
- }
-}
-
-func TestWriteCounter(t *testing.T) {
- dummy1 := "This is a dummy string."
- dummy2 := "This is another dummy string."
- totalLength := int64(len(dummy1) + len(dummy2))
-
- reader1 := strings.NewReader(dummy1)
- reader2 := strings.NewReader(dummy2)
-
- var buffer bytes.Buffer
- wc := NewWriteCounter(&buffer)
-
- reader1.WriteTo(wc)
- reader2.WriteTo(wc)
-
- if wc.Count != totalLength {
- t.Errorf("Wrong count: %d vs. %d", wc.Count, totalLength)
- }
-
- if buffer.String() != dummy1+dummy2 {
- t.Error("Wrong message written")
- }
-}
-
func TestImageReference(t *testing.T) {
tests := []struct {
repo string
@@ -152,3 +55,46 @@ func TestDigestReference(t *testing.T) {
t.Errorf("Unexpected DigestReference=true for input %q", input)
}
}
+
+func TestReadDockerIgnore(t *testing.T) {
+ tmpDir, err := ioutil.TempDir("", "dockerignore-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpDir)
+
+ diName := filepath.Join(tmpDir, ".dockerignore")
+
+ di, err := ReadDockerIgnore(diName)
+ if err != nil {
+ t.Fatalf("Expected not to have error, got %s", err)
+ }
+
+ if diLen := len(di); diLen != 0 {
+ t.Fatalf("Expected to have zero dockerignore entry, got %d", diLen)
+ }
+
+ content := fmt.Sprintf("test1\n/test2\n/a/file/here\n\nlastfile")
+ err = ioutil.WriteFile(diName, []byte(content), 0777)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ di, err = ReadDockerIgnore(diName)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if di[0] != "test1" {
+ t.Fatalf("First element is not test1")
+ }
+ if di[1] != "/test2" {
+ t.Fatalf("Second element is not /test2")
+ }
+ if di[2] != "/a/file/here" {
+ t.Fatalf("Third element is not /a/file/here")
+ }
+ if di[3] != "lastfile" {
+ t.Fatalf("Fourth element is not lastfile")
+ }
+}
diff --git a/vendor/src/github.com/docker/distribution/registry/api/v2/descriptors.go b/vendor/src/github.com/docker/distribution/registry/api/v2/descriptors.go
new file mode 100644
index 0000000000000..5f091bbc927b6
--- /dev/null
+++ b/vendor/src/github.com/docker/distribution/registry/api/v2/descriptors.go
@@ -0,0 +1,1459 @@
+package v2
+
+import (
+ "net/http"
+ "regexp"
+
+ "github.com/docker/distribution/digest"
+)
+
+var (
+ nameParameterDescriptor = ParameterDescriptor{
+ Name: "name",
+ Type: "string",
+ Format: RepositoryNameRegexp.String(),
+ Required: true,
+ Description: `Name of the target repository.`,
+ }
+
+ tagParameterDescriptor = ParameterDescriptor{
+ Name: "tag",
+ Type: "string",
+ Format: TagNameRegexp.String(),
+ Required: true,
+ Description: `Tag of the target manifiest.`,
+ }
+
+ uuidParameterDescriptor = ParameterDescriptor{
+ Name: "uuid",
+ Type: "opaque",
+ Required: true,
+ Description: `A uuid identifying the upload. This field can accept almost anything.`,
+ }
+
+ digestPathParameter = ParameterDescriptor{
+ Name: "digest",
+ Type: "path",
+ Required: true,
+ Format: digest.DigestRegexp.String(),
+ Description: `Digest of desired blob.`,
+ }
+
+ hostHeader = ParameterDescriptor{
+ Name: "Host",
+ Type: "string",
+ Description: "Standard HTTP Host Header. Should be set to the registry host.",
+ Format: "",
+ Examples: []string{"registry-1.docker.io"},
+ }
+
+ authHeader = ParameterDescriptor{
+ Name: "Authorization",
+ Type: "string",
+ Description: "An RFC7235 compliant authorization header.",
+ Format: " ",
+ Examples: []string{"Bearer dGhpcyBpcyBhIGZha2UgYmVhcmVyIHRva2VuIQ=="},
+ }
+
+ authChallengeHeader = ParameterDescriptor{
+ Name: "WWW-Authenticate",
+ Type: "string",
+ Description: "An RFC7235 compliant authentication challenge header.",
+ Format: ` realm="", ..."`,
+ Examples: []string{
+ `Bearer realm="https://auth.docker.com/", service="registry.docker.com", scopes="repository:library/ubuntu:pull"`,
+ },
+ }
+
+ contentLengthZeroHeader = ParameterDescriptor{
+ Name: "Content-Length",
+ Description: "The `Content-Length` header must be zero and the body must be empty.",
+ Type: "integer",
+ Format: "0",
+ }
+
+ dockerUploadUUIDHeader = ParameterDescriptor{
+ Name: "Docker-Upload-UUID",
+ Description: "Identifies the docker upload uuid for the current request.",
+ Type: "uuid",
+ Format: "",
+ }
+
+ digestHeader = ParameterDescriptor{
+ Name: "Docker-Content-Digest",
+ Description: "Digest of the targeted content for the request.",
+ Type: "digest",
+ Format: "",
+ }
+
+ unauthorizedResponse = ResponseDescriptor{
+ Description: "The client does not have access to the repository.",
+ StatusCode: http.StatusUnauthorized,
+ Headers: []ParameterDescriptor{
+ authChallengeHeader,
+ {
+ Name: "Content-Length",
+ Type: "integer",
+ Description: "Length of the JSON error response body.",
+ Format: "",
+ },
+ },
+ ErrorCodes: []ErrorCode{
+ ErrorCodeUnauthorized,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: unauthorizedErrorsBody,
+ },
+ }
+
+ unauthorizedResponsePush = ResponseDescriptor{
+ Description: "The client does not have access to push to the repository.",
+ StatusCode: http.StatusUnauthorized,
+ Headers: []ParameterDescriptor{
+ authChallengeHeader,
+ {
+ Name: "Content-Length",
+ Type: "integer",
+ Description: "Length of the JSON error response body.",
+ Format: "",
+ },
+ },
+ ErrorCodes: []ErrorCode{
+ ErrorCodeUnauthorized,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: unauthorizedErrorsBody,
+ },
+ }
+)
+
+const (
+ manifestBody = `{
+ "name": ,
+ "tag": ,
+ "fsLayers": [
+ {
+ "blobSum":
+ },
+ ...
+ ]
+ ],
+ "history": ,
+ "signature":
+}`
+
+ errorsBody = `{
+ "errors:" [
+ {
+ "code": ,
+ "message": "",
+ "detail": ...
+ },
+ ...
+ ]
+}`
+
+ unauthorizedErrorsBody = `{
+ "errors:" [
+ {
+ "code": "UNAUTHORIZED",
+ "message": "access to the requested resource is not authorized",
+ "detail": ...
+ },
+ ...
+ ]
+}`
+)
+
+// APIDescriptor exports descriptions of the layout of the v2 registry API.
+var APIDescriptor = struct {
+ // RouteDescriptors provides a list of the routes available in the API.
+ RouteDescriptors []RouteDescriptor
+
+ // ErrorDescriptors provides a list of the error codes and their
+ // associated documentation and metadata.
+ ErrorDescriptors []ErrorDescriptor
+}{
+ RouteDescriptors: routeDescriptors,
+ ErrorDescriptors: errorDescriptors,
+}
+
+// RouteDescriptor describes a route specified by name.
+type RouteDescriptor struct {
+ // Name is the name of the route, as specified in RouteNameXXX exports.
+ // These names a should be considered a unique reference for a route. If
+ // the route is registered with gorilla, this is the name that will be
+ // used.
+ Name string
+
+ // Path is a gorilla/mux-compatible regexp that can be used to match the
+ // route. For any incoming method and path, only one route descriptor
+ // should match.
+ Path string
+
+ // Entity should be a short, human-readalbe description of the object
+ // targeted by the endpoint.
+ Entity string
+
+ // Description should provide an accurate overview of the functionality
+ // provided by the route.
+ Description string
+
+ // Methods should describe the various HTTP methods that may be used on
+ // this route, including request and response formats.
+ Methods []MethodDescriptor
+}
+
+// MethodDescriptor provides a description of the requests that may be
+// conducted with the target method.
+type MethodDescriptor struct {
+
+ // Method is an HTTP method, such as GET, PUT or POST.
+ Method string
+
+ // Description should provide an overview of the functionality provided by
+ // the covered method, suitable for use in documentation. Use of markdown
+ // here is encouraged.
+ Description string
+
+ // Requests is a slice of request descriptors enumerating how this
+ // endpoint may be used.
+ Requests []RequestDescriptor
+}
+
+// RequestDescriptor covers a particular set of headers and parameters that
+// can be carried out with the parent method. Its most helpful to have one
+// RequestDescriptor per API use case.
+type RequestDescriptor struct {
+ // Name provides a short identifier for the request, usable as a title or
+ // to provide quick context for the particalar request.
+ Name string
+
+ // Description should cover the requests purpose, covering any details for
+ // this particular use case.
+ Description string
+
+ // Headers describes headers that must be used with the HTTP request.
+ Headers []ParameterDescriptor
+
+ // PathParameters enumerate the parameterized path components for the
+ // given request, as defined in the route's regular expression.
+ PathParameters []ParameterDescriptor
+
+ // QueryParameters provides a list of query parameters for the given
+ // request.
+ QueryParameters []ParameterDescriptor
+
+ // Body describes the format of the request body.
+ Body BodyDescriptor
+
+ // Successes enumerates the possible responses that are considered to be
+ // the result of a successful request.
+ Successes []ResponseDescriptor
+
+ // Failures covers the possible failures from this particular request.
+ Failures []ResponseDescriptor
+}
+
+// ResponseDescriptor describes the components of an API response.
+type ResponseDescriptor struct {
+ // Name provides a short identifier for the response, usable as a title or
+ // to provide quick context for the particalar response.
+ Name string
+
+ // Description should provide a brief overview of the role of the
+ // response.
+ Description string
+
+ // StatusCode specifies the status recieved by this particular response.
+ StatusCode int
+
+ // Headers covers any headers that may be returned from the response.
+ Headers []ParameterDescriptor
+
+ // ErrorCodes enumerates the error codes that may be returned along with
+ // the response.
+ ErrorCodes []ErrorCode
+
+ // Body describes the body of the response, if any.
+ Body BodyDescriptor
+}
+
+// BodyDescriptor describes a request body and its expected content type. For
+// the most part, it should be example json or some placeholder for body
+// data in documentation.
+type BodyDescriptor struct {
+ ContentType string
+ Format string
+}
+
+// ParameterDescriptor describes the format of a request parameter, which may
+// be a header, path parameter or query parameter.
+type ParameterDescriptor struct {
+ // Name is the name of the parameter, either of the path component or
+ // query parameter.
+ Name string
+
+ // Type specifies the type of the parameter, such as string, integer, etc.
+ Type string
+
+ // Description provides a human-readable description of the parameter.
+ Description string
+
+ // Required means the field is required when set.
+ Required bool
+
+ // Format is a specifying the string format accepted by this parameter.
+ Format string
+
+ // Regexp is a compiled regular expression that can be used to validate
+ // the contents of the parameter.
+ Regexp *regexp.Regexp
+
+ // Examples provides multiple examples for the values that might be valid
+ // for this parameter.
+ Examples []string
+}
+
+// ErrorDescriptor provides relevant information about a given error code.
+type ErrorDescriptor struct {
+ // Code is the error code that this descriptor describes.
+ Code ErrorCode
+
+ // Value provides a unique, string key, often captilized with
+ // underscores, to identify the error code. This value is used as the
+ // keyed value when serializing api errors.
+ Value string
+
+ // Message is a short, human readable decription of the error condition
+ // included in API responses.
+ Message string
+
+ // Description provides a complete account of the errors purpose, suitable
+ // for use in documentation.
+ Description string
+
+ // HTTPStatusCodes provides a list of status under which this error
+ // condition may arise. If it is empty, the error condition may be seen
+ // for any status code.
+ HTTPStatusCodes []int
+}
+
+var routeDescriptors = []RouteDescriptor{
+ {
+ Name: RouteNameBase,
+ Path: "/v2/",
+ Entity: "Base",
+ Description: `Base V2 API route. Typically, this can be used for lightweight version checks and to validate registry authorization.`,
+ Methods: []MethodDescriptor{
+ {
+ Method: "GET",
+ Description: "Check that the endpoint implements Docker Registry API V2.",
+ Requests: []RequestDescriptor{
+ {
+ Headers: []ParameterDescriptor{
+ hostHeader,
+ authHeader,
+ },
+ Successes: []ResponseDescriptor{
+ {
+ Description: "The API implements V2 protocol and is accessible.",
+ StatusCode: http.StatusOK,
+ },
+ },
+ Failures: []ResponseDescriptor{
+ {
+ Description: "The client is not authorized to access the registry.",
+ StatusCode: http.StatusUnauthorized,
+ Headers: []ParameterDescriptor{
+ authChallengeHeader,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ ErrorCodes: []ErrorCode{
+ ErrorCodeUnauthorized,
+ },
+ },
+ {
+ Description: "The registry does not implement the V2 API.",
+ StatusCode: http.StatusNotFound,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ Name: RouteNameTags,
+ Path: "/v2/{name:" + RepositoryNameRegexp.String() + "}/tags/list",
+ Entity: "Tags",
+ Description: "Retrieve information about tags.",
+ Methods: []MethodDescriptor{
+ {
+ Method: "GET",
+ Description: "Fetch the tags under the repository identified by `name`.",
+ Requests: []RequestDescriptor{
+ {
+ Headers: []ParameterDescriptor{
+ hostHeader,
+ authHeader,
+ },
+ PathParameters: []ParameterDescriptor{
+ nameParameterDescriptor,
+ },
+ Successes: []ResponseDescriptor{
+ {
+ StatusCode: http.StatusOK,
+ Description: "A list of tags for the named repository.",
+ Headers: []ParameterDescriptor{
+ {
+ Name: "Content-Length",
+ Type: "integer",
+ Description: "Length of the JSON response body.",
+ Format: "",
+ },
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: `{
+ "name": ,
+ "tags": [
+ ,
+ ...
+ ]
+}`,
+ },
+ },
+ },
+ Failures: []ResponseDescriptor{
+ {
+ StatusCode: http.StatusNotFound,
+ Description: "The repository is not known to the registry.",
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ ErrorCodes: []ErrorCode{
+ ErrorCodeNameUnknown,
+ },
+ },
+ {
+ StatusCode: http.StatusUnauthorized,
+ Description: "The client does not have access to the repository.",
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ ErrorCodes: []ErrorCode{
+ ErrorCodeUnauthorized,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ Name: RouteNameManifest,
+ Path: "/v2/{name:" + RepositoryNameRegexp.String() + "}/manifests/{reference:" + TagNameRegexp.String() + "|" + digest.DigestRegexp.String() + "}",
+ Entity: "Manifest",
+ Description: "Create, update and retrieve manifests.",
+ Methods: []MethodDescriptor{
+ {
+ Method: "GET",
+ Description: "Fetch the manifest identified by `name` and `reference` where `reference` can be a tag or digest.",
+ Requests: []RequestDescriptor{
+ {
+ Headers: []ParameterDescriptor{
+ hostHeader,
+ authHeader,
+ },
+ PathParameters: []ParameterDescriptor{
+ nameParameterDescriptor,
+ tagParameterDescriptor,
+ },
+ Successes: []ResponseDescriptor{
+ {
+ Description: "The manifest idenfied by `name` and `reference`. The contents can be used to identify and resolve resources required to run the specified image.",
+ StatusCode: http.StatusOK,
+ Headers: []ParameterDescriptor{
+ digestHeader,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: manifestBody,
+ },
+ },
+ },
+ Failures: []ResponseDescriptor{
+ {
+ Description: "The name or reference was invalid.",
+ StatusCode: http.StatusBadRequest,
+ ErrorCodes: []ErrorCode{
+ ErrorCodeNameInvalid,
+ ErrorCodeTagInvalid,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ },
+ {
+ StatusCode: http.StatusUnauthorized,
+ Description: "The client does not have access to the repository.",
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ ErrorCodes: []ErrorCode{
+ ErrorCodeUnauthorized,
+ },
+ },
+ {
+ Description: "The named manifest is not known to the registry.",
+ StatusCode: http.StatusNotFound,
+ ErrorCodes: []ErrorCode{
+ ErrorCodeNameUnknown,
+ ErrorCodeManifestUnknown,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ Method: "PUT",
+ Description: "Put the manifest identified by `name` and `reference` where `reference` can be a tag or digest.",
+ Requests: []RequestDescriptor{
+ {
+ Headers: []ParameterDescriptor{
+ hostHeader,
+ authHeader,
+ },
+ PathParameters: []ParameterDescriptor{
+ nameParameterDescriptor,
+ tagParameterDescriptor,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: manifestBody,
+ },
+ Successes: []ResponseDescriptor{
+ {
+ Description: "The manifest has been accepted by the registry and is stored under the specified `name` and `tag`.",
+ StatusCode: http.StatusAccepted,
+ Headers: []ParameterDescriptor{
+ {
+ Name: "Location",
+ Type: "url",
+ Description: "The canonical location url of the uploaded manifest.",
+ Format: "",
+ },
+ contentLengthZeroHeader,
+ digestHeader,
+ },
+ },
+ },
+ Failures: []ResponseDescriptor{
+ {
+ Name: "Invalid Manifest",
+ Description: "The received manifest was invalid in some way, as described by the error codes. The client should resolve the issue and retry the request.",
+ StatusCode: http.StatusBadRequest,
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ ErrorCodes: []ErrorCode{
+ ErrorCodeNameInvalid,
+ ErrorCodeTagInvalid,
+ ErrorCodeManifestInvalid,
+ ErrorCodeManifestUnverified,
+ ErrorCodeBlobUnknown,
+ },
+ },
+ {
+ StatusCode: http.StatusUnauthorized,
+ Description: "The client does not have permission to push to the repository.",
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ ErrorCodes: []ErrorCode{
+ ErrorCodeUnauthorized,
+ },
+ },
+ {
+ Name: "Missing Layer(s)",
+ Description: "One or more layers may be missing during a manifest upload. If so, the missing layers will be enumerated in the error response.",
+ StatusCode: http.StatusBadRequest,
+ ErrorCodes: []ErrorCode{
+ ErrorCodeBlobUnknown,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: `{
+ "errors:" [{
+ "code": "BLOB_UNKNOWN",
+ "message": "blob unknown to registry",
+ "detail": {
+ "digest":
+ }
+ },
+ ...
+ ]
+}`,
+ },
+ },
+ {
+ StatusCode: http.StatusUnauthorized,
+ Headers: []ParameterDescriptor{
+ authChallengeHeader,
+ {
+ Name: "Content-Length",
+ Type: "integer",
+ Description: "Length of the JSON error response body.",
+ Format: "",
+ },
+ },
+ ErrorCodes: []ErrorCode{
+ ErrorCodeUnauthorized,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ Method: "DELETE",
+ Description: "Delete the manifest identified by `name` and `reference` where `reference` can be a tag or digest.",
+ Requests: []RequestDescriptor{
+ {
+ Headers: []ParameterDescriptor{
+ hostHeader,
+ authHeader,
+ },
+ PathParameters: []ParameterDescriptor{
+ nameParameterDescriptor,
+ tagParameterDescriptor,
+ },
+ Successes: []ResponseDescriptor{
+ {
+ StatusCode: http.StatusAccepted,
+ },
+ },
+ Failures: []ResponseDescriptor{
+ {
+ Name: "Invalid Name or Tag",
+ Description: "The specified `name` or `tag` were invalid and the delete was unable to proceed.",
+ StatusCode: http.StatusBadRequest,
+ ErrorCodes: []ErrorCode{
+ ErrorCodeNameInvalid,
+ ErrorCodeTagInvalid,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ },
+ {
+ StatusCode: http.StatusUnauthorized,
+ Headers: []ParameterDescriptor{
+ authChallengeHeader,
+ {
+ Name: "Content-Length",
+ Type: "integer",
+ Description: "Length of the JSON error response body.",
+ Format: "",
+ },
+ },
+ ErrorCodes: []ErrorCode{
+ ErrorCodeUnauthorized,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ },
+ {
+ Name: "Unknown Manifest",
+ Description: "The specified `name` or `tag` are unknown to the registry and the delete was unable to proceed. Clients can assume the manifest was already deleted if this response is returned.",
+ StatusCode: http.StatusNotFound,
+ ErrorCodes: []ErrorCode{
+ ErrorCodeNameUnknown,
+ ErrorCodeManifestUnknown,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+
+ {
+ Name: RouteNameBlob,
+ Path: "/v2/{name:" + RepositoryNameRegexp.String() + "}/blobs/{digest:" + digest.DigestRegexp.String() + "}",
+ Entity: "Blob",
+ Description: "Fetch the blob identified by `name` and `digest`. Used to fetch layers by tarsum digest.",
+ Methods: []MethodDescriptor{
+
+ {
+ Method: "GET",
+ Description: "Retrieve the blob from the registry identified by `digest`. A `HEAD` request can also be issued to this endpoint to obtain resource information without receiving all data.",
+ Requests: []RequestDescriptor{
+ {
+ Name: "Fetch Blob",
+ Headers: []ParameterDescriptor{
+ hostHeader,
+ authHeader,
+ },
+ PathParameters: []ParameterDescriptor{
+ nameParameterDescriptor,
+ digestPathParameter,
+ },
+ Successes: []ResponseDescriptor{
+ {
+ Description: "The blob identified by `digest` is available. The blob content will be present in the body of the request.",
+ StatusCode: http.StatusOK,
+ Headers: []ParameterDescriptor{
+ {
+ Name: "Content-Length",
+ Type: "integer",
+ Description: "The length of the requested blob content.",
+ Format: "",
+ },
+ digestHeader,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/octet-stream",
+ Format: "",
+ },
+ },
+ {
+ Description: "The blob identified by `digest` is available at the provided location.",
+ StatusCode: http.StatusTemporaryRedirect,
+ Headers: []ParameterDescriptor{
+ {
+ Name: "Location",
+ Type: "url",
+ Description: "The location where the layer should be accessible.",
+ Format: "",
+ },
+ digestHeader,
+ },
+ },
+ },
+ Failures: []ResponseDescriptor{
+ {
+ Description: "There was a problem with the request that needs to be addressed by the client, such as an invalid `name` or `tag`.",
+ StatusCode: http.StatusBadRequest,
+ ErrorCodes: []ErrorCode{
+ ErrorCodeNameInvalid,
+ ErrorCodeDigestInvalid,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ },
+ unauthorizedResponse,
+ {
+ Description: "The blob, identified by `name` and `digest`, is unknown to the registry.",
+ StatusCode: http.StatusNotFound,
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ ErrorCodes: []ErrorCode{
+ ErrorCodeNameUnknown,
+ ErrorCodeBlobUnknown,
+ },
+ },
+ },
+ },
+ {
+ Name: "Fetch Blob Part",
+ Description: "This endpoint may also support RFC7233 compliant range requests. Support can be detected by issuing a HEAD request. If the header `Accept-Range: bytes` is returned, range requests can be used to fetch partial content.",
+ Headers: []ParameterDescriptor{
+ hostHeader,
+ authHeader,
+ {
+ Name: "Range",
+ Type: "string",
+ Description: "HTTP Range header specifying blob chunk.",
+ Format: "bytes=-",
+ },
+ },
+ PathParameters: []ParameterDescriptor{
+ nameParameterDescriptor,
+ digestPathParameter,
+ },
+ Successes: []ResponseDescriptor{
+ {
+ Description: "The blob identified by `digest` is available. The specified chunk of blob content will be present in the body of the request.",
+ StatusCode: http.StatusPartialContent,
+ Headers: []ParameterDescriptor{
+ {
+ Name: "Content-Length",
+ Type: "integer",
+ Description: "The length of the requested blob chunk.",
+ Format: "",
+ },
+ {
+ Name: "Content-Range",
+ Type: "byte range",
+ Description: "Content range of blob chunk.",
+ Format: "bytes -/",
+ },
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/octet-stream",
+ Format: "",
+ },
+ },
+ },
+ Failures: []ResponseDescriptor{
+ {
+ Description: "There was a problem with the request that needs to be addressed by the client, such as an invalid `name` or `tag`.",
+ StatusCode: http.StatusBadRequest,
+ ErrorCodes: []ErrorCode{
+ ErrorCodeNameInvalid,
+ ErrorCodeDigestInvalid,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ },
+ unauthorizedResponse,
+ {
+ StatusCode: http.StatusNotFound,
+ ErrorCodes: []ErrorCode{
+ ErrorCodeNameUnknown,
+ ErrorCodeBlobUnknown,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ },
+ {
+ Description: "The range specification cannot be satisfied for the requested content. This can happen when the range is not formatted correctly or if the range is outside of the valid size of the content.",
+ StatusCode: http.StatusRequestedRangeNotSatisfiable,
+ },
+ },
+ },
+ },
+ },
+ // TODO(stevvooe): We may want to add a PUT request here to
+ // kickoff an upload of a blob, integrated with the blob upload
+ // API.
+ },
+ },
+
+ {
+ Name: RouteNameBlobUpload,
+ Path: "/v2/{name:" + RepositoryNameRegexp.String() + "}/blobs/uploads/",
+ Entity: "Intiate Blob Upload",
+ Description: "Initiate a blob upload. This endpoint can be used to create resumable uploads or monolithic uploads.",
+ Methods: []MethodDescriptor{
+ {
+ Method: "POST",
+ Description: "Initiate a resumable blob upload. If successful, an upload location will be provided to complete the upload. Optionally, if the `digest` parameter is present, the request body will be used to complete the upload in a single request.",
+ Requests: []RequestDescriptor{
+ {
+ Name: "Initiate Monolithic Blob Upload",
+ Description: "Upload a blob identified by the `digest` parameter in single request. This upload will not be resumable unless a recoverable error is returned.",
+ Headers: []ParameterDescriptor{
+ hostHeader,
+ authHeader,
+ {
+ Name: "Content-Length",
+ Type: "integer",
+ Format: "",
+ },
+ },
+ PathParameters: []ParameterDescriptor{
+ nameParameterDescriptor,
+ },
+ QueryParameters: []ParameterDescriptor{
+ {
+ Name: "digest",
+ Type: "query",
+ Format: "",
+ Regexp: digest.DigestRegexp,
+ Description: `Digest of uploaded blob. If present, the upload will be completed, in a single request, with contents of the request body as the resulting blob.`,
+ },
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/octect-stream",
+ Format: "",
+ },
+ Successes: []ResponseDescriptor{
+ {
+ Description: "The blob has been created in the registry and is available at the provided location.",
+ StatusCode: http.StatusCreated,
+ Headers: []ParameterDescriptor{
+ {
+ Name: "Location",
+ Type: "url",
+ Format: "",
+ },
+ contentLengthZeroHeader,
+ dockerUploadUUIDHeader,
+ },
+ },
+ },
+ Failures: []ResponseDescriptor{
+ {
+ Name: "Invalid Name or Digest",
+ StatusCode: http.StatusBadRequest,
+ ErrorCodes: []ErrorCode{
+ ErrorCodeDigestInvalid,
+ ErrorCodeNameInvalid,
+ },
+ },
+ unauthorizedResponsePush,
+ },
+ },
+ {
+ Name: "Initiate Resumable Blob Upload",
+ Description: "Initiate a resumable blob upload with an empty request body.",
+ Headers: []ParameterDescriptor{
+ hostHeader,
+ authHeader,
+ contentLengthZeroHeader,
+ },
+ PathParameters: []ParameterDescriptor{
+ nameParameterDescriptor,
+ },
+ Successes: []ResponseDescriptor{
+ {
+ Description: "The upload has been created. The `Location` header must be used to complete the upload. The response should be identical to a `GET` request on the contents of the returned `Location` header.",
+ StatusCode: http.StatusAccepted,
+ Headers: []ParameterDescriptor{
+ contentLengthZeroHeader,
+ {
+ Name: "Location",
+ Type: "url",
+ Format: "/v2//blobs/uploads/",
+ Description: "The location of the created upload. Clients should use the contents verbatim to complete the upload, adding parameters where required.",
+ },
+ {
+ Name: "Range",
+ Format: "0-0",
+ Description: "Range header indicating the progress of the upload. When starting an upload, it will return an empty range, since no content has been received.",
+ },
+ dockerUploadUUIDHeader,
+ },
+ },
+ },
+ Failures: []ResponseDescriptor{
+ {
+ Name: "Invalid Name or Digest",
+ StatusCode: http.StatusBadRequest,
+ ErrorCodes: []ErrorCode{
+ ErrorCodeDigestInvalid,
+ ErrorCodeNameInvalid,
+ },
+ },
+ unauthorizedResponsePush,
+ },
+ },
+ },
+ },
+ },
+ },
+
+ {
+ Name: RouteNameBlobUploadChunk,
+ Path: "/v2/{name:" + RepositoryNameRegexp.String() + "}/blobs/uploads/{uuid}",
+ Entity: "Blob Upload",
+ Description: "Interact with blob uploads. Clients should never assemble URLs for this endpoint and should only take it through the `Location` header on related API requests. The `Location` header and its parameters should be preserved by clients, using the latest value returned via upload related API calls.",
+ Methods: []MethodDescriptor{
+ {
+ Method: "GET",
+ Description: "Retrieve status of upload identified by `uuid`. The primary purpose of this endpoint is to resolve the current status of a resumable upload.",
+ Requests: []RequestDescriptor{
+ {
+ Description: "Retrieve the progress of the current upload, as reported by the `Range` header.",
+ Headers: []ParameterDescriptor{
+ hostHeader,
+ authHeader,
+ },
+ PathParameters: []ParameterDescriptor{
+ nameParameterDescriptor,
+ uuidParameterDescriptor,
+ },
+ Successes: []ResponseDescriptor{
+ {
+ Name: "Upload Progress",
+ Description: "The upload is known and in progress. The last received offset is available in the `Range` header.",
+ StatusCode: http.StatusNoContent,
+ Headers: []ParameterDescriptor{
+ {
+ Name: "Range",
+ Type: "header",
+ Format: "0-",
+ Description: "Range indicating the current progress of the upload.",
+ },
+ contentLengthZeroHeader,
+ dockerUploadUUIDHeader,
+ },
+ },
+ },
+ Failures: []ResponseDescriptor{
+ {
+ Description: "There was an error processing the upload and it must be restarted.",
+ StatusCode: http.StatusBadRequest,
+ ErrorCodes: []ErrorCode{
+ ErrorCodeDigestInvalid,
+ ErrorCodeNameInvalid,
+ ErrorCodeBlobUploadInvalid,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ },
+ unauthorizedResponse,
+ {
+ Description: "The upload is unknown to the registry. The upload must be restarted.",
+ StatusCode: http.StatusNotFound,
+ ErrorCodes: []ErrorCode{
+ ErrorCodeBlobUploadUnknown,
+ },
+ Body: BodyDescriptor{
+ ContentType: "application/json; charset=utf-8",
+ Format: errorsBody,
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ Method: "PATCH",
+ Description: "Upload a chunk of data for the specified upload.",
+ Requests: []RequestDescriptor{
+ {
+ Description: "Upload a chunk of data to specified upload without completing the upload.",
+ PathParameters: []ParameterDescriptor{
+ nameParameterDescriptor,
+ uuidParameterDescriptor,
+ },
+ Headers: []ParameterDescriptor{
+ hostHeader,
+ authHeader,
+ {
+ Name: "Content-Range",
+ Type: "header",
+ Format: "-",
+ Required: true,
+ Description: "Range of bytes identifying the desired block of content represented by the body. Start must the end offset retrieved via status check plus one. Note that this is a non-standard use of the `Content-Range` header.",
+ },
+ {
+ Name: "Content-Length",
+ Type: "integer",
+ Format: "]