mirror of
https://github.com/moby/moby.git
synced 2026-01-16 10:21:47 +00:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b539b8df2 | ||
|
|
37bf6e81f9 | ||
|
|
fefdb1bf24 | ||
|
|
3a4c589290 | ||
|
|
6eeb414adf | ||
|
|
54af846a0c | ||
|
|
10cf2d64b6 | ||
|
|
7b86f40aa2 | ||
|
|
84cfcb0893 | ||
|
|
edeb6ba9fb | ||
|
|
adb0b8536d | ||
|
|
01f7ec0f21 | ||
|
|
442462ad4e | ||
|
|
a3eca63b5b | ||
|
|
7177a05666 | ||
|
|
d036255b69 | ||
|
|
88288fedff | ||
|
|
b9f56706c5 | ||
|
|
7c1f8db55e | ||
|
|
12d4379ad1 | ||
|
|
801f77bbef | ||
|
|
0fbb78c187 | ||
|
|
2bc17a1e5c | ||
|
|
fe01a5fc30 | ||
|
|
bf7ca4dc4b | ||
|
|
405a163620 | ||
|
|
812b97d559 | ||
|
|
c4eef2a58c | ||
|
|
8dec1f216f | ||
|
|
068e82bdd2 | ||
|
|
8ae439ddaa | ||
|
|
c27f7de662 | ||
|
|
ec8ff9cbbd | ||
|
|
e5bc931f17 | ||
|
|
6c3b1992d4 | ||
|
|
83171f6b5a | ||
|
|
4cfa21bb92 | ||
|
|
28bdd819d0 | ||
|
|
cb2e98cfbf |
2
.github/workflows/.test.yml
vendored
2
.github/workflows/.test.yml
vendored
@@ -21,7 +21,7 @@ on:
|
||||
default: "graphdriver"
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.21.13"
|
||||
GO_VERSION: "1.22.7"
|
||||
GOTESTLIST_VERSION: v0.3.1
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
ITG_CLI_MATRIX_SIZE: 6
|
||||
|
||||
2
.github/workflows/.windows.yml
vendored
2
.github/workflows/.windows.yml
vendored
@@ -28,7 +28,7 @@ on:
|
||||
default: false
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.21.13"
|
||||
GO_VERSION: "1.22.7"
|
||||
GOTESTLIST_VERSION: v0.3.1
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore
|
||||
|
||||
2
.github/workflows/buildkit.yml
vendored
2
.github/workflows/buildkit.yml
vendored
@@ -22,7 +22,7 @@ on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.21.13"
|
||||
GO_VERSION: "1.22.7"
|
||||
DESTDIR: ./build
|
||||
SETUP_BUILDX_VERSION: latest
|
||||
SETUP_BUILDKIT_IMAGE: moby/buildkit:latest
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -22,7 +22,7 @@ on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.21.13"
|
||||
GO_VERSION: "1.22.7"
|
||||
GIT_PAGER: "cat"
|
||||
PAGER: "cat"
|
||||
SETUP_BUILDX_VERSION: latest
|
||||
|
||||
@@ -45,6 +45,11 @@ linters-settings:
|
||||
|
||||
govet:
|
||||
check-shadowing: false
|
||||
|
||||
gosec:
|
||||
excludes:
|
||||
- G115 # FIXME temporarily suppress 'G115: integer overflow conversion': it produces many hits, some of which may be false positives, and need to be looked at; see https://github.com/moby/moby/issues/48358
|
||||
|
||||
depguard:
|
||||
rules:
|
||||
main:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:1.7
|
||||
|
||||
ARG GO_VERSION=1.21.13
|
||||
ARG GO_VERSION=1.22.7
|
||||
ARG BASE_DEBIAN_DISTRO="bookworm"
|
||||
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"
|
||||
ARG XX_VERSION=1.5.0
|
||||
@@ -229,7 +229,7 @@ FROM binary-dummy AS containerd-windows
|
||||
FROM containerd-${TARGETOS} AS containerd
|
||||
|
||||
FROM base AS golangci_lint
|
||||
ARG GOLANGCI_LINT_VERSION=v1.59.1
|
||||
ARG GOLANGCI_LINT_VERSION=v1.60.2
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
GOBIN=/build/ GO111MODULE=on go install "github.com/golangci/golangci-lint/cmd/golangci-lint@${GOLANGCI_LINT_VERSION}" \
|
||||
@@ -287,7 +287,7 @@ RUN git init . && git remote add origin "https://github.com/opencontainers/runc.
|
||||
# that is used. If you need to update runc, open a pull request in the containerd
|
||||
# project first, and update both after that is merged. When updating RUNC_VERSION,
|
||||
# consider updating runc in vendor.mod accordingly.
|
||||
ARG RUNC_VERSION=v1.1.13
|
||||
ARG RUNC_VERSION=v1.1.14
|
||||
RUN git fetch -q --depth 1 origin "${RUNC_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
|
||||
|
||||
FROM base AS runc-build
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
# This represents the bare minimum required to build and test Docker.
|
||||
|
||||
ARG GO_VERSION=1.21.13
|
||||
ARG GO_VERSION=1.22.7
|
||||
|
||||
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.21.13
|
||||
ARG GO_VERSION=1.22.7
|
||||
ARG GOTESTSUM_VERSION=v1.8.2
|
||||
ARG GOWINRES_VERSION=v0.3.1
|
||||
ARG CONTAINERD_VERSION=v1.7.21
|
||||
|
||||
@@ -940,9 +940,11 @@ func (s *containerRouter) postContainersAttach(ctx context.Context, w http.Respo
|
||||
if multiplexed && versions.GreaterThanOrEqualTo(httputils.VersionFromContext(ctx), "1.42") {
|
||||
contentType = types.MediaTypeMultiplexedStream
|
||||
}
|
||||
fmt.Fprintf(conn, "HTTP/1.1 101 UPGRADED\r\nContent-Type: "+contentType+"\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
|
||||
// FIXME(thaJeztah): we should not ignore errors here; see https://github.com/moby/moby/pull/48359#discussion_r1725562802
|
||||
fmt.Fprintf(conn, "HTTP/1.1 101 UPGRADED\r\nContent-Type: %v\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n", contentType)
|
||||
} else {
|
||||
fmt.Fprintf(conn, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
|
||||
// FIXME(thaJeztah): we should not ignore errors here; see https://github.com/moby/moby/pull/48359#discussion_r1725562802
|
||||
fmt.Fprint(conn, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
|
||||
}
|
||||
|
||||
go notifyClosed(ctx, conn, cancel)
|
||||
|
||||
@@ -142,7 +142,7 @@ func (ir *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrit
|
||||
id, progressErr = ir.backend.ImportImage(ctx, tagRef, platform, comment, layerReader, r.Form["changes"])
|
||||
|
||||
if progressErr == nil {
|
||||
output.Write(streamformatter.FormatStatus("", id.String()))
|
||||
_, _ = output.Write(streamformatter.FormatStatus("", "%v", id.String()))
|
||||
}
|
||||
}
|
||||
if progressErr != nil {
|
||||
|
||||
@@ -5347,7 +5347,7 @@ definitions:
|
||||
The version Go used to compile the daemon, and the version of the Go
|
||||
runtime in use.
|
||||
type: "string"
|
||||
example: "go1.21.13"
|
||||
example: "go1.22.7"
|
||||
Os:
|
||||
description: |
|
||||
The operating system that the daemon is running on ("linux" or "windows")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package container // import "github.com/docker/docker/api/types/container"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@@ -325,12 +326,12 @@ func ValidateRestartPolicy(policy RestartPolicy) error {
|
||||
if policy.MaximumRetryCount < 0 {
|
||||
msg += " and cannot be negative"
|
||||
}
|
||||
return &errInvalidParameter{fmt.Errorf(msg)}
|
||||
return &errInvalidParameter{errors.New(msg)}
|
||||
}
|
||||
return nil
|
||||
case RestartPolicyOnFailure:
|
||||
if policy.MaximumRetryCount < 0 {
|
||||
return &errInvalidParameter{fmt.Errorf("invalid restart policy: maximum retry count cannot be negative")}
|
||||
return &errInvalidParameter{errors.New("invalid restart policy: maximum retry count cannot be negative")}
|
||||
}
|
||||
return nil
|
||||
case "":
|
||||
|
||||
@@ -27,25 +27,25 @@ func parseChownFlag(ctx context.Context, builder *Builder, state *dispatchState,
|
||||
|
||||
passwdPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "passwd"), ctrRootPath)
|
||||
if err != nil {
|
||||
return idtools.Identity{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
|
||||
return idtools.Identity{}, errors.Wrap(err, "can't resolve /etc/passwd path in container rootfs")
|
||||
}
|
||||
groupPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "group"), ctrRootPath)
|
||||
if err != nil {
|
||||
return idtools.Identity{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
|
||||
return idtools.Identity{}, errors.Wrap(err, "can't resolve /etc/group path in container rootfs")
|
||||
}
|
||||
uid, err := lookupUser(userStr, passwdPath)
|
||||
if err != nil {
|
||||
return idtools.Identity{}, errors.Wrapf(err, "can't find uid for user "+userStr)
|
||||
return idtools.Identity{}, errors.Wrap(err, "can't find uid for user "+userStr)
|
||||
}
|
||||
gid, err := lookupGroup(grpStr, groupPath)
|
||||
if err != nil {
|
||||
return idtools.Identity{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
|
||||
return idtools.Identity{}, errors.Wrap(err, "can't find gid for group "+grpStr)
|
||||
}
|
||||
|
||||
// convert as necessary because of user namespaces
|
||||
chownPair, err := identityMapping.ToHost(idtools.Identity{UID: uid, GID: gid})
|
||||
if err != nil {
|
||||
return idtools.Identity{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
|
||||
return idtools.Identity{}, errors.Wrap(err, "unable to convert uid/gid to host mapping")
|
||||
}
|
||||
return chownPair, nil
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ func NoArgs(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if cmd.HasSubCommands() {
|
||||
return errors.Errorf("\n" + strings.TrimRight(cmd.UsageString(), "\n"))
|
||||
return errors.New("\n" + strings.TrimRight(cmd.UsageString(), "\n"))
|
||||
}
|
||||
|
||||
return errors.Errorf(
|
||||
|
||||
@@ -2,6 +2,7 @@ package stream // import "github.com/docker/docker/container/stream"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
@@ -91,24 +92,24 @@ func (c *Config) NewNopInputPipe() {
|
||||
|
||||
// CloseStreams ensures that the configured streams are properly closed.
|
||||
func (c *Config) CloseStreams() error {
|
||||
var errors []string
|
||||
var errs []string
|
||||
|
||||
if c.stdin != nil {
|
||||
if err := c.stdin.Close(); err != nil {
|
||||
errors = append(errors, fmt.Sprintf("error close stdin: %s", err))
|
||||
errs = append(errs, fmt.Sprintf("error close stdin: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
if err := c.stdout.Clean(); err != nil {
|
||||
errors = append(errors, fmt.Sprintf("error close stdout: %s", err))
|
||||
errs = append(errs, fmt.Sprintf("error close stdout: %s", err))
|
||||
}
|
||||
|
||||
if err := c.stderr.Clean(); err != nil {
|
||||
errors = append(errors, fmt.Sprintf("error close stderr: %s", err))
|
||||
errs = append(errs, fmt.Sprintf("error close stderr: %s", err))
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return fmt.Errorf(strings.Join(errors, "\n"))
|
||||
if len(errs) > 0 {
|
||||
return errors.New(strings.Join(errs, "\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -393,17 +393,25 @@ func (i *ImageService) imageSummary(ctx context.Context, img images.Image, platf
|
||||
"error": err,
|
||||
"image": img.Name,
|
||||
}).Warn("unexpected image target (neither a manifest nor index)")
|
||||
return nil, nil, nil
|
||||
} else {
|
||||
return nil, nil, err
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if best == nil {
|
||||
// TODO we should probably show *something* for images we've pulled
|
||||
// but are 100% shallow or an empty manifest list/index
|
||||
// ("tianon/scratch:index" is an empty example image index and
|
||||
// "tianon/scratch:list" is an empty example manifest list)
|
||||
return nil, nil, nil
|
||||
target := img.Target
|
||||
return &imagetypes.Summary{
|
||||
ID: target.Digest.String(),
|
||||
RepoDigests: []string{target.Digest.String()},
|
||||
RepoTags: tagsByDigest[target.Digest],
|
||||
Size: totalSize,
|
||||
// -1 indicates that the value has not been set (avoids ambiguity
|
||||
// between 0 (default) and "not set". We cannot use a pointer (nil)
|
||||
// for this, as the JSON representation uses "omitempty", which would
|
||||
// consider both "0" and "nil" to be "empty".
|
||||
SharedSize: -1,
|
||||
Containers: -1,
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
image, err := i.singlePlatformImage(ctx, i.content, tagsByDigest[best.RealTarget.Digest], best)
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"testing"
|
||||
@@ -206,6 +207,9 @@ func TestImageList(t *testing.T) {
|
||||
configTarget, err := specialimage.ConfigTarget(blobsDir)
|
||||
assert.NilError(t, err)
|
||||
|
||||
textplain, err := specialimage.TextPlain(blobsDir)
|
||||
assert.NilError(t, err)
|
||||
|
||||
cs := &blobsDirContentStore{blobs: filepath.Join(blobsDir, "blobs/sha256")}
|
||||
|
||||
for _, tc := range []struct {
|
||||
@@ -276,17 +280,34 @@ func TestImageList(t *testing.T) {
|
||||
name: "three images, one is an empty index",
|
||||
images: imagesFromIndex(multilayer, emptyIndex, twoplatform),
|
||||
check: func(t *testing.T, all []*imagetypes.Summary) {
|
||||
assert.Check(t, is.Len(all, 2))
|
||||
assert.Check(t, is.Len(all, 3))
|
||||
},
|
||||
},
|
||||
{
|
||||
// Make sure an invalid image target doesn't break the whole operation
|
||||
name: "one good image, second has config as a target",
|
||||
images: imagesFromIndex(multilayer, configTarget),
|
||||
check: func(t *testing.T, all []*imagetypes.Summary) {
|
||||
assert.Check(t, is.Len(all, 1))
|
||||
assert.Check(t, is.Len(all, 2))
|
||||
|
||||
sort.Slice(all, func(i, j int) bool {
|
||||
return slices.Contains(all[i].RepoTags, "multilayer:latest")
|
||||
})
|
||||
|
||||
assert.Check(t, is.Equal(all[0].ID, multilayer.Manifests[0].Digest.String()))
|
||||
assert.Check(t, is.Len(all[0].Manifests, 1))
|
||||
|
||||
assert.Check(t, is.Equal(all[1].ID, configTarget.Manifests[0].Digest.String()))
|
||||
assert.Check(t, is.Len(all[1].Manifests, 0))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "a non-container image manifest",
|
||||
images: imagesFromIndex(textplain),
|
||||
check: func(t *testing.T, all []*imagetypes.Summary) {
|
||||
assert.Check(t, is.Len(all, 1))
|
||||
assert.Check(t, is.Equal(all[0].ID, textplain.Manifests[0].Digest.String()))
|
||||
|
||||
assert.Assert(t, is.Len(all[0].Manifests, 0))
|
||||
},
|
||||
},
|
||||
} {
|
||||
|
||||
@@ -217,6 +217,18 @@ func (i *ImageService) pullTag(ctx context.Context, ref reference.Named, platfor
|
||||
}
|
||||
return errdefs.NotFound(fmt.Errorf("pull access denied for %s, repository does not exist or may require 'docker login'", reference.FamiliarName(ref)))
|
||||
}
|
||||
if cerrdefs.IsNotFound(err) {
|
||||
// Transform "no match for platform in manifest" error returned by containerd into
|
||||
// the same message as the graphdrivers backend.
|
||||
// The one returned by containerd doesn't contain the platform and is much less informative.
|
||||
if strings.Contains(err.Error(), "platform") {
|
||||
platformStr := platforms.DefaultString()
|
||||
if platform != nil {
|
||||
platformStr = platforms.Format(*platform)
|
||||
}
|
||||
return errdefs.NotFound(fmt.Errorf("no matching manifest for %s in the manifest list entries: %w", platformStr, err))
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -943,7 +943,7 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
|
||||
|
||||
// ensureDefaultAppArmorProfile does nothing if apparmor is disabled
|
||||
if err := ensureDefaultAppArmorProfile(); err != nil {
|
||||
log.G(ctx).Errorf(err.Error())
|
||||
log.G(ctx).WithError(err).Error("Failed to ensure default apparmor profile is loaded")
|
||||
}
|
||||
|
||||
daemonRepo := filepath.Join(cfgStore.Root, "containers")
|
||||
|
||||
12916
docs/api/v1.47.yaml
Normal file
12916
docs/api/v1.47.yaml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@ set -e
|
||||
# the containerd project first, and update both after that is merged.
|
||||
#
|
||||
# When updating RUNC_VERSION, consider updating runc in vendor.mod accordingly
|
||||
: "${RUNC_VERSION:=v1.1.13}"
|
||||
: "${RUNC_VERSION:=v1.1.14}"
|
||||
|
||||
install_runc() {
|
||||
RUNC_BUILDTAGS="${RUNC_BUILDTAGS:-"seccomp"}"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG GO_VERSION=1.21.13
|
||||
ARG GO_VERSION=1.22.7
|
||||
ARG BASE_DEBIAN_DISTRO="bookworm"
|
||||
ARG PROTOC_VERSION=3.11.4
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG GO_VERSION=1.21.13
|
||||
ARG GO_VERSION=1.22.7
|
||||
ARG GOVULNCHECK_VERSION=v1.1.3
|
||||
ARG FORMAT=text
|
||||
|
||||
|
||||
@@ -78,6 +78,18 @@ source "${MAKEDIR}/.go-autogen"
|
||||
GCFLAGS="all=-N -l"
|
||||
fi
|
||||
|
||||
if [ "$(go env GOARCH)" = "arm" ] && [ "$(go env GOARM)" = "5" ]; then
|
||||
# cross-compiling for arm/v5 fails on go1.22; a fix is included for this
|
||||
# in go1.23 (https://github.com/golang/go/issues/65290), but for go1.22
|
||||
# we can set the correct option manually.
|
||||
CGO_CFLAGS+=" -Wno-atomic-alignment"
|
||||
export CGO_CFLAGS
|
||||
|
||||
# Make sure libatomic is included on arm/v5, because clang does not auto-link it.
|
||||
# see https://github.com/moby/moby/pull/46982#issuecomment-2206992611
|
||||
export CGO_LDFLAGS="-latomic"
|
||||
fi
|
||||
|
||||
echo "Building $([ "$DOCKER_STATIC" = "1" ] && echo "static" || echo "dynamic") $DEST/$BINARY_FULLNAME ($PLATFORM_NAME)..."
|
||||
if [ -n "$DOCKER_DEBUG" ]; then
|
||||
set -x
|
||||
|
||||
@@ -2,7 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"errors"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
@@ -46,7 +46,7 @@ func (s *DockerBenchmarkSuite) BenchmarkConcurrentContainerActions(c *testing.B)
|
||||
args = append(args, sleepCommandForDaemonPlatform()...)
|
||||
out, _, err := dockerCmdWithError(args...)
|
||||
if err != nil {
|
||||
chErr <- fmt.Errorf(out)
|
||||
chErr <- errors.New(out)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -59,29 +59,29 @@ func (s *DockerBenchmarkSuite) BenchmarkConcurrentContainerActions(c *testing.B)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
out, _, err = dockerCmdWithError("cp", id+":/tmp", tmpDir)
|
||||
if err != nil {
|
||||
chErr <- fmt.Errorf(out)
|
||||
chErr <- errors.New(out)
|
||||
return
|
||||
}
|
||||
|
||||
out, _, err = dockerCmdWithError("kill", id)
|
||||
if err != nil {
|
||||
chErr <- fmt.Errorf(out)
|
||||
chErr <- errors.New(out)
|
||||
}
|
||||
|
||||
out, _, err = dockerCmdWithError("start", id)
|
||||
if err != nil {
|
||||
chErr <- fmt.Errorf(out)
|
||||
chErr <- errors.New(out)
|
||||
}
|
||||
|
||||
out, _, err = dockerCmdWithError("kill", id)
|
||||
if err != nil {
|
||||
chErr <- fmt.Errorf(out)
|
||||
chErr <- errors.New(out)
|
||||
}
|
||||
|
||||
// don't do an rm -f here since it can potentially ignore errors from the graphdriver
|
||||
out, _, err = dockerCmdWithError("rm", id)
|
||||
if err != nil {
|
||||
chErr <- fmt.Errorf(out)
|
||||
chErr <- errors.New(out)
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -91,7 +91,7 @@ func (s *DockerBenchmarkSuite) BenchmarkConcurrentContainerActions(c *testing.B)
|
||||
for i := 0; i < numIterations; i++ {
|
||||
out, _, err := dockerCmdWithError("ps")
|
||||
if err != nil {
|
||||
chErr <- fmt.Errorf(out)
|
||||
chErr <- errors.New(out)
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -116,7 +116,7 @@ func (s *DockerBenchmarkSuite) BenchmarkLogsCLIRotateFollow(c *testing.B) {
|
||||
ch <- nil
|
||||
out, _, _ := dockerCmdWithError("logs", "-f", id)
|
||||
// if this returns at all, it's an error
|
||||
ch <- fmt.Errorf(out)
|
||||
ch <- errors.New(out)
|
||||
}()
|
||||
|
||||
<-ch
|
||||
|
||||
@@ -60,16 +60,18 @@ func (s *DockerNetworkSuite) SetUpSuite(ctx context.Context, c *testing.T) {
|
||||
setupRemoteNetworkDrivers(c, mux, s.server.URL, dummyNetworkDriver, dummyIPAMDriver)
|
||||
}
|
||||
|
||||
func setupRemoteNetworkDrivers(c *testing.T, mux *http.ServeMux, url, netDrv, ipamDrv string) {
|
||||
func setupRemoteNetworkDrivers(t *testing.T, mux *http.ServeMux, url, netDrv, ipamDrv string) {
|
||||
mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType)
|
||||
_, err := fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType)
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
// Network driver implementation
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
fmt.Fprintf(w, `{"Scope":"local"}`)
|
||||
_, err := fmt.Fprint(w, `{"Scope":"local"}`)
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -79,17 +81,20 @@ func setupRemoteNetworkDrivers(c *testing.T, mux *http.ServeMux, url, netDrv, ip
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
fmt.Fprintf(w, "null")
|
||||
_, err = fmt.Fprint(w, "null")
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
fmt.Fprintf(w, "null")
|
||||
_, err := fmt.Fprint(w, "null")
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`)
|
||||
_, err := fmt.Fprint(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`)
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -99,23 +104,28 @@ func setupRemoteNetworkDrivers(c *testing.T, mux *http.ServeMux, url, netDrv, ip
|
||||
LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0",
|
||||
}
|
||||
if err := netlink.LinkAdd(veth); err != nil {
|
||||
fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`)
|
||||
_, err = fmt.Fprintf(w, `{"Error":"failed to add veth pair: %v"}`, err)
|
||||
assert.NilError(t, err)
|
||||
} else {
|
||||
fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`)
|
||||
_, err = fmt.Fprint(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
fmt.Fprintf(w, "null")
|
||||
_, err := fmt.Fprint(w, "null")
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
if link, err := netlink.LinkByName("cnt0"); err == nil {
|
||||
netlink.LinkDel(link)
|
||||
err = netlink.LinkDel(link)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
fmt.Fprintf(w, "null")
|
||||
_, err := fmt.Fprint(w, "null")
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
// IPAM Driver implementation
|
||||
@@ -124,16 +134,19 @@ func setupRemoteNetworkDrivers(c *testing.T, mux *http.ServeMux, url, netDrv, ip
|
||||
poolReleaseReq remoteipam.ReleasePoolRequest
|
||||
addressRequest remoteipam.RequestAddressRequest
|
||||
addressReleaseReq remoteipam.ReleaseAddressRequest
|
||||
lAS = "localAS"
|
||||
gAS = "globalAS"
|
||||
pool = "172.28.0.0/16"
|
||||
poolID = lAS + "/" + pool
|
||||
gw = "172.28.255.254/16"
|
||||
)
|
||||
const (
|
||||
lAS = "localAS"
|
||||
gAS = "globalAS"
|
||||
pool = "172.28.0.0/16"
|
||||
poolID = lAS + "/" + pool
|
||||
gw = "172.28.255.254/16"
|
||||
)
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`)
|
||||
_, err := fmt.Fprint(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`)
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -144,11 +157,14 @@ func setupRemoteNetworkDrivers(c *testing.T, mux *http.ServeMux, url, netDrv, ip
|
||||
}
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS {
|
||||
fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`)
|
||||
_, err := fmt.Fprint(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`)
|
||||
assert.NilError(t, err)
|
||||
} else if poolRequest.Pool != "" && poolRequest.Pool != pool {
|
||||
fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`)
|
||||
_, err := fmt.Fprint(w, `{"Error":"Cannot handle explicit pool requests yet"}`)
|
||||
assert.NilError(t, err)
|
||||
} else {
|
||||
fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`)
|
||||
_, err := fmt.Fprint(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -161,11 +177,14 @@ func setupRemoteNetworkDrivers(c *testing.T, mux *http.ServeMux, url, netDrv, ip
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
// make sure libnetwork is now querying on the expected pool id
|
||||
if addressRequest.PoolID != poolID {
|
||||
fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
|
||||
_, err := fmt.Fprint(w, `{"Error":"unknown pool id"}`)
|
||||
assert.NilError(t, err)
|
||||
} else if addressRequest.Address != "" {
|
||||
fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`)
|
||||
_, err := fmt.Fprint(w, `{"Error":"Cannot handle explicit address requests yet"}`)
|
||||
assert.NilError(t, err)
|
||||
} else {
|
||||
fmt.Fprintf(w, `{"Address":"`+gw+`"}`)
|
||||
_, err := fmt.Fprint(w, `{"Address":"`+gw+`"}`)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -178,11 +197,14 @@ func setupRemoteNetworkDrivers(c *testing.T, mux *http.ServeMux, url, netDrv, ip
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
// make sure libnetwork is now asking to release the expected address from the expected poolid
|
||||
if addressRequest.PoolID != poolID {
|
||||
fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
|
||||
_, err := fmt.Fprint(w, `{"Error":"unknown pool id"}`)
|
||||
assert.NilError(t, err)
|
||||
} else if addressReleaseReq.Address != gw {
|
||||
fmt.Fprintf(w, `{"Error":"unknown address"}`)
|
||||
_, err := fmt.Fprint(w, `{"Error":"unknown address"}`)
|
||||
assert.NilError(t, err)
|
||||
} else {
|
||||
fmt.Fprintf(w, "null")
|
||||
_, err := fmt.Fprint(w, "null")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -195,22 +217,24 @@ func setupRemoteNetworkDrivers(c *testing.T, mux *http.ServeMux, url, netDrv, ip
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
// make sure libnetwork is now asking to release the expected poolid
|
||||
if addressRequest.PoolID != poolID {
|
||||
fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
|
||||
_, err := fmt.Fprint(w, `{"Error":"unknown pool id"}`)
|
||||
assert.NilError(t, err)
|
||||
} else {
|
||||
fmt.Fprintf(w, "null")
|
||||
_, err := fmt.Fprint(w, "null")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
})
|
||||
|
||||
err := os.MkdirAll("/etc/docker/plugins", 0o755)
|
||||
assert.NilError(c, err)
|
||||
assert.NilError(t, err)
|
||||
|
||||
fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv)
|
||||
err = os.WriteFile(fileName, []byte(url), 0o644)
|
||||
assert.NilError(c, err)
|
||||
assert.NilError(t, err)
|
||||
|
||||
ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv)
|
||||
err = os.WriteFile(ipamFileName, []byte(url), 0o644)
|
||||
assert.NilError(c, err)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func (s *DockerNetworkSuite) TearDownSuite(ctx context.Context, c *testing.T) {
|
||||
@@ -509,9 +533,9 @@ func (s *DockerCLINetworkSuite) TestDockerInspectNetworkWithContainerName(c *tes
|
||||
err := json.Unmarshal([]byte(out), &networkResources)
|
||||
assert.NilError(c, err)
|
||||
assert.Equal(c, len(networkResources), 1)
|
||||
container, ok := networkResources[0].Containers[containerID]
|
||||
ctr, ok := networkResources[0].Containers[containerID]
|
||||
assert.Assert(c, ok)
|
||||
assert.Equal(c, container.Name, "testNetInspect1")
|
||||
assert.Equal(c, ctr.Name, "testNetInspect1")
|
||||
|
||||
// rename container and check docker inspect output update
|
||||
newName := "HappyNewName"
|
||||
@@ -826,12 +850,12 @@ func (s *DockerDaemonSuite) TestDockerNetworkNoDiscoveryDefaultBridgeNetwork(c *
|
||||
assert.NilError(c, err)
|
||||
assert.Equal(c, hosts, hostsPost, fmt.Sprintf("Unexpected %s change on second container creation", hostsFile))
|
||||
// but discovery is on when connecting to non default bridge network
|
||||
network := "anotherbridge"
|
||||
out, err = s.d.Cmd("network", "create", network)
|
||||
nw := "anotherbridge"
|
||||
out, err = s.d.Cmd("network", "create", nw)
|
||||
assert.NilError(c, err, out)
|
||||
defer s.d.Cmd("network", "rm", network)
|
||||
defer s.d.Cmd("network", "rm", nw)
|
||||
|
||||
out, err = s.d.Cmd("network", "connect", network, cid1)
|
||||
out, err = s.d.Cmd("network", "connect", nw, cid1)
|
||||
assert.NilError(c, err, out)
|
||||
|
||||
hosts, err = s.d.Cmd("exec", cid1, "cat", hostsFile)
|
||||
@@ -898,15 +922,15 @@ func (s *DockerNetworkSuite) TestDockerNetworkLinkOnDefaultNetworkOnly(c *testin
|
||||
// Legacy Link feature must work only on default network, and not across networks
|
||||
cnt1 := "container1"
|
||||
cnt2 := "container2"
|
||||
network := "anotherbridge"
|
||||
nw := "anotherbridge"
|
||||
|
||||
// Run first container on default network
|
||||
cli.DockerCmd(c, "run", "-d", "--name", cnt1, "busybox", "top")
|
||||
|
||||
// Create another network and run the second container on it
|
||||
cli.DockerCmd(c, "network", "create", network)
|
||||
assertNwIsAvailable(c, network)
|
||||
cli.DockerCmd(c, "run", "-d", "--net", network, "--name", cnt2, "busybox", "top")
|
||||
cli.DockerCmd(c, "network", "create", nw)
|
||||
assertNwIsAvailable(c, nw)
|
||||
cli.DockerCmd(c, "run", "-d", "--net", nw, "--name", cnt2, "busybox", "top")
|
||||
|
||||
// Try launching a container on default network, linking to the first container. Must succeed
|
||||
cli.DockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt1, cnt1), "busybox", "top")
|
||||
@@ -1727,12 +1751,12 @@ func (s *DockerNetworkSuite) TestDockerNetworkValidateIP(c *testing.T) {
|
||||
// Test case for 26220
|
||||
func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromBridge(c *testing.T) {
|
||||
out := cli.DockerCmd(c, "network", "inspect", "--format", "{{.Id}}", "bridge").Stdout()
|
||||
network := strings.TrimSpace(out)
|
||||
nw := strings.TrimSpace(out)
|
||||
|
||||
name := "test"
|
||||
cli.DockerCmd(c, "create", "--name", name, "busybox", "top")
|
||||
|
||||
_, _, err := dockerCmdWithError("network", "disconnect", network, name)
|
||||
_, _, err := dockerCmdWithError("network", "disconnect", nw, name)
|
||||
assert.NilError(c, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -208,12 +208,7 @@ func (s *DockerCLIPullSuite) TestPullLinuxImageFailsOnWindows(c *testing.T) {
|
||||
testRequires(c, DaemonIsWindows, Network)
|
||||
_, _, err := dockerCmdWithError("pull", "ubuntu")
|
||||
|
||||
errorMessage := "no matching manifest for windows"
|
||||
if testEnv.UsingSnapshotter() {
|
||||
errorMessage = "no match for platform in manifest"
|
||||
}
|
||||
|
||||
assert.ErrorContains(c, err, errorMessage)
|
||||
assert.ErrorContains(c, err, "no matching manifest for windows")
|
||||
}
|
||||
|
||||
// Regression test for https://github.com/docker/docker/issues/28892
|
||||
@@ -221,10 +216,5 @@ func (s *DockerCLIPullSuite) TestPullWindowsImageFailsOnLinux(c *testing.T) {
|
||||
testRequires(c, DaemonIsLinux, Network)
|
||||
_, _, err := dockerCmdWithError("pull", "mcr.microsoft.com/windows/servercore:ltsc2022")
|
||||
|
||||
errorMessage := "no matching manifest for linux"
|
||||
if testEnv.UsingSnapshotter() {
|
||||
errorMessage = "no match for platform in manifest"
|
||||
}
|
||||
|
||||
assert.ErrorContains(c, err, errorMessage)
|
||||
assert.ErrorContains(c, err, "no matching manifest for linux")
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
@@ -251,11 +250,8 @@ func (s *DockerCLIRunSuite) TestRunAttachDetachFromConfig(c *testing.T) {
|
||||
os.Mkdir(dotDocker, 0o600)
|
||||
tmpCfg := filepath.Join(dotDocker, "config.json")
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
c.Setenv("USERPROFILE", tmpDir)
|
||||
} else {
|
||||
c.Setenv("HOME", tmpDir)
|
||||
}
|
||||
// TODO(thaJeztah): migrate this test to docker/cli, and run on Windows as well (using USERPROFILE for home-dir)
|
||||
c.Setenv("HOME", tmpDir)
|
||||
|
||||
data := `{
|
||||
"detachKeys": "ctrl-a,a"
|
||||
@@ -335,11 +331,8 @@ func (s *DockerCLIRunSuite) TestRunAttachDetachKeysOverrideConfig(c *testing.T)
|
||||
os.Mkdir(dotDocker, 0o600)
|
||||
tmpCfg := filepath.Join(dotDocker, "config.json")
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
c.Setenv("USERPROFILE", tmpDir)
|
||||
} else {
|
||||
c.Setenv("HOME", tmpDir)
|
||||
}
|
||||
// TODO(thaJeztah): migrate this test to docker/cli, and run on Windows as well (using USERPROFILE for home-dir)
|
||||
c.Setenv("HOME", tmpDir)
|
||||
|
||||
data := `{
|
||||
"detachKeys": "ctrl-e,e"
|
||||
|
||||
@@ -386,7 +386,8 @@ func (s *DockerSwarmSuite) TestSwarmContainerAttachByNetworkId(c *testing.T) {
|
||||
out, err = d.Cmd("run", "-d", "--net", networkID, "busybox", "top")
|
||||
assert.NilError(c, err, out)
|
||||
cID := strings.TrimSpace(out)
|
||||
d.WaitRun(cID)
|
||||
err = d.WaitRun(cID)
|
||||
assert.NilError(c, err)
|
||||
|
||||
out, err = d.Cmd("rm", "-f", cID)
|
||||
assert.NilError(c, err, out)
|
||||
@@ -640,16 +641,18 @@ const (
|
||||
globalIPAMPlugin = "global-ipam-plugin"
|
||||
)
|
||||
|
||||
func setupRemoteGlobalNetworkPlugin(c *testing.T, mux *http.ServeMux, url, netDrv, ipamDrv string) {
|
||||
func setupRemoteGlobalNetworkPlugin(t *testing.T, mux *http.ServeMux, url, netDrv, ipamDrv string) {
|
||||
mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType)
|
||||
_, err := fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType)
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
// Network driver implementation
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
fmt.Fprintf(w, `{"Scope":"global"}`)
|
||||
_, err := fmt.Fprint(w, `{"Scope":"global"}`)
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.AllocateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -659,12 +662,14 @@ func setupRemoteGlobalNetworkPlugin(c *testing.T, mux *http.ServeMux, url, netDr
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
fmt.Fprintf(w, "null")
|
||||
_, err = fmt.Fprint(w, "null")
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.FreeNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
fmt.Fprintf(w, "null")
|
||||
_, err := fmt.Fprint(w, "null")
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -674,17 +679,20 @@ func setupRemoteGlobalNetworkPlugin(c *testing.T, mux *http.ServeMux, url, netDr
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
fmt.Fprintf(w, "null")
|
||||
_, err = fmt.Fprint(w, "null")
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
fmt.Fprintf(w, "null")
|
||||
_, err := fmt.Fprint(w, "null")
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`)
|
||||
_, err := fmt.Fprint(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`)
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -694,23 +702,28 @@ func setupRemoteGlobalNetworkPlugin(c *testing.T, mux *http.ServeMux, url, netDr
|
||||
LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0",
|
||||
}
|
||||
if err := netlink.LinkAdd(veth); err != nil {
|
||||
fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`)
|
||||
_, err = fmt.Fprint(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`)
|
||||
assert.NilError(t, err)
|
||||
} else {
|
||||
fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`)
|
||||
_, err = fmt.Fprint(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
fmt.Fprintf(w, "null")
|
||||
_, err := fmt.Fprint(w, "null")
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
if link, err := netlink.LinkByName("cnt0"); err == nil {
|
||||
netlink.LinkDel(link)
|
||||
err := netlink.LinkDel(link)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
fmt.Fprintf(w, "null")
|
||||
_, err := fmt.Fprint(w, "null")
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
// IPAM Driver implementation
|
||||
@@ -719,16 +732,19 @@ func setupRemoteGlobalNetworkPlugin(c *testing.T, mux *http.ServeMux, url, netDr
|
||||
poolReleaseReq remoteipam.ReleasePoolRequest
|
||||
addressRequest remoteipam.RequestAddressRequest
|
||||
addressReleaseReq remoteipam.ReleaseAddressRequest
|
||||
lAS = "localAS"
|
||||
gAS = "globalAS"
|
||||
pool = "172.28.0.0/16"
|
||||
poolID = lAS + "/" + pool
|
||||
gw = "172.28.255.254/16"
|
||||
)
|
||||
const (
|
||||
lAS = "localAS"
|
||||
gAS = "globalAS"
|
||||
pool = "172.28.0.0/16"
|
||||
poolID = lAS + "/" + pool
|
||||
gw = "172.28.255.254/16"
|
||||
)
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`)
|
||||
_, err := fmt.Fprint(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`)
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -739,11 +755,14 @@ func setupRemoteGlobalNetworkPlugin(c *testing.T, mux *http.ServeMux, url, netDr
|
||||
}
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS {
|
||||
fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`)
|
||||
_, err := fmt.Fprint(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`)
|
||||
assert.NilError(t, err)
|
||||
} else if poolRequest.Pool != "" && poolRequest.Pool != pool {
|
||||
fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`)
|
||||
_, err := fmt.Fprint(w, `{"Error":"Cannot handle explicit pool requests yet"}`)
|
||||
assert.NilError(t, err)
|
||||
} else {
|
||||
fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`)
|
||||
_, err := fmt.Fprint(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -756,11 +775,14 @@ func setupRemoteGlobalNetworkPlugin(c *testing.T, mux *http.ServeMux, url, netDr
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
// make sure libnetwork is now querying on the expected pool id
|
||||
if addressRequest.PoolID != poolID {
|
||||
fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
|
||||
_, err := fmt.Fprint(w, `{"Error":"unknown pool id"}`)
|
||||
assert.NilError(t, err)
|
||||
} else if addressRequest.Address != "" {
|
||||
fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`)
|
||||
_, err := fmt.Fprint(w, `{"Error":"Cannot handle explicit address requests yet"}`)
|
||||
assert.NilError(t, err)
|
||||
} else {
|
||||
fmt.Fprintf(w, `{"Address":"`+gw+`"}`)
|
||||
_, err := fmt.Fprint(w, `{"Address":"`+gw+`"}`)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -773,11 +795,14 @@ func setupRemoteGlobalNetworkPlugin(c *testing.T, mux *http.ServeMux, url, netDr
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
// make sure libnetwork is now asking to release the expected address from the expected poolid
|
||||
if addressRequest.PoolID != poolID {
|
||||
fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
|
||||
_, err := fmt.Fprint(w, `{"Error":"unknown pool id"}`)
|
||||
assert.NilError(t, err)
|
||||
} else if addressReleaseReq.Address != gw {
|
||||
fmt.Fprintf(w, `{"Error":"unknown address"}`)
|
||||
_, err := fmt.Fprint(w, `{"Error":"unknown address"}`)
|
||||
assert.NilError(t, err)
|
||||
} else {
|
||||
fmt.Fprintf(w, "null")
|
||||
_, err := fmt.Fprint(w, "null")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -790,22 +815,24 @@ func setupRemoteGlobalNetworkPlugin(c *testing.T, mux *http.ServeMux, url, netDr
|
||||
w.Header().Set("Content-Type", plugins.VersionMimetype)
|
||||
// make sure libnetwork is now asking to release the expected poolid
|
||||
if addressRequest.PoolID != poolID {
|
||||
fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
|
||||
_, err := fmt.Fprint(w, `{"Error":"unknown pool id"}`)
|
||||
assert.NilError(t, err)
|
||||
} else {
|
||||
fmt.Fprintf(w, "null")
|
||||
_, err := fmt.Fprint(w, "null")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
})
|
||||
|
||||
err := os.MkdirAll("/etc/docker/plugins", 0o755)
|
||||
assert.NilError(c, err)
|
||||
assert.NilError(t, err)
|
||||
|
||||
fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv)
|
||||
err = os.WriteFile(fileName, []byte(url), 0o644)
|
||||
assert.NilError(c, err)
|
||||
assert.NilError(t, err)
|
||||
|
||||
ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv)
|
||||
err = os.WriteFile(ipamFileName, []byte(url), 0o644)
|
||||
assert.NilError(c, err)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestSwarmNetworkPlugin(c *testing.T) {
|
||||
|
||||
@@ -439,7 +439,7 @@ func pollCheck(t *testing.T, f checkF, compare func(x interface{}) assert.BoolOr
|
||||
default:
|
||||
panic(fmt.Errorf("pollCheck: type %T not implemented", r))
|
||||
}
|
||||
return poll.Continue(comment)
|
||||
return poll.Continue("%v", comment)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ func TestCall(t *testing.T) {
|
||||
assert.Check(t, is.ErrorContains(err, errZ.Error()))
|
||||
assert.Check(t, is.ErrorContains(err, "something happened: "+err2.Error()))
|
||||
|
||||
t.Logf(err.Error())
|
||||
t.Log(err)
|
||||
assert.Assert(t, is.Len(errs, 3))
|
||||
|
||||
// Cleanups executed in reverse order.
|
||||
|
||||
39
internal/testutils/specialimage/textplain.go
Normal file
39
internal/testutils/specialimage/textplain.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package specialimage
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// TextPlain creates an non-container image that only contains a text/plain blob.
|
||||
func TextPlain(dir string) (*ocispec.Index, error) {
|
||||
ref, err := reference.ParseNormalizedNamed("tianon/test:text-plain")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
emptyJsonDesc, err := writeBlob(dir, "text/plain", strings.NewReader("{}"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configDesc := emptyJsonDesc
|
||||
configDesc.MediaType = "application/vnd.oci.empty.v1+json"
|
||||
|
||||
desc, err := writeJsonBlob(dir, ocispec.MediaTypeImageManifest, ocispec.Manifest{
|
||||
Config: configDesc,
|
||||
Layers: []ocispec.Descriptor{
|
||||
emptyJsonDesc,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
desc.Annotations = map[string]string{
|
||||
"io.containerd.image.name": ref.String(),
|
||||
}
|
||||
|
||||
return ociImage(dir, nil, desc)
|
||||
}
|
||||
@@ -199,11 +199,11 @@ func createChainIDFromParent(parent ChainID, dgsts ...DiffID) ChainID {
|
||||
return parent
|
||||
}
|
||||
if parent == "" {
|
||||
return createChainIDFromParent(ChainID(dgsts[0]), dgsts[1:]...)
|
||||
return createChainIDFromParent(ChainID(dgsts[0]), dgsts[1:]...) // #nosec G602 -- slice index out of range, which is a false positive
|
||||
}
|
||||
// H = "H(n-1) SHA256(n)"
|
||||
dgst := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0])))
|
||||
return createChainIDFromParent(ChainID(dgst), dgsts[1:]...)
|
||||
dgst := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0]))) // #nosec G602 -- slice index out of range, which is a false positive
|
||||
return createChainIDFromParent(ChainID(dgst), dgsts[1:]...) // #nosec G602 -- slice index out of range, which is a false positive
|
||||
}
|
||||
|
||||
// ReleaseAndLog releases the provided layer from the given layer
|
||||
|
||||
@@ -40,7 +40,7 @@ func initIPAMDrivers(r ipamapi.Registerer, netConfig *networkallocator.Config) e
|
||||
}
|
||||
|
||||
if len(addressPool) > 0 {
|
||||
log.G(context.TODO()).Infof("Swarm initialized global default address pool to: " + str.String())
|
||||
log.G(context.TODO()).Info("Swarm initialized global default address pool to: " + str.String())
|
||||
}
|
||||
|
||||
if err := ipams.Register(r, nil, nil, addressPool); err != nil {
|
||||
|
||||
@@ -1046,7 +1046,7 @@ func (c *Controller) loadDriver(networkType string) error {
|
||||
|
||||
if err != nil {
|
||||
if errors.Cause(err) == plugins.ErrNotFound {
|
||||
return types.NotFoundErrorf(err.Error())
|
||||
return types.NotFoundErrorf("%v", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1065,7 +1065,7 @@ func (c *Controller) loadIPAMDriver(name string) error {
|
||||
|
||||
if err != nil {
|
||||
if errors.Cause(err) == plugins.ErrNotFound {
|
||||
return types.NotFoundErrorf(err.Error())
|
||||
return types.NotFoundErrorf("%v", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -382,7 +382,7 @@ func setINC(version iptables.IPVersion, iface string, enable bool) error {
|
||||
log.G(context.TODO()).Warnf("Failed to rollback iptables rule after failure (%v): %v", err, err2)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf(msg)
|
||||
return errors.New(msg)
|
||||
}
|
||||
log.G(context.TODO()).Warn(msg)
|
||||
}
|
||||
|
||||
@@ -4,18 +4,14 @@ package libnetwork
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/libnetwork/resolvconf"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/skip"
|
||||
)
|
||||
|
||||
func TestDNSOptions(t *testing.T) {
|
||||
skip.If(t, runtime.GOOS == "windows", "test only works on linux")
|
||||
|
||||
c, err := New(OptionBoltdbWithRandomDBFile(t))
|
||||
assert.NilError(t, err)
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ func processReturn(r io.Reader) error {
|
||||
return fmt.Errorf("failed to read buf in processReturn : %v", err)
|
||||
}
|
||||
if string(buf[0:n]) != success {
|
||||
return fmt.Errorf(string(buf[0:n]))
|
||||
return fmt.Errorf("%s", buf[0:n])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -35,7 +35,9 @@ man%:
|
||||
|
||||
.PHONY: install
|
||||
install: all
|
||||
@set -ex; \
|
||||
for sec in $(sections); do \
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man$$sec && \
|
||||
$(INSTALL_DATA) man$$sec/* $(DESTDIR)$(mandir)/man$$sec; \
|
||||
done
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ require (
|
||||
github.com/morikuni/aec v1.0.0
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/opencontainers/image-spec v1.1.0
|
||||
github.com/opencontainers/runc v1.1.13
|
||||
github.com/opencontainers/runc v1.1.14
|
||||
github.com/opencontainers/runtime-spec v1.2.0
|
||||
github.com/opencontainers/selinux v1.11.0
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
|
||||
@@ -531,8 +531,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
github.com/opencontainers/runc v1.1.13 h1:98S2srgG9vw0zWcDpFMn5TRrh8kLxa/5OFUstuUhmRs=
|
||||
github.com/opencontainers/runc v1.1.13/go.mod h1:R016aXacfp/gwQBYw2FDGa9m+n6atbLWrYY8hNMT/sA=
|
||||
github.com/opencontainers/runc v1.1.14 h1:rgSuzbmgz5DUJjeSnw337TxDbRuqjs6iqQck/2weR6w=
|
||||
github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
|
||||
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
|
||||
145
vendor/github.com/opencontainers/runc/libcontainer/system/linux.go
generated
vendored
Normal file
145
vendor/github.com/opencontainers/runc/libcontainer/system/linux.go
generated
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type ParentDeathSignal int
|
||||
|
||||
func (p ParentDeathSignal) Restore() error {
|
||||
if p == 0 {
|
||||
return nil
|
||||
}
|
||||
current, err := GetParentDeathSignal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if p == current {
|
||||
return nil
|
||||
}
|
||||
return p.Set()
|
||||
}
|
||||
|
||||
func (p ParentDeathSignal) Set() error {
|
||||
return SetParentDeathSignal(uintptr(p))
|
||||
}
|
||||
|
||||
// Deprecated: Execv is not used in runc anymore, it will be removed in v1.2.0.
|
||||
func Execv(cmd string, args []string, env []string) error {
|
||||
name, err := exec.LookPath(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return Exec(name, args, env)
|
||||
}
|
||||
|
||||
func Exec(cmd string, args []string, env []string) error {
|
||||
for {
|
||||
err := unix.Exec(cmd, args, env)
|
||||
if err != unix.EINTR { //nolint:errorlint // unix errors are bare
|
||||
return &os.PathError{Op: "exec", Path: cmd, Err: err}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SetParentDeathSignal(sig uintptr) error {
|
||||
if err := unix.Prctl(unix.PR_SET_PDEATHSIG, sig, 0, 0, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetParentDeathSignal() (ParentDeathSignal, error) {
|
||||
var sig int
|
||||
if err := unix.Prctl(unix.PR_GET_PDEATHSIG, uintptr(unsafe.Pointer(&sig)), 0, 0, 0); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return ParentDeathSignal(sig), nil
|
||||
}
|
||||
|
||||
func SetKeepCaps() error {
|
||||
if err := unix.Prctl(unix.PR_SET_KEEPCAPS, 1, 0, 0, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ClearKeepCaps() error {
|
||||
if err := unix.Prctl(unix.PR_SET_KEEPCAPS, 0, 0, 0, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Setctty() error {
|
||||
if err := unix.IoctlSetInt(0, unix.TIOCSCTTY, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetSubreaper sets the value i as the subreaper setting for the calling process
|
||||
func SetSubreaper(i int) error {
|
||||
return unix.Prctl(unix.PR_SET_CHILD_SUBREAPER, uintptr(i), 0, 0, 0)
|
||||
}
|
||||
|
||||
// GetSubreaper returns the subreaper setting for the calling process
|
||||
func GetSubreaper() (int, error) {
|
||||
var i uintptr
|
||||
|
||||
if err := unix.Prctl(unix.PR_GET_CHILD_SUBREAPER, uintptr(unsafe.Pointer(&i)), 0, 0, 0); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
return int(i), nil
|
||||
}
|
||||
|
||||
func prepareAt(dir *os.File, path string) (int, string) {
|
||||
if dir == nil {
|
||||
return unix.AT_FDCWD, path
|
||||
}
|
||||
|
||||
// Rather than just filepath.Join-ing path here, do it manually so the
|
||||
// error and handle correctly indicate cases like path=".." as being
|
||||
// relative to the correct directory. The handle.Name() might end up being
|
||||
// wrong but because this is (currently) only used in MkdirAllInRoot, that
|
||||
// isn't a problem.
|
||||
dirName := dir.Name()
|
||||
if !strings.HasSuffix(dirName, "/") {
|
||||
dirName += "/"
|
||||
}
|
||||
fullPath := dirName + path
|
||||
|
||||
return int(dir.Fd()), fullPath
|
||||
}
|
||||
|
||||
func Openat(dir *os.File, path string, flags int, mode uint32) (*os.File, error) {
|
||||
dirFd, fullPath := prepareAt(dir, path)
|
||||
fd, err := unix.Openat(dirFd, path, flags, mode)
|
||||
if err != nil {
|
||||
return nil, &os.PathError{Op: "openat", Path: fullPath, Err: err}
|
||||
}
|
||||
runtime.KeepAlive(dir)
|
||||
return os.NewFile(uintptr(fd), fullPath), nil
|
||||
}
|
||||
|
||||
func Mkdirat(dir *os.File, path string, mode uint32) error {
|
||||
dirFd, fullPath := prepareAt(dir, path)
|
||||
err := unix.Mkdirat(dirFd, path, mode)
|
||||
if err != nil {
|
||||
err = &os.PathError{Op: "mkdirat", Path: fullPath, Err: err}
|
||||
}
|
||||
runtime.KeepAlive(dir)
|
||||
return err
|
||||
}
|
||||
127
vendor/github.com/opencontainers/runc/libcontainer/system/proc.go
generated
vendored
Normal file
127
vendor/github.com/opencontainers/runc/libcontainer/system/proc.go
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// State is the status of a process.
|
||||
type State rune
|
||||
|
||||
const ( // Only values for Linux 3.14 and later are listed here
|
||||
Dead State = 'X'
|
||||
DiskSleep State = 'D'
|
||||
Running State = 'R'
|
||||
Sleeping State = 'S'
|
||||
Stopped State = 'T'
|
||||
TracingStop State = 't'
|
||||
Zombie State = 'Z'
|
||||
Parked State = 'P'
|
||||
Idle State = 'I'
|
||||
)
|
||||
|
||||
// String forms of the state from proc(5)'s documentation for
|
||||
// /proc/[pid]/status' "State" field.
|
||||
func (s State) String() string {
|
||||
switch s {
|
||||
case Dead:
|
||||
return "dead"
|
||||
case DiskSleep:
|
||||
return "disk sleep"
|
||||
case Running:
|
||||
return "running"
|
||||
case Sleeping:
|
||||
return "sleeping"
|
||||
case Stopped:
|
||||
return "stopped"
|
||||
case TracingStop:
|
||||
return "tracing stop"
|
||||
case Zombie:
|
||||
return "zombie"
|
||||
case Parked:
|
||||
return "parked"
|
||||
case Idle:
|
||||
return "idle" // kernel thread
|
||||
default:
|
||||
return fmt.Sprintf("unknown (%c)", s)
|
||||
}
|
||||
}
|
||||
|
||||
// Stat_t represents the information from /proc/[pid]/stat, as
|
||||
// described in proc(5) with names based on the /proc/[pid]/status
|
||||
// fields.
|
||||
type Stat_t struct {
|
||||
// Name is the command run by the process.
|
||||
Name string
|
||||
|
||||
// State is the state of the process.
|
||||
State State
|
||||
|
||||
// StartTime is the number of clock ticks after system boot (since
|
||||
// Linux 2.6).
|
||||
StartTime uint64
|
||||
}
|
||||
|
||||
// Stat returns a Stat_t instance for the specified process.
|
||||
func Stat(pid int) (stat Stat_t, err error) {
|
||||
bytes, err := os.ReadFile(filepath.Join("/proc", strconv.Itoa(pid), "stat"))
|
||||
if err != nil {
|
||||
return stat, err
|
||||
}
|
||||
return parseStat(string(bytes))
|
||||
}
|
||||
|
||||
func parseStat(data string) (stat Stat_t, err error) {
|
||||
// Example:
|
||||
// 89653 (gunicorn: maste) S 89630 89653 89653 0 -1 4194560 29689 28896 0 3 146 32 76 19 20 0 1 0 2971844 52965376 3920 18446744073709551615 1 1 0 0 0 0 0 16781312 137447943 0 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
// The fields are space-separated, see full description in proc(5).
|
||||
//
|
||||
// We are only interested in:
|
||||
// * field 2: process name. It is the only field enclosed into
|
||||
// parenthesis, as it can contain spaces (and parenthesis) inside.
|
||||
// * field 3: process state, a single character (%c)
|
||||
// * field 22: process start time, a long unsigned integer (%llu).
|
||||
|
||||
// 1. Look for the first '(' and the last ')' first, what's in between is Name.
|
||||
// We expect at least 20 fields and a space after the last one.
|
||||
|
||||
const minAfterName = 20*2 + 1 // the min field is '0 '.
|
||||
|
||||
first := strings.IndexByte(data, '(')
|
||||
if first < 0 || first+minAfterName >= len(data) {
|
||||
return stat, fmt.Errorf("invalid stat data (no comm or too short): %q", data)
|
||||
}
|
||||
|
||||
last := strings.LastIndexByte(data, ')')
|
||||
if last <= first || last+minAfterName >= len(data) {
|
||||
return stat, fmt.Errorf("invalid stat data (no comm or too short): %q", data)
|
||||
}
|
||||
|
||||
stat.Name = data[first+1 : last]
|
||||
|
||||
// 2. Remove fields 1 and 2 and a space after. State is right after.
|
||||
data = data[last+2:]
|
||||
stat.State = State(data[0])
|
||||
|
||||
// 3. StartTime is field 22, data is at field 3 now, so we need to skip 19 spaces.
|
||||
skipSpaces := 22 - 3
|
||||
for first = 0; skipSpaces > 0 && first < len(data); first++ {
|
||||
if data[first] == ' ' {
|
||||
skipSpaces--
|
||||
}
|
||||
}
|
||||
// Now first points to StartTime; look for space right after.
|
||||
i := strings.IndexByte(data[first:], ' ')
|
||||
if i < 0 {
|
||||
return stat, fmt.Errorf("invalid stat data (too short): %q", data)
|
||||
}
|
||||
stat.StartTime, err = strconv.ParseUint(data[first:first+i], 10, 64)
|
||||
if err != nil {
|
||||
return stat, fmt.Errorf("invalid stat data (bad start time): %w", err)
|
||||
}
|
||||
|
||||
return stat, nil
|
||||
}
|
||||
15
vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_linux.go
generated
vendored
Normal file
15
vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_linux.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
//go:build go1.23
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// ClearRlimitNofileCache clears go runtime's nofile rlimit cache. The argument
|
||||
// is process RLIMIT_NOFILE values. Relies on go.dev/cl/588076.
|
||||
func ClearRlimitNofileCache(lim *syscall.Rlimit) {
|
||||
// Ignore the return values since we only need to clean the cache,
|
||||
// the limit is going to be set via unix.Prlimit elsewhere.
|
||||
_ = syscall.Setrlimit(syscall.RLIMIT_NOFILE, lim)
|
||||
}
|
||||
27
vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_linux_go122.go
generated
vendored
Normal file
27
vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_linux_go122.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
//go:build go1.19 && !go1.23
|
||||
|
||||
// TODO: remove this file once go 1.22 is no longer supported.
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
_ "unsafe" // Needed for go:linkname to work.
|
||||
)
|
||||
|
||||
//go:linkname syscallOrigRlimitNofile syscall.origRlimitNofile
|
||||
var syscallOrigRlimitNofile atomic.Pointer[syscall.Rlimit]
|
||||
|
||||
// ClearRlimitNofileCache clears go runtime's nofile rlimit cache.
|
||||
// The argument is process RLIMIT_NOFILE values.
|
||||
func ClearRlimitNofileCache(_ *syscall.Rlimit) {
|
||||
// As reported in issue #4195, the new version of go runtime(since 1.19)
|
||||
// will cache rlimit-nofile. Before executing execve, the rlimit-nofile
|
||||
// of the process will be restored with the cache. In runc, this will
|
||||
// cause the rlimit-nofile setting by the parent process for the container
|
||||
// to become invalid. It can be solved by clearing this cache. But
|
||||
// unfortunately, go stdlib doesn't provide such function, so we need to
|
||||
// link to the private var `origRlimitNofile` in package syscall to hack.
|
||||
syscallOrigRlimitNofile.Store(nil)
|
||||
}
|
||||
7
vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_stub.go
generated
vendored
Normal file
7
vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_stub.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build !go1.19
|
||||
|
||||
package system
|
||||
|
||||
import "syscall"
|
||||
|
||||
func ClearRlimitNofileCache(_ *syscall.Rlimit) {}
|
||||
27
vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_32.go
generated
vendored
Normal file
27
vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_32.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
//go:build linux && (386 || arm)
|
||||
// +build linux
|
||||
// +build 386 arm
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Setuid sets the uid of the calling thread to the specified uid.
|
||||
func Setuid(uid int) (err error) {
|
||||
_, _, e1 := unix.RawSyscall(unix.SYS_SETUID32, uintptr(uid), 0, 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Setgid sets the gid of the calling thread to the specified gid.
|
||||
func Setgid(gid int) (err error) {
|
||||
_, _, e1 := unix.RawSyscall(unix.SYS_SETGID32, uintptr(gid), 0, 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
27
vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_64.go
generated
vendored
Normal file
27
vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_64.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
//go:build linux && (arm64 || amd64 || mips || mipsle || mips64 || mips64le || ppc || ppc64 || ppc64le || riscv64 || s390x)
|
||||
// +build linux
|
||||
// +build arm64 amd64 mips mipsle mips64 mips64le ppc ppc64 ppc64le riscv64 s390x
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Setuid sets the uid of the calling thread to the specified uid.
|
||||
func Setuid(uid int) (err error) {
|
||||
_, _, e1 := unix.RawSyscall(unix.SYS_SETUID, uintptr(uid), 0, 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Setgid sets the gid of the calling thread to the specified gid.
|
||||
func Setgid(gid int) (err error) {
|
||||
_, _, e1 := unix.RawSyscall(unix.SYS_SETGID, uintptr(gid), 0, 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
129
vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go
generated
vendored
129
vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go
generated
vendored
@@ -4,11 +4,17 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
_ "unsafe" // for go:linkname
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/system"
|
||||
|
||||
securejoin "github.com/cyphar/filepath-securejoin"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
@@ -115,3 +121,126 @@ func NewSockPair(name string) (parent *os.File, child *os.File, err error) {
|
||||
}
|
||||
return os.NewFile(uintptr(fds[1]), name+"-p"), os.NewFile(uintptr(fds[0]), name+"-c"), nil
|
||||
}
|
||||
|
||||
// IsLexicallyInRoot is shorthand for strings.HasPrefix(path+"/", root+"/"),
|
||||
// but properly handling the case where path or root are "/".
|
||||
//
|
||||
// NOTE: The return value only make sense if the path doesn't contain "..".
|
||||
func IsLexicallyInRoot(root, path string) bool {
|
||||
if root != "/" {
|
||||
root += "/"
|
||||
}
|
||||
if path != "/" {
|
||||
path += "/"
|
||||
}
|
||||
return strings.HasPrefix(path, root)
|
||||
}
|
||||
|
||||
// MkdirAllInRootOpen attempts to make
|
||||
//
|
||||
// path, _ := securejoin.SecureJoin(root, unsafePath)
|
||||
// os.MkdirAll(path, mode)
|
||||
// os.Open(path)
|
||||
//
|
||||
// safer against attacks where components in the path are changed between
|
||||
// SecureJoin returning and MkdirAll (or Open) being called. In particular, we
|
||||
// try to detect any symlink components in the path while we are doing the
|
||||
// MkdirAll.
|
||||
//
|
||||
// NOTE: Unlike os.MkdirAll, mode is not Go's os.FileMode, it is the unix mode
|
||||
// (the suid/sgid/sticky bits are not the same as for os.FileMode).
|
||||
//
|
||||
// NOTE: If unsafePath is a subpath of root, we assume that you have already
|
||||
// called SecureJoin and so we use the provided path verbatim without resolving
|
||||
// any symlinks (this is done in a way that avoids symlink-exchange races).
|
||||
// This means that the path also must not contain ".." elements, otherwise an
|
||||
// error will occur.
|
||||
//
|
||||
// This is a somewhat less safe alternative to
|
||||
// <https://github.com/cyphar/filepath-securejoin/pull/13>, but it should
|
||||
// detect attempts to trick us into creating directories outside of the root.
|
||||
// We should migrate to securejoin.MkdirAll once it is merged.
|
||||
func MkdirAllInRootOpen(root, unsafePath string, mode uint32) (_ *os.File, Err error) {
|
||||
// If the path is already "within" the root, use it verbatim.
|
||||
fullPath := unsafePath
|
||||
if !IsLexicallyInRoot(root, unsafePath) {
|
||||
var err error
|
||||
fullPath, err = securejoin.SecureJoin(root, unsafePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
subPath, err := filepath.Rel(root, fullPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check for any silly mode bits.
|
||||
if mode&^0o7777 != 0 {
|
||||
return nil, fmt.Errorf("tried to include non-mode bits in MkdirAll mode: 0o%.3o", mode)
|
||||
}
|
||||
|
||||
currentDir, err := os.OpenFile(root, unix.O_DIRECTORY|unix.O_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open root handle: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
if Err != nil {
|
||||
currentDir.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
for _, part := range strings.Split(subPath, string(filepath.Separator)) {
|
||||
switch part {
|
||||
case "", ".":
|
||||
// Skip over no-op components.
|
||||
continue
|
||||
case "..":
|
||||
return nil, fmt.Errorf("possible breakout detected: found %q component in SecureJoin subpath %s", part, subPath)
|
||||
}
|
||||
|
||||
nextDir, err := system.Openat(currentDir, part, unix.O_DIRECTORY|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0)
|
||||
switch {
|
||||
case err == nil:
|
||||
// Update the currentDir.
|
||||
_ = currentDir.Close()
|
||||
currentDir = nextDir
|
||||
|
||||
case errors.Is(err, unix.ENOTDIR):
|
||||
// This might be a symlink or some other random file. Either way,
|
||||
// error out.
|
||||
return nil, fmt.Errorf("cannot mkdir in %s/%s: %w", currentDir.Name(), part, unix.ENOTDIR)
|
||||
|
||||
case errors.Is(err, os.ErrNotExist):
|
||||
// Luckily, mkdirat will not follow trailing symlinks, so this is
|
||||
// safe to do as-is.
|
||||
if err := system.Mkdirat(currentDir, part, mode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Open the new directory. There is a race here where an attacker
|
||||
// could swap the directory with a different directory, but
|
||||
// MkdirAll's fuzzy semantics mean we don't care about that.
|
||||
nextDir, err := system.Openat(currentDir, part, unix.O_DIRECTORY|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open newly created directory: %w", err)
|
||||
}
|
||||
// Update the currentDir.
|
||||
_ = currentDir.Close()
|
||||
currentDir = nextDir
|
||||
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return currentDir, nil
|
||||
}
|
||||
|
||||
// MkdirAllInRoot is a wrapper around MkdirAllInRootOpen which closes the
|
||||
// returned handle, for callers that don't need to use it.
|
||||
func MkdirAllInRoot(root, unsafePath string, mode uint32) error {
|
||||
f, err := MkdirAllInRootOpen(root, unsafePath, mode)
|
||||
if err == nil {
|
||||
_ = f.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
3
vendor/modules.txt
vendored
3
vendor/modules.txt
vendored
@@ -997,11 +997,12 @@ github.com/opencontainers/go-digest/digestset
|
||||
github.com/opencontainers/image-spec/identity
|
||||
github.com/opencontainers/image-spec/specs-go
|
||||
github.com/opencontainers/image-spec/specs-go/v1
|
||||
# github.com/opencontainers/runc v1.1.13
|
||||
# github.com/opencontainers/runc v1.1.14
|
||||
## explicit; go 1.18
|
||||
github.com/opencontainers/runc/libcontainer/cgroups
|
||||
github.com/opencontainers/runc/libcontainer/configs
|
||||
github.com/opencontainers/runc/libcontainer/devices
|
||||
github.com/opencontainers/runc/libcontainer/system
|
||||
github.com/opencontainers/runc/libcontainer/user
|
||||
github.com/opencontainers/runc/libcontainer/userns
|
||||
github.com/opencontainers/runc/libcontainer/utils
|
||||
|
||||
@@ -95,7 +95,7 @@ func (d *FakeDriver) Name() string { return d.name }
|
||||
// It returns an error if the options include an "error" key with a message
|
||||
func (d *FakeDriver) Create(name string, opts map[string]string) (volume.Volume, error) {
|
||||
if opts != nil && opts["error"] != "" {
|
||||
return nil, fmt.Errorf(opts["error"])
|
||||
return nil, errors.New(opts["error"])
|
||||
}
|
||||
v := NewFakeVolume(name, d.name)
|
||||
d.vols[name] = v
|
||||
@@ -105,7 +105,7 @@ func (d *FakeDriver) Create(name string, opts map[string]string) (volume.Volume,
|
||||
// Remove deletes a volume.
|
||||
func (d *FakeDriver) Remove(v volume.Volume) error {
|
||||
if _, exists := d.vols[v.Name()]; !exists {
|
||||
return fmt.Errorf("no such volume")
|
||||
return errors.New("no such volume")
|
||||
}
|
||||
delete(d.vols, v.Name())
|
||||
return nil
|
||||
@@ -125,7 +125,7 @@ func (d *FakeDriver) Get(name string) (volume.Volume, error) {
|
||||
if v, exists := d.vols[name]; exists {
|
||||
return v, nil
|
||||
}
|
||||
return nil, fmt.Errorf("no such volume")
|
||||
return nil, errors.New("no such volume")
|
||||
}
|
||||
|
||||
// Scope returns the local scope
|
||||
|
||||
Reference in New Issue
Block a user