mirror of
https://github.com/moby/moby.git
synced 2026-01-18 01:48:07 +00:00
Compare commits
60 Commits
copilot/ad
...
docker-v29
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b01d641ef | ||
|
|
480df69696 | ||
|
|
dd6a3633ee | ||
|
|
ff5e19865b | ||
|
|
d05a725121 | ||
|
|
01fc4fcf8b | ||
|
|
08440b6ee8 | ||
|
|
b0e62060b0 | ||
|
|
515dbc8c71 | ||
|
|
adf3073cb6 | ||
|
|
8b2c317218 | ||
|
|
3eca177282 | ||
|
|
c4f4c6765e | ||
|
|
f942bce11a | ||
|
|
a1f7fff7a9 | ||
|
|
0e600c7fc4 | ||
|
|
734bb626e4 | ||
|
|
5eaae6db52 | ||
|
|
8ebb104e36 | ||
|
|
fbf3ed25f8 | ||
|
|
518779c90b | ||
|
|
ecf8643fe1 | ||
|
|
5a99e1d1a4 | ||
|
|
bae170eeb7 | ||
|
|
8f33623c5d | ||
|
|
bdc1e7b0fe | ||
|
|
298e2f7d52 | ||
|
|
3376758770 | ||
|
|
bb2e099c3a | ||
|
|
5898ee60f4 | ||
|
|
05a5be917d | ||
|
|
ab55325b58 | ||
|
|
5c69198edd | ||
|
|
cbaccdaf6d | ||
|
|
09d5128bff | ||
|
|
b54adb2d03 | ||
|
|
4612690e23 | ||
|
|
6280a80f32 | ||
|
|
9cbafeac46 | ||
|
|
1fa8a31556 | ||
|
|
3c6e5f0f5a | ||
|
|
e9ff10bf36 | ||
|
|
7faaa44e18 | ||
|
|
e9f9d7a81e | ||
|
|
28665176e5 | ||
|
|
43f91f775a | ||
|
|
bb0d79cb1a | ||
|
|
198b5e3ed5 | ||
|
|
2ad480ccf5 | ||
|
|
cb6c1c3aca | ||
|
|
2a18530fb2 | ||
|
|
14c4e0d73a | ||
|
|
d23fd38f8b | ||
|
|
3076530aa6 | ||
|
|
7a3cdd2c86 | ||
|
|
d7b6f3a7d3 | ||
|
|
7f5694cda1 | ||
|
|
0e2d804e48 | ||
|
|
7242ccd7a0 | ||
|
|
b6705d5e1a |
2
.github/workflows/.test-unit.yml
vendored
2
.github/workflows/.test-unit.yml
vendored
@@ -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
|
||||
|
||||
2
.github/workflows/.test.yml
vendored
2
.github/workflows/.test.yml
vendored
@@ -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
|
||||
|
||||
2
.github/workflows/.vm.yml
vendored
2
.github/workflows/.vm.yml
vendored
@@ -20,7 +20,7 @@ on:
|
||||
type: string
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.25.5"
|
||||
GO_VERSION: "1.25.6"
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
|
||||
jobs:
|
||||
|
||||
2
.github/workflows/.windows.yml
vendored
2
.github/workflows/.windows.yml
vendored
@@ -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
|
||||
|
||||
2
.github/workflows/arm64.yml
vendored
2
.github/workflows/arm64.yml
vendored
@@ -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
|
||||
|
||||
2
.github/workflows/buildkit.yml
vendored
2
.github/workflows/buildkit.yml
vendored
@@ -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
|
||||
|
||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -34,7 +34,7 @@ on:
|
||||
- cron: '0 9 * * 4'
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.25.5"
|
||||
GO_VERSION: "1.25.6"
|
||||
|
||||
jobs:
|
||||
codeql:
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -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
|
||||
|
||||
19
.github/workflows/validate-pr.yml
vendored
19
.github/workflows/validate-pr.yml
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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}"
|
||||
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
4
go.mod
@@ -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
8
go.sum
@@ -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=
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
77
vendor/github.com/moby/buildkit/frontend/gateway/gateway.go
generated
vendored
77
vendor/github.com/moby/buildkit/frontend/gateway/gateway.go
generated
vendored
@@ -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 = ×tamp.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 = ×tamp.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
|
||||
|
||||
26
vendor/github.com/moby/buildkit/solver/llbsolver/policy.go
generated
vendored
26
vendor/github.com/moby/buildkit/solver/llbsolver/policy.go
generated
vendored
@@ -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
4
vendor/modules.txt
vendored
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user