Compare commits

...

60 Commits

Author SHA1 Message Date
Paweł Gronowski
3b01d641ef Merge pull request #51860 from vvoland/51857-docker-29.x
[docker-29.x backport] update to go1.25.6
2026-01-16 12:21:20 +00:00
Paweł Gronowski
480df69696 update to go1.25.6
This releases includes 6 security fixes following the security policy:

- archive/zip: denial of service when parsing arbitrary ZIP archives

    archive/zip used a super-linear file name indexing algorithm that is invoked the first time a file in an archive is opened. This can lead to a denial of service when consuming a maliciously constructed ZIP archive.

    Thanks to Thanks to Jakub Ciolek for reporting this issue.

    This is CVE-2025-61728 and Go issue https://go.dev/issue/77102.

- net/http: memory exhaustion in Request.ParseForm

    When parsing a URL-encoded form net/http may allocate an unexpected amount of
    memory when provided a large number of key-value pairs. This can result in a
    denial of service due to memory exhaustion.

    Thanks to jub0bs for reporting this issue.

    This is CVE-2025-61726 and Go issue https://go.dev/issue/77101.

- crypto/tls: Config.Clone copies automatically generated session ticket keys, session resumption does not account for the expiration of full certificate chain

    The Config.Clone methods allows cloning a Config which has already been passed
    to a TLS function, allowing it to be mutated and reused.

    If Config.SessionTicketKey has not been set, and Config.SetSessionTicketKeys has
    not been called, crypto/tls will generate random session ticket keys and
    automatically rotate them. Config.Clone would copy these automatically generated
    keys into the returned Config, meaning that the two Configs would share session
    ticket keys, allowing sessions created using one Config could be used to resume
    sessions with the other Config. This can allow clients to resume sessions even
    though the Config may be configured such that they should not be able to do so.

    Config.Clone no longer copies the automatically generated session ticket keys.
    Config.Clone still copies keys which are explicitly provided, either by setting
    Config.SessionTicketKey or by calling Config.SetSessionTicketKeys.

    This issue was discoverd by the Go Security team while investigating another
    issue reported by Coia Prant (github.com/rbqvq).

    Additionally, on the server side only the expiration of the leaf certificate, if
    one was provided during the initial handshake, was checked when considering if a
    session could be resumed. This allowed sessions to be resumed if an intermediate
    or root certificate in the chain had expired.

    Session resumption now takes into account of the full chain when determining if
    the session can be resumed.

    Thanks to Coia Prant (github.com/rbqvq) for reporting this issue.

    This is CVE-2025-68121 and Go issue https://go.dev/issue/77113.

- cmd/go: bypass of flag sanitization can lead to arbitrary code execution

    Usage of 'CgoPkgConfig' allowed execution of the pkg-config
    binary with flags that are not explicitly safe-listed.

    To prevent this behavior, compiler flags resulting from usage
    of 'CgoPkgConfig' are sanitized prior to invoking pkg-config.

    Thank you to RyotaK (https://ryotak.net) of GMO Flatt Security Inc.
    for reporting this issue.

    This is CVE-2025-61731 and go.dev/issue/77100.

- cmd/go: unexpected code execution when invoking toolchain

    The Go toolchain supports multiple VCS which are used retrieving modules and
    embedding build information into binaries.

    On systems with Mercurial installed (hg) downloading modules (e.g. via go get or
    go mod download) from non-standard sources (e.g. custom domains) can cause
    unexpected code execution due to how external VCS commands are constructed.

    On systems with Git installed, downloading and building modules with malicious
    version strings could allow an attacker to write to arbitrary files on the
    system the user has access to. This can only be triggered by explicitly
    providing the malicious version strings to the toolchain, and does not affect
    usage of @latest or bare module paths.

    The toolchain now uses safer VCS options to prevent misinterpretation of
    untrusted inputs. In addition, the toolchain now disallows module version
    strings prefixed with a "-" or "/" character.

    Thanks to splitline (@splitline) from DEVCORE Research Team for reporting this
    issue.

    This is CVE-2025-68119 and Go issue https://go.dev/issue/77099.

- crypto/tls: handshake messages may be processed at the incorrect encryption level

    During the TLS 1.3 handshake if multiple messages are sent in records that span
    encryption level boundaries (for instance the Client Hello and Encrypted
    Extensions messages), the subsequent messages may be processed before the
    encryption level changes. This can cause some minor information disclosure if a
    network-local attacker can inject messages during the handshake.

    Thanks to Coia Prant (github.com/rbqvq) for reporting this issue.

    This is CVE-2025-61730 and Go issue https://go.dev/issue/76443

View the release notes for more information:
https://go.dev/doc/devel/release#go1.25.6

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit cebb12ddaf)
2026-01-16 11:56:42 +01:00
Paweł Gronowski
dd6a3633ee Merge pull request #51859 from vvoland/51723-docker-29.x
[docker-29.x backport] ci: Remove concurrency setting from golangci-lint config
2026-01-16 10:55:01 +00:00
Paweł Gronowski
ff5e19865b ci: Remove concurrency setting from golangci-lint config
Remove the hardcoded concurrency limit of 2 from the golangci-lint
configuration to allow the linter to match the machine CPU's core count.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 37fdb6d775)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-01-16 11:38:35 +01:00
Sebastiaan van Stijn
d05a725121 Merge pull request #51843 from corhere/backport-29.x/fix-service-binding-soft-disable
[docker-29.x backport] libnetwork: fix graceful service endpoint removal
2026-01-14 23:46:09 +01:00
Cory Snider
01fc4fcf8b libnetwork: fix graceful service endpoint removal
When a container is stopped, new connections to a published port will
not be routed to that container but any existing connections are
permitted to continue uninterrupted for the duration of the container's
grace period. Unfortunately recent fixes to overlay networks introduced
a regression: existing connections routed over the service mesh to
containers on remote nodes are dropped immediately when the container is
stopped, irrespective of the grace period.

Fix the handling of NetworkDB endpoint table events so that the endpoint
is disabled in the load balancer when a service endpoint transitions to
ServiceDisabled instead of deleting the endpoint and re-adding it. And
fix the other bugged state transitions with the help of a unit test
which exhaustively covers all permutations of endpoint event.

Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit 9ec65542a0)
Signed-off-by: Cory Snider <csnider@mirantis.com>
2026-01-13 18:56:23 -05:00
Paweł Gronowski
08440b6ee8 Merge pull request #51830 from thaJeztah/29.x_backport_windows-network-none
[docker-29.x backport] daemon/libnetwork: Fix panic in findHNSEp when IP networks are nil
2026-01-08 16:57:22 +00:00
Paweł Gronowski
b0e62060b0 Merge pull request #51829 from thaJeztah/29.x_backport_fix-image-mount
[docker-29.x backport] daemon/volumes: More fs friendly image mount layer names
2026-01-08 16:57:12 +00:00
Sebastiaan van Stijn
515dbc8c71 Merge pull request #51826 from thaJeztah/29.x_backport_45939-init-layer-cleanup
[docker-29.x backport] layer: Clean up init layer if initialization fails
2026-01-08 17:24:06 +01:00
Sebastiaan van Stijn
adf3073cb6 Merge pull request #51825 from thaJeztah/29.x_backport_archive_rm_deprecated
[docker-29.x backport] remove uses of deprecated go-archive consts
2026-01-08 17:23:43 +01:00
Sebastiaan van Stijn
8b2c317218 Merge pull request #51824 from thaJeztah/29.x_backport_45939-rw-layer-cleanup
[docker-29.x backport] layer: Clean up RW layer if mount metadata save fails
2026-01-08 17:23:09 +01:00
Paweł Gronowski
3eca177282 daemon/libnetwork: Fix panic in findHNSEp when IP networks are nil
Can happen for `docker run --network none ...`

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit fadd8dc47c)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-08 16:59:22 +01:00
Paweł Gronowski
c4f4c6765e daemon/volumes: More fs friendly image mount layer names
Hash the container ID, mount source and destination together to form a
layer name.

This ensures the generated names are filesystem-friendly and don't
exceed path length limits while maintaining uniqueness across different
mount points and containers.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit cb88c6ba10)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-08 16:56:18 +01:00
Sebastiaan van Stijn
f942bce11a Merge pull request #51821 from vvoland/51740-docker-29.x
[docker-29.x backport] vendor: github.com/moby/buildkit v0.26.3
2026-01-08 16:41:14 +01:00
Paweł Gronowski
a1f7fff7a9 daemon/layer_store: Use named return error for defer
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 26bb1af7e6)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-08 11:00:00 +01:00
Jan Scheffler
0e600c7fc4 layer: Clean up init layer if initialization fails
Add cleanup for the init layer directory if any operation fails after
driver.CreateReadWrite() succeeds in initMount(). Previously, failures
in driver.Get(), initFunc(), or driver.Put() would leave an orphaned
overlay2 directory.

Related to moby/moby#45939

Signed-off-by: Jan Scheffler <jan.scheffler@qodev.ai>
(cherry picked from commit 3fdde529e7)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-08 11:00:00 +01:00
Sebastiaan van Stijn
734bb626e4 remove uses of deprecated go-archive consts
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 7239c72eca)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-08 10:54:50 +01:00
Jan Scheffler
5eaae6db52 layer: Clean up RW layer if mount metadata save fails
Add cleanup for the RW layer directory if saveMount() fails after
driver.CreateReadWrite() succeeds. Previously, this failure path would
leave an orphaned overlay2 directory with no corresponding metadata.

Related to moby/moby#45939

Signed-off-by: Jan Scheffler <jan.scheffler@qodev.ai>
(cherry picked from commit d7a6250b91)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-08 10:49:11 +01:00
Jonathan A. Sternberg
8ebb104e36 vendor: github.com/moby/buildkit v0.26.3
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
(cherry picked from commit c63bf203bf)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-01-07 16:44:38 +01:00
Paweł Gronowski
fbf3ed25f8 Merge pull request #51703 from vvoland/51700-docker-29.x
[docker-29.x backport] layer: Fix orphan creation in registerWithDescriptor
2025-12-12 13:08:08 +00:00
Jan Scheffler
518779c90b layer: Fix orphan creation in registerWithDescriptor
Start the metadata transaction before creating the overlay2 directory.
This ensures that if driver.Create() fails, we can properly cancel the
transaction. Previously, if StartTransaction() failed after driver.Create()
succeeded, the defer cleanup would not run (not registered yet), leaving
an orphaned overlay2 directory.

The fix reorders operations so that:
1. Transaction is started first (no filesystem changes yet)
2. Overlay2 directory is created second (transaction ready for cleanup)
3. Defer is registered after both succeed (tx is guaranteed non-nil)

If driver.Create() fails, the transaction is explicitly cancelled before
returning. The nil check for tx in the defer is no longer needed since
tx is guaranteed to exist when the defer runs.

Related to moby/moby#45939

Signed-off-by: Jan Scheffler <jan.scheffler@qodev.ai>
(cherry picked from commit 70004549fb)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-12-12 12:45:16 +01:00
Sebastiaan van Stijn
ecf8643fe1 Merge pull request #51699 from vvoland/51697-docker-29.x
[docker-29.x backport] vendor: github.com/containernetworking/plugins v1.9.0
2025-12-12 11:38:17 +01:00
Sebastiaan van Stijn
5a99e1d1a4 vendor: github.com/containernetworking/plugins v1.9.0
no changes in vendored code

includes a fix for CVE-2025-67499

full diff: https://github.com/containernetworking/plugins/compare/v1.8.0...v1.9.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 24bac4495e)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-12-12 10:39:19 +01:00
Sebastiaan van Stijn
bae170eeb7 Merge pull request #51695 from vvoland/51684-docker-29.x
[docker-29.x backport] daemon: disallow container port 0
2025-12-11 23:11:07 +01:00
Sebastiaan van Stijn
8f33623c5d Merge pull request #51691 from vvoland/51683-docker-29.x
[docker-29.x backport] daemon: buildCreateEndpointOptions: fix panic with "publish all"
2025-12-11 23:10:00 +01:00
Paweł Gronowski
bdc1e7b0fe Merge pull request #51693 from vvoland/51692-docker-29.x
[docker-29.x backport] daemon: clean up dead containers on start
2025-12-11 20:50:59 +00:00
Albin Kerouanton
298e2f7d52 daemon: disallow container port 0
Signed-off-by: Albin Kerouanton <albin.kerouanton@docker.com>
(cherry picked from commit 43780fe40c)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-12-11 21:42:30 +01:00
Albin Kerouanton
3376758770 daemon: clean up dead containers on start
Stopping the Engine while a container with autoremove set is running may
leave behind dead containers on disk. These containers aren't reclaimed
on next start, appear as "dead" in `docker ps -a` and can't be
inspected or removed by the user.

This bug has existed since a long time but became user visible with
9f5f4f5a42. Prior to that commit,
containers with no rwlayer weren't added to the in-memory viewdb, so
they weren't visible in `docker ps -a`. However, some dangling files
would still live on disk (e.g. folder in /var/lib/docker/containers,
mount points, etc).

The underlying issue is that when the daemon stops, it tries to stop all
running containers and then closes the containerd client. This leaves a
small window of time where the Engine might receive 'task stop' events
from containerd, and trigger autoremove. If the containerd client is
closed in parallel, the Engine is unable to complete the removal,
leaving the container in 'dead' state. In such case, the Engine logs the
following error:

    cannot remove container "bcbc98b4f5c2b072eb3c4ca673fa1c222d2a8af00bf58eae0f37085b9724ea46": Canceled: grpc: the client connection is closing: context canceled

Solving the underlying issue would require complex changes to the
shutdown sequence. Moreover, the same issue could also happen if the
daemon crashes while it deletes a container. Thus, add a cleanup step
on daemon startup to remove these dead containers.

Signed-off-by: Albin Kerouanton <albin.kerouanton@docker.com>
(cherry picked from commit ec9315cd4f)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-12-11 20:55:04 +01:00
Sebastiaan van Stijn
bb2e099c3a daemon/container: Container.BackfillEmptyPBs: prevent nil map
Make sure PortBindings is not a nil-map to match the behavior
we have when creating a container;
c64b781df2/daemon/internal/runconfig/config.go (L30-L47)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 2a191665b8)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-12-11 16:40:38 +01:00
Sebastiaan van Stijn
5898ee60f4 daemon: buildCreateEndpointOptions: fix panic with "publish all"
This code was added in 85b260fba8, but didn't
account for maps.Clone returning a `nil` map if the map cloned was `nil`.

This could lead to a panic, similar to the panic that was fixed in
7517464283d29969c4d3615397b369abd99ce395;

    panic: assignment to entry in nil map

    goroutine 498 [running]:

    github.com/moby/moby/v2/daemon.buildPortsRelatedCreateEndpointOptions(0x400042f348, 0xaaaabcc8f458?, 0x40006feb40)
        /root/build-deb/engine/daemon/network.go:1047 +0x844
    github.com/moby/moby/v2/daemon.buildCreateEndpointOptions(0x400042f348, 0x4001015040, 0x400027d320, 0x40006feb40, {0x0, 0x0, 0x4001506cb8?})
        /root/build-deb/engine/daemon/network.go:988 +0x20c
    github.com/moby/moby/v2/daemon.(*Daemon).connectToNetwork(0x4000898008, {0xaaaabe21d9f8, 0x4000f12b10}, 0x400089a008, 0x400042f348, {0x400077a9f0, 0x6}, 0x400027d320)
        /root/build-deb/engine/daemon/container_operations.go:738 +0x66c
    github.com/moby/moby/v2/daemon.(*Daemon).allocateNetwork(0x4000898008, {0xaaaabe21d9f8, 0x4000f12b10}, 0x400089a008, 0x400042f348)
        /root/build-deb/engine/daemon/container_operations.go:421 +0x298
    github.com/moby/moby/v2/daemon.(*Daemon).initializeCreatedTask(0x4000898008, {0xaaaabe21d9f8, 0x4000f12b10}, 0x400089a008, {0xaaaabe23dc60, 0x4000eb21c8}, 0x400042f348, 0xaaaabd4db3df?)
        /root/build-deb/engine/daemon/start_linux.go:37 +0x260
    github.com/moby/moby/v2/daemon.(*Daemon).containerStart(0x4000898008, {0xaaaabe21d9c0, 0xaaaabfa05300}, 0x400089a008, 0x400042f348, {0x0, 0x0}, {0x0, 0x0}, 0x1)
        /root/build-deb/engine/daemon/start.go:242 +0xba8
    github.com/moby/moby/v2/daemon.(*Daemon).restore.func4(0x400042f348, 0x400117f1f0)
        /root/build-deb/engine/daemon/daemon.go:633 +0x308
    created by github.com/moby/moby/v2/daemon.(*Daemon).restore in goroutine 1
        /root/build-deb/engine/daemon/daemon.go:607 +0x5ec

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 695010ba2e)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-12-11 16:40:38 +01:00
Paweł Gronowski
05a5be917d Merge pull request #51689 from vvoland/51688-docker-29.x
[docker-29.x backport] gha: Fix PR branch validation
2025-12-11 15:39:25 +00:00
Paweł Gronowski
ab55325b58 gha: Fix PR branch validation
Make it work with `docker-XYZ` branches.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit c74203adbb)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-12-11 16:35:09 +01:00
Paweł Gronowski
5c69198edd Merge pull request #51685 from vvoland/sync-29.x
[docker-29.x] Move to `29.1`
2025-12-11 15:25:58 +00:00
Paweł Gronowski
cbaccdaf6d Merge tag 'docker-v29.1.2' into docker-29.x
v29.1.2
2025-12-11 13:38:34 +01:00
Paweł Gronowski
09d5128bff Merge tag 'docker-v29.1.1' into docker-29.x
v29.1.1
2025-12-11 13:38:32 +01:00
Paweł Gronowski
b54adb2d03 Merge tag 'docker-v29.1.0' into docker-29.x
v29.1.0

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-12-11 13:37:59 +01:00
Paweł Gronowski
4612690e23 Merge pull request #51583 from vvoland/51577-docker-29.x
[docker-29.x backport] Allow configured address with no configured subnet
2025-11-24 18:44:28 +00:00
Rob Murray
6280a80f32 Allow configured address with no configured subnet
Signed-off-by: Rob Murray <rob.murray@docker.com>
(cherry picked from commit 84a251d039)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-11-24 17:33:10 +01:00
Rob Murray
9cbafeac46 Update docker-py in test-docker-py
Pick up fixes for:
- test_create_with_ipv6_address
- test_connect_with_ipv6_address

65f7f0c..df3f8e2

Signed-off-by: Rob Murray <rob.murray@docker.com>
(cherry picked from commit 7e14b4d931)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-11-24 17:33:07 +01:00
Sebastiaan van Stijn
1fa8a31556 Merge pull request #51558 from robmry/backport-29.x-replace_lock_in_remote_nw_driver
[docker-29.x backport] Restore missing nwEndpointsMu.Lock
2025-11-19 16:37:22 +00:00
Rob Murray
3c6e5f0f5a Restore missing nwEndpointsMu.Lock
- introduced by 4f7afb8 (Remove libnet's logic to track a driver's
  port mapping state)

Signed-off-by: Rob Murray <rob.murray@docker.com>
(cherry picked from commit ed10b98506)
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-11-18 16:02:30 +00:00
Sebastiaan van Stijn
e9ff10bf36 Merge pull request #51538 from thaJeztah/29.x_backport_dont-remove-removed-gateway
[docker-29.x backport] Don't try to remove cleared docker_gwbridge endpoint
2025-11-16 17:26:01 +01:00
Rob Murray
7faaa44e18 Don't try to remove cleared docker_gwbridge endpoint
If a container is using a docker_gwbridge endpoint as its gateway,
when it's connected to another network that provides a gateway, the
docker_gwbridge endpoint is removed when that endpoint is added (in
a recursive nightmare).

So, the "before" gateway for the container has been removed
before the new gateway is updateExternalConnectivity'd.

Don't pass the old gateway to updateExternalConnectivity in that
case, because the network driver's already forgotten about it.

Signed-off-by: Rob Murray <rob.murray@docker.com>
(cherry picked from commit 1731e9e729)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-11-16 15:16:49 +01:00
Rob Murray
e9f9d7a81e Merge pull request #51545 from thaJeztah/29.x_backport_skip_TestBuildWithHugeFile
[docker-29.x backport] integration: skip TestBuildWithHugeFile
2025-11-16 14:14:51 +00:00
Sebastiaan van Stijn
28665176e5 Merge pull request #51543 from robmry/backport-29.x/rootless-noipv6
[docker-29.x backport] rootless: ignore error when enabling IPv6 forwarding
2025-11-16 14:21:56 +01:00
Sebastiaan van Stijn
43f91f775a integration: skip TestBuildWithHugeFile
We've seen various failures recently where GitHub actions runners are
running out of space. Skip this test for now.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 3e4a3cb03e)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-11-16 14:18:27 +01:00
Rob Murray
bb0d79cb1a rootless: ignore error when enabling IPv6 forwarding
For hosts with IPv6 disabled.

Signed-off-by: Rob Murray <rob.murray@docker.com>
(cherry picked from commit 5c9f2e0388)
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-11-16 11:59:07 +00:00
Paweł Gronowski
198b5e3ed5 Merge pull request #51528 from akerouanton/backport-revendor-ishidawataru-sctp
[docker-29.x backport] Backport revendor ishidawataru sctp
2025-11-14 16:23:22 +01:00
Albin Kerouanton
2ad480ccf5 vendor: github.com/ishidawataru/sctp v0.0.0-20251114114122-1
full diff: 4b890084db..19ddcbc6aa

Signed-off-by: Albin Kerouanton <albin.kerouanton@docker.com>
2025-11-14 16:08:51 +01:00
Paweł Gronowski
cb6c1c3aca Merge pull request #51516 from vvoland/51492-docker-29.x
[docker-29.x backport] daemon: Fix image store choice priority for prior graphdriver state
2025-11-14 09:25:54 +01:00
Paweł Gronowski
2a18530fb2 Merge pull request #51513 from vvoland/51503-docker-29.x
[docker-29.x backport] hack/test/unit: Fix api and client module testing without replace rules
2025-11-14 09:25:21 +01:00
Paweł Gronowski
14c4e0d73a Merge pull request #51514 from vvoland/51493-docker-29.x
[docker-29.x backport] c8d/builder-next: Don't force unpack
2025-11-14 09:25:01 +01:00
Rob Murray
d23fd38f8b Merge pull request #51515 from vvoland/51495-docker-29.x
[docker-29.x backport] libnet: create DNS records on sbJoin (if not agent node)
2025-11-13 22:35:23 +00:00
Paweł Gronowski
3076530aa6 daemon: Fix image store choice priority for prior graphdriver state
The priority order for determining image store choice was incorrect when
a prior graphdriver existed.

The issue occurred because the prior graphdriver check happened after
processing explicit driver configuration, effectively ignoring user
intent when prior state existed.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 391247ce96)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-11-13 20:44:49 +01:00
Paweł Gronowski
7a3cdd2c86 daemon: Add TestDetermineImageStoreChoice
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit c5d0e3e6fa)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-11-13 20:44:37 +01:00
Albin Kerouanton
d7b6f3a7d3 inte/networking: TestDisableIPv6OnInterface: add '-c1' to ping
If the DNS name still resolves to an IP address, and that address is
assigned to a running container, the ping command will run indefinitely
and the test suite will time out for 10 mins.

This is confusing, as it looks like a daemon hang, or a test suite hang,
whereas it's just a test failure. Add '-c1' to ping to make it return
immediately.

Signed-off-by: Albin Kerouanton <albin.kerouanton@docker.com>
(cherry picked from commit 53ea70ea46)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-11-13 20:44:17 +01:00
Albin Kerouanton
7f5694cda1 inte/networking: test DNS resolution for non swarm-scoped nws
Previous commit reverted a faulty change that broke DNS resolution for
non swarm-scoped networks once a node has joined a Swarm cluster.

This commit adds an integration test to verify that we don't break DNS
resolution again.

Signed-off-by: Albin Kerouanton <albin.kerouanton@docker.com>
(cherry picked from commit 47bd247d4d)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-11-13 20:44:16 +01:00
Albin Kerouanton
0e2d804e48 libnet: create DNS records on sbJoin (if not agent node)
Commit a8b9eff90 removed a call to Network.updateSvcRecord from
Network.createEndpoint on the grounds that:

> all callers of Network.createEndpoint follow up with an Endpoint.Join,
> which also sets up the DNS entry.

However, the original call in Network.createEndpoint was gated by:

```
if !n.getController().isSwarmNode() || n.Scope() != scope.Swarm || !n.driverIsMultihost() {
	n.updateSvcRecord(context.WithoutCancel(ctx), ep, true)
}
```

whereas the call in Endpoint.sbJoin() (invoked by Endpoint.Join()) is
gated by:

```
if !n.getController().isAgent() {
    if !n.getController().isSwarmNode() || n.Scope() != scope.Swarm || !n.driverIsMultihost() {
	    n.updateSvcRecord(context.WithoutCancel(ctx), ep, true)
    }
}
```

As a result, once a node has joined a Swarm cluster, no DNS entries are
created for non swarm-scoped networks.

Change the condition used by `sbJoin` to match the original condition
used in `createEndpoint`.

Signed-off-by: Albin Kerouanton <albin.kerouanton@docker.com>
(cherry picked from commit 2e41476a5f)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-11-13 20:44:09 +01:00
Paweł Gronowski
7242ccd7a0 c8d/builder-next: Don't force unpack
The image exporter wrapper was unconditionally setting `unpack=true` for
all build exports, preventing users from controlling this behavior
through buildkit's output image exporter option.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit b4f9bd1cb3)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-11-13 20:43:42 +01:00
Paweł Gronowski
b6705d5e1a hack/test/unit: Fix api and client module testing without replace rules
Running sub-package tests from the root module without readding the
replace rules wasn't running the tests from the local in-tree versions
of these submodules.

Fix by cd-ing into their directories before running tests.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 0f597561e8)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-11-13 20:42:58 +01:00
45 changed files with 570 additions and 126 deletions

View File

@@ -16,7 +16,7 @@ on:
workflow_call:
env:
GO_VERSION: "1.25.5"
GO_VERSION: "1.25.6"
GOTESTLIST_VERSION: v0.3.1
TESTSTAT_VERSION: v0.1.25
SETUP_BUILDX_VERSION: edge

View File

@@ -21,7 +21,7 @@ on:
default: "graphdriver"
env:
GO_VERSION: "1.25.5"
GO_VERSION: "1.25.6"
GOTESTLIST_VERSION: v0.3.1
TESTSTAT_VERSION: v0.1.25
ITG_CLI_MATRIX_SIZE: 6

View File

@@ -20,7 +20,7 @@ on:
type: string
env:
GO_VERSION: "1.25.5"
GO_VERSION: "1.25.6"
TESTSTAT_VERSION: v0.1.25
jobs:

View File

@@ -28,7 +28,7 @@ on:
default: false
env:
GO_VERSION: "1.25.5"
GO_VERSION: "1.25.6"
GOTESTLIST_VERSION: v0.3.1
TESTSTAT_VERSION: v0.1.25
WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore

View File

@@ -23,7 +23,7 @@ on:
pull_request:
env:
GO_VERSION: "1.25.5"
GO_VERSION: "1.25.6"
TESTSTAT_VERSION: v0.1.25
DESTDIR: ./build
SETUP_BUILDX_VERSION: edge

View File

@@ -23,7 +23,7 @@ on:
pull_request:
env:
GO_VERSION: "1.25.5"
GO_VERSION: "1.25.6"
DESTDIR: ./build
SETUP_BUILDX_VERSION: edge
SETUP_BUILDKIT_IMAGE: moby/buildkit:latest

View File

@@ -34,7 +34,7 @@ on:
- cron: '0 9 * * 4'
env:
GO_VERSION: "1.25.5"
GO_VERSION: "1.25.6"
jobs:
codeql:

View File

@@ -23,7 +23,7 @@ on:
pull_request:
env:
GO_VERSION: "1.25.5"
GO_VERSION: "1.25.6"
GIT_PAGER: "cat"
PAGER: "cat"
SETUP_BUILDX_VERSION: edge

View File

@@ -81,13 +81,24 @@ jobs:
- name: Check release branch
id: title_branch
run: |
# If PR targets a different branch than master, the PR title should mention the target branch in square brackets, for example:
# [27.1 backport] Some change that needs backporting to 27.1
# [27.1] Change directly targeting the 27.1 branch
# [docker-29.x] Change directly targeting the docker-29.x branch
# [docker-29.x backport] Some change that needs backporting to docker-29.x
# get the intended major version prefix ("[27.1 backport]" -> "27.") from the PR title.
[[ "$PR_TITLE" =~ ^\[([0-9]*\.)[^]]*\] ]] && branch="${BASH_REMATCH[1]}"
target_branch=$(echo "$PR_TITLE" | sed -nE 's/^\[([^]]+)\].*/\1/p' | sed 's/ backport$//')
# get major version prefix from the release branch ("27.x -> "27.")
[[ "$GITHUB_BASE_REF" =~ ^([0-9]*\.) ]] && target_branch="${BASH_REMATCH[1]}" || target_branch="$GITHUB_BASE_REF"
echo "target_branch: $target_branch"
echo "GITHUB_BASE_REF: $GITHUB_BASE_REF"
if [[ "$target_branch" != "$branch" ]] && ! [[ "$GITHUB_BASE_REF" == "master" && "$branch" == "" ]]; then
# If the PR is opened against the master branch and the target branch is not specified, exit early.
if [[ "$GITHUB_BASE_REF" == "master" && "$target_branch" == "" ]]; then
exit 0
fi
if [[ "$target_branch" != "$GITHUB_BASE_REF" ]]; then
echo "::error::PR is opened against the $GITHUB_BASE_REF branch, but its title suggests otherwise."
exit 1
fi

View File

@@ -3,8 +3,7 @@ version: "2"
run:
# prevent golangci-lint from deducting the go version to lint for through go.mod,
# which causes it to fallback to go1.17 semantics.
go: "1.25.5"
concurrency: 2
go: "1.25.6"
# Only supported with go modules enabled (build flag -mod=vendor only valid when using modules)
# modules-download-mode: vendor

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.25.5
ARG GO_VERSION=1.25.6
ARG BASE_DEBIAN_DISTRO="bookworm"
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"

View File

@@ -5,7 +5,7 @@
# This represents the bare minimum required to build and test Docker.
ARG GO_VERSION=1.25.5
ARG GO_VERSION=1.25.6
ARG BASE_DEBIAN_DISTRO="bookworm"
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"

View File

@@ -161,7 +161,7 @@ FROM ${WINDOWS_BASE_IMAGE}:${WINDOWS_BASE_IMAGE_TAG}
# Use PowerShell as the default shell
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
ARG GO_VERSION=1.25.5
ARG GO_VERSION=1.25.6
# GOTESTSUM_VERSION is the version of gotest.tools/gotestsum to install.
ARG GOTESTSUM_VERSION=v1.13.0

View File

@@ -8,6 +8,7 @@ import (
"github.com/moby/go-archive"
"github.com/moby/go-archive/chrootarchive"
"github.com/moby/go-archive/compression"
containertypes "github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/v2/daemon/container"
@@ -278,7 +279,7 @@ func (daemon *Daemon) containerCopy(container *container.Container, resource str
filter = []string{f}
}
archv, err := chrootarchive.Tar(basePath, &archive.TarOptions{
Compression: archive.Uncompressed,
Compression: compression.None,
IncludeFiles: filter,
}, container.BaseFS)
if err != nil {

View File

@@ -7,6 +7,7 @@ import (
"github.com/moby/buildkit/frontend/dockerfile/instructions"
"github.com/moby/go-archive"
"github.com/moby/go-archive/compression"
"github.com/moby/moby/v2/daemon/builder/remotecontext"
"github.com/moby/sys/reexec"
"gotest.tools/v3/assert"
@@ -105,7 +106,7 @@ func TestDispatch(t *testing.T) {
createTestTempFile(t, contextDir, filename, content, 0o777)
}
tarStream, err := archive.Tar(contextDir, archive.Uncompressed)
tarStream, err := archive.Tar(contextDir, compression.None)
if err != nil {
t.Fatalf("Error when creating tar stream: %s", err)
}

View File

@@ -7,6 +7,7 @@ import (
"testing"
"github.com/moby/go-archive"
"github.com/moby/go-archive/compression"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/v2/daemon/builder"
@@ -61,7 +62,7 @@ func readAndCheckDockerfile(t *testing.T, testName, contextDir, dockerfilePath,
if runtime.GOOS != "windows" {
skip.If(t, os.Getuid() != 0, "skipping test that requires root")
}
tarStream, err := archive.Tar(contextDir, archive.Uncompressed)
tarStream, err := archive.Tar(contextDir, compression.None)
assert.NilError(t, err)
defer func() {

View File

@@ -6,6 +6,7 @@ import (
"github.com/containerd/log"
"github.com/moby/go-archive"
"github.com/moby/go-archive/compression"
"github.com/moby/moby/v2/daemon/builder"
"github.com/moby/moby/v2/daemon/builder/remotecontext/git"
)
@@ -17,7 +18,7 @@ func MakeGitContext(gitURL string) (builder.Source, error) {
return nil, err
}
c, err := archive.Tar(root, archive.Uncompressed)
c, err := archive.Tar(root, compression.None)
if err != nil {
return nil, err
}

View File

@@ -6,6 +6,7 @@ import (
"testing"
"github.com/moby/go-archive"
"github.com/moby/go-archive/compression"
"github.com/moby/moby/v2/daemon/builder"
"github.com/moby/sys/reexec"
"github.com/pkg/errors"
@@ -128,7 +129,7 @@ func TestRemoveDirectory(t *testing.T) {
func makeTestArchiveContext(t *testing.T, dir string) builder.Source {
skip.If(t, os.Getuid() != 0, "skipping test that requires root")
tarStream, err := archive.Tar(dir, archive.Uncompressed)
tarStream, err := archive.Tar(dir, compression.None)
if err != nil {
t.Fatalf("error: %s", err)
}

View File

@@ -335,7 +335,7 @@ func validateHealthCheck(healthConfig *containertypes.HealthConfig) error {
func validatePortBindings(ports networktypes.PortMap) error {
for port := range ports {
if !port.IsValid() {
if !port.IsValid() || port.Num() == 0 {
return errors.Errorf("invalid port specification: %q", port.String())
}

View File

@@ -647,7 +647,10 @@ func (container *Container) BackfillEmptyPBs() {
if container.HostConfig == nil {
return
}
if container.HostConfig.PortBindings == nil {
container.HostConfig.PortBindings = networktypes.PortMap{}
return
}
for portProto, pb := range container.HostConfig.PortBindings {
if len(pb) > 0 || pb == nil {
continue

View File

@@ -15,6 +15,7 @@ import (
cerrdefs "github.com/containerd/errdefs"
"github.com/containerd/platforms"
"github.com/moby/go-archive"
"github.com/moby/go-archive/compression"
"github.com/moby/moby/v2/daemon/server/imagebackend"
"github.com/moby/moby/v2/internal/testutil/labelstore"
"github.com/moby/moby/v2/internal/testutil/specialimage"
@@ -39,7 +40,7 @@ func TestImageLoad(t *testing.T) {
imgSvc.defaultPlatformOverride = platforms.Only(linuxAmd64)
tryLoad := func(ctx context.Context, t *testing.T, dir string, platformList []ocispec.Platform) error {
tarRc, err := archive.Tar(dir, archive.Uncompressed)
tarRc, err := archive.Tar(dir, compression.None)
assert.NilError(t, err)
defer tarRc.Close()

View File

@@ -641,18 +641,25 @@ func (daemon *Daemon) restore(ctx context.Context, cfg *configStore, containers
}
group.Wait()
for id := range removeContainers {
for id, c := range removeContainers {
group.Add(1)
go func(cid string) {
go func(cid string, c *container.Container) {
_ = sem.Acquire(context.Background(), 1)
defer group.Done()
defer sem.Release(1)
if c.State.IsDead() {
if err := daemon.cleanupContainer(c, backend.ContainerRmConfig{ForceRemove: true, RemoveVolume: true}); err != nil {
log.G(ctx).WithField("container", cid).WithError(err).Error("failed to remove dead container")
}
return
}
if err := daemon.containerRm(&cfg.Config, cid, &backend.ContainerRmConfig{ForceRemove: true, RemoveVolume: true}); err != nil {
log.G(ctx).WithField("container", cid).WithError(err).Error("failed to remove container")
}
sem.Release(1)
group.Done()
}(id)
}(id, c)
}
group.Wait()

View File

@@ -300,6 +300,18 @@ func TestValidateContainerIsolation(t *testing.T) {
assert.Check(t, is.Error(err, "invalid isolation 'invalid' on "+runtime.GOOS))
}
func TestInvalidContainerPort0(t *testing.T) {
d := Daemon{}
hc := containertypes.HostConfig{
PortBindings: map[network.Port][]network.PortBinding{
network.MustParsePort("0/tcp"): {},
},
}
_, err := d.verifyContainerSettings(&configStore{}, &hc, nil, false)
assert.Error(t, err, `invalid port specification: "0/tcp"`)
}
func TestFindNetworkErrorType(t *testing.T) {
d := Daemon{}
_, err := d.FindNetwork("fakeNet")

View File

@@ -9,6 +9,7 @@ import (
"github.com/containerd/log"
"github.com/moby/go-archive"
"github.com/moby/go-archive/chrootarchive"
"github.com/moby/go-archive/compression"
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/v2/daemon/container"
"github.com/moby/moby/v2/errdefs"
@@ -65,7 +66,7 @@ func (daemon *Daemon) containerExport(ctx context.Context, ctr *container.Contai
}()
archv, err := chrootarchive.Tar(basefs, &archive.TarOptions{
Compression: archive.Uncompressed,
Compression: compression.None,
IDMap: daemon.idMapping,
}, basefs)
if err != nil {

View File

@@ -8,6 +8,7 @@ import (
"github.com/containerd/log"
"github.com/moby/go-archive"
"github.com/moby/go-archive/chrootarchive"
"github.com/moby/go-archive/compression"
"github.com/moby/moby/v2/pkg/ioutils"
"github.com/moby/sys/user"
)
@@ -64,7 +65,7 @@ func (gdw *NaiveDiffDriver) Diff(id, parent string) (arch io.ReadCloser, retErr
}()
if parent == "" {
tarArchive, err := archive.Tar(layerFs, archive.Uncompressed)
tarArchive, err := archive.Tar(layerFs, compression.None)
if err != nil {
return nil, err
}

View File

@@ -19,6 +19,7 @@ import (
"github.com/docker/go-units"
"github.com/moby/go-archive"
"github.com/moby/go-archive/chrootarchive"
"github.com/moby/go-archive/compression"
"github.com/moby/locker"
"github.com/moby/moby/v2/daemon/graphdriver"
"github.com/moby/moby/v2/daemon/graphdriver/overlayutils"
@@ -721,7 +722,7 @@ func (d *Driver) Diff(id, parent string) (io.ReadCloser, error) {
diffPath := d.getDiffPath(id)
logger.Debugf("Tar with options on %s", diffPath)
return archive.TarWithOptions(diffPath, &archive.TarOptions{
Compression: archive.Uncompressed,
Compression: compression.None,
IDMap: d.idMap,
WhiteoutFormat: archive.OverlayWhiteoutFormat,
})

View File

@@ -17,6 +17,7 @@ import (
"github.com/distribution/reference"
"github.com/docker/distribution"
"github.com/moby/go-archive"
"github.com/moby/go-archive/compression"
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/v2/daemon/internal/image"
v1 "github.com/moby/moby/v2/daemon/internal/image/v1"
@@ -395,7 +396,7 @@ func (s *saveSession) writeTar(ctx context.Context, tempDir string, outStream io
ctx, span := tracing.StartSpan(ctx, "writeTar")
defer span.End()
fs, err := archive.Tar(tempDir, archive.Uncompressed)
fs, err := archive.Tar(tempDir, compression.None)
if err != nil {
span.SetStatus(err)
return err

View File

@@ -294,12 +294,15 @@ func (ls *layerStore) registerWithDescriptor(ts io.Reader, parent ChainID, descr
descriptor: descriptor,
}
if cErr = ls.driver.Create(layer.cacheID, pid, nil); cErr != nil {
tx, cErr := ls.store.StartTransaction()
if cErr != nil {
return nil, cErr
}
tx, cErr := ls.store.StartTransaction()
if cErr != nil {
if cErr = ls.driver.Create(layer.cacheID, pid, nil); cErr != nil {
if err := tx.Cancel(); err != nil {
log.G(context.TODO()).WithFields(log.Fields{"cache-id": layer.cacheID, "error": err}).Error("Error canceling metadata transaction")
}
return nil, cErr
}
@@ -532,6 +535,9 @@ func (ls *layerStore) CreateRWLayer(name string, parent ChainID, opts *CreateRWL
return nil, err
}
if err := ls.saveMount(m); err != nil {
if removeErr := ls.driver.Remove(m.mountID); removeErr != nil {
log.G(context.TODO()).WithFields(log.Fields{"mount-id": m.mountID, "error": removeErr}).Error("Failed to clean up RW layer after mount save failure")
}
return nil, err
}
@@ -642,7 +648,7 @@ func (ls *layerStore) saveMount(mount *mountedLayer) error {
return nil
}
func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc MountInit, storageOpt map[string]string) (string, error) {
func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc MountInit, storageOpt map[string]string) (_ string, retErr error) {
// Use "<graph-id>-init" to maintain compatibility with graph drivers
// which are expecting this layer with this special name. If all
// graph drivers can be updated to not rely on knowing about this layer
@@ -657,6 +663,16 @@ func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc Mou
if err := ls.driver.CreateReadWrite(initID, parent, createOpts); err != nil {
return "", err
}
// Clean up init layer if any subsequent operation fails
defer func() {
if retErr != nil {
if err := ls.driver.Remove(initID); err != nil {
log.G(context.TODO()).WithFields(log.Fields{"init-id": initID, "error": err}).Error("Failed to clean up init layer after error")
}
}
}()
p, err := ls.driver.Get(initID, "")
if err != nil {
return "", err

View File

@@ -12,6 +12,7 @@ import (
"github.com/containerd/continuity/driver"
"github.com/moby/go-archive"
"github.com/moby/go-archive/compression"
"github.com/moby/moby/v2/daemon/graphdriver"
"github.com/moby/moby/v2/daemon/graphdriver/vfs"
"github.com/moby/moby/v2/daemon/internal/stringid"
@@ -587,7 +588,7 @@ func tarFromFiles(files ...FileApplier) ([]byte, error) {
}
}
r, err := archive.Tar(td, archive.Uncompressed)
r, err := archive.Tar(td, compression.None)
if err != nil {
return nil, err
}

View File

@@ -362,7 +362,7 @@ func (c *Controller) agentInit(listenAddr, bindAddrOrInterface, advertiseAddr, d
}
c.mu.Unlock()
go c.handleTableEvents(ch, c.handleEpTableEvent)
go c.handleTableEvents(ch, func(ev events.Event) { handleEpTableEvent(c, ev) })
go c.handleTableEvents(nodeCh, c.handleNodeTableEvent)
keys, tags := c.getKeys(subsysIPSec)
@@ -894,14 +894,17 @@ func unmarshalEndpointRecord(data []byte) (*endpointEvent, error) {
}, nil
}
// EquivalentTo returns true if ev is semantically equivalent to other.
// EquivalentTo returns true if ev is semantically equivalent to other,
// ignoring the ServiceDisabled field.
func (ev *endpointEvent) EquivalentTo(other *endpointEvent) bool {
if ev == nil || other == nil {
return (ev == nil) == (other == nil)
}
return ev.Name == other.Name &&
ev.ServiceName == other.ServiceName &&
ev.ServiceID == other.ServiceID &&
ev.VirtualIP == other.VirtualIP &&
ev.EndpointIP == other.EndpointIP &&
ev.ServiceDisabled == other.ServiceDisabled &&
iterutil.SameValues(
iterutil.Deref(slices.Values(ev.IngressPorts)),
iterutil.Deref(slices.Values(other.IngressPorts))) &&
@@ -909,7 +912,14 @@ func (ev *endpointEvent) EquivalentTo(other *endpointEvent) bool {
iterutil.SameValues(slices.Values(ev.TaskAliases), slices.Values(other.TaskAliases))
}
func (c *Controller) handleEpTableEvent(ev events.Event) {
type serviceBinder interface {
addContainerNameResolution(nID, eID, containerName string, taskAliases []string, ip net.IP, method string) error
delContainerNameResolution(nID, eID, containerName string, taskAliases []string, ip net.IP, method string) error
addServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, ingressPorts []*PortConfig, serviceAliases, taskAliases []string, ip net.IP, method string) error
rmServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, ingressPorts []*PortConfig, serviceAliases []string, taskAliases []string, ip net.IP, method string, deleteSvcRecords bool, fullRemove bool) error
}
func handleEpTableEvent(c serviceBinder, ev events.Event) {
event := ev.(networkdb.WatchEvent)
nid := event.NetworkID
eid := event.Key
@@ -939,8 +949,9 @@ func (c *Controller) handleEpTableEvent(ev events.Event) {
})
logger.Debug("handleEpTableEvent")
equivalent := prev.EquivalentTo(epRec)
if prev != nil {
if epRec != nil && prev.EquivalentTo(epRec) {
if equivalent && prev.ServiceDisabled == epRec.ServiceDisabled {
// Avoid flapping if we would otherwise remove a service
// binding then immediately replace it with an equivalent one.
return
@@ -948,7 +959,11 @@ func (c *Controller) handleEpTableEvent(ev events.Event) {
if prev.ServiceID != "" {
// This is a remote task part of a service
if !prev.ServiceDisabled {
if epRec == nil || !equivalent {
// Either the endpoint is deleted from NetworkDB or has
// been replaced with a different one. Remove the old
// binding. The new binding, if any, will be added
// below.
err := c.rmServiceBinding(prev.ServiceName, prev.ServiceID, nid, eid,
prev.Name, prev.VirtualIP.AsSlice(), prev.IngressPorts,
prev.Aliases, prev.TaskAliases, prev.EndpointIP.AsSlice(),
@@ -957,7 +972,7 @@ func (c *Controller) handleEpTableEvent(ev events.Event) {
logger.WithError(err).Error("failed removing service binding")
}
}
} else {
} else if !prev.ServiceDisabled && (!equivalent || epRec == nil || epRec.ServiceDisabled) {
// This is a remote container simply attached to an attachable network
err := c.delContainerNameResolution(nid, eid, prev.Name, prev.TaskAliases,
prev.EndpointIP.AsSlice(), "handleEpTableEvent")
@@ -970,19 +985,16 @@ func (c *Controller) handleEpTableEvent(ev events.Event) {
if epRec != nil {
if epRec.ServiceID != "" {
// This is a remote task part of a service
if epRec.ServiceDisabled {
// Don't double-remove a service binding
if prev == nil || prev.ServiceID != epRec.ServiceID || !prev.ServiceDisabled {
err := c.rmServiceBinding(epRec.ServiceName, epRec.ServiceID,
nid, eid, epRec.Name, epRec.VirtualIP.AsSlice(),
epRec.IngressPorts, epRec.Aliases, epRec.TaskAliases,
epRec.EndpointIP.AsSlice(), "handleEpTableEvent", true, false)
if err != nil {
logger.WithError(err).Error("failed disabling service binding")
return
}
if equivalent && !prev.ServiceDisabled && epRec.ServiceDisabled {
err := c.rmServiceBinding(epRec.ServiceName, epRec.ServiceID,
nid, eid, epRec.Name, epRec.VirtualIP.AsSlice(),
epRec.IngressPorts, epRec.Aliases, epRec.TaskAliases,
epRec.EndpointIP.AsSlice(), "handleEpTableEvent", true, false)
if err != nil {
logger.WithError(err).Error("failed disabling service binding")
return
}
} else {
} else if !epRec.ServiceDisabled {
err := c.addServiceBinding(epRec.ServiceName, epRec.ServiceID, nid, eid,
epRec.Name, epRec.VirtualIP.AsSlice(), epRec.IngressPorts,
epRec.Aliases, epRec.TaskAliases, epRec.EndpointIP.AsSlice(),
@@ -992,7 +1004,7 @@ func (c *Controller) handleEpTableEvent(ev events.Event) {
return
}
}
} else {
} else if !epRec.ServiceDisabled && (!equivalent || prev == nil || prev.ServiceDisabled) {
// This is a remote container simply attached to an attachable network
err := c.addContainerNameResolution(nid, eid, epRec.Name, epRec.TaskAliases,
epRec.EndpointIP.AsSlice(), "handleEpTableEvent")

View File

@@ -1,11 +1,16 @@
package libnetwork
import (
"fmt"
"net"
"net/netip"
"slices"
"testing"
"github.com/gogo/protobuf/proto"
"gotest.tools/v3/assert"
"github.com/moby/moby/v2/daemon/libnetwork/networkdb"
)
func TestEndpointEvent_EquivalentTo(t *testing.T) {
@@ -40,9 +45,12 @@ func TestEndpointEvent_EquivalentTo(t *testing.T) {
return a.EquivalentTo(b)
}
assert.Check(t, reflexiveEquiv(nil, nil), "nil should be equivalent to nil")
assert.Check(t, !reflexiveEquiv(&a, nil), "non-nil should not be equivalent to nil")
b := a
b.ServiceDisabled = true
assert.Check(t, !reflexiveEquiv(&a, &b), "differing by ServiceDisabled")
assert.Check(t, reflexiveEquiv(&a, &b), "ServiceDisabled value should not matter")
c := a
c.IngressPorts = slices.Clone(a.IngressPorts)
@@ -88,3 +96,321 @@ func TestEndpointEvent_EquivalentTo(t *testing.T) {
l.Name = "aaaaa"
assert.Check(t, !reflexiveEquiv(&a, &l), "Differing Name should not be equivalent")
}
type mockServiceBinder struct {
actions []string
}
func (m *mockServiceBinder) addContainerNameResolution(nID, eID, containerName string, _ []string, ip net.IP, _ string) error {
m.actions = append(m.actions, fmt.Sprintf("addContainerNameResolution(%v, %v, %v, %v)", nID, eID, containerName, ip))
return nil
}
func (m *mockServiceBinder) delContainerNameResolution(nID, eID, containerName string, _ []string, ip net.IP, _ string) error {
m.actions = append(m.actions, fmt.Sprintf("delContainerNameResolution(%v, %v, %v, %v)", nID, eID, containerName, ip))
return nil
}
func (m *mockServiceBinder) addServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, _ []*PortConfig, _, _ []string, ip net.IP, _ string) error {
m.actions = append(m.actions, fmt.Sprintf("addServiceBinding(%v, %v, %v, %v, %v, %v, %v)", svcName, svcID, nID, eID, containerName, vip, ip))
return nil
}
func (m *mockServiceBinder) rmServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, _ []*PortConfig, _, _ []string, ip net.IP, _ string, deleteSvcRecords bool, fullRemove bool) error {
m.actions = append(m.actions, fmt.Sprintf("rmServiceBinding(%v, %v, %v, %v, %v, %v, %v, deleteSvcRecords=%v, fullRemove=%v)", svcName, svcID, nID, eID, containerName, vip, ip, deleteSvcRecords, fullRemove))
return nil
}
func TestHandleEPTableEvent(t *testing.T) {
svc1 := EndpointRecord{
Name: "ep1",
ServiceName: "svc1",
ServiceID: "id1",
VirtualIP: "10.0.0.1",
EndpointIP: "192.168.12.42",
}
svc1disabled := svc1
svc1disabled.ServiceDisabled = true
svc2 := EndpointRecord{
Name: "ep2",
ServiceName: "svc2",
ServiceID: "id2",
VirtualIP: "10.0.0.2",
EndpointIP: "172.16.69.5",
}
svc2disabled := svc2
svc2disabled.ServiceDisabled = true
ctr1 := EndpointRecord{
Name: "ctr1",
EndpointIP: "172.18.1.1",
}
ctr1disabled := ctr1
ctr1disabled.ServiceDisabled = true
ctr2 := EndpointRecord{
Name: "ctr2",
EndpointIP: "172.18.1.2",
}
ctr2disabled := ctr2
ctr2disabled.ServiceDisabled = true
tests := []struct {
name string
prev, ev *EndpointRecord
expectedActions []string
}{
{
name: "Insert/Service/ServiceDisabled=false",
ev: &svc1,
expectedActions: []string{
"addServiceBinding(svc1, id1, network1, endpoint1, ep1, 10.0.0.1, 192.168.12.42)",
},
},
{
name: "Insert/Service/ServiceDisabled=true",
ev: &svc1disabled,
},
{
name: "Insert/Container/ServiceDisabled=false",
ev: &ctr1,
expectedActions: []string{
"addContainerNameResolution(network1, endpoint1, ctr1, 172.18.1.1)",
},
},
{
name: "Insert/Container/ServiceDisabled=true",
ev: &ctr1disabled,
},
{
name: "Update/Service/ServiceDisabled=ft",
prev: &svc1,
ev: &svc1disabled,
expectedActions: []string{
"rmServiceBinding(svc1, id1, network1, endpoint1, ep1, 10.0.0.1, 192.168.12.42, deleteSvcRecords=true, fullRemove=false)",
},
},
{
name: "Update/Service/ServiceDisabled=tf",
prev: &svc1disabled,
ev: &svc1,
expectedActions: []string{
"addServiceBinding(svc1, id1, network1, endpoint1, ep1, 10.0.0.1, 192.168.12.42)",
},
},
{
name: "Update/Service/ServiceDisabled=ff",
prev: &svc1disabled,
ev: &svc1disabled,
},
{
name: "Update/Service/ServiceDisabled=tt",
prev: &svc1,
ev: &svc1,
},
{
name: "Update/Container/ServiceDisabled=ft",
prev: &ctr1,
ev: &ctr1disabled,
expectedActions: []string{
"delContainerNameResolution(network1, endpoint1, ctr1, 172.18.1.1)",
},
},
{
name: "Update/Container/ServiceDisabled=tf",
prev: &ctr1disabled,
ev: &ctr1,
expectedActions: []string{
"addContainerNameResolution(network1, endpoint1, ctr1, 172.18.1.1)",
},
},
{
name: "Update/Container/ServiceDisabled=ff",
prev: &ctr1disabled,
ev: &ctr1disabled,
},
{
name: "Update/Container/ServiceDisabled=tt",
prev: &ctr1,
ev: &ctr1,
},
{
name: "Delete/Service/ServiceDisabled=false",
prev: &svc1,
expectedActions: []string{
"rmServiceBinding(svc1, id1, network1, endpoint1, ep1, 10.0.0.1, 192.168.12.42, deleteSvcRecords=true, fullRemove=true)",
},
},
{
name: "Delete/Service/ServiceDisabled=true",
prev: &svc1disabled,
expectedActions: []string{
"rmServiceBinding(svc1, id1, network1, endpoint1, ep1, 10.0.0.1, 192.168.12.42, deleteSvcRecords=true, fullRemove=true)",
},
},
{
name: "Delete/Container/ServiceDisabled=false",
prev: &ctr1,
expectedActions: []string{
"delContainerNameResolution(network1, endpoint1, ctr1, 172.18.1.1)",
},
},
{
name: "Delete/Container/ServiceDisabled=true",
prev: &ctr1disabled,
},
{
name: "Replace/From=Service/To=Service/ServiceDisabled=ff",
prev: &svc1,
ev: &svc2,
expectedActions: []string{
"rmServiceBinding(svc1, id1, network1, endpoint1, ep1, 10.0.0.1, 192.168.12.42, deleteSvcRecords=true, fullRemove=true)",
"addServiceBinding(svc2, id2, network1, endpoint1, ep2, 10.0.0.2, 172.16.69.5)",
},
},
{
name: "Replace/From=Service/To=Service/ServiceDisabled=ft",
prev: &svc1,
ev: &svc2disabled,
expectedActions: []string{
"rmServiceBinding(svc1, id1, network1, endpoint1, ep1, 10.0.0.1, 192.168.12.42, deleteSvcRecords=true, fullRemove=true)",
},
},
{
name: "Replace/From=Service/To=Service/ServiceDisabled=tf",
prev: &svc1disabled,
ev: &svc2,
expectedActions: []string{
"rmServiceBinding(svc1, id1, network1, endpoint1, ep1, 10.0.0.1, 192.168.12.42, deleteSvcRecords=true, fullRemove=true)",
"addServiceBinding(svc2, id2, network1, endpoint1, ep2, 10.0.0.2, 172.16.69.5)",
},
},
{
name: "Replace/From=Service/To=Service/ServiceDisabled=tt",
prev: &svc1disabled,
ev: &svc2disabled,
expectedActions: []string{
"rmServiceBinding(svc1, id1, network1, endpoint1, ep1, 10.0.0.1, 192.168.12.42, deleteSvcRecords=true, fullRemove=true)",
},
},
{
name: "Replace/From=Service/To=Container/ServiceDisabled=ff",
prev: &svc1,
ev: &ctr2,
expectedActions: []string{
"rmServiceBinding(svc1, id1, network1, endpoint1, ep1, 10.0.0.1, 192.168.12.42, deleteSvcRecords=true, fullRemove=true)",
"addContainerNameResolution(network1, endpoint1, ctr2, 172.18.1.2)",
},
},
{
name: "Replace/From=Service/To=Container/ServiceDisabled=ft",
prev: &svc1,
ev: &ctr2disabled,
expectedActions: []string{
"rmServiceBinding(svc1, id1, network1, endpoint1, ep1, 10.0.0.1, 192.168.12.42, deleteSvcRecords=true, fullRemove=true)",
},
},
{
name: "Replace/From=Service/To=Container/ServiceDisabled=tf",
prev: &svc1disabled,
ev: &ctr2,
expectedActions: []string{
"rmServiceBinding(svc1, id1, network1, endpoint1, ep1, 10.0.0.1, 192.168.12.42, deleteSvcRecords=true, fullRemove=true)",
"addContainerNameResolution(network1, endpoint1, ctr2, 172.18.1.2)",
},
},
{
name: "Replace/From=Service/To=Container/ServiceDisabled=tt",
prev: &svc1disabled,
ev: &ctr2disabled,
expectedActions: []string{
"rmServiceBinding(svc1, id1, network1, endpoint1, ep1, 10.0.0.1, 192.168.12.42, deleteSvcRecords=true, fullRemove=true)",
},
},
{
name: "Replace/From=Container/To=Service/ServiceDisabled=ff",
prev: &ctr1,
ev: &svc2,
expectedActions: []string{
"delContainerNameResolution(network1, endpoint1, ctr1, 172.18.1.1)",
"addServiceBinding(svc2, id2, network1, endpoint1, ep2, 10.0.0.2, 172.16.69.5)",
},
},
{
name: "Replace/From=Container/To=Service/ServiceDisabled=ft",
prev: &ctr1,
ev: &svc2disabled,
expectedActions: []string{
"delContainerNameResolution(network1, endpoint1, ctr1, 172.18.1.1)",
},
},
{
name: "Replace/From=Container/To=Service/ServiceDisabled=tf",
prev: &ctr1disabled,
ev: &svc2,
expectedActions: []string{
"addServiceBinding(svc2, id2, network1, endpoint1, ep2, 10.0.0.2, 172.16.69.5)",
},
},
{
name: "Replace/From=Container/To=Service/ServiceDisabled=tt",
prev: &ctr1disabled,
ev: &svc2disabled,
},
{
name: "Replace/From=Container/To=Container/ServiceDisabled=ff",
prev: &ctr1,
ev: &ctr2,
expectedActions: []string{
"delContainerNameResolution(network1, endpoint1, ctr1, 172.18.1.1)",
"addContainerNameResolution(network1, endpoint1, ctr2, 172.18.1.2)",
},
},
{
name: "Replace/From=Container/To=Container/ServiceDisabled=ft",
prev: &ctr1,
ev: &ctr2disabled,
expectedActions: []string{
"delContainerNameResolution(network1, endpoint1, ctr1, 172.18.1.1)",
},
},
{
name: "Replace/From=Container/To=Container/ServiceDisabled=tf",
prev: &ctr1disabled,
ev: &ctr2,
expectedActions: []string{
"addContainerNameResolution(network1, endpoint1, ctr2, 172.18.1.2)",
},
},
{
name: "Replace/From=Container/To=Container/ServiceDisabled=tt",
prev: &ctr1disabled,
ev: &ctr2disabled,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
msb := &mockServiceBinder{}
event := networkdb.WatchEvent{
NetworkID: "network1",
Key: "endpoint1",
}
var err error
if tt.prev != nil {
event.Prev, err = proto.Marshal(tt.prev)
assert.NilError(t, err)
}
if tt.ev != nil {
event.Value, err = proto.Marshal(tt.ev)
assert.NilError(t, err)
}
handleEpTableEvent(msb, event)
assert.DeepEqual(t, tt.expectedActions, msb.actions)
})
}
}

View File

@@ -251,9 +251,14 @@ func deleteEpFromResolverImpl(
}
func findHNSEp(ip4, ip6 *net.IPNet, hnsEndpoints []hcsshim.HNSEndpoint) *hcsshim.HNSEndpoint {
if ip4 == nil && ip6 == nil {
return nil
}
for _, hnsEp := range hnsEndpoints {
if (hnsEp.IPAddress != nil && hnsEp.IPAddress.Equal(ip4.IP)) ||
(hnsEp.IPv6Address != nil && hnsEp.IPv6Address.Equal(ip6.IP)) {
if ip4 != nil && hnsEp.IPAddress != nil && hnsEp.IPAddress.Equal(ip4.IP) {
return &hnsEp
}
if ip6 != nil && hnsEp.IPv6Address != nil && hnsEp.IPv6Address.Equal(ip6.IP) {
return &hnsEp
}
}

View File

@@ -1038,10 +1038,13 @@ func buildPortsRelatedCreateEndpointOptions(c *container.Container, n *libnetwor
)
ports := c.HostConfig.PortBindings
if c.HostConfig.PublishAllPorts {
if c.HostConfig.PublishAllPorts && len(c.Config.ExposedPorts) > 0 {
// Add exposed ports to a copy of the map to make sure a "publishedPorts" entry is created
// for each exposed port, even if there's no specific binding.
ports = maps.Clone(c.HostConfig.PortBindings)
if ports == nil {
ports = networktypes.PortMap{}
}
for p := range c.Config.ExposedPorts {
if _, exists := ports[p]; !exists {
ports[p] = nil

View File

@@ -2,6 +2,7 @@ package daemon
import (
"context"
"crypto/sha256"
"encoding/hex"
"os"
"path/filepath"
@@ -259,10 +260,11 @@ func (daemon *Daemon) registerMountPoints(ctr *container.Container, defaultReadO
StorageOpt: ctr.HostConfig.StorageOpt,
}
// Include the destination in the layer name to make it unique for each mount point and container.
// Hash the source and destination to create a safe, unique identifier for each mount point and container.
// This makes sure that the same image can be mounted multiple times with different destinations.
// Hex encode the destination to create a safe, unique identifier
layerName := hex.EncodeToString([]byte(ctr.ID + ",src=" + mp.Source + ",dst=" + mp.Destination))
// We hash it so that the snapshot name is friendly to the underlying filesystem and doesn't exceed path length limits.
destHash := sha256.Sum256([]byte(ctr.ID + "-src=" + mp.Source + "-dst=" + mp.Destination))
layerName := hex.EncodeToString(destHash[:])
layer, err := daemon.imageService.CreateLayerFromImage(img, layerName, rwLayerOpts)
if err != nil {
return err

4
go.mod
View File

@@ -56,7 +56,7 @@ require (
github.com/miekg/dns v1.1.66
github.com/mistifyio/go-zfs/v3 v3.1.0
github.com/mitchellh/copystructure v1.2.0
github.com/moby/buildkit v0.26.2
github.com/moby/buildkit v0.26.3
github.com/moby/docker-image-spec v1.3.1
github.com/moby/go-archive v0.1.0
github.com/moby/ipvs v1.1.0
@@ -160,7 +160,7 @@ require (
github.com/containerd/stargz-snapshotter/estargz v0.17.0 // indirect
github.com/containerd/ttrpc v1.2.7 // indirect
github.com/containernetworking/cni v1.3.0 // indirect
github.com/containernetworking/plugins v1.8.0 // indirect
github.com/containernetworking/plugins v1.9.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/cyphar/filepath-securejoin v0.6.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect

8
go.sum
View File

@@ -168,8 +168,8 @@ github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++
github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk=
github.com/containernetworking/cni v1.3.0 h1:v6EpN8RznAZj9765HhXQrtXgX+ECGebEYEmnuFjskwo=
github.com/containernetworking/cni v1.3.0/go.mod h1:Bs8glZjjFfGPHMw6hQu82RUgEPNGEaBb9KS5KtNMnJ4=
github.com/containernetworking/plugins v1.8.0 h1:WjGbV/0UQyo8A4qBsAh6GaDAtu1hevxVxsEuqtBqUFk=
github.com/containernetworking/plugins v1.8.0/go.mod h1:JG3BxoJifxxHBhG3hFyxyhid7JgRVBu/wtooGEvWf1c=
github.com/containernetworking/plugins v1.9.0 h1:Mg3SXBdRGkdXyFC4lcwr6u2ZB2SDeL6LC3U+QrEANuQ=
github.com/containernetworking/plugins v1.9.0/go.mod h1:JG3BxoJifxxHBhG3hFyxyhid7JgRVBu/wtooGEvWf1c=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo=
@@ -417,8 +417,8 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/moby/buildkit v0.26.2 h1:EIh5j0gzRsCZmQzvgNNWzSDbuKqwUIiBH7ssqLv8RU8=
github.com/moby/buildkit v0.26.2/go.mod h1:ylDa7IqzVJgLdi/wO7H1qLREFQpmhFbw2fbn4yoTw40=
github.com/moby/buildkit v0.26.3 h1:D+ruZVAk/3ipRq5XRxBH9/DIFpRjSlTtMbghT5gQP9g=
github.com/moby/buildkit v0.26.3/go.mod h1:4T4wJzQS4kYWIfFRjsbJry4QoxDBjK+UGOEOs1izL7w=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.25.5
ARG GO_VERSION=1.25.6
ARG BASE_DEBIAN_DISTRO="bookworm"
ARG PROTOC_VERSION=3.11.4

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.25.5
ARG GO_VERSION=1.25.6
ARG GOVULNCHECK_VERSION=v1.1.4
ARG FORMAT=text

View File

@@ -2024,11 +2024,11 @@ CMD ["cat", "/foo"]`),
}
func (s *DockerCLIBuildSuite) TestBuildContextTarGzip(c *testing.T) {
testContextTar(c, archive.Gzip)
testContextTar(c, compression.Gzip)
}
func (s *DockerCLIBuildSuite) TestBuildContextTarNoCompression(c *testing.T) {
testContextTar(c, archive.Uncompressed)
testContextTar(c, compression.None)
}
func (s *DockerCLIBuildSuite) TestBuildNoContext(c *testing.T) {

View File

@@ -8,6 +8,7 @@ import (
containertypes "github.com/moby/moby/api/types/container"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/integration/internal/container"
"github.com/moby/moby/v2/internal/testutil/daemon"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/fs"
@@ -107,3 +108,26 @@ func TestRemoveInvalidContainer(t *testing.T) {
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
assert.Check(t, is.ErrorContains(err, "No such container"))
}
func TestRemoveDeadContainersOnDaemonRestart(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon)
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "FIXME: Windows CI does not support multiple daemons yet")
ctx := setupTest(t)
d := daemon.New(t)
d.StartWithBusybox(ctx, t)
defer d.Stop(t)
apiClient := d.NewClientT(t)
container.Run(ctx, t, apiClient, container.WithCmd("top"), container.WithAutoRemove)
list, err := apiClient.ContainerList(ctx, client.ContainerListOptions{All: true})
assert.NilError(t, err)
assert.Check(t, is.Len(list.Items, 1))
d.Restart(t)
list, err = apiClient.ContainerList(ctx, client.ContainerListOptions{All: true})
assert.NilError(t, err)
assert.Check(t, is.Len(list.Items, 0))
}

View File

@@ -10,6 +10,7 @@ import (
"time"
"github.com/moby/go-archive"
"github.com/moby/go-archive/compression"
"github.com/moby/moby/api/types/events"
plugintypes "github.com/moby/moby/api/types/plugin"
"github.com/moby/moby/api/types/registry"
@@ -209,7 +210,7 @@ func makePluginBundle(inPath string, opts ...CreateOpt) (io.ReadCloser, error) {
if err := archive.NewDefaultArchiver().CopyFileWithTar(cfg.binPath, filepath.Join(inPath, "rootfs", p.Entrypoint[0])); err != nil {
return nil, errors.Wrap(err, "error copying plugin binary to rootfs path")
}
tar, err := archive.Tar(inPath, archive.Uncompressed)
tar, err := archive.Tar(inPath, compression.None)
return tar, errors.Wrap(err, "error making plugin archive")
}

View File

@@ -11,6 +11,7 @@ import (
"github.com/distribution/reference"
"github.com/google/uuid"
"github.com/moby/go-archive"
"github.com/moby/go-archive/compression"
"github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/specs-go"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -137,7 +138,7 @@ func fileArchive(dir string, name string, content []byte) (io.ReadCloser, error)
return nil, err
}
return archive.Tar(tmp, archive.Uncompressed)
return archive.Tar(tmp, compression.None)
}
func writeLayerWithOneFile(dir string, filename string, content []byte) (ocispec.Descriptor, error) {

View File

@@ -653,43 +653,7 @@ func (lbf *llbBridgeForwarder) ResolveSourceMeta(ctx context.Context, req *pb.Re
if err != nil {
return nil, err
}
r := &pb.ResolveSourceMetaResponse{
Source: resp.Op,
}
if resp.Image != nil {
r.Image = &pb.ResolveSourceImageResponse{
Digest: string(resp.Image.Digest),
Config: resp.Image.Config,
}
if resp.Image.AttestationChain != nil {
r.Image.AttestationChain = toPBAttestationChain(resp.Image.AttestationChain)
}
}
if resp.Git != nil {
r.Git = &pb.ResolveSourceGitResponse{
Checksum: resp.Git.Checksum,
Ref: resp.Git.Ref,
CommitChecksum: resp.Git.CommitChecksum,
CommitObject: resp.Git.CommitObject,
TagObject: resp.Git.TagObject,
}
}
if resp.HTTP != nil {
var lastModified *timestamp.Timestamp
if resp.HTTP.LastModified != nil {
lastModified = &timestamp.Timestamp{
Seconds: resp.HTTP.LastModified.Unix(),
}
}
r.HTTP = &pb.ResolveSourceHTTPResponse{
Checksum: resp.HTTP.Digest.String(),
Filename: resp.HTTP.Filename,
LastModified: lastModified,
}
}
return r, nil
return ToPBResolveSourceMetaResponse(resp), nil
}
func (lbf *llbBridgeForwarder) ResolveImageConfig(ctx context.Context, req *pb.ResolveImageConfigRequest) (*pb.ResolveImageConfigResponse, error) {
@@ -1705,6 +1669,45 @@ func getCaps(label string) map[string]struct{} {
return out
}
func ToPBResolveSourceMetaResponse(in *sourceresolver.MetaResponse) *pb.ResolveSourceMetaResponse {
r := &pb.ResolveSourceMetaResponse{
Source: in.Op,
}
if in.Image != nil {
r.Image = &pb.ResolveSourceImageResponse{
Digest: string(in.Image.Digest),
Config: in.Image.Config,
}
if in.Image.AttestationChain != nil {
r.Image.AttestationChain = toPBAttestationChain(in.Image.AttestationChain)
}
}
if in.Git != nil {
r.Git = &pb.ResolveSourceGitResponse{
Checksum: in.Git.Checksum,
Ref: in.Git.Ref,
CommitChecksum: in.Git.CommitChecksum,
CommitObject: in.Git.CommitObject,
TagObject: in.Git.TagObject,
}
}
if in.HTTP != nil {
var lastModified *timestamp.Timestamp
if in.HTTP.LastModified != nil {
lastModified = &timestamp.Timestamp{
Seconds: in.HTTP.LastModified.Unix(),
}
}
r.HTTP = &pb.ResolveSourceHTTPResponse{
Checksum: in.HTTP.Digest.String(),
Filename: in.HTTP.Filename,
LastModified: lastModified,
}
}
return r
}
func toPBAttestationChain(ac *sourceresolver.AttestationChain) *pb.AttestationChain {
if ac == nil {
return nil

View File

@@ -5,6 +5,7 @@ import (
"strings"
"github.com/moby/buildkit/client/llb/sourceresolver"
"github.com/moby/buildkit/frontend/gateway"
gatewaypb "github.com/moby/buildkit/frontend/gateway/pb"
"github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/sourcepolicy"
@@ -88,19 +89,26 @@ func (p *policyEvaluator) Evaluate(ctx context.Context, op *pb.Op) (bool, error)
Platform: toOCIPlatform(metareq.Platform),
}
}
if metareq.Image != nil {
if op.ImageOpt == nil {
op.ImageOpt = &sourceresolver.ResolveImageOpt{}
}
op.ImageOpt.NoConfig = metareq.Image.NoConfig
op.ImageOpt.AttestationChain = metareq.Image.AttestationChain
}
if metareq.Git != nil {
op.GitOpt = &sourceresolver.ResolveGitOpt{
ReturnObject: metareq.Git.ReturnObject,
}
}
resp, err := p.resolveSourceMetadata(ctx, metareq.Source, op, false)
if err != nil {
return false, errors.Wrap(err, "error resolving source metadata from policy request")
}
req.Source = &gatewaypb.ResolveSourceMetaResponse{
Source: resp.Op,
}
if resp.Image != nil {
req.Source.Image = &gatewaypb.ResolveSourceImageResponse{
Digest: resp.Image.Digest.String(),
Config: resp.Image.Config,
}
}
req.Source = gateway.ToPBResolveSourceMetaResponse(resp)
continue
}

4
vendor/modules.txt vendored
View File

@@ -525,7 +525,7 @@ github.com/containernetworking/cni/pkg/types/create
github.com/containernetworking/cni/pkg/types/internal
github.com/containernetworking/cni/pkg/utils
github.com/containernetworking/cni/pkg/version
# github.com/containernetworking/plugins v1.8.0
# github.com/containernetworking/plugins v1.9.0
## explicit; go 1.24.2
github.com/containernetworking/plugins/pkg/ns
# github.com/coreos/go-semver v0.3.1
@@ -838,7 +838,7 @@ github.com/mitchellh/hashstructure/v2
# github.com/mitchellh/reflectwalk v1.0.2
## explicit
github.com/mitchellh/reflectwalk
# github.com/moby/buildkit v0.26.2
# github.com/moby/buildkit v0.26.3
## explicit; go 1.24.3
github.com/moby/buildkit/api/services/control
github.com/moby/buildkit/api/types