Compare commits
31 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1331b8c39a | ||
![]() |
907f037141 | ||
![]() |
a5b597ea51 | ||
![]() |
8bbfa32741 | ||
![]() |
807e415260 | ||
![]() |
8587a1c617 | ||
![]() |
9717369913 | ||
![]() |
ed0c147c8f | ||
![]() |
90be9ab802 | ||
![]() |
d73f7031e0 | ||
![]() |
ea7f7f168e | ||
![]() |
233c49438b | ||
![]() |
2b7424512a | ||
![]() |
f77a3274b4 | ||
![]() |
c76bb6a3a3 | ||
![]() |
71846e82c1 | ||
![]() |
ecbc27aa22 | ||
![]() |
c01f02cfcb | ||
![]() |
ce79cd19f6 | ||
![]() |
1235338836 | ||
![]() |
763d2b7996 | ||
![]() |
e9eff01dca | ||
![]() |
69ef9a7f90 | ||
![]() |
86770904be | ||
![]() |
31b98f9502 | ||
![]() |
bfffb0974e | ||
![]() |
e28bc0d271 | ||
![]() |
d169a57306 | ||
![]() |
63640838ba | ||
![]() |
269e55a915 | ||
![]() |
012dd239ce |
5825 changed files with 213829 additions and 489225 deletions
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"name": "moby",
|
||||
"build": {
|
||||
"context": "..",
|
||||
"dockerfile": "../Dockerfile",
|
||||
"target": "devcontainer"
|
||||
},
|
||||
"workspaceFolder": "/go/src/github.com/docker/docker",
|
||||
"workspaceMount": "source=${localWorkspaceFolder},target=/go/src/github.com/docker/docker,type=bind,consistency=cached",
|
||||
|
||||
"remoteUser": "root",
|
||||
"runArgs": ["--privileged"],
|
||||
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"golang.go"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -5,6 +5,7 @@
|
|||
|
||||
builder/** @tonistiigi
|
||||
contrib/mkimage/** @tianon
|
||||
daemon/graphdriver/devmapper/** @rhvgoyal
|
||||
daemon/graphdriver/overlay2/** @dmcgowan
|
||||
daemon/graphdriver/windows/** @johnstep
|
||||
daemon/logger/awslogs/** @samuelkarp
|
||||
|
|
5
.github/PULL_REQUEST_TEMPLATE.md
vendored
5
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -22,12 +22,9 @@ Please provide the following information:
|
|||
**- Description for the changelog**
|
||||
<!--
|
||||
Write a short (one line) summary that describes the changes in this
|
||||
pull request for inclusion in the changelog.
|
||||
It must be placed inside the below triple backticks section:
|
||||
pull request for inclusion in the changelog:
|
||||
-->
|
||||
```markdown changelog
|
||||
|
||||
```
|
||||
|
||||
**- A picture of a cute animal (not mandatory but encouraged)**
|
||||
|
||||
|
|
2
.github/actions/setup-runner/action.yml
vendored
2
.github/actions/setup-runner/action.yml
vendored
|
@ -13,7 +13,7 @@ runs:
|
|||
shell: bash
|
||||
- run: |
|
||||
if [ ! -e /etc/docker/daemon.json ]; then
|
||||
echo '{}' | sudo tee /etc/docker/daemon.json >/dev/null
|
||||
echo '{}' | tee /etc/docker/daemon.json >/dev/null
|
||||
fi
|
||||
DOCKERD_CONFIG=$(jq '.+{"experimental":true,"live-restore":true,"ipv6":true,"fixed-cidr-v6":"2001:db8:1::/64"}' /etc/docker/daemon.json)
|
||||
sudo tee /etc/docker/daemon.json <<<"$DOCKERD_CONFIG" >/dev/null
|
||||
|
|
14
.github/actions/setup-tracing/action.yml
vendored
14
.github/actions/setup-tracing/action.yml
vendored
|
@ -1,14 +0,0 @@
|
|||
name: 'Setup Tracing'
|
||||
description: 'Composite action to set up the tracing for test jobs'
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- run: |
|
||||
set -e
|
||||
# Jaeger is set up on Windows through an inline run step. If you update Jaeger here, don't forget to update
|
||||
# the version set in .github/workflows/.windows.yml.
|
||||
docker run -d --net=host --name jaeger -e COLLECTOR_OTLP_ENABLED=true jaegertracing/all-in-one:1.46
|
||||
docker0_ip="$(ip -f inet addr show docker0 | grep -Po 'inet \K[\d.]+')"
|
||||
echo "OTEL_EXPORTER_OTLP_ENDPOINT=http://${docker0_ip}:4318" >> "${GITHUB_ENV}"
|
||||
shell: bash
|
6
.github/workflows/.dco.yml
vendored
6
.github/workflows/.dco.yml
vendored
|
@ -15,19 +15,19 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Dump context
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
console.log(JSON.stringify(context, null, 2));
|
||||
-
|
||||
name: Get base ref
|
||||
id: base-ref
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
|
|
35
.github/workflows/.test-prepare.yml
vendored
35
.github/workflows/.test-prepare.yml
vendored
|
@ -1,35 +0,0 @@
|
|||
# reusable workflow
|
||||
name: .test-prepare
|
||||
|
||||
# TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
outputs:
|
||||
matrix:
|
||||
description: Test matrix
|
||||
value: ${{ jobs.run.outputs.matrix }}
|
||||
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-20.04
|
||||
outputs:
|
||||
matrix: ${{ steps.set.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Create matrix
|
||||
id: set
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
let matrix = ['graphdriver'];
|
||||
if ("${{ contains(github.event.pull_request.labels.*.name, 'containerd-integration') || github.event_name != 'pull_request' }}" == "true") {
|
||||
matrix.push('snapshotter');
|
||||
}
|
||||
await core.group(`Set matrix`, async () => {
|
||||
core.info(`matrix: ${JSON.stringify(matrix)}`);
|
||||
core.setOutput('matrix', JSON.stringify(matrix));
|
||||
});
|
445
.github/workflows/.test.yml
vendored
445
.github/workflows/.test.yml
vendored
|
@ -1,445 +0,0 @@
|
|||
# reusable workflow
|
||||
name: .test
|
||||
|
||||
# TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
storage:
|
||||
required: true
|
||||
type: string
|
||||
default: "graphdriver"
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.21.9"
|
||||
GOTESTLIST_VERSION: v0.3.1
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
ITG_CLI_MATRIX_SIZE: 6
|
||||
DOCKER_EXPERIMENTAL: 1
|
||||
DOCKER_GRAPHDRIVER: ${{ inputs.storage == 'snapshotter' && 'overlayfs' || 'overlay2' }}
|
||||
TEST_INTEGRATION_USE_SNAPSHOTTER: ${{ inputs.storage == 'snapshotter' && '1' || '' }}
|
||||
|
||||
jobs:
|
||||
unit:
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-unit
|
||||
-
|
||||
name: Prepare reports
|
||||
if: always()
|
||||
run: |
|
||||
mkdir -p bundles /tmp/reports
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \( -name '*-report.json' -o -name '*.log' -o -name '*.out' -o -name '*.prof' -o -name '*-report.xml' \) -print | xargs sudo tar -czf /tmp/reports.tar.gz
|
||||
tar -xzf /tmp/reports.tar.gz -C /tmp/reports
|
||||
sudo chown -R $(id -u):$(id -g) /tmp/reports
|
||||
tree -nh /tmp/reports
|
||||
-
|
||||
name: Send to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
directory: ./bundles
|
||||
env_vars: RUNNER_OS
|
||||
flags: unit
|
||||
token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-reports-unit-${{ inputs.storage }}
|
||||
path: /tmp/reports/*
|
||||
retention-days: 1
|
||||
|
||||
unit-report:
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 10
|
||||
if: always()
|
||||
needs:
|
||||
- unit
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: test-reports-unit-${{ inputs.storage }}
|
||||
path: /tmp/reports
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
find /tmp/reports -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
docker-py:
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up tracing
|
||||
uses: ./.github/actions/setup-tracing
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-docker-py
|
||||
-
|
||||
name: Prepare reports
|
||||
if: always()
|
||||
run: |
|
||||
mkdir -p bundles /tmp/reports
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \( -name '*-report.json' -o -name '*.log' -o -name '*.out' -o -name '*.prof' -o -name '*-report.xml' \) -print | xargs sudo tar -czf /tmp/reports.tar.gz
|
||||
tar -xzf /tmp/reports.tar.gz -C /tmp/reports
|
||||
sudo chown -R $(id -u):$(id -g) /tmp/reports
|
||||
tree -nh /tmp/reports
|
||||
|
||||
curl -sSLf localhost:16686/api/traces?service=integration-test-client > /tmp/reports/jaeger-trace.json
|
||||
-
|
||||
name: Test daemon logs
|
||||
if: always()
|
||||
run: |
|
||||
cat bundles/test-docker-py/docker.log
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-reports-docker-py-${{ inputs.storage }}
|
||||
path: /tmp/reports/*
|
||||
retention-days: 1
|
||||
|
||||
integration-flaky:
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-integration-flaky
|
||||
env:
|
||||
TEST_SKIP_INTEGRATION_CLI: 1
|
||||
|
||||
integration:
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 120
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-20.04
|
||||
- ubuntu-22.04
|
||||
mode:
|
||||
- ""
|
||||
- rootless
|
||||
- systemd
|
||||
#- rootless-systemd FIXME: https://github.com/moby/moby/issues/44084
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up tracing
|
||||
uses: ./.github/actions/setup-tracing
|
||||
-
|
||||
name: Prepare
|
||||
run: |
|
||||
CACHE_DEV_SCOPE=dev
|
||||
if [[ "${{ matrix.mode }}" == *"rootless"* ]]; then
|
||||
echo "DOCKER_ROOTLESS=1" >> $GITHUB_ENV
|
||||
fi
|
||||
if [[ "${{ matrix.mode }}" == *"systemd"* ]]; then
|
||||
echo "SYSTEMD=true" >> $GITHUB_ENV
|
||||
CACHE_DEV_SCOPE="${CACHE_DEV_SCOPE}systemd"
|
||||
fi
|
||||
echo "CACHE_DEV_SCOPE=${CACHE_DEV_SCOPE}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=${{ env.CACHE_DEV_SCOPE }}
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-integration
|
||||
env:
|
||||
TEST_SKIP_INTEGRATION_CLI: 1
|
||||
TESTCOVERAGE: 1
|
||||
-
|
||||
name: Prepare reports
|
||||
if: always()
|
||||
run: |
|
||||
reportsName=${{ matrix.os }}
|
||||
if [ -n "${{ matrix.mode }}" ]; then
|
||||
reportsName="$reportsName-${{ matrix.mode }}"
|
||||
fi
|
||||
reportsPath="/tmp/reports/$reportsName"
|
||||
echo "TESTREPORTS_NAME=$reportsName" >> $GITHUB_ENV
|
||||
|
||||
mkdir -p bundles $reportsPath
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \( -name '*-report.json' -o -name '*.log' -o -name '*.out' -o -name '*.prof' -o -name '*-report.xml' \) -print | xargs sudo tar -czf /tmp/reports.tar.gz
|
||||
tar -xzf /tmp/reports.tar.gz -C $reportsPath
|
||||
sudo chown -R $(id -u):$(id -g) $reportsPath
|
||||
tree -nh $reportsPath
|
||||
|
||||
curl -sSLf localhost:16686/api/traces?service=integration-test-client > $reportsPath/jaeger-trace.json
|
||||
-
|
||||
name: Send to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
directory: ./bundles/test-integration
|
||||
env_vars: RUNNER_OS
|
||||
flags: integration,${{ matrix.mode }}
|
||||
token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533
|
||||
-
|
||||
name: Test daemon logs
|
||||
if: always()
|
||||
run: |
|
||||
cat bundles/test-integration/docker.log
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-reports-integration-${{ inputs.storage }}-${{ env.TESTREPORTS_NAME }}
|
||||
path: /tmp/reports/*
|
||||
retention-days: 1
|
||||
|
||||
integration-report:
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 10
|
||||
if: always()
|
||||
needs:
|
||||
- integration
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/reports
|
||||
pattern: test-reports-integration-${{ inputs.storage }}-*
|
||||
merge-multiple: true
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
find /tmp/reports -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
integration-cli-prepare:
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
outputs:
|
||||
matrix: ${{ steps.tests.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Install gotestlist
|
||||
run:
|
||||
go install github.com/crazy-max/gotestlist/cmd/gotestlist@${{ env.GOTESTLIST_VERSION }}
|
||||
-
|
||||
name: Create matrix
|
||||
id: tests
|
||||
working-directory: ./integration-cli
|
||||
run: |
|
||||
# This step creates a matrix for integration-cli tests. Tests suites
|
||||
# are distributed in integration-cli job through a matrix. There is
|
||||
# also overrides being added to the matrix like "./..." to run
|
||||
# "Test integration" step exclusively and specific tests suites that
|
||||
# take a long time to run.
|
||||
matrix="$(gotestlist -d ${{ env.ITG_CLI_MATRIX_SIZE }} -o "./..." -o "DockerSwarmSuite" -o "DockerNetworkSuite|DockerExternalVolumeSuite" ./...)"
|
||||
echo "matrix=$matrix" >> $GITHUB_OUTPUT
|
||||
-
|
||||
name: Show matrix
|
||||
run: |
|
||||
echo ${{ steps.tests.outputs.matrix }}
|
||||
|
||||
integration-cli:
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- integration-cli-prepare
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
test: ${{ fromJson(needs.integration-cli-prepare.outputs.matrix) }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up tracing
|
||||
uses: ./.github/actions/setup-tracing
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-integration
|
||||
env:
|
||||
TEST_SKIP_INTEGRATION: 1
|
||||
TESTCOVERAGE: 1
|
||||
TESTFLAGS: "-test.run (${{ matrix.test }})/"
|
||||
-
|
||||
name: Prepare reports
|
||||
if: always()
|
||||
run: |
|
||||
reportsName=$(echo -n "${{ matrix.test }}" | sha256sum | cut -d " " -f 1)
|
||||
reportsPath=/tmp/reports/$reportsName
|
||||
echo "TESTREPORTS_NAME=$reportsName" >> $GITHUB_ENV
|
||||
|
||||
mkdir -p bundles $reportsPath
|
||||
echo "${{ matrix.test }}" | tr -s '|' '\n' | tee -a "$reportsPath/tests.txt"
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \( -name '*-report.json' -o -name '*.log' -o -name '*.out' -o -name '*.prof' -o -name '*-report.xml' \) -print | xargs sudo tar -czf /tmp/reports.tar.gz
|
||||
tar -xzf /tmp/reports.tar.gz -C $reportsPath
|
||||
sudo chown -R $(id -u):$(id -g) $reportsPath
|
||||
tree -nh $reportsPath
|
||||
|
||||
curl -sSLf localhost:16686/api/traces?service=integration-test-client > $reportsPath/jaeger-trace.json
|
||||
-
|
||||
name: Send to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
directory: ./bundles/test-integration
|
||||
env_vars: RUNNER_OS
|
||||
flags: integration-cli
|
||||
token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533
|
||||
-
|
||||
name: Test daemon logs
|
||||
if: always()
|
||||
run: |
|
||||
cat bundles/test-integration/docker.log
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-reports-integration-cli-${{ inputs.storage }}-${{ env.TESTREPORTS_NAME }}
|
||||
path: /tmp/reports/*
|
||||
retention-days: 1
|
||||
|
||||
integration-cli-report:
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 10
|
||||
if: always()
|
||||
needs:
|
||||
- integration-cli
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/reports
|
||||
pattern: test-reports-integration-cli-${{ inputs.storage }}-*
|
||||
merge-multiple: true
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
find /tmp/reports -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
|
124
.github/workflows/.windows.yml
vendored
124
.github/workflows/.windows.yml
vendored
|
@ -9,19 +9,15 @@ on:
|
|||
os:
|
||||
required: true
|
||||
type: string
|
||||
storage:
|
||||
required: true
|
||||
type: string
|
||||
default: "graphdriver"
|
||||
send_coverage:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.21.9"
|
||||
GO_VERSION: "1.20.4"
|
||||
GOTESTLIST_VERSION: v0.3.1
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
TESTSTAT_VERSION: v0.1.3
|
||||
WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore
|
||||
WINDOWS_BASE_TAG_2019: ltsc2019
|
||||
WINDOWS_BASE_TAG_2022: ltsc2022
|
||||
|
@ -43,7 +39,7 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
-
|
||||
|
@ -62,7 +58,7 @@ jobs:
|
|||
}
|
||||
-
|
||||
name: Cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~\AppData\Local\go-build
|
||||
|
@ -79,12 +75,9 @@ jobs:
|
|||
-
|
||||
name: Build base image
|
||||
run: |
|
||||
& docker build `
|
||||
--build-arg WINDOWS_BASE_IMAGE `
|
||||
--build-arg WINDOWS_BASE_IMAGE_TAG `
|
||||
--build-arg GO_VERSION `
|
||||
-t ${{ env.TEST_IMAGE_NAME }} `
|
||||
-f Dockerfile.windows .
|
||||
docker pull ${{ env.WINDOWS_BASE_IMAGE }}:${{ env.WINDOWS_BASE_IMAGE_TAG }}
|
||||
docker tag ${{ env.WINDOWS_BASE_IMAGE }}:${{ env.WINDOWS_BASE_IMAGE_TAG }} microsoft/windowsservercore
|
||||
docker build --build-arg GO_VERSION -t ${{ env.TEST_IMAGE_NAME }} -f Dockerfile.windows .
|
||||
-
|
||||
name: Build binaries
|
||||
run: |
|
||||
|
@ -103,9 +96,9 @@ jobs:
|
|||
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\containerd\bin\containerd-shim-runhcs-v1.exe" ${{ env.BIN_OUT }}\
|
||||
-
|
||||
name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: build-${{ inputs.storage }}-${{ inputs.os }}
|
||||
name: build-${{ inputs.os }}
|
||||
path: ${{ env.BIN_OUT }}/*
|
||||
if-no-files-found: error
|
||||
retention-days: 2
|
||||
|
@ -122,7 +115,7 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
-
|
||||
|
@ -142,7 +135,7 @@ jobs:
|
|||
}
|
||||
-
|
||||
name: Cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~\AppData\Local\go-build
|
||||
|
@ -159,12 +152,9 @@ jobs:
|
|||
-
|
||||
name: Build base image
|
||||
run: |
|
||||
& docker build `
|
||||
--build-arg WINDOWS_BASE_IMAGE `
|
||||
--build-arg WINDOWS_BASE_IMAGE_TAG `
|
||||
--build-arg GO_VERSION `
|
||||
-t ${{ env.TEST_IMAGE_NAME }} `
|
||||
-f Dockerfile.windows .
|
||||
docker pull ${{ env.WINDOWS_BASE_IMAGE }}:${{ env.WINDOWS_BASE_IMAGE_TAG }}
|
||||
docker tag ${{ env.WINDOWS_BASE_IMAGE }}:${{ env.WINDOWS_BASE_IMAGE_TAG }} microsoft/windowsservercore
|
||||
docker build --build-arg GO_VERSION -t ${{ env.TEST_IMAGE_NAME }} -f Dockerfile.windows .
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
|
@ -176,21 +166,19 @@ jobs:
|
|||
-
|
||||
name: Send to Codecov
|
||||
if: inputs.send_coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
working-directory: ${{ env.GOPATH }}\src\github.com\docker\docker
|
||||
directory: bundles
|
||||
env_vars: RUNNER_OS
|
||||
flags: unit
|
||||
token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ inputs.os }}-${{ inputs.storage }}-unit-reports
|
||||
name: ${{ inputs.os }}-unit-reports
|
||||
path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\*
|
||||
retention-days: 1
|
||||
|
||||
unit-test-report:
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -200,14 +188,14 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ inputs.os }}-${{ inputs.storage }}-unit-reports
|
||||
name: ${{ inputs.os }}-unit-reports
|
||||
path: /tmp/artifacts
|
||||
-
|
||||
name: Install teststat
|
||||
|
@ -216,7 +204,7 @@ jobs:
|
|||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
find /tmp/artifacts -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
|
||||
teststat -markdown $(find /tmp/artifacts -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
integration-test-prepare:
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -225,10 +213,10 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
|
@ -253,7 +241,6 @@ jobs:
|
|||
|
||||
integration-test:
|
||||
runs-on: ${{ inputs.os }}
|
||||
continue-on-error: ${{ inputs.storage == 'snapshotter' && github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- build
|
||||
|
@ -261,15 +248,10 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
storage:
|
||||
- ${{ inputs.storage }}
|
||||
runtime:
|
||||
- builtin
|
||||
- containerd
|
||||
test: ${{ fromJson(needs.integration-test-prepare.outputs.matrix) }}
|
||||
exclude:
|
||||
- storage: snapshotter
|
||||
runtime: builtin
|
||||
env:
|
||||
GOPATH: ${{ github.workspace }}\go
|
||||
GOBIN: ${{ github.workspace }}\go\bin
|
||||
|
@ -280,28 +262,18 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
-
|
||||
name: Set up Jaeger
|
||||
run: |
|
||||
# Jaeger is set up on Linux through the setup-tracing action. If you update Jaeger here, don't forget to
|
||||
# update the version set in .github/actions/setup-tracing/action.yml.
|
||||
Invoke-WebRequest -Uri "https://github.com/jaegertracing/jaeger/releases/download/v1.46.0/jaeger-1.46.0-windows-amd64.tar.gz" -OutFile ".\jaeger-1.46.0-windows-amd64.tar.gz"
|
||||
tar -zxvf ".\jaeger-1.46.0-windows-amd64.tar.gz"
|
||||
Start-Process '.\jaeger-1.46.0-windows-amd64\jaeger-all-in-one.exe'
|
||||
echo "OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
shell: pwsh
|
||||
-
|
||||
name: Env
|
||||
run: |
|
||||
Get-ChildItem Env: | Out-String
|
||||
-
|
||||
name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: build-${{ inputs.storage }}-${{ inputs.os }}
|
||||
name: build-${{ inputs.os }}
|
||||
path: ${{ env.BIN_OUT }}
|
||||
-
|
||||
name: Init
|
||||
|
@ -313,9 +285,6 @@ jobs:
|
|||
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
}
|
||||
Write-Output "${{ env.BIN_OUT }}" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
|
||||
$testName = ([System.BitConverter]::ToString((New-Object System.Security.Cryptography.SHA256Managed).ComputeHash([System.Text.Encoding]::UTF8.GetBytes("${{ matrix.test }}"))) -replace '-').ToLower()
|
||||
echo "TESTREPORTS_NAME=$testName" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
-
|
||||
# removes docker service that is currently installed on the runner. we
|
||||
# could use Uninstall-Package but not yet available on Windows runners.
|
||||
|
@ -373,11 +342,6 @@ jobs:
|
|||
"--exec-root=$env:TEMP\moby-exec", `
|
||||
"--pidfile=$env:TEMP\docker.pid", `
|
||||
"--register-service"
|
||||
If ("${{ inputs.storage }}" -eq "snapshotter") {
|
||||
# Make the env-var visible to the service-managed dockerd, as there's no CLI flag for this option.
|
||||
& reg add "HKLM\SYSTEM\CurrentControlSet\Services\docker" /v Environment /t REG_MULTI_SZ /s '@' /d TEST_INTEGRATION_USE_SNAPSHOTTER=1
|
||||
echo "TEST_INTEGRATION_USE_SNAPSHOTTER=1" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
}
|
||||
Write-Host "Starting service"
|
||||
Start-Service -Name docker
|
||||
Write-Host "Service started successfully!"
|
||||
|
@ -426,7 +390,7 @@ jobs:
|
|||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
|
@ -451,13 +415,12 @@ jobs:
|
|||
-
|
||||
name: Send to Codecov
|
||||
if: inputs.send_coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
working-directory: ${{ env.GOPATH }}\src\github.com\docker\docker
|
||||
directory: bundles
|
||||
env_vars: RUNNER_OS
|
||||
flags: integration,${{ matrix.runtime }}
|
||||
token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533
|
||||
-
|
||||
name: Docker info
|
||||
run: |
|
||||
|
@ -495,52 +458,37 @@ jobs:
|
|||
Sort-Object @{Expression="TimeCreated";Descending=$false} |
|
||||
ForEach-Object {"$($_.TimeCreated.ToUniversalTime().ToString("o")) [$($_.LevelDisplayName)] $($_.Message)"} |
|
||||
Tee-Object -file ".\bundles\daemon.log"
|
||||
-
|
||||
name: Download Jaeger traces
|
||||
if: always()
|
||||
run: |
|
||||
Invoke-WebRequest `
|
||||
-Uri "http://127.0.0.1:16686/api/traces?service=integration-test-client" `
|
||||
-OutFile ".\bundles\jaeger-trace.json"
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ inputs.os }}-${{ inputs.storage }}-integration-reports-${{ matrix.runtime }}-${{ env.TESTREPORTS_NAME }}
|
||||
name: ${{ inputs.os }}-integration-reports-${{ matrix.runtime }}
|
||||
path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\*
|
||||
retention-days: 1
|
||||
|
||||
integration-test-report:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: ${{ inputs.storage == 'snapshotter' && github.event_name != 'pull_request' }}
|
||||
if: always()
|
||||
needs:
|
||||
- integration-test
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
storage:
|
||||
- ${{ inputs.storage }}
|
||||
runtime:
|
||||
- builtin
|
||||
- containerd
|
||||
exclude:
|
||||
- storage: snapshotter
|
||||
runtime: builtin
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
path: /tmp/reports
|
||||
pattern: ${{ inputs.os }}-${{ inputs.storage }}-integration-reports-${{ matrix.runtime }}-*
|
||||
merge-multiple: true
|
||||
name: ${{ inputs.os }}-integration-reports-${{ matrix.runtime }}
|
||||
path: /tmp/artifacts
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
|
@ -548,4 +496,4 @@ jobs:
|
|||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
find /tmp/reports -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
|
||||
teststat -markdown $(find /tmp/artifacts -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
|
||||
|
|
155
.github/workflows/bin-image.yml
vendored
155
.github/workflows/bin-image.yml
vendored
|
@ -15,33 +15,31 @@ on:
|
|||
pull_request:
|
||||
|
||||
env:
|
||||
MOBYBIN_REPO_SLUG: moby/moby-bin
|
||||
DOCKER_GITCOMMIT: ${{ github.sha }}
|
||||
VERSION: ${{ github.ref }}
|
||||
PLATFORM: Moby Engine - Nightly
|
||||
PRODUCT: moby-bin
|
||||
PACKAGER_NAME: The Moby Project
|
||||
PLATFORM: Moby Engine
|
||||
PRODUCT: Moby
|
||||
DEFAULT_PRODUCT_LICENSE: Moby
|
||||
PACKAGER_NAME: Moby
|
||||
|
||||
jobs:
|
||||
validate-dco:
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
|
||||
uses: ./.github/workflows/.dco.yml
|
||||
|
||||
prepare:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
outputs:
|
||||
platforms: ${{ steps.platforms.outputs.matrix }}
|
||||
needs:
|
||||
- validate-dco
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
${{ env.MOBYBIN_REPO_SLUG }}
|
||||
images: moby-bin
|
||||
### versioning strategy
|
||||
## push semver tag v23.0.0
|
||||
# moby/moby-bin:23.0.0
|
||||
|
@ -52,140 +50,23 @@ jobs:
|
|||
# moby/moby-bin:master
|
||||
## push on 23.0 branch
|
||||
# moby/moby-bin:23.0
|
||||
## any push
|
||||
# moby/moby-bin:sha-ad132f5
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=sha
|
||||
-
|
||||
name: Rename meta bake definition file
|
||||
# see https://github.com/docker/metadata-action/issues/381#issuecomment-1918607161
|
||||
run: |
|
||||
bakeFile="${{ steps.meta.outputs.bake-file }}"
|
||||
mv "${bakeFile#cwd://}" "/tmp/bake-meta.json"
|
||||
-
|
||||
name: Upload meta bake definition
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bake-meta
|
||||
path: /tmp/bake-meta.json
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
-
|
||||
name: Create platforms matrix
|
||||
id: platforms
|
||||
run: |
|
||||
echo "matrix=$(docker buildx bake bin-image-cross --print | jq -cr '.target."bin-image-cross".platforms')" >>${GITHUB_OUTPUT}
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
- prepare
|
||||
if: always() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled')
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: ${{ fromJson(needs.prepare.outputs.platforms) }}
|
||||
steps:
|
||||
-
|
||||
name: Prepare
|
||||
run: |
|
||||
platform=${{ matrix.platform }}
|
||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Download meta bake definition
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: bake-meta
|
||||
path: /tmp
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Login to Docker Hub
|
||||
if: github.event_name != 'pull_request' && github.repository == 'moby/moby'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_MOBYBIN_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_MOBYBIN_TOKEN }}
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
id: bake
|
||||
uses: docker/bake-action@v4
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
files: |
|
||||
./docker-bake.hcl
|
||||
/tmp/bake-meta.json
|
||||
targets: bin-image
|
||||
${{ steps.meta.outputs.bake-file }}
|
||||
targets: bin-image-cross
|
||||
set: |
|
||||
*.platform=${{ matrix.platform }}
|
||||
*.output=type=image,name=${{ env.MOBYBIN_REPO_SLUG }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' && github.repository == 'moby/moby' }}
|
||||
*.tags=
|
||||
-
|
||||
name: Export digest
|
||||
if: github.event_name != 'pull_request' && github.repository == 'moby/moby'
|
||||
run: |
|
||||
mkdir -p /tmp/digests
|
||||
digest="${{ fromJSON(steps.bake.outputs.metadata)['bin-image']['containerimage.digest'] }}"
|
||||
touch "/tmp/digests/${digest#sha256:}"
|
||||
-
|
||||
name: Upload digest
|
||||
if: github.event_name != 'pull_request' && github.repository == 'moby/moby'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: digests-${{ env.PLATFORM_PAIR }}
|
||||
path: /tmp/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
merge:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- build
|
||||
if: always() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && github.event_name != 'pull_request' && github.repository == 'moby/moby'
|
||||
steps:
|
||||
-
|
||||
name: Download meta bake definition
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: bake-meta
|
||||
path: /tmp
|
||||
-
|
||||
name: Download digests
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/digests
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_MOBYBIN_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_MOBYBIN_TOKEN }}
|
||||
-
|
||||
name: Create manifest list and push
|
||||
working-directory: /tmp/digests
|
||||
run: |
|
||||
set -x
|
||||
docker buildx imagetools create $(jq -cr '.target."docker-metadata-action".tags | map("-t " + .) | join(" ")' /tmp/bake-meta.json) \
|
||||
$(printf '${{ env.MOBYBIN_REPO_SLUG }}@sha256:%s ' *)
|
||||
-
|
||||
name: Inspect image
|
||||
run: |
|
||||
set -x
|
||||
docker buildx imagetools inspect ${{ env.MOBYBIN_REPO_SLUG }}:$(jq -cr '.target."docker-metadata-action".args.DOCKER_META_VERSION' /tmp/bake-meta.json)
|
||||
*.output=type=cacheonly
|
||||
|
|
45
.github/workflows/buildkit.yml
vendored
45
.github/workflows/buildkit.yml
vendored
|
@ -13,7 +13,6 @@ on:
|
|||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.21.9"
|
||||
DESTDIR: ./build
|
||||
|
||||
jobs:
|
||||
|
@ -27,18 +26,18 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@v4
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: binary
|
||||
-
|
||||
name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: binary
|
||||
path: ${{ env.DESTDIR }}
|
||||
|
@ -48,11 +47,10 @@ jobs:
|
|||
test:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 120
|
||||
env:
|
||||
BUILDKIT_REPO: moby/buildkit
|
||||
needs:
|
||||
- build
|
||||
env:
|
||||
TEST_IMAGE_BUILD: "0"
|
||||
TEST_IMAGE_ID: "buildkit-tests"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
@ -76,56 +74,42 @@ jobs:
|
|||
disabledFeatures="${disabledFeatures},merge_diff"
|
||||
fi
|
||||
echo "BUILDKIT_TEST_DISABLE_FEATURES=${disabledFeatures}" >> $GITHUB_ENV
|
||||
# Expose `ACTIONS_RUNTIME_TOKEN` and `ACTIONS_CACHE_URL`, which is used
|
||||
# in BuildKit's test suite to skip/unskip cache exporters:
|
||||
# https://github.com/moby/buildkit/blob/567a99433ca23402d5e9b9f9124005d2e59b8861/client/client_test.go#L5407-L5411
|
||||
-
|
||||
name: Expose GitHub Runtime
|
||||
uses: crazy-max/ghaction-github-runtime@v3
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: moby
|
||||
-
|
||||
name: BuildKit ref
|
||||
run: |
|
||||
echo "$(./hack/buildkit-ref)" >> $GITHUB_ENV
|
||||
echo "BUILDKIT_REF=$(./hack/buildkit-ref)" >> $GITHUB_ENV
|
||||
working-directory: moby
|
||||
-
|
||||
name: Checkout BuildKit ${{ env.BUILDKIT_REF }}
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: ${{ env.BUILDKIT_REPO }}
|
||||
ref: ${{ env.BUILDKIT_REF }}
|
||||
path: buildkit
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Download binary artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: binary
|
||||
path: ./buildkit/build/moby/
|
||||
-
|
||||
name: Update daemon.json
|
||||
run: |
|
||||
sudo rm -f /etc/docker/daemon.json
|
||||
sudo rm /etc/docker/daemon.json
|
||||
sudo service docker restart
|
||||
docker version
|
||||
docker info
|
||||
-
|
||||
name: Build test image
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
workdir: ./buildkit
|
||||
targets: integration-tests
|
||||
set: |
|
||||
*.output=type=docker,name=${{ env.TEST_IMAGE_ID }}
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
|
@ -135,5 +119,6 @@ jobs:
|
|||
TEST_DOCKERD: "1"
|
||||
TEST_DOCKERD_BINARY: "./build/moby/dockerd"
|
||||
TESTPKGS: "./${{ matrix.pkg }}"
|
||||
TESTFLAGS: "-v --parallel=1 --timeout=30m --run=//worker=${{ matrix.worker }}$"
|
||||
# Skip buildkit tests checking the digest (see https://github.com/moby/buildkit/pull/3736)
|
||||
TESTFLAGS: "-v --parallel=1 --timeout=30m --run=/^Test([^R]|.[^e]|..[^p]|...[^r]|....[^o]|.....[^S])/worker=${{ matrix.worker }}$"
|
||||
working-directory: buildkit
|
||||
|
|
32
.github/workflows/ci.yml
vendored
32
.github/workflows/ci.yml
vendored
|
@ -10,6 +10,8 @@ on:
|
|||
branches:
|
||||
- 'master'
|
||||
- '[0-9]+.[0-9]+'
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
|
@ -32,15 +34,15 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@v4
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
-
|
||||
|
@ -51,6 +53,14 @@ jobs:
|
|||
name: Check artifacts
|
||||
run: |
|
||||
find ${{ env.DESTDIR }} -type f -exec file -e ascii -- {} +
|
||||
-
|
||||
name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.target }}
|
||||
path: ${{ env.DESTDIR }}
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
prepare-cross:
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -61,7 +71,7 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Create matrix
|
||||
id: platforms
|
||||
|
@ -85,7 +95,7 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
|
@ -95,10 +105,10 @@ jobs:
|
|||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@v4
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: all
|
||||
set: |
|
||||
|
@ -111,3 +121,11 @@ jobs:
|
|||
name: Check artifacts
|
||||
run: |
|
||||
find ${{ env.DESTDIR }} -type f -exec file -e ascii -- {} +
|
||||
-
|
||||
name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cross-${{ env.PLATFORM_PAIR }}
|
||||
path: ${{ env.DESTDIR }}
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
|
450
.github/workflows/test.yml
vendored
450
.github/workflows/test.yml
vendored
|
@ -10,12 +10,17 @@ on:
|
|||
branches:
|
||||
- 'master'
|
||||
- '[0-9]+.[0-9]+'
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.21.9"
|
||||
GIT_PAGER: "cat"
|
||||
PAGER: "cat"
|
||||
GO_VERSION: "1.20.4"
|
||||
GOTESTLIST_VERSION: v0.3.1
|
||||
TESTSTAT_VERSION: v0.1.3
|
||||
ITG_CLI_MATRIX_SIZE: 6
|
||||
DOCKER_EXPERIMENTAL: 1
|
||||
DOCKER_GRAPHDRIVER: overlay2
|
||||
|
||||
jobs:
|
||||
validate-dco:
|
||||
|
@ -40,13 +45,13 @@ jobs:
|
|||
fi
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v4
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
|
@ -54,21 +59,6 @@ jobs:
|
|||
*.cache-to=type=gha,scope=dev${{ matrix.mode }},mode=max
|
||||
*.output=type=cacheonly
|
||||
|
||||
test:
|
||||
needs:
|
||||
- build-dev
|
||||
- validate-dco
|
||||
uses: ./.github/workflows/.test.yml
|
||||
secrets: inherit
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
storage:
|
||||
- graphdriver
|
||||
- snapshotter
|
||||
with:
|
||||
storage: ${{ matrix.storage }}
|
||||
|
||||
validate-prepare:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
|
@ -78,12 +68,12 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Create matrix
|
||||
id: scripts
|
||||
run: |
|
||||
scripts=$(cd ./hack/validate && jq -nc '$ARGS.positional - ["all", "default", "dco"] | map(select(test("[.]")|not)) + ["generate-files"]' --args *)
|
||||
scripts=$(jq -ncR '[inputs]' <<< "$(ls -I .validate -I all -I default -I dco -I golangci-lint.yml -I yamllint.yaml -A ./hack/validate/)")
|
||||
echo "matrix=$scripts" >> $GITHUB_OUTPUT
|
||||
-
|
||||
name: Show matrix
|
||||
|
@ -103,7 +93,7 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
|
@ -111,10 +101,10 @@ jobs:
|
|||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v4
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
|
@ -124,7 +114,399 @@ jobs:
|
|||
run: |
|
||||
make -o build validate-${{ matrix.script }}
|
||||
|
||||
smoke-prepare:
|
||||
unit:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- build-dev
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-unit
|
||||
-
|
||||
name: Prepare reports
|
||||
if: always()
|
||||
run: |
|
||||
mkdir -p bundles /tmp/reports
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \( -name '*-report.json' -o -name '*.log' -o -name '*.out' -o -name '*.prof' -o -name '*-report.xml' \) -print | xargs sudo tar -czf /tmp/reports.tar.gz
|
||||
tar -xzf /tmp/reports.tar.gz -C /tmp/reports
|
||||
sudo chown -R $(id -u):$(id -g) /tmp/reports
|
||||
tree -nh /tmp/reports
|
||||
-
|
||||
name: Send to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
directory: ./bundles
|
||||
env_vars: RUNNER_OS
|
||||
flags: unit
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: unit-reports
|
||||
path: /tmp/reports/*
|
||||
|
||||
unit-report:
|
||||
runs-on: ubuntu-20.04
|
||||
if: always()
|
||||
needs:
|
||||
- unit
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: unit-reports
|
||||
path: /tmp/reports
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
teststat -markdown $(find /tmp/reports -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
docker-py:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- build-dev
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-docker-py
|
||||
-
|
||||
name: Prepare reports
|
||||
if: always()
|
||||
run: |
|
||||
mkdir -p bundles /tmp/reports
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \( -name '*-report.json' -o -name '*.log' -o -name '*.out' -o -name '*.prof' -o -name '*-report.xml' \) -print | xargs sudo tar -czf /tmp/reports.tar.gz
|
||||
tar -xzf /tmp/reports.tar.gz -C /tmp/reports
|
||||
sudo chown -R $(id -u):$(id -g) /tmp/reports
|
||||
tree -nh /tmp/reports
|
||||
-
|
||||
name: Test daemon logs
|
||||
if: always()
|
||||
run: |
|
||||
cat bundles/test-docker-py/docker.log
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: docker-py-reports
|
||||
path: /tmp/reports/*
|
||||
|
||||
integration-flaky:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- build-dev
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-integration-flaky
|
||||
env:
|
||||
TEST_SKIP_INTEGRATION_CLI: 1
|
||||
|
||||
integration:
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- build-dev
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-20.04
|
||||
- ubuntu-22.04
|
||||
mode:
|
||||
- ""
|
||||
- rootless
|
||||
- systemd
|
||||
#- rootless-systemd FIXME: https://github.com/moby/moby/issues/44084
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Prepare
|
||||
run: |
|
||||
CACHE_DEV_SCOPE=dev
|
||||
if [[ "${{ matrix.mode }}" == *"rootless"* ]]; then
|
||||
echo "DOCKER_ROOTLESS=1" >> $GITHUB_ENV
|
||||
fi
|
||||
if [[ "${{ matrix.mode }}" == *"systemd"* ]]; then
|
||||
echo "SYSTEMD=true" >> $GITHUB_ENV
|
||||
CACHE_DEV_SCOPE="${CACHE_DEV_SCOPE}systemd"
|
||||
fi
|
||||
echo "CACHE_DEV_SCOPE=${CACHE_DEV_SCOPE}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=${{ env.CACHE_DEV_SCOPE }}
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-integration
|
||||
env:
|
||||
TEST_SKIP_INTEGRATION_CLI: 1
|
||||
TESTCOVERAGE: 1
|
||||
-
|
||||
name: Prepare reports
|
||||
if: always()
|
||||
run: |
|
||||
reportsPath="/tmp/reports/${{ matrix.os }}"
|
||||
if [ -n "${{ matrix.mode }}" ]; then
|
||||
reportsPath="$reportsPath-${{ matrix.mode }}"
|
||||
fi
|
||||
mkdir -p bundles $reportsPath
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \( -name '*-report.json' -o -name '*.log' -o -name '*.out' -o -name '*.prof' -o -name '*-report.xml' \) -print | xargs sudo tar -czf /tmp/reports.tar.gz
|
||||
tar -xzf /tmp/reports.tar.gz -C $reportsPath
|
||||
sudo chown -R $(id -u):$(id -g) $reportsPath
|
||||
tree -nh $reportsPath
|
||||
-
|
||||
name: Send to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
directory: ./bundles/test-integration
|
||||
env_vars: RUNNER_OS
|
||||
flags: integration,${{ matrix.mode }}
|
||||
-
|
||||
name: Test daemon logs
|
||||
if: always()
|
||||
run: |
|
||||
cat bundles/test-integration/docker.log
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: integration-reports
|
||||
path: /tmp/reports/*
|
||||
|
||||
integration-report:
|
||||
runs-on: ubuntu-20.04
|
||||
if: always()
|
||||
needs:
|
||||
- integration
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: integration-reports
|
||||
path: /tmp/reports
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
teststat -markdown $(find /tmp/reports -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
integration-cli-prepare:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
outputs:
|
||||
matrix: ${{ steps.tests.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Install gotestlist
|
||||
run:
|
||||
go install github.com/crazy-max/gotestlist/cmd/gotestlist@${{ env.GOTESTLIST_VERSION }}
|
||||
-
|
||||
name: Create matrix
|
||||
id: tests
|
||||
working-directory: ./integration-cli
|
||||
run: |
|
||||
# This step creates a matrix for integration-cli tests. Tests suites
|
||||
# are distributed in integration-cli job through a matrix. There is
|
||||
# also overrides being added to the matrix like "./..." to run
|
||||
# "Test integration" step exclusively and specific tests suites that
|
||||
# take a long time to run.
|
||||
matrix="$(gotestlist -d ${{ env.ITG_CLI_MATRIX_SIZE }} -o "./..." -o "DockerSwarmSuite" -o "DockerNetworkSuite|DockerExternalVolumeSuite" ./...)"
|
||||
echo "matrix=$matrix" >> $GITHUB_OUTPUT
|
||||
-
|
||||
name: Show matrix
|
||||
run: |
|
||||
echo ${{ steps.tests.outputs.matrix }}
|
||||
|
||||
integration-cli:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- build-dev
|
||||
- integration-cli-prepare
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
test: ${{ fromJson(needs.integration-cli-prepare.outputs.matrix) }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-integration
|
||||
env:
|
||||
TEST_SKIP_INTEGRATION: 1
|
||||
TESTCOVERAGE: 1
|
||||
TESTFLAGS: "-test.run (${{ matrix.test }})/"
|
||||
-
|
||||
name: Prepare reports
|
||||
if: always()
|
||||
run: |
|
||||
reportsPath=/tmp/reports/$(echo -n "${{ matrix.test }}" | sha256sum | cut -d " " -f 1)
|
||||
mkdir -p bundles $reportsPath
|
||||
echo "${{ matrix.test }}" | tr -s '|' '\n' | tee -a "$reportsPath/tests.txt"
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \( -name '*-report.json' -o -name '*.log' -o -name '*.out' -o -name '*.prof' -o -name '*-report.xml' \) -print | xargs sudo tar -czf /tmp/reports.tar.gz
|
||||
tar -xzf /tmp/reports.tar.gz -C $reportsPath
|
||||
sudo chown -R $(id -u):$(id -g) $reportsPath
|
||||
tree -nh $reportsPath
|
||||
-
|
||||
name: Send to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
directory: ./bundles/test-integration
|
||||
env_vars: RUNNER_OS
|
||||
flags: integration-cli
|
||||
-
|
||||
name: Test daemon logs
|
||||
if: always()
|
||||
run: |
|
||||
cat bundles/test-integration/docker.log
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: integration-cli-reports
|
||||
path: /tmp/reports/*
|
||||
|
||||
integration-cli-report:
|
||||
runs-on: ubuntu-20.04
|
||||
if: always()
|
||||
needs:
|
||||
- integration-cli
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: integration-cli-reports
|
||||
path: /tmp/reports
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
teststat -markdown $(find /tmp/reports -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
prepare-smoke:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
|
@ -133,7 +515,7 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Create matrix
|
||||
id: platforms
|
||||
|
@ -148,15 +530,15 @@ jobs:
|
|||
smoke:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- smoke-prepare
|
||||
- prepare-smoke
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: ${{ fromJson(needs.smoke-prepare.outputs.matrix) }}
|
||||
platform: ${{ fromJson(needs.prepare-smoke.outputs.matrix) }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Prepare
|
||||
run: |
|
||||
|
@ -164,13 +546,13 @@ jobs:
|
|||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Test
|
||||
uses: docker/bake-action@v4
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: binary-smoketest
|
||||
set: |
|
||||
|
|
62
.github/workflows/validate-pr.yml
vendored
62
.github/workflows/validate-pr.yml
vendored
|
@ -1,62 +0,0 @@
|
|||
name: validate-pr
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, edited, labeled, unlabeled]
|
||||
|
||||
jobs:
|
||||
check-area-label:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Missing `area/` label
|
||||
if: contains(join(github.event.pull_request.labels.*.name, ','), 'impact/') && !contains(join(github.event.pull_request.labels.*.name, ','), 'area/')
|
||||
run: |
|
||||
echo "::error::Every PR with an 'impact/*' label should also have an 'area/*' label"
|
||||
exit 1
|
||||
- name: OK
|
||||
run: exit 0
|
||||
|
||||
check-changelog:
|
||||
if: contains(join(github.event.pull_request.labels.*.name, ','), 'impact/')
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
PR_BODY: |
|
||||
${{ github.event.pull_request.body }}
|
||||
steps:
|
||||
- name: Check changelog description
|
||||
run: |
|
||||
# Extract the `markdown changelog` note code block
|
||||
block=$(echo -n "$PR_BODY" | tr -d '\r' | awk '/^```markdown changelog$/{flag=1;next}/^```$/{flag=0}flag')
|
||||
|
||||
# Strip empty lines
|
||||
desc=$(echo "$block" | awk NF)
|
||||
|
||||
if [ -z "$desc" ]; then
|
||||
echo "::error::Changelog section is empty. Please provide a description for the changelog."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
len=$(echo -n "$desc" | wc -c)
|
||||
if [[ $len -le 6 ]]; then
|
||||
echo "::error::Description looks too short: $desc"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "This PR will be included in the release notes with the following note:"
|
||||
echo "$desc"
|
||||
|
||||
check-pr-branch:
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
steps:
|
||||
# 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
|
13
.github/workflows/windows-2019.yml
vendored
13
.github/workflows/windows-2019.yml
vendored
|
@ -13,21 +13,10 @@ jobs:
|
|||
validate-dco:
|
||||
uses: ./.github/workflows/.dco.yml
|
||||
|
||||
test-prepare:
|
||||
uses: ./.github/workflows/.test-prepare.yml
|
||||
needs:
|
||||
- validate-dco
|
||||
|
||||
run:
|
||||
needs:
|
||||
- test-prepare
|
||||
- validate-dco
|
||||
uses: ./.github/workflows/.windows.yml
|
||||
secrets: inherit
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
storage: ${{ fromJson(needs.test-prepare.outputs.matrix) }}
|
||||
with:
|
||||
os: windows-2019
|
||||
storage: ${{ matrix.storage }}
|
||||
send_coverage: false
|
||||
|
|
13
.github/workflows/windows-2022.yml
vendored
13
.github/workflows/windows-2022.yml
vendored
|
@ -16,21 +16,10 @@ jobs:
|
|||
validate-dco:
|
||||
uses: ./.github/workflows/.dco.yml
|
||||
|
||||
test-prepare:
|
||||
uses: ./.github/workflows/.test-prepare.yml
|
||||
needs:
|
||||
- validate-dco
|
||||
|
||||
run:
|
||||
needs:
|
||||
- test-prepare
|
||||
- validate-dco
|
||||
uses: ./.github/workflows/.windows.yml
|
||||
secrets: inherit
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
storage: ${{ fromJson(needs.test-prepare.outputs.matrix) }}
|
||||
with:
|
||||
os: windows-2022
|
||||
storage: ${{ matrix.storage }}
|
||||
send_coverage: true
|
||||
|
|
137
.golangci.yml
137
.golangci.yml
|
@ -1,137 +0,0 @@
|
|||
linters:
|
||||
enable:
|
||||
- depguard
|
||||
- dupword # Checks for duplicate words in the source code.
|
||||
- goimports
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- importas
|
||||
- ineffassign
|
||||
- misspell
|
||||
- revive
|
||||
- staticcheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unused
|
||||
|
||||
disable:
|
||||
- errcheck
|
||||
|
||||
run:
|
||||
concurrency: 2
|
||||
modules-download-mode: vendor
|
||||
|
||||
skip-dirs:
|
||||
- docs
|
||||
|
||||
linters-settings:
|
||||
dupword:
|
||||
ignore:
|
||||
- "true" # some tests use this as expected output
|
||||
- "false" # some tests use this as expected output
|
||||
- "root" # for tests using "ls" output with files owned by "root:root"
|
||||
importas:
|
||||
# Do not allow unaliased imports of aliased packages.
|
||||
no-unaliased: true
|
||||
|
||||
alias:
|
||||
# Enforce alias to prevent it accidentally being used instead of our
|
||||
# own errdefs package (or vice-versa).
|
||||
- pkg: github.com/containerd/containerd/errdefs
|
||||
alias: cerrdefs
|
||||
- pkg: github.com/opencontainers/image-spec/specs-go/v1
|
||||
alias: ocispec
|
||||
|
||||
govet:
|
||||
check-shadowing: false
|
||||
depguard:
|
||||
rules:
|
||||
main:
|
||||
deny:
|
||||
- pkg: io/ioutil
|
||||
desc: The io/ioutil package has been deprecated, see https://go.dev/doc/go1.16#ioutil
|
||||
- pkg: "github.com/stretchr/testify/assert"
|
||||
desc: Use "gotest.tools/v3/assert" instead
|
||||
- pkg: "github.com/stretchr/testify/require"
|
||||
desc: Use "gotest.tools/v3/assert" instead
|
||||
- pkg: "github.com/stretchr/testify/suite"
|
||||
desc: Do not use
|
||||
revive:
|
||||
rules:
|
||||
# FIXME make sure all packages have a description. Currently, there's many packages without.
|
||||
- name: package-comments
|
||||
disabled: true
|
||||
issues:
|
||||
# The default exclusion rules are a bit too permissive, so copying the relevant ones below
|
||||
exclude-use-default: false
|
||||
|
||||
exclude-rules:
|
||||
# We prefer to use an "exclude-list" so that new "default" exclusions are not
|
||||
# automatically inherited. We can decide whether or not to follow upstream
|
||||
# defaults when updating golang-ci-lint versions.
|
||||
# Unfortunately, this means we have to copy the whole exclusion pattern, as
|
||||
# (unlike the "include" option), the "exclude" option does not take exclusion
|
||||
# ID's.
|
||||
#
|
||||
# These exclusion patterns are copied from the default excluses at:
|
||||
# https://github.com/golangci/golangci-lint/blob/v1.46.2/pkg/config/issues.go#L10-L104
|
||||
|
||||
# EXC0001
|
||||
- text: "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*print(f|ln)?|os\\.(Un)?Setenv). is not checked"
|
||||
linters:
|
||||
- errcheck
|
||||
# EXC0006
|
||||
- text: "Use of unsafe calls should be audited"
|
||||
linters:
|
||||
- gosec
|
||||
# EXC0007
|
||||
- text: "Subprocess launch(ed with variable|ing should be audited)"
|
||||
linters:
|
||||
- gosec
|
||||
# EXC0008
|
||||
# TODO: evaluate these and fix where needed: G307: Deferring unsafe method "*os.File" on type "Close" (gosec)
|
||||
- text: "(G104|G307)"
|
||||
linters:
|
||||
- gosec
|
||||
# EXC0009
|
||||
- text: "(Expect directory permissions to be 0750 or less|Expect file permissions to be 0600 or less)"
|
||||
linters:
|
||||
- gosec
|
||||
# EXC0010
|
||||
- text: "Potential file inclusion via variable"
|
||||
linters:
|
||||
- gosec
|
||||
|
||||
# Looks like the match in "EXC0007" above doesn't catch this one
|
||||
# TODO: consider upstreaming this to golangci-lint's default exclusion rules
|
||||
- text: "G204: Subprocess launched with a potential tainted input or cmd arguments"
|
||||
linters:
|
||||
- gosec
|
||||
# Looks like the match in "EXC0009" above doesn't catch this one
|
||||
# TODO: consider upstreaming this to golangci-lint's default exclusion rules
|
||||
- text: "G306: Expect WriteFile permissions to be 0600 or less"
|
||||
linters:
|
||||
- gosec
|
||||
|
||||
# Exclude some linters from running on tests files.
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- errcheck
|
||||
- gosec
|
||||
|
||||
# Suppress golint complaining about generated types in api/types/
|
||||
- text: "type name will be used as (container|volume)\\.(Container|Volume).* by other packages, and that stutters; consider calling this"
|
||||
path: "api/types/(volume|container)/"
|
||||
linters:
|
||||
- revive
|
||||
# FIXME temporarily suppress these (see https://github.com/gotestyourself/gotest.tools/issues/272)
|
||||
- text: "SA1019: (assert|cmp|is)\\.ErrorType is deprecated"
|
||||
linters:
|
||||
- staticcheck
|
||||
|
||||
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
|
||||
max-issues-per-linter: 0
|
||||
|
||||
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
|
||||
max-same-issues: 0
|
24
.mailmap
24
.mailmap
|
@ -32,7 +32,6 @@ Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp> <suda.kyoto@gmail.com>
|
|||
Akshay Moghe <akshay.moghe@gmail.com>
|
||||
Albin Kerouanton <albinker@gmail.com>
|
||||
Albin Kerouanton <albinker@gmail.com> <albin@akerouanton.name>
|
||||
Albin Kerouanton <albinker@gmail.com> <557933+akerouanton@users.noreply.github.com>
|
||||
Aleksa Sarai <asarai@suse.de>
|
||||
Aleksa Sarai <asarai@suse.de> <asarai@suse.com>
|
||||
Aleksa Sarai <asarai@suse.de> <cyphar@cyphar.com>
|
||||
|
@ -104,9 +103,6 @@ Bily Zhang <xcoder@tenxcloud.com>
|
|||
Bin Liu <liubin0329@gmail.com>
|
||||
Bin Liu <liubin0329@gmail.com> <liubin0329@users.noreply.github.com>
|
||||
Bingshen Wang <bingshen.wbs@alibaba-inc.com>
|
||||
Bjorn Neergaard <bjorn@neersighted.com>
|
||||
Bjorn Neergaard <bjorn@neersighted.com> <bjorn.neergaard@docker.com>
|
||||
Bjorn Neergaard <bjorn@neersighted.com> <bneergaard@mirantis.com>
|
||||
Boaz Shuster <ripcurld.github@gmail.com>
|
||||
Bojun Zhu <bojun.zhu@foxmail.com>
|
||||
Boqin Qin <bobbqqin@gmail.com>
|
||||
|
@ -145,8 +141,6 @@ Cristian Ariza <dev@cristianrz.com>
|
|||
Cristian Staretu <cristian.staretu@gmail.com>
|
||||
Cristian Staretu <cristian.staretu@gmail.com> <unclejack@users.noreply.github.com>
|
||||
Cristian Staretu <cristian.staretu@gmail.com> <unclejacksons@gmail.com>
|
||||
cui fliter <imcusg@gmail.com>
|
||||
cui fliter <imcusg@gmail.com> cuishuang <imcusg@gmail.com>
|
||||
CUI Wei <ghostplant@qq.com> cuiwei13 <cuiwei13@pku.edu.cn>
|
||||
Daehyeok Mun <daehyeok@gmail.com>
|
||||
Daehyeok Mun <daehyeok@gmail.com> <daehyeok@daehyeok-ui-MacBook-Air.local>
|
||||
|
@ -173,8 +167,6 @@ Dattatraya Kumbhar <dattatraya.kumbhar@gslab.com>
|
|||
Dave Goodchild <buddhamagnet@gmail.com>
|
||||
Dave Henderson <dhenderson@gmail.com> <Dave.Henderson@ca.ibm.com>
|
||||
Dave Tucker <dt@docker.com> <dave@dtucker.co.uk>
|
||||
David Dooling <dooling@gmail.com>
|
||||
David Dooling <dooling@gmail.com> <david.dooling@docker.com>
|
||||
David M. Karr <davidmichaelkarr@gmail.com>
|
||||
David Sheets <dsheets@docker.com> <sheets@alum.mit.edu>
|
||||
David Sissitka <me@dsissitka.com>
|
||||
|
@ -221,8 +213,6 @@ Felix Hupfeld <felix@quobyte.com> <quofelix@users.noreply.github.com>
|
|||
Felix Ruess <felix.ruess@gmail.com> <felix.ruess@roboception.de>
|
||||
Feng Yan <fy2462@gmail.com>
|
||||
Fengtu Wang <wangfengtu@huawei.com> <wangfengtu@huawei.com>
|
||||
Filipe Pina <hzlu1ot0@duck.com>
|
||||
Filipe Pina <hzlu1ot0@duck.com> <636320+fopina@users.noreply.github.com>
|
||||
Francisco Carriedo <fcarriedo@gmail.com>
|
||||
Frank Rosquin <frank.rosquin+github@gmail.com> <frank.rosquin@gmail.com>
|
||||
Frank Yang <yyb196@gmail.com>
|
||||
|
@ -274,7 +264,6 @@ Hollie Teal <hollie@docker.com> <hollie.teal@docker.com>
|
|||
Hollie Teal <hollie@docker.com> <hollietealok@users.noreply.github.com>
|
||||
hsinko <21551195@zju.edu.cn> <hsinko@users.noreply.github.com>
|
||||
Hu Keping <hukeping@huawei.com>
|
||||
Huajin Tong <fliterdashen@gmail.com>
|
||||
Hui Kang <hkang.sunysb@gmail.com>
|
||||
Hui Kang <hkang.sunysb@gmail.com> <kangh@us.ibm.com>
|
||||
Huu Nguyen <huu@prismskylabs.com> <whoshuu@gmail.com>
|
||||
|
@ -380,9 +369,7 @@ Ken Cochrane <kencochrane@gmail.com> <KenCochrane@gmail.com>
|
|||
Ken Herner <kherner@progress.com> <chosenken@gmail.com>
|
||||
Ken Reese <krrgithub@gmail.com>
|
||||
Kenfe-Mickaël Laventure <mickael.laventure@gmail.com>
|
||||
Kevin Alvarez <github@crazymax.dev>
|
||||
Kevin Alvarez <github@crazymax.dev> <1951866+crazy-max@users.noreply.github.com>
|
||||
Kevin Alvarez <github@crazymax.dev> <crazy-max@users.noreply.github.com>
|
||||
Kevin Alvarez <crazy-max@users.noreply.github.com>
|
||||
Kevin Feyrer <kevin.feyrer@btinternet.com> <kevinfeyrer@users.noreply.github.com>
|
||||
Kevin Kern <kaiwentan@harmonycloud.cn>
|
||||
Kevin Meredith <kevin.m.meredith@gmail.com>
|
||||
|
@ -482,15 +469,10 @@ Mikael Davranche <mikael.davranche@corp.ovh.com>
|
|||
Mikael Davranche <mikael.davranche@corp.ovh.com> <mikael.davranche@corp.ovh.net>
|
||||
Mike Casas <mkcsas0@gmail.com> <mikecasas@users.noreply.github.com>
|
||||
Mike Goelzer <mike.goelzer@docker.com> <mgoelzer@docker.com>
|
||||
Milas Bowman <devnull@milas.dev>
|
||||
Milas Bowman <devnull@milas.dev> <milasb@gmail.com>
|
||||
Milas Bowman <devnull@milas.dev> <milas.bowman@docker.com>
|
||||
Milind Chawre <milindchawre@gmail.com>
|
||||
Misty Stanley-Jones <misty@docker.com> <misty@apache.org>
|
||||
Mohammad Banikazemi <MBanikazemi@gmail.com>
|
||||
Mohammad Banikazemi <MBanikazemi@gmail.com> <mb@us.ibm.com>
|
||||
Mohd Sadiq <mohdsadiq058@gmail.com> <mohdsadiq058@gmail.com>
|
||||
Mohd Sadiq <mohdsadiq058@gmail.com> <42430865+msadiq058@users.noreply.github.com>
|
||||
Mohit Soni <mosoni@ebay.com> <mohitsoni1989@gmail.com>
|
||||
Moorthy RS <rsmoorthy@gmail.com> <rsmoorthy@users.noreply.github.com>
|
||||
Moysés Borges <moysesb@gmail.com>
|
||||
|
@ -566,9 +548,7 @@ Sebastiaan van Stijn <github@gone.nl>
|
|||
Sebastiaan van Stijn <github@gone.nl> <moby@example.com>
|
||||
Sebastiaan van Stijn <github@gone.nl> <sebastiaan@ws-key-sebas3.dpi1.dpi>
|
||||
Sebastiaan van Stijn <github@gone.nl> <thaJeztah@users.noreply.github.com>
|
||||
Sebastian Thomschke <sebthom@users.noreply.github.com>
|
||||
Seongyeol Lim <seongyeol37@gmail.com>
|
||||
Serhii Nakon <serhii.n@thescimus.com>
|
||||
Shaun Kaasten <shaunk@gmail.com>
|
||||
Shawn Landden <shawn@churchofgit.com> <shawnlandden@gmail.com>
|
||||
Shengbo Song <thomassong@tencent.com>
|
||||
|
@ -715,8 +695,6 @@ Xiaodong Liu <liuxiaodong@loongson.cn>
|
|||
Xiaodong Zhang <a4012017@sina.com>
|
||||
Xiaohua Ding <xiao_hua_ding@sina.cn>
|
||||
Xiaoyu Zhang <zhang.xiaoyu33@zte.com.cn>
|
||||
Xinfeng Liu <XinfengLiu@icloud.com>
|
||||
Xinfeng Liu <XinfengLiu@icloud.com> <xinfeng.liu@gmail.com>
|
||||
Xuecong Liao <satorulogic@gmail.com>
|
||||
Yamasaki Masahide <masahide.y@gmail.com>
|
||||
Yao Zaiyong <yaozaiyong@hotmail.com>
|
||||
|
|
58
AUTHORS
58
AUTHORS
|
@ -27,7 +27,6 @@ Adam Miller <admiller@redhat.com>
|
|||
Adam Mills <adam@armills.info>
|
||||
Adam Pointer <adam.pointer@skybettingandgaming.com>
|
||||
Adam Singer <financeCoding@gmail.com>
|
||||
Adam Thornton <adam.thornton@maryville.com>
|
||||
Adam Walz <adam@adamwalz.net>
|
||||
Adam Williams <awilliams@mirantis.com>
|
||||
AdamKorcz <adam@adalogics.com>
|
||||
|
@ -174,7 +173,6 @@ Andy Rothfusz <github@developersupport.net>
|
|||
Andy Smith <github@anarkystic.com>
|
||||
Andy Wilson <wilson.andrew.j+github@gmail.com>
|
||||
Andy Zhang <andy.zhangtao@hotmail.com>
|
||||
Aneesh Kulkarni <askthefactorcamera@gmail.com>
|
||||
Anes Hasicic <anes.hasicic@gmail.com>
|
||||
Angel Velazquez <angelcar@amazon.com>
|
||||
Anil Belur <askb23@gmail.com>
|
||||
|
@ -238,7 +236,6 @@ Ben Golub <ben.golub@dotcloud.com>
|
|||
Ben Gould <ben@bengould.co.uk>
|
||||
Ben Hall <ben@benhall.me.uk>
|
||||
Ben Langfeld <ben@langfeld.me>
|
||||
Ben Lovy <ben@deciduously.com>
|
||||
Ben Sargent <ben@brokendigits.com>
|
||||
Ben Severson <BenSeverson@users.noreply.github.com>
|
||||
Ben Toews <mastahyeti@gmail.com>
|
||||
|
@ -265,7 +262,7 @@ Billy Ridgway <wrridgwa@us.ibm.com>
|
|||
Bily Zhang <xcoder@tenxcloud.com>
|
||||
Bin Liu <liubin0329@gmail.com>
|
||||
Bingshen Wang <bingshen.wbs@alibaba-inc.com>
|
||||
Bjorn Neergaard <bjorn@neersighted.com>
|
||||
Bjorn Neergaard <bneergaard@mirantis.com>
|
||||
Blake Geno <blakegeno@gmail.com>
|
||||
Boaz Shuster <ripcurld.github@gmail.com>
|
||||
bobby abbott <ttobbaybbob@gmail.com>
|
||||
|
@ -282,7 +279,6 @@ Brandon Liu <bdon@bdon.org>
|
|||
Brandon Philips <brandon.philips@coreos.com>
|
||||
Brandon Rhodes <brandon@rhodesmill.org>
|
||||
Brendan Dixon <brendand@microsoft.com>
|
||||
Brennan Kinney <5098581+polarathene@users.noreply.github.com>
|
||||
Brent Salisbury <brent.salisbury@docker.com>
|
||||
Brett Higgins <brhiggins@arbor.net>
|
||||
Brett Kochendorfer <brett.kochendorfer@gmail.com>
|
||||
|
@ -367,7 +363,6 @@ chenyuzhu <chenyuzhi@oschina.cn>
|
|||
Chetan Birajdar <birajdar.chetan@gmail.com>
|
||||
Chewey <prosto-chewey@users.noreply.github.com>
|
||||
Chia-liang Kao <clkao@clkao.org>
|
||||
Chiranjeevi Tirunagari <vchiranjeeviak.tirunagari@gmail.com>
|
||||
chli <chli@freewheel.tv>
|
||||
Cholerae Hu <choleraehyq@gmail.com>
|
||||
Chris Alfonso <calfonso@redhat.com>
|
||||
|
@ -438,8 +433,8 @@ Cristian Staretu <cristian.staretu@gmail.com>
|
|||
cristiano balducci <cristiano.balducci@gmail.com>
|
||||
Cristina Yenyxe Gonzalez Garcia <cristina.yenyxe@gmail.com>
|
||||
Cruceru Calin-Cristian <crucerucalincristian@gmail.com>
|
||||
cui fliter <imcusg@gmail.com>
|
||||
CUI Wei <ghostplant@qq.com>
|
||||
cuishuang <imcusg@gmail.com>
|
||||
Cuong Manh Le <cuong.manhle.vn@gmail.com>
|
||||
Cyprian Gracz <cyprian.gracz@micro-jumbo.eu>
|
||||
Cyril F <cyrilf7x@gmail.com>
|
||||
|
@ -518,7 +513,6 @@ David Dooling <dooling@gmail.com>
|
|||
David Gageot <david@gageot.net>
|
||||
David Gebler <davidgebler@gmail.com>
|
||||
David Glasser <glasser@davidglasser.net>
|
||||
David Karlsson <35727626+dvdksn@users.noreply.github.com>
|
||||
David Lawrence <david.lawrence@docker.com>
|
||||
David Lechner <david@lechnology.com>
|
||||
David M. Karr <davidmichaelkarr@gmail.com>
|
||||
|
@ -608,7 +602,6 @@ Donald Huang <don.hcd@gmail.com>
|
|||
Dong Chen <dongluo.chen@docker.com>
|
||||
Donghwa Kim <shanytt@gmail.com>
|
||||
Donovan Jones <git@gamma.net.nz>
|
||||
Dorin Geman <dorin.geman@docker.com>
|
||||
Doron Podoleanu <doronp@il.ibm.com>
|
||||
Doug Davis <dug@us.ibm.com>
|
||||
Doug MacEachern <dougm@vmware.com>
|
||||
|
@ -643,7 +636,6 @@ Emily Rose <emily@contactvibe.com>
|
|||
Emir Ozer <emirozer@yandex.com>
|
||||
Eng Zer Jun <engzerjun@gmail.com>
|
||||
Enguerran <engcolson@gmail.com>
|
||||
Enrico Weigelt, metux IT consult <info@metux.net>
|
||||
Eohyung Lee <liquidnuker@gmail.com>
|
||||
epeterso <epeterson@breakpoint-labs.com>
|
||||
er0k <er0k@er0k.net>
|
||||
|
@ -669,7 +661,6 @@ Erik Hollensbe <github@hollensbe.org>
|
|||
Erik Inge Bolsø <knan@redpill-linpro.com>
|
||||
Erik Kristensen <erik@erikkristensen.com>
|
||||
Erik Sipsma <erik@sipsma.dev>
|
||||
Erik Sjölund <erik.sjolund@gmail.com>
|
||||
Erik St. Martin <alakriti@gmail.com>
|
||||
Erik Weathers <erikdw@gmail.com>
|
||||
Erno Hopearuoho <erno.hopearuoho@gmail.com>
|
||||
|
@ -685,7 +676,6 @@ Evan Allrich <evan@unguku.com>
|
|||
Evan Carmi <carmi@users.noreply.github.com>
|
||||
Evan Hazlett <ejhazlett@gmail.com>
|
||||
Evan Krall <krall@yelp.com>
|
||||
Evan Lezar <elezar@nvidia.com>
|
||||
Evan Phoenix <evan@fallingsnow.net>
|
||||
Evan Wies <evan@neomantra.net>
|
||||
Evelyn Xu <evelynhsu21@gmail.com>
|
||||
|
@ -732,7 +722,6 @@ Feroz Salam <feroz.salam@sourcegraph.com>
|
|||
Ferran Rodenas <frodenas@gmail.com>
|
||||
Filipe Brandenburger <filbranden@google.com>
|
||||
Filipe Oliveira <contato@fmoliveira.com.br>
|
||||
Filipe Pina <hzlu1ot0@duck.com>
|
||||
Flavio Castelli <fcastelli@suse.com>
|
||||
Flavio Crisciani <flavio.crisciani@docker.com>
|
||||
Florian <FWirtz@users.noreply.github.com>
|
||||
|
@ -755,7 +744,6 @@ Frank Groeneveld <frank@ivaldi.nl>
|
|||
Frank Herrmann <fgh@4gh.tv>
|
||||
Frank Macreery <frank@macreery.com>
|
||||
Frank Rosquin <frank.rosquin+github@gmail.com>
|
||||
Frank Villaro-Dixon <frank.villarodixon@merkle.com>
|
||||
Frank Yang <yyb196@gmail.com>
|
||||
Fred Lifton <fred.lifton@docker.com>
|
||||
Frederick F. Kautz IV <fkautz@redhat.com>
|
||||
|
@ -877,8 +865,6 @@ Hsing-Yu (David) Chen <davidhsingyuchen@gmail.com>
|
|||
hsinko <21551195@zju.edu.cn>
|
||||
Hu Keping <hukeping@huawei.com>
|
||||
Hu Tao <hutao@cn.fujitsu.com>
|
||||
Huajin Tong <fliterdashen@gmail.com>
|
||||
huang-jl <1046678590@qq.com>
|
||||
HuanHuan Ye <logindaveye@gmail.com>
|
||||
Huanzhong Zhang <zhanghuanzhong90@gmail.com>
|
||||
Huayi Zhang <irachex@gmail.com>
|
||||
|
@ -973,7 +959,6 @@ Jannick Fahlbusch <git@jf-projects.de>
|
|||
Januar Wayong <januar@gmail.com>
|
||||
Jared Biel <jared.biel@bolderthinking.com>
|
||||
Jared Hocutt <jaredh@netapp.com>
|
||||
Jaroslav Jindrak <dzejrou@gmail.com>
|
||||
Jaroslaw Zabiello <hipertracker@gmail.com>
|
||||
Jasmine Hegman <jasmine@jhegman.com>
|
||||
Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
|
@ -998,7 +983,6 @@ Jean Rouge <rougej+github@gmail.com>
|
|||
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
|
||||
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
|
||||
Jean-Christophe Berthon <huygens@berthon.eu>
|
||||
Jean-Michel Rouet <jm.rouet@gmail.com>
|
||||
Jean-Paul Calderone <exarkun@twistedmatrix.com>
|
||||
Jean-Pierre Huynh <jean-pierre.huynh@ounet.fr>
|
||||
Jean-Tiare Le Bigot <jt@yadutaf.fr>
|
||||
|
@ -1017,7 +1001,6 @@ Jeffrey Bolle <jeffreybolle@gmail.com>
|
|||
Jeffrey Morgan <jmorganca@gmail.com>
|
||||
Jeffrey van Gogh <jvg@google.com>
|
||||
Jenny Gebske <jennifer@gebske.de>
|
||||
Jeongseok Kang <piono623@naver.com>
|
||||
Jeremy Chambers <jeremy@thehipbot.com>
|
||||
Jeremy Grosser <jeremy@synack.me>
|
||||
Jeremy Huntwork <jhuntwork@lightcubesolutions.com>
|
||||
|
@ -1030,12 +1013,10 @@ Jeroen Jacobs <github@jeroenj.be>
|
|||
Jesse Dearing <jesse.dearing@gmail.com>
|
||||
Jesse Dubay <jesse@thefortytwo.net>
|
||||
Jessica Frazelle <jess@oxide.computer>
|
||||
Jeyanthinath Muthuram <jeyanthinath10@gmail.com>
|
||||
Jezeniel Zapanta <jpzapanta22@gmail.com>
|
||||
Jhon Honce <jhonce@redhat.com>
|
||||
Ji.Zhilong <zhilongji@gmail.com>
|
||||
Jian Liao <jliao@alauda.io>
|
||||
Jian Zeng <anonymousknight96@gmail.com>
|
||||
Jian Zhang <zhangjian.fnst@cn.fujitsu.com>
|
||||
Jiang Jinyang <jjyruby@gmail.com>
|
||||
Jianyong Wu <jianyong.wu@arm.com>
|
||||
|
@ -1160,7 +1141,6 @@ junxu <xujun@cmss.chinamobile.com>
|
|||
Jussi Nummelin <jussi.nummelin@gmail.com>
|
||||
Justas Brazauskas <brazauskasjustas@gmail.com>
|
||||
Justen Martin <jmart@the-coder.com>
|
||||
Justin Chadwell <me@jedevc.com>
|
||||
Justin Cormack <justin.cormack@docker.com>
|
||||
Justin Force <justin.force@gmail.com>
|
||||
Justin Keller <85903732+jk-vb@users.noreply.github.com>
|
||||
|
@ -1203,7 +1183,6 @@ Ke Xu <leonhartx.k@gmail.com>
|
|||
Kei Ohmura <ohmura.kei@gmail.com>
|
||||
Keith Hudgins <greenman@greenman.org>
|
||||
Keli Hu <dev@keli.hu>
|
||||
Ken Bannister <kb2ma@runbox.com>
|
||||
Ken Cochrane <kencochrane@gmail.com>
|
||||
Ken Herner <kherner@progress.com>
|
||||
Ken ICHIKAWA <ichikawa.ken@jp.fujitsu.com>
|
||||
|
@ -1213,7 +1192,7 @@ Kenjiro Nakayama <nakayamakenjiro@gmail.com>
|
|||
Kent Johnson <kentoj@gmail.com>
|
||||
Kenta Tada <Kenta.Tada@sony.com>
|
||||
Kevin "qwazerty" Houdebert <kevin.houdebert@gmail.com>
|
||||
Kevin Alvarez <github@crazymax.dev>
|
||||
Kevin Alvarez <crazy-max@users.noreply.github.com>
|
||||
Kevin Burke <kev@inburke.com>
|
||||
Kevin Clark <kevin.clark@gmail.com>
|
||||
Kevin Feyrer <kevin.feyrer@btinternet.com>
|
||||
|
@ -1246,7 +1225,6 @@ Konstantin Gribov <grossws@gmail.com>
|
|||
Konstantin L <sw.double@gmail.com>
|
||||
Konstantin Pelykh <kpelykh@zettaset.com>
|
||||
Kostadin Plachkov <k.n.plachkov@gmail.com>
|
||||
kpcyrd <git@rxv.cc>
|
||||
Krasi Georgiev <krasi@vip-consult.solutions>
|
||||
Krasimir Georgiev <support@vip-consult.co.uk>
|
||||
Kris-Mikael Krister <krismikael@protonmail.com>
|
||||
|
@ -1328,7 +1306,6 @@ Lorenzo Fontana <fontanalorenz@gmail.com>
|
|||
Lotus Fenn <fenn.lotus@gmail.com>
|
||||
Louis Delossantos <ldelossa.ld@gmail.com>
|
||||
Louis Opter <kalessin@kalessin.fr>
|
||||
Luboslav Pivarc <lpivarc@redhat.com>
|
||||
Luca Favatella <luca.favatella@erlang-solutions.com>
|
||||
Luca Marturana <lucamarturana@gmail.com>
|
||||
Luca Orlandi <luca.orlandi@gmail.com>
|
||||
|
@ -1367,7 +1344,6 @@ Manuel Meurer <manuel@krautcomputing.com>
|
|||
Manuel Rüger <manuel@rueg.eu>
|
||||
Manuel Woelker <github@manuel.woelker.org>
|
||||
mapk0y <mapk0y@gmail.com>
|
||||
Marat Radchenko <marat@slonopotamus.org>
|
||||
Marc Abramowitz <marc@marc-abramowitz.com>
|
||||
Marc Kuo <kuomarc2@gmail.com>
|
||||
Marc Tamsky <mtamsky@gmail.com>
|
||||
|
@ -1407,7 +1383,6 @@ Martijn van Oosterhout <kleptog@svana.org>
|
|||
Martin Braun <braun@neuroforge.de>
|
||||
Martin Dojcak <martin.dojcak@lablabs.io>
|
||||
Martin Honermeyer <maze@strahlungsfrei.de>
|
||||
Martin Jirku <martin@jirku.sk>
|
||||
Martin Kelly <martin@surround.io>
|
||||
Martin Mosegaard Amdisen <martin.amdisen@praqma.com>
|
||||
Martin Muzatko <martin@happy-css.com>
|
||||
|
@ -1486,7 +1461,6 @@ Michael Holzheu <holzheu@linux.vnet.ibm.com>
|
|||
Michael Hudson-Doyle <michael.hudson@canonical.com>
|
||||
Michael Huettermann <michael@huettermann.net>
|
||||
Michael Irwin <mikesir87@gmail.com>
|
||||
Michael Kebe <michael.kebe@hkm.de>
|
||||
Michael Kuehn <micha@kuehn.io>
|
||||
Michael Käufl <docker@c.michael-kaeufl.de>
|
||||
Michael Neale <michael.neale@gmail.com>
|
||||
|
@ -1535,11 +1509,10 @@ Mike Lundy <mike@fluffypenguin.org>
|
|||
Mike MacCana <mike.maccana@gmail.com>
|
||||
Mike Naberezny <mike@naberezny.com>
|
||||
Mike Snitzer <snitzer@redhat.com>
|
||||
Mike Sul <mike.sul@foundries.io>
|
||||
mikelinjie <294893458@qq.com>
|
||||
Mikhail Sobolev <mss@mawhrin.net>
|
||||
Miklos Szegedi <miklos.szegedi@cloudera.com>
|
||||
Milas Bowman <devnull@milas.dev>
|
||||
Milas Bowman <milasb@gmail.com>
|
||||
Milind Chawre <milindchawre@gmail.com>
|
||||
Miloslav Trmač <mitr@redhat.com>
|
||||
mingqing <limingqing@cyou-inc.com>
|
||||
|
@ -1551,7 +1524,6 @@ mlarcher <github@ringabell.org>
|
|||
Mohammad Banikazemi <MBanikazemi@gmail.com>
|
||||
Mohammad Nasirifar <farnasirim@gmail.com>
|
||||
Mohammed Aaqib Ansari <maaquib@gmail.com>
|
||||
Mohd Sadiq <mohdsadiq058@gmail.com>
|
||||
Mohit Soni <mosoni@ebay.com>
|
||||
Moorthy RS <rsmoorthy@gmail.com>
|
||||
Morgan Bauer <mbauer@us.ibm.com>
|
||||
|
@ -1634,7 +1606,6 @@ Noah Treuhaft <noah.treuhaft@docker.com>
|
|||
NobodyOnSE <ich@sektor.selfip.com>
|
||||
noducks <onemannoducks@gmail.com>
|
||||
Nolan Darilek <nolan@thewordnerd.info>
|
||||
Nolan Miles <nolanpmiles@gmail.com>
|
||||
Noriki Nakamura <noriki.nakamura@miraclelinux.com>
|
||||
nponeccop <andy.melnikov@gmail.com>
|
||||
Nurahmadie <nurahmadie@gmail.com>
|
||||
|
@ -1690,7 +1661,6 @@ Paul Lietar <paul@lietar.net>
|
|||
Paul Liljenberg <liljenberg.paul@gmail.com>
|
||||
Paul Morie <pmorie@gmail.com>
|
||||
Paul Nasrat <pnasrat@gmail.com>
|
||||
Paul Seiffert <paul.seiffert@jimdo.com>
|
||||
Paul Weaver <pauweave@cisco.com>
|
||||
Paulo Gomes <pjbgf@linux.com>
|
||||
Paulo Ribeiro <paigr.io@gmail.com>
|
||||
|
@ -1704,7 +1674,6 @@ Pavlos Ratis <dastergon@gentoo.org>
|
|||
Pavol Vargovcik <pallly.vargovcik@gmail.com>
|
||||
Pawel Konczalski <mail@konczalski.de>
|
||||
Paweł Gronowski <pawel.gronowski@docker.com>
|
||||
payall4u <payall4u@qq.com>
|
||||
Peeyush Gupta <gpeeyush@linux.vnet.ibm.com>
|
||||
Peggy Li <peggyli.224@gmail.com>
|
||||
Pei Su <sillyousu@gmail.com>
|
||||
|
@ -1734,9 +1703,7 @@ Phil Estes <estesp@gmail.com>
|
|||
Phil Sphicas <phil.sphicas@att.com>
|
||||
Phil Spitler <pspitler@gmail.com>
|
||||
Philip Alexander Etling <paetling@gmail.com>
|
||||
Philip K. Warren <pkwarren@gmail.com>
|
||||
Philip Monroe <phil@philmonroe.com>
|
||||
Philipp Fruck <dev@p-fruck.de>
|
||||
Philipp Gillé <philipp.gille@gmail.com>
|
||||
Philipp Wahala <philipp.wahala@gmail.com>
|
||||
Philipp Weissensteiner <mail@philippweissensteiner.com>
|
||||
|
@ -1774,7 +1741,6 @@ Quentin Brossard <qbrossard@gmail.com>
|
|||
Quentin Perez <qperez@ocs.online.net>
|
||||
Quentin Tayssier <qtayssier@gmail.com>
|
||||
r0n22 <cameron.regan@gmail.com>
|
||||
Rachit Sharma <rachitsharma613@gmail.com>
|
||||
Radostin Stoyanov <rstoyanov1@gmail.com>
|
||||
Rafal Jeczalik <rjeczalik@gmail.com>
|
||||
Rafe Colton <rafael.colton@gmail.com>
|
||||
|
@ -1807,7 +1773,6 @@ Rich Horwood <rjhorwood@apple.com>
|
|||
Rich Moyse <rich@moyse.us>
|
||||
Rich Seymour <rseymour@gmail.com>
|
||||
Richard Burnison <rburnison@ebay.com>
|
||||
Richard Hansen <rhansen@rhansen.org>
|
||||
Richard Harvey <richard@squarecows.com>
|
||||
Richard Mathie <richard.mathie@amey.co.uk>
|
||||
Richard Metzler <richard@paadee.com>
|
||||
|
@ -1823,7 +1788,6 @@ Ritesh H Shukla <sritesh@vmware.com>
|
|||
Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
|
||||
Rob Cowsill <42620235+rcowsill@users.noreply.github.com>
|
||||
Rob Gulewich <rgulewich@netflix.com>
|
||||
Rob Murray <rob.murray@docker.com>
|
||||
Rob Vesse <rvesse@dotnetrdf.org>
|
||||
Robert Bachmann <rb@robertbachmann.at>
|
||||
Robert Bittle <guywithnose@gmail.com>
|
||||
|
@ -1905,7 +1869,6 @@ ryancooper7 <ryan.cooper7@gmail.com>
|
|||
RyanDeng <sheldon.d1018@gmail.com>
|
||||
Ryo Nakao <nakabonne@gmail.com>
|
||||
Ryoga Saito <contact@proelbtn.com>
|
||||
Régis Behmo <regis@behmo.com>
|
||||
Rémy Greinhofer <remy.greinhofer@livelovely.com>
|
||||
s. rannou <mxs@sbrk.org>
|
||||
Sabin Basyal <sabin.basyal@gmail.com>
|
||||
|
@ -1922,7 +1885,6 @@ Sam J Sharpe <sam.sharpe@digital.cabinet-office.gov.uk>
|
|||
Sam Neirinck <sam@samneirinck.com>
|
||||
Sam Reis <sreis@atlassian.com>
|
||||
Sam Rijs <srijs@airpost.net>
|
||||
Sam Thibault <sam.thibault@docker.com>
|
||||
Sam Whited <sam@samwhited.com>
|
||||
Sambuddha Basu <sambuddhabasu1@gmail.com>
|
||||
Sami Wagiaalla <swagiaal@redhat.com>
|
||||
|
@ -1946,7 +1908,6 @@ Satoshi Tagomori <tagomoris@gmail.com>
|
|||
Scott Bessler <scottbessler@gmail.com>
|
||||
Scott Collier <emailscottcollier@gmail.com>
|
||||
Scott Johnston <scott@docker.com>
|
||||
Scott Moser <smoser@brickies.net>
|
||||
Scott Percival <scottp@lastyard.com>
|
||||
Scott Stamp <scottstamp851@gmail.com>
|
||||
Scott Walls <sawalls@umich.edu>
|
||||
|
@ -1962,7 +1923,6 @@ Sebastiaan van Steenis <mail@superseb.nl>
|
|||
Sebastiaan van Stijn <github@gone.nl>
|
||||
Sebastian Höffner <sebastian.hoeffner@mevis.fraunhofer.de>
|
||||
Sebastian Radloff <sradloff23@gmail.com>
|
||||
Sebastian Thomschke <sebthom@users.noreply.github.com>
|
||||
Sebastien Goasguen <runseb@gmail.com>
|
||||
Senthil Kumar Selvaraj <senthil.thecoder@gmail.com>
|
||||
Senthil Kumaran <senthil@uthcode.com>
|
||||
|
@ -1974,7 +1934,6 @@ Sergey Evstifeev <sergey.evstifeev@gmail.com>
|
|||
Sergii Kabashniuk <skabashnyuk@codenvy.com>
|
||||
Sergio Lopez <slp@redhat.com>
|
||||
Serhat Gülçiçek <serhat25@gmail.com>
|
||||
Serhii Nakon <serhii.n@thescimus.com>
|
||||
SeungUkLee <lsy931106@gmail.com>
|
||||
Sevki Hasirci <s@sevki.org>
|
||||
Shane Canon <scanon@lbl.gov>
|
||||
|
@ -2037,7 +1996,6 @@ Stanislav Bondarenko <stanislav.bondarenko@gmail.com>
|
|||
Stanislav Levin <slev@altlinux.org>
|
||||
Steeve Morin <steeve.morin@gmail.com>
|
||||
Stefan Berger <stefanb@linux.vnet.ibm.com>
|
||||
Stefan Gehrig <stefan.gehrig.hn@googlemail.com>
|
||||
Stefan J. Wernli <swernli@microsoft.com>
|
||||
Stefan Praszalowicz <stefan@greplin.com>
|
||||
Stefan S. <tronicum@user.github.com>
|
||||
|
@ -2045,7 +2003,6 @@ Stefan Scherer <stefan.scherer@docker.com>
|
|||
Stefan Staudenmeyer <doerte@instana.com>
|
||||
Stefan Weil <sw@weilnetz.de>
|
||||
Steffen Butzer <steffen.butzer@outlook.com>
|
||||
Stephan Henningsen <stephan-henningsen@users.noreply.github.com>
|
||||
Stephan Spindler <shutefan@gmail.com>
|
||||
Stephen Benjamin <stephen@redhat.com>
|
||||
Stephen Crosby <stevecrozz@gmail.com>
|
||||
|
@ -2247,7 +2204,6 @@ Vinod Kulkarni <vinod.kulkarni@gmail.com>
|
|||
Vishal Doshi <vishal.doshi@gmail.com>
|
||||
Vishnu Kannan <vishnuk@google.com>
|
||||
Vitaly Ostrosablin <vostrosablin@virtuozzo.com>
|
||||
Vitor Anjos <bartier@users.noreply.github.com>
|
||||
Vitor Monteiro <vmrmonteiro@gmail.com>
|
||||
Vivek Agarwal <me@vivek.im>
|
||||
Vivek Dasgupta <vdasgupt@redhat.com>
|
||||
|
@ -2261,7 +2217,6 @@ VladimirAus <v_roudakov@yahoo.com>
|
|||
Vladislav Kolesnikov <vkolesnikov@beget.ru>
|
||||
Vlastimil Zeman <vlastimil.zeman@diffblue.com>
|
||||
Vojtech Vitek (V-Teq) <vvitek@redhat.com>
|
||||
voloder <110066198+voloder@users.noreply.github.com>
|
||||
Walter Leibbrandt <github@wrl.co.za>
|
||||
Walter Stanish <walter@pratyeka.org>
|
||||
Wang Chao <chao.wang@ucloud.cn>
|
||||
|
@ -2295,7 +2250,6 @@ Wenxuan Zhao <viz@linux.com>
|
|||
Wenyu You <21551128@zju.edu.cn>
|
||||
Wenzhi Liang <wenzhi.liang@gmail.com>
|
||||
Wes Morgan <cap10morgan@gmail.com>
|
||||
Wesley Pettit <wppttt@amazon.com>
|
||||
Wewang Xiaorenfine <wang.xiaoren@zte.com.cn>
|
||||
Wiktor Kwapisiewicz <wiktor@metacode.biz>
|
||||
Will Dietz <w@wdtz.org>
|
||||
|
@ -2335,7 +2289,7 @@ xiekeyang <xiekeyang@huawei.com>
|
|||
Ximo Guanter Gonzálbez <joaquin.guantergonzalbez@telefonica.com>
|
||||
xin.li <xin.li@daocloud.io>
|
||||
Xinbo Weng <xihuanbo_0521@zju.edu.cn>
|
||||
Xinfeng Liu <XinfengLiu@icloud.com>
|
||||
Xinfeng Liu <xinfeng.liu@gmail.com>
|
||||
Xinzi Zhou <imdreamrunner@gmail.com>
|
||||
Xiuming Chen <cc@cxm.cc>
|
||||
Xuecong Liao <satorulogic@gmail.com>
|
||||
|
@ -2401,7 +2355,6 @@ Zen Lin(Zhinan Lin) <linzhinan@huawei.com>
|
|||
Zhang Kun <zkazure@gmail.com>
|
||||
Zhang Wei <zhangwei555@huawei.com>
|
||||
Zhang Wentao <zhangwentao234@huawei.com>
|
||||
zhangguanzhang <zhangguanzhang@qq.com>
|
||||
ZhangHang <stevezhang2014@gmail.com>
|
||||
zhangxianwei <xianwei.zw@alibaba-inc.com>
|
||||
Zhenan Ye <21551168@zju.edu.cn>
|
||||
|
@ -2428,7 +2381,6 @@ Zuhayr Elahi <zuhayr.elahi@docker.com>
|
|||
Zunayed Ali <zunayed@gmail.com>
|
||||
Álvaro Lázaro <alvaro.lazaro.g@gmail.com>
|
||||
Átila Camurça Alves <camurca.home@gmail.com>
|
||||
吴小白 <296015668@qq.com>
|
||||
尹吉峰 <jifeng.yin@gmail.com>
|
||||
屈骏 <qujun@tiduyun.com>
|
||||
徐俊杰 <paco.xu@daocloud.io>
|
||||
|
|
|
@ -101,7 +101,7 @@ the contributors guide.
|
|||
<td>
|
||||
<p>
|
||||
Register for the Docker Community Slack at
|
||||
<a href="https://dockr.ly/comm-slack" target="_blank">https://dockr.ly/comm-slack</a>.
|
||||
<a href="https://dockr.ly/slack" target="_blank">https://dockr.ly/slack</a>.
|
||||
We use the #moby-project channel for general discussion, and there are separate channels for other Moby projects such as #containerd.
|
||||
</p>
|
||||
</td>
|
||||
|
@ -422,6 +422,6 @@ The rules:
|
|||
guidelines. Since you've read all the rules, you now know that.
|
||||
|
||||
If you are having trouble getting into the mood of idiomatic Go, we recommend
|
||||
reading through [Effective Go](https://go.dev/doc/effective_go). The
|
||||
[Go Blog](https://go.dev/blog/) is also a great resource. Drinking the
|
||||
reading through [Effective Go](https://golang.org/doc/effective_go.html). The
|
||||
[Go Blog](https://blog.golang.org) is also a great resource. Drinking the
|
||||
kool-aid is a lot easier than going thirsty.
|
||||
|
|
261
Dockerfile
261
Dockerfile
|
@ -1,35 +1,17 @@
|
|||
# syntax=docker/dockerfile:1.7
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG GO_VERSION=1.21.9
|
||||
ARG BASE_DEBIAN_DISTRO="bookworm"
|
||||
ARG GO_VERSION=1.20.4
|
||||
ARG BASE_DEBIAN_DISTRO="bullseye"
|
||||
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"
|
||||
ARG XX_VERSION=1.4.0
|
||||
ARG XX_VERSION=1.2.1
|
||||
|
||||
ARG VPNKIT_VERSION=0.5.0
|
||||
|
||||
ARG DOCKERCLI_REPOSITORY="https://github.com/docker/cli.git"
|
||||
ARG DOCKERCLI_VERSION=v26.0.0
|
||||
# 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.13.1
|
||||
ARG COMPOSE_VERSION=v2.25.0
|
||||
ARG DOCKERCLI_VERSION=v17.06.2-ce
|
||||
|
||||
ARG SYSTEMD="false"
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG DOCKER_STATIC=1
|
||||
|
||||
# REGISTRY_VERSION specifies the version of the registry to download from
|
||||
# https://hub.docker.com/r/distribution/distribution. This version of
|
||||
# the registry is used to test schema 2 manifests. Generally, the version
|
||||
# specified here should match a current release.
|
||||
ARG REGISTRY_VERSION=2.8.3
|
||||
|
||||
# delve is currently only supported on linux/amd64 and linux/arm64;
|
||||
# https://github.com/go-delve/delve/blob/v1.8.1/pkg/proc/native/support_sentinel.go#L1-L6
|
||||
ARG DELVE_SUPPORTED=${TARGETPLATFORM#linux/amd64} DELVE_SUPPORTED=${DELVE_SUPPORTED#linux/arm64}
|
||||
ARG DELVE_SUPPORTED=${DELVE_SUPPORTED:+"unsupported"}
|
||||
ARG DELVE_SUPPORTED=${DELVE_SUPPORTED:-"supported"}
|
||||
|
||||
# cross compilation helper
|
||||
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
|
||||
|
||||
|
@ -44,19 +26,22 @@ COPY --from=build-dummy /build /build
|
|||
FROM --platform=$BUILDPLATFORM ${GOLANG_IMAGE} AS base
|
||||
COPY --from=xx / /
|
||||
RUN echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
|
||||
ARG APT_MIRROR
|
||||
RUN sed -ri "s/(httpredir|deb).debian.org/${APT_MIRROR:-deb.debian.org}/g" /etc/apt/sources.list \
|
||||
&& sed -ri "s/(security).debian.org/${APT_MIRROR:-security.debian.org}/g" /etc/apt/sources.list
|
||||
ARG DEBIAN_FRONTEND
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y file
|
||||
ENV GO111MODULE=off
|
||||
ENV GOTOOLCHAIN=local
|
||||
|
||||
FROM base AS criu
|
||||
ARG DEBIAN_FRONTEND
|
||||
ADD --chmod=0644 https://download.opensuse.org/repositories/devel:/tools:/criu/Debian_11/Release.key /etc/apt/trusted.gpg.d/criu.gpg.asc
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-criu-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-criu-aptcache,target=/var/cache/apt \
|
||||
echo 'deb https://download.opensuse.org/repositories/devel:/tools:/criu/Debian_12/ /' > /etc/apt/sources.list.d/criu.list \
|
||||
echo 'deb https://download.opensuse.org/repositories/devel:/tools:/criu/Debian_11/ /' > /etc/apt/sources.list.d/criu.list \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends criu \
|
||||
&& install -D /usr/sbin/criu /build/criu \
|
||||
&& /build/criu --version
|
||||
&& install -D /usr/sbin/criu /build/criu
|
||||
|
||||
# registry
|
||||
FROM base AS registry-src
|
||||
|
@ -65,7 +50,11 @@ RUN git init . && git remote add origin "https://github.com/distribution/distrib
|
|||
|
||||
FROM base AS registry
|
||||
WORKDIR /go/src/github.com/docker/distribution
|
||||
|
||||
# REGISTRY_VERSION specifies the version of the registry to build and install
|
||||
# from the https://github.com/docker/distribution repository. This version of
|
||||
# the registry is used to test both schema 1 and schema 2 manifests. Generally,
|
||||
# the version specified here should match a current release.
|
||||
ARG REGISTRY_VERSION=v2.3.0
|
||||
# REGISTRY_VERSION_SCHEMA1 specifies the version of the registry to build and
|
||||
# install from the https://github.com/docker/distribution repository. This is
|
||||
# an older (pre v2.3.0) version of the registry that only supports schema1
|
||||
|
@ -78,10 +67,11 @@ RUN --mount=from=registry-src,src=/usr/src/registry,rw \
|
|||
--mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=tmpfs,target=/go/src <<EOT
|
||||
set -ex
|
||||
git fetch -q --depth 1 origin "${REGISTRY_VERSION}" +refs/tags/*:refs/tags/*
|
||||
git checkout -q FETCH_HEAD
|
||||
export GOPATH="/go/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH"
|
||||
# Make the /build directory no matter what so that it doesn't fail on arm64 or
|
||||
# any other platform where we don't build this registry
|
||||
mkdir /build
|
||||
CGO_ENABLED=0 xx-go build -o /build/registry-v2 -v ./cmd/registry
|
||||
xx-verify /build/registry-v2
|
||||
case $TARGETPLATFORM in
|
||||
linux/amd64|linux/arm/v7|linux/ppc64le|linux/s390x)
|
||||
git fetch -q --depth 1 origin "${REGISTRY_VERSION_SCHEMA1}" +refs/tags/*:refs/tags/*
|
||||
|
@ -92,9 +82,6 @@ RUN --mount=from=registry-src,src=/usr/src/registry,rw \
|
|||
esac
|
||||
EOT
|
||||
|
||||
FROM distribution/distribution:$REGISTRY_VERSION AS registry-v2
|
||||
RUN mkdir /build && mv /bin/registry /build/registry-v2
|
||||
|
||||
# go-swagger
|
||||
FROM base AS swagger-src
|
||||
WORKDIR /usr/src/swagger
|
||||
|
@ -122,6 +109,7 @@ EOT
|
|||
# See also frozenImages in "testutil/environment/protect.go" (which needs to
|
||||
# be updated when adding images to this list)
|
||||
FROM debian:${BASE_DEBIAN_DISTRO} AS frozen-images
|
||||
ARG DEBIAN_FRONTEND
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-frozen-images-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-frozen-images-aptcache,target=/var/cache/apt \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
|
@ -135,7 +123,7 @@ ARG TARGETVARIANT
|
|||
RUN /download-frozen-image-v2.sh /build \
|
||||
busybox:latest@sha256:95cf004f559831017cdf4628aaf1bb30133677be8702a8c5f2994629f637a209 \
|
||||
busybox:glibc@sha256:1f81263701cddf6402afe9f33fca0266d9fff379e59b1748f33d3072da71ee85 \
|
||||
debian:bookworm-slim@sha256:2bc5c236e9b262645a323e9088dfa3bb1ecb16cc75811daf40a23a824d665be9 \
|
||||
debian:bullseye-slim@sha256:dacf278785a4daa9de07596ec739dbc07131e189942772210709c5c0777e8437 \
|
||||
hello-world:latest@sha256:d58e752213a51785838f9eed2b7a498ffa1cb3aa7f946dda11af39286c3db9a9 \
|
||||
arm32v7/hello-world:latest@sha256:50b8560ad574c779908da71f7ce370c0a2471c098d44d1c8f6b513c5a55eeeb1
|
||||
|
||||
|
@ -147,10 +135,10 @@ RUN git init . && git remote add origin "https://github.com/go-delve/delve.git"
|
|||
# from the https://github.com/go-delve/delve repository.
|
||||
# It can be used to run Docker with a possibility of
|
||||
# attaching debugger to it.
|
||||
ARG DELVE_VERSION=v1.21.1
|
||||
ARG DELVE_VERSION=v1.20.1
|
||||
RUN git fetch -q --depth 1 origin "${DELVE_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
|
||||
|
||||
FROM base AS delve-supported
|
||||
FROM base AS delve-build
|
||||
WORKDIR /usr/src/delve
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=from=delve-src,src=/usr/src/delve,rw \
|
||||
|
@ -161,8 +149,16 @@ RUN --mount=from=delve-src,src=/usr/src/delve,rw \
|
|||
xx-verify /build/dlv
|
||||
EOT
|
||||
|
||||
FROM binary-dummy AS delve-unsupported
|
||||
FROM delve-${DELVE_SUPPORTED} AS delve
|
||||
# delve is currently only supported on linux/amd64 and linux/arm64;
|
||||
# https://github.com/go-delve/delve/blob/v1.8.1/pkg/proc/native/support_sentinel.go#L1-L6
|
||||
FROM binary-dummy AS delve-windows
|
||||
FROM binary-dummy AS delve-linux-arm
|
||||
FROM binary-dummy AS delve-linux-ppc64le
|
||||
FROM binary-dummy AS delve-linux-s390x
|
||||
FROM delve-build AS delve-linux-amd64
|
||||
FROM delve-build AS delve-linux-arm64
|
||||
FROM delve-linux-${TARGETARCH} AS delve-linux
|
||||
FROM delve-${TARGETOS} AS delve
|
||||
|
||||
FROM base AS tomll
|
||||
# GOTOML_VERSION specifies the version of the tomll binary to build and install
|
||||
|
@ -179,7 +175,7 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
|
|||
|
||||
FROM base AS gowinres
|
||||
# GOWINRES_VERSION defines go-winres tool version
|
||||
ARG GOWINRES_VERSION=v0.3.1
|
||||
ARG GOWINRES_VERSION=v0.3.0
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
GOBIN=/build/ GO111MODULE=on go install "github.com/tc-hib/go-winres@${GOWINRES_VERSION}" \
|
||||
|
@ -196,19 +192,17 @@ 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.15
|
||||
ARG CONTAINERD_VERSION=v1.7.1
|
||||
RUN git fetch -q --depth 1 origin "${CONTAINERD_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
|
||||
|
||||
FROM base AS containerd-build
|
||||
WORKDIR /go/src/github.com/containerd/containerd
|
||||
ARG DEBIAN_FRONTEND
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-containerd-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-containerd-aptcache,target=/var/cache/apt \
|
||||
apt-get update && xx-apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
libbtrfs-dev \
|
||||
libsecret-1-dev \
|
||||
pkg-config
|
||||
gcc libbtrfs-dev libsecret-1-dev
|
||||
ARG DOCKER_STATIC
|
||||
RUN --mount=from=containerd-src,src=/usr/src/containerd,rw \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=containerd-build-$TARGETPLATFORM <<EOT
|
||||
|
@ -229,7 +223,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.51.2
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
GOBIN=/build/ GO111MODULE=on go install "github.com/golangci/golangci-lint/cmd/golangci-lint@${GOLANGCI_LINT_VERSION}" \
|
||||
|
@ -243,41 +237,40 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
|
|||
&& /build/gotestsum --version
|
||||
|
||||
FROM base AS shfmt
|
||||
ARG SHFMT_VERSION=v3.8.0
|
||||
ARG SHFMT_VERSION=v3.6.0
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
GOBIN=/build/ GO111MODULE=on go install "mvdan.cc/sh/v3/cmd/shfmt@${SHFMT_VERSION}" \
|
||||
&& /build/shfmt --version
|
||||
|
||||
FROM base AS gopls
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
GOBIN=/build/ GO111MODULE=on go install "golang.org/x/tools/gopls@latest" \
|
||||
&& /build/gopls version
|
||||
# dockercli
|
||||
FROM base AS dockercli-src
|
||||
WORKDIR /tmp/dockercli
|
||||
RUN git init . && git remote add origin "https://github.com/docker/cli.git"
|
||||
ARG DOCKERCLI_VERSION
|
||||
RUN git fetch -q --depth 1 origin "${DOCKERCLI_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
|
||||
RUN [ -d ./components/cli ] && mv ./components/cli /usr/src/dockercli || mv /tmp/dockercli /usr/src/dockercli
|
||||
WORKDIR /usr/src/dockercli
|
||||
|
||||
FROM base AS dockercli
|
||||
WORKDIR /go/src/github.com/docker/cli
|
||||
ARG DOCKERCLI_REPOSITORY
|
||||
ARG DOCKERCLI_VERSION
|
||||
ARG DOCKERCLI_CHANNEL=stable
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=source=hack/dockerfile/cli.sh,target=/download-or-build-cli.sh \
|
||||
--mount=type=cache,id=dockercli-git-$TARGETPLATFORM,sharing=locked,target=./.git \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=dockercli-build-$TARGETPLATFORM \
|
||||
rm -f ./.git/*.lock \
|
||||
&& /download-or-build-cli.sh ${DOCKERCLI_VERSION} ${DOCKERCLI_REPOSITORY} /build \
|
||||
&& /build/docker --version
|
||||
|
||||
FROM base AS dockercli-integration
|
||||
WORKDIR /go/src/github.com/docker/cli
|
||||
ARG DOCKERCLI_INTEGRATION_REPOSITORY
|
||||
ARG DOCKERCLI_INTEGRATION_VERSION
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=source=hack/dockerfile/cli.sh,target=/download-or-build-cli.sh \
|
||||
--mount=type=cache,id=dockercli-git-$TARGETPLATFORM,sharing=locked,target=./.git \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=dockercli-build-$TARGETPLATFORM \
|
||||
rm -f ./.git/*.lock \
|
||||
&& /download-or-build-cli.sh ${DOCKERCLI_INTEGRATION_VERSION} ${DOCKERCLI_INTEGRATION_REPOSITORY} /build \
|
||||
&& /build/docker --version
|
||||
RUN xx-apt-get install -y --no-install-recommends gcc libc6-dev
|
||||
RUN --mount=from=dockercli-src,src=/usr/src/dockercli,rw \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=dockercli-build-$TARGETPLATFORM <<EOT
|
||||
set -e
|
||||
DOWNLOAD_URL="https://download.docker.com/linux/static/${DOCKERCLI_CHANNEL}/$(xx-info march)/docker-${DOCKERCLI_VERSION#v}.tgz"
|
||||
if curl --head --silent --fail "${DOWNLOAD_URL}" 1>/dev/null 2>&1; then
|
||||
mkdir /build
|
||||
curl -Ls "${DOWNLOAD_URL}" | tar -xz docker/docker
|
||||
mv docker/docker /build/docker
|
||||
else
|
||||
CGO_ENABLED=0 xx-go build -o /build/docker ./cmd/docker
|
||||
fi
|
||||
xx-verify /build/docker
|
||||
EOT
|
||||
|
||||
# runc
|
||||
FROM base AS runc-src
|
||||
|
@ -287,20 +280,17 @@ RUN git init . && git remote add origin "https://github.com/opencontainers/runc.
|
|||
# that is used. If you need to update runc, open a pull request in the containerd
|
||||
# project first, and update both after that is merged. When updating RUNC_VERSION,
|
||||
# consider updating runc in vendor.mod accordingly.
|
||||
ARG RUNC_VERSION=v1.1.12
|
||||
ARG RUNC_VERSION=v1.1.7
|
||||
RUN git fetch -q --depth 1 origin "${RUNC_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
|
||||
|
||||
FROM base AS runc-build
|
||||
WORKDIR /go/src/github.com/opencontainers/runc
|
||||
ARG DEBIAN_FRONTEND
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-runc-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-runc-aptcache,target=/var/cache/apt \
|
||||
apt-get update && xx-apt-get install -y --no-install-recommends \
|
||||
dpkg-dev \
|
||||
gcc \
|
||||
libc6-dev \
|
||||
libseccomp-dev \
|
||||
pkg-config
|
||||
dpkg-dev gcc libc6-dev libseccomp-dev
|
||||
ARG DOCKER_STATIC
|
||||
RUN --mount=from=runc-src,src=/usr/src/runc,rw \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=runc-build-$TARGETPLATFORM <<EOT
|
||||
|
@ -327,6 +317,7 @@ RUN git fetch -q --depth 1 origin "${TINI_VERSION}" +refs/tags/*:refs/tags/* &&
|
|||
|
||||
FROM base AS tini-build
|
||||
WORKDIR /go/src/github.com/krallin/tini
|
||||
ARG DEBIAN_FRONTEND
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-tini-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-tini-aptcache,target=/var/cache/apt \
|
||||
apt-get update && apt-get install -y --no-install-recommends cmake
|
||||
|
@ -334,9 +325,7 @@ ARG TARGETPLATFORM
|
|||
RUN --mount=type=cache,sharing=locked,id=moby-tini-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-tini-aptcache,target=/var/cache/apt \
|
||||
xx-apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
libc6-dev \
|
||||
pkg-config
|
||||
gcc libc6-dev
|
||||
RUN --mount=from=tini-src,src=/usr/src/tini,rw \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=tini-build-$TARGETPLATFORM <<EOT
|
||||
set -e
|
||||
|
@ -355,19 +344,18 @@ FROM tini-${TARGETOS} AS tini
|
|||
FROM base AS rootlesskit-src
|
||||
WORKDIR /usr/src/rootlesskit
|
||||
RUN git init . && git remote add origin "https://github.com/rootless-containers/rootlesskit.git"
|
||||
# When updating, also update vendor.mod and hack/dockerfile/install/rootlesskit.installer accordingly.
|
||||
ARG ROOTLESSKIT_VERSION=v2.0.2
|
||||
# When updating, also update rootlesskit commit in vendor.mod accordingly.
|
||||
ARG ROOTLESSKIT_VERSION=v1.1.0
|
||||
RUN git fetch -q --depth 1 origin "${ROOTLESSKIT_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
|
||||
|
||||
FROM base AS rootlesskit-build
|
||||
WORKDIR /go/src/github.com/rootless-containers/rootlesskit
|
||||
ARG DEBIAN_FRONTEND
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-rootlesskit-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-rootlesskit-aptcache,target=/var/cache/apt \
|
||||
apt-get update && xx-apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
libc6-dev \
|
||||
pkg-config
|
||||
gcc libc6-dev
|
||||
ENV GO111MODULE=on
|
||||
ARG DOCKER_STATIC
|
||||
RUN --mount=from=rootlesskit-src,src=/usr/src/rootlesskit,rw \
|
||||
|
@ -380,15 +368,15 @@ RUN --mount=from=rootlesskit-src,src=/usr/src/rootlesskit,rw \
|
|||
xx-go build -o /build/rootlesskit-docker-proxy -ldflags="$([ "$DOCKER_STATIC" != "1" ] && echo "-linkmode=external")" ./cmd/rootlesskit-docker-proxy
|
||||
xx-verify $([ "$DOCKER_STATIC" = "1" ] && echo "--static") /build/rootlesskit-docker-proxy
|
||||
EOT
|
||||
COPY --link ./contrib/dockerd-rootless.sh /build/
|
||||
COPY --link ./contrib/dockerd-rootless-setuptool.sh /build/
|
||||
COPY ./contrib/dockerd-rootless.sh /build/
|
||||
COPY ./contrib/dockerd-rootless-setuptool.sh /build/
|
||||
|
||||
FROM rootlesskit-build AS rootlesskit-linux
|
||||
FROM binary-dummy AS rootlesskit-windows
|
||||
FROM rootlesskit-${TARGETOS} AS rootlesskit
|
||||
|
||||
FROM base AS crun
|
||||
ARG CRUN_VERSION=1.12
|
||||
ARG CRUN_VERSION=1.4.5
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-crun-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-crun-aptcache,target=/var/cache/apt \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
|
@ -435,11 +423,7 @@ RUN git fetch -q --depth 1 origin "${CONTAINERUTILITY_VERSION}" +refs/tags/*:ref
|
|||
FROM base AS containerutil-build
|
||||
WORKDIR /usr/src/containerutil
|
||||
ARG TARGETPLATFORM
|
||||
RUN xx-apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
g++ \
|
||||
libc6-dev \
|
||||
pkg-config
|
||||
RUN xx-apt-get install -y --no-install-recommends gcc g++ libc6-dev
|
||||
RUN --mount=from=containerutil-src,src=/usr/src/containerutil,rw \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=containerutil-build-$TARGETPLATFORM <<EOT
|
||||
set -e
|
||||
|
@ -453,39 +437,28 @@ FROM binary-dummy AS containerutil-linux
|
|||
FROM containerutil-build AS containerutil-windows-amd64
|
||||
FROM containerutil-windows-${TARGETARCH} AS containerutil-windows
|
||||
FROM containerutil-${TARGETOS} AS containerutil
|
||||
FROM docker/buildx-bin:${BUILDX_VERSION} as buildx
|
||||
FROM docker/compose-bin:${COMPOSE_VERSION} as compose
|
||||
|
||||
FROM base AS dev-systemd-false
|
||||
COPY --link --from=frozen-images /build/ /docker-frozen-images
|
||||
COPY --link --from=swagger /build/ /usr/local/bin/
|
||||
COPY --link --from=delve /build/ /usr/local/bin/
|
||||
COPY --link --from=tomll /build/ /usr/local/bin/
|
||||
COPY --link --from=gowinres /build/ /usr/local/bin/
|
||||
COPY --link --from=tini /build/ /usr/local/bin/
|
||||
COPY --link --from=registry /build/ /usr/local/bin/
|
||||
COPY --link --from=registry-v2 /build/ /usr/local/bin/
|
||||
|
||||
# Skip the CRIU stage for now, as the opensuse package repository is sometimes
|
||||
# unstable, and we're currently not using it in CI.
|
||||
#
|
||||
# FIXME(thaJeztah): re-enable this stage when https://github.com/moby/moby/issues/38963 is resolved (see https://github.com/moby/moby/pull/38984)
|
||||
# COPY --link --from=criu /build/ /usr/local/bin/
|
||||
COPY --link --from=gotestsum /build/ /usr/local/bin/
|
||||
COPY --link --from=golangci_lint /build/ /usr/local/bin/
|
||||
COPY --link --from=shfmt /build/ /usr/local/bin/
|
||||
COPY --link --from=runc /build/ /usr/local/bin/
|
||||
COPY --link --from=containerd /build/ /usr/local/bin/
|
||||
COPY --link --from=rootlesskit /build/ /usr/local/bin/
|
||||
COPY --link --from=vpnkit / /usr/local/bin/
|
||||
COPY --link --from=containerutil /build/ /usr/local/bin/
|
||||
COPY --link --from=crun /build/ /usr/local/bin/
|
||||
COPY --link hack/dockerfile/etc/docker/ /etc/docker/
|
||||
COPY --link --from=buildx /buildx /usr/local/libexec/docker/cli-plugins/docker-buildx
|
||||
COPY --link --from=compose /docker-compose /usr/libexec/docker/cli-plugins/docker-compose
|
||||
|
||||
COPY --from=dockercli /build/ /usr/local/cli
|
||||
COPY --from=frozen-images /build/ /docker-frozen-images
|
||||
COPY --from=swagger /build/ /usr/local/bin/
|
||||
COPY --from=delve /build/ /usr/local/bin/
|
||||
COPY --from=tomll /build/ /usr/local/bin/
|
||||
COPY --from=gowinres /build/ /usr/local/bin/
|
||||
COPY --from=tini /build/ /usr/local/bin/
|
||||
COPY --from=registry /build/ /usr/local/bin/
|
||||
COPY --from=criu /build/ /usr/local/bin/
|
||||
COPY --from=gotestsum /build/ /usr/local/bin/
|
||||
COPY --from=golangci_lint /build/ /usr/local/bin/
|
||||
COPY --from=shfmt /build/ /usr/local/bin/
|
||||
COPY --from=runc /build/ /usr/local/bin/
|
||||
COPY --from=containerd /build/ /usr/local/bin/
|
||||
COPY --from=rootlesskit /build/ /usr/local/bin/
|
||||
COPY --from=vpnkit / /usr/local/bin/
|
||||
COPY --from=containerutil /build/ /usr/local/bin/
|
||||
COPY --from=crun /build/ /usr/local/bin/
|
||||
COPY hack/dockerfile/etc/docker/ /etc/docker/
|
||||
ENV PATH=/usr/local/cli:$PATH
|
||||
ENV TEST_CLIENT_BINARY=/usr/local/cli-integration/docker
|
||||
ENV CONTAINERD_ADDRESS=/run/docker/containerd/containerd.sock
|
||||
ENV CONTAINERD_NAMESPACE=moby
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
|
@ -505,6 +478,7 @@ RUN --mount=type=cache,sharing=locked,id=moby-dev-aptlib,target=/var/lib/apt \
|
|||
ENTRYPOINT ["hack/dind-systemd"]
|
||||
|
||||
FROM dev-systemd-${SYSTEMD} AS dev-base
|
||||
ARG DEBIAN_FRONTEND
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser \
|
||||
&& mkdir -p /home/unprivilegeduser/.local/share/docker \
|
||||
|
@ -538,6 +512,9 @@ RUN --mount=type=cache,sharing=locked,id=moby-dev-aptlib,target=/var/lib/apt \
|
|||
net-tools \
|
||||
patch \
|
||||
pigz \
|
||||
python3-pip \
|
||||
python3-setuptools \
|
||||
python3-wheel \
|
||||
sudo \
|
||||
systemd-journal-remote \
|
||||
thin-provisioning-tools \
|
||||
|
@ -553,6 +530,8 @@ RUN --mount=type=cache,sharing=locked,id=moby-dev-aptlib,target=/var/lib/apt \
|
|||
RUN update-alternatives --set iptables /usr/sbin/iptables-legacy || true \
|
||||
&& update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy || true \
|
||||
&& update-alternatives --set arptables /usr/sbin/arptables-legacy || true
|
||||
ARG YAMLLINT_VERSION=1.27.1
|
||||
RUN pip3 install yamllint==${YAMLLINT_VERSION}
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-dev-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-dev-aptcache,target=/var/cache/apt \
|
||||
apt-get update && apt-get install --no-install-recommends -y \
|
||||
|
@ -560,19 +539,18 @@ RUN --mount=type=cache,sharing=locked,id=moby-dev-aptlib,target=/var/lib/apt \
|
|||
pkg-config \
|
||||
dpkg-dev \
|
||||
libapparmor-dev \
|
||||
libdevmapper-dev \
|
||||
libseccomp-dev \
|
||||
libsecret-1-dev \
|
||||
libsystemd-dev \
|
||||
libudev-dev \
|
||||
yamllint
|
||||
COPY --link --from=dockercli /build/ /usr/local/cli
|
||||
COPY --link --from=dockercli-integration /build/ /usr/local/cli-integration
|
||||
libudev-dev
|
||||
|
||||
FROM base AS build
|
||||
COPY --from=gowinres /build/ /usr/local/bin/
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV GO111MODULE=off
|
||||
ENV CGO_ENABLED=1
|
||||
ARG DEBIAN_FRONTEND
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-build-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-build-aptcache,target=/var/cache/apt \
|
||||
apt-get update && apt-get install --no-install-recommends -y \
|
||||
|
@ -587,11 +565,11 @@ RUN --mount=type=cache,sharing=locked,id=moby-build-aptlib,target=/var/lib/apt \
|
|||
gcc \
|
||||
libapparmor-dev \
|
||||
libc6-dev \
|
||||
libdevmapper-dev \
|
||||
libseccomp-dev \
|
||||
libsecret-1-dev \
|
||||
libsystemd-dev \
|
||||
libudev-dev \
|
||||
pkg-config
|
||||
libudev-dev
|
||||
ARG DOCKER_BUILDTAGS
|
||||
ARG DOCKER_DEBUG
|
||||
ARG DOCKER_GITCOMMIT=HEAD
|
||||
|
@ -611,7 +589,7 @@ RUN <<EOT
|
|||
XX_CC_PREFER_LINKER=ld xx-clang --setup-target-triple
|
||||
fi
|
||||
EOT
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
RUN --mount=type=bind,target=. \
|
||||
--mount=type=tmpfs,target=cli/winresources/dockerd \
|
||||
--mount=type=tmpfs,target=cli/winresources/docker-proxy \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=moby-build-$TARGETPLATFORM <<EOT
|
||||
|
@ -637,13 +615,13 @@ COPY --from=build /build/ /
|
|||
# usage:
|
||||
# > docker buildx bake all
|
||||
FROM scratch AS all
|
||||
COPY --link --from=tini /build/ /
|
||||
COPY --link --from=runc /build/ /
|
||||
COPY --link --from=containerd /build/ /
|
||||
COPY --link --from=rootlesskit /build/ /
|
||||
COPY --link --from=containerutil /build/ /
|
||||
COPY --link --from=vpnkit / /
|
||||
COPY --link --from=build /build /
|
||||
COPY --from=tini /build/ /
|
||||
COPY --from=runc /build/ /
|
||||
COPY --from=containerd /build/ /
|
||||
COPY --from=rootlesskit /build/ /
|
||||
COPY --from=containerutil /build/ /
|
||||
COPY --from=vpnkit / /
|
||||
COPY --from=build /build /
|
||||
|
||||
# smoke tests
|
||||
# usage:
|
||||
|
@ -659,13 +637,8 @@ RUN <<EOT
|
|||
docker-proxy --version
|
||||
EOT
|
||||
|
||||
# devcontainer is a stage used by .devcontainer/devcontainer.json
|
||||
FROM dev-base AS devcontainer
|
||||
COPY --link . .
|
||||
COPY --link --from=gopls /build/ /usr/local/bin/
|
||||
|
||||
# usage:
|
||||
# > make shell
|
||||
# > SYSTEMD=true make shell
|
||||
FROM dev-base AS dev
|
||||
COPY --link . .
|
||||
COPY . .
|
||||
|
|
84
Dockerfile.e2e
Normal file
84
Dockerfile.e2e
Normal file
|
@ -0,0 +1,84 @@
|
|||
ARG GO_VERSION=1.20.4
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine AS base
|
||||
ENV GO111MODULE=off
|
||||
RUN apk --no-cache add \
|
||||
bash \
|
||||
build-base \
|
||||
curl \
|
||||
lvm2-dev \
|
||||
jq
|
||||
|
||||
RUN mkdir -p /build/
|
||||
RUN mkdir -p /go/src/github.com/docker/docker/
|
||||
WORKDIR /go/src/github.com/docker/docker/
|
||||
|
||||
FROM base AS frozen-images
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /
|
||||
RUN /download-frozen-image-v2.sh /build \
|
||||
busybox:latest@sha256:95cf004f559831017cdf4628aaf1bb30133677be8702a8c5f2994629f637a209 \
|
||||
busybox:latest@sha256:95cf004f559831017cdf4628aaf1bb30133677be8702a8c5f2994629f637a209 \
|
||||
debian:bullseye-slim@sha256:dacf278785a4daa9de07596ec739dbc07131e189942772210709c5c0777e8437 \
|
||||
hello-world:latest@sha256:d58e752213a51785838f9eed2b7a498ffa1cb3aa7f946dda11af39286c3db9a9 \
|
||||
arm32v7/hello-world:latest@sha256:50b8560ad574c779908da71f7ce370c0a2471c098d44d1c8f6b513c5a55eeeb1
|
||||
# See also frozenImages in "testutil/environment/protect.go" (which needs to be updated when adding images to this list)
|
||||
|
||||
FROM base AS dockercli
|
||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||
COPY hack/dockerfile/install/dockercli.installer ./
|
||||
RUN PREFIX=/build ./install.sh dockercli
|
||||
|
||||
# TestDockerCLIBuildSuite dependency
|
||||
FROM base AS contrib
|
||||
COPY contrib/syscall-test /build/syscall-test
|
||||
COPY contrib/httpserver/Dockerfile /build/httpserver/Dockerfile
|
||||
COPY contrib/httpserver contrib/httpserver
|
||||
RUN CGO_ENABLED=0 go build -buildmode=pie -o /build/httpserver/httpserver github.com/docker/docker/contrib/httpserver
|
||||
|
||||
# Build the integration tests and copy the resulting binaries to /build/tests
|
||||
FROM base AS builder
|
||||
|
||||
# Set tag and add sources
|
||||
COPY . .
|
||||
# Copy test sources tests that use assert can print errors
|
||||
RUN mkdir -p /build${PWD} && find integration integration-cli -name \*_test.go -exec cp --parents '{}' /build${PWD} \;
|
||||
# Build and install test binaries
|
||||
ARG DOCKER_GITCOMMIT=undefined
|
||||
RUN hack/make.sh build-integration-test-binary
|
||||
RUN mkdir -p /build/tests && find . -name test.main -exec cp --parents '{}' /build/tests \;
|
||||
|
||||
## Generate testing image
|
||||
FROM alpine:3.10 as runner
|
||||
|
||||
ENV DOCKER_REMOTE_DAEMON=1
|
||||
ENV DOCKER_INTEGRATION_DAEMON_DEST=/
|
||||
ENTRYPOINT ["/scripts/run.sh"]
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN addgroup docker && adduser -D -G docker unprivilegeduser -s /bin/ash
|
||||
|
||||
# GNU tar is used for generating the emptyfs image
|
||||
RUN apk --no-cache add \
|
||||
bash \
|
||||
ca-certificates \
|
||||
g++ \
|
||||
git \
|
||||
inetutils-ping \
|
||||
iptables \
|
||||
libcap2-bin \
|
||||
pigz \
|
||||
tar \
|
||||
xz
|
||||
|
||||
COPY hack/test/e2e-run.sh /scripts/run.sh
|
||||
COPY hack/make/.ensure-emptyfs /scripts/ensure-emptyfs.sh
|
||||
|
||||
COPY integration/testdata /tests/integration/testdata
|
||||
COPY integration/build/testdata /tests/integration/build/testdata
|
||||
COPY integration-cli/fixtures /tests/integration-cli/fixtures
|
||||
|
||||
COPY --from=frozen-images /build/ /docker-frozen-images
|
||||
COPY --from=dockercli /build/ /usr/bin/
|
||||
COPY --from=contrib /build/ /tests/contrib/
|
||||
COPY --from=builder /build/ /
|
|
@ -5,14 +5,17 @@
|
|||
|
||||
# This represents the bare minimum required to build and test Docker.
|
||||
|
||||
ARG GO_VERSION=1.21.9
|
||||
ARG GO_VERSION=1.20.4
|
||||
|
||||
ARG BASE_DEBIAN_DISTRO="bookworm"
|
||||
ARG BASE_DEBIAN_DISTRO="bullseye"
|
||||
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"
|
||||
|
||||
FROM ${GOLANG_IMAGE}
|
||||
ENV GO111MODULE=off
|
||||
ENV GOTOOLCHAIN=local
|
||||
|
||||
# allow replacing httpredir or deb mirror
|
||||
ARG APT_MIRROR=deb.debian.org
|
||||
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
|
||||
|
||||
# Compile and runtime deps
|
||||
# https://github.com/docker/docker/blob/master/project/PACKAGERS.md#build-dependencies
|
||||
|
@ -23,6 +26,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
cmake \
|
||||
git \
|
||||
libapparmor-dev \
|
||||
libdevmapper-dev \
|
||||
libseccomp-dev \
|
||||
ca-certificates \
|
||||
e2fsprogs \
|
||||
|
|
|
@ -154,17 +154,21 @@
|
|||
|
||||
# The number of build steps below are explicitly minimised to improve performance.
|
||||
|
||||
ARG WINDOWS_BASE_IMAGE=mcr.microsoft.com/windows/servercore
|
||||
ARG WINDOWS_BASE_IMAGE_TAG=ltsc2022
|
||||
FROM ${WINDOWS_BASE_IMAGE}:${WINDOWS_BASE_IMAGE_TAG}
|
||||
# Extremely important - do not change the following line to reference a "specific" image,
|
||||
# such as `mcr.microsoft.com/windows/servercore:ltsc2022`. If using this Dockerfile in process
|
||||
# isolated containers, the kernel of the host must match the container image, and hence
|
||||
# would fail between Windows Server 2016 (aka RS1) and Windows Server 2019 (aka RS5).
|
||||
# It is expected that the image `microsoft/windowsservercore:latest` is present, and matches
|
||||
# the hosts kernel version before doing a build.
|
||||
FROM microsoft/windowsservercore
|
||||
|
||||
# Use PowerShell as the default shell
|
||||
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
|
||||
|
||||
ARG GO_VERSION=1.21.9
|
||||
ARG GO_VERSION=1.20.4
|
||||
ARG GOTESTSUM_VERSION=v1.8.2
|
||||
ARG GOWINRES_VERSION=v0.3.1
|
||||
ARG CONTAINERD_VERSION=v1.7.15
|
||||
ARG GOWINRES_VERSION=v0.3.0
|
||||
ARG CONTAINERD_VERSION=v1.7.1
|
||||
|
||||
# Environment variable notes:
|
||||
# - GO_VERSION must be consistent with 'Dockerfile' used by Linux.
|
||||
|
@ -175,7 +179,6 @@ ENV GO_VERSION=${GO_VERSION} `
|
|||
GIT_VERSION=2.11.1 `
|
||||
GOPATH=C:\gopath `
|
||||
GO111MODULE=off `
|
||||
GOTOOLCHAIN=local `
|
||||
FROM_DOCKERFILE=1 `
|
||||
GOTESTSUM_VERSION=${GOTESTSUM_VERSION} `
|
||||
GOWINRES_VERSION=${GOWINRES_VERSION}
|
||||
|
@ -220,8 +223,8 @@ RUN `
|
|||
Download-File $location C:\gitsetup.zip; `
|
||||
`
|
||||
Write-Host INFO: Downloading go...; `
|
||||
$dlGoVersion=$Env:GO_VERSION; `
|
||||
Download-File "https://go.dev/dl/go${dlGoVersion}.windows-amd64.zip" C:\go.zip; `
|
||||
$dlGoVersion=$Env:GO_VERSION -replace '\.0$',''; `
|
||||
Download-File "https://golang.org/dl/go${dlGoVersion}.windows-amd64.zip" C:\go.zip; `
|
||||
`
|
||||
Write-Host INFO: Downloading compiler 1 of 3...; `
|
||||
Download-File https://raw.githubusercontent.com/moby/docker-tdmgcc/master/gcc.zip C:\gcc.zip; `
|
||||
|
|
405
Jenkinsfile
vendored
405
Jenkinsfile
vendored
|
@ -9,12 +9,15 @@ pipeline {
|
|||
}
|
||||
parameters {
|
||||
booleanParam(name: 'arm64', defaultValue: true, description: 'ARM (arm64) Build/Test')
|
||||
booleanParam(name: 's390x', defaultValue: false, description: 'IBM Z (s390x) Build/Test')
|
||||
booleanParam(name: 'ppc64le', defaultValue: false, description: 'PowerPC (ppc64le) Build/Test')
|
||||
booleanParam(name: 'dco', defaultValue: true, description: 'Run the DCO check')
|
||||
}
|
||||
environment {
|
||||
DOCKER_BUILDKIT = '1'
|
||||
DOCKER_EXPERIMENTAL = '1'
|
||||
DOCKER_GRAPHDRIVER = 'overlay2'
|
||||
APT_MIRROR = 'cdn-fastly.deb.debian.org'
|
||||
CHECK_CONFIG_COMMIT = '33a3680e08d1007e72c3b3f1454f823d8e9948ee'
|
||||
TESTDEBUG = '0'
|
||||
TIMEOUT = '120m'
|
||||
|
@ -49,6 +52,406 @@ pipeline {
|
|||
}
|
||||
stage('Build') {
|
||||
parallel {
|
||||
stage('s390x') {
|
||||
when {
|
||||
beforeAgent true
|
||||
// Skip this stage on PRs unless the checkbox is selected
|
||||
anyOf {
|
||||
not { changeRequest() }
|
||||
expression { params.s390x }
|
||||
}
|
||||
}
|
||||
agent { label 's390x-ubuntu-2004' }
|
||||
|
||||
stages {
|
||||
stage("Print info") {
|
||||
steps {
|
||||
sh 'docker version'
|
||||
sh 'docker info'
|
||||
sh '''
|
||||
echo "check-config.sh version: ${CHECK_CONFIG_COMMIT}"
|
||||
curl -fsSL -o ${WORKSPACE}/check-config.sh "https://raw.githubusercontent.com/moby/moby/${CHECK_CONFIG_COMMIT}/contrib/check-config.sh" \
|
||||
&& bash ${WORKSPACE}/check-config.sh || true
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Build dev image") {
|
||||
steps {
|
||||
sh '''
|
||||
docker build --force-rm --build-arg APT_MIRROR -t docker:${GIT_COMMIT} .
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Unit tests") {
|
||||
steps {
|
||||
sh '''
|
||||
sudo modprobe ip6table_filter
|
||||
'''
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/test/unit
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/junit-report*.xml', allowEmptyResults: true
|
||||
}
|
||||
}
|
||||
}
|
||||
stage("Integration tests") {
|
||||
environment { TEST_SKIP_INTEGRATION_CLI = '1' }
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e TESTDEBUG \
|
||||
-e TEST_INTEGRATION_USE_SNAPSHOTTER \
|
||||
-e TEST_SKIP_INTEGRATION_CLI \
|
||||
-e TIMEOUT \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/make.sh \
|
||||
dynbinary \
|
||||
test-integration
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
sh '''
|
||||
echo "Ensuring container killed."
|
||||
docker rm -vf docker-pr$BUILD_NUMBER || true
|
||||
'''
|
||||
|
||||
sh '''
|
||||
echo "Chowning /workspace to jenkins user"
|
||||
docker run --rm -v "$WORKSPACE:/workspace" busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||
'''
|
||||
|
||||
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') {
|
||||
sh '''
|
||||
bundleName=s390x-integration
|
||||
echo "Creating ${bundleName}-bundles.tar.gz"
|
||||
# exclude overlay2 directories
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
|
||||
'''
|
||||
|
||||
archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
|
||||
}
|
||||
}
|
||||
cleanup {
|
||||
sh 'make clean'
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('s390x integration-cli') {
|
||||
when {
|
||||
beforeAgent true
|
||||
// Skip this stage on PRs unless the checkbox is selected
|
||||
anyOf {
|
||||
not { changeRequest() }
|
||||
expression { params.s390x }
|
||||
}
|
||||
}
|
||||
agent { label 's390x-ubuntu-2004' }
|
||||
|
||||
stages {
|
||||
stage("Print info") {
|
||||
steps {
|
||||
sh 'docker version'
|
||||
sh 'docker info'
|
||||
sh '''
|
||||
echo "check-config.sh version: ${CHECK_CONFIG_COMMIT}"
|
||||
curl -fsSL -o ${WORKSPACE}/check-config.sh "https://raw.githubusercontent.com/moby/moby/${CHECK_CONFIG_COMMIT}/contrib/check-config.sh" \
|
||||
&& bash ${WORKSPACE}/check-config.sh || true
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Build dev image") {
|
||||
steps {
|
||||
sh '''
|
||||
docker build --force-rm --build-arg APT_MIRROR -t docker:${GIT_COMMIT} .
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Integration-cli tests") {
|
||||
environment { TEST_SKIP_INTEGRATION = '1' }
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e TEST_INTEGRATION_USE_SNAPSHOTTER \
|
||||
-e TEST_SKIP_INTEGRATION \
|
||||
-e TIMEOUT \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/make.sh \
|
||||
dynbinary \
|
||||
test-integration
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
sh '''
|
||||
echo "Ensuring container killed."
|
||||
docker rm -vf docker-pr$BUILD_NUMBER || true
|
||||
'''
|
||||
|
||||
sh '''
|
||||
echo "Chowning /workspace to jenkins user"
|
||||
docker run --rm -v "$WORKSPACE:/workspace" busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||
'''
|
||||
|
||||
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') {
|
||||
sh '''
|
||||
bundleName=s390x-integration-cli
|
||||
echo "Creating ${bundleName}-bundles.tar.gz"
|
||||
# exclude overlay2 directories
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
|
||||
'''
|
||||
|
||||
archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
|
||||
}
|
||||
}
|
||||
cleanup {
|
||||
sh 'make clean'
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('ppc64le') {
|
||||
when {
|
||||
beforeAgent true
|
||||
// Skip this stage on PRs unless the checkbox is selected
|
||||
anyOf {
|
||||
not { changeRequest() }
|
||||
expression { params.ppc64le }
|
||||
}
|
||||
}
|
||||
agent { label 'ppc64le-ubuntu-1604' }
|
||||
|
||||
stages {
|
||||
stage("Print info") {
|
||||
steps {
|
||||
sh 'docker version'
|
||||
sh 'docker info'
|
||||
sh '''
|
||||
echo "check-config.sh version: ${CHECK_CONFIG_COMMIT}"
|
||||
curl -fsSL -o ${WORKSPACE}/check-config.sh "https://raw.githubusercontent.com/moby/moby/${CHECK_CONFIG_COMMIT}/contrib/check-config.sh" \
|
||||
&& bash ${WORKSPACE}/check-config.sh || true
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Build dev image") {
|
||||
steps {
|
||||
sh '''
|
||||
docker buildx build --load --force-rm --build-arg APT_MIRROR -t docker:${GIT_COMMIT} .
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Unit tests") {
|
||||
steps {
|
||||
sh '''
|
||||
sudo modprobe ip6table_filter
|
||||
'''
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/test/unit
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/junit-report*.xml', allowEmptyResults: true
|
||||
}
|
||||
}
|
||||
}
|
||||
stage("Integration tests") {
|
||||
environment { TEST_SKIP_INTEGRATION_CLI = '1' }
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e TESTDEBUG \
|
||||
-e TEST_INTEGRATION_USE_SNAPSHOTTER \
|
||||
-e TEST_SKIP_INTEGRATION_CLI \
|
||||
-e TIMEOUT \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/make.sh \
|
||||
dynbinary \
|
||||
test-integration
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
sh '''
|
||||
echo "Ensuring container killed."
|
||||
docker rm -vf docker-pr$BUILD_NUMBER || true
|
||||
'''
|
||||
|
||||
sh '''
|
||||
echo "Chowning /workspace to jenkins user"
|
||||
docker run --rm -v "$WORKSPACE:/workspace" busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||
'''
|
||||
|
||||
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') {
|
||||
sh '''
|
||||
bundleName=ppc64le-integration
|
||||
echo "Creating ${bundleName}-bundles.tar.gz"
|
||||
# exclude overlay2 directories
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
|
||||
'''
|
||||
|
||||
archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
|
||||
}
|
||||
}
|
||||
cleanup {
|
||||
sh 'make clean'
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('ppc64le integration-cli') {
|
||||
when {
|
||||
beforeAgent true
|
||||
// Skip this stage on PRs unless the checkbox is selected
|
||||
anyOf {
|
||||
not { changeRequest() }
|
||||
expression { params.ppc64le }
|
||||
}
|
||||
}
|
||||
agent { label 'ppc64le-ubuntu-1604' }
|
||||
|
||||
stages {
|
||||
stage("Print info") {
|
||||
steps {
|
||||
sh 'docker version'
|
||||
sh 'docker info'
|
||||
sh '''
|
||||
echo "check-config.sh version: ${CHECK_CONFIG_COMMIT}"
|
||||
curl -fsSL -o ${WORKSPACE}/check-config.sh "https://raw.githubusercontent.com/moby/moby/${CHECK_CONFIG_COMMIT}/contrib/check-config.sh" \
|
||||
&& bash ${WORKSPACE}/check-config.sh || true
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Build dev image") {
|
||||
steps {
|
||||
sh '''
|
||||
docker buildx build --load --force-rm --build-arg APT_MIRROR -t docker:${GIT_COMMIT} .
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Integration-cli tests") {
|
||||
environment { TEST_SKIP_INTEGRATION = '1' }
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e TEST_INTEGRATION_USE_SNAPSHOTTER \
|
||||
-e TEST_SKIP_INTEGRATION \
|
||||
-e TIMEOUT \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/make.sh \
|
||||
dynbinary \
|
||||
test-integration
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
sh '''
|
||||
echo "Ensuring container killed."
|
||||
docker rm -vf docker-pr$BUILD_NUMBER || true
|
||||
'''
|
||||
|
||||
sh '''
|
||||
echo "Chowning /workspace to jenkins user"
|
||||
docker run --rm -v "$WORKSPACE:/workspace" busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||
'''
|
||||
|
||||
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') {
|
||||
sh '''
|
||||
bundleName=ppc64le-integration-cli
|
||||
echo "Creating ${bundleName}-bundles.tar.gz"
|
||||
# exclude overlay2 directories
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
|
||||
'''
|
||||
|
||||
archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
|
||||
}
|
||||
}
|
||||
cleanup {
|
||||
sh 'make clean'
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('arm64') {
|
||||
when {
|
||||
beforeAgent true
|
||||
|
@ -73,7 +476,7 @@ pipeline {
|
|||
}
|
||||
stage("Build dev image") {
|
||||
steps {
|
||||
sh 'docker build --force-rm -t docker:${GIT_COMMIT} .'
|
||||
sh 'docker build --force-rm --build-arg APT_MIRROR -t docker:${GIT_COMMIT} .'
|
||||
}
|
||||
}
|
||||
stage("Unit tests") {
|
||||
|
|
20
MAINTAINERS
20
MAINTAINERS
|
@ -24,18 +24,15 @@
|
|||
# subsystem maintainers accountable. If ownership is unclear, they are the de facto owners.
|
||||
|
||||
people = [
|
||||
"akerouanton",
|
||||
"akihirosuda",
|
||||
"anusha",
|
||||
"coolljt0725",
|
||||
"corhere",
|
||||
"cpuguy83",
|
||||
"crazy-max",
|
||||
"estesp",
|
||||
"johnstep",
|
||||
"justincormack",
|
||||
"kolyshkin",
|
||||
"laurazard",
|
||||
"mhbauer",
|
||||
"neersighted",
|
||||
"rumpl",
|
||||
|
@ -66,16 +63,17 @@
|
|||
# - close an issue or pull request when it's inappropriate or off-topic
|
||||
|
||||
people = [
|
||||
"akerouanton",
|
||||
"alexellis",
|
||||
"andrewhsu",
|
||||
"bsousaa",
|
||||
"dmcgowan",
|
||||
"crazy-max",
|
||||
"fntlnz",
|
||||
"gianarb",
|
||||
"laurazard",
|
||||
"olljanat",
|
||||
"programmerq",
|
||||
"ripcurld",
|
||||
"robmry",
|
||||
"sam-thibault",
|
||||
"samwhited",
|
||||
"thajeztah"
|
||||
|
@ -359,11 +357,6 @@
|
|||
Email = "dnephin@gmail.com"
|
||||
GitHub = "dnephin"
|
||||
|
||||
[people.dmcgowan]
|
||||
Name = "Derek McGowan"
|
||||
Email = "derek@mcgstyle.net"
|
||||
GitHub = "dmcgowan"
|
||||
|
||||
[people.duglin]
|
||||
Name = "Doug Davis"
|
||||
Email = "dug@us.ibm.com"
|
||||
|
@ -466,7 +459,7 @@
|
|||
|
||||
[people.neersighted]
|
||||
Name = "Bjorn Neergaard"
|
||||
Email = "bjorn@neersighted.com"
|
||||
Email = "bneergaard@mirantis.com"
|
||||
GitHub = "neersighted"
|
||||
|
||||
[people.olljanat]
|
||||
|
@ -479,11 +472,6 @@
|
|||
Email = "jeff@docker.com"
|
||||
GitHub = "programmerq"
|
||||
|
||||
[people.robmry]
|
||||
Name = "Rob Murray"
|
||||
Email = "rob.murray@docker.com"
|
||||
GitHub = "robmry"
|
||||
|
||||
[people.ripcurld]
|
||||
Name = "Boaz Shuster"
|
||||
Email = "ripcurld.github@gmail.com"
|
||||
|
|
53
Makefile
53
Makefile
|
@ -4,10 +4,14 @@ DOCKER ?= docker
|
|||
BUILDX ?= $(DOCKER) buildx
|
||||
|
||||
# set the graph driver as the current graphdriver if not set
|
||||
DOCKER_GRAPHDRIVER := $(if $(DOCKER_GRAPHDRIVER),$(DOCKER_GRAPHDRIVER),$(shell docker info -f '{{ .Driver }}' 2>&1))
|
||||
DOCKER_GRAPHDRIVER := $(if $(DOCKER_GRAPHDRIVER),$(DOCKER_GRAPHDRIVER),$(shell docker info 2>&1 | grep "Storage Driver" | sed 's/.*: //'))
|
||||
export DOCKER_GRAPHDRIVER
|
||||
|
||||
DOCKER_GITCOMMIT := $(shell git rev-parse HEAD)
|
||||
# get OS/Arch of docker engine
|
||||
DOCKER_OSARCH := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $${DOCKER_ENGINE_OSARCH}')
|
||||
DOCKERFILE := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $${DOCKERFILE}')
|
||||
|
||||
DOCKER_GITCOMMIT := $(shell git rev-parse --short HEAD || echo unsupported)
|
||||
export DOCKER_GITCOMMIT
|
||||
|
||||
# allow overriding the repository and branch that validation scripts are running
|
||||
|
@ -16,9 +20,6 @@ export VALIDATE_REPO
|
|||
export VALIDATE_BRANCH
|
||||
export VALIDATE_ORIGIN_BRANCH
|
||||
|
||||
export PAGER
|
||||
export GIT_PAGER
|
||||
|
||||
# env vars passed through directly to Docker's build scripts
|
||||
# to allow things like `make KEEPBUNDLE=1 binary` easily
|
||||
# `project/PACKAGERS.md` have some limited documentation of some of these
|
||||
|
@ -27,9 +28,10 @@ export GIT_PAGER
|
|||
# option of "go build". For example, a built-in graphdriver priority list
|
||||
# can be changed during build time like this:
|
||||
#
|
||||
# make DOCKER_LDFLAGS="-X github.com/docker/docker/daemon/graphdriver.priority=overlay2,zfs" dynbinary
|
||||
# make DOCKER_LDFLAGS="-X github.com/docker/docker/daemon/graphdriver.priority=overlay2,devicemapper" dynbinary
|
||||
#
|
||||
DOCKER_ENVS := \
|
||||
-e BUILD_APT_MIRROR \
|
||||
-e BUILDFLAGS \
|
||||
-e KEEPBUNDLE \
|
||||
-e DOCKER_BUILD_ARGS \
|
||||
|
@ -39,10 +41,6 @@ DOCKER_ENVS := \
|
|||
-e DOCKER_BUILDKIT \
|
||||
-e DOCKER_BASH_COMPLETION_PATH \
|
||||
-e DOCKER_CLI_PATH \
|
||||
-e DOCKERCLI_VERSION \
|
||||
-e DOCKERCLI_REPOSITORY \
|
||||
-e DOCKERCLI_INTEGRATION_VERSION \
|
||||
-e DOCKERCLI_INTEGRATION_REPOSITORY \
|
||||
-e DOCKER_DEBUG \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT \
|
||||
|
@ -60,10 +58,8 @@ DOCKER_ENVS := \
|
|||
-e TEST_FORCE_VALIDATE \
|
||||
-e TEST_INTEGRATION_DIR \
|
||||
-e TEST_INTEGRATION_USE_SNAPSHOTTER \
|
||||
-e TEST_INTEGRATION_FAIL_FAST \
|
||||
-e TEST_SKIP_INTEGRATION \
|
||||
-e TEST_SKIP_INTEGRATION_CLI \
|
||||
-e TEST_IGNORE_CGROUP_CHECK \
|
||||
-e TESTCOVERAGE \
|
||||
-e TESTDEBUG \
|
||||
-e TESTDIRS \
|
||||
|
@ -79,12 +75,7 @@ DOCKER_ENVS := \
|
|||
-e PLATFORM \
|
||||
-e DEFAULT_PRODUCT_LICENSE \
|
||||
-e PRODUCT \
|
||||
-e PACKAGER_NAME \
|
||||
-e PAGER \
|
||||
-e GIT_PAGER \
|
||||
-e OTEL_EXPORTER_OTLP_ENDPOINT \
|
||||
-e OTEL_EXPORTER_OTLP_PROTOCOL \
|
||||
-e OTEL_SERVICE_NAME
|
||||
-e PACKAGER_NAME
|
||||
# note: we _cannot_ add "-e DOCKER_BUILDTAGS" here because even if it's unset in the shell, that would shadow the "ENV DOCKER_BUILDTAGS" set in our Dockerfile, which is very important for our official builds
|
||||
|
||||
# to allow `make BIND_DIR=. shell` or `make BIND_DIR= test`
|
||||
|
@ -116,6 +107,8 @@ DOCKER_PORT_FORWARD := $(if $(DOCKER_PORT),-p "$(DOCKER_PORT)",)
|
|||
DELVE_PORT_FORWARD := $(if $(DELVE_PORT),-p "$(DELVE_PORT)",)
|
||||
|
||||
DOCKER_FLAGS := $(DOCKER) run --rm --privileged $(DOCKER_CONTAINER_NAME) $(DOCKER_ENVS) $(DOCKER_MOUNT) $(DOCKER_PORT_FORWARD) $(DELVE_PORT_FORWARD)
|
||||
BUILD_APT_MIRROR := $(if $(DOCKER_BUILD_APT_MIRROR),--build-arg APT_MIRROR=$(DOCKER_BUILD_APT_MIRROR))
|
||||
export BUILD_APT_MIRROR
|
||||
|
||||
SWAGGER_DOCS_PORT ?= 9000
|
||||
|
||||
|
@ -143,15 +136,11 @@ endif
|
|||
DOCKER_RUN_DOCKER := $(DOCKER_FLAGS) "$(DOCKER_IMAGE)"
|
||||
|
||||
DOCKER_BUILD_ARGS += --build-arg=GO_VERSION
|
||||
DOCKER_BUILD_ARGS += --build-arg=DOCKERCLI_VERSION
|
||||
DOCKER_BUILD_ARGS += --build-arg=DOCKERCLI_REPOSITORY
|
||||
DOCKER_BUILD_ARGS += --build-arg=DOCKERCLI_INTEGRATION_VERSION
|
||||
DOCKER_BUILD_ARGS += --build-arg=DOCKERCLI_INTEGRATION_REPOSITORY
|
||||
ifdef DOCKER_SYSTEMD
|
||||
DOCKER_BUILD_ARGS += --build-arg=SYSTEMD=true
|
||||
endif
|
||||
|
||||
BUILD_OPTS := ${DOCKER_BUILD_ARGS} ${DOCKER_BUILD_OPTS}
|
||||
BUILD_OPTS := ${BUILD_APT_MIRROR} ${DOCKER_BUILD_ARGS} ${DOCKER_BUILD_OPTS} -f "$(DOCKERFILE)"
|
||||
BUILD_CMD := $(BUILDX) build
|
||||
BAKE_CMD := $(BUILDX) bake
|
||||
|
||||
|
@ -225,11 +214,6 @@ test-unit: build ## run the unit tests
|
|||
validate: build ## validate DCO, Seccomp profile generation, gofmt,\n./pkg/ isolation, golint, tests, tomls, go vet and vendor
|
||||
$(DOCKER_RUN_DOCKER) hack/validate/all
|
||||
|
||||
validate-generate-files:
|
||||
$(BUILD_CMD) --target "validate" \
|
||||
--output "type=cacheonly" \
|
||||
--file "./hack/dockerfiles/generate-files.Dockerfile" .
|
||||
|
||||
validate-%: build ## validate specific check
|
||||
$(DOCKER_RUN_DOCKER) hack/validate/$*
|
||||
|
||||
|
@ -251,16 +235,3 @@ swagger-docs: ## preview the API documentation
|
|||
-e 'REDOC_OPTIONS=hide-hostname="true" lazy-rendering' \
|
||||
-p $(SWAGGER_DOCS_PORT):80 \
|
||||
bfirsh/redoc:1.14.0
|
||||
|
||||
.PHONY: generate-files
|
||||
generate-files:
|
||||
$(eval $@_TMP_OUT := $(shell mktemp -d -t moby-output.XXXXXXXXXX))
|
||||
@if [ -z "$($@_TMP_OUT)" ]; then \
|
||||
echo "Temp dir is not set"; \
|
||||
exit 1; \
|
||||
fi
|
||||
$(BUILD_CMD) --target "update" \
|
||||
--output "type=local,dest=$($@_TMP_OUT)" \
|
||||
--file "./hack/dockerfiles/generate-files.Dockerfile" .
|
||||
cp -R "$($@_TMP_OUT)"/. .
|
||||
rm -rf "$($@_TMP_OUT)"/*
|
||||
|
|
|
@ -37,6 +37,6 @@ There is hopefully enough example material in the file for you to copy a similar
|
|||
|
||||
When you make edits to `swagger.yaml`, you may want to check the generated API documentation to ensure it renders correctly.
|
||||
|
||||
Run `make swagger-docs` and a preview will be running at `http://localhost:9000`. Some of the styling may be incorrect, but you'll be able to ensure that it is generating the correct documentation.
|
||||
Run `make swagger-docs` and a preview will be running at `http://localhost`. Some of the styling may be incorrect, but you'll be able to ensure that it is generating the correct documentation.
|
||||
|
||||
The production documentation is generated by vendoring `swagger.yaml` into [docker/docker.github.io](https://github.com/docker/docker.github.io).
|
||||
|
|
|
@ -2,17 +2,8 @@ package api // import "github.com/docker/docker/api"
|
|||
|
||||
// Common constants for daemon and client.
|
||||
const (
|
||||
// DefaultVersion of the current REST API.
|
||||
DefaultVersion = "1.45"
|
||||
|
||||
// MinSupportedAPIVersion is the minimum API version that can be supported
|
||||
// by the API server, specified as "major.minor". Note that the daemon
|
||||
// may be configured with a different minimum API version, as returned
|
||||
// in [github.com/docker/docker/api/types.Version.MinAPIVersion].
|
||||
//
|
||||
// API requests for API versions lower than the configured version produce
|
||||
// an error.
|
||||
MinSupportedAPIVersion = "1.24"
|
||||
// DefaultVersion of Current REST API
|
||||
DefaultVersion = "1.43"
|
||||
|
||||
// NoBaseImageSpecifier is the symbol used by the FROM
|
||||
// command to specify that no base image is to be used.
|
||||
|
|
7
api/common_unix.go
Normal file
7
api/common_unix.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package api // import "github.com/docker/docker/api"
|
||||
|
||||
// MinVersion represents Minimum REST API version supported
|
||||
const MinVersion = "1.12"
|
8
api/common_windows.go
Normal file
8
api/common_windows.go
Normal file
|
@ -0,0 +1,8 @@
|
|||
package api // import "github.com/docker/docker/api"
|
||||
|
||||
// MinVersion represents Minimum REST API version supported
|
||||
// Technically the first daemon API version released on Windows is v1.25 in
|
||||
// engine version 1.13. However, some clients are explicitly using downlevel
|
||||
// APIs (e.g. docker-compose v2.1 file format) and that is just too restrictive.
|
||||
// Hence also allowing 1.24 on Windows.
|
||||
const MinVersion string = "1.24"
|
|
@ -5,7 +5,7 @@ import (
|
|||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
|
@ -76,7 +76,7 @@ func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string
|
|||
return "", nil
|
||||
}
|
||||
|
||||
imageID := build.ImageID
|
||||
var imageID = build.ImageID
|
||||
if options.Squash {
|
||||
if imageID, err = squashBuild(build, b.imageComponent); err != nil {
|
||||
return "", err
|
||||
|
@ -104,7 +104,7 @@ func (b *Backend) PruneCache(ctx context.Context, opts types.BuildCachePruneOpti
|
|||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to prune build cache")
|
||||
}
|
||||
b.eventsService.Log(events.ActionPrune, events.BuilderEventType, events.Actor{
|
||||
b.eventsService.Log("prune", events.BuilderEventType, events.Actor{
|
||||
Attributes: map[string]string{
|
||||
"reclaimed": strconv.FormatInt(buildCacheSize, 10),
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
|
34
api/server/errorhandler.go
Normal file
34
api/server/errorhandler.go
Normal file
|
@ -0,0 +1,34 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httpstatus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/gorilla/mux"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// makeErrorHandler makes an HTTP handler that decodes a Docker error and
|
||||
// returns it in the response.
|
||||
func makeErrorHandler(err error) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
statusCode := httpstatus.FromError(err)
|
||||
vars := mux.Vars(r)
|
||||
if apiVersionSupportsJSONErrors(vars["version"]) {
|
||||
response := &types.ErrorResponse{
|
||||
Message: err.Error(),
|
||||
}
|
||||
_ = httputils.WriteJSON(w, statusCode, response)
|
||||
} else {
|
||||
http.Error(w, status.Convert(err).Message(), statusCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func apiVersionSupportsJSONErrors(version string) bool {
|
||||
const firstAPIVersionWithJSONErrors = "1.23"
|
||||
return version == "" || versions.GreaterThan(version, firstAPIVersionWithJSONErrors)
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
package httpstatus // import "github.com/docker/docker/api/server/httpstatus"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
cerrdefs "github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
@ -20,7 +19,7 @@ type causer interface {
|
|||
// FromError retrieves status code from error message.
|
||||
func FromError(err error) int {
|
||||
if err == nil {
|
||||
log.G(context.TODO()).WithError(err).Error("unexpected HTTP error handling")
|
||||
logrus.WithFields(logrus.Fields{"error": err}).Error("unexpected HTTP error handling")
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
|
||||
|
@ -66,11 +65,10 @@ func FromError(err error) int {
|
|||
return FromError(e.Cause())
|
||||
}
|
||||
|
||||
log.G(context.TODO()).WithFields(log.Fields{
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"module": "api",
|
||||
"error": err,
|
||||
"error_type": fmt.Sprintf("%T", err),
|
||||
}).Debug("FIXME: Got an API for which error does not match any expected type!!!")
|
||||
}).Debugf("FIXME: Got an API for which error does not match any expected type!!!: %+v", err)
|
||||
}
|
||||
|
||||
if statusCode == 0 {
|
||||
|
|
|
@ -12,4 +12,5 @@ import (
|
|||
// container configuration.
|
||||
type ContainerDecoder interface {
|
||||
DecodeConfig(src io.Reader) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error)
|
||||
DecodeHostConfig(src io.Reader) (*container.HostConfig, error)
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
)
|
||||
|
||||
// BoolValue transforms a form value in different formats into a boolean type.
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
"net/url"
|
||||
"sort"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
|
@ -16,7 +16,7 @@ import (
|
|||
|
||||
// WriteLogStream writes an encoded byte stream of log messages from the
|
||||
// messages channel, multiplexing them with a stdcopy.Writer if mux is true
|
||||
func WriteLogStream(_ context.Context, w io.Writer, msgs <-chan *backend.LogMessage, config *container.LogsOptions, mux bool) {
|
||||
func WriteLogStream(_ context.Context, w io.Writer, msgs <-chan *backend.LogMessage, config *types.ContainerLogsOptions, mux bool) {
|
||||
wf := ioutils.NewWriteFlusher(w)
|
||||
defer wf.Close()
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package server // import "github.com/docker/docker/api/server"
|
||||
|
||||
import (
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/server/middleware"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// handlerWithGlobalMiddlewares wraps the handler function for a request with
|
||||
|
@ -16,7 +16,7 @@ func (s *Server) handlerWithGlobalMiddlewares(handler httputils.APIFunc) httputi
|
|||
next = m.WrapHandler(next)
|
||||
}
|
||||
|
||||
if log.GetLevel() == log.DebugLevel {
|
||||
if logrus.GetLevel() == logrus.DebugLevel {
|
||||
next = middleware.DebugRequestMiddleware(next)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@ import (
|
|||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// CORSMiddleware injects CORS headers to each request
|
||||
|
@ -29,7 +29,7 @@ func (c CORSMiddleware) WrapHandler(handler func(ctx context.Context, w http.Res
|
|||
corsHeaders = "*"
|
||||
}
|
||||
|
||||
log.G(ctx).Debugf("CORS header is enabled and set to: %s", corsHeaders)
|
||||
logrus.Debugf("CORS header is enabled and set to: %s", corsHeaders)
|
||||
w.Header().Add("Access-Control-Allow-Origin", corsHeaders)
|
||||
w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, "+registry.AuthHeader)
|
||||
w.Header().Add("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS")
|
||||
|
|
|
@ -8,15 +8,15 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// DebugRequestMiddleware dumps the request to logger
|
||||
func DebugRequestMiddleware(handler func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error) func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
log.G(ctx).Debugf("Calling %s %s", r.Method, r.RequestURI)
|
||||
logrus.Debugf("Calling %s %s", r.Method, r.RequestURI)
|
||||
|
||||
if r.Method != http.MethodPost {
|
||||
return handler(ctx, w, r, vars)
|
||||
|
@ -44,9 +44,9 @@ func DebugRequestMiddleware(handler func(ctx context.Context, w http.ResponseWri
|
|||
maskSecretKeys(postForm)
|
||||
formStr, errMarshal := json.Marshal(postForm)
|
||||
if errMarshal == nil {
|
||||
log.G(ctx).Debugf("form data: %s", string(formStr))
|
||||
logrus.Debugf("form data: %s", string(formStr))
|
||||
} else {
|
||||
log.G(ctx).Debugf("form data: %q", postForm)
|
||||
logrus.Debugf("form data: %q", postForm)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"net/http"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
)
|
||||
|
@ -14,40 +13,19 @@ import (
|
|||
// VersionMiddleware is a middleware that
|
||||
// validates the client and server versions.
|
||||
type VersionMiddleware struct {
|
||||
serverVersion string
|
||||
|
||||
// defaultAPIVersion is the default API version provided by the API server,
|
||||
// specified as "major.minor". It is usually configured to the latest API
|
||||
// version [github.com/docker/docker/api.DefaultVersion].
|
||||
//
|
||||
// API requests for API versions greater than this version are rejected by
|
||||
// the server and produce a [versionUnsupportedError].
|
||||
defaultAPIVersion string
|
||||
|
||||
// minAPIVersion is the minimum API version provided by the API server,
|
||||
// specified as "major.minor".
|
||||
//
|
||||
// API requests for API versions lower than this version are rejected by
|
||||
// the server and produce a [versionUnsupportedError].
|
||||
minAPIVersion string
|
||||
serverVersion string
|
||||
defaultVersion string
|
||||
minVersion string
|
||||
}
|
||||
|
||||
// NewVersionMiddleware creates a VersionMiddleware with the given versions.
|
||||
func NewVersionMiddleware(serverVersion, defaultAPIVersion, minAPIVersion string) (*VersionMiddleware, error) {
|
||||
if versions.LessThan(defaultAPIVersion, api.MinSupportedAPIVersion) || versions.GreaterThan(defaultAPIVersion, api.DefaultVersion) {
|
||||
return nil, fmt.Errorf("invalid default API version (%s): must be between %s and %s", defaultAPIVersion, api.MinSupportedAPIVersion, api.DefaultVersion)
|
||||
// NewVersionMiddleware creates a new VersionMiddleware
|
||||
// with the default versions.
|
||||
func NewVersionMiddleware(s, d, m string) VersionMiddleware {
|
||||
return VersionMiddleware{
|
||||
serverVersion: s,
|
||||
defaultVersion: d,
|
||||
minVersion: m,
|
||||
}
|
||||
if versions.LessThan(minAPIVersion, api.MinSupportedAPIVersion) || versions.GreaterThan(minAPIVersion, api.DefaultVersion) {
|
||||
return nil, fmt.Errorf("invalid minimum API version (%s): must be between %s and %s", minAPIVersion, api.MinSupportedAPIVersion, api.DefaultVersion)
|
||||
}
|
||||
if versions.GreaterThan(minAPIVersion, defaultAPIVersion) {
|
||||
return nil, fmt.Errorf("invalid API version: the minimum API version (%s) is higher than the default version (%s)", minAPIVersion, defaultAPIVersion)
|
||||
}
|
||||
return &VersionMiddleware{
|
||||
serverVersion: serverVersion,
|
||||
defaultAPIVersion: defaultAPIVersion,
|
||||
minAPIVersion: minAPIVersion,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type versionUnsupportedError struct {
|
||||
|
@ -67,18 +45,18 @@ func (e versionUnsupportedError) InvalidParameter() {}
|
|||
func (v VersionMiddleware) WrapHandler(handler func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error) func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
w.Header().Set("Server", fmt.Sprintf("Docker/%s (%s)", v.serverVersion, runtime.GOOS))
|
||||
w.Header().Set("API-Version", v.defaultAPIVersion)
|
||||
w.Header().Set("API-Version", v.defaultVersion)
|
||||
w.Header().Set("OSType", runtime.GOOS)
|
||||
|
||||
apiVersion := vars["version"]
|
||||
if apiVersion == "" {
|
||||
apiVersion = v.defaultAPIVersion
|
||||
apiVersion = v.defaultVersion
|
||||
}
|
||||
if versions.LessThan(apiVersion, v.minAPIVersion) {
|
||||
return versionUnsupportedError{version: apiVersion, minVersion: v.minAPIVersion}
|
||||
if versions.LessThan(apiVersion, v.minVersion) {
|
||||
return versionUnsupportedError{version: apiVersion, minVersion: v.minVersion}
|
||||
}
|
||||
if versions.GreaterThan(apiVersion, v.defaultAPIVersion) {
|
||||
return versionUnsupportedError{version: apiVersion, maxVersion: v.defaultAPIVersion}
|
||||
if versions.GreaterThan(apiVersion, v.defaultVersion) {
|
||||
return versionUnsupportedError{version: apiVersion, maxVersion: v.defaultVersion}
|
||||
}
|
||||
ctx = context.WithValue(ctx, httputils.APIVersionKey{}, apiVersion)
|
||||
return handler(ctx, w, r, vars)
|
||||
|
|
|
@ -2,82 +2,27 @@ package middleware // import "github.com/docker/docker/api/server/middleware"
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestNewVersionMiddlewareValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
doc, defaultVersion, minVersion, expectedErr string
|
||||
}{
|
||||
{
|
||||
doc: "defaults",
|
||||
defaultVersion: api.DefaultVersion,
|
||||
minVersion: api.MinSupportedAPIVersion,
|
||||
},
|
||||
{
|
||||
doc: "invalid default lower than min",
|
||||
defaultVersion: api.MinSupportedAPIVersion,
|
||||
minVersion: api.DefaultVersion,
|
||||
expectedErr: fmt.Sprintf("invalid API version: the minimum API version (%s) is higher than the default version (%s)", api.DefaultVersion, api.MinSupportedAPIVersion),
|
||||
},
|
||||
{
|
||||
doc: "invalid default too low",
|
||||
defaultVersion: "0.1",
|
||||
minVersion: api.MinSupportedAPIVersion,
|
||||
expectedErr: fmt.Sprintf("invalid default API version (0.1): must be between %s and %s", api.MinSupportedAPIVersion, api.DefaultVersion),
|
||||
},
|
||||
{
|
||||
doc: "invalid default too high",
|
||||
defaultVersion: "9999.9999",
|
||||
minVersion: api.DefaultVersion,
|
||||
expectedErr: fmt.Sprintf("invalid default API version (9999.9999): must be between %s and %s", api.MinSupportedAPIVersion, api.DefaultVersion),
|
||||
},
|
||||
{
|
||||
doc: "invalid minimum too low",
|
||||
defaultVersion: api.MinSupportedAPIVersion,
|
||||
minVersion: "0.1",
|
||||
expectedErr: fmt.Sprintf("invalid minimum API version (0.1): must be between %s and %s", api.MinSupportedAPIVersion, api.DefaultVersion),
|
||||
},
|
||||
{
|
||||
doc: "invalid minimum too high",
|
||||
defaultVersion: api.DefaultVersion,
|
||||
minVersion: "9999.9999",
|
||||
expectedErr: fmt.Sprintf("invalid minimum API version (9999.9999): must be between %s and %s", api.MinSupportedAPIVersion, api.DefaultVersion),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
_, err := NewVersionMiddleware("1.2.3", tc.defaultVersion, tc.minVersion)
|
||||
if tc.expectedErr == "" {
|
||||
assert.Check(t, err)
|
||||
} else {
|
||||
assert.Check(t, is.Error(err, tc.expectedErr))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionMiddlewareVersion(t *testing.T) {
|
||||
expectedVersion := "<not set>"
|
||||
defaultVersion := "1.10.0"
|
||||
minVersion := "1.2.0"
|
||||
expectedVersion := defaultVersion
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
v := httputils.VersionFromContext(ctx)
|
||||
assert.Check(t, is.Equal(expectedVersion, v))
|
||||
return nil
|
||||
}
|
||||
|
||||
m, err := NewVersionMiddleware("1.2.3", api.DefaultVersion, api.MinSupportedAPIVersion)
|
||||
assert.NilError(t, err)
|
||||
m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
|
||||
h := m.WrapHandler(handler)
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "/containers/json", nil)
|
||||
|
@ -90,19 +35,19 @@ func TestVersionMiddlewareVersion(t *testing.T) {
|
|||
errString string
|
||||
}{
|
||||
{
|
||||
expectedVersion: api.DefaultVersion,
|
||||
expectedVersion: "1.10.0",
|
||||
},
|
||||
{
|
||||
reqVersion: api.MinSupportedAPIVersion,
|
||||
expectedVersion: api.MinSupportedAPIVersion,
|
||||
reqVersion: "1.9.0",
|
||||
expectedVersion: "1.9.0",
|
||||
},
|
||||
{
|
||||
reqVersion: "0.1",
|
||||
errString: fmt.Sprintf("client version 0.1 is too old. Minimum supported API version is %s, please upgrade your client to a newer version", api.MinSupportedAPIVersion),
|
||||
errString: "client version 0.1 is too old. Minimum supported API version is 1.2.0, please upgrade your client to a newer version",
|
||||
},
|
||||
{
|
||||
reqVersion: "9999.9999",
|
||||
errString: fmt.Sprintf("client version 9999.9999 is too new. Maximum supported API version is %s", api.DefaultVersion),
|
||||
errString: "client version 9999.9999 is too new. Maximum supported API version is 1.10.0",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -126,8 +71,9 @@ func TestVersionMiddlewareWithErrorsReturnsHeaders(t *testing.T) {
|
|||
return nil
|
||||
}
|
||||
|
||||
m, err := NewVersionMiddleware("1.2.3", api.DefaultVersion, api.MinSupportedAPIVersion)
|
||||
assert.NilError(t, err)
|
||||
defaultVersion := "1.10.0"
|
||||
minVersion := "1.2.0"
|
||||
m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
|
||||
h := m.WrapHandler(handler)
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "/containers/json", nil)
|
||||
|
@ -135,12 +81,12 @@ func TestVersionMiddlewareWithErrorsReturnsHeaders(t *testing.T) {
|
|||
ctx := context.Background()
|
||||
|
||||
vars := map[string]string{"version": "0.1"}
|
||||
err = h(ctx, resp, req, vars)
|
||||
err := h(ctx, resp, req, vars)
|
||||
assert.Check(t, is.ErrorContains(err, ""))
|
||||
|
||||
hdr := resp.Result().Header
|
||||
assert.Check(t, is.Contains(hdr.Get("Server"), "Docker/1.2.3"))
|
||||
assert.Check(t, is.Contains(hdr.Get("Server"), "Docker/"+defaultVersion))
|
||||
assert.Check(t, is.Contains(hdr.Get("Server"), runtime.GOOS))
|
||||
assert.Check(t, is.Equal(hdr.Get("API-Version"), api.DefaultVersion))
|
||||
assert.Check(t, is.Equal(hdr.Get("API-Version"), defaultVersion))
|
||||
assert.Check(t, is.Equal(hdr.Get("OSType"), runtime.GOOS))
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ type Backend interface {
|
|||
|
||||
// Prune build cache
|
||||
PruneCache(context.Context, types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error)
|
||||
|
||||
Cancel(context.Context, string) error
|
||||
}
|
||||
|
||||
|
|
|
@ -9,16 +9,18 @@ import (
|
|||
|
||||
// buildRouter is a router to talk with the build controller
|
||||
type buildRouter struct {
|
||||
backend Backend
|
||||
daemon experimentalProvider
|
||||
routes []router.Route
|
||||
backend Backend
|
||||
daemon experimentalProvider
|
||||
routes []router.Route
|
||||
features *map[string]bool
|
||||
}
|
||||
|
||||
// NewRouter initializes a new build router
|
||||
func NewRouter(b Backend, d experimentalProvider) router.Router {
|
||||
func NewRouter(b Backend, d experimentalProvider, features *map[string]bool) router.Router {
|
||||
r := &buildRouter{
|
||||
backend: b,
|
||||
daemon: d,
|
||||
backend: b,
|
||||
daemon: d,
|
||||
features: features,
|
||||
}
|
||||
r.initRoutes()
|
||||
return r
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
|
@ -27,6 +26,7 @@ import (
|
|||
"github.com/docker/docker/pkg/streamformatter"
|
||||
units "github.com/docker/go-units"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type invalidParam struct {
|
||||
|
@ -42,7 +42,6 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
|
|||
SuppressOutput: httputils.BoolValue(r, "q"),
|
||||
NoCache: httputils.BoolValue(r, "nocache"),
|
||||
ForceRemove: httputils.BoolValue(r, "forcerm"),
|
||||
PullParent: httputils.BoolValue(r, "pull"),
|
||||
MemorySwap: httputils.Int64ValueOrZero(r, "memswap"),
|
||||
Memory: httputils.Int64ValueOrZero(r, "memory"),
|
||||
CPUShares: httputils.Int64ValueOrZero(r, "cpushares"),
|
||||
|
@ -67,14 +66,17 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
|
|||
return nil, invalidParam{errors.New("security options are not supported on " + runtime.GOOS)}
|
||||
}
|
||||
|
||||
if httputils.BoolValue(r, "forcerm") {
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if httputils.BoolValue(r, "forcerm") && versions.GreaterThanOrEqualTo(version, "1.12") {
|
||||
options.Remove = true
|
||||
} else if r.FormValue("rm") == "" {
|
||||
} else if r.FormValue("rm") == "" && versions.GreaterThanOrEqualTo(version, "1.12") {
|
||||
options.Remove = true
|
||||
} else {
|
||||
options.Remove = httputils.BoolValue(r, "rm")
|
||||
}
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if httputils.BoolValue(r, "pull") && versions.GreaterThanOrEqualTo(version, "1.16") {
|
||||
options.PullParent = true
|
||||
}
|
||||
if versions.GreaterThanOrEqualTo(version, "1.32") {
|
||||
options.Platform = r.FormValue("platform")
|
||||
}
|
||||
|
@ -105,7 +107,7 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
|
|||
}
|
||||
|
||||
if ulimitsJSON := r.FormValue("ulimits"); ulimitsJSON != "" {
|
||||
buildUlimits := []*units.Ulimit{}
|
||||
var buildUlimits = []*units.Ulimit{}
|
||||
if err := json.Unmarshal([]byte(ulimitsJSON), &buildUlimits); err != nil {
|
||||
return nil, invalidParam{errors.Wrap(err, "error reading ulimit settings")}
|
||||
}
|
||||
|
@ -125,7 +127,7 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
|
|||
// so that it can print a warning about "foo" being unused if there is
|
||||
// no "ARG foo" in the Dockerfile.
|
||||
if buildArgsJSON := r.FormValue("buildargs"); buildArgsJSON != "" {
|
||||
buildArgs := map[string]*string{}
|
||||
var buildArgs = map[string]*string{}
|
||||
if err := json.Unmarshal([]byte(buildArgsJSON), &buildArgs); err != nil {
|
||||
return nil, invalidParam{errors.Wrap(err, "error reading build args")}
|
||||
}
|
||||
|
@ -133,7 +135,7 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
|
|||
}
|
||||
|
||||
if labelsJSON := r.FormValue("labels"); labelsJSON != "" {
|
||||
labels := map[string]string{}
|
||||
var labels = map[string]string{}
|
||||
if err := json.Unmarshal([]byte(labelsJSON), &labels); err != nil {
|
||||
return nil, invalidParam{errors.Wrap(err, "error reading labels")}
|
||||
}
|
||||
|
@ -141,7 +143,7 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
|
|||
}
|
||||
|
||||
if cacheFromJSON := r.FormValue("cachefrom"); cacheFromJSON != "" {
|
||||
cacheFrom := []string{}
|
||||
var cacheFrom = []string{}
|
||||
if err := json.Unmarshal([]byte(cacheFromJSON), &cacheFrom); err != nil {
|
||||
return nil, invalidParam{errors.Wrap(err, "error reading cache-from")}
|
||||
}
|
||||
|
@ -246,7 +248,7 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
|
|||
}
|
||||
_, err = output.Write(streamformatter.FormatError(err))
|
||||
if err != nil {
|
||||
log.G(ctx).Warnf("could not write error response: %v", err)
|
||||
logrus.Warnf("could not write error response: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package checkpoint // import "github.com/docker/docker/api/server/router/checkpoint"
|
||||
|
||||
import "github.com/docker/docker/api/types/checkpoint"
|
||||
import "github.com/docker/docker/api/types"
|
||||
|
||||
// Backend for Checkpoint
|
||||
type Backend interface {
|
||||
CheckpointCreate(container string, config checkpoint.CreateOptions) error
|
||||
CheckpointDelete(container string, config checkpoint.DeleteOptions) error
|
||||
CheckpointList(container string, config checkpoint.ListOptions) ([]checkpoint.Summary, error)
|
||||
CheckpointCreate(container string, config types.CheckpointCreateOptions) error
|
||||
CheckpointDelete(container string, config types.CheckpointDeleteOptions) error
|
||||
CheckpointList(container string, config types.CheckpointListOptions) ([]types.Checkpoint, error)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types/checkpoint"
|
||||
"github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
func (s *checkpointRouter) postContainerCheckpoint(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
|
@ -13,7 +13,7 @@ func (s *checkpointRouter) postContainerCheckpoint(ctx context.Context, w http.R
|
|||
return err
|
||||
}
|
||||
|
||||
var options checkpoint.CreateOptions
|
||||
var options types.CheckpointCreateOptions
|
||||
if err := httputils.ReadJSON(r, &options); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -32,9 +32,10 @@ func (s *checkpointRouter) getContainerCheckpoints(ctx context.Context, w http.R
|
|||
return err
|
||||
}
|
||||
|
||||
checkpoints, err := s.backend.CheckpointList(vars["name"], checkpoint.ListOptions{
|
||||
checkpoints, err := s.backend.CheckpointList(vars["name"], types.CheckpointListOptions{
|
||||
CheckpointDir: r.Form.Get("dir"),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -47,10 +48,11 @@ func (s *checkpointRouter) deleteContainerCheckpoint(ctx context.Context, w http
|
|||
return err
|
||||
}
|
||||
|
||||
err := s.backend.CheckpointDelete(vars["name"], checkpoint.DeleteOptions{
|
||||
err := s.backend.CheckpointDelete(vars["name"], types.CheckpointDeleteOptions{
|
||||
CheckpointDir: r.Form.Get("dir"),
|
||||
CheckpointID: vars["checkpoint"],
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ type execBackend interface {
|
|||
// copyBackend includes functions to implement to provide container copy functionality.
|
||||
type copyBackend interface {
|
||||
ContainerArchivePath(name string, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error)
|
||||
ContainerCopy(name string, res string) (io.ReadCloser, error)
|
||||
ContainerExport(ctx context.Context, name string, out io.Writer) error
|
||||
ContainerExtractToDir(name, path string, copyUIDGID, noOverwriteDirNonDir bool, content io.Reader) error
|
||||
ContainerStatPath(name string, path string) (stat *types.ContainerPathStat, err error)
|
||||
|
@ -31,14 +32,14 @@ type copyBackend interface {
|
|||
|
||||
// stateBackend includes functions to implement to provide container state lifecycle functionality.
|
||||
type stateBackend interface {
|
||||
ContainerCreate(ctx context.Context, config backend.ContainerCreateConfig) (container.CreateResponse, error)
|
||||
ContainerCreate(ctx context.Context, config types.ContainerCreateConfig) (container.CreateResponse, error)
|
||||
ContainerKill(name string, signal string) error
|
||||
ContainerPause(name string) error
|
||||
ContainerRename(oldName, newName string) error
|
||||
ContainerResize(name string, height, width int) error
|
||||
ContainerRestart(ctx context.Context, name string, options container.StopOptions) error
|
||||
ContainerRm(name string, config *backend.ContainerRmConfig) error
|
||||
ContainerStart(ctx context.Context, name string, checkpoint string, checkpointDir string) error
|
||||
ContainerRm(name string, config *types.ContainerRmConfig) error
|
||||
ContainerStart(ctx context.Context, name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
|
||||
ContainerStop(ctx context.Context, name string, options container.StopOptions) error
|
||||
ContainerUnpause(name string) error
|
||||
ContainerUpdate(name string, hostConfig *container.HostConfig) (container.ContainerUpdateOKBody, error)
|
||||
|
@ -49,10 +50,11 @@ type stateBackend interface {
|
|||
type monitorBackend interface {
|
||||
ContainerChanges(ctx context.Context, name string) ([]archive.Change, error)
|
||||
ContainerInspect(ctx context.Context, name string, size bool, version string) (interface{}, error)
|
||||
ContainerLogs(ctx context.Context, name string, config *container.LogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
|
||||
ContainerLogs(ctx context.Context, name string, config *types.ContainerLogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
|
||||
ContainerStats(ctx context.Context, name string, config *backend.ContainerStatsConfig) error
|
||||
ContainerTop(name string, psArgs string) (*container.ContainerTopOKBody, error)
|
||||
Containers(ctx context.Context, config *container.ListOptions) ([]*types.Container, error)
|
||||
|
||||
Containers(ctx context.Context, config *types.ContainerListOptions) ([]*types.Container, error)
|
||||
}
|
||||
|
||||
// attachBackend includes function to implement to provide container attaching functionality.
|
||||
|
|
|
@ -56,6 +56,7 @@ func (r *containerRouter) initRoutes() {
|
|||
router.NewPostRoute("/containers/{name:.*}/wait", r.postContainersWait),
|
||||
router.NewPostRoute("/containers/{name:.*}/resize", r.postContainersResize),
|
||||
router.NewPostRoute("/containers/{name:.*}/attach", r.postContainersAttach),
|
||||
router.NewPostRoute("/containers/{name:.*}/copy", r.postContainersCopy), // Deprecated since 1.8 (API v1.20), errors out since 1.12 (API v1.24)
|
||||
router.NewPostRoute("/containers/{name:.*}/exec", r.postContainerExecCreate),
|
||||
router.NewPostRoute("/exec/{name:.*}/start", r.postContainerExecStart),
|
||||
router.NewPostRoute("/exec/{name:.*}/resize", r.postContainerExecResize),
|
||||
|
|
|
@ -8,10 +8,8 @@ import (
|
|||
"net/http"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/httpstatus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
|
@ -19,14 +17,13 @@ import (
|
|||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
containerpkg "github.com/docker/docker/container"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/runconfig"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/websocket"
|
||||
)
|
||||
|
||||
|
@ -39,8 +36,15 @@ func (s *containerRouter) postCommit(ctx context.Context, w http.ResponseWriter,
|
|||
return err
|
||||
}
|
||||
|
||||
// TODO: remove pause arg, and always pause in backend
|
||||
pause := httputils.BoolValue(r, "pause")
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if r.FormValue("pause") == "" && versions.GreaterThanOrEqualTo(version, "1.13") {
|
||||
pause = true
|
||||
}
|
||||
|
||||
config, _, _, err := s.decoder.DecodeConfig(r.Body)
|
||||
if err != nil && !errors.Is(err, io.EOF) { // Do not fail if body is empty.
|
||||
if err != nil && err != io.EOF { // Do not fail if body is empty.
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -50,7 +54,7 @@ func (s *containerRouter) postCommit(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
|
||||
imgID, err := s.backend.CreateImageFromContainer(ctx, r.Form.Get("container"), &backend.CreateImageConfig{
|
||||
Pause: httputils.BoolValueOrDefault(r, "pause", true), // TODO(dnephin): remove pause arg, and always pause in backend
|
||||
Pause: pause,
|
||||
Tag: ref,
|
||||
Author: r.Form.Get("author"),
|
||||
Comment: r.Form.Get("comment"),
|
||||
|
@ -73,7 +77,7 @@ func (s *containerRouter) getContainersJSON(ctx context.Context, w http.Response
|
|||
return err
|
||||
}
|
||||
|
||||
config := &container.ListOptions{
|
||||
config := &types.ContainerListOptions{
|
||||
All: httputils.BoolValue(r, "all"),
|
||||
Size: httputils.BoolValue(r, "size"),
|
||||
Since: r.Form.Get("since"),
|
||||
|
@ -111,11 +115,14 @@ func (s *containerRouter) getContainersStats(ctx context.Context, w http.Respons
|
|||
oneShot = httputils.BoolValueOrDefault(r, "one-shot", false)
|
||||
}
|
||||
|
||||
return s.backend.ContainerStats(ctx, vars["name"], &backend.ContainerStatsConfig{
|
||||
config := &backend.ContainerStatsConfig{
|
||||
Stream: stream,
|
||||
OneShot: oneShot,
|
||||
OutStream: w,
|
||||
})
|
||||
Version: httputils.VersionFromContext(ctx),
|
||||
}
|
||||
|
||||
return s.backend.ContainerStats(ctx, vars["name"], config)
|
||||
}
|
||||
|
||||
func (s *containerRouter) getContainersLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
|
@ -134,7 +141,7 @@ func (s *containerRouter) getContainersLogs(ctx context.Context, w http.Response
|
|||
}
|
||||
|
||||
containerName := vars["name"]
|
||||
logsConfig := &container.LogsOptions{
|
||||
logsConfig := &types.ContainerLogsOptions{
|
||||
Follow: httputils.BoolValue(r, "follow"),
|
||||
Timestamps: httputils.BoolValue(r, "timestamps"),
|
||||
Since: r.Form.Get("since"),
|
||||
|
@ -168,6 +175,14 @@ func (s *containerRouter) getContainersExport(ctx context.Context, w http.Respon
|
|||
return s.backend.ContainerExport(ctx, vars["name"], w)
|
||||
}
|
||||
|
||||
type bodyOnStartError struct{}
|
||||
|
||||
func (bodyOnStartError) Error() string {
|
||||
return "starting container with non-empty request body was deprecated since API v1.22 and removed in v1.24"
|
||||
}
|
||||
|
||||
func (bodyOnStartError) InvalidParameter() {}
|
||||
|
||||
func (s *containerRouter) postContainersStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
// If contentLength is -1, we can assumed chunked encoding
|
||||
// or more technically that the length is unknown
|
||||
|
@ -175,17 +190,33 @@ func (s *containerRouter) postContainersStart(ctx context.Context, w http.Respon
|
|||
// net/http otherwise seems to swallow any headers related to chunked encoding
|
||||
// including r.TransferEncoding
|
||||
// allow a nil body for backwards compatibility
|
||||
//
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
var hostConfig *container.HostConfig
|
||||
// A non-nil json object is at least 7 characters.
|
||||
if r.ContentLength > 7 || r.ContentLength == -1 {
|
||||
return errdefs.InvalidParameter(errors.New("starting container with non-empty request body was deprecated since API v1.22 and removed in v1.24"))
|
||||
if versions.GreaterThanOrEqualTo(version, "1.24") {
|
||||
return bodyOnStartError{}
|
||||
}
|
||||
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c, err := s.decoder.DecodeHostConfig(r.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hostConfig = c
|
||||
}
|
||||
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.backend.ContainerStart(ctx, vars["name"], r.Form.Get("checkpoint"), r.Form.Get("checkpoint-dir")); err != nil {
|
||||
checkpoint := r.Form.Get("checkpoint")
|
||||
checkpointDir := r.Form.Get("checkpoint-dir")
|
||||
if err := s.backend.ContainerStart(ctx, vars["name"], hostConfig, checkpoint, checkpointDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -221,14 +252,25 @@ func (s *containerRouter) postContainersStop(ctx context.Context, w http.Respons
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *containerRouter) postContainersKill(_ context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *containerRouter) postContainersKill(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := vars["name"]
|
||||
if err := s.backend.ContainerKill(name, r.Form.Get("signal")); err != nil {
|
||||
return errors.Wrapf(err, "cannot kill container: %s", name)
|
||||
var isStopped bool
|
||||
if errdefs.IsConflict(err) {
|
||||
isStopped = true
|
||||
}
|
||||
|
||||
// Return error that's not caused because the container is stopped.
|
||||
// Return error if the container is not running and the api is >= 1.20
|
||||
// to keep backwards compatibility.
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.GreaterThanOrEqualTo(version, "1.20") || !isStopped {
|
||||
return errors.Wrapf(err, "Cannot kill container: %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
|
@ -444,55 +486,23 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
|
|||
|
||||
config, hostConfig, networkingConfig, err := s.decoder.DecodeConfig(r.Body)
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
return errdefs.InvalidParameter(errors.New("invalid JSON: got EOF while reading request body"))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if config == nil {
|
||||
return errdefs.InvalidParameter(runconfig.ErrEmptyConfig)
|
||||
}
|
||||
if hostConfig == nil {
|
||||
hostConfig = &container.HostConfig{}
|
||||
}
|
||||
if networkingConfig == nil {
|
||||
networkingConfig = &network.NetworkingConfig{}
|
||||
}
|
||||
if networkingConfig.EndpointsConfig == nil {
|
||||
networkingConfig.EndpointsConfig = make(map[string]*network.EndpointSettings)
|
||||
}
|
||||
// The NetworkMode "default" is used as a way to express a container should
|
||||
// be attached to the OS-dependant default network, in an OS-independent
|
||||
// way. Doing this conversion as soon as possible ensures we have less
|
||||
// NetworkMode to handle down the path (including in the
|
||||
// backward-compatibility layer we have just below).
|
||||
//
|
||||
// Note that this is not the only place where this conversion has to be
|
||||
// done (as there are various other places where containers get created).
|
||||
if hostConfig.NetworkMode == "" || hostConfig.NetworkMode.IsDefault() {
|
||||
hostConfig.NetworkMode = runconfig.DefaultDaemonNetworkMode()
|
||||
if nw, ok := networkingConfig.EndpointsConfig[network.NetworkDefault]; ok {
|
||||
networkingConfig.EndpointsConfig[hostConfig.NetworkMode.NetworkName()] = nw
|
||||
delete(networkingConfig.EndpointsConfig, network.NetworkDefault)
|
||||
}
|
||||
}
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
adjustCPUShares := versions.LessThan(version, "1.19")
|
||||
|
||||
// When using API 1.24 and under, the client is responsible for removing the container
|
||||
if versions.LessThan(version, "1.25") {
|
||||
if hostConfig != nil && versions.LessThan(version, "1.25") {
|
||||
hostConfig.AutoRemove = false
|
||||
}
|
||||
|
||||
if versions.LessThan(version, "1.40") {
|
||||
if hostConfig != nil && versions.LessThan(version, "1.40") {
|
||||
// Ignore BindOptions.NonRecursive because it was added in API 1.40.
|
||||
for _, m := range hostConfig.Mounts {
|
||||
if bo := m.BindOptions; bo != nil {
|
||||
bo.NonRecursive = false
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore KernelMemoryTCP because it was added in API 1.40.
|
||||
hostConfig.KernelMemoryTCP = 0
|
||||
|
||||
|
@ -501,26 +511,14 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
|
|||
hostConfig.IpcMode = container.IPCModeShareable
|
||||
}
|
||||
}
|
||||
|
||||
if versions.LessThan(version, "1.41") {
|
||||
if hostConfig != nil && versions.LessThan(version, "1.41") && !s.cgroup2 {
|
||||
// Older clients expect the default to be "host" on cgroup v1 hosts
|
||||
if !s.cgroup2 && hostConfig.CgroupnsMode.IsEmpty() {
|
||||
if hostConfig.CgroupnsMode.IsEmpty() {
|
||||
hostConfig.CgroupnsMode = container.CgroupnsModeHost
|
||||
}
|
||||
}
|
||||
|
||||
var platform *ocispec.Platform
|
||||
if versions.GreaterThanOrEqualTo(version, "1.41") {
|
||||
if v := r.Form.Get("platform"); v != "" {
|
||||
p, err := platforms.Parse(v)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
platform = &p
|
||||
}
|
||||
}
|
||||
|
||||
if versions.LessThan(version, "1.42") {
|
||||
if hostConfig != nil && versions.LessThan(version, "1.42") {
|
||||
for _, m := range hostConfig.Mounts {
|
||||
// Ignore BindOptions.CreateMountpoint because it was added in API 1.42.
|
||||
if bo := m.BindOptions; bo != nil {
|
||||
|
@ -540,14 +538,9 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
|
|||
bo.CreateMountpoint = false
|
||||
}
|
||||
}
|
||||
|
||||
if runtime.GOOS == "linux" {
|
||||
// ConsoleSize is not respected by Linux daemon before API 1.42
|
||||
hostConfig.ConsoleSize = [2]uint{0, 0}
|
||||
}
|
||||
}
|
||||
|
||||
if versions.GreaterThanOrEqualTo(version, "1.42") {
|
||||
if hostConfig != nil && versions.GreaterThanOrEqualTo(version, "1.42") {
|
||||
// Ignore KernelMemory removed in API 1.42.
|
||||
hostConfig.KernelMemory = 0
|
||||
for _, m := range hostConfig.Mounts {
|
||||
|
@ -563,63 +556,28 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
|
|||
}
|
||||
}
|
||||
|
||||
if versions.LessThan(version, "1.43") {
|
||||
if hostConfig != nil && runtime.GOOS == "linux" && versions.LessThan(version, "1.42") {
|
||||
// ConsoleSize is not respected by Linux daemon before API 1.42
|
||||
hostConfig.ConsoleSize = [2]uint{0, 0}
|
||||
}
|
||||
|
||||
if hostConfig != nil && versions.LessThan(version, "1.43") {
|
||||
// Ignore Annotations because it was added in API v1.43.
|
||||
hostConfig.Annotations = nil
|
||||
}
|
||||
|
||||
defaultReadOnlyNonRecursive := false
|
||||
if versions.LessThan(version, "1.44") {
|
||||
if config.Healthcheck != nil {
|
||||
// StartInterval was added in API 1.44
|
||||
config.Healthcheck.StartInterval = 0
|
||||
}
|
||||
|
||||
// Set ReadOnlyNonRecursive to true because it was added in API 1.44
|
||||
// Before that all read-only mounts were non-recursive.
|
||||
// Keep that behavior for clients on older APIs.
|
||||
defaultReadOnlyNonRecursive = true
|
||||
|
||||
for _, m := range hostConfig.Mounts {
|
||||
if m.Type == mount.TypeBind {
|
||||
if m.BindOptions != nil && m.BindOptions.ReadOnlyForceRecursive {
|
||||
// NOTE: that technically this is a breaking change for older
|
||||
// API versions, and we should ignore the new field.
|
||||
// However, this option may be incorrectly set by a client with
|
||||
// the expectation that the failing to apply recursive read-only
|
||||
// is enforced, so we decided to produce an error instead,
|
||||
// instead of silently ignoring.
|
||||
return errdefs.InvalidParameter(errors.New("BindOptions.ReadOnlyForceRecursive needs API v1.44 or newer"))
|
||||
}
|
||||
var platform *specs.Platform
|
||||
if versions.GreaterThanOrEqualTo(version, "1.41") {
|
||||
if v := r.Form.Get("platform"); v != "" {
|
||||
p, err := platforms.Parse(v)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Creating a container connected to several networks is not supported until v1.44.
|
||||
if len(networkingConfig.EndpointsConfig) > 1 {
|
||||
l := make([]string, 0, len(networkingConfig.EndpointsConfig))
|
||||
for k := range networkingConfig.EndpointsConfig {
|
||||
l = append(l, k)
|
||||
}
|
||||
return errdefs.InvalidParameter(errors.Errorf("Container cannot be created with multiple network endpoints: %s", strings.Join(l, ", ")))
|
||||
platform = &p
|
||||
}
|
||||
}
|
||||
|
||||
if versions.LessThan(version, "1.45") {
|
||||
for _, m := range hostConfig.Mounts {
|
||||
if m.VolumeOptions != nil && m.VolumeOptions.Subpath != "" {
|
||||
return errdefs.InvalidParameter(errors.New("VolumeOptions.Subpath needs API v1.45 or newer"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var warnings []string
|
||||
if warn, err := handleMACAddressBC(config, hostConfig, networkingConfig, version); err != nil {
|
||||
return err
|
||||
} else if warn != "" {
|
||||
warnings = append(warnings, warn)
|
||||
}
|
||||
|
||||
if hostConfig.PidsLimit != nil && *hostConfig.PidsLimit <= 0 {
|
||||
if hostConfig != nil && hostConfig.PidsLimit != nil && *hostConfig.PidsLimit <= 0 {
|
||||
// Don't set a limit if either no limit was specified, or "unlimited" was
|
||||
// explicitly set.
|
||||
// Both `0` and `-1` are accepted as "unlimited", and historically any
|
||||
|
@ -627,107 +585,28 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
|
|||
hostConfig.PidsLimit = nil
|
||||
}
|
||||
|
||||
ccr, err := s.backend.ContainerCreate(ctx, backend.ContainerCreateConfig{
|
||||
Name: name,
|
||||
Config: config,
|
||||
HostConfig: hostConfig,
|
||||
NetworkingConfig: networkingConfig,
|
||||
Platform: platform,
|
||||
DefaultReadOnlyNonRecursive: defaultReadOnlyNonRecursive,
|
||||
ccr, err := s.backend.ContainerCreate(ctx, types.ContainerCreateConfig{
|
||||
Name: name,
|
||||
Config: config,
|
||||
HostConfig: hostConfig,
|
||||
NetworkingConfig: networkingConfig,
|
||||
AdjustCPUShares: adjustCPUShares,
|
||||
Platform: platform,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ccr.Warnings = append(ccr.Warnings, warnings...)
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusCreated, ccr)
|
||||
}
|
||||
|
||||
// handleMACAddressBC takes care of backward-compatibility for the container-wide MAC address by mutating the
|
||||
// networkingConfig to set the endpoint-specific MACAddress field introduced in API v1.44. It returns a warning message
|
||||
// or an error if the container-wide field was specified for API >= v1.44.
|
||||
func handleMACAddressBC(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, version string) (string, error) {
|
||||
deprecatedMacAddress := config.MacAddress //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
|
||||
|
||||
// For older versions of the API, migrate the container-wide MAC address to EndpointsConfig.
|
||||
if versions.LessThan(version, "1.44") {
|
||||
if deprecatedMacAddress == "" {
|
||||
// If a MAC address is supplied in EndpointsConfig, discard it because the old API
|
||||
// would have ignored it.
|
||||
for _, ep := range networkingConfig.EndpointsConfig {
|
||||
ep.MacAddress = ""
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
if !hostConfig.NetworkMode.IsBridge() && !hostConfig.NetworkMode.IsUserDefined() {
|
||||
return "", runconfig.ErrConflictContainerNetworkAndMac
|
||||
}
|
||||
|
||||
// There cannot be more than one entry in EndpointsConfig with API < 1.44.
|
||||
|
||||
// If there's no EndpointsConfig, create a place to store the configured address. It is
|
||||
// safe to use NetworkMode as the network name, whether it's a name or id/short-id, as
|
||||
// it will be normalised later and there is no other EndpointSettings object that might
|
||||
// refer to this network/endpoint.
|
||||
if len(networkingConfig.EndpointsConfig) == 0 {
|
||||
nwName := hostConfig.NetworkMode.NetworkName()
|
||||
networkingConfig.EndpointsConfig[nwName] = &network.EndpointSettings{}
|
||||
}
|
||||
// There's exactly one network in EndpointsConfig, either from the API or just-created.
|
||||
// Migrate the container-wide setting to it.
|
||||
// No need to check for a match between NetworkMode and the names/ids in EndpointsConfig,
|
||||
// the old version of the API would have applied the address to this network anyway.
|
||||
for _, ep := range networkingConfig.EndpointsConfig {
|
||||
ep.MacAddress = deprecatedMacAddress
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// The container-wide MacAddress parameter is deprecated and should now be specified in EndpointsConfig.
|
||||
if deprecatedMacAddress == "" {
|
||||
return "", nil
|
||||
}
|
||||
var warning string
|
||||
if hostConfig.NetworkMode.IsBridge() || hostConfig.NetworkMode.IsUserDefined() {
|
||||
nwName := hostConfig.NetworkMode.NetworkName()
|
||||
// If there's no endpoint config, create a place to store the configured address.
|
||||
if len(networkingConfig.EndpointsConfig) == 0 {
|
||||
networkingConfig.EndpointsConfig[nwName] = &network.EndpointSettings{
|
||||
MacAddress: deprecatedMacAddress,
|
||||
}
|
||||
} else {
|
||||
// There is existing endpoint config - if it's not indexed by NetworkMode.Name(), we
|
||||
// can't tell which network the container-wide settings was intended for. NetworkMode,
|
||||
// the keys in EndpointsConfig and the NetworkID in EndpointsConfig may mix network
|
||||
// name/id/short-id. It's not safe to create EndpointsConfig under the NetworkMode
|
||||
// name to store the container-wide MAC address, because that may result in two sets
|
||||
// of EndpointsConfig for the same network and one set will be discarded later. So,
|
||||
// reject the request ...
|
||||
ep, ok := networkingConfig.EndpointsConfig[nwName]
|
||||
if !ok {
|
||||
return "", errdefs.InvalidParameter(errors.New("if a container-wide MAC address is supplied, HostConfig.NetworkMode must match the identity of a network in NetworkSettings.Networks"))
|
||||
}
|
||||
// ep is the endpoint that needs the container-wide MAC address; migrate the address
|
||||
// to it, or bail out if there's a mismatch.
|
||||
if ep.MacAddress == "" {
|
||||
ep.MacAddress = deprecatedMacAddress
|
||||
} else if ep.MacAddress != deprecatedMacAddress {
|
||||
return "", errdefs.InvalidParameter(errors.New("the container-wide MAC address must match the endpoint-specific MAC address for the main network, or be left empty"))
|
||||
}
|
||||
}
|
||||
}
|
||||
warning = "The container-wide MacAddress field is now deprecated. It should be specified in EndpointsConfig instead."
|
||||
config.MacAddress = "" //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
|
||||
|
||||
return warning, nil
|
||||
}
|
||||
|
||||
func (s *containerRouter) deleteContainers(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := vars["name"]
|
||||
config := &backend.ContainerRmConfig{
|
||||
config := &types.ContainerRmConfig{
|
||||
ForceRemove: httputils.BoolValue(r, "force"),
|
||||
RemoveVolume: httputils.BoolValue(r, "v"),
|
||||
RemoveLink: httputils.BoolValue(r, "link"),
|
||||
|
@ -812,11 +691,11 @@ func (s *containerRouter) postContainersAttach(ctx context.Context, w http.Respo
|
|||
}
|
||||
|
||||
if err = s.backend.ContainerAttach(containerName, attachConfig); err != nil {
|
||||
log.G(ctx).WithError(err).Errorf("Handler for %s %s returned error", r.Method, r.URL.Path)
|
||||
logrus.WithError(err).Errorf("Handler for %s %s returned error", r.Method, r.URL.Path)
|
||||
// Remember to close stream if error happens
|
||||
conn, _, errHijack := hijacker.Hijack()
|
||||
if errHijack != nil {
|
||||
log.G(ctx).WithError(err).Errorf("Handler for %s %s: unable to close stream; error when hijacking connection", r.Method, r.URL.Path)
|
||||
logrus.WithError(err).Errorf("Handler for %s %s: unable to close stream; error when hijacking connection", r.Method, r.URL.Path)
|
||||
} else {
|
||||
statusCode := httpstatus.FromError(err)
|
||||
statusText := http.StatusText(statusCode)
|
||||
|
@ -886,9 +765,9 @@ func (s *containerRouter) wsContainersAttach(ctx context.Context, w http.Respons
|
|||
select {
|
||||
case <-started:
|
||||
if err != nil {
|
||||
log.G(ctx).Errorf("Error attaching websocket: %s", err)
|
||||
logrus.Errorf("Error attaching websocket: %s", err)
|
||||
} else {
|
||||
log.G(ctx).Debug("websocket connection was closed by client")
|
||||
logrus.Debug("websocket connection was closed by client")
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
|
|
|
@ -1,160 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestHandleMACAddressBC(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
apiVersion string
|
||||
ctrWideMAC string
|
||||
networkMode container.NetworkMode
|
||||
epConfig map[string]*network.EndpointSettings
|
||||
expEpWithCtrWideMAC string
|
||||
expEpWithNoMAC string
|
||||
expCtrWideMAC string
|
||||
expWarning string
|
||||
expError string
|
||||
}{
|
||||
{
|
||||
name: "old api ctr-wide mac mix id and name",
|
||||
apiVersion: "1.43",
|
||||
ctrWideMAC: "11:22:33:44:55:66",
|
||||
networkMode: "aNetId",
|
||||
epConfig: map[string]*network.EndpointSettings{"aNetName": {}},
|
||||
expEpWithCtrWideMAC: "aNetName",
|
||||
expCtrWideMAC: "11:22:33:44:55:66",
|
||||
},
|
||||
{
|
||||
name: "old api clear ep mac",
|
||||
apiVersion: "1.43",
|
||||
networkMode: "aNetId",
|
||||
epConfig: map[string]*network.EndpointSettings{"aNetName": {MacAddress: "11:22:33:44:55:66"}},
|
||||
expEpWithNoMAC: "aNetName",
|
||||
},
|
||||
{
|
||||
name: "old api no-network ctr-wide mac",
|
||||
apiVersion: "1.43",
|
||||
networkMode: "none",
|
||||
ctrWideMAC: "11:22:33:44:55:66",
|
||||
expError: "conflicting options: mac-address and the network mode",
|
||||
expCtrWideMAC: "11:22:33:44:55:66",
|
||||
},
|
||||
{
|
||||
name: "old api create ep",
|
||||
apiVersion: "1.43",
|
||||
networkMode: "aNetId",
|
||||
ctrWideMAC: "11:22:33:44:55:66",
|
||||
epConfig: map[string]*network.EndpointSettings{},
|
||||
expEpWithCtrWideMAC: "aNetId",
|
||||
expCtrWideMAC: "11:22:33:44:55:66",
|
||||
},
|
||||
{
|
||||
name: "old api migrate ctr-wide mac",
|
||||
apiVersion: "1.43",
|
||||
ctrWideMAC: "11:22:33:44:55:66",
|
||||
networkMode: "aNetName",
|
||||
epConfig: map[string]*network.EndpointSettings{"aNetName": {}},
|
||||
expEpWithCtrWideMAC: "aNetName",
|
||||
expCtrWideMAC: "11:22:33:44:55:66",
|
||||
},
|
||||
{
|
||||
name: "new api no macs",
|
||||
apiVersion: "1.44",
|
||||
networkMode: "aNetId",
|
||||
epConfig: map[string]*network.EndpointSettings{"aNetName": {}},
|
||||
},
|
||||
{
|
||||
name: "new api ep specific mac",
|
||||
apiVersion: "1.44",
|
||||
networkMode: "aNetName",
|
||||
epConfig: map[string]*network.EndpointSettings{"aNetName": {MacAddress: "11:22:33:44:55:66"}},
|
||||
},
|
||||
{
|
||||
name: "new api migrate ctr-wide mac to new ep",
|
||||
apiVersion: "1.44",
|
||||
ctrWideMAC: "11:22:33:44:55:66",
|
||||
networkMode: "aNetName",
|
||||
epConfig: map[string]*network.EndpointSettings{},
|
||||
expEpWithCtrWideMAC: "aNetName",
|
||||
expWarning: "The container-wide MacAddress field is now deprecated",
|
||||
expCtrWideMAC: "",
|
||||
},
|
||||
{
|
||||
name: "new api migrate ctr-wide mac to existing ep",
|
||||
apiVersion: "1.44",
|
||||
ctrWideMAC: "11:22:33:44:55:66",
|
||||
networkMode: "aNetName",
|
||||
epConfig: map[string]*network.EndpointSettings{"aNetName": {}},
|
||||
expEpWithCtrWideMAC: "aNetName",
|
||||
expWarning: "The container-wide MacAddress field is now deprecated",
|
||||
expCtrWideMAC: "",
|
||||
},
|
||||
{
|
||||
name: "new api mode vs name mismatch",
|
||||
apiVersion: "1.44",
|
||||
ctrWideMAC: "11:22:33:44:55:66",
|
||||
networkMode: "aNetId",
|
||||
epConfig: map[string]*network.EndpointSettings{"aNetName": {}},
|
||||
expError: "if a container-wide MAC address is supplied, HostConfig.NetworkMode must match the identity of a network in NetworkSettings.Networks",
|
||||
expCtrWideMAC: "11:22:33:44:55:66",
|
||||
},
|
||||
{
|
||||
name: "new api mac mismatch",
|
||||
apiVersion: "1.44",
|
||||
ctrWideMAC: "11:22:33:44:55:66",
|
||||
networkMode: "aNetName",
|
||||
epConfig: map[string]*network.EndpointSettings{"aNetName": {MacAddress: "00:11:22:33:44:55"}},
|
||||
expError: "the container-wide MAC address must match the endpoint-specific MAC address",
|
||||
expCtrWideMAC: "11:22:33:44:55:66",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cfg := &container.Config{
|
||||
MacAddress: tc.ctrWideMAC, //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
|
||||
}
|
||||
hostCfg := &container.HostConfig{
|
||||
NetworkMode: tc.networkMode,
|
||||
}
|
||||
epConfig := make(map[string]*network.EndpointSettings, len(tc.epConfig))
|
||||
for k, v := range tc.epConfig {
|
||||
v := v
|
||||
epConfig[k] = v
|
||||
}
|
||||
netCfg := &network.NetworkingConfig{
|
||||
EndpointsConfig: epConfig,
|
||||
}
|
||||
|
||||
warning, err := handleMACAddressBC(cfg, hostCfg, netCfg, tc.apiVersion)
|
||||
|
||||
if tc.expError == "" {
|
||||
assert.Check(t, err)
|
||||
} else {
|
||||
assert.Check(t, is.ErrorContains(err, tc.expError))
|
||||
}
|
||||
if tc.expWarning == "" {
|
||||
assert.Check(t, is.Equal(warning, ""))
|
||||
} else {
|
||||
assert.Check(t, is.Contains(warning, tc.expWarning))
|
||||
}
|
||||
if tc.expEpWithCtrWideMAC != "" {
|
||||
got := netCfg.EndpointsConfig[tc.expEpWithCtrWideMAC].MacAddress
|
||||
assert.Check(t, is.Equal(got, tc.ctrWideMAC))
|
||||
}
|
||||
if tc.expEpWithNoMAC != "" {
|
||||
got := netCfg.EndpointsConfig[tc.expEpWithNoMAC].MacAddress
|
||||
assert.Check(t, is.Equal(got, ""))
|
||||
}
|
||||
gotCtrWideMAC := cfg.MacAddress //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
|
||||
assert.Check(t, is.Equal(gotCtrWideMAC, tc.expCtrWideMAC))
|
||||
})
|
||||
}
|
||||
}
|
|
@ -11,10 +11,49 @@ import (
|
|||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
gddohttputil "github.com/golang/gddo/httputil"
|
||||
)
|
||||
|
||||
// setContainerPathStatHeader encodes the stat to JSON, base64 encode, and place in a header.
|
||||
type pathError struct{}
|
||||
|
||||
func (pathError) Error() string {
|
||||
return "Path cannot be empty"
|
||||
}
|
||||
|
||||
func (pathError) InvalidParameter() {}
|
||||
|
||||
// postContainersCopy is deprecated in favor of getContainersArchive.
|
||||
//
|
||||
// Deprecated since 1.8 (API v1.20), errors out since 1.12 (API v1.24)
|
||||
func (s *containerRouter) postContainersCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.GreaterThanOrEqualTo(version, "1.24") {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return nil
|
||||
}
|
||||
|
||||
cfg := types.CopyConfig{}
|
||||
if err := httputils.ReadJSON(r, &cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cfg.Resource == "" {
|
||||
return pathError{}
|
||||
}
|
||||
|
||||
data, err := s.backend.ContainerCopy(vars["name"], cfg.Resource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer data.Close()
|
||||
|
||||
w.Header().Set("Content-Type", "application/x-tar")
|
||||
_, err = io.Copy(w, data)
|
||||
return err
|
||||
}
|
||||
|
||||
// // Encode the stat to JSON, base64 encode, and place in a header.
|
||||
func setContainerPathStatHeader(stat *types.ContainerPathStat, header http.Header) error {
|
||||
statJSON, err := json.Marshal(stat)
|
||||
if err != nil {
|
||||
|
|
|
@ -7,13 +7,13 @@ import (
|
|||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (s *containerRouter) getExecByID(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
|
@ -56,7 +56,7 @@ func (s *containerRouter) postContainerExecCreate(ctx context.Context, w http.Re
|
|||
// Register an instance of Exec in container.
|
||||
id, err := s.backend.ContainerExecCreate(vars["name"], execConfig)
|
||||
if err != nil {
|
||||
log.G(ctx).Errorf("Error setting up exec command in container %s: %v", vars["name"], err)
|
||||
logrus.Errorf("Error setting up exec command in container %s: %v", vars["name"], err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -71,6 +71,15 @@ func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.Res
|
|||
return err
|
||||
}
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.LessThan(version, "1.22") {
|
||||
// API versions before 1.22 did not enforce application/json content-type.
|
||||
// Allow older clients to work by patching the content-type.
|
||||
if r.Header.Get("Content-Type") != "application/json" {
|
||||
r.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
execName = vars["name"]
|
||||
stdin, inStream io.ReadCloser
|
||||
|
@ -87,8 +96,6 @@ func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.Res
|
|||
}
|
||||
|
||||
if execStartCheck.ConsoleSize != nil {
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
|
||||
// Not supported before 1.42
|
||||
if versions.LessThan(version, "1.42") {
|
||||
execStartCheck.ConsoleSize = nil
|
||||
|
@ -147,7 +154,7 @@ func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.Res
|
|||
return err
|
||||
}
|
||||
stdout.Write([]byte(err.Error() + "\r\n"))
|
||||
log.G(ctx).Errorf("Error running exec %s in container: %v", execName, err)
|
||||
logrus.Errorf("Error running exec %s in container: %v", execName, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@ package distribution // import "github.com/docker/docker/api/server/router/distr
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
)
|
||||
|
||||
// Backend is all the methods that need to be implemented
|
||||
// to provide image specific functionality.
|
||||
type Backend interface {
|
||||
GetRepositories(context.Context, reference.Named, *registry.AuthConfig) ([]distribution.Repository, error)
|
||||
GetRepository(context.Context, reference.Named, *registry.AuthConfig) (distribution.Repository, error)
|
||||
}
|
||||
|
|
|
@ -4,18 +4,15 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/manifest/manifestlist"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
distributionpkg "github.com/docker/docker/distribution"
|
||||
"github.com/docker/docker/errdefs"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -26,10 +23,10 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res
|
|||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
imgName := vars["name"]
|
||||
image := vars["name"]
|
||||
|
||||
// TODO why is reference.ParseAnyReference() / reference.ParseNormalizedNamed() not using the reference.ErrTagInvalidFormat (and so on) errors?
|
||||
ref, err := reference.ParseAnyReference(imgName)
|
||||
ref, err := reference.ParseAnyReference(image)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
@ -39,58 +36,32 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res
|
|||
// full image ID
|
||||
return errors.Errorf("no manifest found for full image ID")
|
||||
}
|
||||
return errdefs.InvalidParameter(errors.Errorf("unknown image reference format: %s", imgName))
|
||||
return errdefs.InvalidParameter(errors.Errorf("unknown image reference format: %s", image))
|
||||
}
|
||||
|
||||
// For a search it is not an error if no auth was given. Ignore invalid
|
||||
// AuthConfig to increase compatibility with the existing API.
|
||||
authConfig, _ := registry.DecodeAuthConfig(r.Header.Get(registry.AuthHeader))
|
||||
repos, err := s.backend.GetRepositories(ctx, namedRef, authConfig)
|
||||
distrepo, err := s.backend.GetRepository(ctx, namedRef, authConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
blobsrvc := distrepo.Blobs(ctx)
|
||||
|
||||
// Fetch the manifest; if a mirror is configured, try the mirror first,
|
||||
// but continue with upstream on failure.
|
||||
//
|
||||
// FIXME(thaJeztah): construct "repositories" on-demand;
|
||||
// GetRepositories() will attempt to connect to all endpoints (registries),
|
||||
// but we may only need the first one if it contains the manifest we're
|
||||
// looking for, or if the configured mirror is a pull-through mirror.
|
||||
//
|
||||
// Logic for this could be implemented similar to "distribution.Pull()",
|
||||
// which uses the "pullEndpoints" utility to iterate over the list
|
||||
// of endpoints;
|
||||
//
|
||||
// - https://github.com/moby/moby/blob/12c7411b6b7314bef130cd59f1c7384a7db06d0b/distribution/pull.go#L17-L31
|
||||
// - https://github.com/moby/moby/blob/12c7411b6b7314bef130cd59f1c7384a7db06d0b/distribution/pull.go#L76-L152
|
||||
var lastErr error
|
||||
for _, repo := range repos {
|
||||
distributionInspect, err := s.fetchManifest(ctx, repo, namedRef)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, distributionInspect)
|
||||
}
|
||||
return lastErr
|
||||
}
|
||||
|
||||
func (s *distributionRouter) fetchManifest(ctx context.Context, distrepo distribution.Repository, namedRef reference.Named) (registry.DistributionInspect, error) {
|
||||
var distributionInspect registry.DistributionInspect
|
||||
if canonicalRef, ok := namedRef.(reference.Canonical); !ok {
|
||||
namedRef = reference.TagNameOnly(namedRef)
|
||||
|
||||
taggedRef, ok := namedRef.(reference.NamedTagged)
|
||||
if !ok {
|
||||
return registry.DistributionInspect{}, errdefs.InvalidParameter(errors.Errorf("image reference not tagged: %s", namedRef))
|
||||
return errdefs.InvalidParameter(errors.Errorf("image reference not tagged: %s", image))
|
||||
}
|
||||
|
||||
descriptor, err := distrepo.Tags(ctx).Get(ctx, taggedRef.Tag())
|
||||
if err != nil {
|
||||
return registry.DistributionInspect{}, err
|
||||
return err
|
||||
}
|
||||
distributionInspect.Descriptor = ocispec.Descriptor{
|
||||
distributionInspect.Descriptor = v1.Descriptor{
|
||||
MediaType: descriptor.MediaType,
|
||||
Digest: descriptor.Digest,
|
||||
Size: descriptor.Size,
|
||||
|
@ -105,7 +76,7 @@ func (s *distributionRouter) fetchManifest(ctx context.Context, distrepo distrib
|
|||
// we have a digest, so we can retrieve the manifest
|
||||
mnfstsrvc, err := distrepo.Manifests(ctx)
|
||||
if err != nil {
|
||||
return registry.DistributionInspect{}, err
|
||||
return err
|
||||
}
|
||||
mnfst, err := mnfstsrvc.Get(ctx, distributionInspect.Descriptor.Digest)
|
||||
if err != nil {
|
||||
|
@ -117,14 +88,14 @@ func (s *distributionRouter) fetchManifest(ctx context.Context, distrepo distrib
|
|||
reference.ErrNameEmpty,
|
||||
reference.ErrNameTooLong,
|
||||
reference.ErrNameNotCanonical:
|
||||
return registry.DistributionInspect{}, errdefs.InvalidParameter(err)
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
return registry.DistributionInspect{}, err
|
||||
return err
|
||||
}
|
||||
|
||||
mediaType, payload, err := mnfst.Payload()
|
||||
if err != nil {
|
||||
return registry.DistributionInspect{}, err
|
||||
return err
|
||||
}
|
||||
// update MediaType because registry might return something incorrect
|
||||
distributionInspect.Descriptor.MediaType = mediaType
|
||||
|
@ -136,7 +107,7 @@ func (s *distributionRouter) fetchManifest(ctx context.Context, distrepo distrib
|
|||
switch mnfstObj := mnfst.(type) {
|
||||
case *manifestlist.DeserializedManifestList:
|
||||
for _, m := range mnfstObj.Manifests {
|
||||
distributionInspect.Platforms = append(distributionInspect.Platforms, ocispec.Platform{
|
||||
distributionInspect.Platforms = append(distributionInspect.Platforms, v1.Platform{
|
||||
Architecture: m.Platform.Architecture,
|
||||
OS: m.Platform.OS,
|
||||
OSVersion: m.Platform.OSVersion,
|
||||
|
@ -145,9 +116,8 @@ func (s *distributionRouter) fetchManifest(ctx context.Context, distrepo distrib
|
|||
})
|
||||
}
|
||||
case *schema2.DeserializedManifest:
|
||||
blobStore := distrepo.Blobs(ctx)
|
||||
configJSON, err := blobStore.Get(ctx, mnfstObj.Config.Digest)
|
||||
var platform ocispec.Platform
|
||||
configJSON, err := blobsrvc.Get(ctx, mnfstObj.Config.Digest)
|
||||
var platform v1.Platform
|
||||
if err == nil {
|
||||
err := json.Unmarshal(configJSON, &platform)
|
||||
if err == nil && (platform.OS != "" || platform.Architecture != "") {
|
||||
|
@ -155,14 +125,12 @@ func (s *distributionRouter) fetchManifest(ctx context.Context, distrepo distrib
|
|||
}
|
||||
}
|
||||
case *schema1.SignedManifest:
|
||||
if os.Getenv("DOCKER_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE") == "" {
|
||||
return registry.DistributionInspect{}, distributionpkg.DeprecatedSchema1ImageError(namedRef)
|
||||
}
|
||||
platform := ocispec.Platform{
|
||||
platform := v1.Platform{
|
||||
Architecture: mnfstObj.Architecture,
|
||||
OS: "linux",
|
||||
}
|
||||
distributionInspect.Platforms = append(distributionInspect.Platforms, platform)
|
||||
}
|
||||
return distributionInspect, nil
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, distributionInspect)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
package grpc // import "github.com/docker/docker/api/server/router/grpc"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/server/router"
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
"github.com/moby/buildkit/util/grpcerrors"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
"golang.org/x/net/http2"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
@ -20,12 +15,12 @@ type grpcRouter struct {
|
|||
|
||||
// NewRouter initializes a new grpc http router
|
||||
func NewRouter(backends ...Backend) router.Router {
|
||||
unary := grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(unaryInterceptor(), grpcerrors.UnaryServerInterceptor))
|
||||
stream := grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(otelgrpc.StreamServerInterceptor(), grpcerrors.StreamServerInterceptor)) //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/moby/issues/47437
|
||||
|
||||
r := &grpcRouter{
|
||||
h2Server: &http2.Server{},
|
||||
grpcServer: grpc.NewServer(unary, stream),
|
||||
h2Server: &http2.Server{},
|
||||
grpcServer: grpc.NewServer(
|
||||
grpc.UnaryInterceptor(grpcerrors.UnaryServerInterceptor),
|
||||
grpc.StreamInterceptor(grpcerrors.StreamServerInterceptor),
|
||||
),
|
||||
}
|
||||
for _, b := range backends {
|
||||
b.RegisterGRPC(r.grpcServer)
|
||||
|
@ -44,17 +39,3 @@ func (gr *grpcRouter) initRoutes() {
|
|||
router.NewPostRoute("/grpc", gr.serveGRPC),
|
||||
}
|
||||
}
|
||||
|
||||
func unaryInterceptor() grpc.UnaryServerInterceptor {
|
||||
withTrace := otelgrpc.UnaryServerInterceptor() //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/moby/issues/47437
|
||||
|
||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
|
||||
// This method is used by the clients to send their traces to buildkit so they can be included
|
||||
// in the daemon trace and stored in the build history record. This method can not be traced because
|
||||
// it would cause an infinite loop.
|
||||
if strings.HasSuffix(info.FullMethod, "opentelemetry.proto.collector.trace.v1.TraceService/Export") {
|
||||
return handler(ctx, req)
|
||||
}
|
||||
return withTrace(ctx, req, info, handler)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,13 @@ import (
|
|||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
dockerimage "github.com/docker/docker/image"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// Backend is all the methods that need to be implemented
|
||||
|
@ -23,22 +22,22 @@ type Backend interface {
|
|||
}
|
||||
|
||||
type imageBackend interface {
|
||||
ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]image.DeleteResponse, error)
|
||||
ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error)
|
||||
ImageHistory(ctx context.Context, imageName string) ([]*image.HistoryResponseItem, error)
|
||||
Images(ctx context.Context, opts image.ListOptions) ([]*image.Summary, error)
|
||||
GetImage(ctx context.Context, refOrID string, options backend.GetImageOpts) (*dockerimage.Image, error)
|
||||
Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error)
|
||||
GetImage(ctx context.Context, refOrID string, options image.GetImageOpts) (*dockerimage.Image, error)
|
||||
TagImage(ctx context.Context, id dockerimage.ID, newRef reference.Named) error
|
||||
ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error)
|
||||
}
|
||||
|
||||
type importExportBackend interface {
|
||||
LoadImage(ctx context.Context, inTar io.ReadCloser, outStream io.Writer, quiet bool) error
|
||||
ImportImage(ctx context.Context, ref reference.Named, platform *ocispec.Platform, msg string, layerReader io.Reader, changes []string) (dockerimage.ID, error)
|
||||
ImportImage(ctx context.Context, ref reference.Named, platform *specs.Platform, msg string, layerReader io.Reader, changes []string) (dockerimage.ID, error)
|
||||
ExportImage(ctx context.Context, names []string, outStream io.Writer) error
|
||||
}
|
||||
|
||||
type registryBackend interface {
|
||||
PullImage(ctx context.Context, ref reference.Named, platform *ocispec.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
|
||||
PullImage(ctx context.Context, image, tag string, platform *specs.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
|
||||
PushImage(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package image // import "github.com/docker/docker/api/server/router/image"
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -11,13 +10,11 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
imagetypes "github.com/docker/docker/api/types/image"
|
||||
opts "github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/builder/remotecontext"
|
||||
|
@ -27,8 +24,7 @@ import (
|
|||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -45,7 +41,7 @@ func (ir *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrit
|
|||
comment = r.Form.Get("message")
|
||||
progressErr error
|
||||
output = ioutils.NewWriteFlusher(w)
|
||||
platform *ocispec.Platform
|
||||
platform *specs.Platform
|
||||
)
|
||||
defer output.Close()
|
||||
|
||||
|
@ -70,39 +66,10 @@ func (ir *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrit
|
|||
}
|
||||
}
|
||||
|
||||
// Special case: "pull -a" may send an image name with a
|
||||
// trailing :. This is ugly, but let's not break API
|
||||
// compatibility.
|
||||
imgName := strings.TrimSuffix(img, ":")
|
||||
|
||||
ref, err := reference.ParseNormalizedNamed(imgName)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
// TODO(thaJeztah) this could use a WithTagOrDigest() utility
|
||||
if tag != "" {
|
||||
// The "tag" could actually be a digest.
|
||||
var dgst digest.Digest
|
||||
dgst, err = digest.Parse(tag)
|
||||
if err == nil {
|
||||
ref, err = reference.WithDigest(reference.TrimNamed(ref), dgst)
|
||||
} else {
|
||||
ref, err = reference.WithTag(ref, tag)
|
||||
}
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := validateRepoName(ref); err != nil {
|
||||
return errdefs.Forbidden(err)
|
||||
}
|
||||
|
||||
// For a pull it is not an error if no auth was given. Ignore invalid
|
||||
// AuthConfig to increase compatibility with the existing API.
|
||||
authConfig, _ := registry.DecodeAuthConfig(r.Header.Get(registry.AuthHeader))
|
||||
progressErr = ir.backend.PullImage(ctx, ref, platform, metaHeaders, authConfig, output)
|
||||
progressErr = ir.backend.PullImage(ctx, img, tag, platform, metaHeaders, authConfig, output)
|
||||
} else { // import
|
||||
src := r.Form.Get("fromSrc")
|
||||
|
||||
|
@ -190,7 +157,7 @@ func (ir *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter
|
|||
|
||||
var ref reference.Named
|
||||
|
||||
// Tag is empty only in case PushOptions.All is true.
|
||||
// Tag is empty only in case ImagePushOptions.All is true.
|
||||
if tag != "" {
|
||||
r, err := httputils.RepoTagReference(img, tag)
|
||||
if err != nil {
|
||||
|
@ -286,7 +253,7 @@ func (ir *imageRouter) deleteImages(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
|
||||
func (ir *imageRouter) getImagesByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
img, err := ir.backend.GetImage(ctx, vars["name"], backend.GetImageOpts{Details: true})
|
||||
img, err := ir.backend.GetImage(ctx, vars["name"], opts.GetImageOpts{Details: true})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -296,20 +263,6 @@ func (ir *imageRouter) getImagesByName(ctx context.Context, w http.ResponseWrite
|
|||
return err
|
||||
}
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.LessThan(version, "1.44") {
|
||||
imageInspect.VirtualSize = imageInspect.Size //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.44.
|
||||
|
||||
if imageInspect.Created == "" {
|
||||
// backwards compatibility for Created not existing returning "0001-01-01T00:00:00Z"
|
||||
// https://github.com/moby/moby/issues/47368
|
||||
imageInspect.Created = time.Time{}.Format(time.RFC3339Nano)
|
||||
}
|
||||
}
|
||||
if versions.GreaterThanOrEqualTo(version, "1.45") {
|
||||
imageInspect.Container = "" //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.45.
|
||||
imageInspect.ContainerConfig = nil //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.45.
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, imageInspect)
|
||||
}
|
||||
|
||||
|
@ -329,28 +282,15 @@ func (ir *imageRouter) toImageInspect(img *image.Image) (*types.ImageInspect, er
|
|||
comment = img.History[len(img.History)-1].Comment
|
||||
}
|
||||
|
||||
// Make sure we output empty arrays instead of nil.
|
||||
if repoTags == nil {
|
||||
repoTags = []string{}
|
||||
}
|
||||
if repoDigests == nil {
|
||||
repoDigests = []string{}
|
||||
}
|
||||
|
||||
var created string
|
||||
if img.Created != nil {
|
||||
created = img.Created.Format(time.RFC3339Nano)
|
||||
}
|
||||
|
||||
return &types.ImageInspect{
|
||||
ID: img.ID().String(),
|
||||
RepoTags: repoTags,
|
||||
RepoDigests: repoDigests,
|
||||
Parent: img.Parent.String(),
|
||||
Comment: comment,
|
||||
Created: created,
|
||||
Container: img.Container, //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.45.
|
||||
ContainerConfig: &img.ContainerConfig, //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.45.
|
||||
Created: img.Created.Format(time.RFC3339Nano),
|
||||
Container: img.Container,
|
||||
ContainerConfig: &img.ContainerConfig,
|
||||
DockerVersion: img.DockerVersion,
|
||||
Author: img.Author,
|
||||
Config: img.Config,
|
||||
|
@ -359,12 +299,13 @@ func (ir *imageRouter) toImageInspect(img *image.Image) (*types.ImageInspect, er
|
|||
Os: img.OperatingSystem(),
|
||||
OsVersion: img.OSVersion,
|
||||
Size: img.Details.Size,
|
||||
VirtualSize: img.Details.Size, //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.44.
|
||||
GraphDriver: types.GraphDriverData{
|
||||
Name: img.Details.Driver,
|
||||
Data: img.Details.Metadata,
|
||||
},
|
||||
RootFS: rootFSToAPIType(img.RootFS),
|
||||
Metadata: imagetypes.Metadata{
|
||||
Metadata: types.ImageMetadata{
|
||||
LastTagTime: img.Details.LastUpdated,
|
||||
},
|
||||
}, nil
|
||||
|
@ -406,7 +347,7 @@ func (ir *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
|
|||
sharedSize = httputils.BoolValue(r, "shared-size")
|
||||
}
|
||||
|
||||
images, err := ir.backend.Images(ctx, imagetypes.ListOptions{
|
||||
images, err := ir.backend.Images(ctx, types.ImageListOptions{
|
||||
All: httputils.BoolValue(r, "all"),
|
||||
Filters: imageFilters,
|
||||
SharedSize: sharedSize,
|
||||
|
@ -416,7 +357,6 @@ func (ir *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
|
||||
useNone := versions.LessThan(version, "1.43")
|
||||
withVirtualSize := versions.LessThan(version, "1.44")
|
||||
for _, img := range images {
|
||||
if useNone {
|
||||
if len(img.RepoTags) == 0 && len(img.RepoDigests) == 0 {
|
||||
|
@ -431,9 +371,6 @@ func (ir *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
|
|||
img.RepoDigests = []string{}
|
||||
}
|
||||
}
|
||||
if withVirtualSize {
|
||||
img.VirtualSize = img.Size //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.44.
|
||||
}
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, images)
|
||||
|
@ -458,12 +395,7 @@ func (ir *imageRouter) postImagesTag(ctx context.Context, w http.ResponseWriter,
|
|||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
refName := reference.FamiliarName(ref)
|
||||
if refName == string(digest.Canonical) {
|
||||
return errdefs.InvalidParameter(errors.New("refusing to create an ambiguous tag using digest algorithm as name"))
|
||||
}
|
||||
|
||||
img, err := ir.backend.GetImage(ctx, vars["name"], backend.GetImageOpts{})
|
||||
img, err := ir.backend.GetImage(ctx, vars["name"], opts.GetImageOpts{})
|
||||
if err != nil {
|
||||
return errdefs.NotFound(err)
|
||||
}
|
||||
|
@ -497,7 +429,7 @@ func (ir *imageRouter) getImagesSearch(ctx context.Context, w http.ResponseWrite
|
|||
// AuthConfig to increase compatibility with the existing API.
|
||||
authConfig, _ := registry.DecodeAuthConfig(r.Header.Get(registry.AuthHeader))
|
||||
|
||||
headers := http.Header{}
|
||||
var headers = http.Header{}
|
||||
for k, v := range r.Header {
|
||||
k = http.CanonicalHeaderKey(k)
|
||||
if strings.HasPrefix(k, "X-Meta-") {
|
||||
|
@ -528,12 +460,3 @@ func (ir *imageRouter) postImagesPrune(ctx context.Context, w http.ResponseWrite
|
|||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, pruneReport)
|
||||
}
|
||||
|
||||
// validateRepoName validates the name of a repository.
|
||||
func validateRepoName(name reference.Named) error {
|
||||
familiarName := reference.FamiliarName(name)
|
||||
if familiarName == api.NoBaseImageSpecifier {
|
||||
return fmt.Errorf("'%s' is a reserved name", familiarName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -4,15 +4,16 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/libnetwork"
|
||||
)
|
||||
|
||||
// Backend is all the methods that need to be implemented
|
||||
// to provide network specific functionality.
|
||||
type Backend interface {
|
||||
GetNetworks(filters.Args, backend.NetworkListConfig) ([]types.NetworkResource, error)
|
||||
FindNetwork(idName string) (libnetwork.Network, error)
|
||||
GetNetworks(filters.Args, types.NetworkListConfig) ([]types.NetworkResource, error)
|
||||
CreateNetwork(nc types.NetworkCreateRequest) (*types.NetworkCreateResponse, error)
|
||||
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
|
||||
DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error
|
||||
|
|
1
api/server/router/network/filter.go
Normal file
1
api/server/router/network/filter.go
Normal file
|
@ -0,0 +1 @@
|
|||
package network // import "github.com/docker/docker/api/server/router/network"
|
|
@ -8,13 +8,12 @@ import (
|
|||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/libnetwork"
|
||||
"github.com/docker/docker/libnetwork/scope"
|
||||
netconst "github.com/docker/docker/libnetwork/datastore"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -40,7 +39,7 @@ func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWrit
|
|||
|
||||
// Combine the network list returned by Docker daemon if it is not already
|
||||
// returned by the cluster manager
|
||||
localNetworks, err := n.backend.GetNetworks(filter, backend.NetworkListConfig{Detailed: versions.LessThan(httputils.VersionFromContext(ctx), "1.28")})
|
||||
localNetworks, err := n.backend.GetNetworks(filter, types.NetworkListConfig{Detailed: versions.LessThan(httputils.VersionFromContext(ctx), "1.28")})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -84,6 +83,10 @@ func (e ambigousResultsError) Error() string {
|
|||
|
||||
func (ambigousResultsError) InvalidParameter() {}
|
||||
|
||||
func nameConflict(name string) error {
|
||||
return errdefs.Conflict(libnetwork.NetworkNameError(name))
|
||||
}
|
||||
|
||||
func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
|
@ -99,7 +102,7 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
|
|||
return errors.Wrapf(invalidRequestError{err}, "invalid value for verbose: %s", v)
|
||||
}
|
||||
}
|
||||
networkScope := r.URL.Query().Get("scope")
|
||||
scope := r.URL.Query().Get("scope")
|
||||
|
||||
// In case multiple networks have duplicate names, return error.
|
||||
// TODO (yongtang): should we wrap with version here for backward compatibility?
|
||||
|
@ -115,23 +118,23 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
|
|||
// TODO(@cpuguy83): All this logic for figuring out which network to return does not belong here
|
||||
// Instead there should be a backend function to just get one network.
|
||||
filter := filters.NewArgs(filters.Arg("idOrName", term))
|
||||
if networkScope != "" {
|
||||
filter.Add("scope", networkScope)
|
||||
if scope != "" {
|
||||
filter.Add("scope", scope)
|
||||
}
|
||||
networks, _ := n.backend.GetNetworks(filter, backend.NetworkListConfig{Detailed: true, Verbose: verbose})
|
||||
for _, nw := range networks {
|
||||
if nw.ID == term {
|
||||
return httputils.WriteJSON(w, http.StatusOK, nw)
|
||||
nw, _ := n.backend.GetNetworks(filter, types.NetworkListConfig{Detailed: true, Verbose: verbose})
|
||||
for _, network := range nw {
|
||||
if network.ID == term {
|
||||
return httputils.WriteJSON(w, http.StatusOK, network)
|
||||
}
|
||||
if nw.Name == term {
|
||||
if network.Name == term {
|
||||
// No need to check the ID collision here as we are still in
|
||||
// local scope and the network ID is unique in this scope.
|
||||
listByFullName[nw.ID] = nw
|
||||
listByFullName[network.ID] = network
|
||||
}
|
||||
if strings.HasPrefix(nw.ID, term) {
|
||||
if strings.HasPrefix(network.ID, term) {
|
||||
// No need to check the ID collision here as we are still in
|
||||
// local scope and the network ID is unique in this scope.
|
||||
listByPartialID[nw.ID] = nw
|
||||
listByPartialID[network.ID] = network
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,7 +144,7 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
|
|||
// or if the get network was passed with a network name and scope as swarm
|
||||
// return the network. Skipped using isMatchingScope because it is true if the scope
|
||||
// is not set which would be case if the client API v1.30
|
||||
if strings.HasPrefix(nwk.ID, term) || networkScope == scope.Swarm {
|
||||
if strings.HasPrefix(nwk.ID, term) || (netconst.SwarmScope == scope) {
|
||||
// If we have a previous match "backend", return it, we need verbose when enabled
|
||||
// ex: overlay/partial_ID or name/swarm_scope
|
||||
if nwv, ok := listByPartialID[nwk.ID]; ok {
|
||||
|
@ -153,25 +156,25 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
|
|||
}
|
||||
}
|
||||
|
||||
networks, _ = n.cluster.GetNetworks(filter)
|
||||
for _, nw := range networks {
|
||||
if nw.ID == term {
|
||||
return httputils.WriteJSON(w, http.StatusOK, nw)
|
||||
nr, _ := n.cluster.GetNetworks(filter)
|
||||
for _, network := range nr {
|
||||
if network.ID == term {
|
||||
return httputils.WriteJSON(w, http.StatusOK, network)
|
||||
}
|
||||
if nw.Name == term {
|
||||
if network.Name == term {
|
||||
// Check the ID collision as we are in swarm scope here, and
|
||||
// the map (of the listByFullName) may have already had a
|
||||
// network with the same ID (from local scope previously)
|
||||
if _, ok := listByFullName[nw.ID]; !ok {
|
||||
listByFullName[nw.ID] = nw
|
||||
if _, ok := listByFullName[network.ID]; !ok {
|
||||
listByFullName[network.ID] = network
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(nw.ID, term) {
|
||||
if strings.HasPrefix(network.ID, term) {
|
||||
// Check the ID collision as we are in swarm scope here, and
|
||||
// the map (of the listByPartialID) may have already had a
|
||||
// network with the same ID (from local scope previously)
|
||||
if _, ok := listByPartialID[nw.ID]; !ok {
|
||||
listByPartialID[nw.ID] = nw
|
||||
if _, ok := listByPartialID[network.ID]; !ok {
|
||||
listByPartialID[network.ID] = network
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -210,15 +213,21 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr
|
|||
}
|
||||
|
||||
if nws, err := n.cluster.GetNetworksByName(create.Name); err == nil && len(nws) > 0 {
|
||||
return libnetwork.NetworkNameError(create.Name)
|
||||
return nameConflict(create.Name)
|
||||
}
|
||||
|
||||
// For a Swarm-scoped network, this call to backend.CreateNetwork is used to
|
||||
// validate the configuration. The network will not be created but, if the
|
||||
// configuration is valid, ManagerRedirectError will be returned and handled
|
||||
// below.
|
||||
nw, err := n.backend.CreateNetwork(create)
|
||||
if err != nil {
|
||||
var warning string
|
||||
if _, ok := err.(libnetwork.NetworkNameError); ok {
|
||||
// check if user defined CheckDuplicate, if set true, return err
|
||||
// otherwise prepare a warning message
|
||||
if create.CheckDuplicate {
|
||||
return nameConflict(create.Name)
|
||||
}
|
||||
warning = libnetwork.NetworkNameError(create.Name).Error()
|
||||
}
|
||||
|
||||
if _, ok := err.(libnetwork.ManagerRedirectError); !ok {
|
||||
return err
|
||||
}
|
||||
|
@ -227,7 +236,8 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr
|
|||
return err
|
||||
}
|
||||
nw = &types.NetworkCreateResponse{
|
||||
ID: id,
|
||||
ID: id,
|
||||
Warning: warning,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -316,42 +326,42 @@ func (n *networkRouter) findUniqueNetwork(term string) (types.NetworkResource, e
|
|||
listByPartialID := map[string]types.NetworkResource{}
|
||||
|
||||
filter := filters.NewArgs(filters.Arg("idOrName", term))
|
||||
networks, _ := n.backend.GetNetworks(filter, backend.NetworkListConfig{Detailed: true})
|
||||
for _, nw := range networks {
|
||||
if nw.ID == term {
|
||||
return nw, nil
|
||||
nw, _ := n.backend.GetNetworks(filter, types.NetworkListConfig{Detailed: true})
|
||||
for _, network := range nw {
|
||||
if network.ID == term {
|
||||
return network, nil
|
||||
}
|
||||
if nw.Name == term && !nw.Ingress {
|
||||
if network.Name == term && !network.Ingress {
|
||||
// No need to check the ID collision here as we are still in
|
||||
// local scope and the network ID is unique in this scope.
|
||||
listByFullName[nw.ID] = nw
|
||||
listByFullName[network.ID] = network
|
||||
}
|
||||
if strings.HasPrefix(nw.ID, term) {
|
||||
if strings.HasPrefix(network.ID, term) {
|
||||
// No need to check the ID collision here as we are still in
|
||||
// local scope and the network ID is unique in this scope.
|
||||
listByPartialID[nw.ID] = nw
|
||||
listByPartialID[network.ID] = network
|
||||
}
|
||||
}
|
||||
|
||||
networks, _ = n.cluster.GetNetworks(filter)
|
||||
for _, nw := range networks {
|
||||
if nw.ID == term {
|
||||
return nw, nil
|
||||
nr, _ := n.cluster.GetNetworks(filter)
|
||||
for _, network := range nr {
|
||||
if network.ID == term {
|
||||
return network, nil
|
||||
}
|
||||
if nw.Name == term {
|
||||
if network.Name == term {
|
||||
// Check the ID collision as we are in swarm scope here, and
|
||||
// the map (of the listByFullName) may have already had a
|
||||
// network with the same ID (from local scope previously)
|
||||
if _, ok := listByFullName[nw.ID]; !ok {
|
||||
listByFullName[nw.ID] = nw
|
||||
if _, ok := listByFullName[network.ID]; !ok {
|
||||
listByFullName[network.ID] = network
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(nw.ID, term) {
|
||||
if strings.HasPrefix(network.ID, term) {
|
||||
// Check the ID collision as we are in swarm scope here, and
|
||||
// the map (of the listByPartialID) may have already had a
|
||||
// network with the same ID (from local scope previously)
|
||||
if _, ok := listByPartialID[nw.ID]; !ok {
|
||||
listByPartialID[nw.ID] = nw
|
||||
if _, ok := listByPartialID[network.ID]; !ok {
|
||||
listByPartialID[network.ID] = network
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,8 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/plugin"
|
||||
|
@ -15,11 +14,11 @@ import (
|
|||
|
||||
// Backend for Plugin
|
||||
type Backend interface {
|
||||
Disable(name string, config *backend.PluginDisableConfig) error
|
||||
Enable(name string, config *backend.PluginEnableConfig) error
|
||||
Disable(name string, config *types.PluginDisableConfig) error
|
||||
Enable(name string, config *types.PluginEnableConfig) error
|
||||
List(filters.Args) ([]types.Plugin, error)
|
||||
Inspect(name string) (*types.Plugin, error)
|
||||
Remove(name string, config *backend.PluginRmConfig) error
|
||||
Remove(name string, config *types.PluginRmConfig) error
|
||||
Set(name string, args []string) error
|
||||
Privileges(ctx context.Context, ref reference.Named, metaHeaders http.Header, authConfig *registry.AuthConfig) (types.PluginPrivileges, error)
|
||||
Pull(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *registry.AuthConfig, privileges types.PluginPrivileges, outStream io.Writer, opts ...plugin.CreateOpt) error
|
||||
|
|
|
@ -6,10 +6,9 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
|
@ -187,8 +186,7 @@ func (pr *pluginRouter) createPlugin(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
|
||||
options := &types.PluginCreateOptions{
|
||||
RepoName: r.FormValue("name"),
|
||||
}
|
||||
RepoName: r.FormValue("name")}
|
||||
|
||||
if err := pr.backend.CreateFromContext(ctx, r.Body, options); err != nil {
|
||||
return err
|
||||
|
@ -208,7 +206,7 @@ func (pr *pluginRouter) enablePlugin(ctx context.Context, w http.ResponseWriter,
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config := &backend.PluginEnableConfig{Timeout: timeout}
|
||||
config := &types.PluginEnableConfig{Timeout: timeout}
|
||||
|
||||
return pr.backend.Enable(name, config)
|
||||
}
|
||||
|
@ -219,7 +217,7 @@ func (pr *pluginRouter) disablePlugin(ctx context.Context, w http.ResponseWriter
|
|||
}
|
||||
|
||||
name := vars["name"]
|
||||
config := &backend.PluginDisableConfig{
|
||||
config := &types.PluginDisableConfig{
|
||||
ForceDisable: httputils.BoolValue(r, "force"),
|
||||
}
|
||||
|
||||
|
@ -232,7 +230,7 @@ func (pr *pluginRouter) removePlugin(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
|
||||
name := vars["name"]
|
||||
config := &backend.PluginRmConfig{
|
||||
config := &types.PluginRmConfig{
|
||||
ForceRemove: httputils.BoolValue(r, "force"),
|
||||
}
|
||||
return pr.backend.Remove(name, config)
|
||||
|
|
|
@ -3,41 +3,46 @@ package swarm // import "github.com/docker/docker/api/server/router/swarm"
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
basictypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
types "github.com/docker/docker/api/types/swarm"
|
||||
)
|
||||
|
||||
// Backend abstracts a swarm manager.
|
||||
type Backend interface {
|
||||
Init(req swarm.InitRequest) (string, error)
|
||||
Join(req swarm.JoinRequest) error
|
||||
Init(req types.InitRequest) (string, error)
|
||||
Join(req types.JoinRequest) error
|
||||
Leave(ctx context.Context, force bool) error
|
||||
Inspect() (swarm.Swarm, error)
|
||||
Update(uint64, swarm.Spec, swarm.UpdateFlags) error
|
||||
Inspect() (types.Swarm, error)
|
||||
Update(uint64, types.Spec, types.UpdateFlags) error
|
||||
GetUnlockKey() (string, error)
|
||||
UnlockSwarm(req swarm.UnlockRequest) error
|
||||
GetServices(types.ServiceListOptions) ([]swarm.Service, error)
|
||||
GetService(idOrName string, insertDefaults bool) (swarm.Service, error)
|
||||
CreateService(swarm.ServiceSpec, string, bool) (*swarm.ServiceCreateResponse, error)
|
||||
UpdateService(string, uint64, swarm.ServiceSpec, types.ServiceUpdateOptions, bool) (*swarm.ServiceUpdateResponse, error)
|
||||
UnlockSwarm(req types.UnlockRequest) error
|
||||
|
||||
GetServices(basictypes.ServiceListOptions) ([]types.Service, error)
|
||||
GetService(idOrName string, insertDefaults bool) (types.Service, error)
|
||||
CreateService(types.ServiceSpec, string, bool) (*basictypes.ServiceCreateResponse, error)
|
||||
UpdateService(string, uint64, types.ServiceSpec, basictypes.ServiceUpdateOptions, bool) (*basictypes.ServiceUpdateResponse, error)
|
||||
RemoveService(string) error
|
||||
ServiceLogs(context.Context, *backend.LogSelector, *container.LogsOptions) (<-chan *backend.LogMessage, error)
|
||||
GetNodes(types.NodeListOptions) ([]swarm.Node, error)
|
||||
GetNode(string) (swarm.Node, error)
|
||||
UpdateNode(string, uint64, swarm.NodeSpec) error
|
||||
|
||||
ServiceLogs(context.Context, *backend.LogSelector, *basictypes.ContainerLogsOptions) (<-chan *backend.LogMessage, error)
|
||||
|
||||
GetNodes(basictypes.NodeListOptions) ([]types.Node, error)
|
||||
GetNode(string) (types.Node, error)
|
||||
UpdateNode(string, uint64, types.NodeSpec) error
|
||||
RemoveNode(string, bool) error
|
||||
GetTasks(types.TaskListOptions) ([]swarm.Task, error)
|
||||
GetTask(string) (swarm.Task, error)
|
||||
GetSecrets(opts types.SecretListOptions) ([]swarm.Secret, error)
|
||||
CreateSecret(s swarm.SecretSpec) (string, error)
|
||||
|
||||
GetTasks(basictypes.TaskListOptions) ([]types.Task, error)
|
||||
GetTask(string) (types.Task, error)
|
||||
|
||||
GetSecrets(opts basictypes.SecretListOptions) ([]types.Secret, error)
|
||||
CreateSecret(s types.SecretSpec) (string, error)
|
||||
RemoveSecret(idOrName string) error
|
||||
GetSecret(id string) (swarm.Secret, error)
|
||||
UpdateSecret(idOrName string, version uint64, spec swarm.SecretSpec) error
|
||||
GetConfigs(opts types.ConfigListOptions) ([]swarm.Config, error)
|
||||
CreateConfig(s swarm.ConfigSpec) (string, error)
|
||||
GetSecret(id string) (types.Secret, error)
|
||||
UpdateSecret(idOrName string, version uint64, spec types.SecretSpec) error
|
||||
|
||||
GetConfigs(opts basictypes.ConfigListOptions) ([]types.Config, error)
|
||||
CreateConfig(s types.ConfigSpec) (string, error)
|
||||
RemoveConfig(id string) error
|
||||
GetConfig(id string) (swarm.Config, error)
|
||||
UpdateConfig(idOrName string, version uint64, spec swarm.ConfigSpec) error
|
||||
GetConfig(id string) (types.Config, error)
|
||||
UpdateConfig(idOrName string, version uint64, spec types.ConfigSpec) error
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
basictypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
|
@ -16,6 +15,7 @@ import (
|
|||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (sr *swarmRouter) initCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
|
@ -36,7 +36,7 @@ func (sr *swarmRouter) initCluster(ctx context.Context, w http.ResponseWriter, r
|
|||
}
|
||||
nodeID, err := sr.backend.Init(req)
|
||||
if err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error initializing swarm")
|
||||
logrus.WithContext(ctx).WithError(err).Debug("Error initializing swarm")
|
||||
return err
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, nodeID)
|
||||
|
@ -62,7 +62,7 @@ func (sr *swarmRouter) leaveCluster(ctx context.Context, w http.ResponseWriter,
|
|||
func (sr *swarmRouter) inspectCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
swarm, err := sr.backend.Inspect()
|
||||
if err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error getting swarm")
|
||||
logrus.WithContext(ctx).WithError(err).Debug("Error getting swarm")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ func (sr *swarmRouter) updateCluster(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
|
||||
if err := sr.backend.Update(version, swarm, flags); err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error configuring swarm")
|
||||
logrus.WithContext(ctx).WithError(err).Debug("Error configuring swarm")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -127,7 +127,7 @@ func (sr *swarmRouter) unlockCluster(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
|
||||
if err := sr.backend.UnlockSwarm(req); err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error unlocking swarm")
|
||||
logrus.WithContext(ctx).WithError(err).Debug("Error unlocking swarm")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -136,7 +136,7 @@ func (sr *swarmRouter) unlockCluster(ctx context.Context, w http.ResponseWriter,
|
|||
func (sr *swarmRouter) getUnlockKey(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
unlockKey, err := sr.backend.GetUnlockKey()
|
||||
if err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error retrieving swarm unlock key")
|
||||
logrus.WithContext(ctx).WithError(err).Debug("Error retrieving swarm unlock key")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -168,7 +168,7 @@ func (sr *swarmRouter) getServices(ctx context.Context, w http.ResponseWriter, r
|
|||
|
||||
services, err := sr.backend.GetServices(basictypes.ServiceListOptions{Filters: filter, Status: status})
|
||||
if err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error getting services")
|
||||
logrus.WithContext(ctx).WithError(err).Debug("Error getting services")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -194,7 +194,7 @@ func (sr *swarmRouter) getService(ctx context.Context, w http.ResponseWriter, r
|
|||
|
||||
service, err := sr.backend.GetService(vars["id"], insertDefaults)
|
||||
if err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
logrus.WithContext(ctx).WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"service-id": vars["id"],
|
||||
}).Debug("Error getting service")
|
||||
|
@ -209,10 +209,6 @@ func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter,
|
|||
if err := httputils.ReadJSON(r, &service); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO(thaJeztah): remove logentries check and migration code in release v26.0.0.
|
||||
if service.TaskTemplate.LogDriver != nil && service.TaskTemplate.LogDriver.Name == "logentries" {
|
||||
return errdefs.InvalidParameter(errors.New("the logentries logging driver has been deprecated and removed"))
|
||||
}
|
||||
|
||||
// Get returns "" if the header does not exist
|
||||
encodedAuth := r.Header.Get(registry.AuthHeader)
|
||||
|
@ -223,18 +219,9 @@ func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
adjustForAPIVersion(v, &service)
|
||||
}
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.LessThan(version, "1.44") {
|
||||
if service.TaskTemplate.ContainerSpec != nil && service.TaskTemplate.ContainerSpec.Healthcheck != nil {
|
||||
// StartInterval was added in API 1.44
|
||||
service.TaskTemplate.ContainerSpec.Healthcheck.StartInterval = 0
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := sr.backend.CreateService(service, encodedAuth, queryRegistry)
|
||||
if err != nil {
|
||||
log.G(ctx).WithFields(log.Fields{
|
||||
logrus.WithContext(ctx).WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"service-name": service.Name,
|
||||
}).Debug("Error creating service")
|
||||
|
@ -249,10 +236,6 @@ func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter,
|
|||
if err := httputils.ReadJSON(r, &service); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO(thaJeztah): remove logentries check and migration code in release v26.0.0.
|
||||
if service.TaskTemplate.LogDriver != nil && service.TaskTemplate.LogDriver.Name == "logentries" {
|
||||
return errdefs.InvalidParameter(errors.New("the logentries logging driver has been deprecated and removed"))
|
||||
}
|
||||
|
||||
rawVersion := r.URL.Query().Get("version")
|
||||
version, err := strconv.ParseUint(rawVersion, 10, 64)
|
||||
|
@ -277,7 +260,7 @@ func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter,
|
|||
|
||||
resp, err := sr.backend.UpdateService(vars["id"], version, service, flags, queryRegistry)
|
||||
if err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
logrus.WithContext(ctx).WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"service-id": vars["id"],
|
||||
}).Debug("Error updating service")
|
||||
|
@ -288,7 +271,7 @@ func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter,
|
|||
|
||||
func (sr *swarmRouter) removeService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := sr.backend.RemoveService(vars["id"]); err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
logrus.WithContext(ctx).WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"service-id": vars["id"],
|
||||
}).Debug("Error removing service")
|
||||
|
@ -332,7 +315,7 @@ func (sr *swarmRouter) getNodes(ctx context.Context, w http.ResponseWriter, r *h
|
|||
|
||||
nodes, err := sr.backend.GetNodes(basictypes.NodeListOptions{Filters: filter})
|
||||
if err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error getting nodes")
|
||||
logrus.WithContext(ctx).WithError(err).Debug("Error getting nodes")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -342,7 +325,7 @@ func (sr *swarmRouter) getNodes(ctx context.Context, w http.ResponseWriter, r *h
|
|||
func (sr *swarmRouter) getNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
node, err := sr.backend.GetNode(vars["id"])
|
||||
if err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
logrus.WithContext(ctx).WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"node-id": vars["id"],
|
||||
}).Debug("Error getting node")
|
||||
|
@ -366,7 +349,7 @@ func (sr *swarmRouter) updateNode(ctx context.Context, w http.ResponseWriter, r
|
|||
}
|
||||
|
||||
if err := sr.backend.UpdateNode(vars["id"], version, node); err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
logrus.WithContext(ctx).WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"node-id": vars["id"],
|
||||
}).Debug("Error updating node")
|
||||
|
@ -383,7 +366,7 @@ func (sr *swarmRouter) removeNode(ctx context.Context, w http.ResponseWriter, r
|
|||
force := httputils.BoolValue(r, "force")
|
||||
|
||||
if err := sr.backend.RemoveNode(vars["id"], force); err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
logrus.WithContext(ctx).WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"node-id": vars["id"],
|
||||
}).Debug("Error removing node")
|
||||
|
@ -403,7 +386,7 @@ func (sr *swarmRouter) getTasks(ctx context.Context, w http.ResponseWriter, r *h
|
|||
|
||||
tasks, err := sr.backend.GetTasks(basictypes.TaskListOptions{Filters: filter})
|
||||
if err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error getting tasks")
|
||||
logrus.WithContext(ctx).WithError(err).Debug("Error getting tasks")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -413,7 +396,7 @@ func (sr *swarmRouter) getTasks(ctx context.Context, w http.ResponseWriter, r *h
|
|||
func (sr *swarmRouter) getTask(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
task, err := sr.backend.GetTask(vars["id"])
|
||||
if err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
logrus.WithContext(ctx).WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"task-id": vars["id"],
|
||||
}).Debug("Error getting task")
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"github.com/docker/docker/api/server/httputils"
|
||||
basictypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
)
|
||||
|
@ -26,9 +25,9 @@ func (sr *swarmRouter) swarmLogs(ctx context.Context, w http.ResponseWriter, r *
|
|||
return fmt.Errorf("Bad parameters: you must choose at least one stream")
|
||||
}
|
||||
|
||||
// there is probably a neater way to manufacture the LogsOptions
|
||||
// there is probably a neater way to manufacture the ContainerLogsOptions
|
||||
// struct, probably in the caller, to eliminate the dependency on net/http
|
||||
logsConfig := &container.LogsOptions{
|
||||
logsConfig := &basictypes.ContainerLogsOptions{
|
||||
Follow: httputils.BoolValue(r, "follow"),
|
||||
Timestamps: httputils.BoolValue(r, "timestamps"),
|
||||
Since: r.Form.Get("since"),
|
||||
|
@ -119,13 +118,4 @@ func adjustForAPIVersion(cliVersion string, service *swarm.ServiceSpec) {
|
|||
service.Mode.ReplicatedJob = nil
|
||||
service.Mode.GlobalJob = nil
|
||||
}
|
||||
|
||||
if versions.LessThan(cliVersion, "1.44") {
|
||||
// seccomp, apparmor, and no_new_privs were added in 1.44.
|
||||
if service.TaskTemplate.ContainerSpec != nil && service.TaskTemplate.ContainerSpec.Privileges != nil {
|
||||
service.TaskTemplate.ContainerSpec.Privileges.Seccomp = nil
|
||||
service.TaskTemplate.ContainerSpec.Privileges.AppArmor = nil
|
||||
service.TaskTemplate.ContainerSpec.Privileges.NoNewPrivileges = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,9 @@ import (
|
|||
)
|
||||
|
||||
func TestAdjustForAPIVersion(t *testing.T) {
|
||||
expectedSysctls := map[string]string{"foo": "bar"}
|
||||
var (
|
||||
expectedSysctls = map[string]string{"foo": "bar"}
|
||||
)
|
||||
// testing the negative -- does this leave everything else alone? -- is
|
||||
// prohibitively time-consuming to write, because it would need an object
|
||||
// with literally every field filled in.
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/api/types/system"
|
||||
)
|
||||
|
||||
// DiskUsageOptions holds parameters for system disk usage query.
|
||||
|
@ -27,8 +26,8 @@ type DiskUsageOptions struct {
|
|||
// Backend is the methods that need to be implemented to provide
|
||||
// system specific functionality.
|
||||
type Backend interface {
|
||||
SystemInfo(context.Context) (*system.Info, error)
|
||||
SystemVersion(context.Context) (types.Version, error)
|
||||
SystemInfo() *types.Info
|
||||
SystemVersion() types.Version
|
||||
SystemDiskUsage(ctx context.Context, opts DiskUsageOptions) (*types.DiskUsage, error)
|
||||
SubscribeToEvents(since, until time.Time, ef filters.Args) ([]events.Message, chan interface{})
|
||||
UnsubscribeFromEvents(chan interface{})
|
||||
|
@ -38,7 +37,7 @@ type Backend interface {
|
|||
// ClusterBackend is all the methods that need to be implemented
|
||||
// to provide cluster system specific functionality.
|
||||
type ClusterBackend interface {
|
||||
Info(context.Context) swarm.Info
|
||||
Info() swarm.Info
|
||||
}
|
||||
|
||||
// StatusProvider provides methods to get the swarm status of the current node.
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.19
|
||||
|
||||
package system // import "github.com/docker/docker/api/server/router/system"
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/api/types/system"
|
||||
buildkit "github.com/docker/docker/builder/builder-next"
|
||||
"resenje.org/singleflight"
|
||||
)
|
||||
|
||||
// systemRouter provides information about the Docker system overall.
|
||||
|
@ -17,16 +12,11 @@ type systemRouter struct {
|
|||
cluster ClusterBackend
|
||||
routes []router.Route
|
||||
builder *buildkit.Builder
|
||||
features func() map[string]bool
|
||||
|
||||
// collectSystemInfo is a single-flight for the /info endpoint,
|
||||
// unique per API version (as different API versions may return
|
||||
// a different API response).
|
||||
collectSystemInfo singleflight.Group[string, *system.Info]
|
||||
features *map[string]bool
|
||||
}
|
||||
|
||||
// NewRouter initializes a new system router
|
||||
func NewRouter(b Backend, c ClusterBackend, builder *buildkit.Builder, features func() map[string]bool) router.Router {
|
||||
func NewRouter(b Backend, c ClusterBackend, builder *buildkit.Builder, features *map[string]bool) router.Router {
|
||||
r := &systemRouter{
|
||||
backend: b,
|
||||
cluster: c,
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/server/router/build"
|
||||
"github.com/docker/docker/api/types"
|
||||
|
@ -15,11 +14,11 @@ import (
|
|||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/api/types/system"
|
||||
timetypes "github.com/docker/docker/api/types/time"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
|
@ -32,7 +31,7 @@ func (s *systemRouter) pingHandler(ctx context.Context, w http.ResponseWriter, r
|
|||
w.Header().Add("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||
w.Header().Add("Pragma", "no-cache")
|
||||
|
||||
builderVersion := build.BuilderVersion(s.features())
|
||||
builderVersion := build.BuilderVersion(*s.features)
|
||||
if bv := builderVersion; bv != "" {
|
||||
w.Header().Set("Builder-Version", string(bv))
|
||||
}
|
||||
|
@ -58,58 +57,51 @@ func (s *systemRouter) swarmStatus() string {
|
|||
}
|
||||
|
||||
func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
info := s.backend.SystemInfo()
|
||||
|
||||
if s.cluster != nil {
|
||||
info.Swarm = s.cluster.Info()
|
||||
info.Warnings = append(info.Warnings, info.Swarm.Warnings...)
|
||||
}
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
info, _, _ := s.collectSystemInfo.Do(ctx, version, func(ctx context.Context) (*system.Info, error) {
|
||||
info, err := s.backend.SystemInfo(ctx)
|
||||
if versions.LessThan(version, "1.25") {
|
||||
// TODO: handle this conversion in engine-api
|
||||
type oldInfo struct {
|
||||
*types.Info
|
||||
ExecutionDriver string
|
||||
}
|
||||
old := &oldInfo{
|
||||
Info: info,
|
||||
ExecutionDriver: "<not supported>",
|
||||
}
|
||||
nameOnlySecurityOptions := []string{}
|
||||
kvSecOpts, err := types.DecodeSecurityOptions(old.SecurityOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
if s.cluster != nil {
|
||||
info.Swarm = s.cluster.Info(ctx)
|
||||
info.Warnings = append(info.Warnings, info.Swarm.Warnings...)
|
||||
for _, s := range kvSecOpts {
|
||||
nameOnlySecurityOptions = append(nameOnlySecurityOptions, s.Name)
|
||||
}
|
||||
|
||||
if versions.LessThan(version, "1.25") {
|
||||
// TODO: handle this conversion in engine-api
|
||||
kvSecOpts, err := system.DecodeSecurityOptions(info.SecurityOptions)
|
||||
if err != nil {
|
||||
info.Warnings = append(info.Warnings, err.Error())
|
||||
}
|
||||
var nameOnly []string
|
||||
for _, so := range kvSecOpts {
|
||||
nameOnly = append(nameOnly, so.Name)
|
||||
}
|
||||
info.SecurityOptions = nameOnly
|
||||
info.ExecutionDriver = "<not supported>" //nolint:staticcheck // ignore SA1019 (ExecutionDriver is deprecated)
|
||||
old.SecurityOptions = nameOnlySecurityOptions
|
||||
return httputils.WriteJSON(w, http.StatusOK, old)
|
||||
}
|
||||
if versions.LessThan(version, "1.39") {
|
||||
if info.KernelVersion == "" {
|
||||
info.KernelVersion = "<unknown>"
|
||||
}
|
||||
if versions.LessThan(version, "1.39") {
|
||||
if info.KernelVersion == "" {
|
||||
info.KernelVersion = "<unknown>"
|
||||
}
|
||||
if info.OperatingSystem == "" {
|
||||
info.OperatingSystem = "<unknown>"
|
||||
}
|
||||
if info.OperatingSystem == "" {
|
||||
info.OperatingSystem = "<unknown>"
|
||||
}
|
||||
if versions.LessThan(version, "1.44") {
|
||||
for k, rt := range info.Runtimes {
|
||||
// Status field introduced in API v1.44.
|
||||
info.Runtimes[k] = system.RuntimeWithStatus{Runtime: rt.Runtime}
|
||||
}
|
||||
}
|
||||
if versions.GreaterThanOrEqualTo(version, "1.42") {
|
||||
info.KernelMemory = false
|
||||
}
|
||||
return info, nil
|
||||
})
|
||||
}
|
||||
if versions.GreaterThanOrEqualTo(version, "1.42") {
|
||||
info.KernelMemory = false
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, info)
|
||||
}
|
||||
|
||||
func (s *systemRouter) getVersion(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
info, err := s.backend.SystemVersion(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info := s.backend.SystemVersion()
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, info)
|
||||
}
|
||||
|
@ -193,11 +185,6 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
|
|||
b.Parent = "" //nolint:staticcheck // ignore SA1019 (Parent field is deprecated)
|
||||
}
|
||||
}
|
||||
if versions.LessThan(version, "1.44") {
|
||||
for _, b := range systemDiskUsage.Images {
|
||||
b.VirtualSize = b.Size //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.44.
|
||||
}
|
||||
}
|
||||
|
||||
du := types.DiskUsage{
|
||||
BuildCache: buildCache,
|
||||
|
@ -287,7 +274,7 @@ func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *
|
|||
case ev := <-l:
|
||||
jev, ok := ev.(events.Message)
|
||||
if !ok {
|
||||
log.G(ctx).Warnf("unexpected event message: %q", ev)
|
||||
logrus.Warnf("unexpected event message: %q", ev)
|
||||
continue
|
||||
}
|
||||
if err := enc.Encode(jev); err != nil {
|
||||
|
@ -296,7 +283,7 @@ func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *
|
|||
case <-timeout:
|
||||
return nil
|
||||
case <-ctx.Done():
|
||||
log.G(ctx).Debug("Client context cancelled, stop sending events")
|
||||
logrus.Debug("Client context cancelled, stop sending events")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
|
@ -14,6 +13,7 @@ import (
|
|||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/volume/service/opts"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -116,10 +116,10 @@ func (v *volumeRouter) postVolumesCreate(ctx context.Context, w http.ResponseWri
|
|||
// Instead, we will allow creating a volume with a duplicate name, which
|
||||
// should not break anything.
|
||||
if req.ClusterVolumeSpec != nil && versions.GreaterThanOrEqualTo(version, clusterVolumesVersion) {
|
||||
log.G(ctx).Debug("using cluster volume")
|
||||
logrus.Debug("using cluster volume")
|
||||
vol, err = v.cluster.CreateVolume(req)
|
||||
} else {
|
||||
log.G(ctx).Debug("using regular volume")
|
||||
logrus.Debug("using regular volume")
|
||||
vol, err = v.backend.Create(ctx, req.Name, req.Driver, opts.WithCreateOptions(req.DriverOpts), opts.WithCreateLabels(req.Labels))
|
||||
}
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ func TestGetVolumeByNameFoundRegular(t *testing.T) {
|
|||
v := &volumeRouter{
|
||||
backend: &fakeVolumeBackend{
|
||||
volumes: map[string]*volume.Volume{
|
||||
|
||||
"volume1": {
|
||||
Name: "volume1",
|
||||
},
|
||||
|
@ -107,7 +108,6 @@ func TestGetVolumeByNameFoundSwarm(t *testing.T) {
|
|||
_, err := callGetVolume(v, "volume1")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func TestListVolumes(t *testing.T) {
|
||||
v := &volumeRouter{
|
||||
backend: &fakeVolumeBackend{
|
||||
|
|
|
@ -4,16 +4,14 @@ import (
|
|||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/httpstatus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/server/middleware"
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/api/server/router/debug"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/dockerversion"
|
||||
"github.com/gorilla/mux"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// versionMatcher defines a variable matcher to be parsed by the router
|
||||
|
@ -31,8 +29,8 @@ func (s *Server) UseMiddleware(m middleware.Middleware) {
|
|||
s.middlewares = append(s.middlewares, m)
|
||||
}
|
||||
|
||||
func (s *Server) makeHTTPHandler(handler httputils.APIFunc, operation string) http.HandlerFunc {
|
||||
return otelhttp.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Define the context that we'll pass around to share info
|
||||
// like the docker-request-id.
|
||||
//
|
||||
|
@ -44,7 +42,6 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc, operation string) ht
|
|||
// use intermediate variable to prevent "should not use basic type
|
||||
// string as key in context.WithValue" golint errors
|
||||
ctx := context.WithValue(r.Context(), dockerversion.UAStringKey{}, r.Header.Get("User-Agent"))
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
handlerFunc := s.handlerWithGlobalMiddlewares(handler)
|
||||
|
||||
|
@ -56,25 +53,31 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc, operation string) ht
|
|||
if err := handlerFunc(ctx, w, r, vars); err != nil {
|
||||
statusCode := httpstatus.FromError(err)
|
||||
if statusCode >= 500 {
|
||||
log.G(ctx).Errorf("Handler for %s %s returned error: %v", r.Method, r.URL.Path, err)
|
||||
logrus.Errorf("Handler for %s %s returned error: %v", r.Method, r.URL.Path, err)
|
||||
}
|
||||
_ = httputils.WriteJSON(w, statusCode, &types.ErrorResponse{
|
||||
Message: err.Error(),
|
||||
})
|
||||
makeErrorHandler(err)(w, r)
|
||||
}
|
||||
}), operation).ServeHTTP
|
||||
}
|
||||
}
|
||||
|
||||
type pageNotFoundError struct{}
|
||||
|
||||
func (pageNotFoundError) Error() string {
|
||||
return "page not found"
|
||||
}
|
||||
|
||||
func (pageNotFoundError) NotFound() {}
|
||||
|
||||
// CreateMux returns a new mux with all the routers registered.
|
||||
func (s *Server) CreateMux(routers ...router.Router) *mux.Router {
|
||||
m := mux.NewRouter()
|
||||
|
||||
log.G(context.TODO()).Debug("Registering routers")
|
||||
logrus.Debug("Registering routers")
|
||||
for _, apiRouter := range routers {
|
||||
for _, r := range apiRouter.Routes() {
|
||||
f := s.makeHTTPHandler(r.Handler(), r.Method()+" "+r.Path())
|
||||
f := s.makeHTTPHandler(r.Handler())
|
||||
|
||||
log.G(context.TODO()).Debugf("Registering %s, %s", r.Method(), r.Path())
|
||||
logrus.Debugf("Registering %s, %s", r.Method(), r.Path())
|
||||
m.Path(versionMatcher + r.Path()).Methods(r.Method()).Handler(f)
|
||||
m.Path(r.Path()).Methods(r.Method()).Handler(f)
|
||||
}
|
||||
|
@ -82,16 +85,11 @@ func (s *Server) CreateMux(routers ...router.Router) *mux.Router {
|
|||
|
||||
debugRouter := debug.NewRouter()
|
||||
for _, r := range debugRouter.Routes() {
|
||||
f := s.makeHTTPHandler(r.Handler(), r.Method()+" "+r.Path())
|
||||
f := s.makeHTTPHandler(r.Handler())
|
||||
m.Path("/debug" + r.Path()).Handler(f)
|
||||
}
|
||||
|
||||
notFoundHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_ = httputils.WriteJSON(w, http.StatusNotFound, &types.ErrorResponse{
|
||||
Message: "page not found",
|
||||
})
|
||||
})
|
||||
|
||||
notFoundHandler := makeErrorHandler(pageNotFoundError{})
|
||||
m.HandleFunc(versionMatcher+"/{path:.*}", notFoundHandler)
|
||||
m.NotFoundHandler = notFoundHandler
|
||||
m.MethodNotAllowedHandler = notFoundHandler
|
||||
|
|
|
@ -15,11 +15,7 @@ import (
|
|||
func TestMiddlewares(t *testing.T) {
|
||||
srv := &Server{}
|
||||
|
||||
m, err := middleware.NewVersionMiddleware("0.1omega2", api.DefaultVersion, api.MinSupportedAPIVersion)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
srv.UseMiddleware(*m)
|
||||
srv.UseMiddleware(middleware.NewVersionMiddleware("0.1omega2", api.DefaultVersion, api.MinVersion))
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "/containers/json", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
|
423
api/swagger.yaml
423
api/swagger.yaml
|
@ -19,10 +19,10 @@ produces:
|
|||
consumes:
|
||||
- "application/json"
|
||||
- "text/plain"
|
||||
basePath: "/v1.45"
|
||||
basePath: "/v1.43"
|
||||
info:
|
||||
title: "Docker Engine API"
|
||||
version: "1.45"
|
||||
version: "1.43"
|
||||
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.45) is used.
|
||||
For example, calling `/info` is the same as calling `/v1.45/info`. Using the
|
||||
If you omit the version-prefix, the current version of the API (v1.43) is used.
|
||||
For example, calling `/info` is the same as calling `/v1.43/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,
|
||||
|
@ -388,20 +388,6 @@ definitions:
|
|||
description: "Create mount point on host if missing"
|
||||
type: "boolean"
|
||||
default: false
|
||||
ReadOnlyNonRecursive:
|
||||
description: |
|
||||
Make the mount non-recursively read-only, but still leave the mount recursive
|
||||
(unless NonRecursive is set to `true` in conjunction).
|
||||
|
||||
Addded in v1.44, before that version all read-only mounts were
|
||||
non-recursive by default. To match the previous behaviour this
|
||||
will default to `true` for clients on versions prior to v1.44.
|
||||
type: "boolean"
|
||||
default: false
|
||||
ReadOnlyForceRecursive:
|
||||
description: "Raise an error if the mount cannot be made recursively read-only."
|
||||
type: "boolean"
|
||||
default: false
|
||||
VolumeOptions:
|
||||
description: "Optional configuration for the `volume` type."
|
||||
type: "object"
|
||||
|
@ -427,10 +413,6 @@ definitions:
|
|||
type: "object"
|
||||
additionalProperties:
|
||||
type: "string"
|
||||
Subpath:
|
||||
description: "Source path inside the volume. Must be relative without any back traversals."
|
||||
type: "string"
|
||||
example: "dir-inside-volume/subdirectory"
|
||||
TmpfsOptions:
|
||||
description: "Optional configuration for the `tmpfs` type."
|
||||
type: "object"
|
||||
|
@ -812,12 +794,6 @@ definitions:
|
|||
1000000 (1 ms). 0 means inherit.
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
StartInterval:
|
||||
description: |
|
||||
The time to wait between checks in nanoseconds during the start period.
|
||||
It should be 0 or at least 1000000 (1 ms). 0 means inherit.
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
|
||||
Health:
|
||||
description: |
|
||||
|
@ -1321,10 +1297,7 @@ definitions:
|
|||
type: "boolean"
|
||||
x-nullable: true
|
||||
MacAddress:
|
||||
description: |
|
||||
MAC address of the container.
|
||||
|
||||
Deprecated: this field is deprecated in API v1.44 and up. Use EndpointSettings.MacAddress instead.
|
||||
description: "MAC address of the container."
|
||||
type: "string"
|
||||
x-nullable: true
|
||||
OnBuild:
|
||||
|
@ -1374,16 +1347,16 @@ definitions:
|
|||
EndpointsConfig:
|
||||
description: |
|
||||
A mapping of network name to endpoint configuration for that network.
|
||||
The endpoint configuration can be left empty to connect to that
|
||||
network with no particular endpoint configuration.
|
||||
type: "object"
|
||||
additionalProperties:
|
||||
$ref: "#/definitions/EndpointSettings"
|
||||
example:
|
||||
# putting an example here, instead of using the example values from
|
||||
# /definitions/EndpointSettings, because EndpointSettings contains
|
||||
# operational data returned when inspecting a container that we don't
|
||||
# accept here.
|
||||
# /definitions/EndpointSettings, because containers/create currently
|
||||
# does not support attaching to multiple networks, so the example request
|
||||
# would be confusing if it showed that multiple networks can be contained
|
||||
# in the EndpointsConfig.
|
||||
# TODO remove once we support multiple networks on container create (see https://github.com/moby/moby/blob/07e6b843594e061f82baa5fa23c2ff7d536c2a05/daemon/create.go#L323)
|
||||
EndpointsConfig:
|
||||
isolated_nw:
|
||||
IPAMConfig:
|
||||
|
@ -1392,22 +1365,19 @@ definitions:
|
|||
LinkLocalIPs:
|
||||
- "169.254.34.68"
|
||||
- "fe80::3468"
|
||||
MacAddress: "02:42:ac:12:05:02"
|
||||
Links:
|
||||
- "container_1"
|
||||
- "container_2"
|
||||
Aliases:
|
||||
- "server_x"
|
||||
- "server_y"
|
||||
database_nw: {}
|
||||
|
||||
NetworkSettings:
|
||||
description: "NetworkSettings exposes the network settings in the API"
|
||||
type: "object"
|
||||
properties:
|
||||
Bridge:
|
||||
description: |
|
||||
Name of the default bridge interface when dockerd's --bridge flag is set.
|
||||
description: Name of the network's bridge (for example, `docker0`).
|
||||
type: "string"
|
||||
example: "docker0"
|
||||
SandboxID:
|
||||
|
@ -1417,40 +1387,34 @@ definitions:
|
|||
HairpinMode:
|
||||
description: |
|
||||
Indicates if hairpin NAT should be enabled on the virtual interface.
|
||||
|
||||
Deprecated: This field is never set and will be removed in a future release.
|
||||
type: "boolean"
|
||||
example: false
|
||||
LinkLocalIPv6Address:
|
||||
description: |
|
||||
IPv6 unicast address using the link-local prefix.
|
||||
|
||||
Deprecated: This field is never set and will be removed in a future release.
|
||||
description: IPv6 unicast address using the link-local prefix.
|
||||
type: "string"
|
||||
example: ""
|
||||
example: "fe80::42:acff:fe11:1"
|
||||
LinkLocalIPv6PrefixLen:
|
||||
description: |
|
||||
Prefix length of the IPv6 unicast address.
|
||||
|
||||
Deprecated: This field is never set and will be removed in a future release.
|
||||
description: Prefix length of the IPv6 unicast address.
|
||||
type: "integer"
|
||||
example: ""
|
||||
example: "64"
|
||||
Ports:
|
||||
$ref: "#/definitions/PortMap"
|
||||
SandboxKey:
|
||||
description: SandboxKey is the full path of the netns handle
|
||||
description: SandboxKey identifies the sandbox
|
||||
type: "string"
|
||||
example: "/var/run/docker/netns/8ab54b426c38"
|
||||
|
||||
# TODO is SecondaryIPAddresses actually used?
|
||||
SecondaryIPAddresses:
|
||||
description: "Deprecated: This field is never set and will be removed in a future release."
|
||||
description: ""
|
||||
type: "array"
|
||||
items:
|
||||
$ref: "#/definitions/Address"
|
||||
x-nullable: true
|
||||
|
||||
# TODO is SecondaryIPv6Addresses actually used?
|
||||
SecondaryIPv6Addresses:
|
||||
description: "Deprecated: This field is never set and will be removed in a future release."
|
||||
description: ""
|
||||
type: "array"
|
||||
items:
|
||||
$ref: "#/definitions/Address"
|
||||
|
@ -1751,27 +1715,18 @@ definitions:
|
|||
description: |
|
||||
Date and time at which the image was created, formatted in
|
||||
[RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format with nano-seconds.
|
||||
|
||||
This information is only available if present in the image,
|
||||
and omitted otherwise.
|
||||
type: "string"
|
||||
format: "dateTime"
|
||||
x-nullable: true
|
||||
x-nullable: false
|
||||
example: "2022-02-04T21:20:12.497794809Z"
|
||||
Container:
|
||||
description: |
|
||||
The ID of the container that was used to create the image.
|
||||
|
||||
Depending on how the image was created, this field may be empty.
|
||||
|
||||
**Deprecated**: this field is kept for backward compatibility, but
|
||||
will be removed in API v1.45.
|
||||
type: "string"
|
||||
x-nullable: false
|
||||
example: "65974bc86f1770ae4bff79f651ebdbce166ae9aada632ee3fa9af3a264911735"
|
||||
ContainerConfig:
|
||||
description: |
|
||||
**Deprecated**: this field is kept for backward compatibility, but
|
||||
will be removed in API v1.45.
|
||||
$ref: "#/definitions/ContainerConfig"
|
||||
DockerVersion:
|
||||
description: |
|
||||
|
@ -1826,7 +1781,13 @@ definitions:
|
|||
description: |
|
||||
Total size of the image including all layers it is composed of.
|
||||
|
||||
Deprecated: this field is omitted in API v1.44, but kept for backward compatibility. Use Size instead.
|
||||
In versions of Docker before v1.10, this field was calculated from
|
||||
the image itself and all of its parent images. Images are now stored
|
||||
self-contained, and no longer use a parent-chain, making this field
|
||||
an equivalent of the Size field.
|
||||
|
||||
> **Deprecated**: this field is kept for backward compatibility, but
|
||||
> will be removed in API v1.44.
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
example: 1239828
|
||||
|
@ -1868,7 +1829,6 @@ definitions:
|
|||
x-nullable: true
|
||||
ImageSummary:
|
||||
type: "object"
|
||||
x-go-name: "Summary"
|
||||
required:
|
||||
- Id
|
||||
- ParentId
|
||||
|
@ -1965,7 +1925,12 @@ definitions:
|
|||
description: |-
|
||||
Total size of the image including all layers it is composed of.
|
||||
|
||||
Deprecated: this field is omitted in API v1.44, but kept for backward compatibility. Use Size instead.
|
||||
In versions of Docker before v1.10, this field was calculated from
|
||||
the image itself and all of its parent images. Images are now stored
|
||||
self-contained, and no longer use a parent-chain, making this field
|
||||
an equivalent of the Size field.
|
||||
|
||||
Deprecated: this field is kept for backward compatibility, and will be removed in API v1.44.
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
example: 172064416
|
||||
|
@ -2483,11 +2448,6 @@ definitions:
|
|||
example:
|
||||
- "container_1"
|
||||
- "container_2"
|
||||
MacAddress:
|
||||
description: |
|
||||
MAC address for the endpoint on this network. The network driver might ignore this parameter.
|
||||
type: "string"
|
||||
example: "02:42:ac:11:00:04"
|
||||
Aliases:
|
||||
type: "array"
|
||||
items:
|
||||
|
@ -2538,6 +2498,11 @@ definitions:
|
|||
type: "integer"
|
||||
format: "int64"
|
||||
example: 64
|
||||
MacAddress:
|
||||
description: |
|
||||
MAC address for the endpoint on this network.
|
||||
type: "string"
|
||||
example: "02:42:ac:11:00:04"
|
||||
DriverOpts:
|
||||
description: |
|
||||
DriverOpts is a mapping of driver options and values. These options
|
||||
|
@ -2549,21 +2514,6 @@ definitions:
|
|||
example:
|
||||
com.example.some-label: "some-value"
|
||||
com.example.some-other-label: "some-other-value"
|
||||
DNSNames:
|
||||
description: |
|
||||
List of all DNS names an endpoint has on a specific network. This
|
||||
list is based on the container name, network aliases, container short
|
||||
ID, and hostname.
|
||||
|
||||
These DNS names are non-fully qualified but can contain several dots.
|
||||
You can get fully qualified DNS names by appending `.<network-name>`.
|
||||
For instance, if container name is `my.ctr` and the network is named
|
||||
`testnet`, `DNSNames` will contain `my.ctr` and the FQDN will be
|
||||
`my.ctr.testnet`.
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
example: ["foobar", "server_x", "server_y", "my.ctr"]
|
||||
|
||||
EndpointIPAMConfig:
|
||||
description: |
|
||||
|
@ -3061,6 +3011,8 @@ definitions:
|
|||
Name: "journald"
|
||||
- Type: "Log"
|
||||
Name: "json-file"
|
||||
- Type: "Log"
|
||||
Name: "logentries"
|
||||
- Type: "Log"
|
||||
Name: "splunk"
|
||||
- Type: "Log"
|
||||
|
@ -3595,32 +3547,6 @@ definitions:
|
|||
Level:
|
||||
type: "string"
|
||||
description: "SELinux level label"
|
||||
Seccomp:
|
||||
type: "object"
|
||||
description: "Options for configuring seccomp on the container"
|
||||
properties:
|
||||
Mode:
|
||||
type: "string"
|
||||
enum:
|
||||
- "default"
|
||||
- "unconfined"
|
||||
- "custom"
|
||||
Profile:
|
||||
description: "The custom seccomp profile as a json object"
|
||||
type: "string"
|
||||
AppArmor:
|
||||
type: "object"
|
||||
description: "Options for configuring AppArmor on the container"
|
||||
properties:
|
||||
Mode:
|
||||
type: "string"
|
||||
enum:
|
||||
- "default"
|
||||
- "disabled"
|
||||
NoNewPrivileges:
|
||||
type: "boolean"
|
||||
description: "Configuration of the no_new_privs bit in the container"
|
||||
|
||||
TTY:
|
||||
description: "Whether a pseudo-TTY should be allocated."
|
||||
type: "boolean"
|
||||
|
@ -4015,44 +3941,6 @@ definitions:
|
|||
- "remove"
|
||||
- "orphaned"
|
||||
|
||||
ContainerStatus:
|
||||
type: "object"
|
||||
description: "represents the status of a container."
|
||||
properties:
|
||||
ContainerID:
|
||||
type: "string"
|
||||
PID:
|
||||
type: "integer"
|
||||
ExitCode:
|
||||
type: "integer"
|
||||
|
||||
PortStatus:
|
||||
type: "object"
|
||||
description: "represents the port status of a task's host ports whose service has published host ports"
|
||||
properties:
|
||||
Ports:
|
||||
type: "array"
|
||||
items:
|
||||
$ref: "#/definitions/EndpointPortConfig"
|
||||
|
||||
TaskStatus:
|
||||
type: "object"
|
||||
description: "represents the status of a task."
|
||||
properties:
|
||||
Timestamp:
|
||||
type: "string"
|
||||
format: "dateTime"
|
||||
State:
|
||||
$ref: "#/definitions/TaskState"
|
||||
Message:
|
||||
type: "string"
|
||||
Err:
|
||||
type: "string"
|
||||
ContainerStatus:
|
||||
$ref: "#/definitions/ContainerStatus"
|
||||
PortStatus:
|
||||
$ref: "#/definitions/PortStatus"
|
||||
|
||||
Task:
|
||||
type: "object"
|
||||
properties:
|
||||
|
@ -4088,7 +3976,26 @@ definitions:
|
|||
AssignedGenericResources:
|
||||
$ref: "#/definitions/GenericResources"
|
||||
Status:
|
||||
$ref: "#/definitions/TaskStatus"
|
||||
type: "object"
|
||||
properties:
|
||||
Timestamp:
|
||||
type: "string"
|
||||
format: "dateTime"
|
||||
State:
|
||||
$ref: "#/definitions/TaskState"
|
||||
Message:
|
||||
type: "string"
|
||||
Err:
|
||||
type: "string"
|
||||
ContainerStatus:
|
||||
type: "object"
|
||||
properties:
|
||||
ContainerID:
|
||||
type: "string"
|
||||
PID:
|
||||
type: "integer"
|
||||
ExitCode:
|
||||
type: "integer"
|
||||
DesiredState:
|
||||
$ref: "#/definitions/TaskState"
|
||||
JobIteration:
|
||||
|
@ -4304,10 +4211,7 @@ definitions:
|
|||
- "stop-first"
|
||||
- "start-first"
|
||||
Networks:
|
||||
description: |
|
||||
Specifies which networks the service should attach to.
|
||||
|
||||
Deprecated: This field is deprecated since v1.44. The Networks field in TaskSpec should be used instead.
|
||||
description: "Specifies which networks the service should attach to."
|
||||
type: "array"
|
||||
items:
|
||||
$ref: "#/definitions/NetworkAttachmentConfig"
|
||||
|
@ -4541,7 +4445,6 @@ definitions:
|
|||
|
||||
ImageDeleteResponseItem:
|
||||
type: "object"
|
||||
x-go-name: "DeleteResponse"
|
||||
properties:
|
||||
Untagged:
|
||||
description: "The image ID of an image that was untagged"
|
||||
|
@ -4550,29 +4453,6 @@ definitions:
|
|||
description: "The image ID of an image that was deleted"
|
||||
type: "string"
|
||||
|
||||
ServiceCreateResponse:
|
||||
type: "object"
|
||||
description: |
|
||||
contains the information returned to a client on the
|
||||
creation of a new service.
|
||||
properties:
|
||||
ID:
|
||||
description: "The ID of the created service."
|
||||
type: "string"
|
||||
x-nullable: false
|
||||
example: "ak7w3gjqoa3kuz8xcpnyy0pvl"
|
||||
Warnings:
|
||||
description: |
|
||||
Optional warning message.
|
||||
|
||||
FIXME(thaJeztah): this should have "omitempty" in the generated type.
|
||||
type: "array"
|
||||
x-nullable: true
|
||||
items:
|
||||
type: "string"
|
||||
example:
|
||||
- "unable to pin image doesnotexist:latest to digest: image library/doesnotexist:latest not found"
|
||||
|
||||
ServiceUpdateResponse:
|
||||
type: "object"
|
||||
properties:
|
||||
|
@ -4582,8 +4462,7 @@ definitions:
|
|||
items:
|
||||
type: "string"
|
||||
example:
|
||||
Warnings:
|
||||
- "unable to pin image doesnotexist:latest to digest: image library/doesnotexist:latest not found"
|
||||
Warning: "unable to pin image doesnotexist:latest to digest: image library/doesnotexist:latest not found"
|
||||
|
||||
ContainerSummary:
|
||||
type: "object"
|
||||
|
@ -5189,7 +5068,7 @@ definitions:
|
|||
Go runtime (`GOOS`).
|
||||
|
||||
Currently returned values are "linux" and "windows". A full list of
|
||||
possible values can be found in the [Go documentation](https://go.dev/doc/install/source#environment).
|
||||
possible values can be found in the [Go documentation](https://golang.org/doc/install/source#environment).
|
||||
type: "string"
|
||||
example: "linux"
|
||||
Architecture:
|
||||
|
@ -5197,7 +5076,7 @@ definitions:
|
|||
Hardware architecture of the host, as returned by the Go runtime
|
||||
(`GOARCH`).
|
||||
|
||||
A full list of possible values can be found in the [Go documentation](https://go.dev/doc/install/source#environment).
|
||||
A full list of possible values can be found in the [Go documentation](https://golang.org/doc/install/source#environment).
|
||||
type: "string"
|
||||
example: "x86_64"
|
||||
NCPU:
|
||||
|
@ -5283,8 +5162,42 @@ definitions:
|
|||
ServerVersion:
|
||||
description: |
|
||||
Version string of the daemon.
|
||||
|
||||
> **Note**: the [standalone Swarm API](https://docs.docker.com/swarm/swarm-api/)
|
||||
> returns the Swarm version instead of the daemon version, for example
|
||||
> `swarm/1.2.8`.
|
||||
type: "string"
|
||||
example: "24.0.2"
|
||||
example: "17.06.0-ce"
|
||||
ClusterStore:
|
||||
description: |
|
||||
URL of the distributed storage backend.
|
||||
|
||||
|
||||
The storage backend is used for multihost networking (to store
|
||||
network and endpoint information) and by the node discovery mechanism.
|
||||
|
||||
<p><br /></p>
|
||||
|
||||
> **Deprecated**: This field is only propagated when using standalone Swarm
|
||||
> mode, and overlay networking using an external k/v store. Overlay
|
||||
> networks with Swarm mode enabled use the built-in raft store, and
|
||||
> this field will be empty.
|
||||
type: "string"
|
||||
example: "consul://consul.corp.example.com:8600/some/path"
|
||||
ClusterAdvertise:
|
||||
description: |
|
||||
The network endpoint that the Engine advertises for the purpose of
|
||||
node discovery. ClusterAdvertise is a `host:port` combination on which
|
||||
the daemon is reachable by other hosts.
|
||||
|
||||
<p><br /></p>
|
||||
|
||||
> **Deprecated**: This field is only propagated when using standalone Swarm
|
||||
> mode, and overlay networking using an external k/v store. Overlay
|
||||
> networks with Swarm mode enabled use the built-in raft store, and
|
||||
> this field will be empty.
|
||||
type: "string"
|
||||
example: "node5.corp.example.com:8000"
|
||||
Runtimes:
|
||||
description: |
|
||||
List of [OCI compliant](https://github.com/opencontainers/runtime-spec)
|
||||
|
@ -5417,25 +5330,7 @@ definitions:
|
|||
- "WARNING: No memory limit support"
|
||||
- "WARNING: bridge-nf-call-iptables is disabled"
|
||||
- "WARNING: bridge-nf-call-ip6tables is disabled"
|
||||
CDISpecDirs:
|
||||
description: |
|
||||
List of directories where (Container Device Interface) CDI
|
||||
specifications are located.
|
||||
|
||||
These specifications define vendor-specific modifications to an OCI
|
||||
runtime specification for a container being created.
|
||||
|
||||
An empty list indicates that CDI device injection is disabled.
|
||||
|
||||
Note that since using CDI device injection requires the daemon to have
|
||||
experimental enabled. For non-experimental daemons an empty list will
|
||||
always be returned.
|
||||
type: "array"
|
||||
items:
|
||||
type: "string"
|
||||
example:
|
||||
- "/etc/cdi"
|
||||
- "/var/run/cdi"
|
||||
|
||||
# PluginsInfo is a temp struct holding Plugins name
|
||||
# registered with docker daemon. It is used by Info struct
|
||||
|
@ -5473,7 +5368,7 @@ definitions:
|
|||
type: "array"
|
||||
items:
|
||||
type: "string"
|
||||
example: ["awslogs", "fluentd", "gcplogs", "gelf", "journald", "json-file", "splunk", "syslog"]
|
||||
example: ["awslogs", "fluentd", "gcplogs", "gelf", "journald", "json-file", "logentries", "splunk", "syslog"]
|
||||
|
||||
|
||||
RegistryServiceConfig:
|
||||
|
@ -5671,28 +5566,6 @@ definitions:
|
|||
items:
|
||||
type: "string"
|
||||
example: ["--debug", "--systemd-cgroup=false"]
|
||||
status:
|
||||
description: |
|
||||
Information specific to the runtime.
|
||||
|
||||
While this API specification does not define data provided by runtimes,
|
||||
the following well-known properties may be provided by runtimes:
|
||||
|
||||
`org.opencontainers.runtime-spec.features`: features structure as defined
|
||||
in the [OCI Runtime Specification](https://github.com/opencontainers/runtime-spec/blob/main/features.md),
|
||||
in a JSON string representation.
|
||||
|
||||
<p><br /></p>
|
||||
|
||||
> **Note**: The information returned in this field, including the
|
||||
> formatting of values and labels, should not be considered stable,
|
||||
> and may change without notice.
|
||||
type: "object"
|
||||
x-nullable: true
|
||||
additionalProperties:
|
||||
type: "string"
|
||||
example:
|
||||
"org.opencontainers.runtime-spec.features": "{\"ociVersionMin\":\"1.0.0\",\"ociVersionMax\":\"1.1.0\",\"...\":\"...\"}"
|
||||
|
||||
Commit:
|
||||
description: |
|
||||
|
@ -6577,7 +6450,6 @@ paths:
|
|||
Aliases:
|
||||
- "server_x"
|
||||
- "server_y"
|
||||
database_nw: {}
|
||||
|
||||
required: true
|
||||
responses:
|
||||
|
@ -6725,7 +6597,7 @@ paths:
|
|||
StopSignal: "SIGTERM"
|
||||
StopTimeout: 10
|
||||
Created: "2015-01-06T15:47:31.485331387Z"
|
||||
Driver: "overlay2"
|
||||
Driver: "devicemapper"
|
||||
ExecIDs:
|
||||
- "b35395de42bc8abd327f9dd65d913b9ba28c74d2f0734eeeae84fa1c616a0fca"
|
||||
- "3fc1232e5cd20c8de182ed81178503dc6437f4e7ef12b52cc5e8de020652f1c4"
|
||||
|
@ -8156,7 +8028,6 @@ paths:
|
|||
- `label=key` or `label="key=value"` of an image label
|
||||
- `reference`=(`<image-name>[:<tag>]`)
|
||||
- `since`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
|
||||
- `until=<timestamp>`
|
||||
type: "string"
|
||||
- name: "shared-size"
|
||||
in: "query"
|
||||
|
@ -8339,16 +8210,6 @@ paths:
|
|||
description: "BuildKit output configuration"
|
||||
type: "string"
|
||||
default: ""
|
||||
- name: "version"
|
||||
in: "query"
|
||||
type: "string"
|
||||
default: "1"
|
||||
enum: ["1", "2"]
|
||||
description: |
|
||||
Version of the builder backend to use.
|
||||
|
||||
- `1` is the first generation classic (deprecated) builder in the Docker daemon (default)
|
||||
- `2` is [BuildKit](https://github.com/moby/buildkit)
|
||||
responses:
|
||||
200:
|
||||
description: "no error"
|
||||
|
@ -8418,7 +8279,7 @@ paths:
|
|||
/images/create:
|
||||
post:
|
||||
summary: "Create an image"
|
||||
description: "Pull or import an image."
|
||||
description: "Create an image by either pulling it from a registry or importing it."
|
||||
operationId: "ImageCreate"
|
||||
consumes:
|
||||
- "text/plain"
|
||||
|
@ -8769,35 +8630,28 @@ paths:
|
|||
is_official:
|
||||
type: "boolean"
|
||||
is_automated:
|
||||
description: |
|
||||
Whether this repository has automated builds enabled.
|
||||
|
||||
<p><br /></p>
|
||||
|
||||
> **Deprecated**: This field is deprecated and will always be "false".
|
||||
type: "boolean"
|
||||
example: false
|
||||
name:
|
||||
type: "string"
|
||||
star_count:
|
||||
type: "integer"
|
||||
examples:
|
||||
application/json:
|
||||
- description: "A minimal Docker image based on Alpine Linux with a complete package index and only 5 MB in size!"
|
||||
is_official: true
|
||||
- description: ""
|
||||
is_official: false
|
||||
is_automated: false
|
||||
name: "alpine"
|
||||
star_count: 10093
|
||||
- description: "Busybox base image."
|
||||
is_official: true
|
||||
name: "wma55/u1210sshd"
|
||||
star_count: 0
|
||||
- description: ""
|
||||
is_official: false
|
||||
is_automated: false
|
||||
name: "Busybox base image."
|
||||
star_count: 3037
|
||||
- description: "The PostgreSQL object-relational database system provides reliability and data integrity."
|
||||
is_official: true
|
||||
name: "jdswinbank/sshd"
|
||||
star_count: 0
|
||||
- description: ""
|
||||
is_official: false
|
||||
is_automated: false
|
||||
name: "postgres"
|
||||
star_count: 12408
|
||||
name: "vgauthier/sshd"
|
||||
star_count: 0
|
||||
500:
|
||||
description: "Server error"
|
||||
schema:
|
||||
|
@ -8817,6 +8671,7 @@ paths:
|
|||
description: |
|
||||
A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters:
|
||||
|
||||
- `is-automated=(true|false)`
|
||||
- `is-official=(true|false)`
|
||||
- `stars=<number>` Matches images that has at least 'number' stars.
|
||||
type: "string"
|
||||
|
@ -9211,6 +9066,7 @@ paths:
|
|||
Created: 1466724217
|
||||
Size: 1092588
|
||||
SharedSize: 0
|
||||
VirtualSize: 1092588
|
||||
Labels: {}
|
||||
Containers: 1
|
||||
Containers:
|
||||
|
@ -10073,14 +9929,8 @@ paths:
|
|||
example:
|
||||
Id: "22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30"
|
||||
Warning: ""
|
||||
400:
|
||||
description: "bad parameter"
|
||||
schema:
|
||||
$ref: "#/definitions/ErrorResponse"
|
||||
403:
|
||||
description: |
|
||||
Forbidden operation. This happens when trying to create a network named after a pre-defined network,
|
||||
or when trying to create an overlay network on a daemon which is not part of a Swarm cluster.
|
||||
description: "operation not supported for pre-defined networks"
|
||||
schema:
|
||||
$ref: "#/definitions/ErrorResponse"
|
||||
404:
|
||||
|
@ -10106,7 +9956,13 @@ paths:
|
|||
type: "string"
|
||||
CheckDuplicate:
|
||||
description: |
|
||||
Deprecated: CheckDuplicate is now always enabled.
|
||||
Check for networks with duplicate names. Since Network is
|
||||
primarily keyed based on a random ID and not on the name, and
|
||||
network name is strictly a user-friendly alias to the network
|
||||
which is uniquely identified using ID, there is no guaranteed
|
||||
way to check for duplicates. CheckDuplicate is there to provide
|
||||
a best effort checking of any networks which has the same name
|
||||
but it is not guaranteed to catch all name collisions.
|
||||
type: "boolean"
|
||||
Driver:
|
||||
description: "Name of the network driver plugin to use."
|
||||
|
@ -10174,19 +10030,14 @@ paths:
|
|||
/networks/{id}/connect:
|
||||
post:
|
||||
summary: "Connect a container to a network"
|
||||
description: "The network must be either a local-scoped network or a swarm-scoped network with the `attachable` option set. A network cannot be re-attached to a running container"
|
||||
operationId: "NetworkConnect"
|
||||
consumes:
|
||||
- "application/json"
|
||||
responses:
|
||||
200:
|
||||
description: "No error"
|
||||
400:
|
||||
description: "bad parameter"
|
||||
schema:
|
||||
$ref: "#/definitions/ErrorResponse"
|
||||
403:
|
||||
description: "Operation forbidden"
|
||||
description: "Operation not supported for swarm scoped networks"
|
||||
schema:
|
||||
$ref: "#/definitions/ErrorResponse"
|
||||
404:
|
||||
|
@ -10221,7 +10072,6 @@ paths:
|
|||
IPAMConfig:
|
||||
IPv4Address: "172.24.56.89"
|
||||
IPv6Address: "2001:db8::5689"
|
||||
MacAddress: "02:42:ac:12:05:02"
|
||||
tags: ["Network"]
|
||||
|
||||
/networks/{id}/disconnect:
|
||||
|
@ -10543,12 +10393,6 @@ paths:
|
|||
default if omitted.
|
||||
required: true
|
||||
type: "string"
|
||||
- name: "force"
|
||||
in: "query"
|
||||
description: |
|
||||
Force disable a plugin even if still in use.
|
||||
required: false
|
||||
type: "boolean"
|
||||
tags: ["Plugin"]
|
||||
/plugins/{name}/upgrade:
|
||||
post:
|
||||
|
@ -11215,7 +11059,18 @@ paths:
|
|||
201:
|
||||
description: "no error"
|
||||
schema:
|
||||
$ref: "#/definitions/ServiceCreateResponse"
|
||||
type: "object"
|
||||
title: "ServiceCreateResponse"
|
||||
properties:
|
||||
ID:
|
||||
description: "The ID of the created service."
|
||||
type: "string"
|
||||
Warning:
|
||||
description: "Optional warning message"
|
||||
type: "string"
|
||||
example:
|
||||
ID: "ak7w3gjqoa3kuz8xcpnyy0pvl"
|
||||
Warning: "unable to pin image doesnotexist:latest to digest: image library/doesnotexist:latest not found"
|
||||
400:
|
||||
description: "bad parameter"
|
||||
schema:
|
||||
|
|
7
api/types/auth.go
Normal file
7
api/types/auth.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package types // import "github.com/docker/docker/api/types"
|
||||
import "github.com/docker/docker/api/types/registry"
|
||||
|
||||
// AuthConfig contains authorization information for connecting to a Registry.
|
||||
//
|
||||
// Deprecated: use github.com/docker/docker/api/types/registry.AuthConfig
|
||||
type AuthConfig = registry.AuthConfig
|
|
@ -5,29 +5,10 @@ import (
|
|||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// ContainerCreateConfig is the parameter set to ContainerCreate()
|
||||
type ContainerCreateConfig struct {
|
||||
Name string
|
||||
Config *container.Config
|
||||
HostConfig *container.HostConfig
|
||||
NetworkingConfig *network.NetworkingConfig
|
||||
Platform *ocispec.Platform
|
||||
DefaultReadOnlyNonRecursive bool
|
||||
}
|
||||
|
||||
// ContainerRmConfig holds arguments for the container remove
|
||||
// operation. This struct is used to tell the backend what operations
|
||||
// to perform.
|
||||
type ContainerRmConfig struct {
|
||||
ForceRemove, RemoveVolume, RemoveLink bool
|
||||
}
|
||||
|
||||
// ContainerAttachConfig holds the streams to use when connecting to a container to view logs.
|
||||
type ContainerAttachConfig struct {
|
||||
GetStreams func(multiplexed bool) (io.ReadCloser, io.Writer, io.Writer, error)
|
||||
|
@ -90,6 +71,7 @@ type ContainerStatsConfig struct {
|
|||
Stream bool
|
||||
OneShot bool
|
||||
OutStream io.Writer
|
||||
Version string
|
||||
}
|
||||
|
||||
// ExecInspect holds information about a running process started
|
||||
|
@ -129,13 +111,6 @@ type CreateImageConfig struct {
|
|||
Changes []string
|
||||
}
|
||||
|
||||
// GetImageOpts holds parameters to retrieve image information
|
||||
// from the backend.
|
||||
type GetImageOpts struct {
|
||||
Platform *ocispec.Platform
|
||||
Details bool
|
||||
}
|
||||
|
||||
// CommitConfig is the configuration for creating an image as part of a build.
|
||||
type CommitConfig struct {
|
||||
Author string
|
||||
|
@ -147,25 +122,3 @@ type CommitConfig struct {
|
|||
ContainerOS string
|
||||
ParentImageID string
|
||||
}
|
||||
|
||||
// PluginRmConfig holds arguments for plugin remove.
|
||||
type PluginRmConfig struct {
|
||||
ForceRemove bool
|
||||
}
|
||||
|
||||
// PluginEnableConfig holds arguments for plugin enable
|
||||
type PluginEnableConfig struct {
|
||||
Timeout int
|
||||
}
|
||||
|
||||
// PluginDisableConfig holds arguments for plugin disable.
|
||||
type PluginDisableConfig struct {
|
||||
ForceDisable bool
|
||||
}
|
||||
|
||||
// NetworkListConfig stores the options available for listing networks
|
||||
type NetworkListConfig struct {
|
||||
// TODO(@cpuguy83): naming is hard, this is pulled from what was being used in the router before moving here
|
||||
Detailed bool
|
||||
Verbose bool
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// PullOption defines different modes for accessing images
|
||||
|
@ -42,5 +42,5 @@ type GetImageAndLayerOptions struct {
|
|||
PullOption PullOption
|
||||
AuthConfig map[string]registry.AuthConfig
|
||||
Output io.Writer
|
||||
Platform *ocispec.Platform
|
||||
Platform *specs.Platform
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
package checkpoint
|
||||
|
||||
// Summary represents the details of a checkpoint when listing endpoints.
|
||||
type Summary struct {
|
||||
// Name is the name of the checkpoint.
|
||||
Name string
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package checkpoint
|
||||
|
||||
// CreateOptions holds parameters to create a checkpoint from a container.
|
||||
type CreateOptions struct {
|
||||
CheckpointID string
|
||||
CheckpointDir string
|
||||
Exit bool
|
||||
}
|
||||
|
||||
// ListOptions holds parameters to list checkpoints for a container.
|
||||
type ListOptions struct {
|
||||
CheckpointDir string
|
||||
}
|
||||
|
||||
// DeleteOptions holds parameters to delete a checkpoint from a container.
|
||||
type DeleteOptions struct {
|
||||
CheckpointID string
|
||||
CheckpointDir string
|
||||
}
|
|
@ -11,6 +11,44 @@ import (
|
|||
units "github.com/docker/go-units"
|
||||
)
|
||||
|
||||
// CheckpointCreateOptions holds parameters to create a checkpoint from a container
|
||||
type CheckpointCreateOptions struct {
|
||||
CheckpointID string
|
||||
CheckpointDir string
|
||||
Exit bool
|
||||
}
|
||||
|
||||
// CheckpointListOptions holds parameters to list checkpoints for a container
|
||||
type CheckpointListOptions struct {
|
||||
CheckpointDir string
|
||||
}
|
||||
|
||||
// CheckpointDeleteOptions holds parameters to delete a checkpoint from a container
|
||||
type CheckpointDeleteOptions struct {
|
||||
CheckpointID string
|
||||
CheckpointDir string
|
||||
}
|
||||
|
||||
// ContainerAttachOptions holds parameters to attach to a container.
|
||||
type ContainerAttachOptions struct {
|
||||
Stream bool
|
||||
Stdin bool
|
||||
Stdout bool
|
||||
Stderr bool
|
||||
DetachKeys string
|
||||
Logs bool
|
||||
}
|
||||
|
||||
// ContainerCommitOptions holds parameters to commit changes into a container.
|
||||
type ContainerCommitOptions struct {
|
||||
Reference string
|
||||
Comment string
|
||||
Author string
|
||||
Changes []string
|
||||
Pause bool
|
||||
Config *container.Config
|
||||
}
|
||||
|
||||
// ContainerExecInspect holds information returned by exec inspect.
|
||||
type ContainerExecInspect struct {
|
||||
ExecID string `json:"ID"`
|
||||
|
@ -20,6 +58,42 @@ type ContainerExecInspect struct {
|
|||
Pid int
|
||||
}
|
||||
|
||||
// ContainerListOptions holds parameters to list containers with.
|
||||
type ContainerListOptions struct {
|
||||
Size bool
|
||||
All bool
|
||||
Latest bool
|
||||
Since string
|
||||
Before string
|
||||
Limit int
|
||||
Filters filters.Args
|
||||
}
|
||||
|
||||
// ContainerLogsOptions holds parameters to filter logs with.
|
||||
type ContainerLogsOptions struct {
|
||||
ShowStdout bool
|
||||
ShowStderr bool
|
||||
Since string
|
||||
Until string
|
||||
Timestamps bool
|
||||
Follow bool
|
||||
Tail string
|
||||
Details bool
|
||||
}
|
||||
|
||||
// ContainerRemoveOptions holds parameters to remove containers.
|
||||
type ContainerRemoveOptions struct {
|
||||
RemoveVolumes bool
|
||||
RemoveLinks bool
|
||||
Force bool
|
||||
}
|
||||
|
||||
// ContainerStartOptions holds parameters to start containers.
|
||||
type ContainerStartOptions struct {
|
||||
CheckpointID string
|
||||
CheckpointDir string
|
||||
}
|
||||
|
||||
// CopyToContainerOptions holds information
|
||||
// about files to copy into a container
|
||||
type CopyToContainerOptions struct {
|
||||
|
@ -157,12 +231,42 @@ type ImageBuildResponse struct {
|
|||
OSType string
|
||||
}
|
||||
|
||||
// ImageCreateOptions holds information to create images.
|
||||
type ImageCreateOptions struct {
|
||||
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry.
|
||||
Platform string // Platform is the target platform of the image if it needs to be pulled from the registry.
|
||||
}
|
||||
|
||||
// ImageImportSource holds source information for ImageImport
|
||||
type ImageImportSource struct {
|
||||
Source io.Reader // Source is the data to send to the server to create this image from. You must set SourceName to "-" to leverage this.
|
||||
SourceName string // SourceName is the name of the image to pull. Set to "-" to leverage the Source attribute.
|
||||
}
|
||||
|
||||
// ImageImportOptions holds information to import images from the client host.
|
||||
type ImageImportOptions struct {
|
||||
Tag string // Tag is the name to tag this image with. This attribute is deprecated.
|
||||
Message string // Message is the message to tag the image with
|
||||
Changes []string // Changes are the raw changes to apply to this image
|
||||
Platform string // Platform is the target platform of the image
|
||||
}
|
||||
|
||||
// ImageListOptions holds parameters to list images with.
|
||||
type ImageListOptions struct {
|
||||
// All controls whether all images in the graph are filtered, or just
|
||||
// the heads.
|
||||
All bool
|
||||
|
||||
// Filters is a JSON-encoded set of filter arguments.
|
||||
Filters filters.Args
|
||||
|
||||
// SharedSize indicates whether the shared size of images should be computed.
|
||||
SharedSize bool
|
||||
|
||||
// ContainerCount indicates whether container count should be computed.
|
||||
ContainerCount bool
|
||||
}
|
||||
|
||||
// ImageLoadResponse returns information to the client about a load process.
|
||||
type ImageLoadResponse struct {
|
||||
// Body must be closed to avoid a resource leak
|
||||
|
@ -170,6 +274,14 @@ type ImageLoadResponse struct {
|
|||
JSON bool
|
||||
}
|
||||
|
||||
// ImagePullOptions holds information to pull images.
|
||||
type ImagePullOptions struct {
|
||||
All bool
|
||||
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
|
||||
PrivilegeFunc RequestPrivilegeFunc
|
||||
Platform string
|
||||
}
|
||||
|
||||
// RequestPrivilegeFunc is a function interface that
|
||||
// clients can supply to retry operations after
|
||||
// getting an authorization error.
|
||||
|
@ -178,6 +290,15 @@ type ImageLoadResponse struct {
|
|||
// if the privilege request fails.
|
||||
type RequestPrivilegeFunc func() (string, error)
|
||||
|
||||
// ImagePushOptions holds information to push images.
|
||||
type ImagePushOptions ImagePullOptions
|
||||
|
||||
// ImageRemoveOptions holds parameters to remove images.
|
||||
type ImageRemoveOptions struct {
|
||||
Force bool
|
||||
PruneChildren bool
|
||||
}
|
||||
|
||||
// ImageSearchOptions holds parameters to search images with.
|
||||
type ImageSearchOptions struct {
|
||||
RegistryAuth string
|
||||
|
@ -186,6 +307,14 @@ type ImageSearchOptions struct {
|
|||
Limit int
|
||||
}
|
||||
|
||||
// ResizeOptions holds parameters to resize a tty.
|
||||
// It can be used to resize container ttys and
|
||||
// exec process ttys too.
|
||||
type ResizeOptions struct {
|
||||
Height uint
|
||||
Width uint
|
||||
}
|
||||
|
||||
// NodeListOptions holds parameters to list nodes with.
|
||||
type NodeListOptions struct {
|
||||
Filters filters.Args
|
||||
|
@ -211,6 +340,15 @@ type ServiceCreateOptions struct {
|
|||
QueryRegistry bool
|
||||
}
|
||||
|
||||
// ServiceCreateResponse contains the information returned to a client
|
||||
// on the creation of a new service.
|
||||
type ServiceCreateResponse struct {
|
||||
// ID is the ID of the created service.
|
||||
ID string
|
||||
// Warnings is a set of non-fatal warning messages to pass on to the user.
|
||||
Warnings []string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Values for RegistryAuthFrom in ServiceUpdateOptions
|
||||
const (
|
||||
RegistryAuthFromSpec = "spec"
|
||||
|
|
|
@ -1,5 +1,32 @@
|
|||
package types // import "github.com/docker/docker/api/types"
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// configs holds structs used for internal communication between the
|
||||
// frontend (such as an http server) and the backend (such as the
|
||||
// docker daemon).
|
||||
|
||||
// ContainerCreateConfig is the parameter set to ContainerCreate()
|
||||
type ContainerCreateConfig struct {
|
||||
Name string
|
||||
Config *container.Config
|
||||
HostConfig *container.HostConfig
|
||||
NetworkingConfig *network.NetworkingConfig
|
||||
Platform *specs.Platform
|
||||
AdjustCPUShares bool
|
||||
}
|
||||
|
||||
// ContainerRmConfig holds arguments for the container remove
|
||||
// operation. This struct is used to tell the backend what operations
|
||||
// to perform.
|
||||
type ContainerRmConfig struct {
|
||||
ForceRemove, RemoveVolume, RemoveLink bool
|
||||
}
|
||||
|
||||
// ExecConfig is a small subset of the Config struct that holds the configuration
|
||||
// for the exec feature of docker.
|
||||
type ExecConfig struct {
|
||||
|
@ -16,3 +43,25 @@ type ExecConfig struct {
|
|||
WorkingDir string // Working directory
|
||||
Cmd []string // Execution commands and args
|
||||
}
|
||||
|
||||
// PluginRmConfig holds arguments for plugin remove.
|
||||
type PluginRmConfig struct {
|
||||
ForceRemove bool
|
||||
}
|
||||
|
||||
// PluginEnableConfig holds arguments for plugin enable
|
||||
type PluginEnableConfig struct {
|
||||
Timeout int
|
||||
}
|
||||
|
||||
// PluginDisableConfig holds arguments for plugin disable.
|
||||
type PluginDisableConfig struct {
|
||||
ForceDisable bool
|
||||
}
|
||||
|
||||
// NetworkListConfig stores the options available for listing networks
|
||||
type NetworkListConfig struct {
|
||||
// TODO(@cpuguy83): naming is hard, this is pulled from what was being used in the router before moving here
|
||||
Detailed bool
|
||||
Verbose bool
|
||||
}
|
||||
|
|
6
api/types/container/change_response_deprecated.go
Normal file
6
api/types/container/change_response_deprecated.go
Normal file
|
@ -0,0 +1,6 @@
|
|||
package container
|
||||
|
||||
// ContainerChangeResponseItem change item in response to ContainerChanges operation
|
||||
//
|
||||
// Deprecated: use [FilesystemChange].
|
||||
type ContainerChangeResponseItem = FilesystemChange
|
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
"github.com/docker/go-connections/nat"
|
||||
dockerspec "github.com/moby/docker-image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// MinimumDuration puts a minimum on user configured duration.
|
||||
|
@ -34,7 +33,25 @@ type StopOptions struct {
|
|||
}
|
||||
|
||||
// HealthConfig holds configuration settings for the HEALTHCHECK feature.
|
||||
type HealthConfig = dockerspec.HealthcheckConfig
|
||||
type HealthConfig struct {
|
||||
// Test is the test to perform to check that the container is healthy.
|
||||
// An empty slice means to inherit the default.
|
||||
// The options are:
|
||||
// {} : inherit healthcheck
|
||||
// {"NONE"} : disable healthcheck
|
||||
// {"CMD", args...} : exec arguments directly
|
||||
// {"CMD-SHELL", command} : run command with system's default shell
|
||||
Test []string `json:",omitempty"`
|
||||
|
||||
// Zero means to inherit. Durations are expressed as integer nanoseconds.
|
||||
Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks.
|
||||
Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung.
|
||||
StartPeriod time.Duration `json:",omitempty"` // The start period for the container to initialize before the retries starts to count down.
|
||||
|
||||
// Retries is the number of consecutive failures needed to consider a container as unhealthy.
|
||||
// Zero means inherit.
|
||||
Retries int `json:",omitempty"`
|
||||
}
|
||||
|
||||
// ExecStartOptions holds the options to start container's exec.
|
||||
type ExecStartOptions struct {
|
||||
|
@ -70,13 +87,10 @@ type Config struct {
|
|||
WorkingDir string // Current directory (PWD) in the command will be launched
|
||||
Entrypoint strslice.StrSlice // Entrypoint to run when starting the container
|
||||
NetworkDisabled bool `json:",omitempty"` // Is network disabled
|
||||
// Mac Address of the container.
|
||||
//
|
||||
// Deprecated: this field is deprecated since API v1.44. Use EndpointSettings.MacAddress instead.
|
||||
MacAddress string `json:",omitempty"`
|
||||
OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile
|
||||
Labels map[string]string // List of labels set to this container
|
||||
StopSignal string `json:",omitempty"` // Signal to stop a container
|
||||
StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container
|
||||
Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT
|
||||
MacAddress string `json:",omitempty"` // Mac Address of the container
|
||||
OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile
|
||||
Labels map[string]string // List of labels set to this container
|
||||
StopSignal string `json:",omitempty"` // Signal to stop a container
|
||||
StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container
|
||||
Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
package container
|
||||
|
||||
type errInvalidParameter struct{ error }
|
||||
|
||||
func (e *errInvalidParameter) InvalidParameter() {}
|
||||
|
||||
func (e *errInvalidParameter) Unwrap() error {
|
||||
return e.error
|
||||
}
|
|
@ -1,12 +1,10 @@
|
|||
package container // import "github.com/docker/docker/api/types/container"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types/blkiodev"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
"github.com/docker/go-connections/nat"
|
||||
units "github.com/docker/go-units"
|
||||
|
@ -134,12 +132,12 @@ type NetworkMode string
|
|||
|
||||
// IsNone indicates whether container isn't using a network stack.
|
||||
func (n NetworkMode) IsNone() bool {
|
||||
return n == network.NetworkNone
|
||||
return n == "none"
|
||||
}
|
||||
|
||||
// IsDefault indicates whether container uses the default network stack.
|
||||
func (n NetworkMode) IsDefault() bool {
|
||||
return n == network.NetworkDefault
|
||||
return n == "default"
|
||||
}
|
||||
|
||||
// IsPrivate indicates whether container uses its private network stack.
|
||||
|
@ -273,42 +271,33 @@ type DeviceMapping struct {
|
|||
|
||||
// RestartPolicy represents the restart policies of the container.
|
||||
type RestartPolicy struct {
|
||||
Name RestartPolicyMode
|
||||
Name string
|
||||
MaximumRetryCount int
|
||||
}
|
||||
|
||||
type RestartPolicyMode string
|
||||
|
||||
const (
|
||||
RestartPolicyDisabled RestartPolicyMode = "no"
|
||||
RestartPolicyAlways RestartPolicyMode = "always"
|
||||
RestartPolicyOnFailure RestartPolicyMode = "on-failure"
|
||||
RestartPolicyUnlessStopped RestartPolicyMode = "unless-stopped"
|
||||
)
|
||||
|
||||
// IsNone indicates whether the container has the "no" restart policy.
|
||||
// This means the container will not automatically restart when exiting.
|
||||
func (rp *RestartPolicy) IsNone() bool {
|
||||
return rp.Name == RestartPolicyDisabled || rp.Name == ""
|
||||
return rp.Name == "no" || rp.Name == ""
|
||||
}
|
||||
|
||||
// IsAlways indicates whether the container has the "always" restart policy.
|
||||
// This means the container will automatically restart regardless of the exit status.
|
||||
func (rp *RestartPolicy) IsAlways() bool {
|
||||
return rp.Name == RestartPolicyAlways
|
||||
return rp.Name == "always"
|
||||
}
|
||||
|
||||
// IsOnFailure indicates whether the container has the "on-failure" restart policy.
|
||||
// This means the container will automatically restart of exiting with a non-zero exit status.
|
||||
func (rp *RestartPolicy) IsOnFailure() bool {
|
||||
return rp.Name == RestartPolicyOnFailure
|
||||
return rp.Name == "on-failure"
|
||||
}
|
||||
|
||||
// IsUnlessStopped indicates whether the container has the
|
||||
// "unless-stopped" restart policy. This means the container will
|
||||
// automatically restart unless user has put it to stopped state.
|
||||
func (rp *RestartPolicy) IsUnlessStopped() bool {
|
||||
return rp.Name == RestartPolicyUnlessStopped
|
||||
return rp.Name == "unless-stopped"
|
||||
}
|
||||
|
||||
// IsSame compares two RestartPolicy to see if they are the same
|
||||
|
@ -316,33 +305,6 @@ func (rp *RestartPolicy) IsSame(tp *RestartPolicy) bool {
|
|||
return rp.Name == tp.Name && rp.MaximumRetryCount == tp.MaximumRetryCount
|
||||
}
|
||||
|
||||
// ValidateRestartPolicy validates the given RestartPolicy.
|
||||
func ValidateRestartPolicy(policy RestartPolicy) error {
|
||||
switch policy.Name {
|
||||
case RestartPolicyAlways, RestartPolicyUnlessStopped, RestartPolicyDisabled:
|
||||
if policy.MaximumRetryCount != 0 {
|
||||
msg := "invalid restart policy: maximum retry count can only be used with 'on-failure'"
|
||||
if policy.MaximumRetryCount < 0 {
|
||||
msg += " and cannot be negative"
|
||||
}
|
||||
return &errInvalidParameter{fmt.Errorf(msg)}
|
||||
}
|
||||
return nil
|
||||
case RestartPolicyOnFailure:
|
||||
if policy.MaximumRetryCount < 0 {
|
||||
return &errInvalidParameter{fmt.Errorf("invalid restart policy: maximum retry count cannot be negative")}
|
||||
}
|
||||
return nil
|
||||
case "":
|
||||
// Versions before v25.0.0 created an empty restart-policy "name" as
|
||||
// default. Allow an empty name with "any" MaximumRetryCount for
|
||||
// backward-compatibility.
|
||||
return nil
|
||||
default:
|
||||
return &errInvalidParameter{fmt.Errorf("invalid restart policy: unknown policy '%s'; use one of '%s', '%s', '%s', or '%s'", policy.Name, RestartPolicyDisabled, RestartPolicyAlways, RestartPolicyOnFailure, RestartPolicyUnlessStopped)}
|
||||
}
|
||||
}
|
||||
|
||||
// LogMode is a type to define the available modes for logging
|
||||
// These modes affect how logs are handled when log messages start piling up.
|
||||
type LogMode string
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/errdefs"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestValidateRestartPolicy(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input RestartPolicy
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
input: RestartPolicy{},
|
||||
},
|
||||
{
|
||||
name: "empty with invalid MaxRestartCount (for backward compatibility)",
|
||||
input: RestartPolicy{MaximumRetryCount: 123},
|
||||
expectedErr: "", // Allowed for backward compatibility
|
||||
},
|
||||
{
|
||||
name: "empty with negative MaxRestartCount)",
|
||||
input: RestartPolicy{MaximumRetryCount: -123},
|
||||
expectedErr: "", // Allowed for backward compatibility
|
||||
},
|
||||
{
|
||||
name: "always",
|
||||
input: RestartPolicy{Name: RestartPolicyAlways},
|
||||
},
|
||||
{
|
||||
name: "always with MaxRestartCount",
|
||||
input: RestartPolicy{Name: RestartPolicyAlways, MaximumRetryCount: 123},
|
||||
expectedErr: "invalid restart policy: maximum retry count can only be used with 'on-failure'",
|
||||
},
|
||||
{
|
||||
name: "always with negative MaxRestartCount",
|
||||
input: RestartPolicy{Name: RestartPolicyAlways, MaximumRetryCount: -123},
|
||||
expectedErr: "invalid restart policy: maximum retry count can only be used with 'on-failure' and cannot be negative",
|
||||
},
|
||||
{
|
||||
name: "unless-stopped",
|
||||
input: RestartPolicy{Name: RestartPolicyUnlessStopped},
|
||||
},
|
||||
{
|
||||
name: "unless-stopped with MaxRestartCount",
|
||||
input: RestartPolicy{Name: RestartPolicyUnlessStopped, MaximumRetryCount: 123},
|
||||
expectedErr: "invalid restart policy: maximum retry count can only be used with 'on-failure'",
|
||||
},
|
||||
{
|
||||
name: "unless-stopped with negative MaxRestartCount",
|
||||
input: RestartPolicy{Name: RestartPolicyUnlessStopped, MaximumRetryCount: -123},
|
||||
expectedErr: "invalid restart policy: maximum retry count can only be used with 'on-failure' and cannot be negative",
|
||||
},
|
||||
{
|
||||
name: "disabled",
|
||||
input: RestartPolicy{Name: RestartPolicyDisabled},
|
||||
},
|
||||
{
|
||||
name: "disabled with MaxRestartCount",
|
||||
input: RestartPolicy{Name: RestartPolicyDisabled, MaximumRetryCount: 123},
|
||||
expectedErr: "invalid restart policy: maximum retry count can only be used with 'on-failure'",
|
||||
},
|
||||
{
|
||||
name: "disabled with negative MaxRestartCount",
|
||||
input: RestartPolicy{Name: RestartPolicyDisabled, MaximumRetryCount: -123},
|
||||
expectedErr: "invalid restart policy: maximum retry count can only be used with 'on-failure' and cannot be negative",
|
||||
},
|
||||
{
|
||||
name: "on-failure",
|
||||
input: RestartPolicy{Name: RestartPolicyOnFailure},
|
||||
},
|
||||
{
|
||||
name: "on-failure with MaxRestartCount",
|
||||
input: RestartPolicy{Name: RestartPolicyOnFailure, MaximumRetryCount: 123},
|
||||
},
|
||||
{
|
||||
name: "on-failure with negative MaxRestartCount",
|
||||
input: RestartPolicy{Name: RestartPolicyOnFailure, MaximumRetryCount: -123},
|
||||
expectedErr: "invalid restart policy: maximum retry count cannot be negative",
|
||||
},
|
||||
{
|
||||
name: "unknown policy",
|
||||
input: RestartPolicy{Name: "unknown"},
|
||||
expectedErr: "invalid restart policy: unknown policy 'unknown'; use one of 'no', 'always', 'on-failure', or 'unless-stopped'",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := ValidateRestartPolicy(tc.input)
|
||||
if tc.expectedErr == "" {
|
||||
assert.Check(t, err)
|
||||
} else {
|
||||
assert.Check(t, is.ErrorType(err, errdefs.IsInvalidParameter))
|
||||
assert.Check(t, is.Error(err, tc.expectedErr))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,9 +1,8 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package container // import "github.com/docker/docker/api/types/container"
|
||||
|
||||
import "github.com/docker/docker/api/types/network"
|
||||
|
||||
// IsValid indicates if an isolation technology is valid
|
||||
func (i Isolation) IsValid() bool {
|
||||
return i.IsDefault()
|
||||
|
@ -12,15 +11,15 @@ func (i Isolation) IsValid() bool {
|
|||
// NetworkName returns the name of the network stack.
|
||||
func (n NetworkMode) NetworkName() string {
|
||||
if n.IsBridge() {
|
||||
return network.NetworkBridge
|
||||
return "bridge"
|
||||
} else if n.IsHost() {
|
||||
return network.NetworkHost
|
||||
return "host"
|
||||
} else if n.IsContainer() {
|
||||
return "container"
|
||||
} else if n.IsNone() {
|
||||
return network.NetworkNone
|
||||
return "none"
|
||||
} else if n.IsDefault() {
|
||||
return network.NetworkDefault
|
||||
return "default"
|
||||
} else if n.IsUserDefined() {
|
||||
return n.UserDefined()
|
||||
}
|
||||
|
@ -29,12 +28,12 @@ func (n NetworkMode) NetworkName() string {
|
|||
|
||||
// IsBridge indicates whether container uses the bridge network stack
|
||||
func (n NetworkMode) IsBridge() bool {
|
||||
return n == network.NetworkBridge
|
||||
return n == "bridge"
|
||||
}
|
||||
|
||||
// IsHost indicates whether container uses the host network stack.
|
||||
func (n NetworkMode) IsHost() bool {
|
||||
return n == network.NetworkHost
|
||||
return n == "host"
|
||||
}
|
||||
|
||||
// IsUserDefined indicates user-created network
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package container
|
||||
|
||||
|
@ -155,6 +156,7 @@ func TestUTSMode(t *testing.T) {
|
|||
assert.Check(t, is.Equal(mode.IsHost(), expected.host))
|
||||
assert.Check(t, is.Equal(mode.Valid(), expected.valid))
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,7 +223,7 @@ func TestRestartPolicy(t *testing.T) {
|
|||
{Name: "on-failure", MaximumRetryCount: 0}: {none: false, always: false, onFailure: true},
|
||||
}
|
||||
for policy, expected := range policies {
|
||||
t.Run("policy="+string(policy.Name), func(t *testing.T) {
|
||||
t.Run("policy="+policy.Name, func(t *testing.T) {
|
||||
assert.Check(t, is.Equal(policy.IsNone(), expected.none))
|
||||
assert.Check(t, is.Equal(policy.IsAlways(), expected.always))
|
||||
assert.Check(t, is.Equal(policy.IsOnFailure(), expected.onFailure))
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package container // import "github.com/docker/docker/api/types/container"
|
||||
|
||||
import "github.com/docker/docker/api/types/network"
|
||||
|
||||
// IsBridge indicates whether container uses the bridge network stack
|
||||
// in windows it is given the name NAT
|
||||
func (n NetworkMode) IsBridge() bool {
|
||||
return n == network.NetworkNat
|
||||
return n == "nat"
|
||||
}
|
||||
|
||||
// IsHost indicates whether container uses the host network stack.
|
||||
|
@ -27,11 +25,11 @@ func (i Isolation) IsValid() bool {
|
|||
// NetworkName returns the name of the network stack.
|
||||
func (n NetworkMode) NetworkName() string {
|
||||
if n.IsDefault() {
|
||||
return network.NetworkDefault
|
||||
return "default"
|
||||
} else if n.IsBridge() {
|
||||
return network.NetworkNat
|
||||
return "nat"
|
||||
} else if n.IsNone() {
|
||||
return network.NetworkNone
|
||||
return "none"
|
||||
} else if n.IsContainer() {
|
||||
return "container"
|
||||
} else if n.IsUserDefined() {
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
package container
|
||||
|
||||
import "github.com/docker/docker/api/types/filters"
|
||||
|
||||
// ResizeOptions holds parameters to resize a TTY.
|
||||
// It can be used to resize container TTYs and
|
||||
// exec process TTYs too.
|
||||
type ResizeOptions struct {
|
||||
Height uint
|
||||
Width uint
|
||||
}
|
||||
|
||||
// AttachOptions holds parameters to attach to a container.
|
||||
type AttachOptions struct {
|
||||
Stream bool
|
||||
Stdin bool
|
||||
Stdout bool
|
||||
Stderr bool
|
||||
DetachKeys string
|
||||
Logs bool
|
||||
}
|
||||
|
||||
// CommitOptions holds parameters to commit changes into a container.
|
||||
type CommitOptions struct {
|
||||
Reference string
|
||||
Comment string
|
||||
Author string
|
||||
Changes []string
|
||||
Pause bool
|
||||
Config *Config
|
||||
}
|
||||
|
||||
// RemoveOptions holds parameters to remove containers.
|
||||
type RemoveOptions struct {
|
||||
RemoveVolumes bool
|
||||
RemoveLinks bool
|
||||
Force bool
|
||||
}
|
||||
|
||||
// StartOptions holds parameters to start containers.
|
||||
type StartOptions struct {
|
||||
CheckpointID string
|
||||
CheckpointDir string
|
||||
}
|
||||
|
||||
// ListOptions holds parameters to list containers with.
|
||||
type ListOptions struct {
|
||||
Size bool
|
||||
All bool
|
||||
Latest bool
|
||||
Since string
|
||||
Before string
|
||||
Limit int
|
||||
Filters filters.Args
|
||||
}
|
||||
|
||||
// LogsOptions holds parameters to filter logs with.
|
||||
type LogsOptions struct {
|
||||
ShowStdout bool
|
||||
ShowStderr bool
|
||||
Since string
|
||||
Until string
|
||||
Timestamps bool
|
||||
Follow bool
|
||||
Tail string
|
||||
Details bool
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package events // import "github.com/docker/docker/api/types/events"
|
||||
|
||||
// Type is used for event-types.
|
||||
type Type string
|
||||
type Type = string
|
||||
|
||||
// List of known event types.
|
||||
const (
|
||||
|
@ -18,86 +18,6 @@ const (
|
|||
VolumeEventType Type = "volume" // VolumeEventType is the event type that volumes generate.
|
||||
)
|
||||
|
||||
// Action is used for event-actions.
|
||||
type Action string
|
||||
|
||||
const (
|
||||
ActionCreate Action = "create"
|
||||
ActionStart Action = "start"
|
||||
ActionRestart Action = "restart"
|
||||
ActionStop Action = "stop"
|
||||
ActionCheckpoint Action = "checkpoint"
|
||||
ActionPause Action = "pause"
|
||||
ActionUnPause Action = "unpause"
|
||||
ActionAttach Action = "attach"
|
||||
ActionDetach Action = "detach"
|
||||
ActionResize Action = "resize"
|
||||
ActionUpdate Action = "update"
|
||||
ActionRename Action = "rename"
|
||||
ActionKill Action = "kill"
|
||||
ActionDie Action = "die"
|
||||
ActionOOM Action = "oom"
|
||||
ActionDestroy Action = "destroy"
|
||||
ActionRemove Action = "remove"
|
||||
ActionCommit Action = "commit"
|
||||
ActionTop Action = "top"
|
||||
ActionCopy Action = "copy"
|
||||
ActionArchivePath Action = "archive-path"
|
||||
ActionExtractToDir Action = "extract-to-dir"
|
||||
ActionExport Action = "export"
|
||||
ActionImport Action = "import"
|
||||
ActionSave Action = "save"
|
||||
ActionLoad Action = "load"
|
||||
ActionTag Action = "tag"
|
||||
ActionUnTag Action = "untag"
|
||||
ActionPush Action = "push"
|
||||
ActionPull Action = "pull"
|
||||
ActionPrune Action = "prune"
|
||||
ActionDelete Action = "delete"
|
||||
ActionEnable Action = "enable"
|
||||
ActionDisable Action = "disable"
|
||||
ActionConnect Action = "connect"
|
||||
ActionDisconnect Action = "disconnect"
|
||||
ActionReload Action = "reload"
|
||||
ActionMount Action = "mount"
|
||||
ActionUnmount Action = "unmount"
|
||||
|
||||
// ActionExecCreate is the prefix used for exec_create events. These
|
||||
// event-actions are commonly followed by a colon and space (": "),
|
||||
// and the command that's defined for the exec, for example:
|
||||
//
|
||||
// exec_create: /bin/sh -c 'echo hello'
|
||||
//
|
||||
// This is far from ideal; it's a compromise to allow filtering and
|
||||
// to preserve backward-compatibility.
|
||||
ActionExecCreate Action = "exec_create"
|
||||
// ActionExecStart is the prefix used for exec_create events. These
|
||||
// event-actions are commonly followed by a colon and space (": "),
|
||||
// and the command that's defined for the exec, for example:
|
||||
//
|
||||
// exec_start: /bin/sh -c 'echo hello'
|
||||
//
|
||||
// This is far from ideal; it's a compromise to allow filtering and
|
||||
// to preserve backward-compatibility.
|
||||
ActionExecStart Action = "exec_start"
|
||||
ActionExecDie Action = "exec_die"
|
||||
ActionExecDetach Action = "exec_detach"
|
||||
|
||||
// ActionHealthStatus is the prefix to use for health_status events.
|
||||
//
|
||||
// Health-status events can either have a pre-defined status, in which
|
||||
// case the "health_status" action is followed by a colon, or can be
|
||||
// "free-form", in which case they're followed by the output of the
|
||||
// health-check output.
|
||||
//
|
||||
// This is far form ideal, and a compromise to allow filtering, and
|
||||
// to preserve backward-compatibility.
|
||||
ActionHealthStatus Action = "health_status"
|
||||
ActionHealthStatusRunning Action = "health_status: running"
|
||||
ActionHealthStatusHealthy Action = "health_status: healthy"
|
||||
ActionHealthStatusUnhealthy Action = "health_status: unhealthy"
|
||||
)
|
||||
|
||||
// Actor describes something that generates events,
|
||||
// like a container, or a network, or a volume.
|
||||
// It has a defined name and a set of attributes.
|
||||
|
@ -117,7 +37,7 @@ type Message struct {
|
|||
From string `json:"from,omitempty"` // Deprecated: use Actor.Attributes["image"] instead.
|
||||
|
||||
Type Type
|
||||
Action Action
|
||||
Action string
|
||||
Actor Actor
|
||||
// Engine events are local scope. Cluster events are swarm scope.
|
||||
Scope string `json:"scope,omitempty"`
|
||||
|
|
|
@ -98,7 +98,7 @@ func FromJSON(p string) (Args, error) {
|
|||
// Fallback to parsing arguments in the legacy slice format
|
||||
deprecated := map[string][]string{}
|
||||
if legacyErr := json.Unmarshal(raw, &deprecated); legacyErr != nil {
|
||||
return args, &invalidFilter{}
|
||||
return args, invalidFilter{}
|
||||
}
|
||||
|
||||
args.fields = deprecatedArgs(deprecated)
|
||||
|
@ -206,7 +206,7 @@ func (args Args) GetBoolOrDefault(key string, defaultValue bool) (bool, error) {
|
|||
}
|
||||
|
||||
if len(fieldValues) == 0 {
|
||||
return defaultValue, &invalidFilter{key, nil}
|
||||
return defaultValue, invalidFilter{key, nil}
|
||||
}
|
||||
|
||||
isFalse := fieldValues["0"] || fieldValues["false"]
|
||||
|
@ -216,7 +216,7 @@ func (args Args) GetBoolOrDefault(key string, defaultValue bool) (bool, error) {
|
|||
invalid := !isFalse && !isTrue
|
||||
|
||||
if conflicting || invalid {
|
||||
return defaultValue, &invalidFilter{key, args.Get(key)}
|
||||
return defaultValue, invalidFilter{key, args.Get(key)}
|
||||
} else if isFalse {
|
||||
return false, nil
|
||||
} else if isTrue {
|
||||
|
@ -224,7 +224,7 @@ func (args Args) GetBoolOrDefault(key string, defaultValue bool) (bool, error) {
|
|||
}
|
||||
|
||||
// This code shouldn't be reached.
|
||||
return defaultValue, &unreachableCode{Filter: key, Value: args.Get(key)}
|
||||
return defaultValue, unreachableCode{Filter: key, Value: args.Get(key)}
|
||||
}
|
||||
|
||||
// ExactMatch returns true if the source matches exactly one of the values.
|
||||
|
@ -282,7 +282,7 @@ func (args Args) Contains(field string) bool {
|
|||
func (args Args) Validate(accepted map[string]bool) error {
|
||||
for name := range args.fields {
|
||||
if !accepted[name] {
|
||||
return &invalidFilter{name, nil}
|
||||
return invalidFilter{name, nil}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -3,7 +3,6 @@ package filters // import "github.com/docker/docker/api/types/filters"
|
|||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
|
@ -96,19 +95,15 @@ func TestFromJSON(t *testing.T) {
|
|||
if err == nil {
|
||||
t.Fatalf("Expected an error with %v, got nothing", invalid)
|
||||
}
|
||||
var invalidFilterError *invalidFilter
|
||||
var invalidFilterError invalidFilter
|
||||
if !errors.As(err, &invalidFilterError) {
|
||||
t.Fatalf("Expected an invalidFilter error, got %T", err)
|
||||
}
|
||||
wrappedErr := fmt.Errorf("something went wrong: %w", err)
|
||||
if !errors.Is(wrappedErr, err) {
|
||||
t.Errorf("Expected a wrapped error to be detected as invalidFilter")
|
||||
}
|
||||
}
|
||||
|
||||
for expectedArgs, matchers := range valid {
|
||||
for _, jsonString := range matchers {
|
||||
args, err := FromJSON(jsonString)
|
||||
for _, json := range matchers {
|
||||
args, err := FromJSON(json)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -169,17 +164,13 @@ func TestArgsMatchKVList(t *testing.T) {
|
|||
|
||||
matches := map[*Args]string{
|
||||
{}: "field",
|
||||
{
|
||||
map[string]map[string]bool{
|
||||
"created": {"today": true},
|
||||
"labels": {"key1": true},
|
||||
},
|
||||
{map[string]map[string]bool{
|
||||
"created": {"today": true},
|
||||
"labels": {"key1": true}},
|
||||
}: "labels",
|
||||
{
|
||||
map[string]map[string]bool{
|
||||
"created": {"today": true},
|
||||
"labels": {"key1=value1": true},
|
||||
},
|
||||
{map[string]map[string]bool{
|
||||
"created": {"today": true},
|
||||
"labels": {"key1=value1": true}},
|
||||
}: "labels",
|
||||
}
|
||||
|
||||
|
@ -190,22 +181,16 @@ func TestArgsMatchKVList(t *testing.T) {
|
|||
}
|
||||
|
||||
differs := map[*Args]string{
|
||||
{
|
||||
map[string]map[string]bool{
|
||||
"created": {"today": true},
|
||||
},
|
||||
{map[string]map[string]bool{
|
||||
"created": {"today": true}},
|
||||
}: "created",
|
||||
{
|
||||
map[string]map[string]bool{
|
||||
"created": {"today": true},
|
||||
"labels": {"key4": true},
|
||||
},
|
||||
{map[string]map[string]bool{
|
||||
"created": {"today": true},
|
||||
"labels": {"key4": true}},
|
||||
}: "labels",
|
||||
{
|
||||
map[string]map[string]bool{
|
||||
"created": {"today": true},
|
||||
"labels": {"key1=value3": true},
|
||||
},
|
||||
{map[string]map[string]bool{
|
||||
"created": {"today": true},
|
||||
"labels": {"key1=value3": true}},
|
||||
}: "labels",
|
||||
}
|
||||
|
||||
|
@ -221,30 +206,20 @@ func TestArgsMatch(t *testing.T) {
|
|||
|
||||
matches := map[*Args]string{
|
||||
{}: "field",
|
||||
{
|
||||
map[string]map[string]bool{
|
||||
"created": {"today": true},
|
||||
},
|
||||
{map[string]map[string]bool{
|
||||
"created": {"today": true}},
|
||||
}: "today",
|
||||
{
|
||||
map[string]map[string]bool{
|
||||
"created": {"to*": true},
|
||||
},
|
||||
{map[string]map[string]bool{
|
||||
"created": {"to*": true}},
|
||||
}: "created",
|
||||
{
|
||||
map[string]map[string]bool{
|
||||
"created": {"to(.*)": true},
|
||||
},
|
||||
{map[string]map[string]bool{
|
||||
"created": {"to(.*)": true}},
|
||||
}: "created",
|
||||
{
|
||||
map[string]map[string]bool{
|
||||
"created": {"tod": true},
|
||||
},
|
||||
{map[string]map[string]bool{
|
||||
"created": {"tod": true}},
|
||||
}: "created",
|
||||
{
|
||||
map[string]map[string]bool{
|
||||
"created": {"anything": true, "to*": true},
|
||||
},
|
||||
{map[string]map[string]bool{
|
||||
"created": {"anything": true, "to*": true}},
|
||||
}: "created",
|
||||
}
|
||||
|
||||
|
@ -254,31 +229,21 @@ func TestArgsMatch(t *testing.T) {
|
|||
}
|
||||
|
||||
differs := map[*Args]string{
|
||||
{
|
||||
map[string]map[string]bool{
|
||||
"created": {"tomorrow": true},
|
||||
},
|
||||
{map[string]map[string]bool{
|
||||
"created": {"tomorrow": true}},
|
||||
}: "created",
|
||||
{
|
||||
map[string]map[string]bool{
|
||||
"created": {"to(day": true},
|
||||
},
|
||||
{map[string]map[string]bool{
|
||||
"created": {"to(day": true}},
|
||||
}: "created",
|
||||
{
|
||||
map[string]map[string]bool{
|
||||
"created": {"tom(.*)": true},
|
||||
},
|
||||
{map[string]map[string]bool{
|
||||
"created": {"tom(.*)": true}},
|
||||
}: "created",
|
||||
{
|
||||
map[string]map[string]bool{
|
||||
"created": {"tom": true},
|
||||
},
|
||||
{map[string]map[string]bool{
|
||||
"created": {"tom": true}},
|
||||
}: "created",
|
||||
{
|
||||
map[string]map[string]bool{
|
||||
"created": {"today1": true},
|
||||
"labels": {"today": true},
|
||||
},
|
||||
{map[string]map[string]bool{
|
||||
"created": {"today1": true},
|
||||
"labels": {"today": true}},
|
||||
}: "created",
|
||||
}
|
||||
|
||||
|
@ -393,13 +358,9 @@ func TestValidate(t *testing.T) {
|
|||
if err == nil {
|
||||
t.Fatal("Expected to return an error, got nil")
|
||||
}
|
||||
var invalidFilterError *invalidFilter
|
||||
var invalidFilterError invalidFilter
|
||||
if !errors.As(err, &invalidFilterError) {
|
||||
t.Errorf("Expected an invalidFilter error, got %T", err)
|
||||
}
|
||||
wrappedErr := fmt.Errorf("something went wrong: %w", err)
|
||||
if !errors.Is(wrappedErr, err) {
|
||||
t.Errorf("Expected a wrapped error to be detected as invalidFilter")
|
||||
t.Fatalf("Expected an invalidFilter error, got %T", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -460,7 +421,7 @@ func TestClone(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetBoolOrDefault(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
for _, tC := range []struct {
|
||||
name string
|
||||
args map[string][]string
|
||||
defValue bool
|
||||
|
@ -491,7 +452,7 @@ func TestGetBoolOrDefault(t *testing.T) {
|
|||
"dangling": {"potato"},
|
||||
},
|
||||
defValue: true,
|
||||
expectedErr: &invalidFilter{Filter: "dangling", Value: []string{"potato"}},
|
||||
expectedErr: invalidFilter{Filter: "dangling", Value: []string{"potato"}},
|
||||
expectedValue: true,
|
||||
},
|
||||
{
|
||||
|
@ -500,7 +461,7 @@ func TestGetBoolOrDefault(t *testing.T) {
|
|||
"dangling": {"banana", "potato"},
|
||||
},
|
||||
defValue: true,
|
||||
expectedErr: &invalidFilter{Filter: "dangling", Value: []string{"banana", "potato"}},
|
||||
expectedErr: invalidFilter{Filter: "dangling", Value: []string{"banana", "potato"}},
|
||||
expectedValue: true,
|
||||
},
|
||||
{
|
||||
|
@ -509,7 +470,7 @@ func TestGetBoolOrDefault(t *testing.T) {
|
|||
"dangling": {"false", "true"},
|
||||
},
|
||||
defValue: false,
|
||||
expectedErr: &invalidFilter{Filter: "dangling", Value: []string{"false", "true"}},
|
||||
expectedErr: invalidFilter{Filter: "dangling", Value: []string{"false", "true"}},
|
||||
expectedValue: false,
|
||||
},
|
||||
{
|
||||
|
@ -518,7 +479,7 @@ func TestGetBoolOrDefault(t *testing.T) {
|
|||
"dangling": {"false", "true", "1"},
|
||||
},
|
||||
defValue: true,
|
||||
expectedErr: &invalidFilter{Filter: "dangling", Value: []string{"false", "true", "1"}},
|
||||
expectedErr: invalidFilter{Filter: "dangling", Value: []string{"false", "true", "1"}},
|
||||
expectedValue: true,
|
||||
},
|
||||
{
|
||||
|
@ -540,38 +501,36 @@ func TestGetBoolOrDefault(t *testing.T) {
|
|||
expectedValue: false,
|
||||
},
|
||||
} {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tC := tC
|
||||
t.Run(tC.name, func(t *testing.T) {
|
||||
a := NewArgs()
|
||||
|
||||
for key, values := range tc.args {
|
||||
for key, values := range tC.args {
|
||||
for _, value := range values {
|
||||
a.Add(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
value, err := a.GetBoolOrDefault("dangling", tc.defValue)
|
||||
value, err := a.GetBoolOrDefault("dangling", tC.defValue)
|
||||
|
||||
if tc.expectedErr == nil {
|
||||
if tC.expectedErr == nil {
|
||||
assert.Check(t, is.Nil(err))
|
||||
} else {
|
||||
assert.Check(t, is.ErrorType(err, tc.expectedErr))
|
||||
assert.Check(t, is.ErrorType(err, tC.expectedErr))
|
||||
|
||||
// Check if error is the same.
|
||||
expected := tc.expectedErr.(*invalidFilter)
|
||||
actual := err.(*invalidFilter)
|
||||
expected := tC.expectedErr.(invalidFilter)
|
||||
actual := err.(invalidFilter)
|
||||
|
||||
assert.Check(t, is.Equal(expected.Filter, actual.Filter))
|
||||
|
||||
sort.Strings(expected.Value)
|
||||
sort.Strings(actual.Value)
|
||||
assert.Check(t, is.DeepEqual(expected.Value, actual.Value))
|
||||
|
||||
wrappedErr := fmt.Errorf("something went wrong: %w", err)
|
||||
assert.Check(t, errors.Is(wrappedErr, err), "Expected a wrapped error to be detected as invalidFilter")
|
||||
}
|
||||
|
||||
assert.Check(t, is.Equal(tc.expectedValue, value))
|
||||
assert.Check(t, is.Equal(tC.expectedValue, value))
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
package image
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
// DeleteResponse delete response
|
||||
// swagger:model DeleteResponse
|
||||
type DeleteResponse struct {
|
||||
|
||||
// The image ID of an image that was deleted
|
||||
Deleted string `json:"Deleted,omitempty"`
|
||||
|
||||
// The image ID of an image that was untagged
|
||||
Untagged string `json:"Untagged,omitempty"`
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package image
|
||||
|
||||
import "time"
|
||||
|
||||
// Metadata contains engine-local data about the image.
|
||||
type Metadata struct {
|
||||
// LastTagTime is the date and time at which the image was last tagged.
|
||||
LastTagTime time.Time `json:",omitempty"`
|
||||
}
|
|
@ -1,57 +1,9 @@
|
|||
package image
|
||||
|
||||
import "github.com/docker/docker/api/types/filters"
|
||||
import specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
||||
// ImportOptions holds information to import images from the client host.
|
||||
type ImportOptions struct {
|
||||
Tag string // Tag is the name to tag this image with. This attribute is deprecated.
|
||||
Message string // Message is the message to tag the image with
|
||||
Changes []string // Changes are the raw changes to apply to this image
|
||||
Platform string // Platform is the target platform of the image
|
||||
}
|
||||
|
||||
// CreateOptions holds information to create images.
|
||||
type CreateOptions struct {
|
||||
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry.
|
||||
Platform string // Platform is the target platform of the image if it needs to be pulled from the registry.
|
||||
}
|
||||
|
||||
// PullOptions holds information to pull images.
|
||||
type PullOptions struct {
|
||||
All bool
|
||||
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
|
||||
|
||||
// PrivilegeFunc is a function that clients can supply to retry operations
|
||||
// after getting an authorization error. This function returns the registry
|
||||
// authentication header value in base64 encoded format, or an error if the
|
||||
// privilege request fails.
|
||||
//
|
||||
// Also see [github.com/docker/docker/api/types.RequestPrivilegeFunc].
|
||||
PrivilegeFunc func() (string, error)
|
||||
Platform string
|
||||
}
|
||||
|
||||
// PushOptions holds information to push images.
|
||||
type PushOptions PullOptions
|
||||
|
||||
// ListOptions holds parameters to list images with.
|
||||
type ListOptions struct {
|
||||
// All controls whether all images in the graph are filtered, or just
|
||||
// the heads.
|
||||
All bool
|
||||
|
||||
// Filters is a JSON-encoded set of filter arguments.
|
||||
Filters filters.Args
|
||||
|
||||
// SharedSize indicates whether the shared size of images should be computed.
|
||||
SharedSize bool
|
||||
|
||||
// ContainerCount indicates whether container count should be computed.
|
||||
ContainerCount bool
|
||||
}
|
||||
|
||||
// RemoveOptions holds parameters to remove images.
|
||||
type RemoveOptions struct {
|
||||
Force bool
|
||||
PruneChildren bool
|
||||
// GetImageOpts holds parameters to inspect an image.
|
||||
type GetImageOpts struct {
|
||||
Platform *specs.Platform
|
||||
Details bool
|
||||
}
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
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
|
||||
// containers.
|
||||
//
|
||||
// This size is not calculated by default, and depends on which API endpoint
|
||||
// is used. `-1` indicates that the value has not been set / calculated.
|
||||
//
|
||||
// Required: true
|
||||
Containers int64 `json:"Containers"`
|
||||
|
||||
// Date and time at which the image was created as a Unix timestamp
|
||||
// (number of seconds sinds EPOCH).
|
||||
//
|
||||
// Required: true
|
||||
Created int64 `json:"Created"`
|
||||
|
||||
// ID is the content-addressable ID of an image.
|
||||
//
|
||||
// This identifier is a content-addressable digest calculated from the
|
||||
// image's configuration (which includes the digests of layers used by
|
||||
// the image).
|
||||
//
|
||||
// Note that this digest differs from the `RepoDigests` below, which
|
||||
// holds digests of image manifests that reference the image.
|
||||
//
|
||||
// Required: true
|
||||
ID string `json:"Id"`
|
||||
|
||||
// User-defined key/value metadata.
|
||||
// Required: true
|
||||
Labels map[string]string `json:"Labels"`
|
||||
|
||||
// ID of the parent image.
|
||||
//
|
||||
// Depending on how the image was created, this field may be empty and
|
||||
// is only set for images that were built/created locally. This field
|
||||
// is empty if the image was pulled from an image registry.
|
||||
//
|
||||
// Required: true
|
||||
ParentID string `json:"ParentId"`
|
||||
|
||||
// List of content-addressable digests of locally available image manifests
|
||||
// that the image is referenced from. Multiple manifests can refer to the
|
||||
// same image.
|
||||
//
|
||||
// These digests are usually only available if the image was either pulled
|
||||
// from a registry, or if the image was pushed to a registry, which is when
|
||||
// the manifest is generated and its digest calculated.
|
||||
//
|
||||
// Required: true
|
||||
RepoDigests []string `json:"RepoDigests"`
|
||||
|
||||
// List of image names/tags in the local image cache that reference this
|
||||
// image.
|
||||
//
|
||||
// Multiple image tags can refer to the same image, and this list may be
|
||||
// empty if no tags reference the image, in which case the image is
|
||||
// "untagged", in which case it can still be referenced by its ID.
|
||||
//
|
||||
// Required: true
|
||||
RepoTags []string `json:"RepoTags"`
|
||||
|
||||
// Total size of image layers that are shared between this image and other
|
||||
// images.
|
||||
//
|
||||
// This size is not calculated by default. `-1` indicates that the value
|
||||
// has not been set / calculated.
|
||||
//
|
||||
// Required: true
|
||||
SharedSize int64 `json:"SharedSize"`
|
||||
|
||||
// Total size of the image including all layers it is composed of.
|
||||
//
|
||||
// Required: true
|
||||
Size int64 `json:"Size"`
|
||||
|
||||
// Total size of the image including all layers it is composed of.
|
||||
//
|
||||
// Deprecated: this field is omitted in API v1.44, but kept for backward compatibility. Use Size instead.
|
||||
VirtualSize int64 `json:"VirtualSize,omitempty"`
|
||||
}
|
15
api/types/image_delete_response_item.go
Normal file
15
api/types/image_delete_response_item.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package types
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
// ImageDeleteResponseItem image delete response item
|
||||
// swagger:model ImageDeleteResponseItem
|
||||
type ImageDeleteResponseItem struct {
|
||||
|
||||
// The image ID of an image that was deleted
|
||||
Deleted string `json:"Deleted,omitempty"`
|
||||
|
||||
// The image ID of an image that was untagged
|
||||
Untagged string `json:"Untagged,omitempty"`
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue