mirror of
https://github.com/moby/moby.git
synced 2026-01-13 20:48:05 +00:00
Compare commits
178 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ab5c7d003 | ||
|
|
875e8aeef2 | ||
|
|
1900e4d8eb | ||
|
|
cd7746d30b | ||
|
|
2a13a384b8 | ||
|
|
9fd71f5d0e | ||
|
|
ecd2b6ff09 | ||
|
|
d5b03423d1 | ||
|
|
56c5c23114 | ||
|
|
77b2eb5734 | ||
|
|
805becdc7e | ||
|
|
a5828ac742 | ||
|
|
f7246a0e2c | ||
|
|
f110e779f6 | ||
|
|
edbcbf8da7 | ||
|
|
b7cc16b0b0 | ||
|
|
ecbc4f05bb | ||
|
|
43298ad298 | ||
|
|
8cc7f26f56 | ||
|
|
255eaa6647 | ||
|
|
ee27f4cd7f | ||
|
|
c1d3c952e7 | ||
|
|
fc9029a2e2 | ||
|
|
115b10a467 | ||
|
|
488872bcb4 | ||
|
|
f623030fac | ||
|
|
ac7032bff9 | ||
|
|
161006302f | ||
|
|
a6de17d230 | ||
|
|
6513e80c84 | ||
|
|
3d917f3fd6 | ||
|
|
e854a5c201 | ||
|
|
ea58dab95e | ||
|
|
0a38589add | ||
|
|
7c069d3021 | ||
|
|
b27de4ef16 | ||
|
|
5002faebe8 | ||
|
|
a15a309832 | ||
|
|
fd5cede287 | ||
|
|
c050bc3739 | ||
|
|
de22458d0f | ||
|
|
65c4e49aff | ||
|
|
7ebb277873 | ||
|
|
9942d656ba | ||
|
|
ad5eb875d4 | ||
|
|
3d845e0e8c | ||
|
|
3563a707d0 | ||
|
|
89757f83ff | ||
|
|
bb2fec6425 | ||
|
|
0f8fcec1d9 | ||
|
|
1a342adda7 | ||
|
|
1ec5e86154 | ||
|
|
62f32e9a97 | ||
|
|
68484b732a | ||
|
|
830c76c6f2 | ||
|
|
8f969bf61c | ||
|
|
290663ede5 | ||
|
|
354bf75675 | ||
|
|
4ab7d90669 | ||
|
|
c11b2d9c7d | ||
|
|
ccdc79d55a | ||
|
|
35b1a30028 | ||
|
|
9f63aa7435 | ||
|
|
4d16ac993e | ||
|
|
6d5266a650 | ||
|
|
4084dac566 | ||
|
|
c36ab4c2ca | ||
|
|
904867593b | ||
|
|
72876770d0 | ||
|
|
e8109ee4da | ||
|
|
ed65e1224e | ||
|
|
d54aff9312 | ||
|
|
8f12906274 | ||
|
|
5955778fe3 | ||
|
|
c53be2f3d5 | ||
|
|
f9522e5e96 | ||
|
|
a037b7250c | ||
|
|
fc0150b962 | ||
|
|
73c01d0b6a | ||
|
|
c93fe4a27d | ||
|
|
31459c8268 | ||
|
|
35d430c62e | ||
|
|
f5fa0908ef | ||
|
|
a17f5d4f10 | ||
|
|
80a59c2f1a | ||
|
|
95db7055cc | ||
|
|
e7fe276c00 | ||
|
|
e8cd19e810 | ||
|
|
45d37a0ca9 | ||
|
|
e0c52e0ba6 | ||
|
|
b9be986e35 | ||
|
|
efb67b16b0 | ||
|
|
741e23b913 | ||
|
|
f96e26f68d | ||
|
|
78b59867f2 | ||
|
|
7d861e889c | ||
|
|
17e1108324 | ||
|
|
018137b01a | ||
|
|
650e06ac75 | ||
|
|
7f5494dc97 | ||
|
|
bfe5339c7e | ||
|
|
a4046c4ca0 | ||
|
|
99471ac2fe | ||
|
|
b9b43b3bdf | ||
|
|
cc13f95251 | ||
|
|
a21b1a2d12 | ||
|
|
1bc907c97c | ||
|
|
4bb4575ffb | ||
|
|
df7f275db6 | ||
|
|
1c0885d60d | ||
|
|
fb3ec9fc96 | ||
|
|
ed83a9e3a1 | ||
|
|
71b59bf442 | ||
|
|
f8f926b719 | ||
|
|
422ef48c2f | ||
|
|
c9d37a9198 | ||
|
|
1f16a44b3d | ||
|
|
c8f1317585 | ||
|
|
68587c38fe | ||
|
|
d1ea2b1fec | ||
|
|
31c1b7dc17 | ||
|
|
6231ea4a34 | ||
|
|
dc33eb81d8 | ||
|
|
51433d65c0 | ||
|
|
f3bd9da62a | ||
|
|
bc6ae42031 | ||
|
|
af8866f324 | ||
|
|
5e4ddd81a2 | ||
|
|
147eaae6b7 | ||
|
|
c7e4d181a1 | ||
|
|
3d7e824bc2 | ||
|
|
d66b76d2e6 | ||
|
|
0e678a85d7 | ||
|
|
3db1544179 | ||
|
|
03dc388f63 | ||
|
|
5ee23b6050 | ||
|
|
53c521a6b2 | ||
|
|
eccccd7577 | ||
|
|
d9e3d1b815 | ||
|
|
b91e20cc2e | ||
|
|
505be6557b | ||
|
|
b1613dc2a1 | ||
|
|
52f6163746 | ||
|
|
c70e404e9e | ||
|
|
d7a3f01421 | ||
|
|
0f2f9e0049 | ||
|
|
45a1c34202 | ||
|
|
7b31435cf8 | ||
|
|
99df4fee0b | ||
|
|
9f08d1e357 | ||
|
|
d1bbb61844 | ||
|
|
0835eaa5a1 | ||
|
|
73ce798d3b | ||
|
|
b039de78d7 | ||
|
|
7fa33a539a | ||
|
|
7d99ebe418 | ||
|
|
e7e0428218 | ||
|
|
540b29c0c6 | ||
|
|
662f78c0b1 | ||
|
|
b86d9bdaf3 | ||
|
|
0dbc3ac59e | ||
|
|
276a648ec3 | ||
|
|
22aa07b28f | ||
|
|
23b8b023dd | ||
|
|
bf222d635b | ||
|
|
f8231b52d3 | ||
|
|
b951474404 | ||
|
|
c5794e23ec | ||
|
|
02e24483be | ||
|
|
b70040a8fc | ||
|
|
838330bac3 | ||
|
|
e419e22f29 | ||
|
|
e953d76450 | ||
|
|
861fde8cc9 | ||
|
|
3557077867 | ||
|
|
c95b917167 | ||
|
|
c0ff08acbd | ||
|
|
4587688258 |
9
.github/workflows/.dco.yml
vendored
9
.github/workflows/.dco.yml
vendored
@@ -3,6 +3,15 @@ name: .dco
|
||||
|
||||
# TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
|
||||
9
.github/workflows/.test-prepare.yml
vendored
9
.github/workflows/.test-prepare.yml
vendored
@@ -3,6 +3,15 @@ name: .test-prepare
|
||||
|
||||
# TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
outputs:
|
||||
|
||||
11
.github/workflows/.test.yml
vendored
11
.github/workflows/.test.yml
vendored
@@ -3,6 +3,15 @@ name: .test
|
||||
|
||||
# TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
@@ -12,7 +21,7 @@ on:
|
||||
default: "graphdriver"
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.21.9"
|
||||
GO_VERSION: "1.21.13"
|
||||
GOTESTLIST_VERSION: v0.3.1
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
ITG_CLI_MATRIX_SIZE: 6
|
||||
|
||||
11
.github/workflows/.windows.yml
vendored
11
.github/workflows/.windows.yml
vendored
@@ -3,6 +3,15 @@ name: .windows
|
||||
|
||||
# TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
@@ -19,7 +28,7 @@ on:
|
||||
default: false
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.21.11"
|
||||
GO_VERSION: "1.21.13"
|
||||
GOTESTLIST_VERSION: v0.3.1
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore
|
||||
|
||||
9
.github/workflows/bin-image.yml
vendored
9
.github/workflows/bin-image.yml
vendored
@@ -1,5 +1,14 @@
|
||||
name: bin-image
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
11
.github/workflows/buildkit.yml
vendored
11
.github/workflows/buildkit.yml
vendored
@@ -1,5 +1,14 @@
|
||||
name: buildkit
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
@@ -13,7 +22,7 @@ on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.21.11"
|
||||
GO_VERSION: "1.21.13"
|
||||
DESTDIR: ./build
|
||||
SETUP_BUILDX_VERSION: latest
|
||||
SETUP_BUILDKIT_IMAGE: moby/buildkit:latest
|
||||
|
||||
41
.github/workflows/ci.yml
vendored
41
.github/workflows/ci.yml
vendored
@@ -1,5 +1,14 @@
|
||||
name: ci
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
@@ -121,3 +130,35 @@ jobs:
|
||||
name: Check artifacts
|
||||
run: |
|
||||
find ${{ env.DESTDIR }} -type f -exec file -e ascii -- {} +
|
||||
|
||||
govulncheck:
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
# required to write sarif report
|
||||
security-events: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Run
|
||||
uses: docker/bake-action@v5
|
||||
with:
|
||||
targets: govulncheck
|
||||
env:
|
||||
GOVULNCHECK_FORMAT: sarif
|
||||
-
|
||||
name: Upload SARIF report
|
||||
if: ${{ github.event_name != 'pull_request' && github.repository == 'moby/moby' }}
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: ${{ env.DESTDIR }}/govulncheck.out
|
||||
|
||||
11
.github/workflows/test.yml
vendored
11
.github/workflows/test.yml
vendored
@@ -1,5 +1,14 @@
|
||||
name: test
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
@@ -13,7 +22,7 @@ on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.21.11"
|
||||
GO_VERSION: "1.21.13"
|
||||
GIT_PAGER: "cat"
|
||||
PAGER: "cat"
|
||||
SETUP_BUILDX_VERSION: latest
|
||||
|
||||
27
.github/workflows/validate-pr.yml
vendored
27
.github/workflows/validate-pr.yml
vendored
@@ -1,5 +1,14 @@
|
||||
name: validate-pr
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, edited, labeled, unlabeled]
|
||||
@@ -53,10 +62,16 @@ jobs:
|
||||
# Backports or PR that target a release branch directly should mention the target branch in the title, for example:
|
||||
# [X.Y backport] Some change that needs backporting to X.Y
|
||||
# [X.Y] Change directly targeting the X.Y branch
|
||||
- name: Get branch from PR title
|
||||
id: title_branch
|
||||
run: echo "$PR_TITLE" | sed -n 's/^\[\([0-9]*\.[0-9]*\)[^]]*\].*/branch=\1/p' >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Check release branch
|
||||
if: github.event.pull_request.base.ref != steps.title_branch.outputs.branch && !(github.event.pull_request.base.ref == 'master' && steps.title_branch.outputs.branch == '')
|
||||
run: echo "::error::PR title suggests targetting the ${{ steps.title_branch.outputs.branch }} branch, but is opened against ${{ github.event.pull_request.base.ref }}" && exit 1
|
||||
id: title_branch
|
||||
run: |
|
||||
# get the intended major version prefix ("[27.1 backport]" -> "27.") from the PR title.
|
||||
[[ "$PR_TITLE" =~ ^\[([0-9]*\.)[^]]*\] ]] && branch="${BASH_REMATCH[1]}"
|
||||
|
||||
# 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"
|
||||
|
||||
if [[ "$target_branch" != "$branch" ]] && ! [[ "$GITHUB_BASE_REF" == "master" && "$branch" == "" ]]; then
|
||||
echo "::error::PR is opened against the $GITHUB_BASE_REF branch, but its title suggests otherwise."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
9
.github/workflows/windows-2019.yml
vendored
9
.github/workflows/windows-2019.yml
vendored
@@ -1,5 +1,14 @@
|
||||
name: windows-2019
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
9
.github/workflows/windows-2022.yml
vendored
9
.github/workflows/windows-2022.yml
vendored
@@ -1,5 +1,14 @@
|
||||
name: windows-2022
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
@@ -57,10 +57,14 @@ linters-settings:
|
||||
desc: Use "gotest.tools/v3/assert" instead
|
||||
- pkg: "github.com/stretchr/testify/suite"
|
||||
desc: Do not use
|
||||
- pkg: github.com/containerd/containerd/errdefs
|
||||
- pkg: "github.com/containerd/containerd/errdefs"
|
||||
desc: The errdefs package has moved to a separate module, https://github.com/containerd/errdefs
|
||||
- pkg: github.com/containerd/containerd/log
|
||||
- pkg: "github.com/containerd/containerd/log"
|
||||
desc: The logs package has moved to a separate module, https://github.com/containerd/log
|
||||
- pkg: "github.com/containerd/containerd/pkg/userns"
|
||||
desc: Use github.com/moby/sys/userns instead.
|
||||
- pkg: "github.com/opencontainers/runc/libcontainer/userns"
|
||||
desc: Use github.com/moby/sys/userns instead.
|
||||
revive:
|
||||
rules:
|
||||
# FIXME make sure all packages have a description. Currently, there's many packages without.
|
||||
|
||||
14
Dockerfile
14
Dockerfile
@@ -1,19 +1,19 @@
|
||||
# syntax=docker/dockerfile:1.7
|
||||
|
||||
ARG GO_VERSION=1.21.11
|
||||
ARG GO_VERSION=1.21.13
|
||||
ARG BASE_DEBIAN_DISTRO="bookworm"
|
||||
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"
|
||||
ARG XX_VERSION=1.4.0
|
||||
ARG XX_VERSION=1.5.0
|
||||
|
||||
ARG VPNKIT_VERSION=0.5.0
|
||||
|
||||
ARG DOCKERCLI_REPOSITORY="https://github.com/docker/cli.git"
|
||||
ARG DOCKERCLI_VERSION=v26.1.0
|
||||
ARG DOCKERCLI_VERSION=v27.0.2
|
||||
# cli version used for integration-cli tests
|
||||
ARG DOCKERCLI_INTEGRATION_REPOSITORY="https://github.com/docker/cli.git"
|
||||
ARG DOCKERCLI_INTEGRATION_VERSION=v17.06.2-ce
|
||||
ARG BUILDX_VERSION=0.15.1
|
||||
ARG COMPOSE_VERSION=v2.27.1
|
||||
ARG BUILDX_VERSION=0.16.1
|
||||
ARG COMPOSE_VERSION=v2.29.0
|
||||
|
||||
ARG SYSTEMD="false"
|
||||
ARG DOCKER_STATIC=1
|
||||
@@ -196,7 +196,7 @@ RUN git init . && git remote add origin "https://github.com/containerd/container
|
||||
# When updating the binary version you may also need to update the vendor
|
||||
# version to pick up bug fixes or new APIs, however, usually the Go packages
|
||||
# are built from a commit from the master branch.
|
||||
ARG CONTAINERD_VERSION=v1.7.18
|
||||
ARG CONTAINERD_VERSION=v1.7.21
|
||||
RUN git fetch -q --depth 1 origin "${CONTAINERD_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
|
||||
|
||||
FROM base AS containerd-build
|
||||
@@ -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.55.2
|
||||
ARG GOLANGCI_LINT_VERSION=v1.59.1
|
||||
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}" \
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
# This represents the bare minimum required to build and test Docker.
|
||||
|
||||
ARG GO_VERSION=1.21.11
|
||||
ARG GO_VERSION=1.21.13
|
||||
|
||||
ARG BASE_DEBIAN_DISTRO="bookworm"
|
||||
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"
|
||||
|
||||
@@ -161,10 +161,10 @@ 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.11
|
||||
ARG GO_VERSION=1.21.13
|
||||
ARG GOTESTSUM_VERSION=v1.8.2
|
||||
ARG GOWINRES_VERSION=v0.3.1
|
||||
ARG CONTAINERD_VERSION=v1.7.18
|
||||
ARG CONTAINERD_VERSION=v1.7.21
|
||||
|
||||
# Environment variable notes:
|
||||
# - GO_VERSION must be consistent with 'Dockerfile' used by Linux.
|
||||
|
||||
@@ -32,7 +32,7 @@ New projects can be added if they fit with the community goals. Docker is commit
|
||||
However, other projects are also encouraged to use Moby as an upstream, and to reuse the components in diverse ways, and all these uses will be treated in the same way. External maintainers and contributors are welcomed.
|
||||
|
||||
The Moby project is not intended as a location for support or feature requests for Docker products, but as a place for contributors to work on open source code, fix bugs, and make the code more useful.
|
||||
The releases are supported by the maintainers, community and users, on a best efforts basis only, and are not intended for customers who want enterprise or commercial support; Docker EE is the appropriate product for these use cases.
|
||||
The releases are supported by the maintainers, community and users, on a best efforts basis only. For customers who want enterprise or commercial support, [Docker Desktop](https://www.docker.com/products/docker-desktop/) and [Mirantis Container Runtime](https://www.mirantis.com/software/mirantis-container-runtime/) are the appropriate products for these use cases.
|
||||
|
||||
-----
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package api // import "github.com/docker/docker/api"
|
||||
// Common constants for daemon and client.
|
||||
const (
|
||||
// DefaultVersion of the current REST API.
|
||||
DefaultVersion = "1.46"
|
||||
DefaultVersion = "1.47"
|
||||
|
||||
// MinSupportedAPIVersion is the minimum API version that can be supported
|
||||
// by the API server, specified as "major.minor". Note that the daemon
|
||||
|
||||
@@ -88,11 +88,9 @@ func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string
|
||||
}
|
||||
}
|
||||
|
||||
if !useBuildKit {
|
||||
stdout := config.ProgressWriter.StdoutFormatter
|
||||
fmt.Fprintf(stdout, "Successfully built %s\n", stringid.TruncateID(imageID))
|
||||
}
|
||||
if imageID != "" && !useBuildKit {
|
||||
stdout := config.ProgressWriter.StdoutFormatter
|
||||
_, _ = fmt.Fprintf(stdout, "Successfully built %s\n", stringid.TruncateID(imageID))
|
||||
err = tagImages(ctx, b.imageComponent, config.ProgressWriter.StdoutFormatter, image.ID(imageID), tags)
|
||||
}
|
||||
return imageID, err
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/docker/errdefs"
|
||||
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/docker/api/server/httpstatus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
@@ -769,12 +769,14 @@ func handleSysctlBC(
|
||||
netIfSysctl := fmt.Sprintf("net.%s.%s.IFNAME.%s=%s", spl[1], spl[2], spl[4], v)
|
||||
// Find the EndpointConfig to migrate settings to, if not already found.
|
||||
if ep == nil {
|
||||
/* TODO(robmry) - apply this to the API version used in 28.0.0
|
||||
// Per-endpoint sysctls were introduced in API version 1.46. Migration is
|
||||
// needed, but refuse to do it automatically for newer versions of the API.
|
||||
if versions.GreaterThan(version, "1.46") {
|
||||
if versions.GreaterThan(version, "1.??") {
|
||||
return "", fmt.Errorf("interface specific sysctl setting %q must be supplied using driver option '%s'",
|
||||
k, netlabel.EndpointSysctls)
|
||||
}
|
||||
*/
|
||||
var err error
|
||||
ep, err = epConfigForNetMode(version, hostConfig.NetworkMode, netConfig)
|
||||
if err != nil {
|
||||
|
||||
@@ -273,15 +273,17 @@ func TestHandleSysctlBC(t *testing.T) {
|
||||
"net.ipv6.conf.all.disable_ipv6": "0",
|
||||
},
|
||||
},
|
||||
/* TODO(robmry) - enable this test for the API version used in 28.0.0
|
||||
{
|
||||
name: "migration disabled for newer api",
|
||||
apiVersion: "1.47",
|
||||
apiVersion: "1.??",
|
||||
networkMode: "mynet",
|
||||
sysctls: map[string]string{
|
||||
"net.ipv6.conf.eth0.accept_ra": "2",
|
||||
},
|
||||
expError: "must be supplied using driver option 'com.docker.network.endpoint.sysctls'",
|
||||
},
|
||||
*/
|
||||
{
|
||||
name: "only migrate eth0",
|
||||
apiVersion: "1.46",
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/defaults"
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/moby/buildkit/util/grpcerrors"
|
||||
@@ -32,6 +33,8 @@ func NewRouter(backends ...Backend) router.Router {
|
||||
grpc.StatsHandler(tracing.ServerStatsHandler(otelgrpc.WithTracerProvider(otel.GetTracerProvider()))),
|
||||
grpc.ChainUnaryInterceptor(unaryInterceptor, grpcerrors.UnaryServerInterceptor),
|
||||
grpc.StreamInterceptor(grpcerrors.StreamServerInterceptor),
|
||||
grpc.MaxRecvMsgSize(defaults.DefaultMaxRecvMsgSize),
|
||||
grpc.MaxSendMsgSize(defaults.DefaultMaxSendMsgSize),
|
||||
}
|
||||
|
||||
r := &grpcRouter{
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
@@ -220,7 +220,6 @@ func (ir *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter
|
||||
}
|
||||
platform = p
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if err := ir.backend.PushImage(ctx, ref, platform, metaHeaders, authConfig, output); err != nil {
|
||||
@@ -424,10 +423,16 @@ func (ir *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
|
||||
sharedSize = httputils.BoolValue(r, "shared-size")
|
||||
}
|
||||
|
||||
var manifests bool
|
||||
if versions.GreaterThanOrEqualTo(version, "1.47") {
|
||||
manifests = httputils.BoolValue(r, "manifests")
|
||||
}
|
||||
|
||||
images, err := ir.backend.Images(ctx, imagetypes.ListOptions{
|
||||
All: httputils.BoolValue(r, "all"),
|
||||
Filters: imageFilters,
|
||||
SharedSize: sharedSize,
|
||||
Manifests: manifests,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -151,5 +151,4 @@ func adjustForAPIVersion(cliVersion string, service *swarm.ServiceSpec) {
|
||||
service.TaskTemplate.ContainerSpec.OomScoreAdj = 0
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ func TestAdjustForAPIVersion(t *testing.T) {
|
||||
Target: "/bar",
|
||||
TmpfsOptions: &mount.TmpfsOptions{
|
||||
Options: [][]string{
|
||||
[]string{"exec"},
|
||||
{"exec"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -73,7 +73,7 @@ func TestAdjustForAPIVersion(t *testing.T) {
|
||||
adjustForAPIVersion("1.46", spec)
|
||||
if !reflect.DeepEqual(
|
||||
spec.TaskTemplate.ContainerSpec.Mounts[0].TmpfsOptions.Options,
|
||||
[][]string{[]string{"exec"}},
|
||||
[][]string{{"exec"}},
|
||||
) {
|
||||
t.Error("TmpfsOptions.Options was stripped from spec")
|
||||
}
|
||||
|
||||
@@ -81,7 +81,6 @@ func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *ht
|
||||
nameOnly = append(nameOnly, so.Name)
|
||||
}
|
||||
info.SecurityOptions = nameOnly
|
||||
info.ExecutionDriver = "<not supported>" //nolint:staticcheck // ignore SA1019 (ExecutionDriver is deprecated)
|
||||
}
|
||||
if versions.LessThan(version, "1.39") {
|
||||
if info.KernelVersion == "" {
|
||||
|
||||
148
api/swagger.yaml
148
api/swagger.yaml
@@ -19,10 +19,10 @@ produces:
|
||||
consumes:
|
||||
- "application/json"
|
||||
- "text/plain"
|
||||
basePath: "/v1.46"
|
||||
basePath: "/v1.47"
|
||||
info:
|
||||
title: "Docker Engine API"
|
||||
version: "1.46"
|
||||
version: "1.47"
|
||||
x-logo:
|
||||
url: "https://docs.docker.com/assets/images/logo-docker-main.png"
|
||||
description: |
|
||||
@@ -55,8 +55,8 @@ info:
|
||||
the URL is not supported by the daemon, a HTTP `400 Bad Request` error message
|
||||
is returned.
|
||||
|
||||
If you omit the version-prefix, the current version of the API (v1.46) is used.
|
||||
For example, calling `/info` is the same as calling `/v1.46/info`. Using the
|
||||
If you omit the version-prefix, the current version of the API (v1.47) is used.
|
||||
For example, calling `/info` is the same as calling `/v1.47/info`. Using the
|
||||
API without a version-prefix is deprecated and will be removed in a future release.
|
||||
|
||||
Engine releases in the near future should support this version of the API,
|
||||
@@ -2265,6 +2265,19 @@ definitions:
|
||||
x-nullable: false
|
||||
type: "integer"
|
||||
example: 2
|
||||
Manifests:
|
||||
description: |
|
||||
Manifests is a list of manifests available in this image.
|
||||
It provides a more detailed view of the platform-specific image manifests
|
||||
or other image-attached data like build attestations.
|
||||
|
||||
WARNING: This is experimental and may change at any time without any backward
|
||||
compatibility.
|
||||
type: "array"
|
||||
x-nullable: false
|
||||
x-omitempty: true
|
||||
items:
|
||||
$ref: "#/definitions/ImageManifestSummary"
|
||||
|
||||
AuthConfig:
|
||||
type: "object"
|
||||
@@ -5318,7 +5331,7 @@ definitions:
|
||||
description: |
|
||||
The default (and highest) API version that is supported by the daemon
|
||||
type: "string"
|
||||
example: "1.46"
|
||||
example: "1.47"
|
||||
MinAPIVersion:
|
||||
description: |
|
||||
The minimum API version that is supported by the daemon
|
||||
@@ -5334,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.11"
|
||||
example: "go1.21.13"
|
||||
Os:
|
||||
description: |
|
||||
The operating system that the daemon is running on ("linux" or "windows")
|
||||
@@ -5830,13 +5843,13 @@ definitions:
|
||||
- "/var/run/cdi"
|
||||
Containerd:
|
||||
$ref: "#/definitions/ContainerdInfo"
|
||||
x-nullable: true
|
||||
|
||||
ContainerdInfo:
|
||||
description: |
|
||||
Information for connecting to the containerd instance that is used by the daemon.
|
||||
This is included for debugging purposes only.
|
||||
type: "object"
|
||||
x-nullable: true
|
||||
properties:
|
||||
Address:
|
||||
description: "The address of the containerd socket."
|
||||
@@ -6644,6 +6657,120 @@ definitions:
|
||||
additionalProperties:
|
||||
type: "string"
|
||||
|
||||
ImageManifestSummary:
|
||||
x-go-name: "ManifestSummary"
|
||||
description: |
|
||||
ImageManifestSummary represents a summary of an image manifest.
|
||||
type: "object"
|
||||
required: ["ID", "Descriptor", "Available", "Size", "Kind"]
|
||||
properties:
|
||||
ID:
|
||||
description: |
|
||||
ID is the content-addressable ID of an image and is the same as the
|
||||
digest of the image manifest.
|
||||
type: "string"
|
||||
example: "sha256:95869fbcf224d947ace8d61d0e931d49e31bb7fc67fffbbe9c3198c33aa8e93f"
|
||||
Descriptor:
|
||||
$ref: "#/definitions/OCIDescriptor"
|
||||
Available:
|
||||
description: Indicates whether all the child content (image config, layers) is fully available locally.
|
||||
type: "boolean"
|
||||
example: true
|
||||
Size:
|
||||
type: "object"
|
||||
x-nullable: false
|
||||
required: ["Content", "Total"]
|
||||
properties:
|
||||
Total:
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
example: 8213251
|
||||
description: |
|
||||
Total is the total size (in bytes) of all the locally present
|
||||
data (both distributable and non-distributable) that's related to
|
||||
this manifest and its children.
|
||||
This equal to the sum of [Content] size AND all the sizes in the
|
||||
[Size] struct present in the Kind-specific data struct.
|
||||
For example, for an image kind (Kind == "image")
|
||||
this would include the size of the image content and unpacked
|
||||
image snapshots ([Size.Content] + [ImageData.Size.Unpacked]).
|
||||
Content:
|
||||
description: |
|
||||
Content is the size (in bytes) of all the locally present
|
||||
content in the content store (e.g. image config, layers)
|
||||
referenced by this manifest and its children.
|
||||
This only includes blobs in the content store.
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
example: 3987495
|
||||
Kind:
|
||||
type: "string"
|
||||
example: "image"
|
||||
enum:
|
||||
- "image"
|
||||
- "attestation"
|
||||
- "unknown"
|
||||
description: |
|
||||
The kind of the manifest.
|
||||
|
||||
kind | description
|
||||
-------------|-----------------------------------------------------------
|
||||
image | Image manifest that can be used to start a container.
|
||||
attestation | Attestation manifest produced by the Buildkit builder for a specific image manifest.
|
||||
ImageData:
|
||||
description: |
|
||||
The image data for the image manifest.
|
||||
This field is only populated when Kind is "image".
|
||||
type: "object"
|
||||
x-nullable: true
|
||||
x-omitempty: true
|
||||
required: ["Platform", "Containers", "Size", "UnpackedSize"]
|
||||
properties:
|
||||
Platform:
|
||||
$ref: "#/definitions/OCIPlatform"
|
||||
description: |
|
||||
OCI platform of the image. This will be the platform specified in the
|
||||
manifest descriptor from the index/manifest list.
|
||||
If it's not available, it will be obtained from the image config.
|
||||
Containers:
|
||||
description: |
|
||||
The IDs of the containers that are using this image.
|
||||
type: "array"
|
||||
items:
|
||||
type: "string"
|
||||
example: ["ede54ee1fda366ab42f824e8a5ffd195155d853ceaec74a927f249ea270c7430", "abadbce344c096744d8d6071a90d474d28af8f1034b5ea9fb03c3f4bfc6d005e"]
|
||||
Size:
|
||||
type: "object"
|
||||
x-nullable: false
|
||||
required: ["Unpacked"]
|
||||
properties:
|
||||
Unpacked:
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
example: 3987495
|
||||
description: |
|
||||
Unpacked is the size (in bytes) of the locally unpacked
|
||||
(uncompressed) image content that's directly usable by the containers
|
||||
running this image.
|
||||
It's independent of the distributable content - e.g.
|
||||
the image might still have an unpacked data that's still used by
|
||||
some container even when the distributable/compressed content is
|
||||
already gone.
|
||||
AttestationData:
|
||||
description: |
|
||||
The image data for the attestation manifest.
|
||||
This field is only populated when Kind is "attestation".
|
||||
type: "object"
|
||||
x-nullable: true
|
||||
x-omitempty: true
|
||||
required: ["For"]
|
||||
properties:
|
||||
For:
|
||||
description: |
|
||||
The digest of the image manifest that this attestation is for.
|
||||
type: "string"
|
||||
example: "sha256:95869fbcf224d947ace8d61d0e931d49e31bb7fc67fffbbe9c3198c33aa8e93f"
|
||||
|
||||
paths:
|
||||
/containers/json:
|
||||
get:
|
||||
@@ -8622,6 +8749,11 @@ paths:
|
||||
description: "Show digest information as a `RepoDigests` field on each image."
|
||||
type: "boolean"
|
||||
default: false
|
||||
- name: "manifests"
|
||||
in: "query"
|
||||
description: "Include `Manifests` in the image summary."
|
||||
type: "boolean"
|
||||
default: false
|
||||
tags: ["Image"]
|
||||
/build:
|
||||
post:
|
||||
@@ -9563,7 +9695,7 @@ paths:
|
||||
|
||||
Containers report these events: `attach`, `commit`, `copy`, `create`, `destroy`, `detach`, `die`, `exec_create`, `exec_detach`, `exec_start`, `exec_die`, `export`, `health_status`, `kill`, `oom`, `pause`, `rename`, `resize`, `restart`, `start`, `stop`, `top`, `unpause`, `update`, and `prune`
|
||||
|
||||
Images report these events: `create, `delete`, `import`, `load`, `pull`, `push`, `save`, `tag`, `untag`, and `prune`
|
||||
Images report these events: `create`, `delete`, `import`, `load`, `pull`, `push`, `save`, `tag`, `untag`, and `prune`
|
||||
|
||||
Volumes report these events: `create`, `mount`, `unmount`, `destroy`, and `prune`
|
||||
|
||||
|
||||
99
api/types/image/manifest.go
Normal file
99
api/types/image/manifest.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package image
|
||||
|
||||
import (
|
||||
"github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
type ManifestKind string
|
||||
|
||||
const (
|
||||
ManifestKindImage ManifestKind = "image"
|
||||
ManifestKindAttestation ManifestKind = "attestation"
|
||||
ManifestKindUnknown ManifestKind = "unknown"
|
||||
)
|
||||
|
||||
type ManifestSummary struct {
|
||||
// ID is the content-addressable ID of an image and is the same as the
|
||||
// digest of the image manifest.
|
||||
//
|
||||
// Required: true
|
||||
ID string `json:"ID"`
|
||||
|
||||
// Descriptor is the OCI descriptor of the image.
|
||||
//
|
||||
// Required: true
|
||||
Descriptor ocispec.Descriptor `json:"Descriptor"`
|
||||
|
||||
// Indicates whether all the child content (image config, layers) is
|
||||
// fully available locally
|
||||
//
|
||||
// Required: true
|
||||
Available bool `json:"Available"`
|
||||
|
||||
// Size is the size information of the content related to this manifest.
|
||||
// Note: These sizes only take the locally available content into account.
|
||||
//
|
||||
// Required: true
|
||||
Size struct {
|
||||
// Content is the size (in bytes) of all the locally present
|
||||
// content in the content store (e.g. image config, layers)
|
||||
// referenced by this manifest and its children.
|
||||
// This only includes blobs in the content store.
|
||||
Content int64 `json:"Content"`
|
||||
|
||||
// Total is the total size (in bytes) of all the locally present
|
||||
// data (both distributable and non-distributable) that's related to
|
||||
// this manifest and its children.
|
||||
// This equal to the sum of [Content] size AND all the sizes in the
|
||||
// [Size] struct present in the Kind-specific data struct.
|
||||
// For example, for an image kind (Kind == ManifestKindImage),
|
||||
// this would include the size of the image content and unpacked
|
||||
// image snapshots ([Size.Content] + [ImageData.Size.Unpacked]).
|
||||
Total int64 `json:"Total"`
|
||||
} `json:"Size"`
|
||||
|
||||
// Kind is the kind of the image manifest.
|
||||
//
|
||||
// Required: true
|
||||
Kind ManifestKind `json:"Kind"`
|
||||
|
||||
// Fields below are specific to the kind of the image manifest.
|
||||
|
||||
// Present only if Kind == ManifestKindImage.
|
||||
ImageData *ImageProperties `json:"ImageData,omitempty"`
|
||||
|
||||
// Present only if Kind == ManifestKindAttestation.
|
||||
AttestationData *AttestationProperties `json:"AttestationData,omitempty"`
|
||||
}
|
||||
|
||||
type ImageProperties struct {
|
||||
// Platform is the OCI platform object describing the platform of the image.
|
||||
//
|
||||
// Required: true
|
||||
Platform ocispec.Platform `json:"Platform"`
|
||||
|
||||
Size struct {
|
||||
// Unpacked is the size (in bytes) of the locally unpacked
|
||||
// (uncompressed) image content that's directly usable by the containers
|
||||
// running this image.
|
||||
// It's independent of the distributable content - e.g.
|
||||
// the image might still have an unpacked data that's still used by
|
||||
// some container even when the distributable/compressed content is
|
||||
// already gone.
|
||||
//
|
||||
// Required: true
|
||||
Unpacked int64 `json:"Unpacked"`
|
||||
}
|
||||
|
||||
// Containers is an array containing the IDs of the containers that are
|
||||
// using this image.
|
||||
//
|
||||
// Required: true
|
||||
Containers []string `json:"Containers"`
|
||||
}
|
||||
|
||||
type AttestationProperties struct {
|
||||
// For is the digest of the image manifest that this attestation is for.
|
||||
For digest.Digest `json:"For"`
|
||||
}
|
||||
@@ -76,6 +76,9 @@ type ListOptions struct {
|
||||
|
||||
// ContainerCount indicates whether container count should be computed.
|
||||
ContainerCount bool
|
||||
|
||||
// Manifests indicates whether the image manifests should be returned.
|
||||
Manifests bool
|
||||
}
|
||||
|
||||
// RemoveOptions holds parameters to remove images.
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
package image
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
// Summary summary
|
||||
// swagger:model Summary
|
||||
type Summary struct {
|
||||
|
||||
// Number of containers using this image. Includes both stopped and running
|
||||
@@ -47,6 +42,14 @@ type Summary struct {
|
||||
// Required: true
|
||||
ParentID string `json:"ParentId"`
|
||||
|
||||
// Manifests is a list of image manifests available in this image. It
|
||||
// provides a more detailed view of the platform-specific image manifests or
|
||||
// other image-attached data like build attestations.
|
||||
//
|
||||
// WARNING: This is experimental and may change at any time without any backward
|
||||
// compatibility.
|
||||
Manifests []ManifestSummary `json:"Manifests,omitempty"`
|
||||
|
||||
// List of content-addressable digests of locally available image manifests
|
||||
// that the image is referenced from. Multiple manifests can refer to the
|
||||
// same image.
|
||||
|
||||
@@ -102,7 +102,6 @@ func TestEndpointIPAMConfigWithOutOfRangeAddrs(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestEndpointIPAMConfigWithInvalidConfig(t *testing.T) {
|
||||
|
||||
@@ -34,10 +34,9 @@ type AuthConfig struct {
|
||||
}
|
||||
|
||||
// EncodeAuthConfig serializes the auth configuration as a base64url encoded
|
||||
// RFC4648, section 5) JSON string for sending through the X-Registry-Auth header.
|
||||
// ([RFC4648, section 5]) JSON string for sending through the X-Registry-Auth header.
|
||||
//
|
||||
// For details on base64url encoding, see:
|
||||
// - RFC4648, section 5: https://tools.ietf.org/html/rfc4648#section-5
|
||||
// [RFC4648, section 5]: https://tools.ietf.org/html/rfc4648#section-5
|
||||
func EncodeAuthConfig(authConfig AuthConfig) (string, error) {
|
||||
buf, err := json.Marshal(authConfig)
|
||||
if err != nil {
|
||||
@@ -46,15 +45,14 @@ func EncodeAuthConfig(authConfig AuthConfig) (string, error) {
|
||||
return base64.URLEncoding.EncodeToString(buf), nil
|
||||
}
|
||||
|
||||
// DecodeAuthConfig decodes base64url encoded (RFC4648, section 5) JSON
|
||||
// DecodeAuthConfig decodes base64url encoded ([RFC4648, section 5]) JSON
|
||||
// authentication information as sent through the X-Registry-Auth header.
|
||||
//
|
||||
// This function always returns an AuthConfig, even if an error occurs. It is up
|
||||
// This function always returns an [AuthConfig], even if an error occurs. It is up
|
||||
// to the caller to decide if authentication is required, and if the error can
|
||||
// be ignored.
|
||||
//
|
||||
// For details on base64url encoding, see:
|
||||
// - RFC4648, section 5: https://tools.ietf.org/html/rfc4648#section-5
|
||||
// [RFC4648, section 5]: https://tools.ietf.org/html/rfc4648#section-5
|
||||
func DecodeAuthConfig(authEncoded string) (*AuthConfig, error) {
|
||||
if authEncoded == "" {
|
||||
return &AuthConfig{}, nil
|
||||
@@ -69,7 +67,7 @@ func DecodeAuthConfig(authEncoded string) (*AuthConfig, error) {
|
||||
// clients and API versions. Current clients and API versions expect authentication
|
||||
// to be provided through the X-Registry-Auth header.
|
||||
//
|
||||
// Like DecodeAuthConfig, this function always returns an AuthConfig, even if an
|
||||
// Like [DecodeAuthConfig], this function always returns an [AuthConfig], even if an
|
||||
// error occurs. It is up to the caller to decide if authentication is required,
|
||||
// and if the error can be ignored.
|
||||
func DecodeAuthConfigBody(rdr io.ReadCloser) (*AuthConfig, error) {
|
||||
|
||||
@@ -77,9 +77,6 @@ type Info struct {
|
||||
|
||||
Containerd *ContainerdInfo `json:",omitempty"`
|
||||
|
||||
// Legacy API fields for older API versions.
|
||||
legacyFields
|
||||
|
||||
// Warnings contains a slice of warnings that occurred while collecting
|
||||
// system information. These warnings are intended to be informational
|
||||
// messages for the user, and are not intended to be parsed / used for
|
||||
@@ -124,10 +121,6 @@ type ContainerdNamespaces struct {
|
||||
Plugins string
|
||||
}
|
||||
|
||||
type legacyFields struct {
|
||||
ExecutionDriver string `json:",omitempty"` // Deprecated: deprecated since API v1.25, but returned for older versions.
|
||||
}
|
||||
|
||||
// PluginsInfo is a temp struct holding Plugins name
|
||||
// registered with docker daemon. It is used by [Info] struct
|
||||
type PluginsInfo struct {
|
||||
|
||||
@@ -245,18 +245,6 @@ type ContainerState struct {
|
||||
Health *Health `json:",omitempty"`
|
||||
}
|
||||
|
||||
// ContainerNode stores information about the node that a container
|
||||
// is running on. It's only used by the Docker Swarm standalone API
|
||||
type ContainerNode struct {
|
||||
ID string
|
||||
IPAddress string `json:"IP"`
|
||||
Addr string
|
||||
Name string
|
||||
Cpus int
|
||||
Memory int64
|
||||
Labels map[string]string
|
||||
}
|
||||
|
||||
// ContainerJSONBase contains response of Engine API:
|
||||
// GET "/containers/{name:.*}/json"
|
||||
type ContainerJSONBase struct {
|
||||
@@ -270,7 +258,7 @@ type ContainerJSONBase struct {
|
||||
HostnamePath string
|
||||
HostsPath string
|
||||
LogPath string
|
||||
Node *ContainerNode `json:",omitempty"` // Node is only propagated by Docker Swarm standalone API
|
||||
Node *ContainerNode `json:",omitempty"` // Deprecated: Node was only propagated by Docker Swarm standalone API. It sill be removed in the next release.
|
||||
Name string
|
||||
RestartCount int
|
||||
Driver string
|
||||
|
||||
@@ -194,3 +194,17 @@ type ImageImportSource image.ImportSource
|
||||
//
|
||||
// Deprecated: use [image.LoadResponse].
|
||||
type ImageLoadResponse = image.LoadResponse
|
||||
|
||||
// ContainerNode stores information about the node that a container
|
||||
// is running on. It's only used by the Docker Swarm standalone API.
|
||||
//
|
||||
// Deprecated: ContainerNode was used for the classic Docker Swarm standalone API. It will be removed in the next release.
|
||||
type ContainerNode struct {
|
||||
ID string
|
||||
IPAddress string `json:"IP"`
|
||||
Addr string
|
||||
Name string
|
||||
Cpus int
|
||||
Memory int64
|
||||
Labels map[string]string
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
"github.com/containerd/containerd/gc"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/leases"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
cdreference "github.com/containerd/containerd/reference"
|
||||
ctdreference "github.com/containerd/containerd/reference"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
@@ -26,6 +25,7 @@ import (
|
||||
"github.com/containerd/containerd/remotes/docker/schema1" //nolint:staticcheck // Ignore SA1019: "github.com/containerd/containerd/remotes/docker/schema1" is deprecated: use images formatted in Docker Image Manifest v2, Schema 2, or OCI Image Spec v1.
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
distreference "github.com/distribution/reference"
|
||||
dimages "github.com/docker/docker/daemon/images"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
@@ -77,24 +77,24 @@ var cacheFields = map[string]bool{
|
||||
|
||||
// Opt is option struct required for creating the builder
|
||||
type Opt struct {
|
||||
SessionManager *session.Manager
|
||||
Root string
|
||||
EngineID string
|
||||
Dist images.DistributionServices
|
||||
ImageTagger mobyexporter.ImageTagger
|
||||
NetworkController *libnetwork.Controller
|
||||
DefaultCgroupParent string
|
||||
RegistryHosts docker.RegistryHosts
|
||||
BuilderConfig config.BuilderConfig
|
||||
Rootless bool
|
||||
IdentityMapping idtools.IdentityMapping
|
||||
DNSConfig config.DNSConfig
|
||||
ApparmorProfile string
|
||||
UseSnapshotter bool
|
||||
Snapshotter string
|
||||
ContainerdAddress string
|
||||
ContainerdNamespace string
|
||||
ImageExportedCallback exporter.ImageExportedByBuildkit
|
||||
SessionManager *session.Manager
|
||||
Root string
|
||||
EngineID string
|
||||
Dist images.DistributionServices
|
||||
ImageTagger mobyexporter.ImageTagger
|
||||
NetworkController *libnetwork.Controller
|
||||
DefaultCgroupParent string
|
||||
RegistryHosts docker.RegistryHosts
|
||||
BuilderConfig config.BuilderConfig
|
||||
Rootless bool
|
||||
IdentityMapping idtools.IdentityMapping
|
||||
DNSConfig config.DNSConfig
|
||||
ApparmorProfile string
|
||||
UseSnapshotter bool
|
||||
Snapshotter string
|
||||
ContainerdAddress string
|
||||
ContainerdNamespace string
|
||||
Callbacks exporter.BuildkitCallbacks
|
||||
}
|
||||
|
||||
// Builder can build using BuildKit backend
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
ctd "github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/content/local"
|
||||
ctdmetadata "github.com/containerd/containerd/metadata"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/builder/builder-next/adapters/containerimage"
|
||||
@@ -109,11 +109,22 @@ func newSnapshotterController(ctx context.Context, rt http.RoundTripper, opt Opt
|
||||
|
||||
dns := getDNSConfig(opt.DNSConfig)
|
||||
|
||||
wo, err := containerd.NewWorkerOpt(opt.Root, opt.ContainerdAddress, opt.Snapshotter, opt.ContainerdNamespace,
|
||||
opt.Rootless, map[string]string{
|
||||
workerOpts := containerd.WorkerOptions{
|
||||
Root: opt.Root,
|
||||
Address: opt.ContainerdAddress,
|
||||
SnapshotterName: opt.Snapshotter,
|
||||
Namespace: opt.ContainerdNamespace,
|
||||
Rootless: opt.Rootless,
|
||||
Labels: map[string]string{
|
||||
label.Snapshotter: opt.Snapshotter,
|
||||
}, dns, nc, opt.ApparmorProfile, false, nil, "", nil, ctd.WithTimeout(60*time.Second),
|
||||
)
|
||||
},
|
||||
DNS: dns,
|
||||
NetworkOpt: nc,
|
||||
ApparmorProfile: opt.ApparmorProfile,
|
||||
Selinux: false,
|
||||
}
|
||||
|
||||
wo, err := containerd.NewWorkerOpt(workerOpts, ctd.WithTimeout(60*time.Second))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -138,7 +149,7 @@ func newSnapshotterController(ctx context.Context, rt http.RoundTripper, opt Opt
|
||||
}
|
||||
wo.Executor = exec
|
||||
|
||||
w, err := mobyworker.NewContainerdWorker(ctx, wo, opt.ImageExportedCallback)
|
||||
w, err := mobyworker.NewContainerdWorker(ctx, wo, opt.Callbacks)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -321,7 +332,8 @@ func newGraphDriverController(ctx context.Context, rt http.RoundTripper, opt Opt
|
||||
Differ: differ,
|
||||
ImageTagger: opt.ImageTagger,
|
||||
LeaseManager: lm,
|
||||
ImageExportedCallback: opt.ImageExportedCallback,
|
||||
ImageExportedCallback: opt.Callbacks.Exported,
|
||||
// Callbacks.Named is not used here because the tag operation is handled directly by the image service.
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/containerd/containerd/leases"
|
||||
"github.com/containerd/log"
|
||||
distref "github.com/distribution/reference"
|
||||
builderexporter "github.com/docker/docker/builder/builder-next/exporter"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/moby/buildkit/exporter"
|
||||
@@ -38,7 +37,7 @@ type Opt struct {
|
||||
ImageTagger ImageTagger
|
||||
ContentStore content.Store
|
||||
LeaseManager leases.Manager
|
||||
ImageExportedCallback builderexporter.ImageExportedByBuildkit
|
||||
ImageExportedCallback func(ctx context.Context, id string, desc ocispec.Descriptor)
|
||||
}
|
||||
|
||||
type imageExporter struct {
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/moby/buildkit/cache"
|
||||
"github.com/moby/buildkit/exporter/containerimage/exptypes"
|
||||
"github.com/moby/buildkit/util/progress"
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/builder/builder-next/exporter/overrides"
|
||||
"github.com/moby/buildkit/exporter"
|
||||
"github.com/moby/buildkit/exporter/containerimage/exptypes"
|
||||
@@ -11,19 +13,29 @@ import (
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
type ImageExportedByBuildkit = func(ctx context.Context, id string, desc ocispec.Descriptor) error
|
||||
type BuildkitCallbacks struct {
|
||||
// Exported is a Called when an image is exported by buildkit.
|
||||
Exported func(ctx context.Context, id string, desc ocispec.Descriptor)
|
||||
|
||||
// Named is a callback that is called when an image is created in the
|
||||
// containerd image store by buildkit.
|
||||
Named func(ctx context.Context, ref reference.NamedTagged, desc ocispec.Descriptor)
|
||||
}
|
||||
|
||||
// Wraps the containerimage exporter's Resolve method to apply moby-specific
|
||||
// overrides to the exporter attributes.
|
||||
type imageExporterMobyWrapper struct {
|
||||
exp exporter.Exporter
|
||||
callback ImageExportedByBuildkit
|
||||
exp exporter.Exporter
|
||||
callbacks BuildkitCallbacks
|
||||
}
|
||||
|
||||
// NewWrapper returns an exporter wrapper that applies moby specific attributes
|
||||
// and hooks the export process.
|
||||
func NewWrapper(exp exporter.Exporter, callback ImageExportedByBuildkit) (exporter.Exporter, error) {
|
||||
return &imageExporterMobyWrapper{exp: exp, callback: callback}, nil
|
||||
func NewWrapper(exp exporter.Exporter, callbacks BuildkitCallbacks) (exporter.Exporter, error) {
|
||||
return &imageExporterMobyWrapper{
|
||||
exp: exp,
|
||||
callbacks: callbacks,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Resolve applies moby specific attributes to the request.
|
||||
@@ -46,12 +58,15 @@ func (e *imageExporterMobyWrapper) Resolve(ctx context.Context, id int, exporter
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &imageExporterInstanceWrapper{ExporterInstance: inst, callback: e.callback}, nil
|
||||
return &imageExporterInstanceWrapper{
|
||||
ExporterInstance: inst,
|
||||
callbacks: e.callbacks,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type imageExporterInstanceWrapper struct {
|
||||
exporter.ExporterInstance
|
||||
callback ImageExportedByBuildkit
|
||||
callbacks BuildkitCallbacks
|
||||
}
|
||||
|
||||
func (i *imageExporterInstanceWrapper) Export(ctx context.Context, src *exporter.Source, inlineCache exptypes.InlineCache, sessionID string) (map[string]string, exporter.DescriptorReference, error) {
|
||||
@@ -62,8 +77,26 @@ func (i *imageExporterInstanceWrapper) Export(ctx context.Context, src *exporter
|
||||
|
||||
desc := ref.Descriptor()
|
||||
imageID := out[exptypes.ExporterImageDigestKey]
|
||||
if i.callback != nil {
|
||||
i.callback(ctx, imageID, desc)
|
||||
if i.callbacks.Exported != nil {
|
||||
i.callbacks.Exported(ctx, imageID, desc)
|
||||
}
|
||||
|
||||
if i.callbacks.Named != nil {
|
||||
for _, name := range strings.Split(out[string(exptypes.OptKeyName)], ",") {
|
||||
ref, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
// Shouldn't happen, but log if it does and continue.
|
||||
log.G(ctx).WithFields(log.Fields{
|
||||
"name": name,
|
||||
"error": err,
|
||||
}).Warn("image named with invalid reference produced by buildkit")
|
||||
continue
|
||||
}
|
||||
|
||||
namedTagged := reference.TagNameOnly(ref).(reference.NamedTagged)
|
||||
i.callbacks.Named(ctx, namedTagged, desc)
|
||||
}
|
||||
}
|
||||
|
||||
return out, ref, nil
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ package worker
|
||||
import (
|
||||
"context"
|
||||
|
||||
mobyexporter "github.com/docker/docker/builder/builder-next/exporter"
|
||||
"github.com/docker/docker/builder/builder-next/exporter"
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/exporter"
|
||||
bkexporter "github.com/moby/buildkit/exporter"
|
||||
"github.com/moby/buildkit/session"
|
||||
"github.com/moby/buildkit/worker/base"
|
||||
)
|
||||
@@ -13,27 +13,27 @@ import (
|
||||
// ContainerdWorker is a local worker instance with dedicated snapshotter, cache, and so on.
|
||||
type ContainerdWorker struct {
|
||||
*base.Worker
|
||||
callback mobyexporter.ImageExportedByBuildkit
|
||||
callbacks exporter.BuildkitCallbacks
|
||||
}
|
||||
|
||||
// NewContainerdWorker instantiates a local worker.
|
||||
func NewContainerdWorker(ctx context.Context, wo base.WorkerOpt, callback mobyexporter.ImageExportedByBuildkit) (*ContainerdWorker, error) {
|
||||
func NewContainerdWorker(ctx context.Context, wo base.WorkerOpt, callbacks exporter.BuildkitCallbacks) (*ContainerdWorker, error) {
|
||||
bw, err := base.NewWorker(ctx, wo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ContainerdWorker{Worker: bw, callback: callback}, nil
|
||||
return &ContainerdWorker{Worker: bw, callbacks: callbacks}, nil
|
||||
}
|
||||
|
||||
// Exporter returns exporter by name
|
||||
func (w *ContainerdWorker) Exporter(name string, sm *session.Manager) (exporter.Exporter, error) {
|
||||
func (w *ContainerdWorker) Exporter(name string, sm *session.Manager) (bkexporter.Exporter, error) {
|
||||
switch name {
|
||||
case mobyexporter.Moby:
|
||||
case exporter.Moby:
|
||||
exp, err := w.Worker.Exporter(client.ExporterImage, sm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mobyexporter.NewWrapper(exp, w.callback)
|
||||
return exporter.NewWrapper(exp, w.callbacks)
|
||||
default:
|
||||
return w.Worker.Exporter(name, sm)
|
||||
}
|
||||
|
||||
@@ -9,9 +9,10 @@ import (
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/containerd/rootfs"
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
imageadapter "github.com/docker/docker/builder/builder-next/adapters/containerimage"
|
||||
mobyexporter "github.com/docker/docker/builder/builder-next/exporter"
|
||||
distmetadata "github.com/docker/docker/distribution/metadata"
|
||||
@@ -572,5 +573,5 @@ func (p *emptyProvider) ReaderAt(ctx context.Context, dec ocispec.Descriptor) (c
|
||||
}
|
||||
|
||||
func (p *emptyProvider) Info(ctx context.Context, d digest.Digest) (content.Info, error) {
|
||||
return content.Info{}, errors.Errorf("Info not implemented for empty provider")
|
||||
return content.Info{}, errors.Wrapf(cerrdefs.ErrNotImplemented, "Info not implemented for empty provider")
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
@@ -228,7 +228,7 @@ func emitImageID(aux *streamformatter.AuxFormatter, state *dispatchState) error
|
||||
|
||||
func processMetaArg(meta instructions.ArgCommand, shlex *shell.Lex, args *BuildArgs) error {
|
||||
// shell.Lex currently only support the concatenated string format
|
||||
envs := convertMapToEnvList(args.GetAllAllowed())
|
||||
envs := shell.EnvsFromSlice(convertMapToEnvList(args.GetAllAllowed()))
|
||||
if err := meta.Expand(func(word string) (string, error) {
|
||||
newword, _, err := shlex.ProcessWord(word, envs)
|
||||
return newword, err
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
"github.com/docker/docker/builder"
|
||||
@@ -224,7 +224,7 @@ func (d *dispatchRequest) getExpandedString(shlex *shell.Lex, str string) (strin
|
||||
substitutionArgs = append(substitutionArgs, key+"="+value)
|
||||
}
|
||||
|
||||
name, _, err := shlex.ProcessWord(str, substitutionArgs)
|
||||
name, _, err := shlex.ProcessWord(str, shell.EnvsFromSlice(substitutionArgs))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -508,7 +508,7 @@ func dispatchEntrypoint(ctx context.Context, d dispatchRequest, c *instructions.
|
||||
//
|
||||
// Expose ports for links and port mappings. This all ends up in
|
||||
// req.runConfig.ExposedPorts for runconfig.
|
||||
func dispatchExpose(ctx context.Context, d dispatchRequest, c *instructions.ExposeCommand, envs []string) error {
|
||||
func dispatchExpose(ctx context.Context, d dispatchRequest, c *instructions.ExposeCommand, envs shell.EnvGetter) error {
|
||||
// custom multi word expansion
|
||||
// expose $FOO with FOO="80 443" is expanded as EXPOSE [80,443]. This is the only command supporting word to words expansion
|
||||
// so the word processing has been de-generalized
|
||||
|
||||
@@ -43,7 +43,7 @@ func dispatch(ctx context.Context, d dispatchRequest, cmd instructions.Command)
|
||||
}
|
||||
}
|
||||
runConfigEnv := d.state.runConfig.Env
|
||||
envs := append(runConfigEnv, d.state.buildArgs.FilterAllowed(runConfigEnv)...)
|
||||
envs := shell.EnvsFromSlice(append(runConfigEnv, d.state.buildArgs.FilterAllowed(runConfigEnv)...))
|
||||
|
||||
if ex, ok := cmd.(instructions.SupportsSingleWordExpansion); ok {
|
||||
err := ex.Expand(func(word string) (string, error) {
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"context"
|
||||
"runtime"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/builder"
|
||||
dockerimage "github.com/docker/docker/image"
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/docker/builder"
|
||||
"github.com/docker/docker/image"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/errdefs"
|
||||
|
||||
@@ -17,7 +17,6 @@ func createTestTempDir(t *testing.T, dir, prefix string) (string, func()) {
|
||||
|
||||
return path, func() {
|
||||
err = os.RemoveAll(path)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error when removing directory %s: %s", path, err)
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ func downloadRemote(remoteURL string) (string, io.ReadCloser, error) {
|
||||
// GetWithStatusError does an http.Get() and returns an error if the
|
||||
// status code is 4xx or 5xx.
|
||||
func GetWithStatusError(address string) (resp *http.Response, err error) {
|
||||
// #nosec G107
|
||||
if resp, err = http.Get(address); err != nil {
|
||||
resp, err = http.Get(address) // #nosec G107 -- ignore G107: Potential HTTP request made with variable url
|
||||
if err != nil {
|
||||
if uerr, ok := err.(*url.Error); ok {
|
||||
if derr, ok := uerr.Err.(*net.DNSError); ok && !derr.IsTimeout {
|
||||
return nil, errdefs.NotFound(err)
|
||||
|
||||
@@ -33,7 +33,6 @@ func TestCloseRootDirectory(t *testing.T) {
|
||||
|
||||
src := makeTestArchiveContext(t, contextDir)
|
||||
err = src.Close()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error while executing Close: %s", err)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ func createTestTempDir(t *testing.T, dir, prefix string) (string, func()) {
|
||||
|
||||
return path, func() {
|
||||
err = os.RemoveAll(path)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error when removing directory %s: %s", path, err)
|
||||
}
|
||||
|
||||
@@ -83,55 +83,3 @@ func TestContainerInspect(t *testing.T) {
|
||||
t.Fatalf("expected `name`, got %s", r.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// TestContainerInspectNode tests that the "Node" field is included in the "inspect"
|
||||
// output. This information is only present when connected to a Swarm standalone API.
|
||||
func TestContainerInspectNode(t *testing.T) {
|
||||
client := &Client{
|
||||
client: newMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
content, err := json.Marshal(types.ContainerJSON{
|
||||
ContainerJSONBase: &types.ContainerJSONBase{
|
||||
ID: "container_id",
|
||||
Image: "image",
|
||||
Name: "name",
|
||||
Node: &types.ContainerNode{
|
||||
ID: "container_node_id",
|
||||
Addr: "container_node",
|
||||
Labels: map[string]string{"foo": "bar"},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: io.NopCloser(bytes.NewReader(content)),
|
||||
}, nil
|
||||
}),
|
||||
}
|
||||
|
||||
r, err := client.ContainerInspect(context.Background(), "container_id")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if r.ID != "container_id" {
|
||||
t.Fatalf("expected `container_id`, got %s", r.ID)
|
||||
}
|
||||
if r.Image != "image" {
|
||||
t.Fatalf("expected `image`, got %s", r.Image)
|
||||
}
|
||||
if r.Name != "name" {
|
||||
t.Fatalf("expected `name`, got %s", r.Name)
|
||||
}
|
||||
if r.Node.ID != "container_node_id" {
|
||||
t.Fatalf("expected `container_node_id`, got %s", r.Node.ID)
|
||||
}
|
||||
if r.Node.Addr != "container_node" {
|
||||
t.Fatalf("expected `container_node`, got %s", r.Node.Addr)
|
||||
}
|
||||
foo, ok := r.Node.Labels["foo"]
|
||||
if foo != "bar" || !ok {
|
||||
t.Fatalf("expected `bar` for label `foo`")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,11 @@ import (
|
||||
)
|
||||
|
||||
// ImageList returns a list of images in the docker host.
|
||||
//
|
||||
// Experimental: Setting the [options.Manifest] will populate
|
||||
// [image.Summary.Manifests] with information about image manifests.
|
||||
// This is experimental and might change in the future without any backward
|
||||
// compatibility.
|
||||
func (cli *Client) ImageList(ctx context.Context, options image.ListOptions) ([]image.Summary, error) {
|
||||
var images []image.Summary
|
||||
|
||||
@@ -47,6 +52,9 @@ func (cli *Client) ImageList(ctx context.Context, options image.ListOptions) ([]
|
||||
if options.SharedSize && versions.GreaterThanOrEqualTo(cli.version, "1.42") {
|
||||
query.Set("shared-size", "1")
|
||||
}
|
||||
if options.Manifests && versions.GreaterThanOrEqualTo(cli.version, "1.47") {
|
||||
query.Set("manifests", "1")
|
||||
}
|
||||
|
||||
serverResp, err := cli.get(ctx, "/images/json", query, nil)
|
||||
defer ensureReaderClosed(serverResp)
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
systemrouter "github.com/docker/docker/api/server/router/system"
|
||||
"github.com/docker/docker/api/server/router/volume"
|
||||
buildkit "github.com/docker/docker/builder/builder-next"
|
||||
"github.com/docker/docker/builder/builder-next/exporter"
|
||||
"github.com/docker/docker/builder/dockerfile"
|
||||
"github.com/docker/docker/cmd/dockerd/debug"
|
||||
"github.com/docker/docker/cmd/dockerd/trap"
|
||||
@@ -430,24 +431,27 @@ func newRouterOptions(ctx context.Context, config *config.Config, d *daemon.Daem
|
||||
cgroupParent := newCgroupParent(config)
|
||||
|
||||
bk, err := buildkit.New(ctx, buildkit.Opt{
|
||||
SessionManager: sm,
|
||||
Root: filepath.Join(config.Root, "buildkit"),
|
||||
EngineID: d.ID(),
|
||||
Dist: d.DistributionServices(),
|
||||
ImageTagger: d.ImageService(),
|
||||
NetworkController: d.NetworkController(),
|
||||
DefaultCgroupParent: cgroupParent,
|
||||
RegistryHosts: d.RegistryHosts,
|
||||
BuilderConfig: config.Builder,
|
||||
Rootless: daemon.Rootless(config),
|
||||
IdentityMapping: d.IdentityMapping(),
|
||||
DNSConfig: config.DNSConfig,
|
||||
ApparmorProfile: daemon.DefaultApparmorProfile(),
|
||||
UseSnapshotter: d.UsesSnapshotter(),
|
||||
Snapshotter: d.ImageService().StorageDriver(),
|
||||
ContainerdAddress: config.ContainerdAddr,
|
||||
ContainerdNamespace: config.ContainerdNamespace,
|
||||
ImageExportedCallback: d.ImageExportedByBuildkit,
|
||||
SessionManager: sm,
|
||||
Root: filepath.Join(config.Root, "buildkit"),
|
||||
EngineID: d.ID(),
|
||||
Dist: d.DistributionServices(),
|
||||
ImageTagger: d.ImageService(),
|
||||
NetworkController: d.NetworkController(),
|
||||
DefaultCgroupParent: cgroupParent,
|
||||
RegistryHosts: d.RegistryHosts,
|
||||
BuilderConfig: config.Builder,
|
||||
Rootless: daemon.Rootless(config),
|
||||
IdentityMapping: d.IdentityMapping(),
|
||||
DNSConfig: config.DNSConfig,
|
||||
ApparmorProfile: daemon.DefaultApparmorProfile(),
|
||||
UseSnapshotter: d.UsesSnapshotter(),
|
||||
Snapshotter: d.ImageService().StorageDriver(),
|
||||
ContainerdAddress: config.ContainerdAddr,
|
||||
ContainerdNamespace: config.ContainerdNamespace,
|
||||
Callbacks: exporter.BuildkitCallbacks{
|
||||
Exported: d.ImageExportedByBuildkit,
|
||||
Named: d.ImageNamedByBuildkit,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return routerOptions{}, err
|
||||
|
||||
@@ -30,7 +30,6 @@ import (
|
||||
"github.com/docker/docker/layer"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
"github.com/docker/docker/oci"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/restartmanager"
|
||||
@@ -345,7 +344,7 @@ func (container *Container) GetResourcePath(path string) (string, error) {
|
||||
}
|
||||
// IMPORTANT - These are paths on the OS where the daemon is running, hence
|
||||
// any filepath operations must be done in an OS-agnostic way.
|
||||
r, e := symlink.FollowSymlinkInScope(filepath.Join(container.BaseFS, containerfs.CleanScopedPath(path)), container.BaseFS)
|
||||
r, e := symlink.FollowSymlinkInScope(filepath.Join(container.BaseFS, cleanScopedPath(path)), container.BaseFS)
|
||||
|
||||
// Log this here on the daemon side as there's otherwise no indication apart
|
||||
// from the error being propagated all the way back to the client. This makes
|
||||
@@ -356,6 +355,18 @@ func (container *Container) GetResourcePath(path string) (string, error) {
|
||||
return r, e
|
||||
}
|
||||
|
||||
// cleanScopedPath prepares the given path to be combined with a mount path or
|
||||
// a drive-letter. On Windows, it removes any existing driveletter (e.g. "C:").
|
||||
// The returned path is always prefixed with a [filepath.Separator].
|
||||
func cleanScopedPath(path string) string {
|
||||
if len(path) >= 2 {
|
||||
if v := filepath.VolumeName(path); len(v) > 0 {
|
||||
path = path[len(v):]
|
||||
}
|
||||
}
|
||||
return filepath.Join(string(filepath.Separator), path)
|
||||
}
|
||||
|
||||
// GetRootResourcePath evaluates `path` in the scope of the container's root, with proper path
|
||||
// sanitisation. Symlinks are all scoped to the root of the container, as
|
||||
// though the container's root was `/`.
|
||||
|
||||
@@ -269,13 +269,6 @@ init() {
|
||||
# - sysctl: "net.ipv4.ip_unprivileged_port_start"
|
||||
# - external binary: slirp4netns
|
||||
# - external binary: fuse-overlayfs
|
||||
|
||||
# check RootlessKit functionality. RootlessKit will print hints if something is still unsatisfied.
|
||||
# (e.g., `kernel.apparmor_restrict_unprivileged_userns` constraint)
|
||||
if ! rootlesskit true; then
|
||||
ERROR "RootlessKit failed, see the error messages and https://rootlesscontaine.rs/getting-started/common/ ."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# CLI subcommand: "check"
|
||||
@@ -314,6 +307,7 @@ install_systemd() {
|
||||
[Unit]
|
||||
Description=Docker Application Container Engine (Rootless)
|
||||
Documentation=https://docs.docker.com/go/rootless/
|
||||
Requires=dbus.socket
|
||||
|
||||
[Service]
|
||||
Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH
|
||||
@@ -399,7 +393,16 @@ cli_ctx_rm() {
|
||||
# CLI subcommand: "install"
|
||||
cmd_entrypoint_install() {
|
||||
init
|
||||
# requirements are already checked in init()
|
||||
# Most requirements are already checked in init(), except the smoke test below for RootlessKit.
|
||||
# https://github.com/docker/docker-install/issues/417
|
||||
|
||||
# check RootlessKit functionality. RootlessKit will print hints if something is still unsatisfied.
|
||||
# (e.g., `kernel.apparmor_restrict_unprivileged_userns` constraint)
|
||||
if ! rootlesskit true; then
|
||||
ERROR "RootlessKit failed, see the error messages and https://rootlesscontaine.rs/getting-started/common/ ."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$SYSTEMD" ]; then
|
||||
install_nonsystemd
|
||||
else
|
||||
|
||||
@@ -3,6 +3,8 @@ package daemon
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
@@ -10,7 +12,15 @@ import (
|
||||
// This is used to log the image creation event for untagged images.
|
||||
// When no tag is given, buildkit doesn't call the image service so it has no
|
||||
// way of knowing the image was created.
|
||||
func (daemon *Daemon) ImageExportedByBuildkit(ctx context.Context, id string, desc ocispec.Descriptor) error {
|
||||
daemon.imageService.LogImageEvent(id, id, "create")
|
||||
return nil
|
||||
func (daemon *Daemon) ImageExportedByBuildkit(ctx context.Context, id string, desc ocispec.Descriptor) {
|
||||
daemon.imageService.LogImageEvent(id, id, events.ActionCreate)
|
||||
}
|
||||
|
||||
// ImageNamedByBuildkit is a callback that is called when an image is tagged by buildkit.
|
||||
// Note: It is only called if the buildkit didn't call the image service itself to perform the tagging.
|
||||
// Currently this only happens when the containerd image store is used.
|
||||
func (daemon *Daemon) ImageNamedByBuildkit(ctx context.Context, ref reference.NamedTagged, desc ocispec.Descriptor) {
|
||||
id := desc.Digest.String()
|
||||
name := reference.FamiliarString(ref)
|
||||
daemon.imageService.LogImageEvent(id, name, events.ActionTag)
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
|
||||
func TestTmpfsOptionsToGRPC(t *testing.T) {
|
||||
options := [][]string{
|
||||
[]string{"noexec"},
|
||||
[]string{"uid", "12345"},
|
||||
{"noexec"},
|
||||
{"uid", "12345"},
|
||||
}
|
||||
|
||||
expected := `[["noexec"],["uid","12345"]]`
|
||||
@@ -21,8 +21,8 @@ func TestTmpfsOptionsFromGRPC(t *testing.T) {
|
||||
options := `[["noexec"],["uid","12345"]]`
|
||||
|
||||
expected := [][]string{
|
||||
[]string{"noexec"},
|
||||
[]string{"uid", "12345"},
|
||||
{"noexec"},
|
||||
{"uid", "12345"},
|
||||
}
|
||||
actual := tmpfsOptionsFromGRPC(options)
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ func TestTmpfsConversion(t *testing.T) {
|
||||
Target: "/bar",
|
||||
Type: mount.TypeTmpfs,
|
||||
TmpfsOptions: &mount.TmpfsOptions{
|
||||
Options: [][]string{[]string{"exec"}},
|
||||
Options: [][]string{{"exec"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -190,7 +190,7 @@ func TestTmpfsConversion(t *testing.T) {
|
||||
Target: "/bar",
|
||||
Type: mount.TypeTmpfs,
|
||||
TmpfsOptions: &mount.TmpfsOptions{
|
||||
Options: [][]string{[]string{"noexec"}},
|
||||
Options: [][]string{{"noexec"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -557,7 +557,6 @@ func TestValidateMinAPIVersion(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestConfigInvalidDNS(t *testing.T) {
|
||||
|
||||
@@ -44,7 +44,7 @@ func (c cacheAdaptor) Get(id image.ID) (*image.Image, error) {
|
||||
return nil, fmt.Errorf("resolveImage: %w", err)
|
||||
}
|
||||
|
||||
var errFound = errors.New("success")
|
||||
errFound := errors.New("success")
|
||||
err = c.is.walkImageManifests(ctx, c8dImg, func(img *ImageManifest) error {
|
||||
desc, err := img.Config(ctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
"time"
|
||||
|
||||
containerdimages "github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/daemon/images"
|
||||
@@ -26,8 +26,6 @@ import (
|
||||
"golang.org/x/sync/semaphore"
|
||||
)
|
||||
|
||||
var truncatedID = regexp.MustCompile(`^(sha256:)?([a-f0-9]{4,64})$`)
|
||||
|
||||
var errInconsistentData error = errors.New("consistency error: data changed during operation, retry")
|
||||
|
||||
// GetImage returns an image corresponding to the image referred to by refOrID.
|
||||
@@ -326,9 +324,8 @@ func (i *ImageService) resolveImage(ctx context.Context, refOrID string) (contai
|
||||
}
|
||||
}
|
||||
|
||||
// If the identifier could be a short ID, attempt to match
|
||||
if truncatedID.MatchString(refOrID) {
|
||||
idWithoutAlgo := strings.TrimPrefix(refOrID, "sha256:")
|
||||
// If the identifier could be a short ID, attempt to match.
|
||||
if idWithoutAlgo := checkTruncatedID(refOrID); idWithoutAlgo != "" { // Valid ID.
|
||||
filters := []string{
|
||||
fmt.Sprintf("name==%q", ref), // Or it could just look like one.
|
||||
"target.digest~=" + strconv.Quote(fmt.Sprintf(`^sha256:%s[0-9a-fA-F]{%d}$`, regexp.QuoteMeta(idWithoutAlgo), 64-len(idWithoutAlgo))),
|
||||
@@ -435,7 +432,7 @@ func (i *ImageService) resolveAllReferences(ctx context.Context, refOrID string)
|
||||
var dgst digest.Digest
|
||||
var img *containerdimages.Image
|
||||
|
||||
if truncatedID.MatchString(refOrID) {
|
||||
if idWithoutAlgo := checkTruncatedID(refOrID); idWithoutAlgo != "" { // Valid ID.
|
||||
if d, ok := parsed.(reference.Digested); ok {
|
||||
if cimg, err := i.images.Get(ctx, d.String()); err == nil {
|
||||
img = &cimg
|
||||
@@ -451,7 +448,6 @@ func (i *ImageService) resolveAllReferences(ctx context.Context, refOrID string)
|
||||
dgst = d.Digest()
|
||||
}
|
||||
} else {
|
||||
idWithoutAlgo := strings.TrimPrefix(refOrID, "sha256:")
|
||||
name := reference.TagNameOnly(parsed.(reference.Named)).String()
|
||||
filters := []string{
|
||||
fmt.Sprintf("name==%q", name), // Or it could just look like one.
|
||||
@@ -551,3 +547,20 @@ func (i *ImageService) resolveAllReferences(ctx context.Context, refOrID string)
|
||||
|
||||
return img, imgs, nil
|
||||
}
|
||||
|
||||
// checkTruncatedID checks id for validity. If id is invalid, an empty string
|
||||
// is returned; otherwise, the ID without the optional "sha256:" prefix is
|
||||
// returned. The validity check is equivalent to
|
||||
// regexp.MustCompile(`^(sha256:)?([a-f0-9]{4,64})$`).MatchString(id).
|
||||
func checkTruncatedID(id string) string {
|
||||
id = strings.TrimPrefix(id, "sha256:")
|
||||
if l := len(id); l < 4 || l > 64 {
|
||||
return ""
|
||||
}
|
||||
for _, c := range id {
|
||||
if (c < '0' || c > '9') && (c < 'a' || c > 'f') {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@ import (
|
||||
containerdimages "github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/leases"
|
||||
"github.com/containerd/containerd/mount"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/containerd/rootfs"
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
// getImagesWithLabel returns all images that have the matching label key and value.
|
||||
func (i *ImageService) getImagesWithLabel(ctx context.Context, labelKey string, labelValue string) ([]image.ID, error) {
|
||||
imgs, err := i.images.List(ctx, "labels."+labelKey+"=="+labelValue)
|
||||
|
||||
if err != nil {
|
||||
return []image.ID{}, errdefs.System(errors.Wrap(err, "failed to list all images"))
|
||||
}
|
||||
|
||||
@@ -254,7 +254,6 @@ func TestImageDelete(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type testContainerStore struct{}
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
containerdimages "github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/images/archive"
|
||||
"github.com/containerd/containerd/leases"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/container"
|
||||
@@ -131,7 +131,6 @@ func (i *ImageService) ExportImage(ctx context.Context, names []string, outStrea
|
||||
|
||||
for _, img := range imgs {
|
||||
ref, err := reference.ParseNamed(img.Name)
|
||||
|
||||
if err != nil {
|
||||
log.G(ctx).WithFields(log.Fields{
|
||||
"image": img.Name,
|
||||
@@ -291,6 +290,17 @@ func (i *ImageService) LoadImage(ctx context.Context, inTar io.ReadCloser, outSt
|
||||
return nil
|
||||
}
|
||||
|
||||
imgPlat, err := platformImg.ImagePlatform(ctx)
|
||||
if err != nil {
|
||||
logger.WithError(err).Warn("failed to read image platform, skipping unpack")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Only unpack the image if it matches the host platform
|
||||
if !i.hostPlatformMatcher().Match(imgPlat) {
|
||||
return nil
|
||||
}
|
||||
|
||||
unpacked, err := platformImg.IsUnpacked(ctx, i.snapshotter)
|
||||
if err != nil {
|
||||
logger.WithError(err).Warn("failed to check if image is unpacked")
|
||||
@@ -299,7 +309,6 @@ func (i *ImageService) LoadImage(ctx context.Context, inTar io.ReadCloser, outSt
|
||||
|
||||
if !unpacked {
|
||||
err = platformImg.Unpack(ctx, i.snapshotter)
|
||||
|
||||
if err != nil {
|
||||
return errdefs.System(err)
|
||||
}
|
||||
@@ -307,12 +316,14 @@ func (i *ImageService) LoadImage(ctx context.Context, inTar io.ReadCloser, outSt
|
||||
logger.WithField("alreadyUnpacked", unpacked).WithError(err).Debug("unpack")
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to unpack loaded image")
|
||||
}
|
||||
|
||||
fmt.Fprintf(progress, "%s: %s\n", loadedMsg, name)
|
||||
i.LogImageEvent(img.Target.Digest.String(), img.Target.Digest.String(), events.ActionLoad)
|
||||
|
||||
if err != nil {
|
||||
// The image failed to unpack, but is already imported, log the error but don't fail the whole load.
|
||||
fmt.Fprintf(progress, "Error unpacking image %s: %v\n", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"time"
|
||||
|
||||
containerdimages "github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/distribution/reference"
|
||||
imagetype "github.com/docker/docker/api/types/image"
|
||||
dimages "github.com/docker/docker/daemon/images"
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
|
||||
@@ -12,17 +12,17 @@ import (
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/labels"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
imagetypes "github.com/docker/docker/api/types/image"
|
||||
timetypes "github.com/docker/docker/api/types/time"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/moby/buildkit/util/attestation"
|
||||
dockerspec "github.com/moby/docker-image-spec/specs-go/v1"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/opencontainers/image-spec/identity"
|
||||
@@ -209,6 +209,7 @@ func (i *ImageService) Images(ctx context.Context, opts imagetypes.ListOptions)
|
||||
func (i *ImageService) imageSummary(ctx context.Context, img images.Image, platformMatcher platforms.MatchComparer,
|
||||
opts imagetypes.ListOptions, tagsByDigest map[digest.Digest][]string,
|
||||
) (_ *imagetypes.Summary, allChainIDs []digest.Digest, _ error) {
|
||||
var manifestSummaries []imagetypes.ManifestSummary
|
||||
|
||||
// Total size of the image including all its platform
|
||||
var totalSize int64
|
||||
@@ -223,67 +224,154 @@ func (i *ImageService) imageSummary(ctx context.Context, img images.Image, platf
|
||||
var best *ImageManifest
|
||||
var bestPlatform ocispec.Platform
|
||||
|
||||
err := i.walkImageManifests(ctx, img, func(img *ImageManifest) error {
|
||||
if isPseudo, err := img.IsPseudoImage(ctx); isPseudo || err != nil {
|
||||
err := i.walkReachableImageManifests(ctx, img, func(img *ImageManifest) error {
|
||||
target := img.Target()
|
||||
|
||||
logger := log.G(ctx).WithFields(log.Fields{
|
||||
"image": img.Name(),
|
||||
"digest": target.Digest,
|
||||
"manifest": target,
|
||||
})
|
||||
|
||||
available, err := img.CheckContentAvailable(ctx)
|
||||
if err != nil && !errdefs.IsNotFound(err) {
|
||||
logger.WithError(err).Warn("checking availability of platform specific manifest failed")
|
||||
return nil
|
||||
}
|
||||
|
||||
available, err := img.CheckContentAvailable(ctx)
|
||||
mfstSummary := imagetypes.ManifestSummary{
|
||||
ID: target.Digest.String(),
|
||||
Available: available,
|
||||
Descriptor: target,
|
||||
Kind: imagetypes.ManifestKindUnknown,
|
||||
}
|
||||
|
||||
if opts.Manifests {
|
||||
defer func() {
|
||||
// If the platform is available, prepend it to the list of platforms
|
||||
// otherwise append it at the end.
|
||||
if available {
|
||||
manifestSummaries = append([]imagetypes.ManifestSummary{mfstSummary}, manifestSummaries...)
|
||||
} else {
|
||||
manifestSummaries = append(manifestSummaries, mfstSummary)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
contentSize, err := img.Size(ctx)
|
||||
if err != nil {
|
||||
log.G(ctx).WithFields(log.Fields{
|
||||
"error": err,
|
||||
"manifest": img.Target(),
|
||||
"image": img.Name(),
|
||||
}).Warn("checking availability of platform specific manifest failed")
|
||||
if !cerrdefs.IsNotFound(err) {
|
||||
logger.WithError(err).Warn("failed to determine size")
|
||||
}
|
||||
} else {
|
||||
mfstSummary.Size.Content = contentSize
|
||||
totalSize += contentSize
|
||||
mfstSummary.Size.Total += contentSize
|
||||
}
|
||||
|
||||
isPseudo, err := img.IsPseudoImage(ctx)
|
||||
|
||||
// Ignore not found error as it's expected in case where the image is
|
||||
// not fully available. Otherwise, just continue to the next manifest,
|
||||
// so we don't error out the whole list in case the error is related to
|
||||
// the content itself (e.g. corrupted data) or just manifest kind that
|
||||
// we don't know about (yet).
|
||||
if err != nil && !errdefs.IsNotFound(err) {
|
||||
logger.WithError(err).Debug("pseudo image check failed")
|
||||
return nil
|
||||
}
|
||||
|
||||
logger = logger.WithField("isPseudo", isPseudo)
|
||||
if isPseudo {
|
||||
if img.IsAttestation() {
|
||||
if s := target.Annotations[attestation.DockerAnnotationReferenceDigest]; s != "" {
|
||||
dgst, err := digest.Parse(s)
|
||||
if err != nil {
|
||||
logger.WithError(err).Warn("failed to parse attestation digest")
|
||||
return nil
|
||||
}
|
||||
|
||||
mfstSummary.Kind = imagetypes.ManifestKindAttestation
|
||||
mfstSummary.AttestationData = &imagetypes.AttestationProperties{For: dgst}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
mfstSummary.Kind = imagetypes.ManifestKindImage
|
||||
mfstSummary.ImageData = &imagetypes.ImageProperties{}
|
||||
if target.Platform != nil {
|
||||
mfstSummary.ImageData.Platform = *target.Platform
|
||||
}
|
||||
|
||||
if !available {
|
||||
return nil
|
||||
}
|
||||
|
||||
conf, err := img.Config(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
logger.WithError(err).Warn("failed to read image config")
|
||||
return nil
|
||||
}
|
||||
|
||||
var dockerImage dockerspec.DockerOCIImage
|
||||
if err := readConfig(ctx, i.content, conf, &dockerImage); err != nil {
|
||||
return err
|
||||
logger.WithError(err).Warn("failed to read image config")
|
||||
return nil
|
||||
}
|
||||
|
||||
target := img.Target()
|
||||
if target.Platform == nil {
|
||||
mfstSummary.ImageData.Platform = dockerImage.Platform
|
||||
}
|
||||
|
||||
diffIDs, err := img.RootFS(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
logger.WithError(err).Warn("failed to read image config")
|
||||
return nil
|
||||
}
|
||||
|
||||
chainIDs := identity.ChainIDs(diffIDs)
|
||||
|
||||
ts, _, err := i.singlePlatformSize(ctx, img)
|
||||
unpackedSize, imgContentSize, err := i.singlePlatformSize(ctx, img)
|
||||
if err != nil {
|
||||
return err
|
||||
logger.WithError(err).Warn("failed to determine platform specific size")
|
||||
return nil
|
||||
}
|
||||
|
||||
totalSize += ts
|
||||
// If the image-specific content size calculation produces different result
|
||||
// than the "generic" one, adjust the total size with the difference.
|
||||
// Note: This shouldn't happen unless the implementation changes or the
|
||||
// content is added/removed during the list operation.
|
||||
if contentSize != imgContentSize {
|
||||
logger.WithFields(log.Fields{
|
||||
"contentSize": contentSize,
|
||||
"imgContentSize": imgContentSize,
|
||||
}).Warn("content size calculation mismatch")
|
||||
|
||||
mfstSummary.Size.Content = contentSize
|
||||
|
||||
// contentSize was already added to total, adjust it by the difference
|
||||
// between the newly calculated size and the old size.
|
||||
d := imgContentSize - contentSize
|
||||
totalSize += d
|
||||
mfstSummary.Size.Total += d
|
||||
}
|
||||
|
||||
mfstSummary.ImageData.Size.Unpacked = unpackedSize
|
||||
mfstSummary.Size.Total += unpackedSize
|
||||
totalSize += unpackedSize
|
||||
|
||||
allChainsIDs = append(allChainsIDs, chainIDs...)
|
||||
|
||||
if opts.ContainerCount {
|
||||
i.containers.ApplyAll(func(c *container.Container) {
|
||||
if c.ImageManifest != nil && c.ImageManifest.Digest == target.Digest {
|
||||
containersCount++
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var platform ocispec.Platform
|
||||
if target.Platform != nil {
|
||||
platform = *target.Platform
|
||||
} else {
|
||||
platform = dockerImage.Platform
|
||||
for _, c := range i.containers.List() {
|
||||
if c.ImageManifest != nil && c.ImageManifest.Digest == target.Digest {
|
||||
mfstSummary.ImageData.Containers = append(mfstSummary.ImageData.Containers, c.ID)
|
||||
containersCount++
|
||||
}
|
||||
}
|
||||
|
||||
platform := mfstSummary.ImageData.Platform
|
||||
// Filter out platforms that don't match the requested platform. Do it
|
||||
// after the size, container count and chainIDs are summed up to have
|
||||
// the single combined entry still represent the whole multi-platform
|
||||
@@ -323,6 +411,7 @@ func (i *ImageService) imageSummary(ctx context.Context, img images.Image, platf
|
||||
return nil, nil, err
|
||||
}
|
||||
image.Size = totalSize
|
||||
image.Manifests = manifestSummaries
|
||||
|
||||
if opts.ContainerCount {
|
||||
image.Containers = containersCount
|
||||
@@ -330,7 +419,7 @@ func (i *ImageService) imageSummary(ctx context.Context, img images.Image, platf
|
||||
return image, allChainsIDs, nil
|
||||
}
|
||||
|
||||
func (i *ImageService) singlePlatformSize(ctx context.Context, imgMfst *ImageManifest) (totalSize int64, contentSize int64, _ error) {
|
||||
func (i *ImageService) singlePlatformSize(ctx context.Context, imgMfst *ImageManifest) (unpackedSize int64, contentSize int64, _ error) {
|
||||
// TODO(thaJeztah): do we need to take multiple snapshotters into account? See https://github.com/moby/moby/issues/45273
|
||||
snapshotter := i.snapshotterService(i.snapshotter)
|
||||
|
||||
@@ -356,10 +445,7 @@ func (i *ImageService) singlePlatformSize(ctx context.Context, imgMfst *ImageMan
|
||||
return -1, -1, err
|
||||
}
|
||||
|
||||
// totalSize is the size of the image's packed layers and snapshots
|
||||
// (unpacked layers) combined.
|
||||
totalSize = contentSize + unpackedUsage.Size
|
||||
return totalSize, contentSize, nil
|
||||
return unpackedUsage.Size, contentSize, nil
|
||||
}
|
||||
|
||||
func (i *ImageService) singlePlatformImage(ctx context.Context, contentStore content.Store, repoTags []string, imageManifest *ImageManifest) (*imagetypes.Summary, error) {
|
||||
@@ -401,11 +487,15 @@ func (i *ImageService) singlePlatformImage(ctx context.Context, contentStore con
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalSize, _, err := i.singlePlatformSize(ctx, imageManifest)
|
||||
unpackedSize, contentSize, err := i.singlePlatformSize(ctx, imageManifest)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to calculate size of image %s", imageManifest.Name())
|
||||
}
|
||||
|
||||
// totalSize is the size of the image's packed layers and snapshots
|
||||
// (unpacked layers) combined.
|
||||
totalSize := contentSize + unpackedSize
|
||||
|
||||
summary := &imagetypes.Summary{
|
||||
ParentID: rawImg.Labels[imageLabelClassicBuilderParent],
|
||||
ID: target.String(),
|
||||
|
||||
@@ -17,11 +17,12 @@ import (
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/metadata"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/containerd/log/logtest"
|
||||
"github.com/containerd/platforms"
|
||||
imagetypes "github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/container"
|
||||
daemonevents "github.com/docker/docker/daemon/events"
|
||||
"github.com/docker/docker/internal/testutils/specialimage"
|
||||
"github.com/opencontainers/go-digest"
|
||||
@@ -44,7 +45,13 @@ func imagesFromIndex(index ...*ocispec.Index) []images.Image {
|
||||
}
|
||||
|
||||
func BenchmarkImageList(b *testing.B) {
|
||||
populateStore := func(ctx context.Context, is *ImageService, dir string, count int) {
|
||||
populateStore := func(ctx context.Context, is *ImageService, dir string,
|
||||
count int,
|
||||
// % chance for each image to spawn containers
|
||||
containerChance int,
|
||||
// Maximum container count if the image is decided to spawn containers (chance above)
|
||||
maxContainerCount int,
|
||||
) {
|
||||
// Use constant seed for reproducibility
|
||||
src := rand.NewSource(1982731263716)
|
||||
|
||||
@@ -59,15 +66,34 @@ func BenchmarkImageList(b *testing.B) {
|
||||
idx, err := specialimage.RandomSinglePlatform(dir, platform, src)
|
||||
assert.NilError(b, err)
|
||||
|
||||
r1 := int(src.Int63())
|
||||
r2 := int(src.Int63())
|
||||
|
||||
imgs := imagesFromIndex(idx)
|
||||
for _, desc := range imgs {
|
||||
_, err := is.images.Create(ctx, desc)
|
||||
assert.NilError(b, err)
|
||||
|
||||
if r1%100 >= containerChance {
|
||||
continue
|
||||
}
|
||||
|
||||
containersCount := r2 % maxContainerCount
|
||||
for j := 0; j < containersCount; j++ {
|
||||
id := digest.FromString(desc.Name + strconv.Itoa(i)).String()
|
||||
|
||||
target := desc.Target
|
||||
is.containers.Add(id, &container.Container{
|
||||
ID: id,
|
||||
ImageManifest: &target,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, count := range []int{10, 100, 1000} {
|
||||
count := count
|
||||
csDir := b.TempDir()
|
||||
|
||||
ctx := namespaces.WithNamespace(context.TODO(), "testing-"+strconv.Itoa(count))
|
||||
@@ -78,7 +104,11 @@ func BenchmarkImageList(b *testing.B) {
|
||||
}
|
||||
|
||||
is := fakeImageService(b, ctx, cs)
|
||||
populateStore(ctx, is, csDir, count)
|
||||
|
||||
// Every generated image has a 10% chance to spawn up to 5 containers
|
||||
const containerChance = 10
|
||||
const maxContainerCount = 5
|
||||
populateStore(ctx, is, csDir, count, containerChance, maxContainerCount)
|
||||
|
||||
b.Run(strconv.Itoa(count)+"-images", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
@@ -89,6 +119,76 @@ func BenchmarkImageList(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageListCheckTotalSize(t *testing.T) {
|
||||
ctx := namespaces.WithNamespace(context.TODO(), "testing")
|
||||
|
||||
blobsDir := t.TempDir()
|
||||
cs := &blobsDirContentStore{blobs: filepath.Join(blobsDir, "blobs/sha256")}
|
||||
|
||||
twoplatform, mfstsDescs, err := specialimage.MultiPlatform(blobsDir, "test:latest", []ocispec.Platform{
|
||||
{OS: "linux", Architecture: "arm64"},
|
||||
{OS: "linux", Architecture: "amd64"},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
ctx = logtest.WithT(ctx, t)
|
||||
service := fakeImageService(t, ctx, cs)
|
||||
|
||||
_, err = service.images.Create(ctx, imagesFromIndex(twoplatform)[0])
|
||||
assert.NilError(t, err)
|
||||
|
||||
all, err := service.Images(ctx, imagetypes.ListOptions{Manifests: true})
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Check(t, is.Len(all, 1))
|
||||
assert.Check(t, is.Len(all[0].Manifests, 2))
|
||||
|
||||
// TODO: The test snapshotter doesn't do anything, so the size is always 0.
|
||||
assert.Check(t, is.Equal(all[0].Manifests[0].ImageData.Size.Unpacked, int64(0)))
|
||||
assert.Check(t, is.Equal(all[0].Manifests[1].ImageData.Size.Unpacked, int64(0)))
|
||||
|
||||
mfstArm64 := mfstsDescs[0]
|
||||
mfstAmd64 := mfstsDescs[1]
|
||||
|
||||
indexSize := blobSize(t, ctx, cs, twoplatform.Manifests[0].Digest)
|
||||
arm64ManifestSize := blobSize(t, ctx, cs, mfstArm64.Digest)
|
||||
amd64ManifestSize := blobSize(t, ctx, cs, mfstAmd64.Digest)
|
||||
|
||||
var arm64Mfst, amd64Mfst ocispec.Manifest
|
||||
assert.NilError(t, readConfig(ctx, cs, mfstArm64, &arm64Mfst))
|
||||
assert.NilError(t, readConfig(ctx, cs, mfstAmd64, &amd64Mfst))
|
||||
|
||||
// MultiPlatform should produce a single layer. If these fail, the test needs to be adjusted.
|
||||
assert.Assert(t, is.Len(arm64Mfst.Layers, 1))
|
||||
assert.Assert(t, is.Len(amd64Mfst.Layers, 1))
|
||||
|
||||
arm64ConfigSize := blobSize(t, ctx, cs, arm64Mfst.Config.Digest)
|
||||
amd64ConfigSize := blobSize(t, ctx, cs, amd64Mfst.Config.Digest)
|
||||
|
||||
arm64LayerSize := blobSize(t, ctx, cs, arm64Mfst.Layers[0].Digest)
|
||||
amd64LayerSize := blobSize(t, ctx, cs, amd64Mfst.Layers[0].Digest)
|
||||
|
||||
allTotalSize := indexSize +
|
||||
arm64ManifestSize + amd64ManifestSize +
|
||||
arm64ConfigSize + amd64ConfigSize +
|
||||
arm64LayerSize + amd64LayerSize
|
||||
|
||||
assert.Check(t, is.Equal(all[0].Size, allTotalSize-indexSize))
|
||||
|
||||
assert.Check(t, is.Equal(all[0].Manifests[0].Size.Content, arm64ManifestSize+arm64ConfigSize+arm64LayerSize))
|
||||
assert.Check(t, is.Equal(all[0].Manifests[1].Size.Content, amd64ManifestSize+amd64ConfigSize+amd64LayerSize))
|
||||
|
||||
// TODO: This should also include the Size.Unpacked, but the test snapshotter doesn't do anything yet
|
||||
assert.Check(t, is.Equal(all[0].Manifests[0].Size.Total, amd64ManifestSize+amd64ConfigSize+amd64LayerSize))
|
||||
assert.Check(t, is.Equal(all[0].Manifests[1].Size.Total, amd64ManifestSize+amd64ConfigSize+amd64LayerSize))
|
||||
}
|
||||
|
||||
func blobSize(t *testing.T, ctx context.Context, cs content.Store, dgst digest.Digest) int64 {
|
||||
info, err := cs.Info(ctx, dgst)
|
||||
assert.NilError(t, err)
|
||||
return info.Size
|
||||
}
|
||||
|
||||
func TestImageList(t *testing.T) {
|
||||
ctx := namespaces.WithNamespace(context.TODO(), "testing")
|
||||
|
||||
@@ -123,6 +223,10 @@ func TestImageList(t *testing.T) {
|
||||
|
||||
assert.Check(t, is.Equal(all[0].ID, multilayer.Manifests[0].Digest.String()))
|
||||
assert.Check(t, is.DeepEqual(all[0].RepoTags, []string{"multilayer:latest"}))
|
||||
|
||||
assert.Check(t, is.Len(all[0].Manifests, 1))
|
||||
assert.Check(t, all[0].Manifests[0].Available)
|
||||
assert.Check(t, is.Equal(all[0].Manifests[0].Kind, imagetypes.ManifestKindImage))
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -133,6 +237,18 @@ func TestImageList(t *testing.T) {
|
||||
|
||||
assert.Check(t, is.Equal(all[0].ID, twoplatform.Manifests[0].Digest.String()))
|
||||
assert.Check(t, is.DeepEqual(all[0].RepoTags, []string{"twoplatform:latest"}))
|
||||
|
||||
i := all[0]
|
||||
assert.Check(t, is.Len(i.Manifests, 2))
|
||||
|
||||
assert.Check(t, is.Equal(i.Manifests[0].Kind, imagetypes.ManifestKindImage))
|
||||
if assert.Check(t, i.Manifests[0].ImageData != nil) {
|
||||
assert.Check(t, is.Equal(i.Manifests[0].ImageData.Platform.Architecture, "arm64"))
|
||||
}
|
||||
assert.Check(t, is.Equal(i.Manifests[1].Kind, imagetypes.ManifestKindImage))
|
||||
if assert.Check(t, i.Manifests[1].ImageData != nil) {
|
||||
assert.Check(t, is.Equal(i.Manifests[1].ImageData.Platform.Architecture, "amd64"))
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -146,6 +262,14 @@ func TestImageList(t *testing.T) {
|
||||
|
||||
assert.Check(t, is.Equal(all[1].ID, twoplatform.Manifests[0].Digest.String()))
|
||||
assert.Check(t, is.DeepEqual(all[1].RepoTags, []string{"twoplatform:latest"}))
|
||||
|
||||
assert.Check(t, is.Len(all[0].Manifests, 1))
|
||||
assert.Check(t, is.Len(all[1].Manifests, 2))
|
||||
|
||||
assert.Check(t, is.Equal(all[0].Manifests[0].Kind, imagetypes.ManifestKindImage))
|
||||
|
||||
assert.Check(t, is.Equal(all[1].Manifests[0].Kind, imagetypes.ManifestKindImage))
|
||||
assert.Check(t, is.Equal(all[1].Manifests[1].Kind, imagetypes.ManifestKindImage))
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -176,7 +300,9 @@ func TestImageList(t *testing.T) {
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
all, err := service.Images(ctx, tc.opts)
|
||||
opts := tc.opts
|
||||
opts.Manifests = true
|
||||
all, err := service.Images(ctx, opts)
|
||||
assert.NilError(t, err)
|
||||
|
||||
sort.Slice(all, func(i, j int) bool {
|
||||
@@ -192,7 +318,6 @@ func TestImageList(t *testing.T) {
|
||||
tc.check(t, all)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func fakeImageService(t testing.TB, ctx context.Context, cs content.Store) *ImageService {
|
||||
@@ -206,7 +331,7 @@ func fakeImageService(t testing.TB, ctx context.Context, cs content.Store) *Imag
|
||||
|
||||
service := &ImageService{
|
||||
images: metadata.NewImageStore(mdb),
|
||||
containers: emptyTestContainerStore(),
|
||||
containers: container.NewMemoryStore(),
|
||||
content: cs,
|
||||
eventsService: daemonevents.New(),
|
||||
snapshotterServices: snapshotters,
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
containerdimages "github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/moby/buildkit/util/attestation"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
||||
@@ -10,11 +10,12 @@ import (
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/leases"
|
||||
"github.com/containerd/containerd/pkg/snapshotters"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
@@ -79,10 +80,42 @@ func (i *ImageService) pullTag(ctx context.Context, ref reference.Named, platfor
|
||||
resolver, _ := i.newResolverFromAuthConfig(ctx, authConfig, ref)
|
||||
opts = append(opts, containerd.WithResolver(resolver))
|
||||
|
||||
old, err := i.resolveDescriptor(ctx, ref.String())
|
||||
oldImage, err := i.resolveImage(ctx, ref.String())
|
||||
if err != nil && !errdefs.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// Will be set to the new image after pull succeeds.
|
||||
var outNewImg containerd.Image
|
||||
|
||||
if oldImage.Target.Digest != "" {
|
||||
// Lease the old image content to prevent it from being garbage collected until we keep it as dangling image.
|
||||
lm := i.client.LeasesService()
|
||||
lease, err := lm.Create(ctx, leases.WithRandomID())
|
||||
if err != nil {
|
||||
return errdefs.System(fmt.Errorf("failed to create lease: %w", err))
|
||||
}
|
||||
|
||||
err = leaseContent(ctx, i.content, lm, lease, oldImage.Target)
|
||||
if err != nil {
|
||||
return errdefs.System(fmt.Errorf("failed to lease content: %w", err))
|
||||
}
|
||||
|
||||
// If the pulled image is different than the old image, we will keep the old image as a dangling image.
|
||||
defer func() {
|
||||
if outNewImg != nil {
|
||||
if outNewImg.Target().Digest != oldImage.Target.Digest {
|
||||
if err := i.ensureDanglingImage(ctx, oldImage); err != nil {
|
||||
log.G(ctx).WithError(err).Warn("failed to keep the previous image as dangling")
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := lm.Delete(ctx, lease); err != nil {
|
||||
log.G(ctx).WithError(err).Warn("failed to delete lease")
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
p := platforms.Default()
|
||||
if platform != nil {
|
||||
p = platforms.Only(*platform)
|
||||
@@ -100,7 +133,6 @@ func (i *ImageService) pullTag(ctx context.Context, ref reference.Named, platfor
|
||||
pp := pullProgress{store: i.content, showExists: true}
|
||||
finishProgress := jobs.showProgress(ctx, out, pp)
|
||||
|
||||
var outNewImg *containerd.Image
|
||||
defer func() {
|
||||
finishProgress()
|
||||
|
||||
@@ -114,9 +146,10 @@ func (i *ImageService) pullTag(ctx context.Context, ref reference.Named, platfor
|
||||
// Status: Downloaded newer image for hello-world:latest
|
||||
// docker.io/library/hello-world:latest
|
||||
if outNewImg != nil {
|
||||
img := *outNewImg
|
||||
img := outNewImg
|
||||
progress.Message(out, "", "Digest: "+img.Target().Digest.String())
|
||||
writeStatus(out, reference.FamiliarString(ref), old.Digest != img.Target().Digest)
|
||||
newer := oldImage.Target.Digest != img.Target().Digest
|
||||
writeStatus(out, reference.FamiliarString(ref), newer)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -202,7 +235,7 @@ func (i *ImageService) pullTag(ctx context.Context, ref reference.Named, platfor
|
||||
}
|
||||
|
||||
i.LogImageEvent(reference.FamiliarString(ref), reference.FamiliarName(ref), events.ActionPull)
|
||||
outNewImg = &img
|
||||
outNewImg = img
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -12,11 +12,11 @@ import (
|
||||
"github.com/containerd/containerd/images"
|
||||
containerdimages "github.com/containerd/containerd/images"
|
||||
containerdlabels "github.com/containerd/containerd/labels"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api/types/auxprogress"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
containerdimages "github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/internal/testutils/specialimage"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
@@ -204,7 +204,7 @@ func TestImagePushIndex(t *testing.T) {
|
||||
imgSvc.defaultPlatformOverride = platforms.Only(defaultDaemonPlatform)
|
||||
}
|
||||
|
||||
idx, err := specialimage.MultiPlatform(csDir, "multiplatform:latest", tc.indexPlatforms)
|
||||
idx, _, err := specialimage.MultiPlatform(csDir, "multiplatform:latest", tc.indexPlatforms)
|
||||
assert.NilError(t, err)
|
||||
|
||||
imgs := imagesFromIndex(idx)
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
containerdimages "github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/leases"
|
||||
"github.com/containerd/containerd/mount"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/opencontainers/image-spec/identity"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
||||
@@ -267,7 +267,6 @@ func desc(size int64) ocispec.Descriptor {
|
||||
Size: size,
|
||||
MediaType: ocispec.MediaTypeImageIndex,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func digestFor(i int64) digest.Digest {
|
||||
@@ -284,7 +283,7 @@ func newTestDB(ctx context.Context, t testing.TB) *metadata.DB {
|
||||
t.Helper()
|
||||
|
||||
p := filepath.Join(t.TempDir(), "metadata")
|
||||
bdb, err := bbolt.Open(p, 0600, &bbolt.Options{})
|
||||
bdb, err := bbolt.Open(p, 0o600, &bbolt.Options{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/platforms"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
@@ -24,3 +24,11 @@ func (c allPlatformsWithPreferenceMatcher) Match(_ ocispec.Platform) bool {
|
||||
func (c allPlatformsWithPreferenceMatcher) Less(p1, p2 ocispec.Platform) bool {
|
||||
return c.preferred.Less(p1, p2)
|
||||
}
|
||||
|
||||
func (i *ImageService) hostPlatformMatcher() platforms.MatchComparer {
|
||||
// Allow to override the host platform for testing purposes.
|
||||
if i.defaultPlatformOverride != nil {
|
||||
return i.defaultPlatformOverride
|
||||
}
|
||||
return platforms.Default()
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@ import (
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/containerd/plugin"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/container"
|
||||
daemonevents "github.com/docker/docker/daemon/events"
|
||||
|
||||
@@ -23,7 +23,6 @@ func (i *ImageService) softImageDelete(ctx context.Context, img containerdimages
|
||||
// Create dangling image if this is the last image pointing to this target.
|
||||
if len(imgs) == 1 {
|
||||
err := i.ensureDanglingImage(context.WithoutCancel(ctx), img)
|
||||
|
||||
// Error out in case we couldn't persist the old image.
|
||||
if err != nil {
|
||||
return errdefs.System(errors.Wrapf(err, "failed to create a dangling image for the replaced image %s with digest %s",
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/defaults"
|
||||
"github.com/containerd/containerd/pkg/dialer"
|
||||
"github.com/containerd/containerd/pkg/userns"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
"github.com/containerd/log"
|
||||
"github.com/distribution/reference"
|
||||
@@ -81,6 +80,7 @@ import (
|
||||
resolverconfig "github.com/moby/buildkit/util/resolver/config"
|
||||
"github.com/moby/buildkit/util/tracing"
|
||||
"github.com/moby/locker"
|
||||
"github.com/moby/sys/userns"
|
||||
"github.com/pkg/errors"
|
||||
"go.etcd.io/bbolt"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/containerd/cgroups/v3"
|
||||
"github.com/containerd/containerd/pkg/userns"
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/types/blkiodev"
|
||||
pblkiodev "github.com/docker/docker/api/types/blkiodev"
|
||||
@@ -43,6 +42,7 @@ import (
|
||||
"github.com/docker/docker/runconfig"
|
||||
volumemounts "github.com/docker/docker/volume/mounts"
|
||||
"github.com/moby/sys/mount"
|
||||
"github.com/moby/sys/userns"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/opencontainers/selinux/go-selinux"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/daemon/config"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/internal/containerfs"
|
||||
"github.com/opencontainers/selinux/go-selinux"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -161,6 +161,8 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, config ba
|
||||
// so that other goroutines don't attempt to concurrently open files
|
||||
// within it. Having any file open on Windows (without the
|
||||
// FILE_SHARE_DELETE flag) will block it from being deleted.
|
||||
//
|
||||
// TODO(thaJeztah): should this be moved to the "container" itself, or possibly be delegated to the graphdriver or snapshotter?
|
||||
container.Lock()
|
||||
err := containerfs.EnsureRemoveAll(container.Root)
|
||||
container.Unlock()
|
||||
|
||||
@@ -34,14 +34,14 @@ import (
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/containerd/containerd/pkg/userns"
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/daemon/graphdriver"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/internal/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
units "github.com/docker/go-units"
|
||||
"github.com/moby/sys/mount"
|
||||
"github.com/moby/sys/userns"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
@@ -12,9 +12,9 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/pkg/userns"
|
||||
"github.com/docker/docker/pkg/pools"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/moby/sys/userns"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
|
||||
@@ -13,18 +13,18 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/pkg/userns"
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/daemon/graphdriver"
|
||||
"github.com/docker/docker/daemon/graphdriver/overlayutils"
|
||||
"github.com/docker/docker/internal/containerfs"
|
||||
"github.com/docker/docker/internal/directory"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/chrootarchive"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/directory"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"github.com/moby/locker"
|
||||
"github.com/moby/sys/mount"
|
||||
"github.com/moby/sys/userns"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/containerd/containerd/mount"
|
||||
"github.com/containerd/containerd/pkg/userns"
|
||||
"github.com/docker/docker/daemon/graphdriver/overlayutils"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/moby/sys/userns"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
@@ -18,10 +18,10 @@ import (
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/daemon/graphdriver"
|
||||
"github.com/docker/docker/daemon/graphdriver/overlayutils"
|
||||
"github.com/docker/docker/internal/containerfs"
|
||||
"github.com/docker/docker/internal/directory"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/chrootarchive"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/directory"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
units "github.com/docker/go-units"
|
||||
"github.com/moby/locker"
|
||||
"github.com/moby/sys/mount"
|
||||
"github.com/moby/sys/userns"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
@@ -678,7 +679,6 @@ func (d *Driver) ApplyDiff(id string, parent string, diff io.Reader) (size int64
|
||||
return d.naiveDiff.ApplyDiff(id, parent, diff)
|
||||
}
|
||||
|
||||
// never reach here if we are running in UserNS
|
||||
applyDir := d.getDiffPath(id)
|
||||
|
||||
logger.Debugf("Applying tar in %s", applyDir)
|
||||
@@ -686,6 +686,7 @@ func (d *Driver) ApplyDiff(id string, parent string, diff io.Reader) (size int64
|
||||
if err := untar(diff, applyDir, &archive.TarOptions{
|
||||
IDMap: d.idMap,
|
||||
WhiteoutFormat: archive.OverlayWhiteoutFormat,
|
||||
InUserNS: userns.RunningInUserNS(),
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/containerd/containerd/pkg/userns"
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/daemon/graphdriver"
|
||||
"github.com/moby/sys/userns"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
@@ -26,9 +26,9 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/containerd/containerd/mount"
|
||||
"github.com/containerd/containerd/pkg/userns"
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"github.com/moby/sys/userns"
|
||||
)
|
||||
|
||||
// NeedsUserXAttr returns whether overlayfs should be mounted with the "userxattr" mount option.
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/docker/docker/daemon/graphdriver"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/internal/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"github.com/docker/docker/quota"
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/leases"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/errdefs"
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
|
||||
@@ -229,7 +229,6 @@ func (daemon *Daemon) fillDebugInfo(ctx context.Context, v *system.Info) {
|
||||
v.NFd = fileutils.GetTotalUsedFds(ctx)
|
||||
v.NGoroutines = runtime.NumGoroutine()
|
||||
v.NEventsListener = daemon.EventsService.SubscribersCount()
|
||||
|
||||
}
|
||||
|
||||
// fillContainerdInfo provides information about the containerd configuration
|
||||
|
||||
@@ -813,7 +813,7 @@ func (daemon *Daemon) clearAttachableNetworks() {
|
||||
// buildCreateEndpointOptions builds endpoint options from a given network.
|
||||
func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, epConfig *network.EndpointSettings, sb *libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) {
|
||||
var createOptions []libnetwork.EndpointOption
|
||||
var genericOptions = make(options.Generic)
|
||||
genericOptions := make(options.Generic)
|
||||
|
||||
nwName := n.Name()
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"github.com/containerd/containerd/containers"
|
||||
coci "github.com/containerd/containerd/oci"
|
||||
"github.com/containerd/containerd/pkg/apparmor"
|
||||
"github.com/containerd/containerd/pkg/userns"
|
||||
"github.com/containerd/log"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/container"
|
||||
@@ -21,15 +20,16 @@ import (
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/internal/otelutil"
|
||||
"github.com/docker/docker/internal/rootless/mountopts"
|
||||
"github.com/docker/docker/internal/rootless/specconv"
|
||||
"github.com/docker/docker/oci"
|
||||
"github.com/docker/docker/oci/caps"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/rootless/specconv"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
volumemounts "github.com/docker/docker/volume/mounts"
|
||||
"github.com/moby/sys/mount"
|
||||
"github.com/moby/sys/mountinfo"
|
||||
"github.com/moby/sys/user"
|
||||
"github.com/moby/sys/userns"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user