Compare commits

...

214 Commits

Author SHA1 Message Date
Andrew Hsu
eb137ff176 Merge pull request #240 from seemethere/bundle_me_up_1809
[18.09-ce] [ENGSEC-30] CVE-2019-5736 apply fix via git bundle instead of patches
2019-02-06 15:39:49 -08:00
Eli Uriegas
03dfb0ba53 Apply git bundles for CVE-2019-5736
A git bundle allows us keep the same SHA, giving us the ability to
validate our patch against a known entity and allowing us to push
directly from our private forks to public forks without having to
re-apply any patches.

Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2019-02-06 00:25:54 +00:00
Jameson Hyde
a79fabbfe8 If url includes scheme, urlPath will drop hostname, which would not match the auth check
Signed-off-by: Jameson Hyde <jameson.hyde@docker.com>
(cherry picked from commit 754fb8d9d03895ae3ab60d2ad778152b0d835206)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2019-01-09 17:31:53 +00:00
Jameson Hyde
fc274cd2ff Authz plugin security fixes for 0-length content and path validation Signed-off-by: Jameson Hyde <jameson.hyde@docker.com>
fix comments

(cherry picked from commit 9659c3a52bac57e615b5fb49b0652baca448643e)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2019-01-09 17:31:53 +00:00
Eli Uriegas
d4f336d8ef Merge pull request #144 from thaJeztah/18.09_backport_bump_containerd_v1.2.2
[18.09 backport] Bump containerd to v1.2.2
2019-01-08 10:05:03 -08:00
Sebastiaan van Stijn
f80c6d7ae1 Bump containerd to v1.2.2
- Fix a bug that a container can't be stopped or inspected when its corresponding image is deleted
- Fix a bug that the cri plugin handles containerd events outside of k8s.io namespace

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 27cc170d28)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-01-08 02:45:06 +01:00
Sebastiaan van Stijn
ce8b8f1cf3 Merge pull request #142 from docker/revert-130-18.09_backport_fix_api_return_code
Revert "[18.09 backport] API: fix status code on conflicting service names"
2018-12-28 21:50:02 +01:00
Madhu Venugopal
24f71e3998 Revert "[18.09 backport] API: fix status code on conflicting service names"
Signed-off-by: Madhu Venugopal <madhu@docker.com>
2018-12-28 09:40:26 -08:00
Andrew Hsu
484a3c3ad0 Merge pull request #140 from andrewhsu/d
[18.09] libcontainerd: prevent exec delete locking
2018-12-17 16:15:27 +01:00
Tonis Tiigi
6646d08782 libcontainerd: prevent exec delete locking
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit 332f134890)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2018-12-17 12:07:32 +00:00
Andrew Hsu
a9ae6c7547 Revert "Propagate context to exec delete"
This reverts commit b6430ba413.

Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2018-12-17 12:06:35 +00:00
Andrew Hsu
cc7773c787 Merge pull request #139 from andrewhsu/ctxt
[18.09] Propagate context to exec delete
2018-12-16 11:14:58 +00:00
Andrew Hsu
b2185081d9 Merge pull request #138 from andrewhsu/cont
[18.09] Update containerd to aa5e000c963756778ab3ebd1a12c6
2018-12-16 11:14:33 +00:00
Andrew Hsu
a6d4103450 Merge pull request #137 from thaJeztah/18.09_bump_golang_1.10.6
[18.09] Bump Golang 1.10.6 (CVE-2018-16875)
2018-12-14 23:23:09 +00:00
Michael Crosby
b6430ba413 Propagate context to exec delete
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
(cherry picked from commit 96e0ba1afb)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2018-12-14 22:54:46 +00:00
Michael Crosby
d161dfe1a3 Update containerd to aa5e000c963756778ab3ebd1a12c6
This includes a patch on top of containerd 1.2.1 to handle fifo
timeouts.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
(cherry picked from commit e5d9d72162)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2018-12-14 22:47:44 +00:00
Sebastiaan van Stijn
8afe9f422d Bump Golang 1.10.6 (CVE-2018-16875)
go1.10.6 (released 2018/12/14)

- crypto/x509: CPU denial of service in chain validation golang/go#29233
- cmd/go: directory traversal in "go get" via curly braces in import paths golang/go#29231
- cmd/go: remote command execution during "go get -u" golang/go#29230

See the Go 1.10.6 milestone on the issue tracker for details:
https://github.com/golang/go/issues?q=milestone%3AGo1.10.6

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-12-14 00:44:49 +01:00
Andrew Hsu
42b58273f6 Merge pull request #130 from thaJeztah/18.09_backport_fix_api_return_code
[18.09 backport] API: fix status code on conflicting service names
2018-12-13 10:54:52 +00:00
Andrew Hsu
a8572d3e8e Merge pull request #132 from thaJeztah/18.09_backport_idprefix
[18.09 backport] fixes display text in Multiple IDs found with provided prefix
2018-12-13 10:53:54 +00:00
Andrew Hsu
01c732d40a Merge pull request #136 from thaJeztah/18.09_backport_fix_panic
[18.09 engine] registry: use len(via)!=0 instead of via!=nil
2018-12-13 10:43:38 +00:00
Iskander (Alex) Sharipov
3482a3b14a registry: use len(via)!=0 instead of via!=nil
This avoids the corner case where `via` is not nil, but has a length of 0,
so the updated code does not panic in that situation.

Signed-off-by: Iskander Sharipov <quasilyte@gmail.com>
(cherry picked from commit a5c185b994)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-12-12 18:12:01 +01:00
Andrew Hsu
1ffccb515a Merge pull request #133 from thaJeztah/18.09_backport_fix_ipam_swagger
[18.09 backport] Swagger: fix definition of IPAM driver options
2018-12-12 16:24:46 +00:00
Sebastiaan van Stijn
55a4be8cf5 Swagger: fix definition of IPAM driver options
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit a5dd68186c)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-12-12 01:59:01 +01:00
Lifubang
1043f40fb5 fixes display text in Multiple IDs found with provided prefix
Signed-off-by: Lifubang <lifubang@acmcoder.com>
(cherry picked from commit 00eb3480dc)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-12-11 15:15:20 +01:00
Andrew Hsu
d21754a3fb Merge pull request #131 from tonistiigi/1809-update-buildkit
[18.09 backport] vendor: update buildkit to d9f75920
2018-12-10 16:29:04 +00:00
Andrew Hsu
b54b6d145c Merge pull request #129 from thaJeztah/18.09_backport_bump_containerd_vendoring
[18.09 backport] update containerd vendoring to v1.2.1
2018-12-10 13:54:05 +00:00
Tonis Tiigi
43dedf3975 vendor: update buildkit to d9f75920
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit 32f4805815)
2018-12-10 13:03:13 +00:00
Sebastiaan van Stijn
a69626afb1 Add test for status code on conflicting service names
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit b0de11cf30)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-12-10 12:21:26 +01:00
Sebastiaan van Stijn
ad7105260f Update swarmkit to return correct error-codes on conflicting names
This updates the swarmkit vendoring to the latest version in the bump_v18.09
branch

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-12-10 12:18:32 +01:00
Andrew Hsu
b66c7ad62e use empty string as cgroup path to grab first find
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 78045a5419)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-12-07 18:58:03 +01:00
Andrew Hsu
5cd4797c89 vndr libnetwork to adjust for updated runc
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 75c4b74155)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-12-07 18:57:54 +01:00
Andrew Hsu
7dfd23acf1 update containerd to v1.2.1
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 615eecf8ac)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-12-07 18:45:14 +01:00
Andrew Hsu
6c633fbe18 Merge pull request #128 from thaJeztah/18.09_backport_containerd_v1.2.1-GA
[18.09 backport] update just installer of containerd to 1.2.1
2018-12-07 06:18:48 -08:00
Andrew Hsu
2c64d7c858 update just installer of containerd to 1.2.1
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
(cherry picked from commit 1014b2bb66)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-12-07 11:20:22 +01:00
Andrew Hsu
82a4418f57 Merge pull request #126 from thaJeztah/18.09_backport_mask_asound
[18.09 backport] Masked /proc/asound
2018-12-03 14:06:43 -08:00
Andrew Hsu
e7a4385e24 Merge pull request #123 from tonistiigi/1809-builder-net
[18.09] builder: set externalkey option for faster hook processing
2018-11-30 14:02:12 -08:00
Andrew Hsu
09251ef9ca Merge pull request #127 from thaJeztah/18.09_bump_go_to_1.10.5
[18.09] Bump Go to 1.10.5
2018-11-30 13:59:38 -08:00
Sebastiaan van Stijn
00ad8e7c57 Bump Go to 1.10.5
go1.10.5 (released 2018/11/02) includes fixes to the go command, linker,
runtime and the database/sql package. See the milestone on the issue
tracker for details:

List of changes; https://github.com/golang/go/issues?q=milestone%3AGo1.10.5

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-30 20:43:05 +01:00
Jonathan A. Schweder
5fffdb3226 Masked /proc/asound
@sw-pschmied originally post this in #38285

While looking through the Moby source code was found /proc/asound to be
shared with containers as read-only (as defined in
https://github.com/moby/moby/blob/master/oci/defaults.go#L128).

This can lead to two information leaks.

---

**Leak of media playback status of the host**

Steps to reproduce the issue:

 - Listen to music/Play a YouTube video/Do anything else that involves
sound output
 - Execute docker run --rm ubuntu:latest bash -c "sleep 7; cat
/proc/asound/card*/pcm*p/sub*/status | grep state | cut -d ' ' -f2 |
grep RUNNING || echo 'not running'"
 - See that the containerized process is able to check whether someone
on the host is playing music as it prints RUNNING
 - Stop the music output
 - Execute the command again (The sleep is delaying the output because
information regarding playback status isn't propagated instantly)
 - See that it outputs not running

**Describe the results you received:**

A containerized process is able to gather information on the playback
status of an audio device governed by the host. Therefore a process of a
container is able to check whether and what kind of user activity is
present on the host system. Also, this may indicate whether a container
runs on a desktop system or a server as media playback rarely happens on
server systems.

The description above is in regard to media playback - when examining
`/proc/asound/card*/pcm*c/sub*/status` (`pcm*c` instead of `pcm*p`) this
can also leak information regarding capturing sound, as in recording
audio or making calls on the host system.

Signed-off-by: Jonathan A. Schweder <jonathanschweder@gmail.com>

(cherry picked from commit 64e52ff3db)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-30 14:57:51 +01:00
Andrew Hsu
e32fc16daa Merge pull request #125 from thaJeztah/18.09_backport_busybox
[18.09 backport] Windows: Tie busybox to specific version
2018-11-29 22:46:29 -08:00
John Howard
9c93de59da Windows:Tie busybox to version
Signed-off-by: John Howard <jhoward@microsoft.com>
(cherry picked from commit 14c8b67e51)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-30 01:38:11 +01:00
Tonis Tiigi
73911117b3 builder: delete sandbox in a goroutine for performance
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit bcf1967dd0)
2018-11-29 09:15:15 -08:00
Tonis Tiigi
8fe3b4d2ec builder: set externalkey option for faster hook processing
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit 1ad272c7e4)
2018-11-29 09:15:00 -08:00
Andrew Hsu
a1f6b04a8d Merge pull request #81 from thaJeztah/18.09_backport_processandiot
[18.09 backport] Windows:Allow process isolation
2018-11-27 09:58:22 -08:00
Andrew Hsu
7a566c0e4a Merge pull request #85 from thaJeztah/18.09_backport_deprecated_storagedrivers
[18.09 backport] deprecate legacy "overlay", and "devicemapper" storage drivers
2018-11-27 09:57:46 -08:00
Andrew Hsu
61a250fd23 Merge pull request #107 from thaJeztah/18.09_backport_bump_libnetwork
[18.09 backport] update libnetwork to fix iptables compatibility on debian
2018-11-27 09:55:12 -08:00
Andrew Hsu
8f18feabeb Merge pull request #110 from thaJeztah/18.09_backport_handle_invalid_json
[18.09 backport] API: properly handle invalid JSON to return a 400 status
2018-11-27 09:51:54 -08:00
Andrew Hsu
08a77f11a6 Merge pull request #112 from thaJeztah/18.09_backport_moby_37747
[18.09 backport] awslogs: account for UTF-8 normalization in limits
2018-11-27 09:48:39 -08:00
Andrew Hsu
4fd103ae26 Merge pull request #113 from thaJeztah/18.09_backport_detach
[18.09 backport] Windows: DetachVhd attempt in cleanup
2018-11-27 09:47:07 -08:00
Andrew Hsu
52a6fc02b1 Merge pull request #114 from thaJeztah/18.09_backport_limit_client_readall
[18.09 backport] client: use io.LimitedReader for reading HTTP error
2018-11-27 09:44:42 -08:00
Andrew Hsu
12b8ec42b6 Merge pull request #116 from thaJeztah/18.09_backport_apparmor_external_templates
[18.09 backport] apparmor: allow receiving of signals from 'docker kill'
2018-11-27 09:41:37 -08:00
Andrew Hsu
23122e4d52 Merge pull request #118 from thaJeztah/18.09_backport_fence_default_addr_pools
[18.09 backport] Ignore default address-pools on API < 1.39
2018-11-27 09:38:39 -08:00
Andrew Hsu
04a6b49a89 Merge pull request #119 from thaJeztah/18.09_backport_fix_default_addr_pools_swagger
[18.09 backport] Add missing default address pool fields to swagger
2018-11-27 09:36:52 -08:00
Andrew Hsu
c488cf7e95 Merge pull request #120 from thaJeztah/18.09_backport_check_for_more_ipvs_options
[18.09 backport] Add CONFIG_IP_VS_PROTO_TCP, CONFIG_IP_VS_PROTO_UDP, IP_NF_TARGET_REDIRECT to check-config.sh
2018-11-27 09:35:55 -08:00
Andrew Hsu
c95cf2a5d3 Merge pull request #121 from thaJeztah/18.09_backport_containerd_v1.2.1
[18.09 backport] Update containerd to v1.2.1-rc.0
2018-11-27 09:15:48 -08:00
Andrew Hsu
9606931393 Merge pull request #122 from tonistiigi/buildkit-18091
[18.09 backport] BuildKit fixes for 18.09.1
2018-11-26 15:56:38 -08:00
Tonis Tiigi
850fff5fc7 vendor: update buildkit to v0.3.3
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit 6204eb0645)
2018-11-21 14:10:01 -08:00
Tonis Tiigi
0d17f40994 builder: avoid unset credentials in containerd
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit effb2bd9d2)
2018-11-21 14:09:31 -08:00
Tibor Vass
34867646af builder: ignore label and label! prune filters
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit 62923f29f5)
2018-11-21 14:08:18 -08:00
Tibor Vass
0b2d88d328 builder: deprecate prune filter unused-for in favor of until
This is to keep the UX consistent. `unused-for` is still accepted and a synonym.

Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit 369da264ba)
2018-11-21 14:08:04 -08:00
Eli Uriegas
27b0fee846 Merge pull request #84 from thaJeztah/18.09_backport_ovr2_index
[18.09 backport] overlay2: use index=off if possible (fix EBUSY on mount)
2018-11-21 15:46:01 -06:00
Sebastiaan van Stijn
4cc45d91eb Ignore default address-pools on API < 1.39
These options were added in API 1.39, so should be ignored
when using an older version of the API.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 7632ccbc66)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-21 22:15:18 +01:00
Aleksa Sarai
67c602c3fe apparmor: allow receiving of signals from 'docker kill'
In newer kernels, AppArmor will reject attempts to send signals to a
container because the signal originated from outside of that AppArmor
profile. Correct this by allowing all unconfined signals to be received.

Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
Signed-off-by: Aleksa Sarai <asarai@suse.de>
(cherry picked from commit 4822fb1e24)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-21 22:13:56 +01:00
Sebastiaan van Stijn
db7f375d6a Update containerd to v1.2.1-rc.0
The previous update used a commit from master. Now that
all the fixes are backported to the containerd 1.2 release
branch, we can switch back to that branch.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 2fb5de68a9)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-21 21:59:41 +01:00
Michael Crosby
7d6ec38402 wip: bump containerd and runc version
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
(cherry picked from commit d13528c635)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-21 21:59:33 +01:00
Sebastiaan van Stijn
64a05e3d16 Bump containerd binary to fix shim hang
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 7af4c904b3)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-21 21:59:27 +01:00
Sebastiaan van Stijn
262abed3d2 Update runc to 58592df56734acf62e574865fe40b9e53e967910
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit fc0038a3ed)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-21 21:59:20 +01:00
Sebastiaan van Stijn
e137337fe6 Update containerd to v1.2.0
release notes: https://github.com/containerd/containerd/releases/tag/v1.2.0

- New V2 Runtime with a stable gRPC interface for managing containers through
  external shims.
- Updated CRI Plugin, validated against Kubernetes v1.11 and v1.12, but it is
  also compatible with Kubernetes v1.10.
- Support for Kubernetes Runtime Class, introduced in Kubernetes 1.12
- A new proxy plugin configuration has been added to allow external
  snapshotters be connected to containerd using gRPC.-
- A new Install method on the containerd client allows users to publish host
  level binaries using standard container build tooling and container
  distribution tooling to download containerd related binaries on their systems.
- Add support for cleaning up leases and content ingests to garbage collections.
- Improved multi-arch image support using more precise matching and ranking
- Added a runtime `options` field for shim v2 runtime. Use the `options` field to
  config runtime specific options, e.g. `NoPivotRoot` and `SystemdCgroup` for
  runtime type `io.containerd.runc.v1`.
- Some Minor API additions
  - Add `ListStream` method to containers API. This allows listing a larger
    number of containers without hitting message size limts.
  - Add `Sync` flag to `Delete` in leases API. Setting this option will ensure
    a garbage collection completes before the removal call is returned. This can
    be used to guarantee unreferenced objects are removed from disk after a lease.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 8674930c84)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-21 21:59:13 +01:00
Sebastiaan van Stijn
c9c87d76d6 Add a note about updating runc / runc vendoring
Containerd should be "leading" when specifying which version of runc to use.
From the RUNC.MD document in the containerd repository
(https://github.com/containerd/containerd/blob/b1e202c32724e82779544365528a1a082
b335553/RUNC.md);

> We depend on a specific runc version when dealing with advanced features. You
> should have a specific runc build for development. The current supported runc
> commit is described in vendor.conf. Please refer to the line that starts with
> github.com/opencontainers/runc.

This patch adds a note to vendor.conf and runc.installer to describe the order
in which runc should be updated.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit da3810d235)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-21 21:59:06 +01:00
Sebastiaan van Stijn
a4decd0c4c Update containerd to v1.1.4
Fixes a potential content store bug, backported from 1.2

- v1.1.3 release notes: https://github.com/containerd/containerd/releases/tag/v1.1.3
- v1.1.4 release notes: https://github.com/containerd/containerd/releases/tag/v1.1.4

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit b3c3c7a5a3)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-21 21:58:58 +01:00
Sebastiaan van Stijn
25bec4665b Add CONFIG_IP_VS_PROTO_TCP, CONFIG_IP_VS_PROTO_UDP, IP_NF_TARGET_REDIRECT to check-config.sh
On kernels without this options set, publishing ports for swarm
services does not work, making the published port not accessible
("connection refused")

Thanks to Wenbo Wang for reporting, and Tianon for finding this.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 44e1c6ce81)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-20 18:08:44 +01:00
Sebastiaan van Stijn
56cc26f927 Add missing default address pool fields to swagger
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 2e8c913dbd)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-20 15:50:46 +01:00
Andrew Hsu
4980e48e4b Merge pull request #109 from thaJeztah/18.09_backport_cleanup_volume_tests
[18.09 backport] Cleanup volume integration tests
2018-11-14 15:41:13 -08:00
Andrew Hsu
299385de7f Merge pull request #103 from thaJeztah/18.09_backport_fix_double_scheme
[18.09 backport] Fix double "unix://" scheme in TestInfoAPIWarnings
2018-11-14 15:39:54 -08:00
Kir Kolyshkin
8486ea11ae runc.installer: add nokmem build tag for rhel7 kernel
In case we're running on RHEL7 kernel, which has non-working
and broken kernel memory controller, add 'nokmem' build tag
so that runc never enables kmem accounting.

For more info, see the following runc commit:
https://github.com/opencontainers/runc/commit/6a2c1559684

This behavior can be overriden by having `RUNC_NOKMEM` environment
variable set (e.g. to empty value to disable setting nokmem).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 8972aa9350)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-12 15:51:52 +01:00
Kir Kolyshkin
5b8cee93b5 Bump runc
Changes: a00bf01908...9f1e94488e

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 335736fb01)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-12 15:51:44 +01:00
Akihiro Suda
49556e0470 client: use io.LimitedReader for reading HTTP error
client.checkResponseErr() was hanging and consuming infinite memory
when the serverResp.Body io.Reader returns infinite stream.

This commit prohibits reading more than 1MiB.

Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
(cherry picked from commit 1db4be0c32)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-12 11:44:37 +01:00
John Howard
02fe71843e Windows: DetachVhd attempt in cleanup
Signed-off-by: John Howard <jhoward@microsoft.com>

This is a fix for a few related scenarios where it's impossible to remove layers or containers
until the host is rebooted. Generally (or at least easiest to repro) through a forced daemon kill
while a container is running.

Possibly slightly worse than that, as following a host reboot, the scratch layer would possibly be leaked and
left on disk under the dataroot\windowsfilter directory after the container is removed.

One such example of a failure:

1. run a long running container with the --rm flag
docker run --rm -d --name test microsoft/windowsservercore powershell sleep 30
2. Force kill the daemon not allowing it to cleanup. Simulates a crash or a host power-cycle.
3. (re-)Start daemon
4. docker ps -a
PS C:\control> docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                PORTS               NAMES
7aff773d782b        malloc              "powershell start-sl…"   11 seconds ago      Removal In Progress                       malloc
5. Try to remove
PS C:\control> docker rm 7aff
Error response from daemon: container 7aff773d782bbf35d95095369ffcb170b7b8f0e6f8f65d5aff42abf61234855d: driver "windowsfilter" failed to remove root filesystem: rename C:\control\windowsfilter\7aff773d782bbf35d95095369ffcb170b7b8f0e6f8f65d5aff42abf61234855d C:\control\windowsfilter\7aff773d782bbf35d95095369ffcb170b7b8f0e6f8f65d5aff42abf61234855d-removing: Access is denied.
PS C:\control>

Step 5 fails.

(cherry picked from commit efdad53744)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-09 23:31:49 +01:00
Samuel Karp
757650e8dc awslogs: account for UTF-8 normalization in limits
The CloudWatch Logs API defines its limits in terms of bytes, but its
inputs in terms of UTF-8 encoded strings.  Byte-sequences which are not
valid UTF-8 encodings are normalized to the Unicode replacement
character U+FFFD, which is a 3-byte sequence in UTF-8.  This replacement
can cause the input to grow, exceeding the API limit and causing failed
API calls.

This commit adds logic for counting the effective byte length after
normalization and splitting input without splitting valid UTF-8
byte-sequences into two invalid byte-sequences.

Fixes https://github.com/moby/moby/issues/37747

Signed-off-by: Samuel Karp <skarp@amazon.com>
(cherry picked from commit 1e8ef38627)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-08 15:26:01 +01:00
Sebastiaan van Stijn
9e06a42123 API: properly handle invalid JSON to return a 400 status
The API did not treat invalid JSON payloads as a 400 error, as a result
returning a 500 error;

Before this change, an invalid JSON body would return a 500 error;

```bash
curl -v \
  --unix-socket /var/run/docker.sock \
  -X POST \
  "http://localhost/v1.30/networks/create" \
  -H "Content-Type: application/json" \
  -d '{invalid json'
```

```
> POST /v1.30/networks/create HTTP/1.1
> Host: localhost
> User-Agent: curl/7.52.1
> Accept: */*
> Content-Type: application/json
> Content-Length: 13
>
* upload completely sent off: 13 out of 13 bytes
< HTTP/1.1 500 Internal Server Error
< Api-Version: 1.40
< Content-Type: application/json
< Docker-Experimental: false
< Ostype: linux
< Server: Docker/dev (linux)
< Date: Mon, 05 Nov 2018 11:55:20 GMT
< Content-Length: 79
<
{"message":"invalid character 'i' looking for beginning of object key string"}
```

Empty request:

```bash
curl -v \
  --unix-socket /var/run/docker.sock \
  -X POST \
  "http://localhost/v1.30/networks/create" \
  -H "Content-Type: application/json"
```

```
> POST /v1.30/networks/create HTTP/1.1
> Host: localhost
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Type: application/json
>
< HTTP/1.1 500 Internal Server Error
< Api-Version: 1.38
< Content-Length: 18
< Content-Type: application/json
< Date: Mon, 05 Nov 2018 12:00:18 GMT
< Docker-Experimental: true
< Ostype: linux
< Server: Docker/18.06.1-ce (linux)
<
{"message":"EOF"}
```

After this change, a 400 is returned;

```bash
curl -v \
  --unix-socket /var/run/docker.sock \
  -X POST \
  "http://localhost/v1.30/networks/create" \
  -H "Content-Type: application/json" \
  -d '{invalid json'
```

```
> POST /v1.30/networks/create HTTP/1.1
> Host: localhost
> User-Agent: curl/7.52.1
> Accept: */*
> Content-Type: application/json
> Content-Length: 13
>
* upload completely sent off: 13 out of 13 bytes
< HTTP/1.1 400 Bad Request
< Api-Version: 1.40
< Content-Type: application/json
< Docker-Experimental: false
< Ostype: linux
< Server: Docker/dev (linux)
< Date: Mon, 05 Nov 2018 11:57:15 GMT
< Content-Length: 79
<
{"message":"invalid character 'i' looking for beginning of object key string"}
```

Empty request:

```bash
curl -v \
  --unix-socket /var/run/docker.sock \
  -X POST \
  "http://localhost/v1.30/networks/create" \
  -H "Content-Type: application/json"
```

```
> POST /v1.30/networks/create HTTP/1.1
> Host: localhost
> User-Agent: curl/7.52.1
> Accept: */*
> Content-Type: application/json
>
< HTTP/1.1 400 Bad Request
< Api-Version: 1.40
< Content-Type: application/json
< Docker-Experimental: false
< Ostype: linux
< Server: Docker/dev (linux)
< Date: Mon, 05 Nov 2018 11:59:22 GMT
< Content-Length: 49
<
{"message":"got EOF while reading request body"}
```

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit c7b488fbc8)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-08 14:01:27 +01:00
Sebastiaan van Stijn
e8eb3ca4ee Enable volume tests on Windows
These tests don't seem to have anything Linux-specific,
so enable them on Windows

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit b334198e65)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-08 14:00:20 +01:00
Sebastiaan van Stijn
673f04f0b1 Integration test: use filepath.Join() to make path cross-platform
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 05e18429cf)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-08 14:00:14 +01:00
Sebastiaan van Stijn
65bf95f3df Some improvements to TestVolumesInspect
Some improvements in this test;

- use the volume-information that's returned by VolumeCreate as "expected"
- don't use an explict name for the volume, as it was only used to reference
  the volume for inspection
- improve the test-output on failure, so that "expected" and "actual" values
  are printed

Without this patch applied;

    === RUN   TestVolumesInspect
    --- FAIL: TestVolumesInspect (0.02s)
     	volume_test.go:108: assertion failed: false (bool) != true (true bool): Time Volume is CreatedAt not equal to current time
    FAIL

With this patch applied;

    === RUN   TestVolumesInspect
    --- FAIL: TestVolumesInspect (0.02s)
        volume_test.go:95: assertion failed: expression is false: createdAt.Truncate(time.Minute).Equal(now.Truncate(time.Minute)): CreatedAt (2018-11-01 16:15:20 +0000 UTC) not equal to creation time (2018-11-01 16:15:20.2421166 +0000 UTC m=+13.733512701)
    FAIL

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 8e8cac8263)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-08 14:00:08 +01:00
Deep Debroy
9fc9c3099d Renamed windowsRS1.ps1 to windows.ps1
Signed-off-by: Deep Debroy <ddebroy@docker.com>
(cherry picked from commit 7d1c1a411b)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-08 13:56:04 +01:00
Salahuddin Khan
37cb9e7300 Enabling Windows integration tests
Signed-off-by: Salahuddin Khan <salah@docker.com>
(cherry picked from commit 4c8b1fd5a2)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-08 13:55:59 +01:00
Vincent Demeester
59be98043a Windows: Start of enabling tests under integration/
- Add windows CI entrypoint script.

Signed-off-by: John Howard <jhoward@microsoft.com>
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
Signed-off-by: Daniel Nephin <dnephin@docker.com>
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
(cherry picked from commit d3cc071bb9)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-08 13:55:48 +01:00
Andrew Hsu
f5749085e9 Merge pull request #74 from thaJeztah/18.09_backport_no_more_version_mismatch
[18.09 backport] remove version-checks for containerd and runc
2018-11-06 11:31:40 -08:00
Andrew Hsu
6236f7b8a4 Merge pull request #79 from thaJeztah/18.09_backport_bugfix_issue_37870
[18.09 backport] bugfix: wait for stdin creation before CloseIO
2018-11-06 11:27:58 -08:00
Andrew Hsu
9512677feb Merge pull request #108 from tonistiigi/copy-0.1.9
[18.09] builder: update copy to 0.1.9
2018-11-06 11:26:09 -08:00
Tibor Vass
5bb36e25ba Merge pull request #96 from thaJeztah/18.09_backport_fix-duplicate-release
[18.09 backport] builder: fix duplicate mount release
2018-11-06 11:22:47 -08:00
Tonis Tiigi
45654ed012 builder: update copy to 0.1.9
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2018-11-06 10:52:34 -08:00
Andrew Hsu
334099505f Merge pull request #105 from tiborvass/18.09-bk-fix-filters
[18.09] builder: fix bugs when pruning buildkit cache with filters
2018-11-06 09:23:25 -08:00
Sebastiaan van Stijn
e1783a72d1 [18.09 backport] update libnetwork to fix iptables compatibility on debian
Fixes a compatibility issue on recent debian versions, where iptables now uses
nft by default.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-06 12:39:04 +01:00
Sebastiaan van Stijn
c27094289a update containerd client and dependencies to v1.2.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit dd7799afd4)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-06 11:03:22 +01:00
Akihiro Suda
0afe0309bd bump up runc
Changes: 69663f0bd4...a00bf01908

Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
(cherry picked from commit 275044bbc3)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-06 11:03:14 +01:00
John Howard
41f3cea42f Vendor Microsoft/hcsshim @ v0.7.9
Signed-off-by: John Howard <jhoward@microsoft.com>
(cherry picked from commit d03ab10662)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-06 11:03:06 +01:00
John Howard
9cf6464b63 LCOW: ApplyDiff() use tar2ext4, not SVM
Signed-off-by: John Howard <jhoward@microsoft.com>

This removes the need for an SVM in the LCOW driver to ApplyDiff.

This change relates to a fix for https://github.com/moby/moby/issues/36353

However, it found another issue, tracked by https://github.com/moby/moby/issues/37955

(cherry picked from commit bde9996065)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-06 11:03:00 +01:00
Tibor Vass
52a3c39506 builder: fix bugs when pruning buildkit cache with filters
Only the filters the user specified should be added as cache filters to buildkit.
Make an AND operation of the provided filters.
ID filter now does prefix-matching.

Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit b6137bebb83e886aef906b7ff277778b69616991)
Signed-off-by: Tibor Vass <tibor@docker.com>
2018-11-05 22:59:24 +00:00
Andrew Hsu
4fc9786f78 Merge pull request #104 from anshulpundir/1809
[18.09] Vendor swarmkit to 6186e40
2018-10-31 19:01:51 -07:00
Anshul Pundir
46dfcd83bf [18.09] Vendor swarmkit to 6186e40fb04a7681e25a9101dbc7418c37ef0c8b
Signed-off-by: Anshul Pundir <anshul.pundir@docker.com>
2018-10-31 16:04:51 -07:00
Sebastiaan van Stijn
c40a7d393b Fix double "unix://" scheme in TestInfoAPIWarnings
`d.Sock()` already returns the socket-path including the
`unix://` scheme.

Also removed `--iptables=false`, as it didn't really seem
nescessary for this test.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 1434204647)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-31 14:25:40 +01:00
Andrew Hsu
fb51c760c4 Merge pull request #99 from andrewhsu/grpc
[18.09] cluster: set bigger grpc limit for array requests
2018-10-30 18:49:11 -07:00
Andrew Hsu
66bfae52bc Merge pull request #100 from thaJeztah/18.09_backport_log_error_spelling
[18.09 backport] Fix incorrect spelling in error message
2018-10-30 18:47:28 -07:00
Tonis Tiigi
6ca0546f25 cluster: set bigger grpc limit for array requests
4MB client side limit was introduced in vendoring go-grpc#1165 (v1.4.0)
making these requests likely to produce errors

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit 489b8eda66)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2018-10-30 23:04:27 +00:00
Andrew Hsu
2822d49c10 Merge pull request #101 from thaJeztah/18.09_backport_document_service_version
[18.09 backport] Add more API doc details on service update version.
2018-10-30 13:14:04 -07:00
Brian Goff
64b0c76151 Add more API doc details on service update version.
Hopefully this removes some confusion as to what this version number
should be.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit 5bdfa19b86)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-30 14:25:19 +01:00
Phil Estes
5591f0b1ee Fix incorrect spelling in error message
Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com>
(cherry picked from commit f962bd06ed)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-30 11:29:02 +01:00
Eli Uriegas
4594e70063 Merge pull request #38 from thaJeztah/18.09_backport_bump_golang_1.10.4
[18.09 backport] bump Go to 1.10.4
2018-10-26 10:03:38 -07:00
Sebastiaan van Stijn
7236817725 Bump Go to 1.10.4
Includes fixes to the go command, linker, and the net/http, mime/multipart,
ld/macho, bytes, and strings packages. See the Go 1.10.4 milestone on the
issue tracker for details:

https://github.com/golang/go/issues?q=milestone%3AGo1.10.4

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit fe1fb7417c)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-26 12:14:01 +02:00
Andrew Hsu
78746ca9e8 Merge pull request #95 from thaJeztah/add_note_about_branch
[18.09] Add note that we use the bump_v18.09 branch for SwarmKit
2018-10-24 16:57:02 -07:00
Tonis Tiigi
5853cd510c builder: fix duplicate mount release
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit 2732fe527f)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-24 20:11:51 +02:00
Sebastiaan van Stijn
6ee7d86a12 Add note that we use the bump_v18.09 branch for SwarmKit
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-23 13:37:15 +02:00
Wei Fu
ae6284a623 testing: add case for exec closeStdin
add regression case for the issue#37870

Signed-off-by: Wei Fu <fuweid89@gmail.com>
(cherry picked from commit 8e25f4ff6d)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-23 13:20:45 +02:00
Andrew Hsu
8d624c31dd Merge pull request #94 from dperny/18.09-bump-swarmkit
[18.09 Backport] Bump swarmkit to c82e409d
2018-10-22 16:47:21 -07:00
Drew Erny
1222a7081a Bump swarmkit
Signed-off-by: Drew Erny <drew.erny@docker.com>
2018-10-22 15:10:20 -05:00
Andrew Hsu
6f1145e740 Merge pull request #64 from thaJeztah/18.09_backport_syslog
[18.09 backport] move the syslog syscall to be gated by CAP_SYS_ADMIN or CAP_SYSLOG
2018-10-22 08:24:03 -07:00
Madhu Venugopal
ef87a664ef Merge pull request #93 from ctelfer/18.09-backport-dsr
[18.09] Bump libnetwork to 6da50d19 for DSR load balancing changes
2018-10-19 09:37:11 -07:00
Tibor Vass
3dc9802a83 Merge pull request #88 from tonistiigi/fix-private-pull-1809
[18.09 backport] builder: fix private pulls on buildkit
2018-10-18 10:57:46 -07:00
Chris Telfer
fd1fe0b702 Bump libnetwork to 6da50d19 for DSR changes
Bump libnetwork to 6da50d1978302f04c3e2089e29112ea24812f05b which
is the current tip of libnetwork's bump_18.09 branch to get the DSR load
balancing mode option changes for the 18.09 branch of Docker CE.

Signed-off-by: Chris Telfer <ctelfer@docker.com>
2018-10-18 10:52:57 -04:00
Tonis Tiigi
fdaf08a57b builder: fix private pulls on buildkit
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit c693d45acf)
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2018-10-17 17:54:13 -07:00
Andrew Hsu
4d0b8cc2d7 Merge pull request #86 from kolyshkin/18.09-backport-btrfs-prop
[18.09] backport Fix mount propagation for btrfs
2018-10-12 18:28:24 -07:00
Andrew Hsu
7c63f178e7 Merge pull request #82 from tiborvass/18.09-buildkit-cherry-picks
[18.09 backport] builder: treat unset keep-storage as 0
2018-10-12 11:01:20 -07:00
Andrew Hsu
b811212ccd Merge pull request #83 from thaJeztah/18.09_backport_bump_buildkit
[18.09 backport] bump buildkit to c7bb575343df0cbfeab8b5b28149630b8153fcc6
2018-10-12 10:43:01 -07:00
Kir Kolyshkin
fa8ac94616 btrfs: ensure graphdriver home is bind mount
For some reason, shared mount propagation between the host
and a container does not work for btrfs, unless container
root directory (i.e. graphdriver home) is a bind mount.

The above issue was reproduced on SLES 12sp3 + btrfs using
the following script:

	#!/bin/bash
	set -eux -o pipefail

	# DIR should not be under a subvolume
	DIR=${DIR:-/lib}
	MNT=$DIR/my-mnt
	FILE=$MNT/file

	ID=$(docker run -d --privileged -v $DIR:$DIR:rshared ubuntu sleep 24h)
	docker exec $ID mkdir -p $MNT
	docker exec $ID mount -t tmpfs tmpfs $MNT
	docker exec $ID touch $FILE
	ls -l $FILE
	umount $MNT
	docker rm -f $ID

which fails this way:

	+ ls -l /lib/my-mnt/file
	ls: cannot access '/lib/my-mnt/file': No such file or directory

meaning the mount performed inside a priviledged container is not
propagated back to the host (even if all the mounts have "shared"
propagation mode).

The remedy to the above is to make graphdriver home a bind mount.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 16d822bba8)
2018-10-12 09:29:38 -07:00
Kir Kolyshkin
2199ada691 pkg/mount: add MakeMount()
This function ensures the argument is the mount point
(i.e. if it's not, it bind mounts it to itself).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 8abadb36fa)
2018-10-12 09:29:38 -07:00
Kir Kolyshkin
fd7611ff1f pkg/mount: simplify ensureMountedAs
1. There is no need to specify rw argument -- bind mounts are
   read-write by default.

2. There is no point in parsing /proc/self/mountinfo after performing
   a mount, especially if we don't check whether the fs is mounted or
   not -- the only outcome from it could be an error from our mountinfo
   parser, which makes no sense in this context.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit f01297d1ae)
2018-10-12 09:29:38 -07:00
Sebastiaan van Stijn
c20e8dffbb Deprecate legacy overlay storage driver, and add warning
The `overlay` storage driver is deprecated in favor of the `overlay2` storage
driver, which has all the benefits of `overlay`, without its limitations (excessive
inode consumption). The legacy `overlay` storage driver will be removed in a future
release. Users of the `overlay` storage driver should migrate to the `overlay2`
storage driver.

The legacy `overlay` storage driver allowed using overlayFS-backed filesystems
on pre 4.x kernels. Now that all supported distributions are able to run `overlay2`
(as they are either on kernel 4.x, or have support for multiple lowerdirs
backported), there is no reason to keep maintaining the `overlay` storage driver.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 31be4e0ba1)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-12 02:26:17 +02:00
Sebastiaan van Stijn
734e7a8e55 Deprecate "devicemapper" storage driver, and add warning
The `devicemapper` storage driver is deprecated in favor of `overlay2`, and will
be removed in a future release. Users of the `devicemapper` storage driver are
recommended to migrate to a different storage driver, such as `overlay2`, which
is now the default storage driver.

The `devicemapper` storage driver facilitates running Docker on older (3.x) kernels
that have no support for other storage drivers (such as overlay2, or AUFS).

Now that support for `overlay2` is added to all supported distros (as they are
either on kernel 4.x, or have support for multiple lowerdirs backported), there
is no reason to continue maintenance of the `devicemapper` storage driver.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 06fcabbaa0)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-12 02:25:39 +02:00
Tibor Vass
dbfc648a94 builder: treat unset keep-storage as 0
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit d6ac2b0db0)
Signed-off-by: Tibor Vass <tibor@docker.com>
2018-10-11 20:35:43 +00:00
Tibor Vass
8e67dfab97 Merge pull request #75 from thaJeztah/18.09_backport_bump_containerd_client_1.2.0_rc.1
[18.09] backport update containerd client and dependencies to v1.2.0-rc.1
2018-10-11 13:27:48 -07:00
Tibor Vass
b38d454861 Merge pull request #73 from thaJeztah/18.09_backport_addr_pool
[18.09] backport default-addr-pool-mask-length param max value check
2018-10-11 13:27:22 -07:00
Tibor Vass
4b8336f7cf Merge pull request #70 from thaJeztah/18.09_backport_upstream_dos_fix
[18.09] backport fix denial of service with large numbers in cpuset-cpus and cpuset-mems
2018-10-11 13:25:55 -07:00
Tibor Vass
2697d2b687 Merge pull request #72 from thaJeztah/18.09_backport_esc-879
[18.09] backport masking credentials from proxy URL
2018-10-11 13:25:30 -07:00
Kir Kolyshkin
690e097fed overlay2: use index=off if possible
As pointed out in https://github.com/moby/moby/issues/37970,
Docker overlay driver can't work with index=on feature of
the Linux kernel "overlay" filesystem. In case the global
default is set to "yes", Docker will fail with EBUSY when
trying to mount, like this:

> error creating overlay mount to ...../merged: device or resource busy

and the kernel log should contain something like:

> overlayfs: upperdir is in-use by another mount, mount with
> '-o index=off' to override exclusive upperdir protection.

A workaround is to set index=off in overlay kernel module
parameters, or even recompile the kernel with
CONFIG_OVERLAY_FS_INDEX=n in .config. Surely this is not
always practical or even possible.

The solution, as pointed out my Amir Goldstein (as well as
the above kernel message:) is to use 'index=off' option
when mounting.

NOTE since older (< 4.13rc1) kernels do not support "index="
overlayfs parameter, try to figure out whether the option
is supported. In case it's not possible to figure out,
assume it is not.

NOTE the default can be changed anytime (by writing to
/sys/module/overlay/parameters/index) so we need to always
use index=off.

[v2: move the detection code to Init()]
[v3: don't set index=off if stat() failed]

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 8422d85087)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-11 22:09:38 +02:00
Kir Kolyshkin
dc0a4db7c9 overlay2: use global logger instance
This simplifies the code a lot.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit a55d32546a)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-11 22:09:30 +02:00
Sebastiaan van Stijn
f58f842143 bump buildkit to c7bb575343df0cbfeab8b5b28149630b8153fcc6
Relevant changes:

- buildkit#667 gateway: check for `ReadDir` and `StatFile` caps on client side
- buildkit#668 dockerfile: fix ssh required option
- buildkit#669 dockerfile: update default copy image
- buildkit#670 solver: specify SSH key ID in error message when required key was not forwarded
- buildkit#673 solver: fix possible nil dereference
- buildkit#672 fix setting uncompressed label on content
- buildkit#680 dockerfile: fix empty dest directory panic

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 9cfce30214)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-11 21:55:49 +02:00
John Howard
7184074c08 Windows:Allow process isolation
Signed-off-by: John Howard <jhoward@microsoft.com>
(cherry picked from commit c907c2486c)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-11 16:04:45 +02:00
Wei Fu
6679a5faeb bugfix: wait for stdin creation before CloseIO
The stdin fifo of exec process is created in containerd side after
client calls Start. If the client calls CloseIO before Start call, the
stdin of exec process is still opened and wait for close.

For this case, client closes stdinCloseSync channel after Start.

Signed-off-by: Wei Fu <fuweid89@gmail.com>
(cherry picked from commit c7890f25a9)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-10 20:43:14 +02:00
Akihiro Suda
90c72824c3 bump up buildkit
Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
(cherry picked from commit 837b9c6214)
Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
2018-10-11 03:01:18 +09:00
Eli Uriegas
ad08dc12e0 Merge pull request #76 from seemethere/dockerfile_copy_1809
Switch copy image to a docker org based one
2018-10-08 14:10:53 -07:00
Eli Uriegas
7b54720ccb Switch copy image to a docker org based one
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
(cherry picked from commit 5cfd110c30)
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2018-10-05 18:01:10 +00:00
Justin Cormack
0922d32bce Fix denial of service with large numbers in cpuset-cpus and cpuset-mems
Using a value such as `--cpuset-mems=1-9223372036854775807` would cause
`dockerd` to run out of memory allocating a map of the values in the
validation code. Set limits to the normal limit of the number of CPUs,
and improve the error handling.

Reported by Huawei PSIRT.

Signed-off-by: Justin Cormack <justin.cormack@docker.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit f8e876d761)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-05 15:13:43 +02:00
Sebastiaan van Stijn
148d9f0e58 Update containerd client and dependencies to v1.2.0-rc.1
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit dd622c81a4)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-05 14:53:33 +02:00
Sebastiaan van Stijn
5070e418b8 Update containerd dependencies
This updates the containerd dependencies to match
the versions used by the vendored containerd version

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 31a9c9e791)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-05 14:38:34 +02:00
Sebastiaan van Stijn
054c3c2931 Remove version-checks for containerd and runc
With containerd reaching 1.0, the runtime now
has a stable API, so there's no need to do a check
if the installed version matches the expected version.

Current versions of Docker now also package containerd
and runc separately, and can be _updated_ separately.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit c65f0bd13c)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-05 12:35:59 +02:00
selansen
9406f3622d Fix for default-addr-pool-mask-length param max value check
We check for max value for -default-addr-pool-mask-length param as 32.
But There won't be enough addresses on the  overlay network. Hence we are
keeping it 29 so that we would be having atleast 8 addresses in /29 network.

Signed-off-by: selansen <elango.siva@docker.com>
(cherry picked from commit d25c5df80e)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-04 21:59:25 +02:00
selansen
9816bfcaf5 Global Default AddressPool - Update
Addressing few review comments as part of code refactoring.
Also moved validation logic from CLI to Moby.

Signed-off-by: selansen <elango.siva@docker.com>
(cherry picked from commit 148ff00a0a)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-04 21:59:09 +02:00
Sebastiaan van Stijn
52d6ad2a68 Merge pull request #66 from thaJeztah/18.09_backport_fix-dm-errmsg
[18.09] backport: gd/dm: fix error message
2018-10-04 21:28:22 +02:00
Dani Louca
58e5151270 Masking credentials from proxy URL
Signed-off-by: Dani Louca <dani.louca@docker.com>
(cherry picked from commit 78fd978454)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-04 21:20:54 +02:00
Sebastiaan van Stijn
6e5ed2ccce Merge pull request #67 from thaJeztah/18.09_backport_windows-network-plugin-miss-fix
[18.09] Fix long startup on windows, with non-hns governed Hyper-V networks
2018-10-03 23:27:28 +02:00
Simon Ferquel
54bd14a3fe Fix long startup on windows, with non-hns governed Hyper-V networks
Similar to a related issue where previously, private Hyper-V networks
would each add 15 secs to the daemon startup, non-hns governed internal
networks are reported by hns as network type "internal" which is not
mapped to any network plugin (and thus we get the same plugin load retry
loop as before).

This issue hits Docker for Desktop because we setup such a network for
the Linux VM communication.

Signed-off-by: Simon Ferquel <simon.ferquel@docker.com>
(cherry picked from commit 6a1a4f9721)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-03 15:24:34 +02:00
Kir Kolyshkin
c9ddc6effc gd/dm: fix error message
The parameter name was wrong, which may mislead a user.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit c378fb774e)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-03 14:01:13 +02:00
Justin Cormack
16836e60bc Move the syslog syscall to be gated by CAP_SYS_ADMIN or CAP_SYSLOG
This call is what is used to implement `dmesg` to get kernel messages
about the host. This can leak substantial information about the host.
It is normally available to unprivileged users on the host, unless
the sysctl `kernel.dmesg_restrict = 1` is set, but this is not set
by standard on the majority of distributions. Blocking this to restrict
leaks about the configuration seems correct.

Fix #37897

See also https://googleprojectzero.blogspot.com/2018/09/a-cache-invalidation-bug-in-linux.html

Signed-off-by: Justin Cormack <justin.cormack@docker.com>
(cherry picked from commit ccd22ffcc8)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-10-02 20:33:38 +02:00
Andrew Hsu
e44436c31f Merge pull request #62 from thaJeztah/18.09_backport_tweak_error_message
[18.09] backport: tweak bind mount errors
2018-09-28 14:13:41 -07:00
Andrew Hsu
34b3cf4b0c Merge pull request #56 from thaJeztah/18.09_backport_more_permissive_daeon_conf_dir
[18.09] backport loosen permissions on /etc/docker directory
2018-09-28 11:42:01 -07:00
Andrew Hsu
51618f7a83 Merge pull request #63 from tiborvass/18.09-vndr-buildkit
[18.09] vendor buildkit to 8f4dff0d16ea91cb43315d5f5aa4b27f4fe4e1f2
2018-09-28 10:57:56 -07:00
Sebastiaan van Stijn
b499acc0e8 Tweak bind mount errors
These messages were enhanced to include the path that was
missing (in df6af282b9), but
also changed the first part of the message.

This change complicates running e2e tests with mixed versions
of the engine.

Looking at the full error message, "mount" is a bit redundant
as well, because the error message already indicates this is
about a "mount";

    docker run --rm --mount type=bind,source=/no-such-thing,target=/foo busybox
    docker: Error response from daemon: invalid mount config for type "bind": bind mount source path does not exist: /no-such-thing.

Removing the "mount" part from the error message, because
it was redundant, and makes cross-version testing easier :)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 574db7a537)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-09-28 14:35:55 +02:00
Tibor Vass
67541d5841 vendor buildkit to 8f4dff0d16ea91cb43315d5f5aa4b27f4fe4e1f2
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit e161a8d1e9)
Signed-off-by: Tibor Vass <tibor@docker.com>
2018-09-27 22:46:57 +00:00
Eli Uriegas
989fab3c71 Merge pull request #61 from tiborvass/18.09-remove-docker-prefix-containerd
[18.09] Remove 'docker-' prefix for containerd and runc binaries
2018-09-26 11:45:50 -07:00
Tibor Vass
6bf8dfc4d8 fix daemon tests that were using wrong containerd socket
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit 52b60f705c)
Signed-off-by: Tibor Vass <tibor@docker.com>
2018-09-25 23:09:25 +00:00
Tibor Vass
e090646d47 hack/make: remove 'docker-' prefix when copying binaries
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit 361412c79e)
Signed-off-by: Tibor Vass <tibor@docker.com>
2018-09-25 23:09:25 +00:00
Tibor Vass
b3bb2aabb8 Remove 'docker-' prefix for containerd and runc binaries
This allows to run the daemon in environments that have upstream containerd installed.

Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit 34eede0296)
Signed-off-by: Tibor Vass <tibor@docker.com>
2018-09-24 22:35:36 +00:00
Andrew Hsu
e69efe2ef5 Merge pull request #51 from thaJeztah/18.09_backport_fix-libcontainerd-startup-error
[18.09] backport: Add fail fast path when containerd fails on startup
2018-09-22 00:11:43 -07:00
Andrew Hsu
ccab609365 Merge pull request #60 from tiborvass/18.09-remove-boltdb
[18.09] Remove boltdb dependency
2018-09-22 00:11:17 -07:00
Andrew Hsu
0a6866b839 Merge pull request #59 from tonistiigi/buildkit-1809
[18.09] Backport Buildkit fixes for 18.09
2018-09-21 21:59:27 -07:00
Tibor Vass
cce1763d57 vendor: remove boltdb dependency which is superseded by bbolt
This also brings in these PRs from swarmkit:
- https://github.com/docker/swarmkit/pull/2691
- https://github.com/docker/swarmkit/pull/2744
- https://github.com/docker/swarmkit/pull/2732
- https://github.com/docker/swarmkit/pull/2729
- https://github.com/docker/swarmkit/pull/2748

Signed-off-by: Tibor Vass <tibor@docker.com>
2018-09-22 01:24:11 +00:00
Tibor Vass
3d67dd0465 builder: vendor buildkit to 39404586a50d1b9d0fb1c578cf0f4de7bdb7afe5
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit d0f00bc1fb)
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2018-09-21 17:06:25 -07:00
Tibor Vass
73e2f72a7c builder: use buildkit's GC for build cache
This allows users to configure the buildkit GC.

The following enables the default GC:
```
{
  "builder": {
    "gc": {
      "enabled": true
    }
  }
}
```

The default GC policy has a simple config:
```
{
  "builder": {
    "gc": {
      "enabled": true,
      "defaultKeepStorage": "30GB"
    }
  }
}
```

A custom GC policy can be used instead by specifying a list of cache prune rules:
```
{
  "builder": {
    "gc": {
      "enabled": true,
      "policy": [
        {"keepStorage": "512MB", "filter": ["unused-for=1400h"]]},
        {"keepStorage": "30GB", "all": true}
      ]
    }
  }
}
```

Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit 4a776d0ca7)
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2018-09-21 17:06:25 -07:00
Anda Xu
2926a45be6 add support of registry-mirrors and insecure-registries to buildkit
Signed-off-by: Anda Xu <anda.xu@docker.com>
(cherry picked from commit 171d51c861)
(cherry picked from commit a72752b2f74467333b4ebe21c6c474eb0c2b99e0)
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2018-09-21 17:06:25 -07:00
Anda Xu
b73fd4d936 update vendor
Signed-off-by: Anda Xu <anda.xu@docker.com>
(cherry picked from commit 308701fac6)
(cherry picked from commit b48afc216f46c8e786560b807528699012e1627b)
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2018-09-21 17:06:25 -07:00
Tibor Vass
bb2adc4496 daemon/images: removed "found leaked image layer" warning, because it is expected now with buildkit
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit 5aa222d0fe)
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2018-09-21 17:06:25 -07:00
Tonis Tiigi
b501aa82d5 vendor: update bolt to bbolt
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2018-09-21 17:06:25 -07:00
Tonis Tiigi
46a703bb3b vendor: add bbolt v1.3.1-etcd.8
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2018-09-21 17:06:25 -07:00
Andrew Hsu
ff9340ca2c Merge pull request #52 from thaJeztah/18.09_backport_fix-TestServiceWithDefaultAddressPoolInit
[18.09] backport TestServiceWithDefaultAddressPoolInit: avoid panic
2018-09-21 11:19:57 -07:00
Andrew Hsu
90a90ae2e1 Merge pull request #57 from AntaresS/cherry-37871
[18.09] backport fixing daemon won't start when "runtimes" option defined in both config file and cli
2018-09-21 09:54:31 -07:00
Anda Xu
66ed41aec8 fixed the dockerd won't start bug when 'runtimes' field is defined in both daemon config file and cli flags
Signed-off-by: Anda Xu <anda.xu@docker.com>
(cherry picked from commit 8392d0930b)
2018-09-20 10:54:47 -07:00
Andrew Hsu
ea2e2c5427 Merge pull request #50 from AntaresS/cherry-pick-moby
[18.09] backport propagate the dockerd cgroup-parent config to buildkitd
2018-09-18 16:36:12 -07:00
Anda Xu
a5d731edec create newBuildKit function separately in daemon_unix.go and daemon_windows.go for cross platform build
Signed-off-by: Anda Xu <anda.xu@docker.com>
(cherry picked from commit 66ac92cdc6)
2018-09-18 11:19:51 -07:00
Sebastiaan van Stijn
fc576226b2 Loosen permissions on /etc/docker directory
The `/etc/docker` directory is used both by the dockerd daemon
and the docker cli (if installed on the saem host as the daemon).

In situations where the `/etc/docker` directory does not exist,
and an initial `key.json` (legacy trust key) is generated (at the
default location), the `/etc/docker/` directory was created with
0700 permissions, making the directory only accessible by `root`.

Given that the `0600` permissions on the key itself already protect
it from being used by other users, the permissions of `/etc/docker`
can be less restrictive.

This patch changes the permissions for the directory to `0755`, so
that the CLI (if executed as non-root) can also access this directory.

> **NOTE**: "strictly", this patch is only needed for situations where no _custom_
> location for the trustkey is specified (not overridden with `--deprecated-key-path`),
> but setting the permissions only for the "default" case would make
> this more complicated.

```bash
make binary shell

make install

ls -la /etc/ | grep docker

dockerd
^C

ls -la /etc/ | grep docker
drwxr-xr-x 2 root root    4096 Sep 14 12:11 docker
```

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit cecd981717)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-09-18 12:34:56 +02:00
Tibor Vass
c24fd7a2c3 Merge pull request #55 from thaJeztah/18.09_backport_fix-progress-panic
[18.09] backport pkg/progress: work around closing closed channel panic
2018-09-17 11:43:41 -07:00
Sebastiaan van Stijn
5fb0a7ced7 Merge pull request #53 from thaJeztah/18.09_backport_buildkit-cli-control
[18.09] backport always hornor client side to choose which builder to use with DOCKER_…
2018-09-17 12:34:28 +02:00
Tibor Vass
2c26eac566 pkg/progress: work around closing closed channel panic
I could not reproduce the panic in #37735, so here's a bandaid.

Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit 7dac70324d)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-09-17 12:28:09 +02:00
Anda Xu
5badfb40eb always hornor client side to choose which builder to use with DOCKER_BUILDKIT env var regardless the server setup
Signed-off-by: Anda Xu <anda.xu@docker.com>
(cherry picked from commit 5d931705e3)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-09-14 17:29:47 +02:00
Kir Kolyshkin
f43fc6650c TestServiceWithDefaultAddressPoolInit: avoid panic
Saw this in moby ci:

> 00:22:07.582 === RUN   TestServiceWithDefaultAddressPoolInit
> 00:22:08.887 --- FAIL: TestServiceWithDefaultAddressPoolInit (1.30s)
> 00:22:08.887 	daemon.go:290: [d905878b35bb9] waiting for daemon to start
> 00:22:08.887 	daemon.go:322: [d905878b35bb9] daemon started
> 00:22:08.888 panic: runtime error: index out of range [recovered]
> 00:22:08.889 	panic: runtime error: index out of range
> 00:22:08.889
> 00:22:08.889 goroutine 360 [running]:
> 00:22:08.889 testing.tRunner.func1(0xc42069d770)
> 00:22:08.889 	/usr/local/go/src/testing/testing.go:742 +0x29d
> 00:22:08.890 panic(0x85d680, 0xb615f0)
> 00:22:08.890 	/usr/local/go/src/runtime/panic.go:502 +0x229
> 00:22:08.890 github.com/docker/docker/integration/network.TestServiceWithDefaultAddressPoolInit(0xc42069d770)
> 00:22:08.891 	/go/src/github.com/docker/docker/integration/network/service_test.go:348 +0xb53
> .....

Apparently `out.IPAM.Config[0]` is not there, so to avoid panic, let's
check the size of `out.IPAM.Config` first.

Fixes: f7ad95cab9

[v2: add logging of data returned by NetworkInspect()]
[v3: use assert.Assert to fail immediately]

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 69d3a8936b)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-09-14 15:22:43 +02:00
Derek McGowan
85361af1f7 Add fail fast path when containerd fails on startup
Prevents looping of startup errors such as containerd
not being found on the path.

Signed-off-by: Derek McGowan <derek@mcgstyle.net>
(cherry picked from commit ce0b0b72bc)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-09-14 15:20:07 +02:00
Anda Xu
ee40a9ebcd update vendor
Signed-off-by: Anda Xu <anda.xu@docker.com>
(cherry picked from commit 54b3af4c7d)
2018-09-13 16:42:13 -07:00
Anda Xu
e8620110fc propagate the dockerd cgroup-parent config to buildkitd
Signed-off-by: Anda Xu <anda.xu@docker.com>
(cherry picked from commit d52485c2f9)
2018-09-13 16:36:57 -07:00
Andrew Hsu
e988001872 Merge pull request #46 from kolyshkin/18.09-backport-pr37771
[18.09] backport #37771 "vendor: update tar-split"
2018-09-12 18:16:16 -07:00
Andrew Hsu
6531bac59b Merge pull request #48 from kolyshkin/18.09-backport-logs-follow
[18.09] backport "daemon.ContainerLogs(): fix resource leak on follow"
2018-09-12 18:13:56 -07:00
Kir Kolyshkin
2a82480df9 TestFollowLogsProducerGone: add
This should test that
 - all the messages produced are delivered (i.e. not lost)
 - followLogs() exits

Loosely based on the test having the same name by Brian Goff, see
https://gist.github.com/cpuguy83/e538793de18c762608358ee0eaddc197

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit f845d76d04)
2018-09-06 18:39:22 -07:00
Kir Kolyshkin
84a5b528ae daemon.ContainerLogs(): fix resource leak on follow
When daemon.ContainerLogs() is called with options.follow=true
(as in "docker logs --follow"), the "loggerutils.followLogs()"
function never returns (even then the logs consumer is gone).
As a result, all the resources associated with it (including
an opened file descriptor for the log file being read, two FDs
for a pipe, and two FDs for inotify watch) are never released.

If this is repeated (such as by running "docker logs --follow"
and pressing Ctrl-C a few times), this results in DoS caused by
either hitting the limit of inotify watches, or the limit of
opened files. The only cure is daemon restart.

Apparently, what happens is:

1. logs producer (a container) is gone, calling (*LogWatcher).Close()
for all its readers (daemon/logger/jsonfilelog/jsonfilelog.go:175).

2. WatchClose() is properly handled by a dedicated goroutine in
followLogs(), cancelling the context.

3. Upon receiving the ctx.Done(), the code in followLogs()
(daemon/logger/loggerutils/logfile.go#L626-L638) keeps to
send messages _synchronously_ (which is OK for now).

4. Logs consumer is gone (Ctrl-C is pressed on a terminal running
"docker logs --follow"). Method (*LogWatcher).Close() is properly
called (see daemon/logs.go:114). Since it was called before and
due to to once.Do(), nothing happens (which is kinda good, as
otherwise it will panic on closing a closed channel).

5. A goroutine (see item 3 above) keeps sending log messages
synchronously to the logWatcher.Msg channel. Since the
channel reader is gone, the channel send operation blocks forever,
and resource cleanup set up in defer statements at the beginning
of followLogs() never happens.

Alas, the fix is somewhat complicated:

1. Distinguish between close from logs producer and logs consumer.
To that effect,
 - yet another channel is added to LogWatcher();
 - {Watch,}Close() are renamed to {Watch,}ProducerGone();
 - {Watch,}ConsumerGone() are added;

*NOTE* that ProducerGone()/WatchProducerGone() pair is ONLY needed
in order to stop ConsumerLogs(follow=true) when a container is stopped;
otherwise we're not interested in it. In other words, we're only
using it in followLogs().

2. Code that was doing (logWatcher*).Close() is modified to either call
ProducerGone() or ConsumerGone(), depending on the context.

3. Code that was waiting for WatchClose() is modified to wait for
either ConsumerGone() or ProducerGone(), or both, depending on the
context.

4. followLogs() are modified accordingly:
 - context cancellation is happening on WatchProducerGone(),
and once it's received the FileWatcher is closed and waitRead()
returns errDone on EOF (i.e. log rotation handling logic is disabled);
 - due to this, code that was writing synchronously to logWatcher.Msg
can be and is removed as the code above it handles this case;
 - function returns once ConsumerGone is received, freeing all the
resources -- this is the bugfix itself.

While at it,

1. Let's also remove the ctx usage to simplify the code a bit.
It was introduced by commit a69a59ffc7 ("Decouple removing the
fileWatcher from reading") in order to fix a bug. The bug was actually
a deadlock in fsnotify, and the fix was just a workaround. Since then
the fsnofify bug has been fixed, and a new fsnotify was vendored in.
For more details, please see
https://github.com/moby/moby/pull/27782#issuecomment-416794490

2. Since `(*filePoller).Close()` is fixed to remove all the files
being watched, there is no need to explicitly call
fileWatcher.Remove(name) anymore, so get rid of the extra code.

Should fix https://github.com/moby/moby/issues/37391

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 916eabd459)
2018-09-06 18:39:22 -07:00
Brian Goff
511741735e daemon/logger/loggerutils: add TestFollowLogsClose
This test case checks that followLogs() exits once the reader is gone.
Currently it does not (i.e. this test is supposed to fail) due to #37391.

[kolyshkin@: test case Brian Goff, changelog and all bugs are by me]
Source: https://gist.github.com/cpuguy83/e538793de18c762608358ee0eaddc197

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit d37a11bfba)
2018-09-06 18:39:22 -07:00
Kir Kolyshkin
2b8bc86679 daemon.ContainerLogs: minor debug logging cleanup
This code has many return statements, for some of them the
"end logs" or "end stream" message was not printed, giving
the impression that this "for" loop never ended.

Make sure that "begin logs" is to be followed by "end logs".

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 2e4c2a6bf9)
2018-09-06 18:39:22 -07:00
Kir Kolyshkin
4e2dbfa1af pkg/filenotify/poller: fix Close()
The code in Close() that removes the watches was not working,
because it first sets `w.closed = true` and then calls w.close(),
which starts with
```
        if w.closed {
                return errPollerClosed
	}
```

Fix by setting w.closed only after calling w.remove() for all the
files being watched.

While at it, remove the duplicated `delete(w.watches, name)` code.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit fffa8958d0)
2018-09-06 18:39:21 -07:00
Kir Kolyshkin
3a3bfcbf47 pkg/filenotify/poller: close file asap
There is no need to wait for up to 200ms in order to close
the file descriptor once the chClose is received.

This commit might reduce the chances for occasional "The process
cannot access the file because it is being used by another process"
error on Windows, where an opened file can't be removed.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit dfbb64ea7d)
2018-09-06 18:39:21 -07:00
Kir Kolyshkin
7be43586af pkg/filenotify: poller.Add: fix fd leaks on err
In case of errors, the file descriptor is never closed. Fix it.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 88bcf1573c)
2018-09-06 18:39:21 -07:00
Kir Kolyshkin
d7085abec2 vendor: update tar-split
To include https://github.com/vbatts/tar-split/pull/48 which
fixes the issue of creating an image with >8GB file in it.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 92e7543903)
2018-09-06 17:24:39 -07:00
Kir Kolyshkin
fc1d808c44 integration/build: add TestBuildHugeFile
Add a test case for creating a 8GB file inside a container.
Due to a bug in tar-split this was failing in Docker 18.06.

The file being created is sparse, so there's not much I/O
happening or disk space being used -- meaning the test is
fast and does not require a lot of disk space.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit b3165f5b2d)
2018-09-06 17:24:36 -07:00
Andrew Hsu
7485ef7e46 Merge pull request #44 from andrewhsu/sup
[18.09] Fix supervisor healthcheck throttling
2018-09-05 11:14:31 -07:00
Andrew Hsu
d2ecc7bad1 Merge pull request #43 from andrewhsu/tls
[18.09] client: dial tls on Dialer if tls config is set
2018-09-05 06:43:23 -07:00
Derek McGowan
f121eccf29 Fix supervisor healthcheck throttling
Fix default case causing the throttling to not be used.
Ensure that nil client condition is handled.

Signed-off-by: Derek McGowan <derek@mcgstyle.net>
(cherry picked from commit c3e3293843)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2018-09-05 06:59:52 +00:00
Andrew Hsu
00a9cf39ed Merge pull request #42 from tiborvass/18.09-cp-buildkit
[18.09] Buildkit cherry-picks
2018-09-04 18:46:24 -07:00
Tonis Tiigi
c2d0053207 client: dial tls on Dialer if tls config is set
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit 5974fc2540)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2018-09-05 01:17:31 +00:00
Tibor Vass
4c35d81147 vendor buildkit to fix a couple of bugs
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit effa24bf48)
Signed-off-by: Tibor Vass <tibor@docker.com>
2018-09-04 15:52:24 +00:00
Tonis Tiigi
28150fc70c builder: implement ref checker
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit 354c241041)
Signed-off-by: Tibor Vass <tibor@docker.com>
2018-09-04 15:02:28 +00:00
Tibor Vass
d2c3163642 builder: fix pruning all cache
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit d47435a004)
Signed-off-by: Tibor Vass <tibor@docker.com>
2018-09-04 15:02:28 +00:00
Tibor Vass
3153708f13 builder: add prune options to the API
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit 8ff7847d1c)
Signed-off-by: Tibor Vass <tibor@docker.com>
2018-09-04 15:02:28 +00:00
Anda Xu
2f94f10342 allow features option live reloadable
Signed-off-by: Anda Xu <anda.xu@docker.com>
(cherry picked from commit 58a75cebdd)
Signed-off-by: Tibor Vass <tibor@docker.com>
2018-09-04 15:01:46 +00:00
Andrew Hsu
b8a4fe5f8f Merge pull request #37 from thaJeztah/18.09_backport_fix_prefix_matching
[18.09] backport: fix regression when filtering container names using a leading slash
2018-08-31 21:15:00 -07:00
Madhu Venugopal
648704522b Merge pull request #41 from kolyshkin/18.09-backport-pr37739
[18.09] backport "fix relabeling local volume source dir"
2018-08-31 19:01:01 -07:00
Kir Kolyshkin
4032b6778d Fix relabeling local volume source dir
In case a volume is specified via Mounts API, and SELinux is enabled,
the following error happens on container start:

> $ docker volume create testvol
> $ docker run --rm --mount source=testvol,target=/tmp busybox true
> docker: Error response from daemon: error setting label on mount
> source '': no such file or directory.

The functionality to relabel the source of a local mount specified via
Mounts API was introduced in commit 5bbf5cc and later broken by commit
e4b6adc, which removed setting mp.Source field.

With the current data structures, the host dir is already available in
v.Mountpoint, so let's just use it.

Fixes: e4b6adc
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2018-08-30 17:34:59 -07:00
Sebastiaan van Stijn
5fa80da2d3 Fix regression when filtering container names using a leading slash
Commit 5c8da2e967 updated the filtering behavior
to match container-names without having to specify the leading slash.

This change caused a regression in situations where a regex was provided as
filter, using an explicit leading slash (`--filter name=^/mycontainername`).

This fix changes the filters to match containers both with, and without the
leading slash, effectively making the leading slash optional when filtering.

With this fix, filters with and without a leading slash produce the same result:

    $ docker ps --filter name=^a
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    21afd6362b0c        busybox             "sh"                2 minutes ago       Up 2 minutes                            a2
    56e53770e316        busybox             "sh"                2 minutes ago       Up 2 minutes                            a1

    $ docker ps --filter name=^/a
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    21afd6362b0c        busybox             "sh"                2 minutes ago       Up 2 minutes                            a2
    56e53770e316        busybox             "sh"                3 minutes ago       Up 3 minutes                            a1

    $ docker ps --filter name=^b
    CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
    b69003b6a6fe        busybox             "sh"                About a minute ago   Up About a minute                       b1

    $ docker ps --filter name=^/b
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    b69003b6a6fe        busybox             "sh"                56 seconds ago      Up 54 seconds                           b1

    $ docker ps --filter name=/a
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    21afd6362b0c        busybox             "sh"                3 minutes ago       Up 3 minutes                            a2
    56e53770e316        busybox             "sh"                4 minutes ago       Up 4 minutes                            a1

    $ docker ps --filter name=a
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    21afd6362b0c        busybox             "sh"                3 minutes ago       Up 3 minutes                            a2
    56e53770e316        busybox             "sh"                4 minutes ago       Up 4 minutes                            a1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 6f9b5ba810)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-08-29 12:54:06 +02:00
Tibor Vass
be371291bc Merge pull request #35 from tiborvass/18.09-fix-network-buildkit
[18.09] builder: fix bridge networking when using buildkit
2018-08-23 06:21:34 -07:00
Tibor Vass
1d531ff64f builder: fix bridge networking when using buildkit
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit dc7e472db9)
Signed-off-by: Tibor Vass <tibor@docker.com>
2018-08-23 05:32:51 +00:00
794 changed files with 30887 additions and 11818 deletions

View File

@@ -24,10 +24,10 @@
# the case. Therefore, you don't have to disable it anymore.
#
FROM golang:1.10.3 AS base
FROM golang:1.10.6 AS base
# FIXME(vdemeester) this is kept for other script depending on it to not fail right away
# Remove this once the other scripts uses something else to detect the version
ENV GO_VERSION 1.10.3
ENV GO_VERSION 1.10.6
# allow replacing httpredir or deb mirror
ARG APT_MIRROR=deb.debian.org
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
@@ -154,6 +154,7 @@ RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
FROM runtime-dev AS runc
ENV INSTALL_BINARY_NAME=runc
COPY hack/dockerfile/install/install.sh ./install.sh
COPY git-bundles /go/src/github.com/docker/docker/git-bundles
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME

View File

@@ -1,5 +1,5 @@
## Step 1: Build tests
FROM golang:1.10.3-alpine3.7 as builder
FROM golang:1.10.6-alpine3.7 as builder
RUN apk add --update \
bash \

View File

@@ -42,7 +42,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
# will need updating, to avoid errors. Ping #docker-maintainers on IRC
# with a heads-up.
# IMPORTANT: When updating this please note that stdlib archive/tar pkg is vendored
ENV GO_VERSION 1.10.3
ENV GO_VERSION 1.10.6
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" \
| tar -xzC /usr/local
ENV PATH /go/bin:/usr/local/go/bin:$PATH

View File

@@ -161,7 +161,7 @@ SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPref
# Environment variable notes:
# - GO_VERSION must be consistent with 'Dockerfile' used by Linux.
# - FROM_DOCKERFILE is used for detection of building within a container.
ENV GO_VERSION=1.10.3 `
ENV GO_VERSION=1.10.6 `
GIT_VERSION=2.11.1 `
GOPATH=C:\go `
FROM_DOCKERFILE=1

View File

@@ -88,7 +88,7 @@ func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string
}
// PruneCache removes all cached build sources
func (b *Backend) PruneCache(ctx context.Context) (*types.BuildCachePruneReport, error) {
func (b *Backend) PruneCache(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) {
eg, ctx := errgroup.WithContext(ctx)
var fsCacheSize uint64
@@ -102,9 +102,10 @@ func (b *Backend) PruneCache(ctx context.Context) (*types.BuildCachePruneReport,
})
var buildCacheSize int64
var cacheIDs []string
eg.Go(func() error {
var err error
buildCacheSize, err = b.buildkit.Prune(ctx)
buildCacheSize, cacheIDs, err = b.buildkit.Prune(ctx, opts)
if err != nil {
return errors.Wrap(err, "failed to prune build cache")
}
@@ -115,7 +116,7 @@ func (b *Backend) PruneCache(ctx context.Context) (*types.BuildCachePruneReport,
return nil, err
}
return &types.BuildCachePruneReport{SpaceReclaimed: fsCacheSize + uint64(buildCacheSize)}, nil
return &types.BuildCachePruneReport{SpaceReclaimed: fsCacheSize + uint64(buildCacheSize), CachesDeleted: cacheIDs}, nil
}
// Cancel cancels the build by ID

View File

@@ -14,7 +14,7 @@ type Backend interface {
Build(context.Context, backend.BuildConfig) (string, error)
// Prune build cache
PruneCache(context.Context) (*types.BuildCachePruneReport, error)
PruneCache(context.Context, types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error)
Cancel(context.Context, string) error
}

View File

@@ -7,15 +7,19 @@ import (
// buildRouter is a router to talk with the build controller
type buildRouter struct {
backend Backend
daemon experimentalProvider
routes []router.Route
builderVersion types.BuilderVersion
backend Backend
daemon experimentalProvider
routes []router.Route
features *map[string]bool
}
// NewRouter initializes a new build router
func NewRouter(b Backend, d experimentalProvider, bv types.BuilderVersion) router.Router {
r := &buildRouter{backend: b, daemon: d, builderVersion: bv}
func NewRouter(b Backend, d experimentalProvider, features *map[string]bool) router.Router {
r := &buildRouter{
backend: b,
daemon: d,
features: features,
}
r.initRoutes()
return r
}
@@ -32,3 +36,18 @@ func (r *buildRouter) initRoutes() {
router.NewPostRoute("/build/cancel", r.postCancel),
}
}
// BuilderVersion derives the default docker builder version from the config
// Note: it is valid to have BuilderVersion unset which means it is up to the
// client to choose which builder to use.
func BuilderVersion(features map[string]bool) types.BuilderVersion {
var bv types.BuilderVersion
if v, ok := features["buildkit"]; ok {
if v {
bv = types.BuilderBuildKit
} else {
bv = types.BuilderV1
}
}
return bv
}

View File

@@ -18,6 +18,7 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/errdefs"
"github.com/docker/docker/pkg/ioutils"
@@ -161,7 +162,29 @@ func parseVersion(s string) (types.BuilderVersion, error) {
}
func (br *buildRouter) postPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
report, err := br.backend.PruneCache(ctx)
if err := httputils.ParseForm(r); err != nil {
return err
}
filters, err := filters.FromJSON(r.Form.Get("filters"))
if err != nil {
return errors.Wrap(err, "could not parse filters")
}
ksfv := r.FormValue("keep-storage")
if ksfv == "" {
ksfv = "0"
}
ks, err := strconv.Atoi(ksfv)
if err != nil {
return errors.Wrapf(err, "keep-storage is in bytes and expects an integer, got %v", ksfv)
}
opts := types.BuildCachePruneOptions{
All: httputils.BoolValue(r, "all"),
Filters: filters,
KeepStorage: int64(ks),
}
report, err := br.backend.PruneCache(ctx, opts)
if err != nil {
return err
}
@@ -230,11 +253,6 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
return errdefs.InvalidParameter(errors.New("squash is only supported with experimental mode"))
}
// check if the builder feature has been enabled from daemon as well.
if buildOptions.Version == types.BuilderBuildKit && br.builderVersion != "" && br.builderVersion != types.BuilderBuildKit {
return errdefs.InvalidParameter(errors.New("buildkit is not enabled on daemon"))
}
out := io.Writer(output)
if buildOptions.SuppressOutput {
out = notVerboseBuffer

View File

@@ -6,12 +6,14 @@ import (
"context"
"encoding/base64"
"encoding/json"
"errors"
"io"
"net/http"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/errdefs"
gddohttputil "github.com/golang/gddo/httputil"
)
@@ -37,7 +39,10 @@ func (s *containerRouter) postContainersCopy(ctx context.Context, w http.Respons
cfg := types.CopyConfig{}
if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
return err
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
if cfg.Resource == "" {

View File

@@ -3,6 +3,7 @@ package container // import "github.com/docker/docker/api/server/router/containe
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
@@ -44,7 +45,10 @@ func (s *containerRouter) postContainerExecCreate(ctx context.Context, w http.Re
execConfig := &types.ExecConfig{}
if err := json.NewDecoder(r.Body).Decode(execConfig); err != nil {
return err
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
if len(execConfig.Cmd) == 0 {
@@ -84,7 +88,10 @@ func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.Res
execStartCheck := &types.ExecStartCheck{}
if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil {
return err
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
if exists, err := s.backend.ExecExists(execName); !exists {

View File

@@ -3,6 +3,7 @@ package network // import "github.com/docker/docker/api/server/router/network"
import (
"context"
"encoding/json"
"io"
"net/http"
"strconv"
"strings"
@@ -215,7 +216,10 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr
}
if err := json.NewDecoder(r.Body).Decode(&create); err != nil {
return err
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
if nws, err := n.cluster.GetNetworksByName(create.Name); err == nil && len(nws) > 0 {
@@ -261,7 +265,10 @@ func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseW
}
if err := json.NewDecoder(r.Body).Decode(&connect); err != nil {
return err
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
// Unlike other operations, we does not check ambiguity of the name/ID here.
@@ -282,7 +289,10 @@ func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.Respon
}
if err := json.NewDecoder(r.Body).Decode(&disconnect); err != nil {
return err
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
return n.backend.DisconnectContainerFromNetwork(disconnect.Container, vars["id"], disconnect.Force)

View File

@@ -4,6 +4,7 @@ import (
"context"
"encoding/base64"
"encoding/json"
"io"
"net/http"
"strconv"
"strings"
@@ -12,6 +13,7 @@ import (
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/errdefs"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/streamformatter"
"github.com/pkg/errors"
@@ -276,7 +278,10 @@ func (pr *pluginRouter) pushPlugin(ctx context.Context, w http.ResponseWriter, r
func (pr *pluginRouter) setPlugin(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var args []string
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
return err
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
if err := pr.backend.Set(vars["name"], args); err != nil {
return err

View File

@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
@@ -21,7 +22,16 @@ import (
func (sr *swarmRouter) initCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var req types.InitRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return err
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
version := httputils.VersionFromContext(ctx)
// DefaultAddrPool and SubnetSize were added in API 1.39. Ignore on older API versions.
if versions.LessThan(version, "1.39") {
req.DefaultAddrPool = nil
req.SubnetSize = 0
}
nodeID, err := sr.backend.Init(req)
if err != nil {
@@ -34,7 +44,10 @@ func (sr *swarmRouter) initCluster(ctx context.Context, w http.ResponseWriter, r
func (sr *swarmRouter) joinCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var req types.JoinRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return err
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
return sr.backend.Join(req)
}
@@ -61,7 +74,10 @@ func (sr *swarmRouter) inspectCluster(ctx context.Context, w http.ResponseWriter
func (sr *swarmRouter) updateCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var swarm types.Spec
if err := json.NewDecoder(r.Body).Decode(&swarm); err != nil {
return err
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
rawVersion := r.URL.Query().Get("version")
@@ -112,7 +128,10 @@ func (sr *swarmRouter) updateCluster(ctx context.Context, w http.ResponseWriter,
func (sr *swarmRouter) unlockCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var req types.UnlockRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return err
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
if err := sr.backend.UnlockSwarm(req); err != nil {
@@ -175,7 +194,10 @@ func (sr *swarmRouter) getService(ctx context.Context, w http.ResponseWriter, r
func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var service types.ServiceSpec
if err := json.NewDecoder(r.Body).Decode(&service); err != nil {
return err
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
// Get returns "" if the header does not exist
@@ -198,7 +220,10 @@ func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter,
func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var service types.ServiceSpec
if err := json.NewDecoder(r.Body).Decode(&service); err != nil {
return err
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
rawVersion := r.URL.Query().Get("version")
@@ -291,7 +316,10 @@ func (sr *swarmRouter) getNode(ctx context.Context, w http.ResponseWriter, r *ht
func (sr *swarmRouter) updateNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var node types.NodeSpec
if err := json.NewDecoder(r.Body).Decode(&node); err != nil {
return err
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
rawVersion := r.URL.Query().Get("version")
@@ -370,7 +398,10 @@ func (sr *swarmRouter) getSecrets(ctx context.Context, w http.ResponseWriter, r
func (sr *swarmRouter) createSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var secret types.SecretSpec
if err := json.NewDecoder(r.Body).Decode(&secret); err != nil {
return err
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
version := httputils.VersionFromContext(ctx)
if secret.Templating != nil && versions.LessThan(version, "1.37") {
@@ -408,6 +439,9 @@ func (sr *swarmRouter) getSecret(ctx context.Context, w http.ResponseWriter, r *
func (sr *swarmRouter) updateSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var secret types.SecretSpec
if err := json.NewDecoder(r.Body).Decode(&secret); err != nil {
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
@@ -441,7 +475,10 @@ func (sr *swarmRouter) getConfigs(ctx context.Context, w http.ResponseWriter, r
func (sr *swarmRouter) createConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var config types.ConfigSpec
if err := json.NewDecoder(r.Body).Decode(&config); err != nil {
return err
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
version := httputils.VersionFromContext(ctx)
@@ -480,6 +517,9 @@ func (sr *swarmRouter) getConfig(ctx context.Context, w http.ResponseWriter, r *
func (sr *swarmRouter) updateConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var config types.ConfigSpec
if err := json.NewDecoder(r.Body).Decode(&config); err != nil {
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}

View File

@@ -2,30 +2,29 @@ package system // import "github.com/docker/docker/api/server/router/system"
import (
"github.com/docker/docker/api/server/router"
"github.com/docker/docker/api/types"
buildkit "github.com/docker/docker/builder/builder-next"
"github.com/docker/docker/builder/builder-next"
"github.com/docker/docker/builder/fscache"
)
// systemRouter provides information about the Docker system overall.
// It gathers information about host, daemon and container events.
type systemRouter struct {
backend Backend
cluster ClusterBackend
routes []router.Route
fscache *fscache.FSCache // legacy
builder *buildkit.Builder
builderVersion types.BuilderVersion
backend Backend
cluster ClusterBackend
routes []router.Route
fscache *fscache.FSCache // legacy
builder *buildkit.Builder
features *map[string]bool
}
// NewRouter initializes a new system router
func NewRouter(b Backend, c ClusterBackend, fscache *fscache.FSCache, builder *buildkit.Builder, bv types.BuilderVersion) router.Router {
func NewRouter(b Backend, c ClusterBackend, fscache *fscache.FSCache, builder *buildkit.Builder, features *map[string]bool) router.Router {
r := &systemRouter{
backend: b,
cluster: c,
fscache: fscache,
builder: builder,
builderVersion: bv,
backend: b,
cluster: c,
fscache: fscache,
builder: builder,
features: features,
}
r.routes = []router.Route{

View File

@@ -8,6 +8,7 @@ import (
"time"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/server/router/build"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/filters"
@@ -26,7 +27,8 @@ func optionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request,
}
func (s *systemRouter) pingHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if bv := s.builderVersion; bv != "" {
builderVersion := build.BuilderVersion(*s.features)
if bv := builderVersion; bv != "" {
w.Header().Set("Builder-Version", string(bv))
}
_, err := w.Write([]byte{'O', 'K'})

View File

@@ -56,7 +56,7 @@ func (v *volumeRouter) postVolumesCreate(ctx context.Context, w http.ResponseWri
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return err
return errdefs.InvalidParameter(err)
}
volume, err := v.backend.Create(ctx, req.Name, req.Driver, opts.WithCreateOptions(req.DriverOpts), opts.WithCreateLabels(req.Labels))

View File

@@ -1473,11 +1473,9 @@ definitions:
type: "string"
Options:
description: "Driver-specific options, specified as a map."
type: "array"
items:
type: "object"
additionalProperties:
type: "string"
type: "object"
additionalProperties:
type: "string"
NetworkContainer:
type: "object"
@@ -1513,6 +1511,31 @@ definitions:
aux:
$ref: "#/definitions/ImageID"
BuildCache:
type: "object"
properties:
ID:
type: "string"
Parent:
type: "string"
Type:
type: "string"
Description:
type: "string"
InUse:
type: "boolean"
Shared:
type: "boolean"
Size:
type: "integer"
CreatedAt:
type: "integer"
LastUsedAt:
type: "integer"
x-nullable: true
UsageCount:
type: "integer"
ImageID:
type: "object"
description: "Image ID or Digest"
@@ -2434,6 +2457,22 @@ definitions:
description: "Whether there is currently a root CA rotation in progress for the swarm"
type: "boolean"
example: false
DefaultAddrPool:
description: |
Default Address Pool specifies default subnet pools for global scope networks.
type: "array"
items:
type: "string"
format: "CIDR"
example: ["10.10.0.0/16", "20.20.0.0/16"]
SubnetSize:
description: |
SubnetSize specifies the subnet size of the networks created from the default subnet pool
type: "integer"
format: "uint32"
maximum: 29
default: 24
example: 24
JoinTokens:
description: |
@@ -3722,18 +3761,22 @@ definitions:
description: |
HTTP-proxy configured for the daemon. This value is obtained from the
[`HTTP_PROXY`](https://www.gnu.org/software/wget/manual/html_node/Proxies.html) environment variable.
Credentials ([user info component](https://tools.ietf.org/html/rfc3986#section-3.2.1)) in the proxy URL
are masked in the API response.
Containers do not automatically inherit this configuration.
type: "string"
example: "http://user:pass@proxy.corp.example.com:8080"
example: "http://xxxxx:xxxxx@proxy.corp.example.com:8080"
HttpsProxy:
description: |
HTTPS-proxy configured for the daemon. This value is obtained from the
[`HTTPS_PROXY`](https://www.gnu.org/software/wget/manual/html_node/Proxies.html) environment variable.
Credentials ([user info component](https://tools.ietf.org/html/rfc3986#section-3.2.1)) in the proxy URL
are masked in the API response.
Containers do not automatically inherit this configuration.
type: "string"
example: "https://user:pass@proxy.corp.example.com:4443"
example: "https://xxxxx:xxxxx@proxy.corp.example.com:4443"
NoProxy:
description: |
Comma-separated list of domain extensions for which no proxy should be
@@ -3823,10 +3866,10 @@ definitions:
$ref: "#/definitions/Runtime"
default:
runc:
path: "docker-runc"
path: "runc"
example:
runc:
path: "docker-runc"
path: "runc"
runc-master:
path: "/go/bin/runc"
custom:
@@ -6358,6 +6401,29 @@ paths:
produces:
- "application/json"
operationId: "BuildPrune"
parameters:
- name: "keep-storage"
in: "query"
description: "Amount of disk space in bytes to keep for cache"
type: "integer"
format: "int64"
- name: "all"
in: "query"
type: "boolean"
description: "Remove all types of build cache"
- name: "filters"
in: "query"
type: "string"
description: |
A JSON encoded value of the filters (a `map[string][]string`) to process on the list of build cache objects. Available filters:
- `until=<duration>`: duration relative to daemon's time, during which build cache was not used, in Go's duration format (e.g., '24h')
- `id=<id>`
- `parent=<id>`
- `type=<string>`
- `description=<string>`
- `inuse`
- `shared`
- `private`
responses:
200:
description: "No error"
@@ -6365,6 +6431,11 @@ paths:
type: "object"
title: "BuildPruneResponse"
properties:
CachesDeleted:
type: "array"
items:
description: "ID of build cache object"
type: "string"
SpaceReclaimed:
description: "Disk space reclaimed in bytes"
type: "integer"
@@ -7199,6 +7270,10 @@ paths:
type: "array"
items:
$ref: "#/definitions/Volume"
BuildCache:
type: "array"
items:
$ref: "#/definitions/BuildCache"
example:
LayersSize: 1092588
Images:
@@ -9284,7 +9359,10 @@ paths:
- name: "version"
in: "query"
description: "The version number of the service object being updated. This is required to avoid conflicting writes."
description: "The version number of the service object being updated.
This is required to avoid conflicting writes.
This version number should be the value as currently set on the service *before* the update.
You can find the current version by calling `GET /services/{id}`"
required: true
type: "integer"
- name: "registryAuthFrom"

View File

@@ -543,6 +543,7 @@ type ImagesPruneReport struct {
// BuildCachePruneReport contains the response for Engine API:
// POST "/build/prune"
type BuildCachePruneReport struct {
CachesDeleted []string
SpaceReclaimed uint64
}
@@ -592,14 +593,21 @@ type BuildResult struct {
// BuildCache contains information about a build cache record
type BuildCache struct {
ID string
Mutable bool
InUse bool
Size int64
ID string
Parent string
Type string
Description string
InUse bool
Shared bool
Size int64
CreatedAt time.Time
LastUsedAt *time.Time
UsageCount int
Parent string
Description string
}
// BuildCachePruneOptions hold parameters to prune the build cache
type BuildCachePruneOptions struct {
All bool
KeepStorage int64
Filters filters.Args
}

View File

@@ -34,6 +34,7 @@ import (
"github.com/moby/buildkit/util/flightcontrol"
"github.com/moby/buildkit/util/imageutil"
"github.com/moby/buildkit/util/progress"
"github.com/moby/buildkit/util/resolver"
"github.com/moby/buildkit/util/tracing"
digest "github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/identity"
@@ -51,6 +52,7 @@ type SourceOpt struct {
DownloadManager distribution.RootFSDownloadManager
MetadataStore metadata.V2MetadataService
ImageStore image.Store
ResolverOpt resolver.ResolveOptionsFunc
}
type imageSource struct {
@@ -71,17 +73,25 @@ func (is *imageSource) ID() string {
return source.DockerImageScheme
}
func (is *imageSource) getResolver(ctx context.Context) remotes.Resolver {
return docker.NewResolver(docker.ResolverOptions{
Client: tracing.DefaultClient,
Credentials: is.getCredentialsFromSession(ctx),
})
func (is *imageSource) getResolver(ctx context.Context, rfn resolver.ResolveOptionsFunc, ref string) remotes.Resolver {
opt := docker.ResolverOptions{
Client: tracing.DefaultClient,
}
if rfn != nil {
opt = rfn(ref)
}
opt.Credentials = is.getCredentialsFromSession(ctx)
r := docker.NewResolver(opt)
return r
}
func (is *imageSource) getCredentialsFromSession(ctx context.Context) func(string) (string, string, error) {
id := session.FromContext(ctx)
if id == "" {
return nil
// can be removed after containerd/containerd#2812
return func(string) (string, string, error) {
return "", "", nil
}
}
return func(host string) (string, string, error) {
timeoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
@@ -118,7 +128,7 @@ func (is *imageSource) resolveRemote(ctx context.Context, ref string, platform *
dt []byte
}
res, err := is.g.Do(ctx, ref, func(ctx context.Context) (interface{}, error) {
dgst, dt, err := imageutil.Config(ctx, ref, is.getResolver(ctx), is.ContentStore, platform)
dgst, dt, err := imageutil.Config(ctx, ref, is.getResolver(ctx, is.ResolverOpt, ref), is.ContentStore, platform)
if err != nil {
return nil, err
}
@@ -181,7 +191,7 @@ func (is *imageSource) Resolve(ctx context.Context, id source.Identifier) (sourc
p := &puller{
src: imageIdentifier,
is: is,
resolver: is.getResolver(ctx),
resolver: is.getResolver(ctx, is.ResolverOpt, imageIdentifier.Reference.String()),
platform: platform,
}
return p, nil
@@ -516,6 +526,15 @@ func (p *puller) Snapshot(ctx context.Context) (cache.ImmutableRef, error) {
return nil, err
}
// TODO: handle windows layers for cross platform builds
if p.src.RecordType != "" && cache.GetRecordType(ref) == "" {
if err := cache.SetRecordType(ref, p.src.RecordType); err != nil {
ref.Release(context.TODO())
return nil, err
}
}
return ref, nil
}

View File

@@ -5,10 +5,10 @@ import (
"os"
"path/filepath"
"github.com/boltdb/bolt"
"github.com/docker/docker/layer"
"github.com/docker/docker/pkg/ioutils"
"github.com/pkg/errors"
bolt "go.etcd.io/bbolt"
"golang.org/x/sync/errgroup"
)

View File

@@ -7,7 +7,6 @@ import (
"strings"
"sync"
"github.com/boltdb/bolt"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/snapshots"
"github.com/docker/docker/daemon/graphdriver"
@@ -16,6 +15,7 @@ import (
"github.com/moby/buildkit/snapshot"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
bolt "go.etcd.io/bbolt"
)
var keyParent = []byte("parent")
@@ -110,6 +110,10 @@ func (s *snapshotter) chainID(key string) (layer.ChainID, bool) {
return "", false
}
func (s *snapshotter) GetLayer(key string) (layer.Layer, error) {
return s.getLayer(key, true)
}
func (s *snapshotter) getLayer(key string, withCommitted bool) (layer.Layer, error) {
s.mu.Lock()
l, ok := s.refs[key]
@@ -422,10 +426,11 @@ func (s *snapshotter) Close() error {
}
type mountable struct {
mu sync.Mutex
mounts []mount.Mount
acquire func() ([]mount.Mount, error)
release func() error
mu sync.Mutex
mounts []mount.Mount
acquire func() ([]mount.Mount, error)
release func() error
refCount int
}
func (m *mountable) Mount() ([]mount.Mount, error) {
@@ -433,6 +438,7 @@ func (m *mountable) Mount() ([]mount.Mount, error) {
defer m.mu.Unlock()
if m.mounts != nil {
m.refCount++
return m.mounts, nil
}
@@ -441,6 +447,7 @@ func (m *mountable) Mount() ([]mount.Mount, error) {
return nil, err
}
m.mounts = mounts
m.refCount = 1
return m.mounts, nil
}
@@ -448,6 +455,13 @@ func (m *mountable) Mount() ([]mount.Mount, error) {
func (m *mountable) Release() error {
m.mu.Lock()
defer m.mu.Unlock()
if m.refCount > 1 {
m.refCount--
return nil
}
m.refCount = 0
if m.release == nil {
return nil
}

View File

@@ -2,6 +2,7 @@ package buildkit
import (
"context"
"fmt"
"io"
"net"
"strings"
@@ -13,32 +14,67 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/builder"
"github.com/docker/docker/daemon/config"
"github.com/docker/docker/daemon/images"
"github.com/docker/docker/pkg/streamformatter"
"github.com/docker/docker/pkg/system"
"github.com/docker/libnetwork"
controlapi "github.com/moby/buildkit/api/services/control"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/control"
"github.com/moby/buildkit/identity"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/solver/llbsolver"
"github.com/moby/buildkit/util/entitlements"
"github.com/moby/buildkit/util/resolver"
"github.com/moby/buildkit/util/tracing"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
grpcmetadata "google.golang.org/grpc/metadata"
)
type errMultipleFilterValues struct{}
func (errMultipleFilterValues) Error() string { return "filters expect only one value" }
func (errMultipleFilterValues) InvalidParameter() {}
type errConflictFilter struct {
a, b string
}
func (e errConflictFilter) Error() string {
return fmt.Sprintf("conflicting filters: %q and %q", e.a, e.b)
}
func (errConflictFilter) InvalidParameter() {}
var cacheFields = map[string]bool{
"id": true,
"parent": true,
"type": true,
"description": true,
"inuse": true,
"shared": true,
"private": true,
// fields from buildkit that are not exposed
"mutable": false,
"immutable": false,
}
func init() {
llbsolver.AllowNetworkHostUnstable = true
}
// Opt is option struct required for creating the builder
type Opt struct {
SessionManager *session.Manager
Root string
Dist images.DistributionServices
NetworkController libnetwork.NetworkController
SessionManager *session.Manager
Root string
Dist images.DistributionServices
NetworkController libnetwork.NetworkController
DefaultCgroupParent string
ResolverOpt resolver.ResolveOptionsFunc
BuilderConfig config.BuilderConfig
}
// Builder can build using BuildKit backend
@@ -86,48 +122,72 @@ func (b *Builder) DiskUsage(ctx context.Context) ([]*types.BuildCache, error) {
var items []*types.BuildCache
for _, r := range duResp.Record {
items = append(items, &types.BuildCache{
ID: r.ID,
Mutable: r.Mutable,
InUse: r.InUse,
Size: r.Size_,
ID: r.ID,
Parent: r.Parent,
Type: r.RecordType,
Description: r.Description,
InUse: r.InUse,
Shared: r.Shared,
Size: r.Size_,
CreatedAt: r.CreatedAt,
LastUsedAt: r.LastUsedAt,
UsageCount: int(r.UsageCount),
Parent: r.Parent,
Description: r.Description,
})
}
return items, nil
}
// Prune clears all reclaimable build cache
func (b *Builder) Prune(ctx context.Context) (int64, error) {
func (b *Builder) Prune(ctx context.Context, opts types.BuildCachePruneOptions) (int64, []string, error) {
ch := make(chan *controlapi.UsageRecord)
eg, ctx := errgroup.WithContext(ctx)
validFilters := make(map[string]bool, 1+len(cacheFields))
validFilters["unused-for"] = true
validFilters["until"] = true
validFilters["label"] = true // TODO(tiborvass): handle label
validFilters["label!"] = true // TODO(tiborvass): handle label!
for k, v := range cacheFields {
validFilters[k] = v
}
if err := opts.Filters.Validate(validFilters); err != nil {
return 0, nil, err
}
pi, err := toBuildkitPruneInfo(opts)
if err != nil {
return 0, nil, err
}
eg.Go(func() error {
defer close(ch)
return b.controller.Prune(&controlapi.PruneRequest{}, &pruneProxy{
return b.controller.Prune(&controlapi.PruneRequest{
All: pi.All,
KeepDuration: int64(pi.KeepDuration),
KeepBytes: pi.KeepBytes,
Filter: pi.Filter,
}, &pruneProxy{
streamProxy: streamProxy{ctx: ctx},
ch: ch,
})
})
var size int64
var cacheIDs []string
eg.Go(func() error {
for r := range ch {
size += r.Size_
cacheIDs = append(cacheIDs, r.ID)
}
return nil
})
if err := eg.Wait(); err != nil {
return 0, err
return 0, nil, err
}
return size, nil
return size, cacheIDs, nil
}
// Build executes a build request
@@ -179,7 +239,9 @@ func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder.
id := identity.NewID()
frontendAttrs := map[string]string{}
frontendAttrs := map[string]string{
"override-copy-image": "docker.io/docker/dockerfile-copy:v0.1.9@sha256:e8f159d3f00786604b93c675ee2783f8dc194bb565e61ca5788f6a6e9d304061",
}
if opt.Options.Target != "" {
frontendAttrs["target"] = opt.Options.Target
@@ -460,6 +522,7 @@ func toBuildkitExtraHosts(inp []string) (string, error) {
hosts := make([]string, 0, len(inp))
for _, h := range inp {
parts := strings.Split(h, ":")
if len(parts) != 2 || parts[0] == "" || net.ParseIP(parts[1]) == nil {
return "", errors.Errorf("invalid host %s", h)
}
@@ -467,3 +530,56 @@ func toBuildkitExtraHosts(inp []string) (string, error) {
}
return strings.Join(hosts, ","), nil
}
func toBuildkitPruneInfo(opts types.BuildCachePruneOptions) (client.PruneInfo, error) {
var until time.Duration
untilValues := opts.Filters.Get("until") // canonical
unusedForValues := opts.Filters.Get("unused-for") // deprecated synonym for "until" filter
if len(untilValues) > 0 && len(unusedForValues) > 0 {
return client.PruneInfo{}, errConflictFilter{"until", "unused-for"}
}
filterKey := "until"
if len(unusedForValues) > 0 {
filterKey = "unused-for"
}
untilValues = append(untilValues, unusedForValues...)
switch len(untilValues) {
case 0:
// nothing to do
case 1:
var err error
until, err = time.ParseDuration(untilValues[0])
if err != nil {
return client.PruneInfo{}, errors.Wrapf(err, "%q filter expects a duration (e.g., '24h')", filterKey)
}
default:
return client.PruneInfo{}, errMultipleFilterValues{}
}
bkFilter := make([]string, 0, opts.Filters.Len())
for cacheField := range cacheFields {
if opts.Filters.Include(cacheField) {
values := opts.Filters.Get(cacheField)
switch len(values) {
case 0:
bkFilter = append(bkFilter, cacheField)
case 1:
if cacheField == "id" {
bkFilter = append(bkFilter, cacheField+"~="+values[0])
} else {
bkFilter = append(bkFilter, cacheField+"=="+values[0])
}
default:
return client.PruneInfo{}, errMultipleFilterValues{}
}
}
}
return client.PruneInfo{
All: opts.All,
KeepDuration: until,
KeepBytes: opts.KeepStorage,
Filter: []string{strings.Join(bkFilter, ",")},
}, nil
}

View File

@@ -6,14 +6,19 @@ import (
"path/filepath"
"github.com/containerd/containerd/content/local"
"github.com/docker/docker/api/types"
"github.com/docker/docker/builder/builder-next/adapters/containerimage"
"github.com/docker/docker/builder/builder-next/adapters/snapshot"
containerimageexp "github.com/docker/docker/builder/builder-next/exporter"
"github.com/docker/docker/builder/builder-next/imagerefchecker"
mobyworker "github.com/docker/docker/builder/builder-next/worker"
"github.com/docker/docker/daemon/config"
"github.com/docker/docker/daemon/graphdriver"
units "github.com/docker/go-units"
"github.com/moby/buildkit/cache"
"github.com/moby/buildkit/cache/metadata"
registryremotecache "github.com/moby/buildkit/cache/remotecache/registry"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/control"
"github.com/moby/buildkit/exporter"
"github.com/moby/buildkit/frontend"
@@ -21,7 +26,7 @@ import (
"github.com/moby/buildkit/frontend/gateway"
"github.com/moby/buildkit/frontend/gateway/forwarder"
"github.com/moby/buildkit/snapshot/blobmapping"
"github.com/moby/buildkit/solver/boltdbcachestorage"
"github.com/moby/buildkit/solver/bboltcachestorage"
"github.com/moby/buildkit/worker"
"github.com/pkg/errors"
)
@@ -69,9 +74,20 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
MetadataStore: md,
})
layerGetter, ok := sbase.(imagerefchecker.LayerGetter)
if !ok {
return nil, errors.Errorf("snapshotter does not implement layergetter")
}
refChecker := imagerefchecker.New(imagerefchecker.Opt{
ImageStore: dist.ImageStore,
LayerGetter: layerGetter,
})
cm, err := cache.NewManager(cache.ManagerOpt{
Snapshotter: snapshotter,
MetadataStore: md,
Snapshotter: snapshotter,
MetadataStore: md,
PruneRefChecker: refChecker,
})
if err != nil {
return nil, err
@@ -85,12 +101,13 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
MetadataStore: dist.V2MetadataService,
ImageStore: dist.ImageStore,
ReferenceStore: dist.ReferenceStore,
ResolverOpt: opt.ResolverOpt,
})
if err != nil {
return nil, err
}
exec, err := newExecutor(root, opt.NetworkController)
exec, err := newExecutor(root, opt.DefaultCgroupParent, opt.NetworkController)
if err != nil {
return nil, err
}
@@ -109,17 +126,23 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
return nil, err
}
cacheStorage, err := boltdbcachestorage.NewStore(filepath.Join(opt.Root, "cache.db"))
cacheStorage, err := bboltcachestorage.NewStore(filepath.Join(opt.Root, "cache.db"))
if err != nil {
return nil, err
}
gcPolicy, err := getGCPolicy(opt.BuilderConfig, root)
if err != nil {
return nil, errors.Wrap(err, "could not get builder GC policy")
}
wopt := mobyworker.Opt{
ID: "moby",
SessionManager: opt.SessionManager,
MetadataStore: md,
ContentStore: store,
CacheManager: cm,
GCPolicy: gcPolicy,
Snapshotter: snapshotter,
Executor: exec,
ImageSource: src,
@@ -148,7 +171,48 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
WorkerController: wc,
Frontends: frontends,
CacheKeyStorage: cacheStorage,
ResolveCacheImporterFunc: registryremotecache.ResolveCacheImporterFunc(opt.SessionManager),
ResolveCacheImporterFunc: registryremotecache.ResolveCacheImporterFunc(opt.SessionManager, opt.ResolverOpt),
// TODO: set ResolveCacheExporterFunc for exporting cache
})
}
func getGCPolicy(conf config.BuilderConfig, root string) ([]client.PruneInfo, error) {
var gcPolicy []client.PruneInfo
if conf.GC.Enabled {
var (
defaultKeepStorage int64
err error
)
if conf.GC.DefaultKeepStorage != "" {
defaultKeepStorage, err = units.RAMInBytes(conf.GC.DefaultKeepStorage)
if err != nil {
return nil, errors.Wrapf(err, "could not parse '%s' as Builder.GC.DefaultKeepStorage config", conf.GC.DefaultKeepStorage)
}
}
if conf.GC.Policy == nil {
gcPolicy = mobyworker.DefaultGCPolicy(root, defaultKeepStorage)
} else {
gcPolicy = make([]client.PruneInfo, len(conf.GC.Policy))
for i, p := range conf.GC.Policy {
b, err := units.RAMInBytes(p.KeepStorage)
if err != nil {
return nil, err
}
if b == 0 {
b = defaultKeepStorage
}
gcPolicy[i], err = toBuildkitPruneInfo(types.BuildCachePruneOptions{
All: p.All,
KeepStorage: b,
Filters: p.Filter,
})
if err != nil {
return nil, err
}
}
}
}
return gcPolicy, nil
}

View File

@@ -3,41 +3,47 @@
package buildkit
import (
"fmt"
"os"
"path/filepath"
"strconv"
"sync"
"github.com/docker/libnetwork"
"github.com/moby/buildkit/executor"
"github.com/moby/buildkit/executor/runcexecutor"
"github.com/moby/buildkit/identity"
"github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/util/network"
"github.com/pkg/errors"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
)
const networkName = "bridge"
func newExecutor(root string, net libnetwork.NetworkController) (executor.Executor, error) {
// FIXME: fix bridge networking
_ = bridgeProvider{}
func newExecutor(root, cgroupParent string, net libnetwork.NetworkController) (executor.Executor, error) {
networkProviders := map[pb.NetMode]network.Provider{
pb.NetMode_UNSET: &bridgeProvider{NetworkController: net},
pb.NetMode_HOST: network.NewHostProvider(),
pb.NetMode_NONE: network.NewNoneProvider(),
}
return runcexecutor.New(runcexecutor.Opt{
Root: filepath.Join(root, "executor"),
CommandCandidates: []string{"docker-runc", "runc"},
}, nil)
Root: filepath.Join(root, "executor"),
CommandCandidates: []string{"runc"},
DefaultCgroupParent: cgroupParent,
}, networkProviders)
}
type bridgeProvider struct {
libnetwork.NetworkController
}
func (p *bridgeProvider) NewInterface() (network.Interface, error) {
func (p *bridgeProvider) New() (network.Namespace, error) {
n, err := p.NetworkByName(networkName)
if err != nil {
return nil, err
}
iface := &lnInterface{ready: make(chan struct{})}
iface := &lnInterface{ready: make(chan struct{}), provider: p}
iface.Once.Do(func() {
go iface.init(p.NetworkController, n)
})
@@ -45,46 +51,26 @@ func (p *bridgeProvider) NewInterface() (network.Interface, error) {
return iface, nil
}
func (p *bridgeProvider) Release(iface network.Interface) error {
go func() {
if err := p.release(iface); err != nil {
logrus.Errorf("%s", err)
}
}()
return nil
}
func (p *bridgeProvider) release(iface network.Interface) error {
li, ok := iface.(*lnInterface)
if !ok {
return errors.Errorf("invalid interface %T", iface)
}
err := li.sbx.Delete()
if err1 := li.ep.Delete(true); err1 != nil && err == nil {
err = err1
}
return err
}
type lnInterface struct {
ep libnetwork.Endpoint
sbx libnetwork.Sandbox
sync.Once
err error
ready chan struct{}
err error
ready chan struct{}
provider *bridgeProvider
}
func (iface *lnInterface) init(c libnetwork.NetworkController, n libnetwork.Network) {
defer close(iface.ready)
id := identity.NewID()
ep, err := n.CreateEndpoint(id)
ep, err := n.CreateEndpoint(id, libnetwork.CreateOptionDisableResolution())
if err != nil {
iface.err = err
return
}
sbx, err := c.NewSandbox(id)
sbx, err := c.NewSandbox(id, libnetwork.OptionUseExternalKey())
if err != nil {
iface.err = err
return
@@ -99,14 +85,26 @@ func (iface *lnInterface) init(c libnetwork.NetworkController, n libnetwork.Netw
iface.ep = ep
}
func (iface *lnInterface) Set(pid int) error {
func (iface *lnInterface) Set(s *specs.Spec) {
<-iface.ready
if iface.err != nil {
return iface.err
return
}
// attach netns to bridge within the container namespace, using reexec in a prestart hook
s.Hooks = &specs.Hooks{
Prestart: []specs.Hook{{
Path: filepath.Join("/proc", strconv.Itoa(os.Getpid()), "exe"),
Args: []string{"libnetwork-setkey", iface.sbx.ContainerID(), iface.provider.NetworkController.ID()},
}},
}
return iface.sbx.SetKey(fmt.Sprintf("/proc/%d/ns/net", pid))
}
func (iface *lnInterface) Remove(pid int) error {
return nil
func (iface *lnInterface) Close() error {
<-iface.ready
go func() {
if err := iface.sbx.Delete(); err != nil {
logrus.Errorf("failed to delete builder network sandbox: %v", err)
}
}()
return iface.err
}

View File

@@ -10,7 +10,7 @@ import (
"github.com/moby/buildkit/executor"
)
func newExecutor(_ string, _ libnetwork.NetworkController) (executor.Executor, error) {
func newExecutor(_, _ string, _ libnetwork.NetworkController) (executor.Executor, error) {
return &winExecutor{}, nil
}

View File

@@ -0,0 +1,96 @@
package imagerefchecker
import (
"sync"
"github.com/docker/docker/image"
"github.com/docker/docker/layer"
"github.com/moby/buildkit/cache"
)
// LayerGetter abstracts away the snapshotter
type LayerGetter interface {
GetLayer(string) (layer.Layer, error)
}
// Opt represents the options needed to create a refchecker
type Opt struct {
LayerGetter LayerGetter
ImageStore image.Store
}
// New creates new image reference checker that can be used to see if a reference
// is being used by any of the images in the image store
func New(opt Opt) cache.ExternalRefCheckerFunc {
return func() (cache.ExternalRefChecker, error) {
return &checker{opt: opt, layers: lchain{}, cache: map[string]bool{}}, nil
}
}
type lchain map[layer.DiffID]lchain
func (c lchain) add(ids []layer.DiffID) {
if len(ids) == 0 {
return
}
id := ids[0]
ch, ok := c[id]
if !ok {
ch = lchain{}
c[id] = ch
}
ch.add(ids[1:])
}
func (c lchain) has(ids []layer.DiffID) bool {
if len(ids) == 0 {
return true
}
ch, ok := c[ids[0]]
return ok && ch.has(ids[1:])
}
type checker struct {
opt Opt
once sync.Once
layers lchain
cache map[string]bool
}
func (c *checker) Exists(key string) bool {
if c.opt.ImageStore == nil {
return false
}
c.once.Do(c.init)
if b, ok := c.cache[key]; ok {
return b
}
l, err := c.opt.LayerGetter.GetLayer(key)
if err != nil || l == nil {
c.cache[key] = false
return false
}
ok := c.layers.has(diffIDs(l))
c.cache[key] = ok
return ok
}
func (c *checker) init() {
imgs := c.opt.ImageStore.Map()
for _, img := range imgs {
c.layers.add(img.RootFS.DiffIDs)
}
}
func diffIDs(l layer.Layer) []layer.DiffID {
p := l.Parent()
if p == nil {
return []layer.DiffID{l.DiffID()}
}
return append(diffIDs(p), l.DiffID())
}

View File

@@ -0,0 +1,51 @@
package worker
import (
"math"
"github.com/moby/buildkit/client"
)
const defaultCap int64 = 2e9 // 2GB
// tempCachePercent represents the percentage ratio of the cache size in bytes to temporarily keep for a short period of time (couple of days)
// over the total cache size in bytes. Because there is no perfect value, a mathematically pleasing one was chosen.
// The value is approximately 13.8
const tempCachePercent = math.E * math.Pi * math.Phi
// DefaultGCPolicy returns a default builder GC policy
func DefaultGCPolicy(p string, defaultKeepBytes int64) []client.PruneInfo {
keep := defaultKeepBytes
if defaultKeepBytes == 0 {
keep = detectDefaultGCCap(p)
}
tempCacheKeepBytes := int64(math.Round(float64(keep) / 100. * float64(tempCachePercent)))
const minTempCacheKeepBytes = 512 * 1e6 // 512MB
if tempCacheKeepBytes < minTempCacheKeepBytes {
tempCacheKeepBytes = minTempCacheKeepBytes
}
return []client.PruneInfo{
// if build cache uses more than 512MB delete the most easily reproducible data after it has not been used for 2 days
{
Filter: []string{"type==source.local,type==exec.cachemount,type==source.git.checkout"},
KeepDuration: 48 * 3600, // 48h
KeepBytes: tempCacheKeepBytes,
},
// remove any data not used for 60 days
{
KeepDuration: 60 * 24 * 3600, // 60d
KeepBytes: keep,
},
// keep the unshared build cache under cap
{
KeepBytes: keep,
},
// if previous policies were insufficient start deleting internal data to keep build cache under cap
{
All: true,
KeepBytes: keep,
},
}
}

View File

@@ -0,0 +1,17 @@
// +build !windows
package worker
import (
"syscall"
)
func detectDefaultGCCap(root string) int64 {
var st syscall.Statfs_t
if err := syscall.Statfs(root, &st); err != nil {
return defaultCap
}
diskSize := int64(st.Bsize) * int64(st.Blocks) // nolint unconvert
avail := diskSize / 10
return (avail/(1<<30) + 1) * 1e9 // round up
}

View File

@@ -0,0 +1,7 @@
// +build windows
package worker
func detectDefaultGCCap(root string) int64 {
return defaultCap
}

View File

@@ -46,6 +46,7 @@ import (
type Opt struct {
ID string
Labels map[string]string
GCPolicy []client.PruneInfo
SessionManager *session.Manager
MetadataStore *metadata.Store
Executor executor.Executor
@@ -130,9 +131,18 @@ func (w *Worker) Platforms() []ocispec.Platform {
return []ocispec.Platform{platforms.DefaultSpec()}
}
// GCPolicy returns automatic GC Policy
func (w *Worker) GCPolicy() []client.PruneInfo {
return w.Opt.GCPolicy
}
// LoadRef loads a reference by ID
func (w *Worker) LoadRef(id string) (cache.ImmutableRef, error) {
return w.CacheManager.Get(context.TODO(), id)
func (w *Worker) LoadRef(id string, hidden bool) (cache.ImmutableRef, error) {
var opts []cache.RefOption
if hidden {
opts = append(opts, cache.NoUpdateLastUsed)
}
return w.CacheManager.Get(context.TODO(), id, opts...)
}
// ResolveOp converts a LLB vertex into a LLB operation
@@ -176,8 +186,8 @@ func (w *Worker) DiskUsage(ctx context.Context, opt client.DiskUsageInfo) ([]*cl
}
// Prune deletes reclaimable build cache
func (w *Worker) Prune(ctx context.Context, ch chan client.UsageInfo, info client.PruneInfo) error {
return w.CacheManager.Prune(ctx, ch, info)
func (w *Worker) Prune(ctx context.Context, ch chan client.UsageInfo, info ...client.PruneInfo) error {
return w.CacheManager.Prune(ctx, ch, info...)
}
// Exporter returns exporter by name

View File

@@ -12,7 +12,6 @@ import (
"sync"
"time"
"github.com/boltdb/bolt"
"github.com/docker/docker/builder"
"github.com/docker/docker/builder/remotecontext"
"github.com/docker/docker/pkg/archive"
@@ -23,6 +22,8 @@ import (
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/tonistiigi/fsutil"
fsutiltypes "github.com/tonistiigi/fsutil/types"
bolt "go.etcd.io/bbolt"
"golang.org/x/sync/singleflight"
)
@@ -614,7 +615,7 @@ func (s sortableCacheSources) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func newTarsumHash(stat *fsutil.Stat) (hash.Hash, error) {
func newTarsumHash(stat *fsutiltypes.Stat) (hash.Hash, error) {
fi := &fsutil.StatInfo{Stat: stat}
p := stat.Path
if fi.IsDir() {

View File

@@ -4,19 +4,34 @@ import (
"context"
"encoding/json"
"fmt"
"net/url"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/pkg/errors"
)
// BuildCachePrune requests the daemon to delete unused cache data
func (cli *Client) BuildCachePrune(ctx context.Context) (*types.BuildCachePruneReport, error) {
func (cli *Client) BuildCachePrune(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) {
if err := cli.NewVersionError("1.31", "build prune"); err != nil {
return nil, err
}
report := types.BuildCachePruneReport{}
serverResp, err := cli.post(ctx, "/build/prune", nil, nil, nil)
query := url.Values{}
if opts.All {
query.Set("all", "1")
}
query.Set("keep-storage", fmt.Sprintf("%d", opts.KeepStorage))
filters, err := filters.ToJSON(opts.Filters)
if err != nil {
return nil, errors.Wrap(err, "prune could not marshal filters option")
}
query.Set("filters", filters)
serverResp, err := cli.post(ctx, "/build/prune", query, nil, nil)
if err != nil {
return nil, err
}

View File

@@ -413,7 +413,7 @@ func (cli *Client) SetCustomHTTPHeaders(headers map[string]string) {
func (cli *Client) Dialer() func(context.Context) (net.Conn, error) {
return func(ctx context.Context) (net.Conn, error) {
if transport, ok := cli.client.Transport.(*http.Transport); ok {
if transport.DialContext != nil {
if transport.DialContext != nil && transport.TLSClientConfig == nil {
return transport.DialContext(ctx, cli.proto, cli.addr)
}
}

View File

@@ -86,7 +86,7 @@ type DistributionAPIClient interface {
// ImageAPIClient defines API client methods for the images
type ImageAPIClient interface {
ImageBuild(ctx context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error)
BuildCachePrune(ctx context.Context) (*types.BuildCachePruneReport, error)
BuildCachePrune(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error)
BuildCancel(ctx context.Context, id string) error
ImageCreate(ctx context.Context, parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error)
ImageHistory(ctx context.Context, image string) ([]image.HistoryResponseItem, error)

View File

@@ -195,10 +195,18 @@ func (cli *Client) checkResponseErr(serverResp serverResponse) error {
return nil
}
body, err := ioutil.ReadAll(serverResp.body)
bodyMax := 1 * 1024 * 1024 // 1 MiB
bodyR := &io.LimitedReader{
R: serverResp.body,
N: int64(bodyMax),
}
body, err := ioutil.ReadAll(bodyR)
if err != nil {
return err
}
if bodyR.N == 0 {
return fmt.Errorf("request returned %s with a message (> %d bytes) for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), bodyMax, serverResp.reqURL)
}
if len(body) == 0 {
return fmt.Errorf("request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), serverResp.reqURL)
}

View File

@@ -5,12 +5,14 @@ import (
"context"
"fmt"
"io/ioutil"
"math/rand"
"net/http"
"strings"
"testing"
"github.com/docker/docker/api/types"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
// TestSetHostHeader should set fake host for local communications, set real host
@@ -87,3 +89,18 @@ func TestPlainTextError(t *testing.T) {
t.Fatalf("expected a Server Error, got %v", err)
}
}
func TestInfiniteError(t *testing.T) {
infinitR := rand.New(rand.NewSource(42))
client := &Client{
client: newMockClient(func(req *http.Request) (*http.Response, error) {
resp := &http.Response{StatusCode: http.StatusInternalServerError}
resp.Header = http.Header{}
resp.Body = ioutil.NopCloser(infinitR)
return resp, nil
}),
}
_, err := client.Ping(context.Background())
assert.Check(t, is.ErrorContains(err, "request returned Internal Server Error"))
}

View File

@@ -10,6 +10,7 @@ import (
"strings"
"time"
containerddefaults "github.com/containerd/containerd/defaults"
"github.com/docker/distribution/uuid"
"github.com/docker/docker/api"
apiserver "github.com/docker/docker/api/server"
@@ -27,7 +28,6 @@ import (
swarmrouter "github.com/docker/docker/api/server/router/swarm"
systemrouter "github.com/docker/docker/api/server/router/system"
"github.com/docker/docker/api/server/router/volume"
"github.com/docker/docker/api/types"
buildkit "github.com/docker/docker/builder/builder-next"
"github.com/docker/docker/builder/dockerfile"
"github.com/docker/docker/builder/fscache"
@@ -141,22 +141,25 @@ func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
ctx, cancel := context.WithCancel(context.Background())
if cli.Config.ContainerdAddr == "" && runtime.GOOS != "windows" {
opts, err := cli.getContainerdDaemonOpts()
if err != nil {
cancel()
return fmt.Errorf("Failed to generate containerd options: %v", err)
if !systemContainerdRunning() {
opts, err := cli.getContainerdDaemonOpts()
if err != nil {
cancel()
return fmt.Errorf("Failed to generate containerd options: %v", err)
}
r, err := supervisor.Start(ctx, filepath.Join(cli.Config.Root, "containerd"), filepath.Join(cli.Config.ExecRoot, "containerd"), opts...)
if err != nil {
cancel()
return fmt.Errorf("Failed to start containerd: %v", err)
}
cli.Config.ContainerdAddr = r.Address()
// Try to wait for containerd to shutdown
defer r.WaitTimeout(10 * time.Second)
} else {
cli.Config.ContainerdAddr = containerddefaults.DefaultAddress
}
r, err := supervisor.Start(ctx, filepath.Join(cli.Config.Root, "containerd"), filepath.Join(cli.Config.ExecRoot, "containerd"), opts...)
if err != nil {
cancel()
return fmt.Errorf("Failed to start containerd: %v", err)
}
cli.Config.ContainerdAddr = r.Address()
// Try to wait for containerd to shutdown
defer r.WaitTimeout(10 * time.Second)
}
defer cancel()
@@ -253,14 +256,14 @@ type routerOptions struct {
sessionManager *session.Manager
buildBackend *buildbackend.Backend
buildCache *fscache.FSCache // legacy
features *map[string]bool
buildkit *buildkit.Builder
builderVersion types.BuilderVersion
daemon *daemon.Daemon
api *apiserver.Server
cluster *cluster.Cluster
}
func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptions, error) {
func newRouterOptions(config *config.Config, d *daemon.Daemon) (routerOptions, error) {
opts := routerOptions{}
sm, err := session.NewManager()
if err != nil {
@@ -281,39 +284,35 @@ func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptio
return opts, errors.Wrap(err, "failed to create fscache")
}
manager, err := dockerfile.NewBuildManager(daemon.BuilderBackend(), sm, buildCache, daemon.IdentityMapping())
manager, err := dockerfile.NewBuildManager(d.BuilderBackend(), sm, buildCache, d.IdentityMapping())
if err != nil {
return opts, err
}
cgroupParent := newCgroupParent(config)
bk, err := buildkit.New(buildkit.Opt{
SessionManager: sm,
Root: filepath.Join(config.Root, "buildkit"),
Dist: daemon.DistributionServices(),
NetworkController: daemon.NetworkController(),
SessionManager: sm,
Root: filepath.Join(config.Root, "buildkit"),
Dist: d.DistributionServices(),
NetworkController: d.NetworkController(),
DefaultCgroupParent: cgroupParent,
ResolverOpt: d.NewResolveOptionsFunc(),
BuilderConfig: config.Builder,
})
if err != nil {
return opts, err
}
bb, err := buildbackend.NewBackend(daemon.ImageService(), manager, buildCache, bk)
bb, err := buildbackend.NewBackend(d.ImageService(), manager, buildCache, bk)
if err != nil {
return opts, errors.Wrap(err, "failed to create buildmanager")
}
var bv types.BuilderVersion
if v, ok := config.Features["buildkit"]; ok {
if v {
bv = types.BuilderBuildKit
} else {
bv = types.BuilderV1
}
}
return routerOptions{
sessionManager: sm,
buildBackend: bb,
buildCache: buildCache,
buildkit: bk,
builderVersion: bv,
daemon: daemon,
features: d.Features(),
daemon: d,
}, nil
}
@@ -486,9 +485,9 @@ func initRouter(opts routerOptions) {
checkpointrouter.NewRouter(opts.daemon, decoder),
container.NewRouter(opts.daemon, decoder),
image.NewRouter(opts.daemon.ImageService()),
systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildCache, opts.buildkit, opts.builderVersion),
systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildCache, opts.buildkit, opts.features),
volume.NewRouter(opts.daemon.VolumesService()),
build.NewRouter(opts.buildBackend, opts.daemon, opts.builderVersion),
build.NewRouter(opts.buildBackend, opts.daemon, opts.features),
sessionrouter.NewRouter(opts.sessionManager),
swarmrouter.NewRouter(opts.cluster),
pluginrouter.NewRouter(opts.daemon.PluginManager()),
@@ -666,3 +665,8 @@ func validateAuthzPlugins(requestedPlugins []string, pg plugingetter.PluginGette
}
return nil
}
func systemContainerdRunning() bool {
_, err := os.Lstat(containerddefaults.DefaultAddress)
return err == nil
}

View File

@@ -13,6 +13,7 @@ import (
"github.com/containerd/containerd/runtime/v1/linux"
"github.com/docker/docker/cmd/dockerd/hack"
"github.com/docker/docker/daemon"
"github.com/docker/docker/daemon/config"
"github.com/docker/docker/libcontainerd/supervisor"
"github.com/docker/libnetwork/portallocator"
"golang.org/x/sys/unix"
@@ -107,3 +108,18 @@ func wrapListeners(proto string, ls []net.Listener) []net.Listener {
}
return ls
}
func newCgroupParent(config *config.Config) string {
cgroupParent := "docker"
useSystemd := daemon.UsingSystemd(config)
if useSystemd {
cgroupParent = "system.slice"
}
if config.CgroupParent != "" {
cgroupParent = config.CgroupParent
}
if useSystemd {
cgroupParent = cgroupParent + ":" + "docker" + ":"
}
return cgroupParent
}

View File

@@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"github.com/docker/docker/daemon/config"
"github.com/docker/docker/libcontainerd/supervisor"
"github.com/sirupsen/logrus"
"golang.org/x/sys/windows"
@@ -83,3 +84,7 @@ func allocateDaemonPort(addr string) error {
func wrapListeners(proto string, ls []net.Listener) []net.Listener {
return ls
}
func newCgroupParent(config *config.Config) string {
return ""
}

View File

@@ -265,8 +265,11 @@ flags=(
CGROUP_HUGETLB
NET_CLS_CGROUP $netprio
CFS_BANDWIDTH FAIR_GROUP_SCHED RT_GROUP_SCHED
IP_NF_TARGET_REDIRECT
IP_VS
IP_VS_NFCT
IP_VS_PROTO_TCP
IP_VS_PROTO_UDP
IP_VS_RR
)
check_flags "${flags[@]}"

View File

@@ -31,7 +31,7 @@ bundle_files(){
echo $BUNDLE/binary-daemon/$f
fi
done
for f in docker-containerd docker-containerd-ctr docker-containerd-shim docker-init docker-runc; do
for f in containerd ctr containerd-shim docker-init runc; do
echo $BUNDLE/binary-daemon/$f
done
if [ -d $BUNDLE/dynbinary-client ]; then

View File

@@ -123,7 +123,7 @@ func (daemon *Daemon) containerAttach(c *container.Container, cfg *stream.Attach
return logger.ErrReadLogsNotSupported{}
}
logs := cLog.ReadLogs(logger.ReadConfig{Tail: -1})
defer logs.Close()
defer logs.ConsumerGone()
LogLoop:
for {

View File

@@ -41,6 +41,7 @@ package cluster // import "github.com/docker/docker/daemon/cluster"
import (
"context"
"fmt"
"math"
"net"
"os"
"path/filepath"
@@ -67,9 +68,10 @@ const stateFile = "docker-state.json"
const defaultAddr = "0.0.0.0:2377"
const (
initialReconnectDelay = 100 * time.Millisecond
maxReconnectDelay = 30 * time.Second
contextPrefix = "com.docker.swarm"
initialReconnectDelay = 100 * time.Millisecond
maxReconnectDelay = 30 * time.Second
contextPrefix = "com.docker.swarm"
defaultRecvSizeForListResponse = math.MaxInt32 // the max recv limit grpc <1.4.0
)
// NetworkSubnetsProvider exposes functions for retrieving the subnets

View File

@@ -3,6 +3,7 @@ package cluster // import "github.com/docker/docker/daemon/cluster"
import (
"fmt"
"net"
"strings"
)
const (
@@ -87,6 +88,41 @@ func (c *Cluster) resolveAdvertiseAddr(advertiseAddr, listenAddrPort string) (st
return systemAddr.String(), listenAddrPort, nil
}
// validateDefaultAddrPool validates default address pool
// it also strips white space from the string before validation
func validateDefaultAddrPool(defaultAddrPool []string, size uint32) error {
if defaultAddrPool == nil {
// defaultAddrPool is not defined
return nil
}
//if size is not set, then we use default value 24
if size == 0 {
size = 24
}
// We allow max value as 29. We can have 8 IP addresses for max value 29
// If we allow 30, then we will get only 4 IP addresses. But with latest
// libnetwork LB scale implementation, we use total of 4 IP addresses for internal use.
// Hence keeping 29 as max value, we will have 8 IP addresses. This will be
// smallest subnet that can be used in overlay network.
if size > 29 {
return fmt.Errorf("subnet size is out of range: %d", size)
}
for i := range defaultAddrPool {
// trim leading and trailing white spaces
defaultAddrPool[i] = strings.TrimSpace(defaultAddrPool[i])
_, b, err := net.ParseCIDR(defaultAddrPool[i])
if err != nil {
return fmt.Errorf("invalid base pool %s: %v", defaultAddrPool[i], err)
}
ones, _ := b.Mask.Size()
if size < uint32(ones) {
return fmt.Errorf("invalid CIDR: %q. Subnet size is too small for pool: %d", defaultAddrPool[i], size)
}
}
return nil
}
func resolveDataPathAddr(dataPathAddr string) (string, error) {
if dataPathAddr == "" {
// dataPathAddr is not defined

View File

@@ -3,7 +3,6 @@ package cluster // import "github.com/docker/docker/daemon/cluster"
import (
"context"
"fmt"
"net"
"path/filepath"
"runtime"
"strings"
@@ -14,6 +13,7 @@ import (
"github.com/docker/docker/daemon/cluster/executor/container"
lncluster "github.com/docker/libnetwork/cluster"
swarmapi "github.com/docker/swarmkit/api"
"github.com/docker/swarmkit/manager/allocator/cnmallocator"
swarmnode "github.com/docker/swarmkit/node"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -115,12 +115,6 @@ func (n *nodeRunner) start(conf nodeStartConfig) error {
joinAddr = conf.RemoteAddr
}
var defaultAddrPool []*net.IPNet
for _, address := range conf.DefaultAddressPool {
if _, b, err := net.ParseCIDR(address); err == nil {
defaultAddrPool = append(defaultAddrPool, b)
}
}
// Hostname is not set here. Instead, it is obtained from
// the node description that is reported periodically
swarmnodeConfig := swarmnode.Config{
@@ -128,11 +122,13 @@ func (n *nodeRunner) start(conf nodeStartConfig) error {
ListenControlAPI: control,
ListenRemoteAPI: conf.ListenAddr,
AdvertiseRemoteAPI: conf.AdvertiseAddr,
DefaultAddrPool: defaultAddrPool,
SubnetSize: int(conf.SubnetSize),
JoinAddr: joinAddr,
StateDir: n.cluster.root,
JoinToken: conf.joinToken,
NetworkConfig: &cnmallocator.NetworkConfig{
DefaultAddrPool: conf.DefaultAddressPool,
SubnetSize: conf.SubnetSize,
},
JoinAddr: joinAddr,
StateDir: n.cluster.root,
JoinToken: conf.joinToken,
Executor: container.NewExecutor(
n.cluster.config.Backend,
n.cluster.config.PluginBackend,

View File

@@ -23,6 +23,7 @@ import (
gogotypes "github.com/gogo/protobuf/types"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"google.golang.org/grpc"
)
// GetServices returns all services of a managed swarm cluster.
@@ -67,7 +68,9 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv
r, err := state.controlClient.ListServices(
ctx,
&swarmapi.ListServicesRequest{Filters: filters})
&swarmapi.ListServicesRequest{Filters: filters},
grpc.MaxCallRecvMsgSize(defaultRecvSizeForListResponse),
)
if err != nil {
return nil, err
}

View File

@@ -92,6 +92,10 @@ func (c *Cluster) Init(req types.InitRequest) (string, error) {
}
}
//Validate Default Address Pool input
if err := validateDefaultAddrPool(req.DefaultAddrPool, req.SubnetSize); err != nil {
return "", err
}
nr, err := c.newNodeRunner(nodeStartConfig{
forceNewCluster: req.ForceNewCluster,
autolock: req.AutoLockManagers,

View File

@@ -8,6 +8,7 @@ import (
types "github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/daemon/cluster/convert"
swarmapi "github.com/docker/swarmkit/api"
"google.golang.org/grpc"
)
// GetTasks returns a list of tasks matching the filter options.
@@ -53,7 +54,9 @@ func (c *Cluster) GetTasks(options apitypes.TaskListOptions) ([]types.Task, erro
r, err = state.controlClient.ListTasks(
ctx,
&swarmapi.ListTasksRequest{Filters: filters})
&swarmapi.ListTasksRequest{Filters: filters},
grpc.MaxCallRecvMsgSize(defaultRecvSizeForListResponse),
)
return err
}); err != nil {
return nil, err

22
daemon/config/builder.go Normal file
View File

@@ -0,0 +1,22 @@
package config
import "github.com/docker/docker/api/types/filters"
// BuilderGCRule represents a GC rule for buildkit cache
type BuilderGCRule struct {
All bool `json:",omitempty"`
Filter filters.Args `json:",omitempty"`
KeepStorage string `json:",omitempty"`
}
// BuilderGCConfig contains GC config for a buildkit builder
type BuilderGCConfig struct {
Enabled bool `json:",omitempty"`
Policy []BuilderGCRule `json:",omitempty"`
DefaultKeepStorage string `json:",omitempty"`
}
// BuilderConfig contains config for the builder
type BuilderConfig struct {
GC BuilderGCConfig `json:",omitempty"`
}

View File

@@ -55,6 +55,7 @@ var flatOptions = map[string]bool{
"runtimes": true,
"default-ulimits": true,
"features": true,
"builder": true,
}
// skipValidateOptions contains configuration keys
@@ -62,6 +63,17 @@ var flatOptions = map[string]bool{
// for unknown flag validation.
var skipValidateOptions = map[string]bool{
"features": true,
"builder": true,
}
// skipDuplicates contains configuration keys that
// will be skipped when checking duplicated
// configuration field defined in both daemon
// config file and from dockerd cli flags.
// This allows some configurations to be merged
// during the parsing.
var skipDuplicates = map[string]bool{
"runtimes": true,
}
// LogConfig represents the default log configuration.
@@ -215,6 +227,8 @@ type CommonConfig struct {
// Features contains a list of feature key value pairs indicating what features are enabled or disabled.
// If a certain feature doesn't appear in this list then it's unset (i.e. neither true nor false).
Features map[string]bool `json:"features,omitempty"`
Builder BuilderConfig `json:"builder,omitempty"`
}
// IsValueSet returns true if a configuration value
@@ -491,13 +505,13 @@ func findConfigurationConflicts(config map[string]interface{}, flags *pflag.Flag
duplicatedConflicts := func(f *pflag.Flag) {
// search option name in the json configuration payload if the value is a named option
if namedOption, ok := f.Value.(opts.NamedOption); ok {
if optsValue, ok := config[namedOption.Name()]; ok {
if optsValue, ok := config[namedOption.Name()]; ok && !skipDuplicates[namedOption.Name()] {
conflicts = append(conflicts, printConflict(namedOption.Name(), f.Value.String(), optsValue))
}
} else {
// search flag name in the json configuration payload
for _, name := range []string{f.Name, f.Shorthand} {
if value, ok := config[name]; ok {
if value, ok := config[name]; ok && !skipDuplicates[name] {
conflicts = append(conflicts, printConflict(name, f.Value.String(), value))
break
}

View File

@@ -9,6 +9,7 @@ import (
"context"
"fmt"
"io/ioutil"
"math/rand"
"net"
"os"
"path"
@@ -23,6 +24,8 @@ import (
"github.com/containerd/containerd"
"github.com/containerd/containerd/defaults"
"github.com/containerd/containerd/pkg/dialer"
"github.com/containerd/containerd/remotes/docker"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/swarm"
@@ -36,6 +39,8 @@ import (
"github.com/docker/docker/daemon/logger"
"github.com/docker/docker/daemon/network"
"github.com/docker/docker/errdefs"
"github.com/moby/buildkit/util/resolver"
"github.com/moby/buildkit/util/tracing"
"github.com/sirupsen/logrus"
// register graph drivers
_ "github.com/docker/docker/daemon/graphdriver/register"
@@ -136,6 +141,62 @@ func (daemon *Daemon) HasExperimental() bool {
return daemon.configStore != nil && daemon.configStore.Experimental
}
// Features returns the features map from configStore
func (daemon *Daemon) Features() *map[string]bool {
return &daemon.configStore.Features
}
// NewResolveOptionsFunc returns a call back function to resolve "registry-mirrors" and
// "insecure-registries" for buildkit
func (daemon *Daemon) NewResolveOptionsFunc() resolver.ResolveOptionsFunc {
return func(ref string) docker.ResolverOptions {
var (
registryKey = "docker.io"
mirrors = make([]string, len(daemon.configStore.Mirrors))
m = map[string]resolver.RegistryConf{}
)
// must trim "https://" or "http://" prefix
for i, v := range daemon.configStore.Mirrors {
v = strings.TrimPrefix(v, "https://")
v = strings.TrimPrefix(v, "http://")
mirrors[i] = v
}
// set "registry-mirrors"
m[registryKey] = resolver.RegistryConf{Mirrors: mirrors}
// set "insecure-registries"
for _, v := range daemon.configStore.InsecureRegistries {
v = strings.TrimPrefix(v, "http://")
m[v] = resolver.RegistryConf{
PlainHTTP: true,
}
}
def := docker.ResolverOptions{
Client: tracing.DefaultClient,
}
parsed, err := reference.ParseNormalizedNamed(ref)
if err != nil {
return def
}
host := reference.Domain(parsed)
c, ok := m[host]
if !ok {
return def
}
if len(c.Mirrors) > 0 {
def.Host = func(string) (string, error) {
return c.Mirrors[rand.Intn(len(c.Mirrors))], nil
}
}
def.PlainHTTP = c.PlainHTTP
return def
}
}
func (daemon *Daemon) restore() error {
containers := make(map[string]*container.Container)

View File

@@ -54,11 +54,11 @@ import (
const (
// DefaultShimBinary is the default shim to be used by containerd if none
// is specified
DefaultShimBinary = "docker-containerd-shim"
DefaultShimBinary = "containerd-shim"
// DefaultRuntimeBinary is the default runtime to be used by
// containerd if none is specified
DefaultRuntimeBinary = "docker-runc"
DefaultRuntimeBinary = "runc"
// See https://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/tree/kernel/sched/sched.h?id=8cd9234c64c584432f6992fe944ca9e46ca8ea76#n269
linuxMinCPUShares = 2
@@ -76,7 +76,7 @@ const (
// DefaultRuntimeName is the default runtime to be used by
// containerd if none is specified
DefaultRuntimeName = "docker-runc"
DefaultRuntimeName = "runc"
)
type containerGetter interface {
@@ -482,14 +482,14 @@ func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysi
}
cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(resources.CpusetCpus)
if err != nil {
return warnings, fmt.Errorf("Invalid value %s for cpuset cpus", resources.CpusetCpus)
return warnings, errors.Wrapf(err, "Invalid value %s for cpuset cpus", resources.CpusetCpus)
}
if !cpusAvailable {
return warnings, fmt.Errorf("Requested CPUs are not available - requested %s, available: %s", resources.CpusetCpus, sysInfo.Cpus)
}
memsAvailable, err := sysInfo.IsCpusetMemsAvailable(resources.CpusetMems)
if err != nil {
return warnings, fmt.Errorf("Invalid value %s for cpuset mems", resources.CpusetMems)
return warnings, errors.Wrapf(err, "Invalid value %s for cpuset mems", resources.CpusetMems)
}
if !memsAvailable {
return warnings, fmt.Errorf("Requested memory nodes are not available - requested %s, available: %s", resources.CpusetMems, sysInfo.Mems)
@@ -1480,7 +1480,7 @@ func (daemon *Daemon) initCgroupsPath(path string) error {
// for the period and runtime as this limits what the children can be set to.
daemon.initCgroupsPath(filepath.Dir(path))
mnt, root, err := cgroups.FindCgroupMountpointAndRoot("cpu")
mnt, root, err := cgroups.FindCgroupMountpointAndRoot("", "cpu")
if err != nil {
return err
}

View File

@@ -193,12 +193,15 @@ func verifyContainerResources(resources *containertypes.Resources, isHyperv bool
// hostconfig and config structures.
func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
warnings := []string{}
osv := system.GetOSVersion()
hyperv := daemon.runAsHyperVContainer(hostConfig)
if !hyperv && system.IsWindowsClient() && !system.IsIoTCore() {
// @engine maintainers. This block should not be removed. It partially enforces licensing
// restrictions on Windows. Ping @jhowardmsft if there are concerns or PRs to change this.
return warnings, fmt.Errorf("Windows client operating systems only support Hyper-V containers")
// On RS5, we allow (but don't strictly support) process isolation on Client SKUs.
// Prior to RS5, we don't allow process isolation on Client SKUs.
// @engine maintainers. This block should not be removed. It partially enforces licensing
// restrictions on Windows. Ping @jhowardmsft if there are concerns or PRs to change this.
if !hyperv && system.IsWindowsClient() && osv.Build < 17763 {
return warnings, fmt.Errorf("Windows client operating systems earlier than version 1809 can only run Hyper-V containers")
}
w, err := verifyContainerResources(&hostConfig.Resources, hyperv)
@@ -323,7 +326,8 @@ func (daemon *Daemon) initNetworkController(config *config.Config, activeSandbox
// discover and add HNS networks to windows
// network that exist are removed and added again
for _, v := range hnsresponse {
if strings.ToLower(v.Type) == "private" {
networkTypeNorm := strings.ToLower(v.Type)
if networkTypeNorm == "private" || networkTypeNorm == "internal" {
continue // workaround for HNS reporting unsupported networks
}
var n libnetwork.Network
@@ -591,9 +595,12 @@ func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
// daemon to run in. This is only applicable on Windows
func (daemon *Daemon) setDefaultIsolation() error {
daemon.defaultIsolation = containertypes.Isolation("process")
// On client SKUs, default to Hyper-V. Note that IoT reports as a client SKU
// but it should not be treated as such.
if system.IsWindowsClient() && !system.IsIoTCore() {
osv := system.GetOSVersion()
// On client SKUs, default to Hyper-V. @engine maintainers. This
// should not be removed. Ping @jhowardmsft is there are PRs to
// to change this.
if system.IsWindowsClient() {
daemon.defaultIsolation = containertypes.Isolation("hyperv")
}
for _, option := range daemon.configStore.ExecOptions {
@@ -612,10 +619,11 @@ func (daemon *Daemon) setDefaultIsolation() error {
daemon.defaultIsolation = containertypes.Isolation("hyperv")
}
if containertypes.Isolation(val).IsProcess() {
if system.IsWindowsClient() && !system.IsIoTCore() {
if system.IsWindowsClient() && osv.Build < 17763 {
// On RS5, we allow (but don't strictly support) process isolation on Client SKUs.
// @engine maintainers. This block should not be removed. It partially enforces licensing
// restrictions on Windows. Ping @jhowardmsft if there are concerns or PRs to change this.
return fmt.Errorf("Windows client operating systems only support Hyper-V containers")
return fmt.Errorf("Windows client operating systems earlier than version 1809 can only run Hyper-V containers")
}
daemon.defaultIsolation = containertypes.Isolation("process")
}

View File

@@ -29,10 +29,12 @@ import (
"github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/system"
"github.com/docker/go-units"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
@@ -81,6 +83,15 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, err
}
// For some reason shared mount propagation between a container
// and the host does not work for btrfs, and a remedy is to bind
// mount graphdriver home to itself (even without changing the
// propagation mode).
err = mount.MakeMount(home)
if err != nil {
return nil, errors.Wrapf(err, "failed to make %s a mount", home)
}
driver := &Driver{
home: home,
uidMaps: uidMaps,
@@ -158,7 +169,19 @@ func (d *Driver) GetMetadata(id string) (map[string]string, error) {
// Cleanup unmounts the home directory.
func (d *Driver) Cleanup() error {
return d.subvolDisableQuota()
err := d.subvolDisableQuota()
umountErr := mount.Unmount(d.home)
// in case we have two errors, prefer the one from disableQuota()
if err != nil {
return err
}
if umountErr != nil {
return errors.Wrapf(umountErr, "error unmounting %s", d.home)
}
return nil
}
func free(p *C.char) {

View File

@@ -27,7 +27,7 @@ type directLVMConfig struct {
var (
errThinpPercentMissing = errors.New("must set both `dm.thinp_percent` and `dm.thinp_metapercent` if either is specified")
errThinpPercentTooBig = errors.New("combined `dm.thinp_percent` and `dm.thinp_metapercent` must not be greater than 100")
errMissingSetupDevice = errors.New("must provide device path in `dm.setup_device` in order to configure direct-lvm")
errMissingSetupDevice = errors.New("must provide device path in `dm.directlvm_device` in order to configure direct-lvm")
)
func validateLVMConfig(cfg directLVMConfig) error {

View File

@@ -195,6 +195,7 @@ type Options struct {
func New(name string, pg plugingetter.PluginGetter, config Options) (Driver, error) {
if name != "" {
logrus.Debugf("[graphdriver] trying provided driver: %s", name) // so the logs show specified driver
logDeprecatedWarning(name)
return GetDriver(name, pg, config)
}
@@ -232,6 +233,7 @@ func New(name string, pg plugingetter.PluginGetter, config Options) (Driver, err
}
logrus.Infof("[graphdriver] using prior storage driver: %s", name)
logDeprecatedWarning(name)
return driver, nil
}
}
@@ -245,6 +247,7 @@ func New(name string, pg plugingetter.PluginGetter, config Options) (Driver, err
}
return nil, err
}
logDeprecatedWarning(name)
return driver, nil
}
@@ -257,6 +260,7 @@ func New(name string, pg plugingetter.PluginGetter, config Options) (Driver, err
}
return nil, err
}
logDeprecatedWarning(name)
return driver, nil
}
return nil, fmt.Errorf("No supported storage backend found")
@@ -305,3 +309,20 @@ func isEmptyDir(name string) bool {
}
return false
}
// isDeprecated checks if a storage-driver is marked "deprecated"
func isDeprecated(name string) bool {
switch name {
// NOTE: when deprecating a driver, update daemon.fillDriverInfo() accordingly
case "devicemapper", "overlay":
return true
}
return false
}
// logDeprecatedWarning logs a warning if the given storage-driver is marked "deprecated"
func logDeprecatedWarning(name string) {
if isDeprecated(name) {
logrus.Warnf("[graphdriver] WARNING: the %s storage-driver is deprecated, and will be removed in a future release", name)
}
}

View File

@@ -71,20 +71,33 @@ import (
"time"
"github.com/Microsoft/hcsshim"
"github.com/Microsoft/hcsshim/ext4/tar2ext4"
"github.com/Microsoft/opengcs/client"
"github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/reexec"
"github.com/docker/docker/pkg/system"
"github.com/sirupsen/logrus"
)
// noreexec controls reexec functionality. Off by default, on for debugging purposes.
var noreexec = false
// init registers this driver to the register. It gets initialised by the
// function passed in the second parameter, implemented in this file.
func init() {
graphdriver.Register("lcow", InitDriver)
// DOCKER_LCOW_NOREEXEC allows for inline processing which makes
// debugging issues in the re-exec codepath significantly easier.
if os.Getenv("DOCKER_LCOW_NOREEXEC") != "" {
logrus.Warnf("LCOW Graphdriver is set to not re-exec. This is intended for debugging purposes only.")
noreexec = true
} else {
reexec.Register("docker-lcow-tar2ext4", tar2ext4Reexec)
}
}
const (
@@ -846,32 +859,72 @@ func (d *Driver) Diff(id, parent string) (io.ReadCloser, error) {
func (d *Driver) ApplyDiff(id, parent string, diff io.Reader) (int64, error) {
logrus.Debugf("lcowdriver: applydiff: id %s", id)
svm, err := d.startServiceVMIfNotRunning(id, nil, fmt.Sprintf("applydiff %s", id))
// Log failures here as it's undiagnosable sometimes, due to a possible panic.
// See https://github.com/moby/moby/issues/37955 for more information.
dest := filepath.Join(d.dataRoot, id, layerFilename)
if !noreexec {
cmd := reexec.Command([]string{"docker-lcow-tar2ext4", dest}...)
stdout := bytes.NewBuffer(nil)
stderr := bytes.NewBuffer(nil)
cmd.Stdin = diff
cmd.Stdout = stdout
cmd.Stderr = stderr
if err := cmd.Start(); err != nil {
logrus.Warnf("lcowdriver: applydiff: id %s failed to start re-exec: %s", id, err)
return 0, err
}
if err := cmd.Wait(); err != nil {
logrus.Warnf("lcowdriver: applydiff: id %s failed %s", id, err)
return 0, fmt.Errorf("re-exec error: %v: stderr: %s", err, stderr)
}
return strconv.ParseInt(stdout.String(), 10, 64)
}
// The inline case
size, err := tar2ext4Actual(dest, diff)
if err != nil {
logrus.Warnf("lcowdriver: applydiff: id %s failed %s", id, err)
}
return size, err
}
// tar2ext4Reexec is the re-exec entry point for writing a layer from a tar file
func tar2ext4Reexec() {
size, err := tar2ext4Actual(os.Args[1], os.Stdin)
if err != nil {
fmt.Fprint(os.Stderr, err)
os.Exit(1)
}
fmt.Fprint(os.Stdout, size)
}
// tar2ext4Actual is the implementation of tar2ext to write a layer from a tar file.
// It can be called through re-exec (default), or inline for debugging.
func tar2ext4Actual(dest string, diff io.Reader) (int64, error) {
// maxDiskSize is not relating to the sandbox size - this is the
// maximum possible size a layer VHD generated can be from an EXT4
// layout perspective.
const maxDiskSize = 128 * 1024 * 1024 * 1024 // 128GB
out, err := os.Create(dest)
if err != nil {
return 0, err
}
defer d.terminateServiceVM(id, fmt.Sprintf("applydiff %s", id), false)
logrus.Debugf("lcowdriver: applydiff: waiting for svm to finish booting")
err = svm.getStartError()
defer out.Close()
if err := tar2ext4.Convert(
diff,
out,
tar2ext4.AppendVhdFooter,
tar2ext4.ConvertWhiteout,
tar2ext4.MaximumDiskSize(maxDiskSize)); err != nil {
return 0, err
}
fi, err := os.Stat(dest)
if err != nil {
return 0, fmt.Errorf("lcowdriver: applydiff: svm failed to boot: %s", err)
}
// TODO @jhowardmsft - the retries are temporary to overcome platform reliability issues.
// Obviously this will be removed as platform bugs are fixed.
retries := 0
for {
retries++
size, err := svm.config.TarToVhd(filepath.Join(d.dataRoot, id, layerFilename), diff)
if err != nil {
if retries <= 10 {
continue
}
return 0, err
}
return size, err
return 0, err
}
return fi.Size(), nil
}
// Changes produces a list of changes between the specified layer

View File

@@ -12,7 +12,6 @@ import (
"github.com/docker/docker/pkg/system"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
@@ -27,7 +26,7 @@ func doesSupportNativeDiff(d string) error {
}
defer func() {
if err := os.RemoveAll(td); err != nil {
logrus.WithField("storage-driver", "overlay2").Warnf("Failed to remove check directory %v: %v", td, err)
logger.Warnf("Failed to remove check directory %v: %v", td, err)
}
}()
@@ -62,7 +61,7 @@ func doesSupportNativeDiff(d string) error {
}
defer func() {
if err := unix.Unmount(filepath.Join(td, "merged"), 0); err != nil {
logrus.WithField("storage-driver", "overlay2").Warnf("Failed to unmount check directory %v: %v", filepath.Join(td, "merged"), err)
logger.Warnf("Failed to unmount check directory %v: %v", filepath.Join(td, "merged"), err)
}
}()
@@ -113,7 +112,7 @@ func supportsMultipleLowerDir(d string) error {
}
defer func() {
if err := os.RemoveAll(td); err != nil {
logrus.WithField("storage-driver", "overlay2").Warnf("Failed to remove check directory %v: %v", td, err)
logger.Warnf("Failed to remove check directory %v: %v", td, err)
}
}()
@@ -128,7 +127,7 @@ func supportsMultipleLowerDir(d string) error {
return errors.Wrap(err, "failed to mount overlay")
}
if err := unix.Unmount(filepath.Join(td, "merged"), 0); err != nil {
logrus.WithField("storage-driver", "overlay2").Warnf("Failed to unmount check directory %v: %v", filepath.Join(td, "merged"), err)
logger.Warnf("Failed to unmount check directory %v: %v", filepath.Join(td, "merged"), err)
}
return nil
}

View File

@@ -106,11 +106,14 @@ type Driver struct {
}
var (
logger = logrus.WithField("storage-driver", "overlay2")
backingFs = "<unknown>"
projectQuotaSupported = false
useNaiveDiffLock sync.Once
useNaiveDiffOnly bool
indexOff string
)
func init() {
@@ -155,8 +158,6 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
backingFs = fsName
}
logger := logrus.WithField("storage-driver", "overlay2")
switch fsMagic {
case graphdriver.FsMagicAufs, graphdriver.FsMagicEcryptfs, graphdriver.FsMagicNfsFs, graphdriver.FsMagicOverlay, graphdriver.FsMagicZfs:
logger.Errorf("'overlay2' is not supported over %s", backingFs)
@@ -228,7 +229,18 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, fmt.Errorf("Storage Option overlay2.size only supported for backingFS XFS. Found %v", backingFs)
}
logger.Debugf("backingFs=%s, projectQuotaSupported=%v", backingFs, projectQuotaSupported)
// figure out whether "index=off" option is recognized by the kernel
_, err = os.Stat("/sys/module/overlay/parameters/index")
switch {
case err == nil:
indexOff = "index=off,"
case os.IsNotExist(err):
// old kernel, no index -- do nothing
default:
logger.Warnf("Unable to detect whether overlay kernel module supports index parameter: %s", err)
}
logger.Debugf("backingFs=%s, projectQuotaSupported=%v, indexOff=%q", backingFs, projectQuotaSupported, indexOff)
return d, nil
}
@@ -277,14 +289,14 @@ func supportsOverlay() error {
return nil
}
}
logrus.WithField("storage-driver", "overlay2").Error("'overlay' not found as a supported filesystem on this host. Please ensure kernel is new enough and has overlay support loaded.")
logger.Error("'overlay' not found as a supported filesystem on this host. Please ensure kernel is new enough and has overlay support loaded.")
return graphdriver.ErrNotSupported
}
func useNaiveDiff(home string) bool {
useNaiveDiffLock.Do(func() {
if err := doesSupportNativeDiff(home); err != nil {
logrus.WithField("storage-driver", "overlay2").Warnf("Not using native diff for overlay2, this may cause degraded performance for building images: %v", err)
logger.Warnf("Not using native diff for overlay2, this may cause degraded performance for building images: %v", err)
useNaiveDiffOnly = true
}
})
@@ -522,9 +534,9 @@ func (d *Driver) Remove(id string) error {
lid, err := ioutil.ReadFile(path.Join(dir, "link"))
if err == nil {
if len(lid) == 0 {
logrus.WithField("storage-driver", "overlay2").Errorf("refusing to remove empty link for layer %v", id)
logger.Errorf("refusing to remove empty link for layer %v", id)
} else if err := os.RemoveAll(path.Join(d.home, linkDir, string(lid))); err != nil {
logrus.WithField("storage-driver", "overlay2").Debugf("Failed to remove link: %v", err)
logger.Debugf("Failed to remove link: %v", err)
}
}
@@ -561,11 +573,11 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
if retErr != nil {
if c := d.ctr.Decrement(mergedDir); c <= 0 {
if mntErr := unix.Unmount(mergedDir, 0); mntErr != nil {
logrus.WithField("storage-driver", "overlay2").Errorf("error unmounting %v: %v", mergedDir, mntErr)
logger.Errorf("error unmounting %v: %v", mergedDir, mntErr)
}
// Cleanup the created merged directory; see the comment in Put's rmdir
if rmErr := unix.Rmdir(mergedDir); rmErr != nil && !os.IsNotExist(rmErr) {
logrus.WithField("storage-driver", "overlay2").Debugf("Failed to remove %s: %v: %v", id, rmErr, err)
logger.Debugf("Failed to remove %s: %v: %v", id, rmErr, err)
}
}
}
@@ -577,7 +589,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
for i, s := range splitLowers {
absLowers[i] = path.Join(d.home, s)
}
opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", strings.Join(absLowers, ":"), path.Join(dir, "diff"), path.Join(dir, "work"))
opts := indexOff + "lowerdir=" + strings.Join(absLowers, ":") + ",upperdir=" + path.Join(dir, "diff") + ",workdir=" + path.Join(dir, "work")
mountData := label.FormatMountLabel(opts, mountLabel)
mount := unix.Mount
mountTarget := mergedDir
@@ -606,7 +618,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
// fit within a page and relative links make the mount data much
// smaller at the expense of requiring a fork exec to chroot.
if len(mountData) > pageSize {
opts = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", string(lowers), path.Join(id, "diff"), path.Join(id, "work"))
opts = indexOff + "lowerdir=" + string(lowers) + ",upperdir=" + path.Join(id, "diff") + ",workdir=" + path.Join(id, "work")
mountData = label.FormatMountLabel(opts, mountLabel)
if len(mountData) > pageSize {
return nil, fmt.Errorf("cannot mount layer, mount label too large %d", len(mountData))
@@ -648,7 +660,6 @@ func (d *Driver) Put(id string) error {
}
mountpoint := path.Join(dir, "merged")
logger := logrus.WithField("storage-driver", "overlay2")
if count := d.ctr.Decrement(mountpoint); count > 0 {
return nil
}
@@ -704,7 +715,7 @@ func (d *Driver) ApplyDiff(id string, parent string, diff io.Reader) (size int64
applyDir := d.getDiffPath(id)
logrus.WithField("storage-driver", "overlay2").Debugf("Applying tar in %s", applyDir)
logger.Debugf("Applying tar in %s", applyDir)
// Overlay doesn't need the parent id to apply the diff
if err := untar(diff, applyDir, &archive.TarOptions{
UIDMaps: d.uidMaps,
@@ -742,7 +753,7 @@ func (d *Driver) Diff(id, parent string) (io.ReadCloser, error) {
}
diffPath := d.getDiffPath(id)
logrus.WithField("storage-driver", "overlay2").Debugf("Tar with options on %s", diffPath)
logger.Debugf("Tar with options on %s", diffPath)
return archive.TarWithOptions(diffPath, &archive.TarOptions{
Compression: archive.Uncompressed,
UIDMaps: d.uidMaps,

View File

@@ -11,7 +11,6 @@ import (
"syscall"
"time"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
@@ -47,7 +46,7 @@ func generateID(l int) string {
if retryOnError(err) && retries < maxretries {
count += n
retries++
logrus.Errorf("error generating version 4 uuid, retrying: %v", err)
logger.Errorf("error generating version 4 uuid, retrying: %v", err)
continue
}

View File

@@ -6,7 +6,6 @@ import (
"bufio"
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
@@ -23,6 +22,7 @@ import (
"github.com/Microsoft/go-winio"
"github.com/Microsoft/go-winio/archive/tar"
"github.com/Microsoft/go-winio/backuptar"
"github.com/Microsoft/go-winio/vhd"
"github.com/Microsoft/hcsshim"
"github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/archive"
@@ -33,6 +33,7 @@ import (
"github.com/docker/docker/pkg/reexec"
"github.com/docker/docker/pkg/system"
units "github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sys/windows"
)
@@ -331,7 +332,18 @@ func (d *Driver) Remove(id string) error {
tmpID := fmt.Sprintf("%s-removing", rID)
tmpLayerPath := filepath.Join(d.info.HomeDir, tmpID)
if err := os.Rename(layerPath, tmpLayerPath); err != nil && !os.IsNotExist(err) {
return err
if !os.IsPermission(err) {
return err
}
// If permission denied, it's possible that the scratch is still mounted, an
// artifact after a hard daemon crash for example. Worth a shot to try detaching it
// before retrying the rename.
if detachErr := vhd.DetachVhd(filepath.Join(layerPath, "sandbox.vhdx")); detachErr != nil {
return errors.Wrapf(err, "failed to detach VHD: %s", detachErr)
}
if renameErr := os.Rename(layerPath, tmpLayerPath); renameErr != nil && !os.IsNotExist(renameErr) {
return errors.Wrapf(err, "second rename attempt following detach failed: %s", renameErr)
}
}
if err := hcsshim.DestroyLayer(d.info, tmpID); err != nil {
logrus.Errorf("Failed to DestroyLayer %s: %s", id, err)

View File

@@ -205,8 +205,6 @@ func (i *ImageService) LayerDiskUsage(ctx context.Context) (int64, error) {
if err == nil {
if _, ok := layerRefs[l.ChainID()]; ok {
allLayersSize += size
} else {
logrus.Warnf("found leaked image layer %v", l.ChainID())
}
} else {
logrus.Warnf("failed to get diff size for layer %v", l.ChainID())

View File

@@ -2,6 +2,7 @@ package daemon // import "github.com/docker/docker/daemon"
import (
"fmt"
"net/url"
"os"
"runtime"
"strings"
@@ -61,8 +62,8 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
ServerVersion: dockerversion.Version,
ClusterStore: daemon.configStore.ClusterStore,
ClusterAdvertise: daemon.configStore.ClusterAdvertise,
HTTPProxy: sockets.GetProxyEnv("http_proxy"),
HTTPSProxy: sockets.GetProxyEnv("https_proxy"),
HTTPProxy: maskCredentials(sockets.GetProxyEnv("http_proxy")),
HTTPSProxy: maskCredentials(sockets.GetProxyEnv("https_proxy")),
NoProxy: sockets.GetProxyEnv("no_proxy"),
LiveRestoreEnabled: daemon.configStore.LiveRestoreEnabled,
Isolation: daemon.defaultIsolation,
@@ -130,6 +131,10 @@ func (daemon *Daemon) fillDriverInfo(v *types.Info) {
if len(daemon.graphDrivers) > 1 {
drivers += fmt.Sprintf(" (%s) ", os)
}
switch gd {
case "devicemapper", "overlay":
v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: the %s storage-driver is deprecated, and will be removed in a future release.", gd))
}
}
drivers = strings.TrimSpace(drivers)
@@ -245,3 +250,13 @@ func operatingSystem() string {
}
return operatingSystem
}
func maskCredentials(rawURL string) string {
parsedURL, err := url.Parse(rawURL)
if err != nil || parsedURL.User == nil {
return rawURL
}
parsedURL.User = url.UserPassword("xxxxx", "xxxxx")
maskedURL := parsedURL.String()
return maskedURL
}

53
daemon/info_test.go Normal file
View File

@@ -0,0 +1,53 @@
package daemon
import (
"testing"
"gotest.tools/assert"
)
func TestMaskURLCredentials(t *testing.T) {
tests := []struct {
rawURL string
maskedURL string
}{
{
rawURL: "",
maskedURL: "",
}, {
rawURL: "invalidURL",
maskedURL: "invalidURL",
}, {
rawURL: "http://proxy.example.com:80/",
maskedURL: "http://proxy.example.com:80/",
}, {
rawURL: "http://USER:PASSWORD@proxy.example.com:80/",
maskedURL: "http://xxxxx:xxxxx@proxy.example.com:80/",
}, {
rawURL: "http://PASSWORD:PASSWORD@proxy.example.com:80/",
maskedURL: "http://xxxxx:xxxxx@proxy.example.com:80/",
}, {
rawURL: "http://USER:@proxy.example.com:80/",
maskedURL: "http://xxxxx:xxxxx@proxy.example.com:80/",
}, {
rawURL: "http://:PASSWORD@proxy.example.com:80/",
maskedURL: "http://xxxxx:xxxxx@proxy.example.com:80/",
}, {
rawURL: "http://USER@docker:password@proxy.example.com:80/",
maskedURL: "http://xxxxx:xxxxx@proxy.example.com:80/",
}, {
rawURL: "http://USER%40docker:password@proxy.example.com:80/",
maskedURL: "http://xxxxx:xxxxx@proxy.example.com:80/",
}, {
rawURL: "http://USER%40docker:pa%3Fsword@proxy.example.com:80/",
maskedURL: "http://xxxxx:xxxxx@proxy.example.com:80/",
}, {
rawURL: "http://USER%40docker:pa%3Fsword@proxy.example.com:80/hello%20world",
maskedURL: "http://xxxxx:xxxxx@proxy.example.com:80/hello%20world",
},
}
for _, test := range tests {
maskedURL := maskCredentials(test.rawURL)
assert.Equal(t, maskedURL, test.maskedURL)
}
}

View File

@@ -29,7 +29,6 @@ func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo)
v.DefaultRuntime = daemon.configStore.GetDefaultRuntimeName()
v.InitBinary = daemon.configStore.GetInitPath()
v.RuncCommit.Expected = dockerversion.RuncCommitID
defaultRuntimeBinary := daemon.configStore.GetRuntime(v.DefaultRuntime).Path
if rv, err := exec.Command(defaultRuntimeBinary, "--version").Output(); err == nil {
parts := strings.Split(strings.TrimSpace(string(rv)), "\n")
@@ -49,7 +48,10 @@ func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo)
v.RuncCommit.ID = "N/A"
}
v.ContainerdCommit.Expected = dockerversion.ContainerdCommitID
// runc is now shipped as a separate package. Set "expected" to same value
// as "ID" to prevent clients from reporting a version-mismatch
v.RuncCommit.Expected = v.RuncCommit.ID
if rv, err := daemon.containerd.Version(context.Background()); err == nil {
v.ContainerdCommit.ID = rv.Revision
} else {
@@ -57,6 +59,10 @@ func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo)
v.ContainerdCommit.ID = "N/A"
}
// containerd is now shipped as a separate package. Set "expected" to same
// value as "ID" to prevent clients from reporting a version-mismatch
v.ContainerdCommit.Expected = v.ContainerdCommit.ID
defaultInitBinary := daemon.configStore.GetInitPath()
if rv, err := exec.Command(defaultInitBinary, "--version").Output(); err == nil {
ver, err := parseInitVersion(string(rv))

View File

@@ -146,7 +146,8 @@ func (daemon *Daemon) filterByNameIDMatches(view container.View, ctx *listContex
continue
}
for _, eachName := range idNames {
if ctx.filters.Match("name", strings.TrimPrefix(eachName, "/")) {
// match both on container name with, and without slash-prefix
if ctx.filters.Match("name", eachName) || ctx.filters.Match("name", strings.TrimPrefix(eachName, "/")) {
matches[id] = true
}
}
@@ -429,7 +430,7 @@ func includeContainerInList(container *container.Snapshot, ctx *listContext) ite
}
// Do not include container if the name doesn't match
if !ctx.filters.Match("name", strings.TrimPrefix(container.Name, "/")) {
if !ctx.filters.Match("name", container.Name) && !ctx.filters.Match("name", strings.TrimPrefix(container.Name, "/")) {
return excludeContainer
}

View File

@@ -4,7 +4,6 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/docker/docker/api/types"
@@ -35,6 +34,7 @@ func TestMain(m *testing.M) {
// work against it. It takes in a pointer to Daemon so that
// minor operations are not repeated by the caller
func setupContainerWithName(t *testing.T, name string, daemon *Daemon) *container.Container {
t.Helper()
var (
id = uuid.New()
computedImageID = digest.FromString(id)
@@ -46,6 +46,9 @@ func setupContainerWithName(t *testing.T, name string, daemon *Daemon) *containe
c := container.NewBaseContainer(id, cRoot)
// these are for passing includeContainerInList
if name[0] != '/' {
name = "/" + name
}
c.Name = name
c.Running = true
c.HostConfig = &containertypes.HostConfig{}
@@ -68,7 +71,7 @@ func setupContainerWithName(t *testing.T, name string, daemon *Daemon) *containe
func containerListContainsName(containers []*types.Container, name string) bool {
for _, container := range containers {
for _, containerName := range container.Names {
if strings.TrimPrefix(containerName, "/") == name {
if containerName == name {
return true
}
}
@@ -110,16 +113,33 @@ func TestNameFilter(t *testing.T) {
containerList, err := d.Containers(&types.ContainerListOptions{
Filters: filters.NewArgs(filters.Arg("name", "^a")),
})
assert.Assert(t, err == nil)
assert.NilError(t, err)
assert.Assert(t, is.Len(containerList, 2))
assert.Assert(t, containerListContainsName(containerList, one.Name))
assert.Assert(t, containerListContainsName(containerList, two.Name))
// Same as above but with slash prefix should produce the same result
containerListWithPrefix, err := d.Containers(&types.ContainerListOptions{
Filters: filters.NewArgs(filters.Arg("name", "^/a")),
})
assert.NilError(t, err)
assert.Assert(t, is.Len(containerListWithPrefix, 2))
assert.Assert(t, containerListContainsName(containerListWithPrefix, one.Name))
assert.Assert(t, containerListContainsName(containerListWithPrefix, two.Name))
// Same as above but make sure it works for exact names
containerList, err = d.Containers(&types.ContainerListOptions{
Filters: filters.NewArgs(filters.Arg("name", "b1")),
})
assert.Assert(t, err == nil)
assert.NilError(t, err)
assert.Assert(t, is.Len(containerList, 1))
assert.Assert(t, containerListContainsName(containerList, three.Name))
// Same as above but with slash prefix should produce the same result
containerListWithPrefix, err = d.Containers(&types.ContainerListOptions{
Filters: filters.NewArgs(filters.Arg("name", "/b1")),
})
assert.NilError(t, err)
assert.Assert(t, is.Len(containerListWithPrefix, 1))
assert.Assert(t, containerListContainsName(containerListWithPrefix, three.Name))
}

View File

@@ -93,21 +93,12 @@ func (a *pluginAdapterWithRead) ReadLogs(config ReadConfig) *LogWatcher {
dec := logdriver.NewLogEntryDecoder(stream)
for {
select {
case <-watcher.WatchClose():
return
default:
}
var buf logdriver.LogEntry
if err := dec.Decode(&buf); err != nil {
if err == io.EOF {
return
}
select {
case watcher.Err <- errors.Wrap(err, "error decoding log message"):
case <-watcher.WatchClose():
}
watcher.Err <- errors.Wrap(err, "error decoding log message")
return
}
@@ -125,11 +116,10 @@ func (a *pluginAdapterWithRead) ReadLogs(config ReadConfig) *LogWatcher {
return
}
// send the message unless the consumer is gone
select {
case watcher.Msg <- msg:
case <-watcher.WatchClose():
// make sure the message we consumed is sent
watcher.Msg <- msg
case <-watcher.WatchConsumerGone():
return
}
}

View File

@@ -174,7 +174,7 @@ func TestAdapterReadLogs(t *testing.T) {
t.Fatal("timeout waiting for message channel to close")
}
lw.Close()
lw.ProducerGone()
lw = lr.ReadLogs(ReadConfig{Follow: true})
for _, x := range testMsg {

View File

@@ -11,6 +11,7 @@ import (
"strings"
"sync"
"time"
"unicode/utf8"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
@@ -46,6 +47,10 @@ const (
maximumLogEventsPerPut = 10000
// See: http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/cloudwatch_limits.html
// Because the events are interpreted as UTF-8 encoded Unicode, invalid UTF-8 byte sequences are replaced with the
// Unicode replacement character (U+FFFD), which is a 3-byte sequence in UTF-8. To compensate for that and to avoid
// splitting valid UTF-8 characters into invalid byte sequences, we calculate the length of each event assuming that
// this replacement happens.
maximumBytesPerEvent = 262144 - perEventBytes
resourceAlreadyExistsCode = "ResourceAlreadyExistsException"
@@ -495,15 +500,16 @@ func (l *logStream) collectBatch(created chan bool) {
}
line := msg.Line
if l.multilinePattern != nil {
if l.multilinePattern.Match(line) || len(eventBuffer)+len(line) > maximumBytesPerEvent {
lineEffectiveLen := effectiveLen(string(line))
if l.multilinePattern.Match(line) || effectiveLen(string(eventBuffer))+lineEffectiveLen > maximumBytesPerEvent {
// This is a new log event or we will exceed max bytes per event
// so flush the current eventBuffer to events and reset timestamp
l.processEvent(batch, eventBuffer, eventBufferTimestamp)
eventBufferTimestamp = msg.Timestamp.UnixNano() / int64(time.Millisecond)
eventBuffer = eventBuffer[:0]
}
// Append new line if event is less than max event size
if len(line) < maximumBytesPerEvent {
// Append newline if event is less than max event size
if lineEffectiveLen < maximumBytesPerEvent {
line = append(line, "\n"...)
}
eventBuffer = append(eventBuffer, line...)
@@ -524,16 +530,17 @@ func (l *logStream) collectBatch(created chan bool) {
// batch (defined in maximumBytesPerPut). Log messages are split by the maximum
// bytes per event (defined in maximumBytesPerEvent). There is a fixed per-event
// byte overhead (defined in perEventBytes) which is accounted for in split- and
// batch-calculations.
func (l *logStream) processEvent(batch *eventBatch, events []byte, timestamp int64) {
for len(events) > 0 {
// batch-calculations. Because the events are interpreted as UTF-8 encoded
// Unicode, invalid UTF-8 byte sequences are replaced with the Unicode
// replacement character (U+FFFD), which is a 3-byte sequence in UTF-8. To
// compensate for that and to avoid splitting valid UTF-8 characters into
// invalid byte sequences, we calculate the length of each event assuming that
// this replacement happens.
func (l *logStream) processEvent(batch *eventBatch, bytes []byte, timestamp int64) {
for len(bytes) > 0 {
// Split line length so it does not exceed the maximum
lineBytes := len(events)
if lineBytes > maximumBytesPerEvent {
lineBytes = maximumBytesPerEvent
}
line := events[:lineBytes]
splitOffset, lineBytes := findValidSplit(string(bytes), maximumBytesPerEvent)
line := bytes[:splitOffset]
event := wrappedEvent{
inputLogEvent: &cloudwatchlogs.InputLogEvent{
Message: aws.String(string(line)),
@@ -544,7 +551,7 @@ func (l *logStream) processEvent(batch *eventBatch, events []byte, timestamp int
added := batch.add(event, lineBytes)
if added {
events = events[lineBytes:]
bytes = bytes[splitOffset:]
} else {
l.publishBatch(batch)
batch.reset()
@@ -552,6 +559,37 @@ func (l *logStream) processEvent(batch *eventBatch, events []byte, timestamp int
}
}
// effectiveLen counts the effective number of bytes in the string, after
// UTF-8 normalization. UTF-8 normalization includes replacing bytes that do
// not constitute valid UTF-8 encoded Unicode codepoints with the Unicode
// replacement codepoint U+FFFD (a 3-byte UTF-8 sequence, represented in Go as
// utf8.RuneError)
func effectiveLen(line string) int {
effectiveBytes := 0
for _, rune := range line {
effectiveBytes += utf8.RuneLen(rune)
}
return effectiveBytes
}
// findValidSplit finds the byte offset to split a string without breaking valid
// Unicode codepoints given a maximum number of total bytes. findValidSplit
// returns the byte offset for splitting a string or []byte, as well as the
// effective number of bytes if the string were normalized to replace invalid
// UTF-8 encoded bytes with the Unicode replacement character (a 3-byte UTF-8
// sequence, represented in Go as utf8.RuneError)
func findValidSplit(line string, maxBytes int) (splitOffset, effectiveBytes int) {
for offset, rune := range line {
splitOffset = offset
if effectiveBytes+utf8.RuneLen(rune) > maxBytes {
return splitOffset, effectiveBytes
}
effectiveBytes += utf8.RuneLen(rune)
}
splitOffset = len(line)
return
}
// publishBatch calls PutLogEvents for a given set of InputLogEvents,
// accounting for sequencing requirements (each request must reference the
// sequence token returned by the previous request).

View File

@@ -938,6 +938,62 @@ func TestCollectBatchClose(t *testing.T) {
}
}
func TestEffectiveLen(t *testing.T) {
tests := []struct {
str string
effectiveBytes int
}{
{"Hello", 5},
{string([]byte{1, 2, 3, 4}), 4},
{"🙃", 4},
{string([]byte{0xFF, 0xFF, 0xFF, 0xFF}), 12},
{"He\xff\xffo", 9},
{"", 0},
}
for i, tc := range tests {
t.Run(fmt.Sprintf("%d/%s", i, tc.str), func(t *testing.T) {
assert.Equal(t, tc.effectiveBytes, effectiveLen(tc.str))
})
}
}
func TestFindValidSplit(t *testing.T) {
tests := []struct {
str string
maxEffectiveBytes int
splitOffset int
effectiveBytes int
}{
{"", 10, 0, 0},
{"Hello", 6, 5, 5},
{"Hello", 2, 2, 2},
{"Hello", 0, 0, 0},
{"🙃", 3, 0, 0},
{"🙃", 4, 4, 4},
{string([]byte{'a', 0xFF}), 2, 1, 1},
{string([]byte{'a', 0xFF}), 4, 2, 4},
}
for i, tc := range tests {
t.Run(fmt.Sprintf("%d/%s", i, tc.str), func(t *testing.T) {
splitOffset, effectiveBytes := findValidSplit(tc.str, tc.maxEffectiveBytes)
assert.Equal(t, tc.splitOffset, splitOffset, "splitOffset")
assert.Equal(t, tc.effectiveBytes, effectiveBytes, "effectiveBytes")
t.Log(tc.str[:tc.splitOffset])
t.Log(tc.str[tc.splitOffset:])
})
}
}
func TestProcessEventEmoji(t *testing.T) {
stream := &logStream{}
batch := &eventBatch{}
bytes := []byte(strings.Repeat("🙃", maximumBytesPerEvent/4+1))
stream.processEvent(batch, bytes, 0)
assert.Equal(t, 2, len(batch.batch), "should be two events in the batch")
assert.Equal(t, strings.Repeat("🙃", maximumBytesPerEvent/4), aws.StringValue(batch.batch[0].inputLogEvent.Message))
assert.Equal(t, "🙃", aws.StringValue(batch.batch[1].inputLogEvent.Message))
}
func TestCollectBatchLineSplit(t *testing.T) {
mockClient := newMockClient()
stream := &logStream{
@@ -987,6 +1043,55 @@ func TestCollectBatchLineSplit(t *testing.T) {
}
}
func TestCollectBatchLineSplitWithBinary(t *testing.T) {
mockClient := newMockClient()
stream := &logStream{
client: mockClient,
logGroupName: groupName,
logStreamName: streamName,
sequenceToken: aws.String(sequenceToken),
messages: make(chan *logger.Message),
}
mockClient.putLogEventsResult <- &putLogEventsResult{
successResult: &cloudwatchlogs.PutLogEventsOutput{
NextSequenceToken: aws.String(nextSequenceToken),
},
}
var ticks = make(chan time.Time)
newTicker = func(_ time.Duration) *time.Ticker {
return &time.Ticker{
C: ticks,
}
}
d := make(chan bool)
close(d)
go stream.collectBatch(d)
longline := strings.Repeat("\xFF", maximumBytesPerEvent/3) // 0xFF is counted as the 3-byte utf8.RuneError
stream.Log(&logger.Message{
Line: []byte(longline + "\xFD"),
Timestamp: time.Time{},
})
// no ticks
stream.Close()
argument := <-mockClient.putLogEventsArgument
if argument == nil {
t.Fatal("Expected non-nil PutLogEventsInput")
}
if len(argument.LogEvents) != 2 {
t.Errorf("Expected LogEvents to contain 2 elements, but contains %d", len(argument.LogEvents))
}
if *argument.LogEvents[0].Message != longline {
t.Errorf("Expected message to be %s but was %s", longline, *argument.LogEvents[0].Message)
}
if *argument.LogEvents[1].Message != "\xFD" {
t.Errorf("Expected message to be %s but was %s", "\xFD", *argument.LogEvents[1].Message)
}
}
func TestCollectBatchMaxEvents(t *testing.T) {
mockClient := newMockClientBuffered(1)
stream := &logStream{
@@ -1125,6 +1230,83 @@ func TestCollectBatchMaxTotalBytes(t *testing.T) {
}
}
func TestCollectBatchMaxTotalBytesWithBinary(t *testing.T) {
expectedPuts := 2
mockClient := newMockClientBuffered(expectedPuts)
stream := &logStream{
client: mockClient,
logGroupName: groupName,
logStreamName: streamName,
sequenceToken: aws.String(sequenceToken),
messages: make(chan *logger.Message),
}
for i := 0; i < expectedPuts; i++ {
mockClient.putLogEventsResult <- &putLogEventsResult{
successResult: &cloudwatchlogs.PutLogEventsOutput{
NextSequenceToken: aws.String(nextSequenceToken),
},
}
}
var ticks = make(chan time.Time)
newTicker = func(_ time.Duration) *time.Ticker {
return &time.Ticker{
C: ticks,
}
}
d := make(chan bool)
close(d)
go stream.collectBatch(d)
// maxline is the maximum line that could be submitted after
// accounting for its overhead.
maxline := strings.Repeat("\xFF", (maximumBytesPerPut-perEventBytes)/3) // 0xFF is counted as the 3-byte utf8.RuneError
// This will be split and batched up to the `maximumBytesPerPut'
// (+/- `maximumBytesPerEvent'). This /should/ be aligned, but
// should also tolerate an offset within that range.
stream.Log(&logger.Message{
Line: []byte(maxline),
Timestamp: time.Time{},
})
stream.Log(&logger.Message{
Line: []byte("B"),
Timestamp: time.Time{},
})
// no ticks, guarantee batch by size (and chan close)
stream.Close()
argument := <-mockClient.putLogEventsArgument
if argument == nil {
t.Fatal("Expected non-nil PutLogEventsInput")
}
// Should total to the maximum allowed bytes.
eventBytes := 0
for _, event := range argument.LogEvents {
eventBytes += effectiveLen(*event.Message)
}
eventsOverhead := len(argument.LogEvents) * perEventBytes
payloadTotal := eventBytes + eventsOverhead
// lowestMaxBatch allows the payload to be offset if the messages
// don't lend themselves to align with the maximum event size.
lowestMaxBatch := maximumBytesPerPut - maximumBytesPerEvent
if payloadTotal > maximumBytesPerPut {
t.Errorf("Expected <= %d bytes but was %d", maximumBytesPerPut, payloadTotal)
}
if payloadTotal < lowestMaxBatch {
t.Errorf("Batch to be no less than %d but was %d", lowestMaxBatch, payloadTotal)
}
argument = <-mockClient.putLogEventsArgument
message := *argument.LogEvents[len(argument.LogEvents)-1].Message
if message[len(message)-1:] != "B" {
t.Errorf("Expected message to be %s but was %s", "B", message[len(message)-1:])
}
}
func TestCollectBatchWithDuplicateTimestamps(t *testing.T) {
mockClient := newMockClient()
stream := &logStream{

View File

@@ -165,7 +165,7 @@ func (s *journald) Close() error {
s.mu.Lock()
s.closed = true
for reader := range s.readers.readers {
reader.Close()
reader.ProducerGone()
}
s.mu.Unlock()
return nil
@@ -299,7 +299,7 @@ func (s *journald) followJournal(logWatcher *logger.LogWatcher, j *C.sd_journal,
// Wait until we're told to stop.
select {
case cursor = <-newCursor:
case <-logWatcher.WatchClose():
case <-logWatcher.WatchConsumerGone():
// Notify the other goroutine that its work is done.
C.close(pfd[1])
cursor = <-newCursor

View File

@@ -50,7 +50,7 @@ func New(info logger.Info) (logger.Logger, error) {
return nil, err
}
if capval <= 0 {
return nil, fmt.Errorf("max-size should be a positive numbler")
return nil, fmt.Errorf("max-size must be a positive number")
}
}
var maxFiles = 1
@@ -166,13 +166,14 @@ func ValidateLogOpt(cfg map[string]string) error {
return nil
}
// Close closes underlying file and signals all readers to stop.
// Close closes underlying file and signals all the readers
// that the logs producer is gone.
func (l *JSONFileLogger) Close() error {
l.mu.Lock()
l.closed = true
err := l.writer.Close()
for r := range l.readers {
r.Close()
r.ProducerGone()
delete(l.readers, r)
}
l.mu.Unlock()

View File

@@ -50,11 +50,10 @@ func BenchmarkJSONFileLoggerReadLogs(b *testing.B) {
}()
lw := jsonlogger.(*JSONFileLogger).ReadLogs(logger.ReadConfig{Follow: true})
watchClose := lw.WatchClose()
for {
select {
case <-lw.Msg:
case <-watchClose:
case <-lw.WatchProducerGone():
return
case err := <-chError:
if err != nil {

View File

@@ -166,7 +166,7 @@ func (d *driver) Close() error {
d.closed = true
err := d.logfile.Close()
for r := range d.readers {
r.Close()
r.ProducerGone()
delete(d.readers, r)
}
d.mu.Unlock()

View File

@@ -104,33 +104,50 @@ type LogWatcher struct {
// For sending log messages to a reader.
Msg chan *Message
// For sending error messages that occur while while reading logs.
Err chan error
closeOnce sync.Once
closeNotifier chan struct{}
Err chan error
producerOnce sync.Once
producerGone chan struct{}
consumerOnce sync.Once
consumerGone chan struct{}
}
// NewLogWatcher returns a new LogWatcher.
func NewLogWatcher() *LogWatcher {
return &LogWatcher{
Msg: make(chan *Message, logWatcherBufferSize),
Err: make(chan error, 1),
closeNotifier: make(chan struct{}),
Msg: make(chan *Message, logWatcherBufferSize),
Err: make(chan error, 1),
producerGone: make(chan struct{}),
consumerGone: make(chan struct{}),
}
}
// Close notifies the underlying log reader to stop.
func (w *LogWatcher) Close() {
// ProducerGone notifies the underlying log reader that
// the logs producer (a container) is gone.
func (w *LogWatcher) ProducerGone() {
// only close if not already closed
w.closeOnce.Do(func() {
close(w.closeNotifier)
w.producerOnce.Do(func() {
close(w.producerGone)
})
}
// WatchClose returns a channel receiver that receives notification
// when the watcher has been closed. This should only be called from
// one goroutine.
func (w *LogWatcher) WatchClose() <-chan struct{} {
return w.closeNotifier
// WatchProducerGone returns a channel receiver that receives notification
// once the logs producer (a container) is gone.
func (w *LogWatcher) WatchProducerGone() <-chan struct{} {
return w.producerGone
}
// ConsumerGone notifies that the logs consumer is gone.
func (w *LogWatcher) ConsumerGone() {
// only close if not already closed
w.consumerOnce.Do(func() {
close(w.consumerGone)
})
}
// WatchConsumerGone returns a channel receiver that receives notification
// when the log watcher consumer is gone.
func (w *LogWatcher) WatchConsumerGone() <-chan struct{} {
return w.consumerGone
}
// Capability defines the list of capabilities that a driver can implement

View File

@@ -488,7 +488,7 @@ func tailFiles(files []SizeReaderAt, watcher *logger.LogWatcher, createDecoder m
go func() {
select {
case <-ctx.Done():
case <-watcher.WatchClose():
case <-watcher.WatchConsumerGone():
cancel()
}
}()
@@ -546,22 +546,9 @@ func followLogs(f *os.File, logWatcher *logger.LogWatcher, notifyRotate chan int
}
defer func() {
f.Close()
fileWatcher.Remove(name)
fileWatcher.Close()
}()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
select {
case <-logWatcher.WatchClose():
fileWatcher.Remove(name)
cancel()
case <-ctx.Done():
return
}
}()
var retries int
handleRotate := func() error {
f.Close()
@@ -596,7 +583,9 @@ func followLogs(f *os.File, logWatcher *logger.LogWatcher, notifyRotate chan int
case fsnotify.Rename, fsnotify.Remove:
select {
case <-notifyRotate:
case <-ctx.Done():
case <-logWatcher.WatchProducerGone():
return errDone
case <-logWatcher.WatchConsumerGone():
return errDone
}
if err := handleRotate(); err != nil {
@@ -618,7 +607,9 @@ func followLogs(f *os.File, logWatcher *logger.LogWatcher, notifyRotate chan int
return errRetry
}
return err
case <-ctx.Done():
case <-logWatcher.WatchProducerGone():
return errDone
case <-logWatcher.WatchConsumerGone():
return errDone
}
}
@@ -664,23 +655,11 @@ func followLogs(f *os.File, logWatcher *logger.LogWatcher, notifyRotate chan int
if !until.IsZero() && msg.Timestamp.After(until) {
return
}
// send the message, unless the consumer is gone
select {
case logWatcher.Msg <- msg:
case <-ctx.Done():
logWatcher.Msg <- msg
for {
msg, err := decodeLogLine()
if err != nil {
return
}
if !since.IsZero() && msg.Timestamp.Before(since) {
continue
}
if !until.IsZero() && msg.Timestamp.After(until) {
return
}
logWatcher.Msg <- msg
}
case <-logWatcher.WatchConsumerGone():
return
}
}
}

View File

@@ -4,6 +4,8 @@ import (
"bufio"
"context"
"io"
"io/ioutil"
"os"
"strings"
"testing"
"time"
@@ -74,3 +76,128 @@ func TestTailFiles(t *testing.T) {
assert.Assert(t, string(msg.Line) == "Where we're going we don't need roads.", string(msg.Line))
}
}
func TestFollowLogsConsumerGone(t *testing.T) {
lw := logger.NewLogWatcher()
f, err := ioutil.TempFile("", t.Name())
assert.NilError(t, err)
defer func() {
f.Close()
os.Remove(f.Name())
}()
makeDecoder := func(rdr io.Reader) func() (*logger.Message, error) {
return func() (*logger.Message, error) {
return &logger.Message{}, nil
}
}
followLogsDone := make(chan struct{})
var since, until time.Time
go func() {
followLogs(f, lw, make(chan interface{}), makeDecoder, since, until)
close(followLogsDone)
}()
select {
case <-lw.Msg:
case err := <-lw.Err:
assert.NilError(t, err)
case <-followLogsDone:
t.Fatal("follow logs finished unexpectedly")
case <-time.After(10 * time.Second):
t.Fatal("timeout waiting for log message")
}
lw.ConsumerGone()
select {
case <-followLogsDone:
case <-time.After(20 * time.Second):
t.Fatal("timeout waiting for followLogs() to finish")
}
}
func TestFollowLogsProducerGone(t *testing.T) {
lw := logger.NewLogWatcher()
f, err := ioutil.TempFile("", t.Name())
assert.NilError(t, err)
defer os.Remove(f.Name())
var sent, received, closed int
makeDecoder := func(rdr io.Reader) func() (*logger.Message, error) {
return func() (*logger.Message, error) {
if closed == 1 {
closed++
t.Logf("logDecode() closed after sending %d messages\n", sent)
return nil, io.EOF
} else if closed > 1 {
t.Fatal("logDecode() called after closing!")
return nil, io.EOF
}
sent++
return &logger.Message{}, nil
}
}
var since, until time.Time
followLogsDone := make(chan struct{})
go func() {
followLogs(f, lw, make(chan interface{}), makeDecoder, since, until)
close(followLogsDone)
}()
// read 1 message
select {
case <-lw.Msg:
received++
case err := <-lw.Err:
assert.NilError(t, err)
case <-followLogsDone:
t.Fatal("followLogs() finished unexpectedly")
case <-time.After(10 * time.Second):
t.Fatal("timeout waiting for log message")
}
// "stop" the "container"
closed = 1
lw.ProducerGone()
// should receive all the messages sent
readDone := make(chan struct{})
go func() {
defer close(readDone)
for {
select {
case <-lw.Msg:
received++
if received == sent {
return
}
case err := <-lw.Err:
assert.NilError(t, err)
}
}
}()
select {
case <-readDone:
case <-time.After(30 * time.Second):
t.Fatalf("timeout waiting for log messages to be read (sent: %d, received: %d", sent, received)
}
t.Logf("messages sent: %d, received: %d", sent, received)
// followLogs() should be done by now
select {
case <-followLogsDone:
case <-time.After(30 * time.Second):
t.Fatal("timeout waiting for followLogs() to finish")
}
select {
case <-lw.WatchConsumerGone():
t.Fatal("consumer should not have exited")
default:
}
}

View File

@@ -110,14 +110,16 @@ func (daemon *Daemon) ContainerLogs(ctx context.Context, containerName string, c
}
}()
}
// set up some defers
defer logs.Close()
// signal that the log reader is gone
defer logs.ConsumerGone()
// close the messages channel. closing is the only way to signal above
// that we're doing with logs (other than context cancel i guess).
defer close(messageChan)
lg.Debug("begin logs")
defer lg.Debugf("end logs (%v)", ctx.Err())
for {
select {
// i do not believe as the system is currently designed any error
@@ -132,14 +134,12 @@ func (daemon *Daemon) ContainerLogs(ctx context.Context, containerName string, c
}
return
case <-ctx.Done():
lg.Debugf("logs: end stream, ctx is done: %v", ctx.Err())
return
case msg, ok := <-logs.Msg:
// there is some kind of pool or ring buffer in the logger that
// produces these messages, and a possible future optimization
// might be to use that pool and reuse message objects
if !ok {
lg.Debug("end logs")
return
}
m := msg.AsLogMessage() // just a pointer conversion, does not copy data

View File

@@ -45,6 +45,7 @@ func (daemon *Daemon) Reload(conf *config.Config) (err error) {
daemon.reloadDebug(conf, attributes)
daemon.reloadMaxConcurrentDownloadsAndUploads(conf, attributes)
daemon.reloadShutdownTimeout(conf, attributes)
daemon.reloadFeatures(conf, attributes)
if err := daemon.reloadClusterDiscovery(conf, attributes); err != nil {
return err
@@ -322,3 +323,13 @@ func (daemon *Daemon) reloadNetworkDiagnosticPort(conf *config.Config, attribute
return nil
}
// reloadFeatures updates configuration with enabled/disabled features
func (daemon *Daemon) reloadFeatures(conf *config.Config, attributes map[string]string) {
// update corresponding configuration
// note that we allow features option to be entirely unset
daemon.configStore.Features = conf.Features
// prepare reload event attributes with updatable configurations
attributes["features"] = fmt.Sprintf("%v", daemon.configStore.Features)
}

View File

@@ -17,7 +17,7 @@ import (
// TODO: this should use more of libtrust.LoadOrCreateTrustKey which may need
// a refactor or this function to be moved into libtrust
func loadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) {
err := system.MkdirAll(filepath.Dir(trustKeyPath), 0700, "")
err := system.MkdirAll(filepath.Dir(trustKeyPath), 0755, "")
if err != nil {
return nil, err
}

View File

@@ -210,6 +210,8 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
mp.Name = v.Name
mp.Driver = v.Driver
// need to selinux-relabel local mounts
mp.Source = v.Mountpoint
if mp.Driver == volume.DefaultDriverName {
setBindModeIfNull(mp)
}

View File

@@ -10,8 +10,6 @@ const (
Version = "library-import"
BuildTime = "library-import"
IAmStatic = "library-import"
ContainerdCommitID = "library-import"
RuncCommitID = "library-import"
InitCommitID = "library-import"
PlatformName = ""
ProductName = ""

Binary file not shown.

997
hack/ci/windows.ps1 Normal file
View File

@@ -0,0 +1,997 @@
# WARNING WARNING WARNING - DO NOT EDIT THIS FILE IN JENKINS DIRECTLY.
# SUBMIT A PR TO https://github.com/jhowardmsft/docker-w2wCIScripts/blob/master/runCI/executeCI.ps1,
# AND MAKE SURE https://github.com/jhowardmsft/docker-w2wCIScripts/blob/master/runCI/Invoke-DockerCI.ps1
# ISN'T BROKEN!!!!!!! VALIDATE USING A TEST CONTEXT IN JENKINS. THEN COPY/PASTE INTO JENKINS PRODUCTION.
#
# Jenkins CI scripts for Windows to Windows CI (Powershell Version)
# By John Howard (@jhowardmsft) January 2016 - bash version; July 2016 Ported to PowerShell
$ErrorActionPreference = 'Stop'
$StartTime=Get-Date
# Put up top to be blindingly obvious. The production jenkins.dockerproject.org Linux-container
# CI job is "Docker-PRs-LoW-RS3". Force into LCOW mode for this run, or not.
if ($env:BUILD_TAG -match "-LoW") { $env:LCOW_MODE=1 }
if ($env:BUILD_TAG -match "-WoW") { $env:LCOW_MODE="" }
# -------------------------------------------------------------------------------------------
# When executed, we rely on four variables being set in the environment:
#
# [The reason for being environment variables rather than parameters is historical. No reason
# why it couldn't be updated.]
#
# SOURCES_DRIVE is the drive on which the sources being tested are cloned from.
# This should be a straight drive letter, no platform semantics.
# For example 'c'
#
# SOURCES_SUBDIR is the top level directory under SOURCES_DRIVE where the
# sources are cloned to. There are no platform semantics in this
# as it does not include slashes.
# For example 'gopath'
#
# Based on the above examples, it would be expected that Jenkins
# would clone the sources being tested to
# SOURCES_DRIVE\SOURCES_SUBDIR\src\github.com\docker\docker, or
# c:\gopath\src\github.com\docker\docker
#
# TESTRUN_DRIVE is the drive where we build the binary on and redirect everything
# to for the daemon under test. On an Azure D2 type host which has
# an SSD temporary storage D: drive, this is ideal for performance.
# For example 'd'
#
# TESTRUN_SUBDIR is the top level directory under TESTRUN_DRIVE where we redirect
# everything to for the daemon under test. For example 'CI'.
# Hence, the daemon under test is run under
# TESTRUN_DRIVE\TESTRUN_SUBDIR\CI-<CommitID> or
# d:\CI\CI-<CommitID>
#
# In addition, the following variables can control the run configuration:
#
# DOCKER_DUT_DEBUG if defined starts the daemon under test in debug mode.
#
# SKIP_VALIDATION_TESTS if defined skips the validation tests
#
# SKIP_UNIT_TESTS if defined skips the unit tests
#
# SKIP_INTEGRATION_TESTS if defined skips the integration tests
#
# SKIP_COPY_GO if defined skips copy the go installer from the image
#
# DOCKER_DUT_HYPERV if default daemon under test default isolation is hyperv
#
# INTEGRATION_TEST_NAME to only run partial tests eg "TestInfo*" will only run
# any tests starting "TestInfo"
#
# SKIP_BINARY_BUILD if defined skips building the binary
#
# SKIP_ZAP_DUT if defined doesn't zap the daemon under test directory
#
# SKIP_IMAGE_BUILD if defined doesn't build the 'docker' image
#
# INTEGRATION_IN_CONTAINER if defined, runs the integration tests from inside a container.
# As of July 2016, there are known issues with this.
#
# SKIP_ALL_CLEANUP if defined, skips any cleanup at the start or end of the run
#
# WINDOWS_BASE_IMAGE if defined, uses that as the base image. Note that the
# docker integration tests are also coded to use the same
# environment variable, and if no set, defaults to microsoft/windowsservercore
#
# LCOW_BASIC_MODE if defined, does very basic LCOW verification. Ultimately we
# want to run the entire CI suite from docker, but that's a way off.
#
# LCOW_MODE if defined, runs the entire CI suite
#
# -------------------------------------------------------------------------------------------
#
# Jenkins Integration. Add a Windows Powershell build step as follows:
#
# Write-Host -ForegroundColor green "INFO: Jenkins build step starting"
# $CISCRIPT_DEFAULT_LOCATION = "https://raw.githubusercontent.com/jhowardmsft/docker-w2wCIScripts/master/runCI/executeCI.ps1"
# $CISCRIPT_LOCAL_LOCATION = "$env:TEMP\executeCI.ps1"
# Write-Host -ForegroundColor green "INFO: Removing cached execution script"
# Remove-Item $CISCRIPT_LOCAL_LOCATION -Force -ErrorAction SilentlyContinue 2>&1 | Out-Null
# $wc = New-Object net.webclient
# try {
# Write-Host -ForegroundColor green "INFO: Downloading latest execution script..."
# $wc.Downloadfile($CISCRIPT_DEFAULT_LOCATION, $CISCRIPT_LOCAL_LOCATION)
# }
# catch [System.Net.WebException]
# {
# Throw ("Failed to download: $_")
# }
# & $CISCRIPT_LOCAL_LOCATION
# -------------------------------------------------------------------------------------------
$SCRIPT_VER="28-Aug-2018 09:33 PDT"
$FinallyColour="Cyan"
#$env:DOCKER_DUT_DEBUG="yes" # Comment out to not be in debug mode
#$env:SKIP_UNIT_TESTS="yes"
#$env:SKIP_VALIDATION_TESTS="yes"
#$env:SKIP_ZAP_DUT=""
#$env:SKIP_BINARY_BUILD="yes"
#$env:INTEGRATION_TEST_NAME=""
#$env:SKIP_IMAGE_BUILD="yes"
#$env:SKIP_ALL_CLEANUP="yes"
#$env:INTEGRATION_IN_CONTAINER="yes"
#$env:WINDOWS_BASE_IMAGE=""
#$env:SKIP_COPY_GO="yes"
Function Nuke-Everything {
$ErrorActionPreference = 'SilentlyContinue'
try {
if ($env:SKIP_ALL_CLEANUP -eq $null) {
Write-Host -ForegroundColor green "INFO: Nuke-Everything..."
$containerCount = ($(docker ps -aq | Measure-Object -line).Lines)
if (-not $LastExitCode -eq 0) {
Throw "ERROR: Failed to get container count from control daemon while nuking"
}
Write-Host -ForegroundColor green "INFO: Container count on control daemon to delete is $containerCount"
if ($(docker ps -aq | Measure-Object -line).Lines -gt 0) {
docker rm -f $(docker ps -aq)
}
$imageCount=($(docker images --format "{{.Repository}}:{{.ID}}" | `
select-string -NotMatch "windowsservercore" | `
select-string -NotMatch "nanoserver" | `
select-string -NotMatch "docker" | `
Measure-Object -line).Lines)
if ($imageCount -gt 0) {
Write-Host -Foregroundcolor green "INFO: Non-base image count on control daemon to delete is $imageCount"
docker rmi -f `
$(docker images --format "{{.Repository}}:{{.ID}}" | `
select-string -NotMatch "windowsservercore" | `
select-string -NotMatch "nanoserver" | `
select-string -NotMatch "docker").ToString().Split(":")[1]
}
} else {
Write-Host -ForegroundColor Magenta "WARN: Skipping cleanup of images and containers"
}
# Kill any spurious daemons. The '-' is IMPORTANT otherwise will kill the control daemon!
$pids=$(get-process | where-object {$_.ProcessName -like 'dockerd-*'}).id
foreach ($p in $pids) {
Write-Host "INFO: Killing daemon with PID $p"
Stop-Process -Id $p -Force -ErrorAction SilentlyContinue
}
if ($pidFile -ne $Null) {
Write-Host "INFO: Tidying pidfile $pidfile"
if (Test-Path $pidFile) {
$p=Get-Content $pidFile -raw
if ($p -ne $null){
Write-Host -ForegroundColor green "INFO: Stopping possible daemon pid $p"
taskkill -f -t -pid $p
}
Remove-Item "$env:TEMP\docker.pid" -force -ErrorAction SilentlyContinue
}
}
Stop-Process -name "cc1" -Force -ErrorAction SilentlyContinue 2>&1 | Out-Null
Stop-Process -name "link" -Force -ErrorAction SilentlyContinue 2>&1 | Out-Null
Stop-Process -name "compile" -Force -ErrorAction SilentlyContinue 2>&1 | Out-Null
Stop-Process -name "ld" -Force -ErrorAction SilentlyContinue 2>&1 | Out-Null
Stop-Process -name "go" -Force -ErrorAction SilentlyContinue 2>&1 | Out-Null
Stop-Process -name "git" -Force -ErrorAction SilentlyContinue 2>&1 | Out-Null
Stop-Process -name "git-remote-https" -Force -ErrorAction SilentlyContinue 2>&1 | Out-Null
Stop-Process -name "integration-cli.test" -Force -ErrorAction SilentlyContinue 2>&1 | Out-Null
Stop-Process -name "tail" -Force -ErrorAction SilentlyContinue 2>&1 | Out-Null
# Detach any VHDs
gwmi msvm_mountedstorageimage -namespace root/virtualization/v2 -ErrorAction SilentlyContinue | foreach-object {$_.DetachVirtualHardDisk() }
# Stop any compute processes
Get-ComputeProcess | Stop-ComputeProcess -Force
# Delete the directory using our dangerous utility unless told not to
if (Test-Path "$env:TESTRUN_DRIVE`:\$env:TESTRUN_SUBDIR") {
if (($env:SKIP_ZAP_DUT -ne $null) -or ($env:SKIP_ALL_CLEANUP -eq $null)) {
Write-Host -ForegroundColor Green "INFO: Nuking $env:TESTRUN_DRIVE`:\$env:TESTRUN_SUBDIR"
docker-ci-zap "-folder=$env:TESTRUN_DRIVE`:\$env:TESTRUN_SUBDIR"
} else {
Write-Host -ForegroundColor Magenta "WARN: Skip nuking $env:TESTRUN_DRIVE`:\$env:TESTRUN_SUBDIR"
}
}
# TODO: This should be able to be removed in August 2017 update. Only needed for RS1 Production Server workaround - Psched
$reg = "HKLM:\System\CurrentControlSet\Services\Psched\Parameters\NdisAdapters"
$count=(Get-ChildItem $reg | Measure-Object).Count
if ($count -gt 0) {
Write-Warning "There are $count NdisAdapters leaked under Psched\Parameters"
if ($env:COMPUTERNAME -match "jenkins-rs1-") {
Write-Warning "Cleaning Psched..."
Get-ChildItem $reg | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
} else {
Write-Warning "Not cleaning as not a production RS1 server"
}
}
# TODO: This should be able to be removed in August 2017 update. Only needed for RS1
$reg = "HKLM:\System\CurrentControlSet\Services\WFPLWFS\Parameters\NdisAdapters"
$count=(Get-ChildItem $reg | Measure-Object).Count
if ($count -gt 0) {
Write-Warning "There are $count NdisAdapters leaked under WFPLWFS\Parameters"
if ($env:COMPUTERNAME -match "jenkins-rs1-") {
Write-Warning "Cleaning WFPLWFS..."
Get-ChildItem $reg | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
} else {
Write-Warning "Not cleaning as not a production RS1 server"
}
}
} catch {
# Don't throw any errors onwards Throw $_
}
}
Try {
Write-Host -ForegroundColor Cyan "`nINFO: executeCI.ps1 starting at $(date)`n"
Write-Host -ForegroundColor Green "INFO: Script version $SCRIPT_VER"
Set-PSDebug -Trace 0 # 1 to turn on
$origPath="$env:PATH" # so we can restore it at the end
$origDOCKER_HOST="$DOCKER_HOST" # So we can restore it at the end
$origGOROOT="$env:GOROOT" # So we can restore it at the end
$origGOPATH="$env:GOPATH" # So we can restore it at the end
# Turn off progress bars
$origProgressPreference=$global:ProgressPreference
$global:ProgressPreference='SilentlyContinue'
# Git version
Write-Host -ForegroundColor Green "INFO: Running $(git version)"
# OS Version
$bl=(Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name BuildLabEx).BuildLabEx
$a=$bl.ToString().Split(".")
$Branch=$a[3]
$WindowsBuild=$a[0]+"."+$a[1]+"."+$a[4]
Write-Host -ForegroundColor green "INFO: Branch:$Branch Build:$WindowsBuild"
# List the environment variables
Write-Host -ForegroundColor green "INFO: Environment variables:"
Get-ChildItem Env: | Out-String
# PR
if (-not ($env:PR -eq $Null)) { echo "INFO: PR#$env:PR (https://github.com/docker/docker/pull/$env:PR)" }
# Make sure docker is installed
if ((Get-Command "docker" -ErrorAction SilentlyContinue) -eq $null) { Throw "ERROR: docker is not installed or not found on path" }
# Make sure docker-ci-zap is installed
if ((Get-Command "docker-ci-zap" -ErrorAction SilentlyContinue) -eq $null) { Throw "ERROR: docker-ci-zap is not installed or not found on path" }
# Make sure SOURCES_DRIVE is set
if ($env:SOURCES_DRIVE -eq $Null) { Throw "ERROR: Environment variable SOURCES_DRIVE is not set" }
# Make sure TESTRUN_DRIVE is set
if ($env:TESTRUN_DRIVE -eq $Null) { Throw "ERROR: Environment variable TESTRUN_DRIVE is not set" }
# Make sure SOURCES_SUBDIR is set
if ($env:SOURCES_SUBDIR -eq $Null) { Throw "ERROR: Environment variable SOURCES_SUBDIR is not set" }
# Make sure TESTRUN_SUBDIR is set
if ($env:TESTRUN_SUBDIR -eq $Null) { Throw "ERROR: Environment variable TESTRUN_SUBDIR is not set" }
# SOURCES_DRIVE\SOURCES_SUBDIR must be a directory and exist
if (-not (Test-Path -PathType Container "$env:SOURCES_DRIVE`:\$env:SOURCES_SUBDIR")) { Throw "ERROR: $env:SOURCES_DRIVE`:\$env:SOURCES_SUBDIR must be an existing directory" }
# Create the TESTRUN_DRIVE\TESTRUN_SUBDIR if it does not already exist
New-Item -ItemType Directory -Force -Path "$env:TESTRUN_DRIVE`:\$env:TESTRUN_SUBDIR" -ErrorAction SilentlyContinue | Out-Null
Write-Host -ForegroundColor Green "INFO: Sources under $env:SOURCES_DRIVE`:\$env:SOURCES_SUBDIR\..."
Write-Host -ForegroundColor Green "INFO: Test run under $env:TESTRUN_DRIVE`:\$env:TESTRUN_SUBDIR\..."
# Check the intended source location is a directory
if (-not (Test-Path -PathType Container "$env:SOURCES_DRIVE`:\$env:SOURCES_SUBDIR\src\github.com\docker\docker" -ErrorAction SilentlyContinue)) {
Throw "ERROR: $env:SOURCES_DRIVE`:\$env:SOURCES_SUBDIR\src\github.com\docker\docker is not a directory!"
}
# Make sure we start at the root of the sources
cd "$env:SOURCES_DRIVE`:\$env:SOURCES_SUBDIR\src\github.com\docker\docker"
Write-Host -ForegroundColor Green "INFO: Running in $(pwd)"
# Make sure we are in repo
if (-not (Test-Path -PathType Leaf -Path ".\Dockerfile.windows")) {
Throw "$(pwd) does not contain Dockerfile.windows!"
}
Write-Host -ForegroundColor Green "INFO: docker/docker repository was found"
# Make sure microsoft/windowsservercore:latest image is installed in the control daemon. On public CI machines, windowsservercore.tar and nanoserver.tar
# are pre-baked and tagged appropriately in the c:\baseimages directory, and can be directly loaded.
# Note - this script will only work on 10B (Oct 2016) or later machines! Not 9D or previous due to image tagging assumptions.
#
# On machines not on Microsoft corpnet, or those which have not been pre-baked, we have to docker pull the image in which case it will
# will come in directly as microsoft/windowsservercore:latest. The ultimate goal of all this code is to ensure that whatever,
# we have microsoft/windowsservercore:latest
#
# Note we cannot use (as at Oct 2016) nanoserver as the control daemons base image, even if nanoserver is used in the tests themselves.
$ErrorActionPreference = "SilentlyContinue"
$ControlDaemonBaseImage="windowsservercore"
$readBaseFrom="c"
if ($((docker images --format "{{.Repository}}:{{.Tag}}" | Select-String $("microsoft/"+$ControlDaemonBaseImage+":latest") | Measure-Object -Line).Lines) -eq 0) {
# Try the internal azure CI image version or Microsoft internal corpnet where the base image is already pre-prepared on the disk,
# either through Invoke-DockerCI or, in the case of Azure CI servers, baked into the VHD at the same location.
if (Test-Path $("$env:SOURCES_DRIVE`:\baseimages\"+$ControlDaemonBaseImage+".tar")) {
# An optimization for CI servers to copy it to the D: drive which is an SSD.
if ($env:SOURCES_DRIVE -ne $env:TESTRUN_DRIVE) {
$readBaseFrom=$env:TESTRUN_DRIVE
if (!(Test-Path "$env:TESTRUN_DRIVE`:\baseimages")) {
New-Item "$env:TESTRUN_DRIVE`:\baseimages" -type directory | Out-Null
}
if (!(Test-Path "$env:TESTRUN_DRIVE`:\baseimages\windowsservercore.tar")) {
if (Test-Path "$env:SOURCES_DRIVE`:\baseimages\windowsservercore.tar") {
Write-Host -ForegroundColor Green "INFO: Optimisation - copying $env:SOURCES_DRIVE`:\baseimages\windowsservercore.tar to $env:TESTRUN_DRIVE`:\baseimages"
Copy-Item "$env:SOURCES_DRIVE`:\baseimages\windowsservercore.tar" "$env:TESTRUN_DRIVE`:\baseimages"
}
}
if (!(Test-Path "$env:TESTRUN_DRIVE`:\baseimages\nanoserver.tar")) {
if (Test-Path "$env:SOURCES_DRIVE`:\baseimages\nanoserver.tar") {
Write-Host -ForegroundColor Green "INFO: Optimisation - copying $env:SOURCES_DRIVE`:\baseimages\nanoserver.tar to $env:TESTRUN_DRIVE`:\baseimages"
Copy-Item "$env:SOURCES_DRIVE`:\baseimages\nanoserver.tar" "$env:TESTRUN_DRIVE`:\baseimages"
}
}
$readBaseFrom=$env:TESTRUN_DRIVE
}
Write-Host -ForegroundColor Green "INFO: Loading"$ControlDaemonBaseImage".tar from disk. This may take some time..."
$ErrorActionPreference = "SilentlyContinue"
docker load -i $("$readBaseFrom`:\baseimages\"+$ControlDaemonBaseImage+".tar")
$ErrorActionPreference = "Stop"
if (-not $LastExitCode -eq 0) {
Throw $("ERROR: Failed to load $readBaseFrom`:\baseimages\"+$ControlDaemonBaseImage+".tar")
}
Write-Host -ForegroundColor Green "INFO: docker load of"$ControlDaemonBaseImage" completed successfully"
} else {
# We need to docker pull it instead. It will come in directly as microsoft/imagename:latest
Write-Host -ForegroundColor Green $("INFO: Pulling microsoft/"+$ControlDaemonBaseImage+":latest from docker hub. This may take some time...")
$ErrorActionPreference = "SilentlyContinue"
docker pull $("microsoft/"+$ControlDaemonBaseImage)
$ErrorActionPreference = "Stop"
if (-not $LastExitCode -eq 0) {
Throw $("ERROR: Failed to docker pull microsoft/"+$ControlDaemonBaseImage+":latest.")
}
Write-Host -ForegroundColor Green $("INFO: docker pull of microsoft/"+$ControlDaemonBaseImage+":latest completed successfully")
}
} else {
Write-Host -ForegroundColor Green "INFO: Image"$("microsoft/"+$ControlDaemonBaseImage+":latest")"is already loaded in the control daemon"
}
# Inspect the pulled image to get the version directly
$ErrorActionPreference = "SilentlyContinue"
$imgVersion = $(docker inspect $("microsoft/"+$ControlDaemonBaseImage) --format "{{.OsVersion}}")
$ErrorActionPreference = "Stop"
Write-Host -ForegroundColor Green $("INFO: Version of microsoft/"+$ControlDaemonBaseImage+":latest is '"+$imgVersion+"'")
# Provide the docker version for debugging purposes.
Write-Host -ForegroundColor Green "INFO: Docker version of control daemon"
Write-Host
$ErrorActionPreference = "SilentlyContinue"
docker version
$ErrorActionPreference = "Stop"
if (-not($LastExitCode -eq 0)) {
Write-Host
Write-Host -ForegroundColor Green "---------------------------------------------------------------------------"
Write-Host -ForegroundColor Green " Failed to get a response from the control daemon. It may be down."
Write-Host -ForegroundColor Green " Try re-running this CI job, or ask on #docker-maintainers on docker slack"
Write-Host -ForegroundColor Green " to see if the the daemon is running. Also check the service configuration."
Write-Host -ForegroundColor Green " DOCKER_HOST is set to $DOCKER_HOST."
Write-Host -ForegroundColor Green "---------------------------------------------------------------------------"
Write-Host
Throw "ERROR: The control daemon does not appear to be running."
}
Write-Host
# Same as above, but docker info
Write-Host -ForegroundColor Green "INFO: Docker info of control daemon"
Write-Host
$ErrorActionPreference = "SilentlyContinue"
docker info
$ErrorActionPreference = "Stop"
if (-not($LastExitCode -eq 0)) {
Throw "ERROR: The control daemon does not appear to be running."
}
Write-Host
# Get the commit has and verify we have something
$ErrorActionPreference = "SilentlyContinue"
$COMMITHASH=$(git rev-parse --short HEAD)
$ErrorActionPreference = "Stop"
if (-not($LastExitCode -eq 0)) {
Throw "ERROR: Failed to get commit hash. Are you sure this is a docker repository?"
}
Write-Host -ForegroundColor Green "INFO: Commit hash is $COMMITHASH"
# Nuke everything and go back to our sources after
Nuke-Everything
cd "$env:SOURCES_DRIVE`:\$env:SOURCES_SUBDIR\src\github.com\docker\docker"
# Redirect to a temporary location.
$TEMPORIG=$env:TEMP
$env:TEMP="$env:TESTRUN_DRIVE`:\$env:TESTRUN_SUBDIR\CI-$COMMITHASH"
$env:LOCALAPPDATA="$TEMP\localappdata"
$errorActionPreference='Stop'
New-Item -ItemType Directory "$env:TEMP" -ErrorAction SilentlyContinue | Out-Null
New-Item -ItemType Directory "$env:TEMP\userprofile" -ErrorAction SilentlyContinue | Out-Null
New-Item -ItemType Directory "$env:TEMP\localappdata" -ErrorAction SilentlyContinue | Out-Null
New-Item -ItemType Directory "$env:TEMP\binary" -ErrorAction SilentlyContinue | Out-Null
New-Item -ItemType Directory "$env:TEMP\installer" -ErrorAction SilentlyContinue | Out-Null
if ($env:SKIP_COPY_GO -eq $null) {
# Wipe the previous version of GO - we're going to get it out of the image
if (Test-Path "$env:TEMP\go") { Remove-Item "$env:TEMP\go" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null }
New-Item -ItemType Directory "$env:TEMP\go" -ErrorAction SilentlyContinue | Out-Null
}
Write-Host -ForegroundColor Green "INFO: Location for testing is $env:TEMP"
# CI Integrity check - ensure Dockerfile.windows and Dockerfile go versions match
$goVersionDockerfileWindows=$(Get-Content ".\Dockerfile.windows" | Select-String "^ENV GO_VERSION").ToString().Replace("ENV GO_VERSION=","").Replace("\","").Replace("``","").Trim()
$goVersionDockerfile=$(Get-Content ".\Dockerfile" | Select-String "^ENV GO_VERSION")
# As of go 1.11, Dockerfile changed to be in the format like "FROM golang:1.11.0 AS base".
# If a version number ends with .0 (as in 1.11.0, a convention used in golang docker
# image versions), it needs to be removed (i.e. "1.11.0" becomes "1.11").
if ($goVersionDockerfile -eq $Null) {
$goVersionDockerfile=$(Get-Content ".\Dockerfile" | Select-String "^FROM golang:")
if ($goVersionDockerfile -ne $Null) {
$goVersionDockerfile = $goVersionDockerfile.ToString().Split(" ")[1].Split(":")[1] -replace '\.0$',''
}
} else {
$goVersionDockerfile = $goVersionDockerfile.ToString().Split(" ")[2]
}
if ($goVersionDockerfile -eq $Null) {
Throw "ERROR: Failed to extract golang version from Dockerfile"
}
Write-Host -ForegroundColor Green "INFO: Validating GOLang consistency in Dockerfile.windows..."
if (-not ($goVersionDockerfile -eq $goVersionDockerfileWindows)) {
Throw "ERROR: Mismatched GO versions between Dockerfile and Dockerfile.windows. Update your PR to ensure that both files are updated and in sync. $goVersionDockerfile $goVersionDockerfileWindows"
}
# Build the image
if ($env:SKIP_IMAGE_BUILD -eq $null) {
Write-Host -ForegroundColor Cyan "`n`nINFO: Building the image from Dockerfile.windows at $(Get-Date)..."
Write-Host
$ErrorActionPreference = "SilentlyContinue"
$Duration=$(Measure-Command { docker build -t docker -f Dockerfile.windows . | Out-Host })
$ErrorActionPreference = "Stop"
if (-not($LastExitCode -eq 0)) {
Throw "ERROR: Failed to build image from Dockerfile.windows"
}
Write-Host -ForegroundColor Green "INFO: Image build ended at $(Get-Date). Duration`:$Duration"
} else {
Write-Host -ForegroundColor Magenta "WARN: Skipping building the docker image"
}
# Following at the moment must be docker\docker as it's dictated by dockerfile.Windows
$contPath="$COMMITHASH`:c`:\go\src\github.com\docker\docker\bundles"
# After https://github.com/docker/docker/pull/30290, .git was added to .dockerignore. Therefore
# we have to calculate unsupported outside of the container, and pass the commit ID in through
# an environment variable for the binary build
$CommitUnsupported=""
if ($(git status --porcelain --untracked-files=no).Length -ne 0) {
$CommitUnsupported="-unsupported"
}
# Build the binary in a container unless asked to skip it.
if ($env:SKIP_BINARY_BUILD -eq $null) {
Write-Host -ForegroundColor Cyan "`n`nINFO: Building the test binaries at $(Get-Date)..."
$ErrorActionPreference = "SilentlyContinue"
docker rm -f $COMMITHASH 2>&1 | Out-Null
if ($CommitUnsupported -ne "") {
Write-Host ""
Write-Warning "This version is unsupported because there are uncommitted file(s)."
Write-Warning "Either commit these changes, or add them to .gitignore."
git status --porcelain --untracked-files=no | Write-Warning
Write-Host ""
}
$Duration=$(Measure-Command {docker run --name $COMMITHASH -e DOCKER_GITCOMMIT=$COMMITHASH$CommitUnsupported docker hack\make.ps1 -Daemon -Client | Out-Host })
$ErrorActionPreference = "Stop"
if (-not($LastExitCode -eq 0)) {
Throw "ERROR: Failed to build binary"
}
Write-Host -ForegroundColor Green "INFO: Binaries build ended at $(Get-Date). Duration`:$Duration"
# Copy the binaries and the generated version_autogen.go out of the container
$ErrorActionPreference = "SilentlyContinue"
docker cp "$contPath\docker.exe" $env:TEMP\binary\
if (-not($LastExitCode -eq 0)) {
Throw "ERROR: Failed to docker cp the client binary (docker.exe) to $env:TEMP\binary"
}
docker cp "$contPath\dockerd.exe" $env:TEMP\binary\
if (-not($LastExitCode -eq 0)) {
Throw "ERROR: Failed to docker cp the daemon binary (dockerd.exe) to $env:TEMP\binary"
}
$ErrorActionPreference = "Stop"
# Copy the built dockerd.exe to dockerd-$COMMITHASH.exe so that easily spotted in task manager.
Write-Host -ForegroundColor Green "INFO: Copying the built daemon binary to $env:TEMP\binary\dockerd-$COMMITHASH.exe..."
Copy-Item $env:TEMP\binary\dockerd.exe $env:TEMP\binary\dockerd-$COMMITHASH.exe -Force -ErrorAction SilentlyContinue
# Copy the built docker.exe to docker-$COMMITHASH.exe
Write-Host -ForegroundColor Green "INFO: Copying the built client binary to $env:TEMP\binary\docker-$COMMITHASH.exe..."
Copy-Item $env:TEMP\binary\docker.exe $env:TEMP\binary\docker-$COMMITHASH.exe -Force -ErrorAction SilentlyContinue
} else {
Write-Host -ForegroundColor Magenta "WARN: Skipping building the binaries"
}
Write-Host -ForegroundColor Green "INFO: Copying dockerversion from the container..."
$ErrorActionPreference = "SilentlyContinue"
docker cp "$contPath\..\dockerversion\version_autogen.go" "$env:SOURCES_DRIVE`:\$env:SOURCES_SUBDIR\src\github.com\docker\docker\dockerversion"
if (-not($LastExitCode -eq 0)) {
Throw "ERROR: Failed to docker cp the generated version_autogen.go to $env:SOURCES_DRIVE`:\$env:SOURCES_SUBDIR\src\github.com\docker\docker\dockerversion"
}
$ErrorActionPreference = "Stop"
# Grab the golang installer out of the built image. That way, we know we are consistent once extracted and paths set,
# so there's no need to re-deploy on account of an upgrade to the version of GO being used in docker.
if ($env:SKIP_COPY_GO -eq $null) {
Write-Host -ForegroundColor Green "INFO: Copying the golang package from the container to $env:TEMP\installer\go.zip..."
docker cp "$COMMITHASH`:c`:\go.zip" $env:TEMP\installer\
if (-not($LastExitCode -eq 0)) {
Throw "ERROR: Failed to docker cp the golang installer 'go.zip' from container:c:\go.zip to $env:TEMP\installer"
}
$ErrorActionPreference = "Stop"
# Extract the golang installer
Write-Host -ForegroundColor Green "INFO: Extracting go.zip to $env:TEMP\go"
$Duration=$(Measure-Command { Expand-Archive $env:TEMP\installer\go.zip $env:TEMP -Force | Out-Null})
Write-Host -ForegroundColor Green "INFO: Extraction ended at $(Get-Date). Duration`:$Duration"
} else {
Write-Host -ForegroundColor Magenta "WARN: Skipping copying and extracting golang from the image"
}
# Set the GOPATH
Write-Host -ForegroundColor Green "INFO: Updating the golang and path environment variables"
$env:GOPATH="$env:SOURCES_DRIVE`:\$env:SOURCES_SUBDIR"
Write-Host -ForegroundColor Green "INFO: GOPATH=$env:GOPATH"
# Set the path to have the version of go from the image at the front
$env:PATH="$env:TEMP\go\bin;$env:PATH"
# Set the GOROOT to be our copy of go from the image
$env:GOROOT="$env:TEMP\go"
Write-Host -ForegroundColor Green "INFO: $(go version)"
# Work out the the -H parameter for the daemon under test (DASHH_DUT) and client under test (DASHH_CUT)
#$DASHH_DUT="npipe:////./pipe/$COMMITHASH" # Can't do remote named pipe
#$ip = (resolve-dnsname $env:COMPUTERNAME -type A -NoHostsFile -LlmnrNetbiosOnly).IPAddress # Useful to tie down
$DASHH_CUT="tcp://127.0.0.1`:2357" # Not a typo for 2375!
$DASHH_DUT="tcp://0.0.0.0:2357" # Not a typo for 2375!
# Arguments for the daemon under test
$dutArgs=@()
$dutArgs += "-H $DASHH_DUT"
$dutArgs += "--data-root $env:TEMP\daemon"
$dutArgs += "--pidfile $env:TEMP\docker.pid"
# Save the PID file so we can nuke it if set
$pidFile="$env:TEMP\docker.pid"
# Arguments: Are we starting the daemon under test in debug mode?
if (-not ("$env:DOCKER_DUT_DEBUG" -eq "")) {
Write-Host -ForegroundColor Green "INFO: Running the daemon under test in debug mode"
$dutArgs += "-D"
}
# Arguments: Are we starting the daemon under test with Hyper-V containers as the default isolation?
if (-not ("$env:DOCKER_DUT_HYPERV" -eq "")) {
Write-Host -ForegroundColor Green "INFO: Running the daemon under test with Hyper-V containers as the default"
$dutArgs += "--exec-opt isolation=hyperv"
}
# Start the daemon under test, ensuring everything is redirected to folders under $TEMP.
# Important - we launch the -$COMMITHASH version so that we can kill it without
# killing the control daemon.
Write-Host -ForegroundColor Green "INFO: Starting a daemon under test..."
Write-Host -ForegroundColor Green "INFO: Args: $dutArgs"
New-Item -ItemType Directory $env:TEMP\daemon -ErrorAction SilentlyContinue | Out-Null
# In LCOW mode, for now we need to set an environment variable before starting the daemon under test
if (($env:LCOW_MODE -ne $Null) -or ($env:LCOW_BASIC_MODE -ne $Null)) {
$env:LCOW_SUPPORTED=1
}
# Cannot fathom why, but always writes to stderr....
Start-Process "$env:TEMP\binary\dockerd-$COMMITHASH" `
-ArgumentList $dutArgs `
-RedirectStandardOutput "$env:TEMP\dut.out" `
-RedirectStandardError "$env:TEMP\dut.err"
Write-Host -ForegroundColor Green "INFO: Process started successfully."
$daemonStarted=1
# In LCOW mode, turn off that variable
if (($env:LCOW_MODE -ne $Null) -or ($env:LCOW_BASIC_MODE -ne $Null)) {
$env:LCOW_SUPPORTED=""
}
# Start tailing the daemon under test if the command is installed
if ((Get-Command "tail" -ErrorAction SilentlyContinue) -ne $null) {
$tail = start-process "tail" -ArgumentList "-f $env:TEMP\dut.out" -ErrorAction SilentlyContinue
}
# Verify we can get the daemon under test to respond
$tries=20
Write-Host -ForegroundColor Green "INFO: Waiting for the daemon under test to start..."
while ($true) {
$ErrorActionPreference = "SilentlyContinue"
& "$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" version 2>&1 | Out-Null
$ErrorActionPreference = "Stop"
if ($LastExitCode -eq 0) {
break
}
$tries--
if ($tries -le 0) {
$DumpDaemonLog=1
Throw "ERROR: Failed to get a response from the daemon under test"
}
Write-Host -NoNewline "."
sleep 1
}
Write-Host -ForegroundColor Green "INFO: Daemon under test started and replied!"
# Provide the docker version of the daemon under test for debugging purposes.
Write-Host -ForegroundColor Green "INFO: Docker version of the daemon under test"
Write-Host
$ErrorActionPreference = "SilentlyContinue"
& "$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" version
$ErrorActionPreference = "Stop"
if ($LastExitCode -ne 0) {
Throw "ERROR: The daemon under test does not appear to be running."
$DumpDaemonLog=1
}
Write-Host
# Same as above but docker info
Write-Host -ForegroundColor Green "INFO: Docker info of the daemon under test"
Write-Host
$ErrorActionPreference = "SilentlyContinue"
& "$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" info
$ErrorActionPreference = "Stop"
if ($LastExitCode -ne 0) {
Throw "ERROR: The daemon under test does not appear to be running."
$DumpDaemonLog=1
}
Write-Host
# Same as above but docker images
Write-Host -ForegroundColor Green "INFO: Docker images of the daemon under test"
Write-Host
$ErrorActionPreference = "SilentlyContinue"
& "$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" images
$ErrorActionPreference = "Stop"
if ($LastExitCode -ne 0) {
Throw "ERROR: The daemon under test does not appear to be running."
$DumpDaemonLog=1
}
Write-Host
# Don't need Windows images when in LCOW mode.
if (($env:LCOW_MODE -eq $Null) -and ($env:LCOW_BASIC_MODE -eq $Null)) {
# Default to windowsservercore for the base image used for the tests. The "docker" image
# and the control daemon use microsoft/windowsservercore regardless. This is *JUST* for the tests.
if ($env:WINDOWS_BASE_IMAGE -eq $Null) {
$env:WINDOWS_BASE_IMAGE="microsoft/windowsservercore"
}
# Lowercase and make sure it has a microsoft/ prefix
$env:WINDOWS_BASE_IMAGE = $env:WINDOWS_BASE_IMAGE.ToLower()
if ($($env:WINDOWS_BASE_IMAGE -Split "/")[0] -ne "microsoft") {
Throw "ERROR: WINDOWS_BASE_IMAGE should start microsoft/"
}
Write-Host -ForegroundColor Green "INFO: Base image for tests is $env:WINDOWS_BASE_IMAGE"
$ErrorActionPreference = "SilentlyContinue"
if ($((& "$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" images --format "{{.Repository}}:{{.Tag}}" | Select-String $($env:WINDOWS_BASE_IMAGE+":latest") | Measure-Object -Line).Lines) -eq 0) {
# Try the internal azure CI image version or Microsoft internal corpnet where the base image is already pre-prepared on the disk,
# either through Invoke-DockerCI or, in the case of Azure CI servers, baked into the VHD at the same location.
if (Test-Path $("c:\baseimages\"+$($env:WINDOWS_BASE_IMAGE -Split "/")[1]+".tar")) {
Write-Host -ForegroundColor Green "INFO: Loading"$($env:WINDOWS_BASE_IMAGE -Split "/")[1]".tar from disk into the daemon under test. This may take some time..."
$ErrorActionPreference = "SilentlyContinue"
& "$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" load -i $("$readBaseFrom`:\baseimages\"+$($env:WINDOWS_BASE_IMAGE -Split "/")[1]+".tar")
$ErrorActionPreference = "Stop"
if (-not $LastExitCode -eq 0) {
Throw $("ERROR: Failed to load $readBaseFrom`:\baseimages\"+$($env:WINDOWS_BASE_IMAGE -Split "/")[1]+".tar into daemon under test")
}
Write-Host -ForegroundColor Green "INFO: docker load of"$($env:WINDOWS_BASE_IMAGE -Split "/")[1]" into daemon under test completed successfully"
} else {
# We need to docker pull it instead. It will come in directly as microsoft/imagename:latest
Write-Host -ForegroundColor Green $("INFO: Pulling "+$env:WINDOWS_BASE_IMAGE+":latest from docker hub into daemon under test. This may take some time...")
$ErrorActionPreference = "SilentlyContinue"
& "$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" pull $($env:WINDOWS_BASE_IMAGE)
$ErrorActionPreference = "Stop"
if (-not $LastExitCode -eq 0) {
Throw $("ERROR: Failed to docker pull "+$env:WINDOWS_BASE_IMAGE+":latest into daemon under test.")
}
Write-Host -ForegroundColor Green $("INFO: docker pull of "+$env:WINDOWS_BASE_IMAGE+":latest into daemon under test completed successfully")
}
} else {
Write-Host -ForegroundColor Green "INFO: Image"$($env:WINDOWS_BASE_IMAGE+":latest")"is already loaded in the daemon under test"
}
# Inspect the pulled or loaded image to get the version directly
$ErrorActionPreference = "SilentlyContinue"
$dutimgVersion = $(&"$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" inspect $($env:WINDOWS_BASE_IMAGE) --format "{{.OsVersion}}")
$ErrorActionPreference = "Stop"
Write-Host -ForegroundColor Green $("INFO: Version of "+$env:WINDOWS_BASE_IMAGE+":latest is '"+$dutimgVersion+"'")
}
# Run the validation tests unless SKIP_VALIDATION_TESTS is defined.
if ($env:SKIP_VALIDATION_TESTS -eq $null) {
Write-Host -ForegroundColor Cyan "INFO: Running validation tests at $(Get-Date)..."
$ErrorActionPreference = "SilentlyContinue"
$Duration=$(Measure-Command { hack\make.ps1 -DCO -GoFormat -PkgImports | Out-Host })
$ErrorActionPreference = "Stop"
if (-not($LastExitCode -eq 0)) {
Throw "ERROR: Validation tests failed"
}
Write-Host -ForegroundColor Green "INFO: Validation tests ended at $(Get-Date). Duration`:$Duration"
} else {
Write-Host -ForegroundColor Magenta "WARN: Skipping validation tests"
}
# Note the unit tests won't work in LCOW mode as I turned off loading the base images above.
# Run the unit tests inside a container unless SKIP_UNIT_TESTS is defined
if (($env:LCOW_MODE -eq $Null) -and ($env:LCOW_BASIC_MODE -eq $Null)) {
if ($env:SKIP_UNIT_TESTS -eq $null) {
Write-Host -ForegroundColor Cyan "INFO: Running unit tests at $(Get-Date)..."
$ErrorActionPreference = "SilentlyContinue"
$Duration=$(Measure-Command {docker run -e DOCKER_GITCOMMIT=$COMMITHASH$CommitUnsupported docker hack\make.ps1 -TestUnit | Out-Host })
$ErrorActionPreference = "Stop"
if (-not($LastExitCode -eq 0)) {
Throw "ERROR: Unit tests failed"
}
Write-Host -ForegroundColor Green "INFO: Unit tests ended at $(Get-Date). Duration`:$Duration"
} else {
Write-Host -ForegroundColor Magenta "WARN: Skipping unit tests"
}
}
# Add the Windows busybox image. Needed for WCOW integration tests
if (($env:LCOW_MODE -eq $Null) -and ($env:LCOW_BASIC_MODE -eq $Null)) {
if ($env:SKIP_INTEGRATION_TESTS -eq $null) {
$ErrorActionPreference = "SilentlyContinue"
# Build it regardless while switching between nanoserver and windowsservercore
#$bbCount = $(& "$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" images | Select-String "busybox" | Measure-Object -line).Lines
#$ErrorActionPreference = "Stop"
#if (-not($LastExitCode -eq 0)) {
# Throw "ERROR: Could not determine if busybox image is present"
#}
#if ($bbCount -eq 0) {
Write-Host -ForegroundColor Green "INFO: Building busybox"
$ErrorActionPreference = "SilentlyContinue"
# This is a temporary hack for nanoserver
if ($env:WINDOWS_BASE_IMAGE -ne "microsoft/windowsservercore") {
Write-Host -ForegroundColor Red "HACK HACK HACK - Building 64-bit nanoserver busybox image"
$(& "$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" build -t busybox https://raw.githubusercontent.com/jhowardmsft/busybox64/v1.0/Dockerfile | Out-Host)
} else {
$(& "$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" build -t busybox https://raw.githubusercontent.com/jhowardmsft/busybox/v1.0/Dockerfile | Out-Host)
}
$ErrorActionPreference = "Stop"
if (-not($LastExitCode -eq 0)) {
Throw "ERROR: Failed to build busybox image"
}
#}
Write-Host -ForegroundColor Green "INFO: Docker images of the daemon under test"
Write-Host
$ErrorActionPreference = "SilentlyContinue"
& "$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" images
$ErrorActionPreference = "Stop"
if ($LastExitCode -ne 0) {
Throw "ERROR: The daemon under test does not appear to be running."
$DumpDaemonLog=1
}
Write-Host
}
}
# Run the WCOW integration tests unless SKIP_INTEGRATION_TESTS is defined
if (($env:LCOW_MODE -eq $Null) -and ($env:LCOW_BASIC_MODE -eq $Null)) {
if ($env:SKIP_INTEGRATION_TESTS -eq $null) {
Write-Host -ForegroundColor Cyan "INFO: Running integration tests at $(Get-Date)..."
$ErrorActionPreference = "SilentlyContinue"
# Location of the daemon under test.
$env:OrigDOCKER_HOST="$env:DOCKER_HOST"
#https://blogs.technet.microsoft.com/heyscriptingguy/2011/09/20/solve-problems-with-external-command-lines-in-powershell/ is useful to see tokenising
$c = "go test "
$c += "`"-check.v`" "
if ($env:INTEGRATION_TEST_NAME -ne $null) { # Makes is quicker for debugging to be able to run only a subset of the integration tests
$c += "`"-check.f`" "
$c += "`"$env:INTEGRATION_TEST_NAME`" "
Write-Host -ForegroundColor Magenta "WARN: Only running integration tests matching $env:INTEGRATION_TEST_NAME"
}
$c += "`"-tags`" " + "`"autogen`" "
$c += "`"-check.timeout`" " + "`"10m`" "
$c += "`"-test.timeout`" " + "`"200m`" "
if ($env:INTEGRATION_IN_CONTAINER -ne $null) {
Write-Host -ForegroundColor Green "INFO: Integration tests being run inside a container"
# Note we talk back through the containers gateway address
# And the ridiculous lengths we have to go to to get the default gateway address... (GetNetIPConfiguration doesn't work in nanoserver)
# I just could not get the escaping to work in a single command, so output $c to a file and run that in the container instead...
# Not the prettiest, but it works.
$c | Out-File -Force "$env:TEMP\binary\runIntegrationCLI.ps1"
$Duration= $(Measure-Command { & docker run `
--rm `
-e c=$c `
--workdir "c`:\go\src\github.com\docker\docker\integration-cli" `
-v "$env:TEMP\binary`:c:\target" `
docker `
"`$env`:PATH`='c`:\target;'+`$env:PATH`; `$env:DOCKER_HOST`='tcp`://'+(ipconfig | select -last 1).Substring(39)+'`:2357'; c:\target\runIntegrationCLI.ps1" | Out-Host } )
} else {
Write-Host -ForegroundColor Green "INFO: Integration tests being run from the host:"
cd "$env:SOURCES_DRIVE`:\$env:SOURCES_SUBDIR\src\github.com\docker\docker\integration-cli"
$env:DOCKER_HOST=$DASHH_CUT
$env:PATH="$env:TEMP\binary;$env:PATH;" # Force to use the test binaries, not the host ones.
Write-Host -ForegroundColor Green "INFO: $c"
Write-Host -ForegroundColor Green "INFO: DOCKER_HOST at $DASHH_CUT"
# Explicit to not use measure-command otherwise don't get output as it goes
$start=(Get-Date); Invoke-Expression $c; $Duration=New-Timespan -Start $start -End (Get-Date)
}
$ErrorActionPreference = "Stop"
if (-not($LastExitCode -eq 0)) {
Throw "ERROR: Integration tests failed at $(Get-Date). Duration`:$Duration"
}
Write-Host -ForegroundColor Green "INFO: Integration tests ended at $(Get-Date). Duration`:$Duration"
} else {
Write-Host -ForegroundColor Magenta "WARN: Skipping integration tests"
}
} else {
# The LCOW version of the tests here
if ($env:SKIP_INTEGRATION_TESTS -eq $null) {
Write-Host -ForegroundColor Cyan "INFO: Running LCOW tests at $(Get-Date)..."
$ErrorActionPreference = "SilentlyContinue"
# Location of the daemon under test.
$env:OrigDOCKER_HOST="$env:DOCKER_HOST"
# Make sure we are pointing at the DUT
$env:DOCKER_HOST=$DASHH_CUT
Write-Host -ForegroundColor Green "INFO: DOCKER_HOST at $DASHH_CUT"
# Force to use the test binaries, not the host ones.
$env:PATH="$env:TEMP\binary;$env:PATH;"
if ($env:LCOW_BASIC_MODE -ne $null) {
$wc = New-Object net.webclient
try {
Write-Host -ForegroundColor green "INFO: Downloading latest execution script..."
$wc.Downloadfile("https://raw.githubusercontent.com/jhowardmsft/docker-w2wCIScripts/master/runCI/lcowbasicvalidation.ps1", "$env:TEMP\binary\lcowbasicvalidation.ps1")
}
catch [System.Net.WebException]
{
Throw ("Failed to download: $_")
}
# Explicit to not use measure-command otherwise don't get output as it goes
$ErrorActionPreference = "Stop"
$start=(Get-Date); Invoke-Expression "powershell $env:TEMP\binary\lcowbasicvalidation.ps1"; $lec=$lastExitCode; $Duration=New-Timespan -Start $start -End (Get-Date)
$Duration=New-Timespan -Start $start -End (Get-Date)
Write-Host -ForegroundColor Green "INFO: LCOW tests ended at $(Get-Date). Duration`:$Duration"
if ($lec -ne 0) {
Throw "LCOW validation tests failed"
}
} else {
#https://blogs.technet.microsoft.com/heyscriptingguy/2011/09/20/solve-problems-with-external-command-lines-in-powershell/ is useful to see tokenising
$c = "go test "
$c += "`"-check.v`" "
if ($env:INTEGRATION_TEST_NAME -ne $null) { # Makes is quicker for debugging to be able to run only a subset of the integration tests
$c += "`"-check.f`" "
$c += "`"$env:INTEGRATION_TEST_NAME`" "
Write-Host -ForegroundColor Magenta "WARN: Only running LCOW integration tests matching $env:INTEGRATION_TEST_NAME"
}
$c += "`"-tags`" " + "`"autogen`" "
$c += "`"-check.timeout`" " + "`"10m`" "
$c += "`"-test.timeout`" " + "`"200m`" "
Write-Host -ForegroundColor Green "INFO: LCOW Integration tests being run from the host:"
cd "$env:SOURCES_DRIVE`:\$env:SOURCES_SUBDIR\src\github.com\docker\docker\integration-cli"
Write-Host -ForegroundColor Green "INFO: $c"
Write-Host -ForegroundColor Green "INFO: DOCKER_HOST at $DASHH_CUT"
# Explicit to not use measure-command otherwise don't get output as it goes
$start=(Get-Date); Invoke-Expression $c; $Duration=New-Timespan -Start $start -End (Get-Date)
}
$ErrorActionPreference = "Stop"
if (-not($LastExitCode -eq 0)) {
Throw "ERROR: Integration tests failed at $(Get-Date). Duration`:$Duration"
}
Write-Host -ForegroundColor Green "INFO: Integration tests ended at $(Get-Date). Duration`:$Duration"
} else {
Write-Host -ForegroundColor Magenta "WARN: Skipping LCOW tests"
}
}
# Docker info now to get counts (after or if jjh/containercounts is merged)
if ($daemonStarted -eq 1) {
Write-Host -ForegroundColor Green "INFO: Docker info of the daemon under test at end of run"
Write-Host
$ErrorActionPreference = "SilentlyContinue"
& "$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" info
$ErrorActionPreference = "Stop"
if ($LastExitCode -ne 0) {
Throw "ERROR: The daemon under test does not appear to be running."
$DumpDaemonLog=1
}
Write-Host
}
# Stop the daemon under test
if (Test-Path "$env:TEMP\docker.pid") {
$p=Get-Content "$env:TEMP\docker.pid" -raw
if (($p -ne $null) -and ($daemonStarted -eq 1)) {
Write-Host -ForegroundColor green "INFO: Stopping daemon under test"
taskkill -f -t -pid $p
#sleep 5
}
Remove-Item "$env:TEMP\docker.pid" -force -ErrorAction SilentlyContinue
}
Write-Host -ForegroundColor Green "INFO: executeCI.ps1 Completed successfully at $(Get-Date)."
}
Catch [Exception] {
$FinallyColour="Red"
Write-Host -ForegroundColor Red ("`r`n`r`nERROR: Failed '$_' at $(Get-Date)")
Write-Host -ForegroundColor Red ($_.InvocationInfo.PositionMessage)
Write-Host "`n`n"
# Exit to ensure Jenkins captures it. Don't do this in the ISE or interactive Powershell - they will catch the Throw onwards.
if ( ([bool]([Environment]::GetCommandLineArgs() -Like '*-NonInteractive*')) -and `
([bool]([Environment]::GetCommandLineArgs() -NotLike "*Powershell_ISE.exe*"))) {
exit 1
}
Throw $_
}
Finally {
$ErrorActionPreference="SilentlyContinue"
$global:ProgressPreference=$origProgressPreference
Write-Host -ForegroundColor Green "INFO: Tidying up at end of run"
# Restore the path
if ($origPath -ne $null) { $env:PATH=$origPath }
# Restore the DOCKER_HOST
if ($origDOCKER_HOST -ne $null) { $env:DOCKER_HOST=$origDOCKER_HOST }
# Restore the GOROOT and GOPATH variables
if ($origGOROOT -ne $null) { $env:GOROOT=$origGOROOT }
if ($origGOPATH -ne $null) { $env:GOPATH=$origGOPATH }
# Dump the daemon log if asked to
if ($daemonStarted -eq 1) {
if ($dumpDaemonLog -eq 1) {
Write-Host -ForegroundColor Cyan "----------- DAEMON LOG ------------"
Get-Content "$env:TEMP\dut.err" -ErrorAction SilentlyContinue | Write-Host -ForegroundColor Cyan
Write-Host -ForegroundColor Cyan "----------- END DAEMON LOG --------"
}
}
# Save the daemon under test log
if ($daemonStarted -eq 1) {
Write-Host -ForegroundColor Green "INFO: Saving daemon under test log ($env:TEMP\dut.err) to $TEMPORIG\CIDUT.log"
Copy-Item "$env:TEMP\dut.err" "$TEMPORIG\CIDUT.log" -Force -ErrorAction SilentlyContinue
}
cd "$env:SOURCES_DRIVE\$env:SOURCES_SUBDIR" -ErrorAction SilentlyContinue
Nuke-Everything
$Dur=New-TimeSpan -Start $StartTime -End $(Get-Date)
Write-Host -ForegroundColor $FinallyColour "`nINFO: executeCI.ps1 exiting at $(date). Duration $dur`n"
}

View File

@@ -4,7 +4,7 @@
# containerd is also pinned in vendor.conf. When updating the binary
# version you may also need to update the vendor version to pick up bug
# fixes or new APIs.
CONTAINERD_COMMIT=468a545b9edcd5932818eb9de8e72413e616e86e # v1.1.2
CONTAINERD_COMMIT=9754871865f7fe2f4e74d43e2fc7ccd237edcbce # v1.2.2
install_containerd() {
echo "Install containerd version $CONTAINERD_COMMIT"
@@ -30,7 +30,7 @@ install_containerd() {
mkdir -p ${PREFIX}
cp bin/containerd ${PREFIX}/docker-containerd
cp bin/containerd-shim ${PREFIX}/docker-containerd-shim
cp bin/ctr ${PREFIX}/docker-containerd-ctr
cp bin/containerd ${PREFIX}/containerd
cp bin/containerd-shim ${PREFIX}/containerd-shim
cp bin/ctr ${PREFIX}/ctr
}

View File

@@ -3,7 +3,7 @@
# LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When
# updating the binary version, consider updating github.com/docker/libnetwork
# in vendor.conf accordingly
LIBNETWORK_COMMIT=f30a35b091cc2a431ef9856c75c343f75bb5f2e2
LIBNETWORK_COMMIT=2cfbf9b1f98162a55829a21cc603c76072a75382 # bump_18.09 branch
install_proxy() {
case "$1" in

View File

@@ -1,22 +1,45 @@
#!/bin/sh
# When updating RUNC_COMMIT, also update runc in vendor.conf accordingly
RUNC_COMMIT=69663f0bd4b60df09991c08812a60108003fa340
# The version of runc should match the version that is used by the containerd
# version that is used. If you need to update runc, open a pull request in
# the containerd project first, and update both after that is merged.
RUNC_COMMIT=96ec2177ae841256168fcf76954f7177af9446eb
RUNC_OVERRIDE_COMMIT=09c8266bf2fcf9519a651b04ae54c967b9ab86ec
RUNC_BUNDLE=/go/src/github.com/docker/docker/git-bundles/CVE-2019-5736.bundle
install_runc() {
# Do not build with ambient capabilities support
RUNC_BUILDTAGS="${RUNC_BUILDTAGS:-"seccomp apparmor selinux"}"
# If using RHEL7 kernels (3.10.0 el7), disable kmem accounting/limiting
if uname -r | grep -q '^3\.10\.0.*\.el7\.'; then
: ${RUNC_NOKMEM='nokmem'}
fi
echo "Install runc version $RUNC_COMMIT"
# Do not build with ambient capabilities support
RUNC_BUILDTAGS="${RUNC_BUILDTAGS:-"seccomp apparmor selinux $RUNC_NOKMEM"}"
echo "Install runc version $RUNC_COMMIT (build tags: $RUNC_BUILDTAGS)"
git clone https://github.com/opencontainers/runc.git "$GOPATH/src/github.com/opencontainers/runc"
cd "$GOPATH/src/github.com/opencontainers/runc"
git checkout -q "$RUNC_COMMIT"
if [ -f "$RUNC_BUNDLE" ];then
git bundle unbundle "$RUNC_BUNDLE"
git checkout -q "$RUNC_OVERRIDE_COMMIT"
if [ "$(git rev-parse HEAD)" != "$RUNC_OVERRIDE_COMMIT" ]; then
echo "ERROR: Commit with bundle does not match override commit"
echo " $(git rev-parse HEAD) != '$RUNC_OVERRIDE_COMMIT'"
exit 1
fi
RUNC_COMMIT=$RUNC_OVERRIDE_COMMIT
fi
if [ -z "$1" ]; then
target=static
else
target="$1"
fi
make BUILDTAGS="$RUNC_BUILDTAGS" "$target"
OVERRIDE_VERSION="1.0.0-rc6+dev.docker-18.09"
make BUILDTAGS="$RUNC_BUILDTAGS" COMMIT="$RUNC_COMMIT" VERSION="$OVERRIDE_VERSION" "$target"
mkdir -p ${PREFIX}
cp runc ${PREFIX}/docker-runc
cp runc ${PREFIX}/runc
}

View File

@@ -1,9 +1,9 @@
#!/usr/bin/env bash
DOCKER_DAEMON_BINARY_NAME='dockerd'
DOCKER_RUNC_BINARY_NAME='docker-runc'
DOCKER_CONTAINERD_BINARY_NAME='docker-containerd'
DOCKER_CONTAINERD_CTR_BINARY_NAME='docker-containerd-ctr'
DOCKER_CONTAINERD_SHIM_BINARY_NAME='docker-containerd-shim'
DOCKER_RUNC_BINARY_NAME='runc'
DOCKER_CONTAINERD_BINARY_NAME='containerd'
DOCKER_CONTAINERD_CTR_BINARY_NAME='ctr'
DOCKER_CONTAINERD_SHIM_BINARY_NAME='containerd-shim'
DOCKER_PROXY_BINARY_NAME='docker-proxy'
DOCKER_INIT_BINARY_NAME='docker-init'

View File

@@ -19,7 +19,6 @@ const (
Version string = "$VERSION"
BuildTime string = "$BUILDTIME"
IAmStatic string = "${IAMSTATIC:-true}"
ContainerdCommitID string = "${CONTAINERD_COMMIT}"
PlatformName string = "${PLATFORM}"
ProductName string = "${PRODUCT}"
DefaultProductLicense string = "${DEFAULT_PRODUCT_LICENSE}"
@@ -37,7 +36,6 @@ package dockerversion
// Default build-time variable for library-import.
// This file is overridden on build with build-time informations.
const (
RuncCommitID string = "${RUNC_COMMIT}"
InitCommitID string = "${TINI_COMMIT}"
)

View File

@@ -112,7 +112,7 @@ error_on_leaked_containerd_shims() {
fi
leftovers=$(ps -ax -o pid,cmd |
awk '$2 == "docker-containerd-shim" && $4 ~ /.*\/bundles\/.*\/test-integration/ { print $1 }')
awk '$2 == "containerd-shim" && $4 ~ /.*\/bundles\/.*\/test-integration/ { print $1 }')
if [ -n "$leftovers" ]; then
ps aux
kill -9 $leftovers 2> /dev/null

View File

@@ -10,14 +10,14 @@ copy_binaries() {
if [ "$(go env GOOS)/$(go env GOARCH)" != "$(go env GOHOSTOS)/$(go env GOHOSTARCH)" ]; then
return
fi
if [ ! -x /usr/local/bin/docker-runc ]; then
if [ ! -x /usr/local/bin/runc ]; then
return
fi
echo "Copying nested executables into $dir"
for file in containerd containerd-shim containerd-ctr runc init proxy; do
cp -f `which "docker-$file"` "$dir/"
for file in containerd containerd-shim ctr runc docker-init docker-proxy; do
cp -f `which "$file"` "$dir/"
if [ "$hash" == "hash" ]; then
hash_files "$dir/docker-$file"
hash_files "$dir/$file"
fi
done
}

View File

@@ -32,7 +32,7 @@ const (
privateRegistryURL = registry.DefaultURL
// path to containerd's ctr binary
ctrBinary = "docker-containerd-ctr"
ctrBinary = "ctr"
// the docker daemon binary to use
dockerdBinary = "dockerd"

View File

@@ -1759,7 +1759,7 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *check.C) {
Target: destPath}}},
msg: "source path does not exist",
// FIXME(vdemeester) fails into e2e, migrate to integration/container anyway
// msg: "bind mount source path does not exist: " + notExistPath,
// msg: "source path does not exist: " + notExistPath,
},
{
config: containertypes.Config{

View File

@@ -44,6 +44,8 @@ import (
"gotest.tools/icmd"
)
const containerdSocket = "/var/run/docker/containerd/containerd.sock"
// TestLegacyDaemonCommand test starting docker daemon using "deprecated" docker daemon
// command. Remove this test when we remove this.
func (s *DockerDaemonSuite) TestLegacyDaemonCommand(c *check.C) {
@@ -1449,7 +1451,7 @@ func (s *DockerDaemonSuite) TestCleanupMountsAfterDaemonAndContainerKill(c *chec
c.Assert(d.Kill(), check.IsNil)
// kill the container
icmd.RunCommand(ctrBinary, "--address", "/var/run/docker/containerd/docker-containerd.sock",
icmd.RunCommand(ctrBinary, "--address", containerdSocket,
"--namespace", moby_daemon.ContainersNamespace, "tasks", "kill", id).Assert(c, icmd.Success)
// restart daemon.
@@ -1971,7 +1973,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithKilledRunningContainer(t *check
}
// kill the container
icmd.RunCommand(ctrBinary, "--address", "/var/run/docker/containerd/docker-containerd.sock",
icmd.RunCommand(ctrBinary, "--address", containerdSocket,
"--namespace", moby_daemon.ContainersNamespace, "tasks", "kill", cid).Assert(t, icmd.Success)
// Give time to containerd to process the command if we don't
@@ -2074,7 +2076,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithUnpausedRunningContainer(t *che
// resume the container
result := icmd.RunCommand(
ctrBinary,
"--address", "/var/run/docker/containerd/docker-containerd.sock",
"--address", containerdSocket,
"--namespace", moby_daemon.ContainersNamespace,
"tasks", "resume", cid)
result.Assert(t, icmd.Success)
@@ -2409,7 +2411,7 @@ func (s *DockerDaemonSuite) TestRunWithRuntimeFromConfigFile(c *check.C) {
{
"runtimes": {
"oci": {
"path": "docker-runc"
"path": "runc"
},
"vm": {
"path": "/usr/local/bin/vm-manager",
@@ -2491,7 +2493,7 @@ func (s *DockerDaemonSuite) TestRunWithRuntimeFromConfigFile(c *check.C) {
"default-runtime": "vm",
"runtimes": {
"oci": {
"path": "docker-runc"
"path": "runc"
},
"vm": {
"path": "/usr/local/bin/vm-manager",
@@ -2517,7 +2519,7 @@ func (s *DockerDaemonSuite) TestRunWithRuntimeFromConfigFile(c *check.C) {
}
func (s *DockerDaemonSuite) TestRunWithRuntimeFromCommandLine(c *check.C) {
s.d.StartWithBusybox(c, "--add-runtime", "oci=docker-runc", "--add-runtime", "vm=/usr/local/bin/vm-manager")
s.d.StartWithBusybox(c, "--add-runtime", "oci=runc", "--add-runtime", "vm=/usr/local/bin/vm-manager")
// Run with default runtime
out, err := s.d.Cmd("run", "--rm", "busybox", "ls")
@@ -2564,7 +2566,7 @@ func (s *DockerDaemonSuite) TestRunWithRuntimeFromCommandLine(c *check.C) {
// Check that we can select a default runtime
s.d.Stop(c)
s.d.StartWithBusybox(c, "--default-runtime=vm", "--add-runtime", "oci=docker-runc", "--add-runtime", "vm=/usr/local/bin/vm-manager")
s.d.StartWithBusybox(c, "--default-runtime=vm", "--add-runtime", "oci=runc", "--add-runtime", "vm=/usr/local/bin/vm-manager")
out, err = s.d.Cmd("run", "--rm", "busybox", "ls")
c.Assert(err, check.NotNil, check.Commentf("%s", out))

View File

@@ -7,7 +7,9 @@ import (
"strings"
"testing"
"github.com/docker/docker/api/types"
dclient "github.com/docker/docker/client"
"github.com/docker/docker/internal/test/daemon"
"github.com/docker/docker/internal/test/fakecontext"
"github.com/docker/docker/internal/test/request"
"github.com/moby/buildkit/session"
@@ -19,7 +21,11 @@ import (
)
func TestBuildWithSession(t *testing.T) {
skip.If(t, !testEnv.DaemonInfo.ExperimentalBuild)
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
d := daemon.New(t, daemon.WithExperimental)
d.StartWithBusybox(t)
defer d.Stop(t)
client := testEnv.APIClient()
@@ -76,7 +82,7 @@ func TestBuildWithSession(t *testing.T) {
assert.Check(t, is.Contains(string(outBytes), "Successfully built"))
assert.Check(t, is.Equal(strings.Count(string(outBytes), "Using cache"), 4))
_, err = client.BuildCachePrune(context.TODO())
_, err = client.BuildCachePrune(context.TODO(), types.BuildCachePruneOptions{All: true})
assert.Check(t, err)
du, err = client.DiskUsage(context.TODO())

View File

@@ -10,6 +10,7 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/integration/internal/container"
"github.com/docker/docker/internal/test/daemon"
"github.com/docker/docker/internal/test/fakecontext"
"github.com/docker/docker/pkg/stdcopy"
"gotest.tools/assert"
@@ -18,7 +19,12 @@ import (
)
func TestBuildSquashParent(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
skip.If(t, !testEnv.DaemonInfo.ExperimentalBuild)
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
d := daemon.New(t, daemon.WithExperimental)
d.StartWithBusybox(t)
defer d.Stop(t)
client := testEnv.APIClient()

View File

@@ -9,6 +9,7 @@ import (
"io/ioutil"
"strings"
"testing"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
@@ -22,6 +23,7 @@ import (
)
func TestBuildWithRemoveAndForceRemove(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "FIXME")
defer setupTest(t)()
t.Parallel()
cases := []struct {
@@ -137,6 +139,7 @@ func buildContainerIdsFilter(buildOutput io.Reader) (filters.Args, error) {
func TestBuildMultiStageParentConfig(t *testing.T) {
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.35"), "broken in earlier versions")
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "FIXME")
dockerfile := `
FROM busybox AS stage0
ENV WHO=parent
@@ -166,16 +169,27 @@ func TestBuildMultiStageParentConfig(t *testing.T) {
resp.Body.Close()
assert.NilError(t, err)
time.Sleep(30 * time.Second)
imgs, err := apiclient.ImageList(ctx, types.ImageListOptions{})
assert.NilError(t, err)
t.Log(imgs)
image, _, err := apiclient.ImageInspectWithRaw(ctx, "build1")
assert.NilError(t, err)
assert.Check(t, is.Equal("/foo/sub2", image.Config.WorkingDir))
expected := "/foo/sub2"
if testEnv.DaemonInfo.OSType == "windows" {
expected = `C:\foo\sub2`
}
assert.Check(t, is.Equal(expected, image.Config.WorkingDir))
assert.Check(t, is.Contains(image.Config.Env, "WHO=parent"))
}
// Test cases in #36996
func TestBuildLabelWithTargets(t *testing.T) {
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.38"), "test added after 1.38")
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "FIXME")
bldName := "build-a"
testLabels := map[string]string{
"foo": "bar",
@@ -282,6 +296,7 @@ func TestBuildWithEmptyLayers(t *testing.T) {
// #35652
func TestBuildMultiStageOnBuild(t *testing.T) {
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.33"), "broken in earlier versions")
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "FIXME")
defer setupTest(t)()
// test both metadata and layer based commands as they may be implemented differently
dockerfile := `FROM busybox AS stage1
@@ -289,7 +304,8 @@ ONBUILD RUN echo 'foo' >somefile
ONBUILD ENV bar=baz
FROM stage1
RUN cat somefile # fails if ONBUILD RUN fails
# fails if ONBUILD RUN fails
RUN cat somefile
FROM stage1
RUN cat somefile`
@@ -327,6 +343,8 @@ RUN cat somefile`
// #35403 #36122
func TestBuildUncleanTarFilenames(t *testing.T) {
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.37"), "broken in earlier versions")
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "FIXME")
ctx := context.TODO()
defer setupTest(t)()
@@ -385,6 +403,7 @@ COPY bar /`
// docker/for-linux#135
// #35641
func TestBuildMultiStageLayerLeak(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "FIXME")
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.37"), "broken in earlier versions")
ctx := context.TODO()
defer setupTest(t)()
@@ -423,6 +442,39 @@ RUN [ ! -f foo ]
assert.Check(t, is.Contains(out.String(), "Successfully built"))
}
// #37581
func TestBuildWithHugeFile(t *testing.T) {
skip.If(t, testEnv.OSType == "windows")
ctx := context.TODO()
defer setupTest(t)()
dockerfile := `FROM busybox
# create a sparse file with size over 8GB
RUN for g in $(seq 0 8); do dd if=/dev/urandom of=rnd bs=1K count=1 seek=$((1024*1024*g)) status=none; done && \
ls -la rnd && du -sk rnd`
buf := bytes.NewBuffer(nil)
w := tar.NewWriter(buf)
writeTarRecord(t, w, "Dockerfile", dockerfile)
err := w.Close()
assert.NilError(t, err)
apiclient := testEnv.APIClient()
resp, err := apiclient.ImageBuild(ctx,
buf,
types.ImageBuildOptions{
Remove: true,
ForceRemove: true,
})
out := bytes.NewBuffer(nil)
assert.NilError(t, err)
_, err = io.Copy(out, resp.Body)
resp.Body.Close()
assert.NilError(t, err)
assert.Check(t, is.Contains(out.String(), "Successfully built"))
}
func writeTarRecord(t *testing.T, w *tar.Writer, fn, contents string) {
err := w.WriteHeader(&tar.Header{
Name: fn,

View File

@@ -20,7 +20,7 @@ import (
)
func TestConfigList(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
defer setupTest(t)()
d := swarm.NewSwarm(t, testEnv)
@@ -102,7 +102,7 @@ func createConfig(ctx context.Context, t *testing.T, client client.APIClient, na
}
func TestConfigsCreateAndDelete(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
defer setupTest(t)()
d := swarm.NewSwarm(t, testEnv)
@@ -130,7 +130,7 @@ func TestConfigsCreateAndDelete(t *testing.T) {
}
func TestConfigsUpdate(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
defer setupTest(t)()
d := swarm.NewSwarm(t, testEnv)
@@ -184,6 +184,7 @@ func TestConfigsUpdate(t *testing.T) {
}
func TestTemplatedConfig(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
d := swarm.NewSwarm(t, testEnv)
defer d.Stop(t)
client := d.NewClientT(t)
@@ -323,7 +324,7 @@ func waitAndAssert(t *testing.T, timeout time.Duration, f func(*testing.T) bool)
}
func TestConfigInspect(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
defer setupTest(t)()
d := swarm.NewSwarm(t, testEnv)

View File

@@ -0,0 +1,42 @@
package container // import "github.com/docker/docker/integration/container"
import (
"net/http"
"testing"
"github.com/docker/docker/internal/test/request"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
func TestContainerInvalidJSON(t *testing.T) {
defer setupTest(t)()
endpoints := []string{
"/containers/foobar/copy",
"/containers/foobar/exec",
"/exec/foobar/start",
}
for _, ep := range endpoints {
t.Run(ep, func(t *testing.T) {
t.Parallel()
res, body, err := request.Post(ep, request.RawString("{invalid json"), request.JSON)
assert.NilError(t, err)
assert.Equal(t, res.StatusCode, http.StatusBadRequest)
buf, err := request.ReadBody(body)
assert.NilError(t, err)
assert.Check(t, is.Contains(string(buf), "invalid character 'i' looking for beginning of object key string"))
res, body, err = request.Post(ep, request.JSON)
assert.NilError(t, err)
assert.Equal(t, res.StatusCode, http.StatusBadRequest)
buf, err = request.ReadBody(body)
assert.NilError(t, err)
assert.Check(t, is.Contains(string(buf), "got EOF while reading request body"))
})
}
}

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