Compare commits

...

227 Commits

Author SHA1 Message Date
fa84cfd802 Merge pull request #4950 from vvoland/vendor-docker-26.0.0-rc3-dev
Some checks failed
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / e2e (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / e2e (alpine, 23, experimental) (push) Has been cancelled
e2e / e2e (alpine, 23, non-experimental) (push) Has been cancelled
e2e / e2e (alpine, 24, connhelper-ssh) (push) Has been cancelled
e2e / e2e (alpine, 24, experimental) (push) Has been cancelled
e2e / e2e (alpine, 24, non-experimental) (push) Has been cancelled
e2e / e2e (alpine, 25, connhelper-ssh) (push) Has been cancelled
e2e / e2e (alpine, 25, experimental) (push) Has been cancelled
e2e / e2e (alpine, 25, non-experimental) (push) Has been cancelled
e2e / e2e (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / e2e (debian, 23, experimental) (push) Has been cancelled
e2e / e2e (debian, 23, non-experimental) (push) Has been cancelled
e2e / e2e (debian, 24, connhelper-ssh) (push) Has been cancelled
e2e / e2e (debian, 24, experimental) (push) Has been cancelled
e2e / e2e (debian, 24, non-experimental) (push) Has been cancelled
e2e / e2e (debian, 25, connhelper-ssh) (push) Has been cancelled
e2e / e2e (debian, 25, experimental) (push) Has been cancelled
e2e / e2e (debian, 25, non-experimental) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-12) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
vendor: github.com/docker/docker 330d777c53fb (v26.0.0-rc3-dev)
2024-03-19 14:40:12 +01:00
b70a26deaf vendor: github.com/docker/docker 330d777c53fb (v26.0.0-rc3-dev)
full diff: 70e46f2c7c...330d777c53

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-03-19 14:31:41 +01:00
23563728bc Merge pull request #4944 from thaJeztah/update_engine
vendor: github.com/docker/docker 70e46f2c7c2d (v26.0.0-rc3-dev)
2024-03-19 11:00:31 +01:00
ea3201c575 Merge pull request #4945 from thaJeztah/remove_gocompat
scripts/vendor: remove -compat=1.19
2024-03-18 12:29:42 +01:00
c050bf0909 Merge pull request #4946 from thaJeztah/bump_gofumpt
Dockerfile: update mvdan/gofumpt to v0.6.0
2024-03-18 12:24:26 +01:00
4eef4afbf4 Merge pull request #4893 from vvoland/deprecate-container
docs/deprecated: Deprecate Container fields in image inspect
2024-03-18 12:14:10 +01:00
396a0823f8 Merge pull request #4947 from thaJeztah/fix_codeql
ci: fix CodeQL 2.16.4 autobuild
2024-03-18 12:07:08 +01:00
b120b96ac7 ci: set DISABLE_WARN_OUTSIDE_CONTAINER=1 for CodeQL action
CodeQL autobuild uses the makefile, but outside of a container, so let's
set this variable to prevent it having to wait 10 seconds;

    Use "make dev" to start an interactive development container,
    use "make -f docker.Makefile " to execute this target
    in a container, or set DISABLE_WARN_OUTSIDE_CONTAINER=1 to
    disable this warning.

    Press Ctrl+C now to abort, or wait for the script to continue..

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-03-17 14:49:49 +01:00
24186d8008 ci: fix CodeQL 2.16.4 autobuild
CodeQL 2.16.4's auto-build added support for multi-module repositories,
and is trying to be smart by searching for modules in every directory,
including vendor directories. If no module is found, it's creating one
which is ... not what we want, so let's give it a "go.mod".

Here's from a run in CI;

    /opt/hostedtoolcache/CodeQL/2.16.4/x64/codeql/codeql version --format=json
    {
      "productName" : "CodeQL",
      "vendor" : "GitHub",
      "version" : "2.16.4",
      "sha" : "9727ba3cd3d5a26f8b9347bf3c3eb4f565ac077b",
      "branches" : [
        "codeql-cli-2.16.4"
      ],
      "copyright" : "Copyright (C) 2019-2024 GitHub, Inc.",
      "unpackedLocation" : "/opt/hostedtoolcache/CodeQL/2.16.4/x64/codeql",
      "configFileLocation" : "/home/runner/.config/codeql/config",
      "configFileFound" : false,
      "features" : {
        "analysisSummaryV2Option" : true,
        "buildModeOption" : true,
        "bundleSupportsIncludeDiagnostics" : true,
        "featuresInVersionResult" : true,
        "indirectTracingSupportsStaticBinaries" : false,
        "informsAboutUnsupportedPathFilters" : true,
        "supportsPython312" : true,
        "mrvaPackCreate" : true,
        "threatModelOption" : true,
        "traceCommandUseBuildMode" : true,
        "v2ramSizing" : true,
        "mrvaPackCreateMultipleQueries" : true,
        "setsCodeqlRunnerEnvVar" : true
      }
    }

With 2.16.4, first it is unable to correlate files with the project, considering
them "stray" files;

    Attempting to automatically build go code
    /opt/hostedtoolcache/CodeQL/2.16.4/x64/codeql/go/tools/autobuild.sh
    2024/03/16 15:54:34 Autobuilder was built with go1.22.0, environment has go1.21.8
    2024/03/16 15:54:34 LGTM_SRC is /home/runner/work/cli/cli
    2024/03/16 15:54:34 Found no go.work files in the workspace; looking for go.mod files...
    2024/03/16 15:54:34 Found stray Go source file in cli/cobra.go.
    2024/03/16 15:54:34 Found stray Go source file in cli/cobra_test.go.
    2024/03/16 15:54:34 Found stray Go source file in cli/command/builder/client_test.go.
    2024/03/16 15:54:34 Found stray Go source file in cli/command/builder/cmd.go.
    ...

It then tries to build the binary, but in go modules mode, which fails (it also
seems to be doing this for each and every directory);

    Use "make dev" to start an interactive development container,
    use "make -f docker.Makefile " to execute this target
    in a container, or set DISABLE_WARN_OUTSIDE_CONTAINER=1 to
    disable this warning.

    Press Ctrl+C now to abort, or wait for the script to continue..

    ./scripts/build/binary
    Building static docker-linux-amd64
    + go build -o build/docker-linux-amd64 -tags  osusergo pkcs11 -ldflags  -X "github.com/docker/cli/cli/version.GitCommit=38c3ff6" -X "github.com/docker/cli/cli/version.BuildTime=2024-03-16T17:20:38Z" -X "github.com/docker/cli/cli/version.Version=38c3ff6.m" -extldflags -static -buildmode=pie github.com/docker/cli/cmd/docker
    cannot find package "github.com/docker/cli/cmd/docker" in any of:
        /opt/hostedtoolcache/go/1.21.8/x64/src/github.com/docker/cli/cmd/docker (from $GOROOT)
        /home/runner/go/src/github.com/docker/cli/cmd/docker (from $GOPATH)
    make: *** [Makefile:62: binary] Error 1
    2024/03/16 17:20:38 Running /usr/bin/make [make] failed, continuing anyway: exit status 2
    2024/03/16 17:20:38 Build failed, continuing to install dependencies.
    2024/03/16 17:20:38 The code in vendor/gotest.tools/v3/skip seems to be missing a go.mod file. Attempting to initialize one...
    2024/03/16 17:20:38 Import path is 'github.com/docker/cli'

If also seems to be doing this for ... every package?

    cat 0_codeql.log | grep 'you are not in a container' | wc -l
    497

After which it starts to create modules out of every directory;

    The code in internal/test/network seems to be missing a go.mod file. Attempting to initialize one...
    The code in internal/test/notary seems to be missing a go.mod file. Attempting to initialize one...
    The code in internal/test/output seems to be missing a go.mod file. Attempting to initialize one...
    The code in opts seems to be missing a go.mod file. Attempting to initialize one...
    The code in service seems to be missing a go.mod file. Attempting to initialize one...
    The code in service/logs seems to be missing a go.mod file. Attempting to initialize one...
    The code in templates seems to be missing a go.mod file. Attempting to initialize one...
    The code in vendor seems to be missing a go.mod file. Attempting to initialize one...
    The code in vendor/dario.cat seems to be missing a go.mod file. Attempting to initialize one...
    The code in vendor/dario.cat/mergo seems to be missing a go.mod file. Attempting to initialize one...
    ...
    Skipping dependency package regexp.
    Skipping dependency package github.com/opencontainers/go-digest.
    Skipping dependency package github.com/distribution/reference.
    Extracting /home/runner/work/cli/cli/cli/command/go.mod
    Done extracting /home/runner/work/cli/cli/cli/command/go.mod (1ms)
    Extracting /home/runner/work/cli/cli/cli/command/go.mod
    Done extracting /home/runner/work/cli/cli/cli/command/go.mod (0ms)
    Extracting /home/runner/work/cli/cli/cli/command/go.mod
    Done extracting /home/runner/work/cli/cli/cli/command/go.mod (0ms)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-03-17 14:27:10 +01:00
48b5efee03 Dockerfile: update mvdan/gofumpt to v0.6.0
- full diff: https://github.com/mvdan/gofumpt/compare/v0.4.0...v0.6.0
- v0.6.0 release notes: https://github.com/mvdan/gofumpt/releases/tag/v0.6.0
- v0.5.0 release notes: https://github.com/mvdan/gofumpt/releases/tag/v0.5.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-03-17 13:48:13 +01:00
38c3ff67aa vendor: github.com/docker/docker 70e46f2c7c2d (v26.0.0-rc3-dev)
full diff: https://github.com/docker/docker/compare/v26.0.0-rc2...70e46f2c7c2df8d8cc483d9831a907b12efa201b

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-03-16 16:53:20 +01:00
f8fc5b6bc3 scripts/vendor: remove -compat=1.19
We originally added this -compat to keep a consistent format of
the vendor.mod files for cases where there were differences
between go versions.

I don't think we really need this anymore, so let's remove.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-03-16 16:44:25 +01:00
a4a79d75c0 vendor: google.golang.org/protobuf v1.33.0, github.com/golang/protobuf v1.5.4
full diffs:

- https://github.com/protocolbuffers/protobuf-go/compare/v1.31.0...v1.33.0
- https://github.com/golang/protobuf/compare/v1.5.3...v1.5.4

From the Go security announcement list;

> Version v1.33.0 of the google.golang.org/protobuf module fixes a bug in
> the google.golang.org/protobuf/encoding/protojson package which could cause
> the Unmarshal function to enter an infinite loop when handling some invalid
> inputs.
>
> This condition could only occur when unmarshaling into a message which contains
> a google.protobuf.Any value, or when the UnmarshalOptions.UnmarshalUnknown
> option is set. Unmarshal now correctly returns an error when handling these
> inputs.
>
> This is CVE-2024-24786.

In a follow-up post;

> A small correction: This vulnerability applies when the UnmarshalOptions.DiscardUnknown
> option is set (as well as when unmarshaling into any message which contains a
> google.protobuf.Any). There is no UnmarshalUnknown option.
>
> In addition, version 1.33.0 of google.golang.org/protobuf inadvertently
> introduced an incompatibility with the older github.com/golang/protobuf
> module. (https://github.com/golang/protobuf/issues/1596) Users of the older
> module should update to github.com/golang/protobuf@v1.5.4.

govulncheck results in our code shows that this does not affect the CLI:

    govulncheck ./...
    Scanning your code and 448 packages across 72 dependent modules for known vulnerabilities...

    === Symbol Results ===

    No vulnerabilities found.

    Your code is affected by 0 vulnerabilities.
    This scan also found 1 vulnerability in packages you import and 0
    vulnerabilities in modules you require, but your code doesn't appear to call
    these vulnerabilities.
    Use '-show verbose' for more details.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-03-16 16:41:42 +01:00
115c8d56e5 vendor: github.com/containerd/containerd v1.7.14
no changes in vendored files, but now requires go1.21

full diff: https://github.com/containerd/containerd/compare/v1.7.13...v1.7.14

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-03-16 16:41:38 +01:00
38fcd1ca63 Merge pull request #4943 from jsternberg/correct-build-command-path
builder: correct the command path for docker build
2024-03-16 15:30:43 +01:00
9392831817 builder: correct the command path for docker build
The command path sent for `docker build` should be `docker` rather than
`docker build` to be consistent with the other command paths.

* `docker buildx build` has a command path of `docker buildx`
* `docker builder build` has a command path of `docker builder`
* `docker image build` has a command path of `docker image`

The reason this gets set to `docker buildx` rather than `docker buildx
build` is because the `build` portion of the command path is processed
by the plugin. So the command path only contains the portions of the
command path that were processed by this tool.

Since the `build` of `docker build` gets forwarded to `buildx`, it is
not included in the command path.

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2024-03-15 11:36:38 -05:00
4e9abfecf5 Merge pull request #4916 from dvdksn/docs-typos-corrections
docs: typo fixes and other corrections
2024-03-14 13:20:39 +01:00
dc4163fb1a docs/deprecated: Deprecate Container fields in image inspect
See moby#46939

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-03-14 12:42:31 +01:00
8adf1ddb86 Merge pull request #4928 from dvdksn/deprecate-nontls-tcp
docs: deprecate TCP connection without TLS
2024-03-14 12:29:42 +01:00
c8e470057a Merge pull request #4938 from thaJeztah/deprecate_legacy_images
deprecate legacy image formats
2024-03-14 12:20:17 +01:00
3da26a5e79 docs: add description and link for --userns flag
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-03-14 10:10:49 +01:00
4bb2abaa54 docs: typo fixes and other corrections
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-03-14 10:10:49 +01:00
90c33dbfd9 deprecate legacy image formats
Mark pulling legacy image formats as deprecated, and describe the
DOCKER_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE environment variable.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-03-12 17:20:33 +01:00
d17b3b2d80 Merge pull request #4937 from crazy-max/update-xx
Dockerfile: update to xx 1.4.0
2024-03-12 16:19:19 +01:00
adb018084c Dockerfile: update to xx 1.4.0
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2024-03-11 14:24:26 +01:00
a2f3f40233 Merge pull request #4936 from thaJeztah/deprecate_eventhandler
cli/command: deprecate EventHandler and InitEventHandler
2024-03-11 14:21:19 +01:00
46afd26c45 cli/command: deprecate EventHandler and InitEventHandler
This code was only used as part of container.RunStats, so moving the code
there instead as a non-exported type. The actual use also did not have to
handle concurrency, so the mutex is removed in the new location.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-03-11 13:25:22 +01:00
d06f137170 Merge pull request #4934 from thaJeztah/stats_improve
cli/command/container: use ping-result for OS-version
2024-03-11 12:59:47 +01:00
b55cf2f71f Merge pull request #4931 from robmry/internal_network
Add a description of '--internal' to the docs
2024-03-11 12:41:29 +01:00
412d6fca9c Merge pull request #4930 from vvoland/vendor-docker-v26.0.0-rc2
vendor: github.com/docker/docker v26.0.0-rc2
2024-03-11 12:39:14 +01:00
5c54f75f2a cli/command/container: use ping-result for OS-version
The daemonOSType variable is already set when collecting stats, so we unlikely
hit this code in practice, and it would only be set if `collect()` failed and
we never got a stats response. If we do need to get this information, let's use
the OSVersion we already obtained from the ping response.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-03-11 11:05:56 +01:00
617377c045 Describe an 'internal' network.
Added a description of a '--internal' network (from @neersighted).

Co-authored-by: Bjorn Neergaard <bjorn.neergaard@docker.com>
Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-03-11 09:13:25 +00:00
860b4f3a7d 'docker daemon' flags refer to the default bridge
Replace 'docker daemon' with the wording used for the preceeding table,
to make it extra-clear that those flags apply to the default bridge.

Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-03-08 17:11:28 +00:00
645b973521 vendor: github.com/docker/docker v26.0.0-rc2
full diff: https://github.com/docker/docker/compare/f4c696eef17d...v26.0.0-rc2

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-03-08 17:10:05 +01:00
3cf2fe0fff docs: deprecate TCP connection without TLS
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-03-08 14:50:15 +01:00
952c807716 Merge pull request #4926 from vvoland/vendor-docker
Some checks failed
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / e2e (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / e2e (alpine, 23, experimental) (push) Has been cancelled
e2e / e2e (alpine, 23, non-experimental) (push) Has been cancelled
e2e / e2e (alpine, 24, connhelper-ssh) (push) Has been cancelled
e2e / e2e (alpine, 24, experimental) (push) Has been cancelled
e2e / e2e (alpine, 24, non-experimental) (push) Has been cancelled
e2e / e2e (alpine, 25, connhelper-ssh) (push) Has been cancelled
e2e / e2e (alpine, 25, experimental) (push) Has been cancelled
e2e / e2e (alpine, 25, non-experimental) (push) Has been cancelled
e2e / e2e (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / e2e (debian, 23, experimental) (push) Has been cancelled
e2e / e2e (debian, 23, non-experimental) (push) Has been cancelled
e2e / e2e (debian, 24, connhelper-ssh) (push) Has been cancelled
e2e / e2e (debian, 24, experimental) (push) Has been cancelled
e2e / e2e (debian, 24, non-experimental) (push) Has been cancelled
e2e / e2e (debian, 25, connhelper-ssh) (push) Has been cancelled
e2e / e2e (debian, 25, experimental) (push) Has been cancelled
e2e / e2e (debian, 25, non-experimental) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-12) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
vendor: github.com/docker/docker f4c696eef17d62a42
2024-03-07 19:35:08 +01:00
a8379092af vendor: github.com/docker/docker f4c696eef17d62a42
full diff: https://github.com/docker/docker/compare/v26.0.0-rc1+incompatible...f4c696eef17d62a421877d95c4810185750c5641

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-03-07 19:13:04 +01:00
a1361a1372 Merge pull request #4923 from vvoland/cli-arm64
bake: Add `windows/arm64` target to bin-image-cross
2024-03-06 09:08:20 -07:00
ab9d560570 bake: Add windows/arm64 target to bin-image-cross
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-03-06 16:46:39 +01:00
ba6460829b Merge pull request #4918 from vvoland/go-1.21.8
update to go1.21.8
2024-03-05 22:24:30 +01:00
3b77477943 update to go1.21.8
go1.21.8 (released 2024-03-05) includes 5 security fixes:

- crypto/x509: Verify panics on certificates with an unknown public key algorithm (CVE-2024-24783, https://go.dev/issue/65390)
- net/http: memory exhaustion in Request.ParseMultipartForm (CVE-2023-45290, https://go.dev/issue/65383)
- net/http, net/http/cookiejar: incorrect forwarding of sensitive headers and cookies on HTTP redirect (CVE-2023-45289, https://go.dev/issue/65065)
- html/template: errors returned from MarshalJSON methods may break template escaping (CVE-2024-24785, https://go.dev/issue/65697)
- net/mail: comments in display names are incorrectly handled (CVE-2024-24784, https://go.dev/issue/65083)

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

- https://github.com/golang/go/issues?q=milestone%3AGo1.21.8+label%3ACherryPickApproved
- full diff: https://github.com/golang/go/compare/go1.21.6...go1.21.8

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-03-05 22:08:26 +01:00
181575bf55 Merge pull request #4888 from Benehiko/fix-prompt-termination
fix: cli prompt termination exit code
2024-03-04 07:56:38 -07:00
10bf91a02d fix: cli prompt termination exit code
Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com>
2024-03-04 15:26:17 +01:00
310daf2db9 Merge pull request #4259 from gmargaritis/373-support-detach-flag-in-stack-rm
Add support for --detach flag in stack rm
2024-03-04 10:04:41 +01:00
238d659ff9 Add support for --detach/-d flag in stack rm
Added --detach/-d to stack rm. Setting --detach=false waits until
all of the stack tasks have reached a terminal state.

Co-authored-by: Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: George Margaritis <gmargaritis@protonmail.com>
2024-03-04 09:56:53 +01:00
4a43b8eaed Merge pull request #4258 from gmargaritis/373-support-detach-in-docker-stack-deploy
Add support for --detach flag in stack deploy
2024-03-04 09:45:01 +01:00
b086d72769 Add support for --detach flag in stack deploy
Added --detach and --quiet/-q flags to stack deploy. Setting --detach=false
waits until all of the stack services have converged. Shows progress bars for
each individual task, unless  --quiet/-q is specified.

Co-authored-by: Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: George Margaritis <gmargaritis@protonmail.com>
2024-03-04 09:36:36 +01:00
35e6a41ff2 Merge pull request #4906 from Benehiko/benehiko/v26.0.0-rc1
vendor: github.com/docker/docker v26.0.0-rc1
2024-03-01 18:33:58 +01:00
5e80232398 vendor: github.com/docker/docker v26.0.0-rc1
full diff: https://github.com/docker/docker/compare/c70d7905fbd9...v26.0.0-rc1

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>

test: update fixtures

Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com>
2024-03-01 18:23:25 +01:00
19d02cd101 Merge pull request #4896 from Benehiko/help-plugin-descriptions
chore: `docker help` should not show plugin vendor and version
2024-02-29 07:32:20 -07:00
ec35bab4fa Merge pull request #4901 from dvdksn/docs-fix-typo-tty
docs: fix typo in tty example
2024-02-29 14:53:02 +01:00
d51ba41791 docs: prefer -it over -ti
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-02-29 13:38:53 +01:00
a5b82e9f87 docs: fix typo in tty example
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-02-29 13:38:48 +01:00
abe78b79de chore: docker help should not show plugin vendor and version
Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com>
2024-02-29 08:47:18 +01:00
9015b71163 Merge pull request #4875 from jsternberg/build-alias-env-var
plugins: set OTEL_RESOURCE_ATTRIBUTES when invoking a plugin
2024-02-28 22:02:22 +01:00
5786f20687 plugins: fix encoding for OTEL env var passed to plugin
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2024-02-28 12:43:07 -08:00
85dcacd78f plugins: set OTEL_RESOURCE_ATTRIBUTES when invoking a plugin
When a plugin is invoked, the docker cli will now set
`OTEL_RESOURCE_ATTRIBUTES` to pass OTEL resource attribute names to the
plugin as additional resource attributes. At the moment, the only
resource attribute passed is `cobra.command_path`.

All resource attributes passed by the CLI are prepended with the
namespace `docker.cli` to avoid clashing with existing ones the plugin
uses or ones defined by the user.

For aliased commands like the various builder commands, the command path
is overwritten to match with the original name (such as `docker
builder`) instead of the forwarded name (such as `docker buildx build`).

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2024-02-28 12:43:05 -08:00
eb306df13d Merge pull request #4887 from dvdksn/invalid-daemon.json
Some checks failed
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / e2e (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / e2e (alpine, 23, experimental) (push) Has been cancelled
e2e / e2e (alpine, 23, non-experimental) (push) Has been cancelled
e2e / e2e (alpine, 24, connhelper-ssh) (push) Has been cancelled
e2e / e2e (alpine, 24, experimental) (push) Has been cancelled
e2e / e2e (alpine, 24, non-experimental) (push) Has been cancelled
e2e / e2e (alpine, 25, connhelper-ssh) (push) Has been cancelled
e2e / e2e (alpine, 25, experimental) (push) Has been cancelled
e2e / e2e (alpine, 25, non-experimental) (push) Has been cancelled
e2e / e2e (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / e2e (debian, 23, experimental) (push) Has been cancelled
e2e / e2e (debian, 23, non-experimental) (push) Has been cancelled
e2e / e2e (debian, 24, connhelper-ssh) (push) Has been cancelled
e2e / e2e (debian, 24, experimental) (push) Has been cancelled
e2e / e2e (debian, 24, non-experimental) (push) Has been cancelled
e2e / e2e (debian, 25, connhelper-ssh) (push) Has been cancelled
e2e / e2e (debian, 25, experimental) (push) Has been cancelled
e2e / e2e (debian, 25, non-experimental) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-12) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
docs: fix invalid daemon.json examples
2024-02-28 18:00:17 +01:00
efb9206433 Merge pull request #4897 from thaJeztah/bump_engine
vendor: github.com/docker/docker c70d7905fbd9 (v26.0.0-dev)
2024-02-26 19:24:28 +01:00
acc675014f vendor: github.com/docker/docker c70d7905fbd9 (v26.0.0-dev)
full diff: 86b86412a1...c70d7905fb

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-26 17:54:20 +01:00
79541b7e21 vendor: google.golang.org/grpc v1.59.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-26 17:53:12 +01:00
096ced0894 vendor: OTEL v0.46.1 / v1.21.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-26 17:50:23 +01:00
f3c77df31e vendor: github.com/prometheus/client_golang v1.17.0
full diffs:

- https://github.com/prometheus/client_golang/compare/v1.14.0...v1.17.0
- https://github.com/prometheus/client_model/compare/v0.3.0...v0.5.0
- https://github.com/prometheus/common/compare/v0.42.0...v0.44.0
- https://github.com/prometheus/procfs/compare/v0.9.0...v0.12.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-26 17:45:07 +01:00
1b42d04d63 vendor: github.com/go-logr/logr v1.3.0
full diff: https://github.com/go-logr/logr/compare/v1.2.4...v1.3.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-26 17:39:47 +01:00
f5a29ff8eb vendor: github.com/containerd/containerd v1.7.13
no changes in vendored files

full diff: https://github.com/containerd/containerd/compare/v1.7.12...v1.7.13

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-26 17:36:46 +01:00
dc6bfac81a Merge pull request #4331 from vvoland/mount-volsubpath
mount: Add volume-subpath option
2024-02-23 17:29:42 +01:00
9767d02493 Merge pull request #4894 from crazy-max/codecov-token
ci: set codecov token
2024-02-22 23:20:49 +01:00
2663c10574 ci: set codecov token
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2024-02-22 18:11:18 +01:00
48a670f26b docs: fix invalid daemon.json examples
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-02-21 12:29:31 +01:00
1443014cbd Merge pull request #4884 from thaJeztah/regenerate_mdddocs
docs: regenerate markdown
2024-02-21 11:33:23 +01:00
f2e98f9a93 docs: regenerate markdown
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-21 10:40:13 +01:00
f6b7a11b93 Merge pull request #4866 from dvdksn/docs-cli-reference-urlscheme
docs: update link targets
2024-02-21 09:18:52 +01:00
caf72655fb docs: update url scheme for reference docs
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-02-20 21:38:50 +01:00
e244044944 deps: update cli-docs-tool version (v0.7.0)
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-02-20 08:31:53 +01:00
a10debe6c4 Merge pull request #4881 from thaJeztah/update_go_1.21.7
update to go1.21.7
2024-02-19 15:18:52 +01:00
20b9d489e0 update to go1.21.7
go1.21.7 (released 2024-02-06) includes fixes to the compiler, the go command,
the runtime, and the crypto/x509 package. See the Go 1.21.7 milestone on our
issue tracker for details:

- https://github.com/golang/go/issues?q=milestone%3AGo1.21.7+label%3ACherryPickApproved
- full diff: https://github.com/golang/go/compare/go1.21.6...go1.21.7

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-19 14:13:51 +01:00
67105e0995 Merge pull request #4876 from systemmonkey42/patch-1
Fixed typo in bash completion functions
2024-02-19 11:50:49 +01:00
c514003e69 Fixed typo in bash completion functions
Signed-off-by: David le Blanc <david-le-blanc@users.noreply.github.com>
2024-02-17 17:11:28 +11:00
49a44fb73f Merge pull request #4879 from qyanu-pull-requests/master
man/docker-build.1: typo in parameter variable: CID => IID
2024-02-16 18:27:24 +01:00
ff5b0d18fe man/docker-build.1: typo in parameter variable: CID => IID
--iidfile logically specifies the IIDFILE and not the CIDFILE
(use --cidfile from docker-run.1.md for specifying a cidfile).

Signed-off-by: Max-Julian Pogner <max-julian@pogner.at>
2024-02-16 11:10:06 +01:00
21d96ffb8f Merge pull request #4839 from krissetto/upgrade-ci
update CI
2024-02-15 14:09:42 +01:00
155b5b4eaa Merge pull request #4872 from thaJeztah/use_non_deprecated_uuid
cli-plugins/socket: remove use of deprecated distribution uuid package
2024-02-14 10:33:46 +01:00
3b5e814242 cli-plugins/socket: remove use of deprecated distribution uuid package
The "github.com/docker/distribution" module moved to the distribution
org ("github.com/docker/distribution/v3"), and the new module deprecated
and removed the uuid package in favor of Google's UUID package.

While we still depend on the old module through packages and as an indirect
dependency, we may want to try avoid using it.

This patch replaces the use for the socket package, and replaces it for a
local utility, taking the same approach as `stringid.GenerateRandomID()`,
which should be random enough for this purpose.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-13 16:24:53 +01:00
69ed6588a8 Cleanup of dockerfiles, compose files and env vars
Signed-off-by: Christopher Petito <chrisjpetito@gmail.com>
2024-02-13 13:32:45 +00:00
6b67b95493 Update gha runners and engines used in e2e tests
- gha runners updated to ubuntu 22.04
- e2e now runs against moby 23.0, 24.0 and 25.0
- temporarily skip broken test for moby < 25

Signed-off-by: Christopher Petito <chrisjpetito@gmail.com>
2024-02-13 13:30:09 +00:00
edc09e6038 mount: Add volume-subpath option
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-02-13 14:04:00 +01:00
a253318869 Merge pull request #4873 from vvoland/test-daemon-apiversion
testenv: Add DaemonAPIVersion helper
2024-02-13 13:50:35 +01:00
9831fea4db testenv: Add DaemonAPIVersion helper
Allow tests to check the negotiated API version used by the client.

Can be used to skip tests based on API versions, for example:
```go
    skip.If(t, versions.LessThan(environment.DaemonAPIVersion(t), "1.44"))
```

will skip the test if the API version is older than 1.44

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-02-12 16:29:47 +01:00
d1b88930c3 Merge pull request #4867 from krissetto/test-fixes
Test fixes needed for upgrading ci runners and engine
2024-02-12 14:40:22 +01:00
d7f195833d Merge pull request #4862 from catap/openbsd
Avoid keeping @docker_cli_[UUID] files
2024-02-12 13:53:33 +01:00
b807ea8084 Merge pull request #4868 from thaJeztah/update_engine
vendor: github.com/docker/docker 86b86412a1b7 (v26.0-dev)
2024-02-12 09:36:04 +01:00
1cda2c45f8 Merge pull request #4869 from thaJeztah/commandcon_cleanup
cli/connhelper/commandconn: inline variables
2024-02-12 07:46:14 +01:00
8bae662713 cli/connhelper/commandconn: inline variables
Inline the variables used to define the command + args used in the
tests, which makes it slightly easier to see what's run.

Also explicitly define a context, in case we want to add telemetry
to these tests.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-10 13:59:36 +01:00
df6220d434 vendor: github.com/docker/docker 86b86412a1b7 (v26.0-dev)
full diff: 9e075f3808...86b86412a1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-10 12:26:39 +01:00
30dd7c1319 Minor test fixes necessary for eventually upgrading ci runners and engine version
Signed-off-by: Christopher Petito <chrisjpetito@gmail.com>
2024-02-09 13:55:03 +00:00
2c214241fa Avoid keeping @docker_cli_[UUID] files
Seems that OpenBSD behaves like darwin and requires to unlink all
socket, after it was used.

Tested on OpenBSD 7.4

Signed-off-by: Kirill A. Korinsky <kirill@korins.ky>
2024-02-09 00:19:27 +01:00
34797d1678 Merge pull request #4860 from robmry/4859_compose_extra_hosts_eq_sep
docker stack: allow '=' separator in extra_hosts
2024-02-08 17:08:47 +01:00
c986d09bca docker stack: allow '=' separator in extra_hosts
extra_hosts in the compose file format allows '=' as a separator, and brackets
around IP addresses, the engine API doesn't.

So, transform the values when reading a compose file for 'docker stack'.

Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-02-07 17:57:17 +00:00
79fa65e7b5 Merge pull request #4835 from thaJeztah/update_engine_api_removal
vendor: github.com/docker/docker 9e075f3808a5 (master, v26.0.0-dev)
2024-02-07 10:47:21 +01:00
324309b086 vendor: github.com/docker/docker 9e075f3808a5 (master, v26.0.0-dev)
Vendor docker/docker with API < 1.24 removed. This should not affect client
code.

43ffb1ee9d..9e075f3808

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-07 02:27:53 +01:00
93ad9fbdf6 vendor: github.com/moby/swarmkit/v2 v2.0.0-20240125134710-dcda100a8261
full diff: f082dd7a0c...dcda100a82

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-07 02:23:51 +01:00
57d72237d7 Merge pull request #4854 from krissetto/uniform-volume-prune-output
Uniform output of volume prune cmd with other prune cmds
2024-02-06 19:45:51 +01:00
69e0f53a03 Uniform volume prune output msg with other prune commands
- Return error when user refuses at confirmation prompt
- Avoid sending space freed msg if user cancelled
- Fixed unit tests

Signed-off-by: Christopher Petito <chrisjpetito@gmail.com>
2024-02-06 14:04:53 +00:00
ce3b07c0db Merge pull request #4849 from thaJeztah/image_list_dedup
images: print hint when invoking "docker images" with ambiguous argument
2024-02-05 16:25:51 +01:00
809eb8cdee images: print hint when invoking "docker images" with ambiguous argument
The `docker images` top-level subcommand predates the `docker <object> <verb>`
convention (e.g. `docker image ls`), but accepts a positional argument to
search/filter images by name (globbing). It's common for users to accidentally
mistake these commands, and to use (e.g.) `docker images ls`, expecting
to see all images, but ending up with an empty list because no image named
"ls" was found.

Disallowing these search-terms would be a breaking change, but we can print
and informational message to help the users correct their mistake.

Before this patch:

    docker images ls
    REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

With this patch applied:

    docker images ls
    REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

    No images found matching "ls": did you mean "docker image ls"?

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-03 18:10:55 +01:00
b158181a1d cli/command/images: runImages: use proper camel-case for dockerCLI
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-03 17:56:06 +01:00
1328bb3381 cli/command/images: runImages: inline intermediate var
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-03 17:54:23 +01:00
843951e84a Merge pull request #4843 from docker/dependabot/github_actions/codecov/codecov-action-4
build(deps): Bump codecov/codecov-action from 3 to 4
2024-02-01 15:47:14 +01:00
b123ce6526 build(deps): Bump codecov/codecov-action from 3 to 4
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 3 to 4.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 08:57:32 +00:00
297704984b Merge pull request #4396 from zliang-akamai/patch-1
Add Linode docker volume plugin
2024-01-31 12:55:31 +01:00
d001ac4892 Merge pull request #4836 from thaJeztah/remove_dummy_circleci
Remove dummy circleci config
2024-01-30 17:46:03 +01:00
1587b70ee7 Remove dummy circleci config
The 20.10 branch reached EOL, so we can probably remove this
one again.

This reverts commit a3d53e319f.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-30 17:29:11 +01:00
3865da2bc8 Merge pull request #4828 from laurazard/plugin-socket-tests
Add tests for CLI/plugin communication (i.e. let's not break everyone's plugins 🥲)
2024-01-29 14:46:25 +01:00
cfa9fef77d tests: add plugin-socket-compatibility tests
Adds a new plugin to the e2e plugins that simulates an older
plugin binary and a test suite to ensure older plugin binaries
keep behaving the same with newer CLI versions.

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2024-01-29 13:39:58 +00:00
6dcf285ff1 Merge pull request #4834 from thaJeztah/flags_dont_varp
cli/command: don't use pflags.XXXVarP for flags without shorthand
2024-01-29 12:26:08 +01:00
dfdff11a22 cli/command: don't use pflags.XXXVarP for flags without shorthand
Use the `XXXVar` equivalent for flags that don't have a shorthand flag
instead of passing an empty string for the shorthand flag.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-29 11:16:38 +01:00
abf8cff233 Merge pull request #4832 from thaJeztah/docker_attach_fixups
cli/command/container: minor cleanup in attach
2024-01-26 16:45:59 +01:00
0ef5e95481 Merge pull request #4831 from thaJeztah/bump_compose
Dockerfile: update docker compose to v2.24.3
2024-01-26 16:19:38 +01:00
690f63e6d3 cli/command/container: minor cleanup in attach
- rename confusing `target` argument, and use `containerID` in all places;
  also make the variable more clearly local-scoped.
- rename `dockerCli` to be correctly camel-case, and to be consistent in
  all places in this file.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-26 13:38:09 +01:00
53e2e54c29 Dockerfile: update docker compose to v2.24.3
Update the version of compose used in CI to the latest version.

- full diff: https://github.com/docker/compose/compare/v2.24.2...v2.24.3
- release notes: https://github.com/docker/compose/releases/tag/v2.24.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-26 11:06:44 +01:00
1c4d6d85dd scripts: don't hardcode architecture in e2e script
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2024-01-25 15:37:17 +00:00
a1bd689a4d Merge pull request #4821 from vvoland/vendor-v26.0.0-43ffb1ee9d5a
vendor: github.com/docker/docker 43ffb1ee9d5a (v26.0.0-dev)
2024-01-24 15:06:06 +01:00
4fa2fe9b9e Replace deprecated types.Image* usage
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-24 14:59:10 +01:00
68dac842a1 vendor: github.com/docker/docker 43ffb1ee9d5a (v26.0.0-dev)
full diff: https://github.com/docker/docker/compare/v25.0.0...43ffb1ee9d5a

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-24 14:59:08 +01:00
bb1cb4992c Merge pull request #4820 from thaJeztah/bump_engine_25.0.1
vendor: github.com/docker/docker v25.0.1
2024-01-24 14:57:12 +01:00
9e2615bc46 Merge pull request #4809 from thaJeztah/remove_printSecurityOptionsWarnings
info: remove printSecurityOptionsWarnings, printServerWarnings
2024-01-24 12:36:19 +01:00
4b1ed1f442 vendor: github.com/docker/docker v25.0.1
relevant changes:

- Fix isGitURL regular expression
- pkg/system: return even richer xattr errors

full diff: https://github.com/moby/moby/compare/v25.0.0...v25.0.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-24 12:17:20 +01:00
d9294f06b5 info: remove printSecurityOptionsWarnings, printServerWarnings
Docker Engine 1.13 (API v1.25) added an option to set a custom default seccomp
profile on the daemon (see [moby/moby@b237189]). A warning was added on the
client-side if a non-default profile was set.

Docker Engine 23.0 (API v1.42) added warnings about non-default seccomp
profiles to the "info" response ([moby/moby@04f932a]), and the client was
updated to skip generating client-side warnings for API v1.42 and up in
[docker/cli@8964595].

These warnings are purely informational, and given that Docker Engine versions
before 23.0 have reached EOL, and any current version of the Engine now returns
the Warnings, it should be safe to remove the client-side fall back logic.

This patch removes the client-side fall back code for warnings that was
added in 8964595692.

[moby/moby@b237189]: b237189e6c
[moby/moby@04f932a]: 04f932ac86
[docker/cli@8964595]: 8964595692

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-23 18:23:35 +01:00
c6ae74956c Merge pull request #4808 from thaJeztah/remove_printServerWarningsLegacy
info: remove printServerWarningsLegacy
2024-01-23 18:22:58 +01:00
69a4fcc3bb Merge pull request #4810 from thaJeztah/remove_deprecated_cliopts
cli/command: remove deprecated DockerCliOption, InitializeOpt
2024-01-23 18:22:28 +01:00
ea84a3fc31 Merge pull request #4811 from thaJeztah/remove_deprecated_NewStartOptions
cli/command/container: remove deprecated NewStartOptions
2024-01-23 18:22:03 +01:00
1e8555a38e Merge pull request #4818 from dvdksn/docs-dockerd-host-gateway-ip-daemonconfig
docs: update host-gateway-ip to use daemon.json instead of cli flag
2024-01-23 15:55:03 +01:00
ec0a62436e docs: update host-gateway-ip to use daemon.json instead of cli flag
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-01-23 15:45:59 +01:00
469bfc05ed tests: add tests for cli-plugins/socket
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2024-01-23 14:19:33 +00:00
c89975d531 Merge pull request #4814 from thaJeztah/update_compose
Dockerfile: update docker compose to v2.24.2
2024-01-23 11:04:31 +01:00
091af560ca Dockerfile: update docker compose to v2.24.2
Update the version of compose used in CI to the latest version.

- full diff: docker/compose@v2.24.0...v2.24.2
- release notes: https://github.com/docker/compose/releases/tag/v2.24.1
- release notes: https://github.com/docker/compose/releases/tag/v2.24.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-23 10:32:22 +01:00
2402dac819 cli/command/container: remove deprecated NewStartOptions
This function was deprecated in 298bddcc23 for
v25.0, and unused. This patch removes the function.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-20 21:48:46 +01:00
b43377a38b cli/command: remove deprecated DockerCliOption, InitializeOpt
These types were deprecated in 7af509c7f1 (v25.0),
in favor of CLIOption, and are no longer used.

This patch removes the deprecated type-aliases, and while updating, also improves
the documentation for the CLIOption type.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-20 21:39:32 +01:00
a71d39bcad info: remove printServerWarningsLegacy
Docker Engine 18.09 (API v1.39) introduced a Warnings field in the into response.
This enhancement was not gated by API version (see [moby/moby@a3d4238]), and
will be returned by Docker Engine 18.09 and up, regardless of the API version
chosen.

Likewise, the client-side code was written to prefer warnings returned by
the daemon, but to fall back on client-side detection of missing features
based on information in the Info response (see [docker/cli@3c27ce2]).

Thse warnings are purely informational, and given that Docker Engine versions
before 18.09 have reached EOL 6 Years ago, and any current version of the
Engine now returns the Warnings, it should be safe to remove the client-side
fall back logic.

This patch removes the client-side fall back code for warnings that was
added in 3c27ce21c9.

[moby/moby@a3d4238]: a3d4238b9c
[docker/cli@3c27ce2]: 3c27ce21c9

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-20 20:45:59 +01:00
f18a476b6d Merge pull request #4805 from tonistiigi/socket-eof-return
socket: return from loop after EOF
2024-01-20 13:44:45 +01:00
8cd3b00420 socket: return from loop after EOF
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2024-01-19 17:06:43 -08:00
e2519aefcb Merge pull request #4802 from thaJeztah/update_engine
vendor: github.com/docker/docker v25.0.0
2024-01-19 15:31:23 +01:00
1c73abb634 Merge pull request #4800 from dvdksn/docs-fix-broken-alias-links
docs: fix broken links to alias pages
2024-01-19 15:06:33 +01:00
337dd82d8b vendor: github.com/docker/docker v25.0.0
full diff: https://github.com/docker/docker/compare/v25.0.0-rc.3...v25.0.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-19 15:03:52 +01:00
d633890f91 docs: move base command to docker.md
CLI reference for the base command was generated to cli.md

Changed it to docker.md to handle broken links.

Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-01-19 14:44:35 +01:00
ca95badb36 Merge pull request #4799 from dvdksn/docs-cdi
docs: add documentation for CDI
2024-01-19 14:15:00 +01:00
aff4649cb7 docs: fix broken links to alias pages
Alias pages redirect to the canonical names, but these pages still
linked to the aliases, causing broken links when building the docs site.

Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-01-19 14:06:29 +01:00
852d198bb5 docs: add documentation for CDI
- Add section about cdi-spec-dirs daemon configuration
- Add subsection about cdi in --device section for docker run
- Update `docker info` output example

Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-01-18 14:58:43 +01:00
e758fe5a7f Merge pull request #4795 from thaJeztah/bump_engine
Some checks failed
build / prepare (push) Has been cancelled
build / build (push) Has been cancelled
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / e2e (19.03-dind, non-experimental) (push) Has been cancelled
e2e / e2e (alpine, stable-dind, connhelper-ssh) (push) Has been cancelled
e2e / e2e (alpine, stable-dind, experimental) (push) Has been cancelled
e2e / e2e (alpine, stable-dind, non-experimental) (push) Has been cancelled
e2e / e2e (debian, stable-dind, connhelper-ssh) (push) Has been cancelled
e2e / e2e (debian, stable-dind, experimental) (push) Has been cancelled
e2e / e2e (debian, stable-dind, non-experimental) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-12) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
vendor: github.com/docker/docker v25.0.0-rc.3
2024-01-18 10:33:39 +01:00
cdb1c105f6 vendor: github.com/docker/docker v25.0.0-rc.3
full diff: https://github.com/moby/moby/compare/v25.0.0-rc.2...v25.0.0-rc.3

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-17 23:28:28 +01:00
d161a2a470 Merge pull request #4767 from dvdksn/refresh-plugin-docs
Some checks failed
build / prepare (push) Has been cancelled
build / build (push) Has been cancelled
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / e2e (19.03-dind, non-experimental) (push) Has been cancelled
e2e / e2e (alpine, stable-dind, connhelper-ssh) (push) Has been cancelled
e2e / e2e (alpine, stable-dind, experimental) (push) Has been cancelled
e2e / e2e (alpine, stable-dind, non-experimental) (push) Has been cancelled
e2e / e2e (debian, stable-dind, connhelper-ssh) (push) Has been cancelled
e2e / e2e (debian, stable-dind, experimental) (push) Has been cancelled
e2e / e2e (debian, stable-dind, non-experimental) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-12) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
docs(plugins): fix typos and formatting
2024-01-17 14:28:58 +01:00
3df149545e docs(plugins): fix typos and formatting
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-01-16 20:37:29 +01:00
33b00e5185 Merge pull request #4797 from dvdksn/daemon-builder-config
docs: add "builder" key to full daemon.json example
2024-01-16 20:34:02 +01:00
22bbdc7984 docs: add "builder" key to full daemon.json example
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-01-16 20:19:06 +01:00
5fde1f2b80 Merge pull request #4796 from thaJeztah/deprecate_old_api_versions
deprecate old API versions (1.23 and lower)
2024-01-16 19:42:14 +01:00
350d6bcc2c Merge pull request #4792 from laurazard/alternative-fix-no-socket-notif
cli/plugins: use same pgid + skip signal forwarding when attached to a TTY
2024-01-16 18:28:38 +01:00
d2efc5b09c deprecate old API versions (1.23 and lower)
The Docker daemon provides a versioned API for backward compatibility with old
clients. Docker clients can perform API-version negotiation to select the most
recent API version supported by the daemon (downgrading to and older version of
the API when necessary). API version negotiation was introduced in Docker v1.12.0
(API 1.24), and clients before that used a fixed API version.

Docker Engine versions through v25.0 provide support for all [API versions](https://docs.docker.com/engine/api/#api-version-matrix)
included in stable releases for a given platform. For Docker daemons on Linux,
the earliest supported API version is 1.12 (corresponding with Docker Engine
v1.0.0), whereas for Docker daemons on Windows, the earliest supported API
version is 1.24 (corresponding with Docker Engine v1.12.0).

Support for legacy API versions (providing old API versions on current versions
of the Docker Engine) is primarily intended to provide compatibility with recent,
but still supported versions of the client, which is a common scenario (the Docker
daemon may be updated to the latest release, but not all clients may be up-to-date
or vice versa). Support for API versions before that (API versions provided by
EOL versions of the Docker Daemon) is provided on a "best effort" basis.

Use of old API versions is very rare, and support for legacy API versions
involves significant complexity (Docker 1.0.0 having been released 10 years ago).
Because of this, we'll start deprecating support for legacy API versions.

Docker Engine v25.0 by default disables API version older than 1.24 (aligning
the minimum supported API version between Linux and Windows daemons). When
connecting with a client that uses an API version version older than 1.24,
the daemon returns an error. The following example configures the docker
CLI to use API version 1.23, which produces an error:

    DOCKER_API_VERSION=1.23 docker version
    Error response from daemon: client version 1.23 is too old. Minimum supported API version is 1.24, please upgrade your client to a newer version

An environment variable (`DOCKER_MIN_API_VERSION`) is introduced that allows
re-enabling older API versions in the daemon. This environment variable must
be set in the daemon's environment (for example, through a [systemd override
file](https://docs.docker.com/config/daemon/systemd/)), and the specified
API version must be supported by the daemon (`1.12` or higher on Linux, or
`1.24` or higher on Windows).

Support for API versions lower than `1.24` will be permanently removed in Docker
Engine v26, and the minimum supported API version will be incrementally raised
in releases following that.

We do not recommend depending on the `DOCKER_MIN_API_VERSION` environment
variable other than for exceptional cases where it's not possible to update
old clients, and those clients must be supported.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-16 18:13:53 +01:00
a18dad3832 Merge pull request #4755 from dvdksn/cli-reference-canonical
docs: rename reference docs to "object_action"
2024-01-16 15:29:04 +01:00
508346ef61 plugins: fix plugin socket being closed before use
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2024-01-15 15:48:57 +00:00
ca58fdf5a1 Merge pull request #4794 from thaJeztah/ci_update_macos_runner
gha: update to use macos-12 runners
2024-01-15 15:31:39 +01:00
f722e07c62 gha: update to use macos-12 runners
It's the minimum version supported by Docker Desktop

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-15 15:00:09 +01:00
5f6c55a724 plugins: don't handle signal/notify if TTY
In order to solve the "double notification" issue (see:
ef5e5fa03f)
without running the plugin process under a new pgid (see:
https://github.com/moby/moby/issues/47073) we instead check if we're
attached to a TTY, and if so skip signalling the plugin process since it
will already be signalled.

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2024-01-15 13:30:17 +00:00
26560ff93c Revert "plugins: run plugin with new process group ID"
This reverts commit ef5e5fa03f.

Running new plugins under a new pgid isn't a viable solution due to
it causing issues with plugin processes attempting to read from the
TTY (see: https://github.com/moby/moby/issues/47073).

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2024-01-15 13:30:01 +00:00
37f5515666 docs: fix broken link to tmpfs (missing anchor)
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-01-15 14:16:24 +01:00
b35361e8d2 docs: regenerate stubs for non-canonical commands
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-01-15 13:49:53 +01:00
67c5a9b6ff Merge pull request #4791 from vvoland/ci-bin-image-2
ci: Add bin-image workflow (2nd approach)
2024-01-15 13:11:13 +01:00
9beb0e5f03 Merge pull request #4790 from thaJeztah/bump_x_sys
vendor: golang.org/x/sys v0.16.0
2024-01-15 12:40:05 +01:00
dfa2930afc ci: Add bin-image workflow
Build and push an image containing a static CLI binary for master branch
and every release branch and tag.

This is a slightly adjusted copy of the bin-image workflow from
docker/buildx (by @crazy-max).

Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-15 12:05:10 +01:00
21c2536051 vendor: golang.org/x/sys v0.16.0
full diff: https://github.com/golang/sys/compare/v0.15.0...v0.16.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-15 12:01:27 +01:00
a6774de682 docs: rename cli reference aliases to canonical
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-01-15 11:29:30 +01:00
cf9d3692a3 docs: remove empty cli reference stubs
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-01-15 11:19:39 +01:00
077d07c4f0 Merge pull request #4771 from thaJeztah/update_engine
vendor: github.com/docker/docker v25.0.0-rc.2
2024-01-15 11:03:40 +01:00
d868dca00f vendor: github.com/docker/docker v25.0.0-rc.2
- feat: make errdefs.IsXXX helper functions work with wrapped errors

full diff: https://github.com/moby/moby/compare/v25.0.0-rc.1...v25.0.0-rc.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-13 02:08:29 +01:00
1fc6ef9d63 Merge pull request #4785 from thaJeztah/revert_bin_image
Some checks failed
build / prepare (push) Has been cancelled
build / build (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / e2e (19.03-dind, non-experimental) (push) Has been cancelled
e2e / e2e (alpine, stable-dind, connhelper-ssh) (push) Has been cancelled
e2e / e2e (alpine, stable-dind, experimental) (push) Has been cancelled
e2e / e2e (alpine, stable-dind, non-experimental) (push) Has been cancelled
e2e / e2e (debian, stable-dind, connhelper-ssh) (push) Has been cancelled
e2e / e2e (debian, stable-dind, experimental) (push) Has been cancelled
e2e / e2e (debian, stable-dind, non-experimental) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-11) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
temporarily revert ci: Add bin-image workflow
2024-01-12 14:46:30 -07:00
1609916f2c Revert "Dockerfile/binary: Output the binary directly"
Looks like this change caused docker-ce-packaging to fail;

    dest=$PWD/build/mac; cd /home/ubuntu/workspace/release-packaging_ce-nightly/packaging/src/github.com/docker/cli/build && for platform in *; do \
        arch=$(echo $platform | cut -d_ -f2); \
        mkdir -p $dest/$arch/docker; \
        cp $platform/docker-darwin-* $dest/$arch/docker/docker && \
        tar -C $dest/$arch -c -z -f $dest/$arch/docker-25.0.0-rc.2.tgz docker; \
    done
    cp: cannot stat 'darwin_amd64/docker-darwin-*': No such file or directory
    cp: cannot stat 'darwin_arm64/docker-darwin-*': No such file or directory

This reverts commit 6ad07f2a4b.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-12 22:39:30 +01:00
ff25c4334b Revert "ci: Add bin-image workflow"
This reverts commit 15d4c99f38.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-12 22:39:05 +01:00
688de6db16 Merge pull request #4769 from laurazard/signal-handling-fix-tty
plugins: run plugin with new process group ID
2024-01-12 22:06:23 +01:00
ef5e5fa03f plugins: run plugin with new process group ID
Changes were made in 1554ac3b5f to provide
a mechanism for the CLI to notify running plugin processes that they
should exit, in order to improve the general CLI/plugin UX. The current
implementation boils down to:
1. The CLI creates a socket
2. The CLI executes the plugin
3. The plugin connects to the socket
4. (When) the CLI receives a termination signal, it uses the socket to
   notify the plugin that it should exit
5. The plugin's gets notified via the socket, and cancels it's `cmd.Context`,
   which then gets handled appropriately

This change works in most cases and fixes the issue it sets out to solve
(see: https://github.com/docker/compose/pull/11292) however, in the case
where the user has a TTY attached and the plugin is not already handling
received signals, steps 4+ changes:
4. (When) the CLI receives a termination signal, before it can use the
   socket to notify the plugin that it should exit, the plugin process
   also receives a signal due to sharing the pgid with the CLI

Since we now have a proper "job control" mechanism, we can simplify the
scenarios by executing the plugins with their own process group id,
thereby removing the "double notification" issue and making it so that
plugins can handle the same whether attached to a TTY or not.

In order to make this change "plugin-binary" backwards-compatible, in
the case that a plugin does not connect to the socket, the CLI passes
the signal to the plugin process.

Co-authored-by: Bjorn Neergaard <bjorn.neergaard@docker.com>
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
Signed-off-by: Bjorn Neergaard <bjorn.neergaard@docker.com>
2024-01-12 13:53:28 -07:00
ad12276ea0 Merge pull request #4783 from laurazard/fix-no-abstract-sockets
cli-plugins: don't use abstract sockets on macOS
2024-01-12 21:40:06 +01:00
a226502619 Merge pull request #4784 from thaJeztah/vendor_containerd
vendor: github.com/containerd/containerd v1.7.12
2024-01-12 21:14:36 +01:00
6d0b329b0d cli-plugins: use non-abstract socket on darwin
As macOS does not support the abstract socket namespace, use a temporary
socket in $TMPDIR to connect with the plugin. Ensure this socket is
cleaned up even in the case of crash/ungraceful termination by removing
it after the first connection is accepted.

Co-authored-by: Laura Brehm <laurabrehm@hey.com>
Signed-off-by: Bjorn Neergaard <bjorn.neergaard@docker.com>
2024-01-12 12:30:27 -07:00
dbf992f91f cli-plugins: move socket code into common package
Signed-off-by: Bjorn Neergaard <bjorn.neergaard@docker.com>
2024-01-12 11:49:25 -07:00
8b6ffbdf77 vendor: github.com/containerd/containerd v1.7.12
- full diff: https://github.com/containerd/containerd/compare/v1.7.11...v1.7.12
- release notes: https://github.com/containerd/containerd/releases/tag/v1.7.12

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-12 19:31:12 +01:00
52b740ac27 Merge pull request #4781 from thaJeztah/bump_buildx_compose
Dockerfile: update buildx to v0.12.1
2024-01-12 18:32:47 +01:00
d469be256e Merge pull request #4752 from vvoland/ci-bin-image
ci: Add bin-image workflow
2024-01-12 15:50:30 +01:00
ccc7ad2f2c Dockerfile: update buildx to v0.12.1
Update the version of buildx used in CI to the latest version.

- full diff: https://github.com/docker/buildx/compare/v0.12.0...v0.12.1
- release notes: https://github.com/docker/buildx/releases/tag/v0.12.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-12 15:29:58 +01:00
708d1136d6 Merge pull request #4782 from thaJeztah/bump_compose
Dockerfile: update docker compose to v2.24.0
2024-01-12 15:29:33 +01:00
fdcb78a0fe Dockerfile: update docker compose to v2.24.0
Update the version of compose used in CI to the latest version.

- full diff: https://github.com/docker/compose/compare/v2.22.0...v2.24.0
- release notes: https://github.com/docker/compose/releases/tag/v2.24.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-12 14:39:08 +01:00
15d4c99f38 ci: Add bin-image workflow
Build and push an image containing a static CLI binary for master branch
and every release branch and tag.

This is a slightly adjusted copy of the bin-image workflow from
docker/buildx (by @crazy-max).

Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-12 12:28:20 +01:00
ecf338f43b scripts/build: Handle VERSION containing git ref
Transform `VERSION` variable if it contains a git ref.
This is the same as moby does (with "<<<" bashism removed).

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-12 12:28:18 +01:00
6ad07f2a4b Dockerfile/binary: Output the binary directly
`scripts/make/binary` produces `docker` file that is a symlink to a
`docker-<platform>` file.
Make the `binary` Dockerfile target produce an image that only contains
the `docker` binary and not the symlink.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-12 12:28:15 +01:00
859154b94c Merge pull request #4778 from thaJeztah/cmd_docker_smaller_interface
cmd/docker: registerCompletionFuncForGlobalFlags: take store.Store as argument
2024-01-11 22:50:47 +01:00
76e09dd44b Merge pull request #4777 from thaJeztah/pluginmanager_smaller_interface
cli-plugins/manager: getPluginDirs: take ConfigFile as argument
2024-01-11 22:50:31 +01:00
a745bffb86 Merge pull request #4776 from thaJeztah/fix_shadow
cli-plugins: helloworld: rename var that collided with import
2024-01-11 22:50:12 +01:00
e5d225de16 Merge pull request #4775 from thaJeztah/move_main
cmd/docker: move main() to the top
2024-01-11 22:49:48 +01:00
0e37dd49f0 cmd/docker: registerCompletionFuncForGlobalFlags: take store.Store as argument
Update this function to accept a smaller interface, as it doesn't need
all of "CLI". Also return errors encountered during its operation (although
the caller currently has no error return on its own).

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-11 22:31:17 +01:00
c0a0b05dc8 cli-plugins: helloworld: rename var that collided with import
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-11 22:25:15 +01:00
11b2e871bc cmd/docker: move main() to the top
It was hidden half-way the file; let's move it to the top, where I'd expect
to find it.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-11 22:19:17 +01:00
4dc2c895b1 cli-plugins/manager: getPluginDirs: take ConfigFile as argument
Update this function to accept a smaller interface, as it doesn't need
all of "CLI".

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-11 18:15:30 +01:00
c825db8a69 Merge pull request #4773 from thaJeztah/daemon_fix_env_table
docs: dockerd: fix markdown table, and rephrase environment-variables intro
2024-01-11 15:31:56 +01:00
79992184e0 docs: dockerd: rephrase environment-variables intro
Slightly rephrase the intro (remove "easy reference"), and cross-reference
the corresponding section on the docker CLI page.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-11 14:55:16 +01:00
4d2b4e7fba docs: dockerd: fix stray column-separateor in env-var table
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-11 13:54:39 +01:00
5a31004bdb Merge pull request #4772 from thaJeztah/update_credential_helpers
vendor: github.com/docker/docker-credential-helpers v0.8.1
2024-01-10 23:00:53 +01:00
a5e5563f13 vendor: github.com/docker/docker-credential-helpers v0.8.1
full diff: https://github.com/docker/docker-credential-helpers/compare/v0.8.0...v0.8.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-10 22:35:03 +01:00
bc6b9d9c4b Merge pull request #4766 from thaJeztah/update_golang_1.21.6
update to go1.21.6
2024-01-10 17:59:42 +01:00
4f49508861 update to go1.21.6
go1.21.6 (released 2024-01-09) includes fixes to the compiler, the runtime, and
the crypto/tls, maps, and runtime/pprof packages. See the Go 1.21.6 milestone on
our issue tracker for details:

- https://github.com/golang/go/issues?q=milestone%3AGo1.21.6+label%3ACherryPickApproved
- full diff: https://github.com/golang/go/compare/go1.21.5...go1.21.6

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-10 09:41:03 +01:00
cfe18f5e03 Merge pull request #4760 from thaJeztah/improve_asserts
cli/compose/loader: use golden.Assert() for readability
2024-01-08 16:59:16 +01:00
26f59b2f66 cli/compose/loader: use golden.Assert() for readability
golden.AssertBytes prints the failure as a bytes-array, which makes
it not human-readable; let's compare strings instead.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-08 14:16:19 +01:00
5c6ca07208 Merge pull request #4758 from thaJeztah/bump_assorted
vendor: update some (test) dependencies
2024-01-08 12:39:50 +01:00
9db56ea2f6 vendor: golang.org/x/tools v0.16.0, golang.org/x/mod v0.14.0
removes dependency on golang.org/x/sys/execabs

full diff:

- https://github.com/golang/tools/compare/v0.10.0...v0.16.0
- https://github.com/golang/mod/compare/v0.11.0...v0.14.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-08 11:02:26 +01:00
efae960e5a vendor: golang.org/x/net v0.19.0
drops various code to support go1.17 and older

full diff: https://golang.org/x/net/compare/v0.17.0...v0.19.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-08 10:55:39 +01:00
996cce9098 vendor: golang.org/x/sync v0.6.0
full diff: https://github.com/golang/sync/compare/v0.3.0...v0.6.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-08 10:52:47 +01:00
4b10e55256 vendor: github.com/google/go-cmp v0.6.0
- removes purego fallbacks

full diff: https://github.com/google/go-cmp/compare/v0.5.9...v0.6.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-08 10:25:45 +01:00
1ebc233b4b vendor: github.com/creack/pty v1.1.21
full diff: https://github.com/creack/pty/compare/v1.18.0...v1.21.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-08 10:22:09 +01:00
4b06a93c5e Merge pull request #4757 from thaJeztah/go_connection_0.5.0
vendor: github.com/docker/go-connections v0.5.0
2024-01-05 23:01:04 +01:00
b4fe77a124 vendor: github.com/docker/go-connections v0.5.0
no diff, as the tag is the same commit as we used already;
https://github.com/docker/go-connections/compare/fa09c952e3ea...v0.5.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-05 18:25:04 +01:00
acbc2540ae Merge pull request #4748 from thaJeztah/update_nosec
change back nolint -> nosec
2024-01-05 17:17:10 +01:00
1df7161b4b Merge pull request #4756 from dvdksn/fix-run-flag-example-heading-levels
docs: fix incorrect heading levels in docker run reference
2024-01-05 16:52:29 +01:00
909111b3ad docs: fix incorrect heading levels in docker run reference
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-01-05 16:41:26 +01:00
26e3eb32ce Merge pull request #4753 from thaJeztah/bump_engine
vendor: github.com/docker/docker v25.0.0-rc.1
2024-01-05 14:56:51 +01:00
b36c16d38d Merge pull request #4754 from thaJeztah/fix_seccomp_defaults
cli/command/container: parseSecurityOpts: fix --security-opt seccomp=builtin
2024-01-05 14:30:33 +01:00
bce868bdfd Merge pull request #4252 from ChrisChinchilla/chrisward/cmd-build-refresh
Docker build command docs refresh
2024-01-05 14:30:05 +01:00
b43ea528b8 vendor: github.com/docker/docker v25.0.0-rc.1
full diff: https://github.com/docker/docker/compare/v25.0.0-beta.3...v25.0.0-rc.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-05 13:23:48 +01:00
6d0aa0a52d cli/command/container: parseSecurityOpts: fix --security-opt seccomp=builtin
Docker v23.0 and up allow the daemon to be configured to have seccomp disabled
by default (using the "unconfined" profile as default), and introduced a new
"builtin" profile-name for the default (see [moby@f8795ed364586acd][1] and
[mnoby@ac449d6b5ad29a50][2]).

However, the CLI had no special handling for the "builtin" profile, which
resulted in it trying to load it as a file, which would fail;

    docker run -it --rm --security-opt seccomp=builtin busybox
    docker: opening seccomp profile (builtin) failed: open builtin: no such file or directory.
    See 'docker run --help'.

This patch adds a special case for the "builtin" profile, to allow using the
default profile on daemons with seccomp disabled (unconfined) by default.

[1]: f8795ed364
[2]: ac449d6b5a

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-05 12:19:00 +01:00
9be600a97b Docker build command docs refresh
Co-authored-by: Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: Chris Chinchilla <chris.ward@docker.com>
2024-01-05 00:07:34 +01:00
f0edc79530 change back nolint -> nosec
commit 9e1f8d646e changed this to a
"nolint" comment due to a regression in GoSec. That regression was
fixed, so we can go back to use the more fine-grained "nosec" comment.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-03 15:33:16 +01:00
1f9573bb05 Add Linode docker volume plugin
Signed-off-by: Zhiwei Liang <zliang@akamai.com>
2023-06-30 21:39:58 -04:00
577 changed files with 18623 additions and 11508 deletions

View File

@ -1,19 +0,0 @@
# This is a dummy CircleCI config file to avoid GitHub status failures reported
# on branches that don't use CircleCI. This file should be deleted when all
# branches are no longer dependent on CircleCI.
version: 2
jobs:
dummy:
docker:
- image: busybox
steps:
- run:
name: "dummy"
command: echo "dummy job"
workflows:
version: 2
ci:
jobs:
- dummy

View File

@ -4,6 +4,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
VERSION: ${{ github.ref }}
on:
workflow_dispatch:
push:
@ -16,7 +19,7 @@ on:
jobs:
prepare:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
outputs:
matrix: ${{ steps.platforms.outputs.matrix }}
steps:
@ -34,7 +37,7 @@ jobs:
echo ${{ steps.platforms.outputs.matrix }}
build:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
needs:
- prepare
strategy:
@ -86,8 +89,52 @@ jobs:
path: /tmp/out/*
if-no-files-found: error
bin-image:
runs-on: ubuntu-22.04
if: ${{ github.event_name != 'pull_request' && github.repository == 'docker/cli' }}
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Set up QEMU
uses: docker/setup-qemu-action@v3
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
-
name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: dockereng/cli-bin
tags: |
type=semver,pattern={{version}}
type=ref,event=branch
type=ref,event=pr
type=sha
-
name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_CLIBIN_USERNAME }}
password: ${{ secrets.DOCKERHUB_CLIBIN_TOKEN }}
-
name: Build and push image
uses: docker/bake-action@v4
with:
files: |
./docker-bake.hcl
${{ steps.meta.outputs.bake-file }}
targets: bin-image-cross
push: ${{ github.event_name != 'pull_request' }}
set: |
*.cache-from=type=gha,scope=bin-image
*.cache-to=type=gha,scope=bin-image,mode=max
prepare-plugins:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
outputs:
matrix: ${{ steps.platforms.outputs.matrix }}
steps:
@ -105,7 +152,7 @@ jobs:
echo ${{ steps.platforms.outputs.matrix }}
plugins:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
needs:
- prepare-plugins
strategy:

View File

@ -26,6 +26,8 @@ jobs:
codeql:
runs-on: 'ubuntu-latest'
timeout-minutes: 360
env:
DISABLE_WARN_OUTSIDE_CONTAINER: '1'
permissions:
actions: read
contents: read
@ -52,6 +54,16 @@ jobs:
uses: github/codeql-action/init@v3
with:
languages: go
# CodeQL 2.16.4's auto-build added support for multi-module repositories,
# and is trying to be smart by searching for modules in every directory,
# including vendor directories. If no module is found, it's creating one
# which is ... not what we want, so let's give it a "go.mod".
# see: https://github.com/docker/cli/pull/4944#issuecomment-2002034698
-
name: Create go.mod
run: |
ln -s vendor.mod go.mod
ln -s vendor.sum go.sum
-
name: Autobuild
uses: github/codeql-action/autobuild@v3

View File

@ -16,7 +16,7 @@ on:
jobs:
e2e:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
@ -28,11 +28,11 @@ jobs:
- alpine
- debian
engine-version:
# - 20.10-dind # FIXME: Fails on 20.10
- stable-dind # TODO: Use 20.10-dind, stable-dind is deprecated
include:
- target: non-experimental
engine-version: 19.03-dind
- 25.0 # latest
- 24.0 # latest - 1
- 23.0 # mirantis lts
# TODO(krissetto) 19.03 needs a look, doesn't work ubuntu 22.04 (cgroup errors).
# we could have a separate job that tests it against ubuntu 20.04
steps:
-
name: Checkout
@ -55,10 +55,11 @@ jobs:
make -f docker.Makefile test-e2e-${{ matrix.target }}
env:
BASE_VARIANT: ${{ matrix.base }}
E2E_ENGINE_VERSION: ${{ matrix.engine-version }}
ENGINE_VERSION: ${{ matrix.engine-version }}
TESTFLAGS: -coverprofile=/tmp/coverage/coverage.txt
-
name: Send to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
file: ./build/coverage/coverage.txt
token: ${{ secrets.CODECOV_TOKEN }}

View File

@ -16,7 +16,7 @@ on:
jobs:
ctn:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
-
name: Checkout
@ -31,9 +31,10 @@ jobs:
targets: test-coverage
-
name: Send to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
file: ./build/coverage/coverage.txt
token: ${{ secrets.CODECOV_TOKEN }}
host:
runs-on: ${{ matrix.os }}
@ -45,7 +46,7 @@ jobs:
fail-fast: false
matrix:
os:
- macos-11
- macos-12
# - windows-2022 # FIXME: some tests are failing on the Windows runner, as well as on Appveyor since June 24, 2018: https://ci.appveyor.com/project/docker/cli/history
steps:
-
@ -63,7 +64,7 @@ jobs:
name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.21.5
go-version: 1.21.8
-
name: Test
run: |
@ -73,7 +74,8 @@ jobs:
shell: bash
-
name: Send to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
file: /tmp/coverage.txt
working-directory: ${{ env.GOPATH }}/src/github.com/docker/cli
token: ${{ secrets.CODECOV_TOKEN }}

View File

@ -16,7 +16,7 @@ on:
jobs:
validate:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
@ -37,7 +37,7 @@ jobs:
# check that the generated Markdown and the checked-in files match
validate-md:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
-
name: Checkout
@ -57,7 +57,7 @@ jobs:
fi
validate-make:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:

View File

@ -4,12 +4,12 @@ ARG BASE_VARIANT=alpine
ARG ALPINE_VERSION=3.18
ARG BASE_DEBIAN_DISTRO=bookworm
ARG GO_VERSION=1.21.5
ARG XX_VERSION=1.2.1
ARG GO_VERSION=1.21.8
ARG XX_VERSION=1.4.0
ARG GOVERSIONINFO_VERSION=v1.3.0
ARG GOTESTSUM_VERSION=v1.10.0
ARG BUILDX_VERSION=0.12.0
ARG COMPOSE_VERSION=v2.22.0
ARG BUILDX_VERSION=0.12.1
ARG COMPOSE_VERSION=v2.24.3
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
@ -123,5 +123,8 @@ COPY --link . .
FROM scratch AS plugins
COPY --from=build-plugins /out .
FROM scratch AS bin-image
COPY --from=build /out/docker /docker
FROM scratch AS binary
COPY --from=build /out .

View File

@ -52,7 +52,7 @@ shellcheck: ## run shellcheck validation
.PHONY: fmt
fmt: ## run gofumpt (if present) or gofmt
@if command -v gofumpt > /dev/null; then \
gofumpt -w -d -lang=1.19 . ; \
gofumpt -w -d -lang=1.21 . ; \
else \
go list -f {{.Dir}} ./... | xargs gofmt -w -s -d ; \
fi

View File

@ -45,8 +45,8 @@ func main() {
}
var (
who, context string
preRun, debug bool
who, optContext string
preRun, debug bool
)
cmd := &cobra.Command{
Use: "helloworld",
@ -65,7 +65,7 @@ func main() {
fmt.Fprintf(dockerCli.Err(), "Plugin debug mode enabled")
}
switch context {
switch optContext {
case "Christmas":
fmt.Fprintf(dockerCli.Out(), "Merry Christmas!\n")
return nil
@ -92,7 +92,7 @@ func main() {
// These are intended to deliberately clash with the CLIs own top
// level arguments.
flags.BoolVarP(&debug, "debug", "D", false, "Enable debug")
flags.StringVarP(&context, "context", "c", "", "Is it Christmas?")
flags.StringVarP(&optContext, "context", "c", "", "Is it Christmas?")
cmd.AddCommand(goodbye, apiversion, exitStatus2)
return cmd

View File

@ -2,11 +2,14 @@ package manager
import (
"fmt"
"net/url"
"os"
"strings"
"sync"
"github.com/docker/cli/cli/command"
"github.com/spf13/cobra"
"go.opentelemetry.io/otel/attribute"
)
const (
@ -30,6 +33,10 @@ const (
// is, one which failed it's candidate test) and contains the
// reason for the failure.
CommandAnnotationPluginInvalid = "com.docker.cli.plugin-invalid"
// CommandAnnotationPluginCommandPath is added to overwrite the
// command path for a plugin invocation.
CommandAnnotationPluginCommandPath = "com.docker.cli.plugin.command_path"
)
var pluginCommandStubsOnce sync.Once
@ -98,3 +105,44 @@ func AddPluginCommandStubs(dockerCli command.Cli, rootCmd *cobra.Command) (err e
})
return err
}
const (
dockerCliAttributePrefix = attribute.Key("docker.cli")
cobraCommandPath = attribute.Key("cobra.command_path")
)
func getPluginResourceAttributes(cmd *cobra.Command, plugin Plugin) attribute.Set {
commandPath := cmd.Annotations[CommandAnnotationPluginCommandPath]
if commandPath == "" {
commandPath = fmt.Sprintf("%s %s", cmd.CommandPath(), plugin.Name)
}
attrSet := attribute.NewSet(
cobraCommandPath.String(commandPath),
)
kvs := make([]attribute.KeyValue, 0, attrSet.Len())
for iter := attrSet.Iter(); iter.Next(); {
attr := iter.Attribute()
kvs = append(kvs, attribute.KeyValue{
Key: dockerCliAttributePrefix + "." + attr.Key,
Value: attr.Value,
})
}
return attribute.NewSet(kvs...)
}
func appendPluginResourceAttributesEnvvar(env []string, cmd *cobra.Command, plugin Plugin) []string {
if attrs := getPluginResourceAttributes(cmd, plugin); attrs.Len() > 0 {
// values in environment variables need to be in baggage format
// otel/baggage package can be used after update to v1.22, currently it encodes incorrectly
attrsSlice := make([]string, attrs.Len())
for iter := attrs.Iter(); iter.Next(); {
i, v := iter.IndexedAttribute()
attrsSlice[i] = string(v.Key) + "=" + url.PathEscape(v.Value.AsString())
}
env = append(env, ResourceAttributesEnvvar+"="+strings.Join(attrsSlice, ","))
}
return env
}

View File

@ -11,16 +11,23 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/config/configfile"
"github.com/fvbommel/sortorder"
"github.com/spf13/cobra"
"golang.org/x/sync/errgroup"
)
// ReexecEnvvar is the name of an ennvar which is set to the command
// used to originally invoke the docker CLI when executing a
// plugin. Assuming $PATH and $CWD remain unchanged this should allow
// the plugin to re-execute the original CLI.
const ReexecEnvvar = "DOCKER_CLI_PLUGIN_ORIGINAL_CLI_COMMAND"
const (
// ReexecEnvvar is the name of an ennvar which is set to the command
// used to originally invoke the docker CLI when executing a
// plugin. Assuming $PATH and $CWD remain unchanged this should allow
// the plugin to re-execute the original CLI.
ReexecEnvvar = "DOCKER_CLI_PLUGIN_ORIGINAL_CLI_COMMAND"
// ResourceAttributesEnvvar is the name of the envvar that includes additional
// resource attributes for OTEL.
ResourceAttributesEnvvar = "OTEL_RESOURCE_ATTRIBUTES"
)
// errPluginNotFound is the error returned when a plugin could not be found.
type errPluginNotFound string
@ -42,10 +49,10 @@ func IsNotFound(err error) bool {
return ok
}
func getPluginDirs(dockerCli command.Cli) ([]string, error) {
func getPluginDirs(cfg *configfile.ConfigFile) ([]string, error) {
var pluginDirs []string
if cfg := dockerCli.ConfigFile(); cfg != nil {
if cfg != nil {
pluginDirs = append(pluginDirs, cfg.CLIPluginsExtraDirs...)
}
pluginDir, err := config.Path("cli-plugins")
@ -108,7 +115,7 @@ func listPluginCandidates(dirs []string) (map[string][]string, error) {
// GetPlugin returns a plugin on the system by its name
func GetPlugin(name string, dockerCli command.Cli, rootcmd *cobra.Command) (*Plugin, error) {
pluginDirs, err := getPluginDirs(dockerCli)
pluginDirs, err := getPluginDirs(dockerCli.ConfigFile())
if err != nil {
return nil, err
}
@ -138,7 +145,7 @@ func GetPlugin(name string, dockerCli command.Cli, rootcmd *cobra.Command) (*Plu
// ListPlugins produces a list of the plugins available on the system
func ListPlugins(dockerCli command.Cli, rootcmd *cobra.Command) ([]Plugin, error) {
pluginDirs, err := getPluginDirs(dockerCli)
pluginDirs, err := getPluginDirs(dockerCli.ConfigFile())
if err != nil {
return nil, err
}
@ -198,7 +205,7 @@ func PluginRunCommand(dockerCli command.Cli, name string, rootcmd *cobra.Command
return nil, errPluginNotFound(name)
}
exename := addExeSuffix(NamePrefix + name)
pluginDirs, err := getPluginDirs(dockerCli)
pluginDirs, err := getPluginDirs(dockerCli.ConfigFile())
if err != nil {
return nil, err
}
@ -235,6 +242,7 @@ func PluginRunCommand(dockerCli command.Cli, name string, rootcmd *cobra.Command
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, ReexecEnvvar+"="+os.Args[0])
cmd.Env = appendPluginResourceAttributesEnvvar(cmd.Env, rootcmd, plugin)
return cmd, nil
}

View File

@ -149,7 +149,7 @@ func TestGetPluginDirs(t *testing.T) {
expected := append([]string{pluginDir}, defaultSystemPluginDirs...)
var pluginDirs []string
pluginDirs, err = getPluginDirs(cli)
pluginDirs, err = getPluginDirs(cli.ConfigFile())
assert.Equal(t, strings.Join(expected, ":"), strings.Join(pluginDirs, ":"))
assert.NilError(t, err)
@ -160,7 +160,7 @@ func TestGetPluginDirs(t *testing.T) {
cli.SetConfigFile(&configfile.ConfigFile{
CLIPluginsExtraDirs: extras,
})
pluginDirs, err = getPluginDirs(cli)
pluginDirs, err = getPluginDirs(cli.ConfigFile())
assert.DeepEqual(t, expected, pluginDirs)
assert.NilError(t, err)
}

View File

@ -3,26 +3,19 @@ package plugin
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net"
"os"
"sync"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli-plugins/manager"
"github.com/docker/cli/cli-plugins/socket"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/connhelper"
"github.com/docker/docker/client"
"github.com/spf13/cobra"
)
// CLIPluginSocketEnvKey is used to pass the plugin being
// executed the abstract socket name it should listen on to know
// when the CLI has exited.
const CLIPluginSocketEnvKey = "DOCKER_CLI_PLUGIN_SOCKET"
// PersistentPreRunE must be called by any plugin command (or
// subcommand) which uses the cobra `PersistentPreRun*` hook. Plugins
// which do not make use of `PersistentPreRun*` do not need to call
@ -33,38 +26,6 @@ const CLIPluginSocketEnvKey = "DOCKER_CLI_PLUGIN_SOCKET"
// called.
var PersistentPreRunE func(*cobra.Command, []string) error
// closeOnCLISocketClose connects to the socket specified
// by the DOCKER_CLI_PLUGIN_SOCKET env var, if present, and attempts
// to read from it until it receives an EOF, which signals that
// the CLI is going to exit and the plugin should also exit.
func closeOnCLISocketClose(cancel func()) {
socketAddr, ok := os.LookupEnv(CLIPluginSocketEnvKey)
if !ok {
// if a plugin compiled against a more recent version of docker/cli
// is executed by an older CLI binary, ignore missing environment
// variable and behave as usual
return
}
addr, err := net.ResolveUnixAddr("unix", socketAddr)
if err != nil {
return
}
cliCloseConn, err := net.DialUnix("unix", nil, addr)
if err != nil {
return
}
go func() {
b := make([]byte, 1)
for {
_, err := cliCloseConn.Read(b)
if errors.Is(err, io.EOF) {
cancel()
}
}
}()
}
// RunPlugin executes the specified plugin command
func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager.Metadata) error {
tcmd := newPluginCommand(dockerCli, plugin, meta)
@ -81,7 +42,8 @@ func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager
}
ctx, cancel := context.WithCancel(cmdContext)
cmd.SetContext(ctx)
closeOnCLISocketClose(cancel)
// Set up the context to cancel based on signalling via CLI socket.
socket.ConnectAndWait(cancel)
var opts []command.CLIOption
if os.Getenv("DOCKER_CLI_PLUGIN_USE_DIAL_STDIO") != "" {

View File

@ -0,0 +1,80 @@
package socket
import (
"crypto/rand"
"encoding/hex"
"errors"
"io"
"net"
"os"
)
// EnvKey represents the well-known environment variable used to pass the plugin being
// executed the socket name it should listen on to coordinate with the host CLI.
const EnvKey = "DOCKER_CLI_PLUGIN_SOCKET"
// SetupConn sets up a Unix socket listener, establishes a goroutine to handle connections
// and update the conn pointer, and returns the listener for the socket (which the caller
// is responsible for closing when it's no longer needed).
func SetupConn(conn **net.UnixConn) (*net.UnixListener, error) {
listener, err := listen("docker_cli_" + randomID())
if err != nil {
return nil, err
}
accept(listener, conn)
return listener, nil
}
func randomID() string {
b := make([]byte, 16)
if _, err := rand.Read(b); err != nil {
panic(err) // This shouldn't happen
}
return hex.EncodeToString(b)
}
func accept(listener *net.UnixListener, conn **net.UnixConn) {
go func() {
for {
// ignore error here, if we failed to accept a connection,
// conn is nil and we fallback to previous behavior
*conn, _ = listener.AcceptUnix()
// perform any platform-specific actions on accept (e.g. unlink non-abstract sockets)
onAccept(*conn, listener)
}
}()
}
// ConnectAndWait connects to the socket passed via well-known env var,
// if present, and attempts to read from it until it receives an EOF, at which
// point cb is called.
func ConnectAndWait(cb func()) {
socketAddr, ok := os.LookupEnv(EnvKey)
if !ok {
// if a plugin compiled against a more recent version of docker/cli
// is executed by an older CLI binary, ignore missing environment
// variable and behave as usual
return
}
addr, err := net.ResolveUnixAddr("unix", socketAddr)
if err != nil {
return
}
conn, err := net.DialUnix("unix", nil, addr)
if err != nil {
return
}
go func() {
b := make([]byte, 1)
for {
_, err := conn.Read(b)
if errors.Is(err, io.EOF) {
cb()
return
}
}
}()
}

View File

@ -0,0 +1,19 @@
package socket
import (
"net"
"os"
"path/filepath"
"syscall"
)
func listen(socketname string) (*net.UnixListener, error) {
return net.ListenUnix("unix", &net.UnixAddr{
Name: filepath.Join(os.TempDir(), socketname),
Net: "unix",
})
}
func onAccept(conn *net.UnixConn, listener *net.UnixListener) {
syscall.Unlink(listener.Addr().String())
}

View File

@ -0,0 +1,20 @@
//go:build !darwin && !openbsd
package socket
import (
"net"
)
func listen(socketname string) (*net.UnixListener, error) {
return net.ListenUnix("unix", &net.UnixAddr{
Name: "@" + socketname,
Net: "unix",
})
}
func onAccept(conn *net.UnixConn, listener *net.UnixListener) {
// do nothing
// while on darwin and OpenBSD we would unlink here;
// on non-darwin the socket is abstract and not present on the filesystem
}

View File

@ -0,0 +1,19 @@
package socket
import (
"net"
"os"
"path/filepath"
"syscall"
)
func listen(socketname string) (*net.UnixListener, error) {
return net.ListenUnix("unix", &net.UnixAddr{
Name: filepath.Join(os.TempDir(), socketname),
Net: "unix",
})
}
func onAccept(conn *net.UnixConn, listener *net.UnixListener) {
syscall.Unlink(listener.Addr().String())
}

View File

@ -0,0 +1,133 @@
package socket
import (
"io/fs"
"net"
"os"
"runtime"
"strings"
"testing"
"time"
"gotest.tools/v3/assert"
"gotest.tools/v3/poll"
)
func TestSetupConn(t *testing.T) {
t.Run("updates conn when connected", func(t *testing.T) {
var conn *net.UnixConn
listener, err := SetupConn(&conn)
assert.NilError(t, err)
assert.Check(t, listener != nil, "returned nil listener but no error")
addr, err := net.ResolveUnixAddr("unix", listener.Addr().String())
assert.NilError(t, err, "failed to resolve listener address")
_, err = net.DialUnix("unix", nil, addr)
assert.NilError(t, err, "failed to dial returned listener")
pollConnNotNil(t, &conn)
})
t.Run("allows reconnects", func(t *testing.T) {
var conn *net.UnixConn
listener, err := SetupConn(&conn)
assert.NilError(t, err)
assert.Check(t, listener != nil, "returned nil listener but no error")
addr, err := net.ResolveUnixAddr("unix", listener.Addr().String())
assert.NilError(t, err, "failed to resolve listener address")
otherConn, err := net.DialUnix("unix", nil, addr)
assert.NilError(t, err, "failed to dial returned listener")
otherConn.Close()
_, err = net.DialUnix("unix", nil, addr)
assert.NilError(t, err, "failed to redial listener")
})
t.Run("does not leak sockets to local directory", func(t *testing.T) {
var conn *net.UnixConn
listener, err := SetupConn(&conn)
assert.NilError(t, err)
assert.Check(t, listener != nil, "returned nil listener but no error")
checkDirNoPluginSocket(t)
addr, err := net.ResolveUnixAddr("unix", listener.Addr().String())
assert.NilError(t, err, "failed to resolve listener address")
_, err = net.DialUnix("unix", nil, addr)
assert.NilError(t, err, "failed to dial returned listener")
checkDirNoPluginSocket(t)
})
}
func checkDirNoPluginSocket(t *testing.T) {
t.Helper()
files, err := os.ReadDir(".")
assert.NilError(t, err, "failed to list files in dir to check for leaked sockets")
for _, f := range files {
info, err := f.Info()
assert.NilError(t, err, "failed to check file info")
// check for a socket with `docker_cli_` in the name (from `SetupConn()`)
if strings.Contains(f.Name(), "docker_cli_") && info.Mode().Type() == fs.ModeSocket {
t.Fatal("found socket in a local directory")
}
}
}
func TestConnectAndWait(t *testing.T) {
t.Run("calls cancel func on EOF", func(t *testing.T) {
var conn *net.UnixConn
listener, err := SetupConn(&conn)
assert.NilError(t, err, "failed to setup listener")
done := make(chan struct{})
t.Setenv(EnvKey, listener.Addr().String())
cancelFunc := func() {
done <- struct{}{}
}
ConnectAndWait(cancelFunc)
pollConnNotNil(t, &conn)
conn.Close()
select {
case <-done:
case <-time.After(10 * time.Millisecond):
t.Fatal("cancel function not closed after 10ms")
}
})
// TODO: this test cannot be executed with `t.Parallel()`, due to
// relying on goroutine numbers to ensure correct behaviour
t.Run("connect goroutine exits after EOF", func(t *testing.T) {
var conn *net.UnixConn
listener, err := SetupConn(&conn)
assert.NilError(t, err, "failed to setup listener")
t.Setenv(EnvKey, listener.Addr().String())
numGoroutines := runtime.NumGoroutine()
ConnectAndWait(func() {})
assert.Equal(t, runtime.NumGoroutine(), numGoroutines+1)
pollConnNotNil(t, &conn)
conn.Close()
poll.WaitOn(t, func(t poll.LogT) poll.Result {
if runtime.NumGoroutine() > numGoroutines+1 {
return poll.Continue("waiting for connect goroutine to exit")
}
return poll.Success()
}, poll.WithDelay(1*time.Millisecond), poll.WithTimeout(10*time.Millisecond))
})
}
func pollConnNotNil(t *testing.T, conn **net.UnixConn) {
t.Helper()
poll.WaitOn(t, func(t poll.LogT) poll.Result {
if *conn == nil {
return poll.Continue("waiting for conn to not be nil")
}
return poll.Success()
}, poll.WithDelay(1*time.Millisecond), poll.WithTimeout(10*time.Millisecond))
}

View File

@ -470,7 +470,7 @@ Common Commands:
Management Commands:
{{- range managementSubCommands . }}
{{rpad (decoratedName .) (add .NamePadding 1)}}{{.Short}}{{ if isPlugin .}} {{vendorAndVersion .}}{{ end}}
{{rpad (decoratedName .) (add .NamePadding 1)}}{{.Short}}
{{- end}}
{{- end}}
@ -479,7 +479,7 @@ Management Commands:
Swarm Commands:
{{- range orchestratorSubCommands . }}
{{rpad (decoratedName .) (add .NamePadding 1)}}{{.Short}}{{ if isPlugin .}} {{vendorAndVersion .}}{{ end}}
{{rpad (decoratedName .) (add .NamePadding 1)}}{{.Short}}
{{- end}}
{{- end}}

View File

@ -0,0 +1,20 @@
package builder
import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
type fakeClient struct {
client.Client
builderPruneFunc func(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error)
}
func (c *fakeClient) BuildCachePrune(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) {
if c.builderPruneFunc != nil {
return c.builderPruneFunc(ctx, opts)
}
return nil, nil
}

View File

@ -66,8 +66,10 @@ func runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions)
if options.all {
warning = allCacheWarning
}
if !options.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) {
return 0, "", nil
if !options.force {
if r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), warning); !r || err != nil {
return 0, "", err
}
}
report, err := dockerCli.Client().BuildCachePrune(ctx, types.BuildCachePruneOptions{

View File

@ -0,0 +1,28 @@
package builder
import (
"context"
"errors"
"testing"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"gotest.tools/v3/assert"
)
func TestBuilderPromptTermination(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
cli := test.NewFakeCli(&fakeClient{
builderPruneFunc: func(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) {
return nil, errors.New("fakeClient builderPruneFunc should not be called")
},
})
cmd := NewPruneCommand(cli)
test.TerminatePrompt(ctx, t, cmd, cli, func(t *testing.T, err error) {
t.Helper()
assert.ErrorIs(t, err, command.ErrPromptTerminated)
})
}

View File

@ -35,7 +35,7 @@ func newCreateCommand(dockerCli command.Cli) *cobra.Command {
flags := cmd.Flags()
flags.BoolVar(&opts.leaveRunning, "leave-running", false, "Leave the container running after checkpoint")
flags.StringVarP(&opts.checkpointDir, "checkpoint-dir", "", "", "Use a custom checkpoint storage directory")
flags.StringVar(&opts.checkpointDir, "checkpoint-dir", "", "Use a custom checkpoint storage directory")
return cmd
}

View File

@ -30,7 +30,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
}
flags := cmd.Flags()
flags.StringVarP(&opts.checkpointDir, "checkpoint-dir", "", "", "Use a custom checkpoint storage directory")
flags.StringVar(&opts.checkpointDir, "checkpoint-dir", "", "Use a custom checkpoint storage directory")
return cmd
}

View File

@ -27,7 +27,7 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
}
flags := cmd.Flags()
flags.StringVarP(&opts.checkpointDir, "checkpoint-dir", "", "", "Use a custom checkpoint storage directory")
flags.StringVar(&opts.checkpointDir, "checkpoint-dir", "", "Use a custom checkpoint storage directory")
return cmd
}

View File

@ -11,19 +11,11 @@ import (
"github.com/moby/term"
)
// CLIOption applies a modification on a DockerCli.
// CLIOption is a functional argument to apply options to a [DockerCli]. These
// options can be passed to [NewDockerCli] to initialize a new CLI, or
// applied with [DockerCli.Initialize] or [DockerCli.Apply].
type CLIOption func(cli *DockerCli) error
// DockerCliOption applies a modification on a DockerCli.
//
// Deprecated: use [CLIOption] instead.
type DockerCliOption = CLIOption
// InitializeOpt is the type of the functional options passed to DockerCli.Initialize
//
// Deprecated: use [CLIOption] instead.
type InitializeOpt = CLIOption
// WithStandardStreams sets a cli in, out and err streams with the standard streams.
func WithStandardStreams() CLIOption {
return func(cli *DockerCli) error {

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/volume"
"github.com/spf13/cobra"
)
@ -17,7 +18,7 @@ type ValidArgsFn func(cmd *cobra.Command, args []string, toComplete string) ([]s
// ImageNames offers completion for images present within the local store
func ImageNames(dockerCli command.Cli) ValidArgsFn {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
list, err := dockerCli.Client().ImageList(cmd.Context(), types.ImageListOptions{})
list, err := dockerCli.Client().ImageList(cmd.Context(), image.ListOptions{})
if err != nil {
return nil, cobra.ShellCompDirectiveError
}

View File

@ -38,7 +38,7 @@ func newConfigListCommand(dockerCli command.Cli) *cobra.Command {
flags := cmd.Flags()
flags.BoolVarP(&listOpts.Quiet, "quiet", "q", false, "Only display IDs")
flags.StringVarP(&listOpts.Format, "format", "", "", flagsHelper.FormatHelp)
flags.StringVar(&listOpts.Format, "format", "", flagsHelper.FormatHelp)
flags.VarP(&listOpts.Filter, "filter", "f", "Filter output based on conditions provided")
return cmd

View File

@ -43,22 +43,21 @@ func inspectContainerAndCheckState(ctx context.Context, apiClient client.APIClie
}
// NewAttachCommand creates a new cobra.Command for `docker attach`
func NewAttachCommand(dockerCli command.Cli) *cobra.Command {
func NewAttachCommand(dockerCLI command.Cli) *cobra.Command {
var opts AttachOptions
var ctr string
cmd := &cobra.Command{
Use: "attach [OPTIONS] CONTAINER",
Short: "Attach local standard input, output, and error streams to a running container",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
ctr = args[0]
return RunAttach(cmd.Context(), dockerCli, ctr, &opts)
containerID := args[0]
return RunAttach(cmd.Context(), dockerCLI, containerID, &opts)
},
Annotations: map[string]string{
"aliases": "docker container attach, docker attach",
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false, func(ctr types.Container) bool {
ValidArgsFunction: completion.ContainerNames(dockerCLI, false, func(ctr types.Container) bool {
return ctr.State != "paused"
}),
}
@ -71,13 +70,13 @@ func NewAttachCommand(dockerCli command.Cli) *cobra.Command {
}
// RunAttach executes an `attach` command
func RunAttach(ctx context.Context, dockerCLI command.Cli, target string, opts *AttachOptions) error {
func RunAttach(ctx context.Context, dockerCLI command.Cli, containerID string, opts *AttachOptions) error {
apiClient := dockerCLI.Client()
// request channel to wait for client
resultC, errC := apiClient.ContainerWait(ctx, target, "")
resultC, errC := apiClient.ContainerWait(ctx, containerID, "")
c, err := inspectContainerAndCheckState(ctx, apiClient, target)
c, err := inspectContainerAndCheckState(ctx, apiClient, containerID)
if err != nil {
return err
}
@ -106,11 +105,11 @@ func RunAttach(ctx context.Context, dockerCLI command.Cli, target string, opts *
if opts.Proxy && !c.Config.Tty {
sigc := notifyAllSignals()
go ForwardAllSignals(ctx, apiClient, target, sigc)
go ForwardAllSignals(ctx, apiClient, containerID, sigc)
defer signal.StopCatch(sigc)
}
resp, errAttach := apiClient.ContainerAttach(ctx, target, options)
resp, errAttach := apiClient.ContainerAttach(ctx, containerID, options)
if errAttach != nil {
return errAttach
}
@ -124,13 +123,13 @@ func RunAttach(ctx context.Context, dockerCLI command.Cli, target string, opts *
// the container and not exit.
//
// Recheck the container's state to avoid attach block.
_, err = inspectContainerAndCheckState(ctx, apiClient, target)
_, err = inspectContainerAndCheckState(ctx, apiClient, containerID)
if err != nil {
return err
}
if c.Config.Tty && dockerCLI.Out().IsTerminal() {
resizeTTY(ctx, dockerCLI, target)
resizeTTY(ctx, dockerCLI, containerID)
}
streamer := hijackedIOStreamer{

View File

@ -6,6 +6,8 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/system"
"github.com/docker/docker/client"
@ -23,7 +25,7 @@ type fakeClient struct {
platform *specs.Platform,
containerName string) (container.CreateResponse, error)
containerStartFunc func(containerID string, options container.StartOptions) error
imageCreateFunc func(parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error)
imageCreateFunc func(parentReference string, options image.CreateOptions) (io.ReadCloser, error)
infoFunc func() (system.Info, error)
containerStatPathFunc func(containerID, path string) (types.ContainerPathStat, error)
containerCopyFromFunc func(containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error)
@ -34,6 +36,7 @@ type fakeClient struct {
containerExecResizeFunc func(id string, options container.ResizeOptions) error
containerRemoveFunc func(ctx context.Context, containerID string, options container.RemoveOptions) error
containerKillFunc func(ctx context.Context, containerID, signal string) error
containerPruneFunc func(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error)
Version string
}
@ -90,7 +93,7 @@ func (f *fakeClient) ContainerRemove(ctx context.Context, containerID string, op
return nil
}
func (f *fakeClient) ImageCreate(_ context.Context, parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) {
func (f *fakeClient) ImageCreate(_ context.Context, parentReference string, options image.CreateOptions) (io.ReadCloser, error) {
if f.imageCreateFunc != nil {
return f.imageCreateFunc(parentReference, options)
}
@ -163,3 +166,10 @@ func (f *fakeClient) ContainerKill(ctx context.Context, containerID, signal stri
}
return nil
}
func (f *fakeClient) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error) {
if f.containerPruneFunc != nil {
return f.containerPruneFunc(ctx, pruneFilters)
}
return types.ContainersPruneReport{}, nil
}

View File

@ -15,8 +15,8 @@ import (
"github.com/docker/cli/cli/command/image"
"github.com/docker/cli/cli/streams"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
imagetypes "github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/errdefs"
"github.com/docker/docker/pkg/jsonmessage"
@ -119,7 +119,7 @@ func pullImage(ctx context.Context, dockerCli command.Cli, img string, options *
return err
}
responseBody, err := dockerCli.Client().ImageCreate(ctx, img, types.ImageCreateOptions{
responseBody, err := dockerCli.Client().ImageCreate(ctx, img, imagetypes.CreateOptions{
RegistryAuth: encodedAuth,
Platform: options.platform,
})

View File

@ -15,8 +15,8 @@ import (
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/notary"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/system"
"github.com/google/go-cmp/cmp"
@ -134,7 +134,7 @@ func TestCreateContainerImagePullPolicy(t *testing.T) {
return container.CreateResponse{ID: containerID}, nil
}
},
imageCreateFunc: func(parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) {
imageCreateFunc: func(parentReference string, options image.CreateOptions) (io.ReadCloser, error) {
defer func() { pullCounter++ }()
return io.NopCloser(strings.NewReader("")), nil
},

View File

@ -66,12 +66,12 @@ func NewExecCommand(dockerCli command.Cli) *cobra.Command {
flags := cmd.Flags()
flags.SetInterspersed(false)
flags.StringVarP(&options.DetachKeys, "detach-keys", "", "", "Override the key sequence for detaching a container")
flags.StringVar(&options.DetachKeys, "detach-keys", "", "Override the key sequence for detaching a container")
flags.BoolVarP(&options.Interactive, "interactive", "i", false, "Keep STDIN open even if not attached")
flags.BoolVarP(&options.TTY, "tty", "t", false, "Allocate a pseudo-TTY")
flags.BoolVarP(&options.Detach, "detach", "d", false, "Detached mode: run command in the background")
flags.StringVarP(&options.User, "user", "u", "", `Username or UID (format: "<name|uid>[:<group|gid>]")`)
flags.BoolVarP(&options.Privileged, "privileged", "", false, "Give extended privileges to the command")
flags.BoolVar(&options.Privileged, "privileged", false, "Give extended privileges to the command")
flags.VarP(&options.Env, "env", "e", "Set environment variables")
flags.SetAnnotation("env", "version", []string{"1.25"})
flags.Var(&options.EnvFile, "env-file", "Read in a file of environment variables")

View File

@ -55,7 +55,7 @@ func NewPsCommand(dockerCLI command.Cli) *cobra.Command {
flags.BoolVar(&options.noTrunc, "no-trunc", false, "Don't truncate output")
flags.BoolVarP(&options.nLatest, "latest", "l", false, "Show the latest created container (includes all states)")
flags.IntVarP(&options.last, "last", "n", -1, "Show n last created containers (includes all states)")
flags.StringVarP(&options.format, "format", "", "", flagsHelper.FormatHelp)
flags.StringVar(&options.format, "format", "", flagsHelper.FormatHelp)
flags.VarP(&options.filter, "filter", "f", "Filter output based on conditions provided")
return cmd

View File

@ -28,6 +28,20 @@ import (
cdi "tags.cncf.io/container-device-interface/pkg/parser"
)
const (
// TODO(thaJeztah): define these in the API-types, or query available defaults
// from the daemon, or require "local" profiles to be an absolute path or
// relative paths starting with "./". The daemon-config has consts for this
// but we don't want to import that package:
// https://github.com/moby/moby/blob/v23.0.0/daemon/config/config.go#L63-L67
// seccompProfileDefault is the built-in default seccomp profile.
seccompProfileDefault = "builtin"
// seccompProfileUnconfined is a special profile name for seccomp to use an
// "unconfined" seccomp profile.
seccompProfileUnconfined = "unconfined"
)
var deviceCgroupRuleRegexp = regexp.MustCompile(`^[acb] ([0-9]+|\*):([0-9]+|\*) [rwm]{1,3}$`)
// containerOptions is a data object with all the options for creating a container
@ -914,16 +928,23 @@ func parseSecurityOpts(securityOpts []string) ([]string, error) {
// "no-new-privileges" is the only option that does not require a value.
return securityOpts, errors.Errorf("Invalid --security-opt: %q", opt)
}
if k == "seccomp" && v != "unconfined" {
f, err := os.ReadFile(v)
if err != nil {
return securityOpts, errors.Errorf("opening seccomp profile (%s) failed: %v", v, err)
if k == "seccomp" {
switch v {
case seccompProfileDefault, seccompProfileUnconfined:
// known special names for built-in profiles, nothing to do.
default:
// value may be a filename, in which case we send the profile's
// content if it's valid JSON.
f, err := os.ReadFile(v)
if err != nil {
return securityOpts, errors.Errorf("opening seccomp profile (%s) failed: %v", v, err)
}
b := bytes.NewBuffer(nil)
if err := json.Compact(b, f); err != nil {
return securityOpts, errors.Errorf("compacting json for seccomp profile (%s) failed: %v", v, err)
}
securityOpts[key] = fmt.Sprintf("seccomp=%s", b.Bytes())
}
b := bytes.NewBuffer(nil)
if err := json.Compact(b, f); err != nil {
return securityOpts, errors.Errorf("compacting json for seccomp profile (%s) failed: %v", v, err)
}
securityOpts[key] = fmt.Sprintf("seccomp=%s", b.Bytes())
}
}

View File

@ -53,8 +53,10 @@ Are you sure you want to continue?`
func runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions) (spaceReclaimed uint64, output string, err error) {
pruneFilters := command.PruneFilters(dockerCli, options.filter.Value())
if !options.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) {
return 0, "", nil
if !options.force {
if r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), warning); !r || err != nil {
return 0, "", err
}
}
report, err := dockerCli.Client().ContainersPrune(ctx, pruneFilters)

View File

@ -0,0 +1,29 @@
package container
import (
"context"
"testing"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/pkg/errors"
"gotest.tools/v3/assert"
)
func TestContainerPrunePromptTermination(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
cli := test.NewFakeCli(&fakeClient{
containerPruneFunc: func(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error) {
return types.ContainersPruneReport{}, errors.New("fakeClient containerPruneFunc should not be called")
},
})
cmd := NewPruneCommand(cli)
test.TerminatePrompt(ctx, t, cmd, cli, func(t *testing.T, err error) {
t.Helper()
assert.ErrorIs(t, err, command.ErrPromptTerminated)
})
}

View File

@ -28,13 +28,6 @@ type StartOptions struct {
Containers []string
}
// NewStartOptions creates a new StartOptions.
//
// Deprecated: create a new [StartOptions] directly.
func NewStartOptions() StartOptions {
return StartOptions{}
}
// NewStartCommand creates a new cobra.Command for `docker start`
func NewStartCommand(dockerCli command.Cli) *cobra.Command {
var opts StartOptions

View File

@ -18,6 +18,7 @@ import (
"github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/filters"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@ -106,15 +107,6 @@ var acceptedStatsFilters = map[string]bool{
func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions) error {
apiClient := dockerCLI.Client()
// Get the daemonOSType if not set already
if daemonOSType == "" {
sv, err := apiClient.ServerVersion(ctx)
if err != nil {
return err
}
daemonOSType = sv.Os
}
// waitFirst is a WaitGroup to wait first stat data's reach for each container
waitFirst := &sync.WaitGroup{}
// closeChan is a non-buffered channel used to collect errors from goroutines.
@ -138,9 +130,9 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
return err
}
eh := command.InitEventHandler()
eh := newEventHandler()
if options.All {
eh.Handle(events.ActionCreate, func(e events.Message) {
eh.setHandler(events.ActionCreate, func(e events.Message) {
s := NewStats(e.Actor.ID[:12])
if cStats.add(s) {
waitFirst.Add(1)
@ -149,7 +141,7 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
})
}
eh.Handle(events.ActionStart, func(e events.Message) {
eh.setHandler(events.ActionStart, func(e events.Message) {
s := NewStats(e.Actor.ID[:12])
if cStats.add(s) {
waitFirst.Add(1)
@ -158,7 +150,7 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
})
if !options.All {
eh.Handle(events.ActionDie, func(e events.Message) {
eh.setHandler(events.ActionDie, func(e events.Message) {
cStats.remove(e.Actor.ID[:12])
})
}
@ -195,7 +187,7 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
}
eventChan := make(chan events.Message)
go eh.Watch(eventChan)
go eh.watch(eventChan)
stopped := make(chan struct{})
go monitorContainerEvents(started, eventChan, stopped)
defer close(stopped)
@ -267,6 +259,12 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
format = formatter.TableFormatKey
}
}
if daemonOSType == "" {
// Get the daemonOSType if not set already. The daemonOSType variable
// should already be set when collecting stats as part of "collect()",
// so we unlikely hit this code in practice.
daemonOSType = dockerCLI.ServerInfo().OSType
}
statsCtx := formatter.Context{
Output: dockerCLI.Out(),
Format: NewStatsFormat(format, daemonOSType),
@ -316,3 +314,31 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
}
return err
}
// newEventHandler initializes and returns an eventHandler
func newEventHandler() *eventHandler {
return &eventHandler{handlers: make(map[events.Action]func(events.Message))}
}
// eventHandler allows for registering specific events to setHandler.
type eventHandler struct {
handlers map[events.Action]func(events.Message)
}
func (eh *eventHandler) setHandler(action events.Action, handler func(events.Message)) {
eh.handlers[action] = handler
}
// watch ranges over the passed in event chan and processes the events based on the
// handlers created for a given action.
// To stop watching, close the event chan.
func (eh *eventHandler) watch(c <-chan events.Message) {
for e := range c {
h, exists := eh.handlers[e.Action]
if !exists {
continue
}
logrus.Debugf("event handler: received event: %v", e)
go h(e)
}
}

View File

@ -9,12 +9,16 @@ import (
// EventHandler is abstract interface for user to customize
// own handle functions of each type of events
//
// Deprecated: EventHandler is no longer used, and will be removed in the next release.
type EventHandler interface {
Handle(action events.Action, h func(events.Message))
Watch(c <-chan events.Message)
}
// InitEventHandler initializes and returns an EventHandler
//
// Deprecated: InitEventHandler is no longer used, and will be removed in the next release.
func InitEventHandler() EventHandler {
return &eventHandler{handlers: make(map[events.Action]func(events.Message))}
}

View File

@ -234,7 +234,8 @@ func GetContextFromURL(out io.Writer, remoteURL, dockerfileName string) (io.Read
// getWithStatusError does an http.Get() and returns an error if the
// status code is 4xx or 5xx.
func getWithStatusError(url string) (resp *http.Response, err error) {
if resp, err = http.Get(url); err != nil { //nolint:gosec // Ignore G107: Potential HTTP request made with variable url
//#nosec G107 -- Ignore G107: Potential HTTP request made with variable url
if resp, err = http.Get(url); err != nil {
return nil, err
}
if resp.StatusCode < http.StatusBadRequest {

View File

@ -129,7 +129,6 @@ func TestGetContextFromReaderString(t *testing.T) {
tarReader := tar.NewReader(tarArchive)
_, err = tarReader.Next()
if err != nil {
t.Fatalf("Error when reading tar archive: %s", err)
}

View File

@ -17,15 +17,15 @@ type fakeClient struct {
client.Client
imageTagFunc func(string, string) error
imageSaveFunc func(images []string) (io.ReadCloser, error)
imageRemoveFunc func(image string, options types.ImageRemoveOptions) ([]image.DeleteResponse, error)
imagePushFunc func(ref string, options types.ImagePushOptions) (io.ReadCloser, error)
imageRemoveFunc func(image string, options image.RemoveOptions) ([]image.DeleteResponse, error)
imagePushFunc func(ref string, options image.PushOptions) (io.ReadCloser, error)
infoFunc func() (system.Info, error)
imagePullFunc func(ref string, options types.ImagePullOptions) (io.ReadCloser, error)
imagePullFunc func(ref string, options image.PullOptions) (io.ReadCloser, error)
imagesPruneFunc func(pruneFilter filters.Args) (types.ImagesPruneReport, error)
imageLoadFunc func(input io.Reader, quiet bool) (types.ImageLoadResponse, error)
imageListFunc func(options types.ImageListOptions) ([]image.Summary, error)
imageListFunc func(options image.ListOptions) ([]image.Summary, error)
imageInspectFunc func(image string) (types.ImageInspect, []byte, error)
imageImportFunc func(source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error)
imageImportFunc func(source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error)
imageHistoryFunc func(image string) ([]image.HistoryResponseItem, error)
imageBuildFunc func(context.Context, io.Reader, types.ImageBuildOptions) (types.ImageBuildResponse, error)
}
@ -45,7 +45,7 @@ func (cli *fakeClient) ImageSave(_ context.Context, images []string) (io.ReadClo
}
func (cli *fakeClient) ImageRemove(_ context.Context, img string,
options types.ImageRemoveOptions,
options image.RemoveOptions,
) ([]image.DeleteResponse, error) {
if cli.imageRemoveFunc != nil {
return cli.imageRemoveFunc(img, options)
@ -53,7 +53,7 @@ func (cli *fakeClient) ImageRemove(_ context.Context, img string,
return []image.DeleteResponse{}, nil
}
func (cli *fakeClient) ImagePush(_ context.Context, ref string, options types.ImagePushOptions) (io.ReadCloser, error) {
func (cli *fakeClient) ImagePush(_ context.Context, ref string, options image.PushOptions) (io.ReadCloser, error) {
if cli.imagePushFunc != nil {
return cli.imagePushFunc(ref, options)
}
@ -67,7 +67,7 @@ func (cli *fakeClient) Info(_ context.Context) (system.Info, error) {
return system.Info{}, nil
}
func (cli *fakeClient) ImagePull(_ context.Context, ref string, options types.ImagePullOptions) (io.ReadCloser, error) {
func (cli *fakeClient) ImagePull(_ context.Context, ref string, options image.PullOptions) (io.ReadCloser, error) {
if cli.imagePullFunc != nil {
cli.imagePullFunc(ref, options)
}
@ -88,7 +88,7 @@ func (cli *fakeClient) ImageLoad(_ context.Context, input io.Reader, quiet bool)
return types.ImageLoadResponse{}, nil
}
func (cli *fakeClient) ImageList(_ context.Context, options types.ImageListOptions) ([]image.Summary, error) {
func (cli *fakeClient) ImageList(_ context.Context, options image.ListOptions) ([]image.Summary, error) {
if cli.imageListFunc != nil {
return cli.imageListFunc(options)
}
@ -103,7 +103,7 @@ func (cli *fakeClient) ImageInspectWithRaw(_ context.Context, img string) (types
}
func (cli *fakeClient) ImageImport(_ context.Context, source types.ImageImportSource, ref string,
options types.ImageImportOptions,
options image.ImportOptions,
) (io.ReadCloser, error) {
if cli.imageImportFunc != nil {
return cli.imageImportFunc(source, ref, options)

View File

@ -9,6 +9,7 @@ import (
"github.com/docker/cli/cli/command"
dockeropts "github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/spf13/cobra"
)
@ -78,7 +79,7 @@ func runImport(ctx context.Context, dockerCli command.Cli, options importOptions
}
}
responseBody, err := dockerCli.Client().ImageImport(ctx, source, options.reference, types.ImageImportOptions{
responseBody, err := dockerCli.Client().ImageImport(ctx, source, options.reference, image.ImportOptions{
Message: options.message,
Changes: options.changes.GetAll(),
Platform: options.platform,

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/image"
"github.com/pkg/errors"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@ -17,7 +18,7 @@ func TestNewImportCommandErrors(t *testing.T) {
name string
args []string
expectedError string
imageImportFunc func(source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error)
imageImportFunc func(source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error)
}{
{
name: "wrong-args",
@ -28,7 +29,7 @@ func TestNewImportCommandErrors(t *testing.T) {
name: "import-failed",
args: []string{"testdata/import-command-success.input.txt"},
expectedError: "something went wrong",
imageImportFunc: func(source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) {
imageImportFunc: func(source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
return nil, errors.Errorf("something went wrong")
},
},
@ -52,7 +53,7 @@ func TestNewImportCommandSuccess(t *testing.T) {
testCases := []struct {
name string
args []string
imageImportFunc func(source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error)
imageImportFunc func(source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error)
}{
{
name: "simple",
@ -65,7 +66,7 @@ func TestNewImportCommandSuccess(t *testing.T) {
{
name: "double",
args: []string{"-", "image:local"},
imageImportFunc: func(source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) {
imageImportFunc: func(source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
assert.Check(t, is.Equal("image:local", ref))
return io.NopCloser(strings.NewReader("")), nil
},
@ -73,7 +74,7 @@ func TestNewImportCommandSuccess(t *testing.T) {
{
name: "message",
args: []string{"--message", "test message", "-"},
imageImportFunc: func(source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) {
imageImportFunc: func(source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
assert.Check(t, is.Equal("test message", options.Message))
return io.NopCloser(strings.NewReader("")), nil
},
@ -81,7 +82,7 @@ func TestNewImportCommandSuccess(t *testing.T) {
{
name: "change",
args: []string{"--change", "ENV DEBUG=true", "-"},
imageImportFunc: func(source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) {
imageImportFunc: func(source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
assert.Check(t, is.Equal("ENV DEBUG=true", options.Changes[0]))
return io.NopCloser(strings.NewReader("")), nil
},
@ -89,7 +90,7 @@ func TestNewImportCommandSuccess(t *testing.T) {
{
name: "change legacy syntax",
args: []string{"--change", "ENV DEBUG true", "-"},
imageImportFunc: func(source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) {
imageImportFunc: func(source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
assert.Check(t, is.Equal("ENV DEBUG true", options.Changes[0]))
return io.NopCloser(strings.NewReader("")), nil
},

View File

@ -2,13 +2,15 @@ package image
import (
"context"
"fmt"
"io"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/image"
"github.com/spf13/cobra"
)
@ -21,10 +23,11 @@ type imagesOptions struct {
showDigests bool
format string
filter opts.FilterOpt
calledAs string
}
// NewImagesCommand creates a new `docker images` command
func NewImagesCommand(dockerCli command.Cli) *cobra.Command {
func NewImagesCommand(dockerCLI command.Cli) *cobra.Command {
options := imagesOptions{filter: opts.NewFilterOpt()}
cmd := &cobra.Command{
@ -35,7 +38,11 @@ func NewImagesCommand(dockerCli command.Cli) *cobra.Command {
if len(args) > 0 {
options.matchName = args[0]
}
return runImages(cmd.Context(), dockerCli, options)
// Pass through how the command was invoked. We use this to print
// warnings when an ambiguous argument was passed when using the
// legacy (top-level) "docker images" subcommand.
options.calledAs = cmd.CalledAs()
return runImages(cmd.Context(), dockerCLI, options)
},
Annotations: map[string]string{
"category-top": "7",
@ -55,33 +62,31 @@ func NewImagesCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func newListCommand(dockerCli command.Cli) *cobra.Command {
cmd := *NewImagesCommand(dockerCli)
func newListCommand(dockerCLI command.Cli) *cobra.Command {
cmd := *NewImagesCommand(dockerCLI)
cmd.Aliases = []string{"list"}
cmd.Use = "ls [OPTIONS] [REPOSITORY[:TAG]]"
return &cmd
}
func runImages(ctx context.Context, dockerCli command.Cli, options imagesOptions) error {
func runImages(ctx context.Context, dockerCLI command.Cli, options imagesOptions) error {
filters := options.filter.Value()
if options.matchName != "" {
filters.Add("reference", options.matchName)
}
listOptions := types.ImageListOptions{
images, err := dockerCLI.Client().ImageList(ctx, image.ListOptions{
All: options.all,
Filters: filters,
}
images, err := dockerCli.Client().ImageList(ctx, listOptions)
})
if err != nil {
return err
}
format := options.format
if len(format) == 0 {
if len(dockerCli.ConfigFile().ImagesFormat) > 0 && !options.quiet {
format = dockerCli.ConfigFile().ImagesFormat
if len(dockerCLI.ConfigFile().ImagesFormat) > 0 && !options.quiet {
format = dockerCLI.ConfigFile().ImagesFormat
} else {
format = formatter.TableFormatKey
}
@ -89,11 +94,50 @@ func runImages(ctx context.Context, dockerCli command.Cli, options imagesOptions
imageCtx := formatter.ImageContext{
Context: formatter.Context{
Output: dockerCli.Out(),
Output: dockerCLI.Out(),
Format: formatter.NewImageFormat(format, options.quiet, options.showDigests),
Trunc: !options.noTrunc,
},
Digest: options.showDigests,
}
return formatter.ImageWrite(imageCtx, images)
if err := formatter.ImageWrite(imageCtx, images); err != nil {
return err
}
if options.matchName != "" && len(images) == 0 && options.calledAs == "images" {
printAmbiguousHint(dockerCLI.Err(), options.matchName)
}
return nil
}
// printAmbiguousHint prints an informational warning if the provided filter
// argument is ambiguous.
//
// The "docker images" top-level subcommand predates the "docker <object> <verb>"
// convention (e.g. "docker image ls"), but accepts a positional argument to
// search/filter images by name (globbing). It's common for users to accidentally
// mistake these commands, and to use (e.g.) "docker images ls", expecting
// to see all images, but ending up with an empty list because no image named
// "ls" was found.
//
// Disallowing these search-terms would be a breaking change, but we can print
// and informational message to help the users correct their mistake.
func printAmbiguousHint(stdErr io.Writer, matchName string) {
switch matchName {
// List of subcommands for "docker image" and their aliases (see "docker image --help"):
case "build",
"history",
"import",
"inspect",
"list",
"load",
"ls",
"prune",
"pull",
"push",
"rm",
"save",
"tag":
_, _ = fmt.Fprintf(stdErr, "\nNo images found matching %q: did you mean \"docker image %[1]s\"?\n", matchName)
}
}

View File

@ -7,7 +7,6 @@ import (
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/image"
"github.com/pkg/errors"
"gotest.tools/v3/assert"
@ -20,7 +19,7 @@ func TestNewImagesCommandErrors(t *testing.T) {
name string
args []string
expectedError string
imageListFunc func(options types.ImageListOptions) ([]image.Summary, error)
imageListFunc func(options image.ListOptions) ([]image.Summary, error)
}{
{
name: "wrong-args",
@ -30,7 +29,7 @@ func TestNewImagesCommandErrors(t *testing.T) {
{
name: "failed-list",
expectedError: "something went wrong",
imageListFunc: func(options types.ImageListOptions) ([]image.Summary, error) {
imageListFunc: func(options image.ListOptions) ([]image.Summary, error) {
return []image.Summary{}, errors.Errorf("something went wrong")
},
},
@ -48,7 +47,7 @@ func TestNewImagesCommandSuccess(t *testing.T) {
name string
args []string
imageFormat string
imageListFunc func(options types.ImageListOptions) ([]image.Summary, error)
imageListFunc func(options image.ListOptions) ([]image.Summary, error)
}{
{
name: "simple",
@ -65,7 +64,7 @@ func TestNewImagesCommandSuccess(t *testing.T) {
{
name: "match-name",
args: []string{"image"},
imageListFunc: func(options types.ImageListOptions) ([]image.Summary, error) {
imageListFunc: func(options image.ListOptions) ([]image.Summary, error) {
assert.Check(t, is.Equal("image", options.Filters.Get("reference")[0]))
return []image.Summary{}, nil
},
@ -73,7 +72,7 @@ func TestNewImagesCommandSuccess(t *testing.T) {
{
name: "filters",
args: []string{"--filter", "name=value"},
imageListFunc: func(options types.ImageListOptions) ([]image.Summary, error) {
imageListFunc: func(options image.ListOptions) ([]image.Summary, error) {
assert.Check(t, is.Equal("value", options.Filters.Get("name")[0]))
return []image.Summary{}, nil
},
@ -96,3 +95,17 @@ func TestNewListCommandAlias(t *testing.T) {
assert.Check(t, cmd.HasAlias("list"))
assert.Check(t, !cmd.HasAlias("other"))
}
func TestNewListCommandAmbiguous(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{})
cmd := NewImagesCommand(cli)
cmd.SetOut(io.Discard)
// Set the Use field to mimic that the command was called as "docker images",
// not "docker image ls".
cmd.Use = "images"
cmd.SetArgs([]string{"ls"})
err := cmd.Execute()
assert.NilError(t, err)
golden.Assert(t, cli.ErrBuffer().String(), "list-command-ambiguous.golden")
}

View File

@ -67,8 +67,10 @@ func runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions)
if options.all {
warning = allImageWarning
}
if !options.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) {
return 0, "", nil
if !options.force {
if r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), warning); !r || err != nil {
return 0, "", err
}
}
report, err := dockerCli.Client().ImagesPrune(ctx, pruneFilters)

View File

@ -1,10 +1,12 @@
package image
import (
"context"
"fmt"
"io"
"testing"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
@ -101,3 +103,19 @@ func TestNewPruneCommandSuccess(t *testing.T) {
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("prune-command-success.%s.golden", tc.name))
}
}
func TestPrunePromptTermination(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
cli := test.NewFakeCli(&fakeClient{
imagesPruneFunc: func(pruneFilter filters.Args) (types.ImagesPruneReport, error) {
return types.ImagesPruneReport{}, errors.New("fakeClient imagesPruneFunc should not be called")
},
})
cmd := NewPruneCommand(cli)
test.TerminatePrompt(ctx, t, cmd, cli, func(t *testing.T, err error) {
t.Helper()
assert.ErrorIs(t, err, command.ErrPromptTerminated)
})
}

View File

@ -8,7 +8,7 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/notary"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/image"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/golden"
@ -69,7 +69,7 @@ func TestNewPullCommandSuccess(t *testing.T) {
}
for _, tc := range testCases {
cli := test.NewFakeCli(&fakeClient{
imagePullFunc: func(ref string, options types.ImagePullOptions) (io.ReadCloser, error) {
imagePullFunc: func(ref string, options image.PullOptions) (io.ReadCloser, error) {
assert.Check(t, is.Equal(tc.expectedTag, ref), tc.name)
return io.NopCloser(strings.NewReader("")), nil
},
@ -111,7 +111,7 @@ func TestNewPullCommandWithContentTrustErrors(t *testing.T) {
}
for _, tc := range testCases {
cli := test.NewFakeCli(&fakeClient{
imagePullFunc: func(ref string, options types.ImagePullOptions) (io.ReadCloser, error) {
imagePullFunc: func(ref string, options image.PullOptions) (io.ReadCloser, error) {
return io.NopCloser(strings.NewReader("")), fmt.Errorf("shouldn't try to pull image")
},
}, test.EnableContentTrust)

View File

@ -10,7 +10,7 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/streams"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/image"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/registry"
@ -80,7 +80,7 @@ func RunPush(ctx context.Context, dockerCli command.Cli, opts pushOptions) error
return err
}
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "push")
options := types.ImagePushOptions{
options := image.PushOptions{
All: opts.all,
RegistryAuth: encodedAuth,
PrivilegeFunc: requestPrivilege,

View File

@ -6,7 +6,7 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/image"
"github.com/pkg/errors"
"gotest.tools/v3/assert"
)
@ -16,7 +16,7 @@ func TestNewPushCommandErrors(t *testing.T) {
name string
args []string
expectedError string
imagePushFunc func(ref string, options types.ImagePushOptions) (io.ReadCloser, error)
imagePushFunc func(ref string, options image.PushOptions) (io.ReadCloser, error)
}{
{
name: "wrong-args",
@ -32,7 +32,7 @@ func TestNewPushCommandErrors(t *testing.T) {
name: "push-failed",
args: []string{"image:repo"},
expectedError: "Failed to push",
imagePushFunc: func(ref string, options types.ImagePushOptions) (io.ReadCloser, error) {
imagePushFunc: func(ref string, options image.PushOptions) (io.ReadCloser, error) {
return io.NopCloser(strings.NewReader("")), errors.Errorf("Failed to push")
},
},
@ -67,7 +67,7 @@ func TestNewPushCommandSuccess(t *testing.T) {
tc := tc
t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
imagePushFunc: func(ref string, options types.ImagePushOptions) (io.ReadCloser, error) {
imagePushFunc: func(ref string, options image.PushOptions) (io.ReadCloser, error) {
return io.NopCloser(strings.NewReader("")), nil
},
})

View File

@ -7,7 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/errdefs"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -52,7 +52,7 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
func runRemove(ctx context.Context, dockerCli command.Cli, opts removeOptions, images []string) error {
client := dockerCli.Client()
options := types.ImageRemoveOptions{
options := image.RemoveOptions{
Force: opts.force,
PruneChildren: !opts.noPrune,
}

View File

@ -6,7 +6,6 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/image"
"github.com/pkg/errors"
"gotest.tools/v3/assert"
@ -36,7 +35,7 @@ func TestNewRemoveCommandErrors(t *testing.T) {
name string
args []string
expectedError string
imageRemoveFunc func(img string, options types.ImageRemoveOptions) ([]image.DeleteResponse, error)
imageRemoveFunc func(img string, options image.RemoveOptions) ([]image.DeleteResponse, error)
}{
{
name: "wrong args",
@ -46,7 +45,7 @@ func TestNewRemoveCommandErrors(t *testing.T) {
name: "ImageRemove fail with force option",
args: []string{"-f", "image1"},
expectedError: "error removing image",
imageRemoveFunc: func(img string, options types.ImageRemoveOptions) ([]image.DeleteResponse, error) {
imageRemoveFunc: func(img string, options image.RemoveOptions) ([]image.DeleteResponse, error) {
assert.Check(t, is.Equal("image1", img))
return []image.DeleteResponse{}, errors.Errorf("error removing image")
},
@ -55,7 +54,7 @@ func TestNewRemoveCommandErrors(t *testing.T) {
name: "ImageRemove fail",
args: []string{"arg1"},
expectedError: "error removing image",
imageRemoveFunc: func(img string, options types.ImageRemoveOptions) ([]image.DeleteResponse, error) {
imageRemoveFunc: func(img string, options image.RemoveOptions) ([]image.DeleteResponse, error) {
assert.Check(t, !options.Force)
assert.Check(t, options.PruneChildren)
return []image.DeleteResponse{}, errors.Errorf("error removing image")
@ -78,13 +77,13 @@ func TestNewRemoveCommandSuccess(t *testing.T) {
testCases := []struct {
name string
args []string
imageRemoveFunc func(img string, options types.ImageRemoveOptions) ([]image.DeleteResponse, error)
imageRemoveFunc func(img string, options image.RemoveOptions) ([]image.DeleteResponse, error)
expectedStderr string
}{
{
name: "Image Deleted",
args: []string{"image1"},
imageRemoveFunc: func(img string, options types.ImageRemoveOptions) ([]image.DeleteResponse, error) {
imageRemoveFunc: func(img string, options image.RemoveOptions) ([]image.DeleteResponse, error) {
assert.Check(t, is.Equal("image1", img))
return []image.DeleteResponse{{Deleted: img}}, nil
},
@ -92,7 +91,7 @@ func TestNewRemoveCommandSuccess(t *testing.T) {
{
name: "Image not found with force option",
args: []string{"-f", "image1"},
imageRemoveFunc: func(img string, options types.ImageRemoveOptions) ([]image.DeleteResponse, error) {
imageRemoveFunc: func(img string, options image.RemoveOptions) ([]image.DeleteResponse, error) {
assert.Check(t, is.Equal("image1", img))
assert.Check(t, is.Equal(true, options.Force))
return []image.DeleteResponse{}, notFound{"image1"}
@ -103,7 +102,7 @@ func TestNewRemoveCommandSuccess(t *testing.T) {
{
name: "Image Untagged",
args: []string{"image1"},
imageRemoveFunc: func(img string, options types.ImageRemoveOptions) ([]image.DeleteResponse, error) {
imageRemoveFunc: func(img string, options image.RemoveOptions) ([]image.DeleteResponse, error) {
assert.Check(t, is.Equal("image1", img))
return []image.DeleteResponse{{Untagged: img}}, nil
},
@ -111,7 +110,7 @@ func TestNewRemoveCommandSuccess(t *testing.T) {
{
name: "Image Deleted and Untagged",
args: []string{"image1", "image2"},
imageRemoveFunc: func(img string, options types.ImageRemoveOptions) ([]image.DeleteResponse, error) {
imageRemoveFunc: func(img string, options image.RemoveOptions) ([]image.DeleteResponse, error) {
if img == "image1" {
return []image.DeleteResponse{{Untagged: img}}, nil
}

View File

@ -5,9 +5,6 @@
"RepoDigests": null,
"Parent": "",
"Comment": "",
"Created": "",
"Container": "",
"ContainerConfig": null,
"DockerVersion": "",
"Author": "",
"Config": null,
@ -29,9 +26,6 @@
"RepoDigests": null,
"Parent": "",
"Comment": "",
"Created": "",
"Container": "",
"ContainerConfig": null,
"DockerVersion": "",
"Author": "",
"Config": null,

View File

@ -5,9 +5,6 @@
"RepoDigests": null,
"Parent": "",
"Comment": "",
"Created": "",
"Container": "",
"ContainerConfig": null,
"DockerVersion": "",
"Author": "",
"Config": null,

View File

@ -0,0 +1,2 @@
No images found matching "ls": did you mean "docker image ls"?

View File

@ -13,6 +13,7 @@ import (
"github.com/docker/cli/cli/streams"
"github.com/docker/cli/cli/trust"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/image"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/registry"
@ -30,7 +31,7 @@ type target struct {
}
// TrustedPush handles content trust pushing of an image
func TrustedPush(ctx context.Context, cli command.Cli, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig registrytypes.AuthConfig, options types.ImagePushOptions) error {
func TrustedPush(ctx context.Context, cli command.Cli, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig registrytypes.AuthConfig, options image.PushOptions) error {
responseBody, err := cli.Client().ImagePush(ctx, reference.FamiliarString(ref), options)
if err != nil {
return err
@ -267,7 +268,7 @@ func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth tru
return err
}
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(cli, imgRefAndAuth.RepoInfo().Index, "pull")
responseBody, err := cli.Client().ImagePull(ctx, reference.FamiliarString(imgRefAndAuth.Reference()), types.ImagePullOptions{
responseBody, err := cli.Client().ImagePull(ctx, reference.FamiliarString(imgRefAndAuth.Reference()), image.PullOptions{
RegistryAuth: encodedAuth,
PrivilegeFunc: requestPrivilege,
All: opts.all,

View File

@ -4,6 +4,7 @@ import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
)
@ -15,6 +16,8 @@ type fakeClient struct {
networkDisconnectFunc func(ctx context.Context, networkID, container string, force bool) error
networkRemoveFunc func(ctx context.Context, networkID string) error
networkListFunc func(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error)
networkPruneFunc func(ctx context.Context, pruneFilters filters.Args) (types.NetworksPruneReport, error)
networkInspectFunc func(ctx context.Context, networkID string, options types.NetworkInspectOptions) (types.NetworkResource, []byte, error)
}
func (c *fakeClient) NetworkCreate(ctx context.Context, name string, options types.NetworkCreate) (types.NetworkCreateResponse, error) {
@ -52,6 +55,16 @@ func (c *fakeClient) NetworkRemove(ctx context.Context, networkID string) error
return nil
}
func (c *fakeClient) NetworkInspectWithRaw(context.Context, string, types.NetworkInspectOptions) (types.NetworkResource, []byte, error) {
func (c *fakeClient) NetworkInspectWithRaw(ctx context.Context, networkID string, opts types.NetworkInspectOptions) (types.NetworkResource, []byte, error) {
if c.networkInspectFunc != nil {
return c.networkInspectFunc(ctx, networkID, opts)
}
return types.NetworkResource{}, nil, nil
}
func (c *fakeClient) NetworksPrune(ctx context.Context, pruneFilter filters.Args) (types.NetworksPruneReport, error) {
if c.networkPruneFunc != nil {
return c.networkPruneFunc(ctx, pruneFilter)
}
return types.NetworksPruneReport{}, nil
}

View File

@ -49,8 +49,10 @@ Are you sure you want to continue?`
func runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions) (output string, err error) {
pruneFilters := command.PruneFilters(dockerCli, options.filter.Value())
if !options.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) {
return "", nil
if !options.force {
if r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), warning); !r || err != nil {
return "", err
}
}
report, err := dockerCli.Client().NetworksPrune(ctx, pruneFilters)

View File

@ -0,0 +1,29 @@
package network
import (
"context"
"testing"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/pkg/errors"
"gotest.tools/v3/assert"
)
func TestNetworkPrunePromptTermination(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
cli := test.NewFakeCli(&fakeClient{
networkPruneFunc: func(ctx context.Context, pruneFilters filters.Args) (types.NetworksPruneReport, error) {
return types.NetworksPruneReport{}, errors.New("fakeClient networkPruneFunc should not be called")
},
})
cmd := NewPruneCommand(cli)
test.TerminatePrompt(ctx, t, cmd, cli, func(t *testing.T, err error) {
t.Helper()
assert.ErrorIs(t, err, command.ErrPromptTerminated)
})
}

View File

@ -46,10 +46,15 @@ func runRemove(ctx context.Context, dockerCli command.Cli, networks []string, op
status := 0
for _, name := range networks {
if nw, _, err := client.NetworkInspectWithRaw(ctx, name, types.NetworkInspectOptions{}); err == nil &&
nw.Ingress &&
!command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), ingressWarning) {
continue
nw, _, err := client.NetworkInspectWithRaw(ctx, name, types.NetworkInspectOptions{})
if err == nil && nw.Ingress {
r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), ingressWarning)
if err != nil {
return err
}
if !r {
continue
}
}
if err := client.NetworkRemove(ctx, name); err != nil {
if opts.force && errdefs.IsNotFound(err) {

View File

@ -5,7 +5,9 @@ import (
"io"
"testing"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/errdefs"
"github.com/pkg/errors"
"gotest.tools/v3/assert"
@ -94,3 +96,27 @@ func TestNetworkRemoveForce(t *testing.T) {
})
}
}
func TestNetworkRemovePromptTermination(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
cli := test.NewFakeCli(&fakeClient{
networkRemoveFunc: func(ctx context.Context, networkID string) error {
return errors.New("fakeClient networkRemoveFunc should not be called")
},
networkInspectFunc: func(ctx context.Context, networkID string, options types.NetworkInspectOptions) (types.NetworkResource, []byte, error) {
return types.NetworkResource{
ID: "existing-network",
Name: "existing-network",
Ingress: true,
}, nil, nil
},
})
cmd := newRemoveCommand(cli)
cmd.SetArgs([]string{"existing-network"})
test.TerminatePrompt(ctx, t, cmd, cli, func(t *testing.T, err error) {
t.Helper()
assert.ErrorIs(t, err, command.ErrPromptTerminated)
})
}

View File

@ -19,6 +19,7 @@ type fakeClient struct {
pluginInstallFunc func(name string, options types.PluginInstallOptions) (io.ReadCloser, error)
pluginListFunc func(filter filters.Args) (types.PluginsListResponse, error)
pluginInspectFunc func(name string) (*types.Plugin, []byte, error)
pluginUpgradeFunc func(name string, options types.PluginInstallOptions) (io.ReadCloser, error)
}
func (c *fakeClient) PluginCreate(_ context.Context, createContext io.Reader, createOptions types.PluginCreateOptions) error {
@ -75,3 +76,10 @@ func (c *fakeClient) PluginInspectWithRaw(_ context.Context, name string) (*type
func (c *fakeClient) Info(context.Context) (system.Info, error) {
return system.Info{}, nil
}
func (c *fakeClient) PluginUpgrade(ctx context.Context, name string, options types.PluginInstallOptions) (io.ReadCloser, error) {
if c.pluginUpgradeFunc != nil {
return c.pluginUpgradeFunc(name, options)
}
return nil, nil
}

View File

@ -114,7 +114,6 @@ func runCreate(ctx context.Context, dockerCli command.Cli, options pluginCreateO
createCtx, err = archive.TarWithOptions(absContextDir, &archive.TarOptions{
Compression: compression,
})
if err != nil {
return err
}

View File

@ -142,6 +142,7 @@ func acceptPrivileges(dockerCli command.Cli, name string) func(privileges types.
for _, privilege := range privileges {
fmt.Fprintf(dockerCli.Out(), " - %s: %v\n", privilege.Name, privilege.Value)
}
return command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), "Do you grant the above permissions?"), nil
ctx := context.TODO()
return command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), "Do you grant the above permissions?")
}
}

View File

@ -0,0 +1,2 @@
Upgrading plugin foo/bar from localhost:5000/foo/bar:v0.1.0 to localhost:5000/foo/bar:v1.0.0
Plugin images do not match, are you sure? [y/N]

View File

@ -63,7 +63,10 @@ func runUpgrade(ctx context.Context, dockerCli command.Cli, opts pluginOptions)
fmt.Fprintf(dockerCli.Out(), "Upgrading plugin %s from %s to %s\n", p.Name, reference.FamiliarString(old), reference.FamiliarString(remote))
if !opts.skipRemoteCheck && remote.String() != old.String() {
if !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), "Plugin images do not match, are you sure?") {
if r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), "Plugin images do not match, are you sure?"); !r || err != nil {
if err != nil {
return errors.Wrap(err, "canceling upgrade request")
}
return errors.New("canceling upgrade request")
}
}

View File

@ -0,0 +1,42 @@
package plugin
import (
"context"
"io"
"testing"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/pkg/errors"
"gotest.tools/v3/assert"
"gotest.tools/v3/golden"
)
func TestUpgradePromptTermination(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
cli := test.NewFakeCli(&fakeClient{
pluginUpgradeFunc: func(name string, options types.PluginInstallOptions) (io.ReadCloser, error) {
return nil, errors.New("should not be called")
},
pluginInspectFunc: func(name string) (*types.Plugin, []byte, error) {
return &types.Plugin{
ID: "5724e2c8652da337ab2eedd19fc6fc0ec908e4bd907c7421bf6a8dfc70c4c078",
Name: "foo/bar",
Enabled: false,
PluginReference: "localhost:5000/foo/bar:v0.1.0",
}, []byte{}, nil
},
})
cmd := newUpgradeCommand(cli)
// need to set a remote address that does not match the plugin
// reference sent by the `pluginInspectFunc`
cmd.SetArgs([]string{"foo/bar", "localhost:5000/foo/bar:v1.0.0"})
test.TerminatePrompt(ctx, t, cmd, cli, func(t *testing.T, err error) {
t.Helper()
assert.ErrorIs(t, err, command.ErrPromptTerminated)
})
golden.Assert(t, cli.OutBuffer().String(), "plugin-upgrade-terminate.golden")
}

View File

@ -55,7 +55,7 @@ func NewLoginCommand(dockerCli command.Cli) *cobra.Command {
flags.StringVarP(&opts.user, "username", "u", "", "Username")
flags.StringVarP(&opts.password, "password", "p", "", "Password")
flags.BoolVarP(&opts.passwordStdin, "password-stdin", "", false, "Take the password from stdin")
flags.BoolVar(&opts.passwordStdin, "password-stdin", false, "Take the password from stdin")
return cmd
}

View File

@ -38,7 +38,7 @@ func newSecretListCommand(dockerCli command.Cli) *cobra.Command {
flags := cmd.Flags()
flags.BoolVarP(&options.quiet, "quiet", "q", false, "Only display IDs")
flags.StringVarP(&options.format, "format", "", "", flagsHelper.FormatHelp)
flags.StringVar(&options.format, "format", "", flagsHelper.FormatHelp)
flags.VarP(&options.filter, "filter", "f", "Filter output based on conditions provided")
return cmd

View File

@ -137,7 +137,7 @@ func runCreate(ctx context.Context, dockerCli command.Cli, flags *pflag.FlagSet,
return nil
}
return waitOnService(ctx, dockerCli, response.ID, opts.quiet)
return WaitOnService(ctx, dockerCli, response.ID, opts.quiet)
}
// setConfigs does double duty: it both sets the ConfigReferences of the

View File

@ -9,9 +9,9 @@ import (
"github.com/docker/docker/pkg/jsonmessage"
)
// waitOnService waits for the service to converge. It outputs a progress bar,
// WaitOnService waits for the service to converge. It outputs a progress bar,
// if appropriate based on the CLI flags.
func waitOnService(ctx context.Context, dockerCli command.Cli, serviceID string, quiet bool) error {
func WaitOnService(ctx context.Context, dockerCli command.Cli, serviceID string, quiet bool) error {
errChan := make(chan error, 1)
pipeReader, pipeWriter := io.Pipe()

View File

@ -143,7 +143,7 @@ func ServiceProgress(ctx context.Context, apiClient client.APIClient, serviceID
if converged && time.Since(convergedAt) >= monitor {
progressOut.WriteProgress(progress.Progress{
ID: "verify",
Action: "Service converged",
Action: fmt.Sprintf("Service %s converged", serviceID),
})
if message != nil {
progressOut.WriteProgress(*message)

View File

@ -62,5 +62,5 @@ func runRollback(ctx context.Context, dockerCli command.Cli, options *serviceOpt
return nil
}
return waitOnService(ctx, dockerCli, serviceID, options.quiet)
return WaitOnService(ctx, dockerCli, serviceID, options.quiet)
}

View File

@ -80,7 +80,7 @@ func runScale(ctx context.Context, dockerCli command.Cli, options *scaleOptions,
if len(serviceIDs) > 0 {
if !options.detach && versions.GreaterThanOrEqualTo(dockerCli.Client().ClientVersion(), "1.29") {
for _, serviceID := range serviceIDs {
if err := waitOnService(ctx, dockerCli, serviceID, false); err != nil {
if err := WaitOnService(ctx, dockerCli, serviceID, false); err != nil {
errs = append(errs, fmt.Sprintf("%s: %v", serviceID, err))
}
}

View File

@ -249,7 +249,7 @@ func runUpdate(ctx context.Context, dockerCli command.Cli, flags *pflag.FlagSet,
return nil
}
return waitOnService(ctx, dockerCli, serviceID, options.quiet)
return WaitOnService(ctx, dockerCli, serviceID, options.quiet)
}
//nolint:gocyclo

View File

@ -26,7 +26,7 @@ func newDeployCommand(dockerCli command.Cli) *cobra.Command {
if err != nil {
return err
}
return swarm.RunDeploy(cmd.Context(), dockerCli, opts, config)
return swarm.RunDeploy(cmd.Context(), dockerCli, cmd.Flags(), &opts, config)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return completeNames(dockerCli)(cmd, args, toComplete)
@ -42,5 +42,7 @@ func newDeployCommand(dockerCli command.Cli) *cobra.Command {
flags.StringVar(&opts.ResolveImage, "resolve-image", swarm.ResolveImageAlways,
`Query the registry to resolve image digest and supported platforms ("`+swarm.ResolveImageAlways+`", "`+swarm.ResolveImageChanged+`", "`+swarm.ResolveImageNever+`")`)
flags.SetAnnotation("resolve-image", "version", []string{"1.30"})
flags.BoolVarP(&opts.Detach, "detach", "d", true, "Exit immediately instead of waiting for the stack services to converge")
flags.BoolVarP(&opts.Quiet, "quiet", "q", false, "Suppress progress output")
return cmd
}

View File

@ -9,6 +9,8 @@ type Deploy struct {
ResolveImage string
SendRegistryAuth bool
Prune bool
Detach bool
Quiet bool
}
// Config holds docker stack config options
@ -36,6 +38,7 @@ type PS struct {
// Remove holds docker stack remove options
type Remove struct {
Namespaces []string
Detach bool
}
// Services holds docker stack services options

View File

@ -27,5 +27,8 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
return completeNames(dockerCli)(cmd, args, toComplete)
},
}
flags := cmd.Flags()
flags.BoolVarP(&opts.Detach, "detach", "d", true, "Do not wait for stack removal")
return cmd
}

View File

@ -44,3 +44,7 @@ func getStackSecrets(ctx context.Context, apiclient client.APIClient, namespace
func getStackConfigs(ctx context.Context, apiclient client.APIClient, namespace string) ([]swarm.Config, error) {
return apiclient.ConfigList(ctx, types.ConfigListOptions{Filters: getStackFilter(namespace)})
}
func getStackTasks(ctx context.Context, apiclient client.APIClient, namespace string) ([]swarm.Task, error) {
return apiclient.TaskList(ctx, types.TaskListOptions{Filters: getStackFilter(namespace)})
}

View File

@ -11,6 +11,7 @@ import (
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/versions"
"github.com/pkg/errors"
"github.com/spf13/pflag"
)
// Resolve image constants
@ -22,8 +23,8 @@ const (
)
// RunDeploy is the swarm implementation of docker stack deploy
func RunDeploy(ctx context.Context, dockerCli command.Cli, opts options.Deploy, cfg *composetypes.Config) error {
if err := validateResolveImageFlag(&opts); err != nil {
func RunDeploy(ctx context.Context, dockerCli command.Cli, flags *pflag.FlagSet, opts *options.Deploy, cfg *composetypes.Config) error {
if err := validateResolveImageFlag(opts); err != nil {
return err
}
// client side image resolution should not be done when the supported
@ -32,6 +33,11 @@ func RunDeploy(ctx context.Context, dockerCli command.Cli, opts options.Deploy,
opts.ResolveImage = ResolveImageNever
}
if opts.Detach && !flags.Changed("detach") {
fmt.Fprintln(dockerCli.Err(), "Since --detach=false was not specified, tasks will be created in the background.\n"+
"In a future release, --detach=false will become the default.")
}
return deployCompose(ctx, dockerCli, opts, cfg)
}

View File

@ -2,9 +2,11 @@ package swarm
import (
"context"
"errors"
"fmt"
"github.com/docker/cli/cli/command"
servicecli "github.com/docker/cli/cli/command/service"
"github.com/docker/cli/cli/command/stack/options"
"github.com/docker/cli/cli/compose/convert"
composetypes "github.com/docker/cli/cli/compose/types"
@ -13,10 +15,9 @@ import (
"github.com/docker/docker/api/types/swarm"
apiclient "github.com/docker/docker/client"
"github.com/docker/docker/errdefs"
"github.com/pkg/errors"
)
func deployCompose(ctx context.Context, dockerCli command.Cli, opts options.Deploy, config *composetypes.Config) error {
func deployCompose(ctx context.Context, dockerCli command.Cli, opts *options.Deploy, config *composetypes.Config) error {
if err := checkDaemonIsSwarmManager(ctx, dockerCli); err != nil {
return err
}
@ -60,7 +61,17 @@ func deployCompose(ctx context.Context, dockerCli command.Cli, opts options.Depl
if err != nil {
return err
}
return deployServices(ctx, dockerCli, services, namespace, opts.SendRegistryAuth, opts.ResolveImage)
serviceIDs, err := deployServices(ctx, dockerCli, services, namespace, opts.SendRegistryAuth, opts.ResolveImage)
if err != nil {
return err
}
if opts.Detach {
return nil
}
return waitOnServices(ctx, dockerCli, serviceIDs, opts.Quiet)
}
func getServicesDeclaredNetworks(serviceConfigs []composetypes.ServiceConfig) map[string]struct{} {
@ -87,11 +98,11 @@ func validateExternalNetworks(ctx context.Context, client apiclient.NetworkAPICl
network, err := client.NetworkInspect(ctx, networkName, types.NetworkInspectOptions{})
switch {
case errdefs.IsNotFound(err):
return errors.Errorf("network %q is declared as external, but could not be found. You need to create a swarm-scoped network before the stack is deployed", networkName)
return fmt.Errorf("network %q is declared as external, but could not be found. You need to create a swarm-scoped network before the stack is deployed", networkName)
case err != nil:
return err
case network.Scope != "swarm":
return errors.Errorf("network %q is declared as external, but it is not in the right scope: %q instead of \"swarm\"", networkName, network.Scope)
return fmt.Errorf("network %q is declared as external, but it is not in the right scope: %q instead of \"swarm\"", networkName, network.Scope)
}
}
return nil
@ -106,13 +117,13 @@ func createSecrets(ctx context.Context, dockerCli command.Cli, secrets []swarm.S
case err == nil:
// secret already exists, then we update that
if err := client.SecretUpdate(ctx, secret.ID, secret.Meta.Version, secretSpec); err != nil {
return errors.Wrapf(err, "failed to update secret %s", secretSpec.Name)
return fmt.Errorf("failed to update secret %s: %w", secretSpec.Name, err)
}
case errdefs.IsNotFound(err):
// secret does not exist, then we create a new one.
fmt.Fprintf(dockerCli.Out(), "Creating secret %s\n", secretSpec.Name)
if _, err := client.SecretCreate(ctx, secretSpec); err != nil {
return errors.Wrapf(err, "failed to create secret %s", secretSpec.Name)
return fmt.Errorf("failed to create secret %s: %w", secretSpec.Name, err)
}
default:
return err
@ -130,13 +141,13 @@ func createConfigs(ctx context.Context, dockerCli command.Cli, configs []swarm.C
case err == nil:
// config already exists, then we update that
if err := client.ConfigUpdate(ctx, config.ID, config.Meta.Version, configSpec); err != nil {
return errors.Wrapf(err, "failed to update config %s", configSpec.Name)
return fmt.Errorf("failed to update config %s: %w", configSpec.Name, err)
}
case errdefs.IsNotFound(err):
// config does not exist, then we create a new one.
fmt.Fprintf(dockerCli.Out(), "Creating config %s\n", configSpec.Name)
if _, err := client.ConfigCreate(ctx, configSpec); err != nil {
return errors.Wrapf(err, "failed to create config %s", configSpec.Name)
return fmt.Errorf("failed to create config %s: %w", configSpec.Name, err)
}
default:
return err
@ -169,19 +180,19 @@ func createNetworks(ctx context.Context, dockerCli command.Cli, namespace conver
fmt.Fprintf(dockerCli.Out(), "Creating network %s\n", name)
if _, err := client.NetworkCreate(ctx, name, createOpts); err != nil {
return errors.Wrapf(err, "failed to create network %s", name)
return fmt.Errorf("failed to create network %s: %w", name, err)
}
}
return nil
}
func deployServices(ctx context.Context, dockerCli command.Cli, services map[string]swarm.ServiceSpec, namespace convert.Namespace, sendAuth bool, resolveImage string) error {
func deployServices(ctx context.Context, dockerCli command.Cli, services map[string]swarm.ServiceSpec, namespace convert.Namespace, sendAuth bool, resolveImage string) ([]string, error) {
apiClient := dockerCli.Client()
out := dockerCli.Out()
existingServices, err := getStackServices(ctx, apiClient, namespace.Name())
if err != nil {
return err
return nil, err
}
existingServiceMap := make(map[string]swarm.Service)
@ -189,6 +200,8 @@ func deployServices(ctx context.Context, dockerCli command.Cli, services map[str
existingServiceMap[service.Spec.Name] = service
}
var serviceIDs []string
for internalName, serviceSpec := range services {
var (
name = namespace.Scope(internalName)
@ -200,7 +213,7 @@ func deployServices(ctx context.Context, dockerCli command.Cli, services map[str
// Retrieve encoded auth token from the image reference
encodedAuth, err = command.RetrieveAuthTokenFromImage(dockerCli.ConfigFile(), image)
if err != nil {
return err
return nil, err
}
}
@ -241,12 +254,14 @@ func deployServices(ctx context.Context, dockerCli command.Cli, services map[str
response, err := apiClient.ServiceUpdate(ctx, service.ID, service.Version, serviceSpec, updateOpts)
if err != nil {
return errors.Wrapf(err, "failed to update service %s", name)
return nil, fmt.Errorf("failed to update service %s: %w", name, err)
}
for _, warning := range response.Warnings {
fmt.Fprintln(dockerCli.Err(), warning)
}
serviceIDs = append(serviceIDs, service.ID)
} else {
fmt.Fprintf(out, "Creating service %s\n", name)
@ -257,10 +272,29 @@ func deployServices(ctx context.Context, dockerCli command.Cli, services map[str
createOpts.QueryRegistry = true
}
if _, err := apiClient.ServiceCreate(ctx, serviceSpec, createOpts); err != nil {
return errors.Wrapf(err, "failed to create service %s", name)
response, err := apiClient.ServiceCreate(ctx, serviceSpec, createOpts)
if err != nil {
return nil, fmt.Errorf("failed to create service %s: %w", name, err)
}
serviceIDs = append(serviceIDs, response.ID)
}
}
return serviceIDs, nil
}
func waitOnServices(ctx context.Context, dockerCli command.Cli, serviceIDs []string, quiet bool) error {
var errs []error
for _, serviceID := range serviceIDs {
if err := servicecli.WaitOnService(ctx, dockerCli, serviceID, quiet); err != nil {
errs = append(errs, fmt.Errorf("%s: %w", serviceID, err))
}
}
if len(errs) > 0 {
return errors.Join(errs...)
}
return nil
}

View File

@ -99,7 +99,7 @@ func TestServiceUpdateResolveImageChanged(t *testing.T) {
},
},
}
err := deployServices(ctx, client, spec, namespace, false, ResolveImageChanged)
_, err := deployServices(ctx, client, spec, namespace, false, ResolveImageChanged)
assert.NilError(t, err)
assert.Check(t, is.Equal(receivedOptions.QueryRegistry, tc.expectedQueryRegistry))
assert.Check(t, is.Equal(receivedService.TaskTemplate.ContainerSpec.Image, tc.expectedImage))

View File

@ -11,6 +11,7 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/versions"
apiclient "github.com/docker/docker/client"
"github.com/pkg/errors"
)
@ -58,6 +59,14 @@ func RunRemove(ctx context.Context, dockerCli command.Cli, opts options.Remove)
if hasError {
errs = append(errs, fmt.Sprintf("Failed to remove some resources from stack: %s", namespace))
continue
}
if !opts.Detach {
err = waitOnTasks(ctx, client, namespace)
if err != nil {
errs = append(errs, fmt.Sprintf("Failed to wait on tasks of stack: %s: %s", namespace, err))
}
}
}
@ -137,3 +146,45 @@ func removeConfigs(
}
return hasError
}
var numberedStates = map[swarm.TaskState]int64{
swarm.TaskStateNew: 1,
swarm.TaskStateAllocated: 2,
swarm.TaskStatePending: 3,
swarm.TaskStateAssigned: 4,
swarm.TaskStateAccepted: 5,
swarm.TaskStatePreparing: 6,
swarm.TaskStateReady: 7,
swarm.TaskStateStarting: 8,
swarm.TaskStateRunning: 9,
swarm.TaskStateComplete: 10,
swarm.TaskStateShutdown: 11,
swarm.TaskStateFailed: 12,
swarm.TaskStateRejected: 13,
}
func terminalState(state swarm.TaskState) bool {
return numberedStates[state] > numberedStates[swarm.TaskStateRunning]
}
func waitOnTasks(ctx context.Context, client apiclient.APIClient, namespace string) error {
terminalStatesReached := 0
for {
tasks, err := getStackTasks(ctx, client, namespace)
if err != nil {
return fmt.Errorf("failed to get tasks: %w", err)
}
for _, task := range tasks {
if terminalState(task.Status.State) {
terminalStatesReached++
break
}
}
if terminalStatesReached == len(tasks) {
break
}
}
return nil
}

View File

@ -20,7 +20,7 @@ func equalCIDR(c1 net.IPNet, c2 net.IPNet) bool {
func setUpIPNetFlagSet(ipsp *[]net.IPNet) *pflag.FlagSet {
f := pflag.NewFlagSet("test", pflag.ContinueOnError)
f.VarP(newIPNetSliceValue([]net.IPNet{}, ipsp), "cidrs", "", "Command separated list!")
f.Var(newIPNetSliceValue([]net.IPNet{}, ipsp), "cidrs", "Command separated list!")
return f
}

View File

@ -5,15 +5,18 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
)
type fakeClient struct {
client.Client
version string
serverVersion func(ctx context.Context) (types.Version, error)
eventsFn func(context.Context, types.EventsOptions) (<-chan events.Message, <-chan error)
version string
serverVersion func(ctx context.Context) (types.Version, error)
eventsFn func(context.Context, types.EventsOptions) (<-chan events.Message, <-chan error)
containerPruneFunc func(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error)
networkPruneFunc func(ctx context.Context, pruneFilter filters.Args) (types.NetworksPruneReport, error)
}
func (cli *fakeClient) ServerVersion(ctx context.Context) (types.Version, error) {
@ -27,3 +30,17 @@ func (cli *fakeClient) ClientVersion() string {
func (cli *fakeClient) Events(ctx context.Context, opts types.EventsOptions) (<-chan events.Message, <-chan error) {
return cli.eventsFn(ctx, opts)
}
func (cli *fakeClient) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error) {
if cli.containerPruneFunc != nil {
return cli.containerPruneFunc(ctx, pruneFilters)
}
return types.ContainersPruneReport{}, nil
}
func (cli *fakeClient) NetworksPrune(ctx context.Context, pruneFilter filters.Args) (types.NetworksPruneReport, error) {
if cli.networkPruneFunc != nil {
return cli.networkPruneFunc(ctx, pruneFilter)
}
return types.NetworksPruneReport{}, nil
}

View File

@ -21,7 +21,6 @@ import (
"github.com/docker/cli/templates"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/system"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/registry"
"github.com/docker/go-units"
"github.com/spf13/cobra"
@ -380,7 +379,10 @@ func prettyPrintServerInfo(streams command.Streams, info *dockerInfo) []error {
}
fprintln(output)
printServerWarnings(streams.Err(), info)
for _, w := range info.Warnings {
fprintln(streams.Err(), w)
}
return errs
}
@ -454,84 +456,6 @@ func printSwarmInfo(output io.Writer, info system.Info) {
}
}
func printServerWarnings(stdErr io.Writer, info *dockerInfo) {
if versions.LessThan(info.ClientInfo.APIVersion, "1.42") {
printSecurityOptionsWarnings(stdErr, *info.Info)
}
if len(info.Warnings) > 0 {
fprintln(stdErr, strings.Join(info.Warnings, "\n"))
return
}
// daemon didn't return warnings. Fallback to old behavior
printServerWarningsLegacy(stdErr, *info.Info)
}
// printSecurityOptionsWarnings prints warnings based on the security options
// returned by the daemon.
//
// Deprecated: warnings are now generated by the daemon, and returned in
// info.Warnings. This function is used to provide backward compatibility with
// daemons that do not provide these warnings. No new warnings should be added
// here.
func printSecurityOptionsWarnings(stdErr io.Writer, info system.Info) {
if info.OSType == "windows" {
return
}
kvs, _ := system.DecodeSecurityOptions(info.SecurityOptions)
for _, so := range kvs {
if so.Name != "seccomp" {
continue
}
for _, o := range so.Options {
if o.Key == "profile" && o.Value != "default" && o.Value != "builtin" {
_, _ = fmt.Fprintln(stdErr, "WARNING: You're not using the default seccomp profile")
}
}
}
}
// printServerWarningsLegacy generates warnings based on information returned by the daemon.
//
// Deprecated: warnings are now generated by the daemon, and returned in
// info.Warnings. This function is used to provide backward compatibility with
// daemons that do not provide these warnings. No new warnings should be added
// here.
func printServerWarningsLegacy(stdErr io.Writer, info system.Info) {
if info.OSType == "windows" {
return
}
if !info.MemoryLimit {
fprintln(stdErr, "WARNING: No memory limit support")
}
if !info.SwapLimit {
fprintln(stdErr, "WARNING: No swap limit support")
}
if !info.OomKillDisable && info.CgroupVersion != "2" {
fprintln(stdErr, "WARNING: No oom kill disable support")
}
if !info.CPUCfsQuota {
fprintln(stdErr, "WARNING: No cpu cfs quota support")
}
if !info.CPUCfsPeriod {
fprintln(stdErr, "WARNING: No cpu cfs period support")
}
if !info.CPUShares {
fprintln(stdErr, "WARNING: No cpu shares support")
}
if !info.CPUSet {
fprintln(stdErr, "WARNING: No cpuset support")
}
if !info.IPv4Forwarding {
fprintln(stdErr, "WARNING: IPv4 forwarding is disabled")
}
if !info.BridgeNfIptables {
fprintln(stdErr, "WARNING: bridge-nf-call-iptables is disabled")
}
if !info.BridgeNfIP6tables {
fprintln(stdErr, "WARNING: bridge-nf-call-ip6tables is disabled")
}
}
func formatInfo(output io.Writer, info dockerInfo, format string) error {
if format == formatter.JSONFormatKey {
format = formatter.JSONFormat

View File

@ -333,23 +333,6 @@ func TestPrettyPrintInfo(t *testing.T) {
prettyGolden: "docker-info-with-swarm",
jsonGolden: "docker-info-with-swarm",
},
{
doc: "info with legacy warnings",
dockerInfo: dockerInfo{
Info: &infoWithWarningsLinux,
ClientInfo: &clientInfo{
clientVersion: clientVersion{
Platform: &platformInfo{Name: "Docker Engine - Community"},
Version: "24.0.0",
Context: "default",
},
Debug: true,
},
},
prettyGolden: "docker-info-no-swarm",
warningsGolden: "docker-info-warnings",
jsonGolden: "docker-info-legacy-warnings",
},
{
doc: "info with daemon warnings",
dockerInfo: dockerInfo{

View File

@ -74,8 +74,10 @@ func runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions)
if options.pruneVolumes && options.filter.Value().Contains("until") {
return fmt.Errorf(`ERROR: The "until" filter is not supported with "--volumes"`)
}
if !options.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), confirmationMessage(dockerCli, options)) {
return nil
if !options.force {
if r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), confirmationMessage(dockerCli, options)); !r || err != nil {
return err
}
}
pruneFuncs := []func(ctx context.Context, dockerCli command.Cli, all bool, filter opts.FilterOpt) (uint64, string, error){
container.RunPrune,

View File

@ -1,10 +1,15 @@
package system
import (
"context"
"testing"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/pkg/errors"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
@ -49,3 +54,23 @@ func TestPrunePromptFilters(t *testing.T) {
Are you sure you want to continue? [y/N] `
assert.Check(t, is.Equal(expected, cli.OutBuffer().String()))
}
func TestSystemPrunePromptTermination(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
cli := test.NewFakeCli(&fakeClient{
containerPruneFunc: func(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error) {
return types.ContainersPruneReport{}, errors.New("fakeClient containerPruneFunc should not be called")
},
networkPruneFunc: func(ctx context.Context, pruneFilters filters.Args) (types.NetworksPruneReport, error) {
return types.NetworksPruneReport{}, errors.New("fakeClient networkPruneFunc should not be called")
},
})
cmd := newPruneCommand(cli)
test.TerminatePrompt(ctx, t, cmd, cli, func(t *testing.T, err error) {
t.Helper()
assert.ErrorIs(t, err, command.ErrPromptTerminated)
})
}

View File

@ -1 +0,0 @@
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"overlay2","DriverStatus":[["Backing Filesystem","extfs"],["Supports d_type","true"],["Using metacopy","false"],["Native Overlay Diff","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","splunk","syslog"]},"MemoryLimit":false,"SwapLimit":false,"CpuCfsPeriod":false,"CpuCfsQuota":false,"CPUShares":false,"CPUSet":false,"PidsLimit":false,"IPv4Forwarding":false,"BridgeNfIptables":false,"BridgeNfIp6tables":false,"Debug":true,"NFd":33,"OomKillDisable":false,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"AllowNondistributableArtifactsCIDRs":null,"AllowNondistributableArtifactsHostnames":null,"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170","Expected":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2","Expected":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa","Expected":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"CDISpecDirs":["/etc/cdi","/var/run/cdi"],"Warnings":null,"ClientInfo":{"Debug":true,"Platform":{"Name":"Docker Engine - Community"},"Version":"24.0.0","Context":"default","Plugins":[],"Warnings":null}}

View File

@ -11,6 +11,7 @@ import (
"github.com/docker/cli/internal/test"
notaryfake "github.com/docker/cli/internal/test/notary"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/system"
apiclient "github.com/docker/docker/client"
"github.com/theupdateframework/notary"
@ -36,7 +37,7 @@ func (c *fakeClient) ImageInspectWithRaw(context.Context, string) (types.ImageIn
return types.ImageInspect{}, []byte{}, nil
}
func (c *fakeClient) ImagePush(context.Context, string, types.ImagePushOptions) (io.ReadCloser, error) {
func (c *fakeClient) ImagePush(context.Context, string, image.PushOptions) (io.ReadCloser, error) {
return &utils.NoopCloser{Reader: bytes.NewBuffer([]byte{})}, nil
}

View File

@ -3,7 +3,6 @@ package trust
import (
"context"
"fmt"
"os"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
@ -44,7 +43,11 @@ func revokeTrust(ctx context.Context, dockerCLI command.Cli, remote string, opti
return fmt.Errorf("cannot use a digest reference for IMAGE:TAG")
}
if imgRefAndAuth.Tag() == "" && !options.forceYes {
deleteRemote := command.PromptForConfirmation(os.Stdin, dockerCLI.Out(), fmt.Sprintf("Please confirm you would like to delete all signature data for %s?", remote))
deleteRemote, err := command.PromptForConfirmation(ctx, dockerCLI.In(), dockerCLI.Out(), fmt.Sprintf("Please confirm you would like to delete all signature data for %s?", remote))
if err != nil {
fmt.Fprintf(dockerCLI.Out(), "\nAborting action.\n")
return errors.Wrap(err, "aborting action")
}
if !deleteRemote {
fmt.Fprintf(dockerCLI.Out(), "\nAborting action.\n")
return nil

View File

@ -1,9 +1,11 @@
package trust
import (
"context"
"io"
"testing"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/trust"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/notary"
@ -12,6 +14,7 @@ import (
"github.com/theupdateframework/notary/trustpinning"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/golden"
)
func TestTrustRevokeCommandErrors(t *testing.T) {
@ -148,3 +151,18 @@ func TestGetSignableRolesForTargetAndRemoveError(t *testing.T) {
err = getSignableRolesForTargetAndRemove(target, notaryRepo)
assert.Error(t, err, "client is offline")
}
func TestRevokeTrustPromptTermination(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
cli := test.NewFakeCli(&fakeClient{})
cmd := newRevokeCommand(cli)
cmd.SetArgs([]string{"example/trust-demo"})
test.TerminatePrompt(ctx, t, cmd, cli, func(t *testing.T, err error) {
t.Helper()
assert.ErrorIs(t, err, command.ErrPromptTerminated)
})
assert.Equal(t, cli.ErrBuffer().String(), "")
golden.Assert(t, cli.OutBuffer().String(), "trust-revoke-prompt-termination.golden")
}

View File

@ -12,7 +12,7 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/image"
"github.com/docker/cli/cli/trust"
"github.com/docker/docker/api/types"
imagetypes "github.com/docker/docker/api/types/image"
registrytypes "github.com/docker/docker/api/types/registry"
apiclient "github.com/docker/docker/client"
"github.com/pkg/errors"
@ -98,7 +98,7 @@ func runSignImage(ctx context.Context, dockerCLI command.Cli, options signOption
if err != nil {
return err
}
options := types.ImagePushOptions{
options := imagetypes.PushOptions{
RegistryAuth: encodedAuth,
PrivilegeFunc: requestPrivilege,
}

View File

@ -3,7 +3,6 @@ package trust
import (
"context"
"fmt"
"os"
"strings"
"github.com/docker/cli/cli"
@ -76,6 +75,22 @@ func isLastSignerForReleases(roleWithSig data.Role, allRoles []client.RoleWithSi
return counter < releasesRoleWithSigs.Threshold, nil
}
func maybePromptForSignerRemoval(ctx context.Context, dockerCLI command.Cli, repoName, signerName string, isLastSigner, forceYes bool) (bool, error) {
if isLastSigner && !forceYes {
message := fmt.Sprintf("The signer \"%s\" signed the last released version of %s. "+
"Removing this signer will make %s unpullable. "+
"Are you sure you want to continue?",
signerName, repoName, repoName,
)
removeSigner, err := command.PromptForConfirmation(ctx, dockerCLI.In(), dockerCLI.Out(), message)
if err != nil {
return false, err
}
return removeSigner, nil
}
return false, nil
}
// removeSingleSigner attempts to remove a single signer and returns whether signer removal happened.
// The signer not being removed doesn't necessarily raise an error e.g. user choosing "No" when prompted for confirmation.
func removeSingleSigner(ctx context.Context, dockerCLI command.Cli, repoName, signerName string, forceYes bool) (bool, error) {
@ -110,28 +125,26 @@ func removeSingleSigner(ctx context.Context, dockerCLI command.Cli, repoName, si
if err != nil {
return false, err
}
if ok, err := isLastSignerForReleases(role, allRoles); ok && !forceYes {
removeSigner := command.PromptForConfirmation(os.Stdin, dockerCLI.Out(), fmt.Sprintf("The signer \"%s\" signed the last released version of %s. "+
"Removing this signer will make %s unpullable. "+
"Are you sure you want to continue?",
signerName, repoName, repoName,
))
if !removeSigner {
fmt.Fprintf(dockerCLI.Out(), "\nAborting action.\n")
return false, nil
}
} else if err != nil {
return false, err
}
if err = notaryRepo.RemoveDelegationKeys(releasesRoleTUFName, role.KeyIDs); err != nil {
return false, err
}
if err = notaryRepo.RemoveDelegationRole(signerDelegation); err != nil {
isLastSigner, err := isLastSignerForReleases(role, allRoles)
if err != nil {
return false, err
}
if err = notaryRepo.Publish(); err != nil {
ok, err := maybePromptForSignerRemoval(ctx, dockerCLI, repoName, signerName, isLastSigner, forceYes)
if err != nil || !ok {
fmt.Fprintf(dockerCLI.Out(), "\nAborting action.\n")
return false, err
}
if err := notaryRepo.RemoveDelegationKeys(releasesRoleTUFName, role.KeyIDs); err != nil {
return false, err
}
if err := notaryRepo.RemoveDelegationRole(signerDelegation); err != nil {
return false, err
}
if err := notaryRepo.Publish(); err != nil {
return false, err
}

View File

@ -111,7 +111,8 @@ func TestIsLastSignerForReleases(t *testing.T) {
releaserole.Name = releasesRoleTUFName
releaserole.Threshold = 1
allrole := []client.RoleWithSignatures{releaserole}
lastsigner, _ := isLastSignerForReleases(role, allrole)
lastsigner, err := isLastSignerForReleases(role, allrole)
assert.Error(t, err, "all signed tags are currently revoked, use docker trust sign to fix")
assert.Check(t, is.Equal(false, lastsigner))
role.KeyIDs = []string{"deadbeef"}
@ -120,13 +121,15 @@ func TestIsLastSignerForReleases(t *testing.T) {
releaserole.Signatures = []data.Signature{sig}
releaserole.Threshold = 1
allrole = []client.RoleWithSignatures{releaserole}
lastsigner, _ = isLastSignerForReleases(role, allrole)
lastsigner, err = isLastSignerForReleases(role, allrole)
assert.NilError(t, err)
assert.Check(t, is.Equal(true, lastsigner))
sig.KeyID = "8badf00d"
releaserole.Signatures = []data.Signature{sig}
releaserole.Threshold = 1
allrole = []client.RoleWithSignatures{releaserole}
lastsigner, _ = isLastSignerForReleases(role, allrole)
lastsigner, err = isLastSignerForReleases(role, allrole)
assert.NilError(t, err)
assert.Check(t, is.Equal(false, lastsigner))
}

View File

@ -0,0 +1,2 @@
Please confirm you would like to delete all signature data for example/trust-demo? [y/N]
Aborting action.

View File

@ -5,12 +5,15 @@ package command
import (
"bufio"
"context"
"fmt"
"io"
"os"
"os/signal"
"path/filepath"
"runtime"
"strings"
"syscall"
"github.com/docker/cli/cli/streams"
"github.com/docker/docker/api/types/filters"
@ -72,12 +75,21 @@ func PrettyPrint(i any) string {
}
}
// PromptForConfirmation requests and checks confirmation from user.
// This will display the provided message followed by ' [y/N] '. If
// the user input 'y' or 'Y' it returns true other false. If no
// message is provided "Are you sure you want to proceed? [y/N] "
// will be used instead.
func PromptForConfirmation(ins io.Reader, outs io.Writer, message string) bool {
type PromptError error
var ErrPromptTerminated = PromptError(errors.New("prompt terminated"))
// PromptForConfirmation requests and checks confirmation from the user.
// This will display the provided message followed by ' [y/N] '. If the user
// input 'y' or 'Y' it returns true otherwise false. If no message is provided,
// "Are you sure you want to proceed? [y/N] " will be used instead.
//
// If the user terminates the CLI with SIGINT or SIGTERM while the prompt is
// active, the prompt will return false with an ErrPromptTerminated error.
// When the prompt returns an error, the caller should propagate the error up
// the stack and close the io.Reader used for the prompt which will prevent the
// background goroutine from blocking indefinitely.
func PromptForConfirmation(ctx context.Context, ins io.Reader, outs io.Writer, message string) (bool, error) {
if message == "" {
message = "Are you sure you want to proceed?"
}
@ -90,9 +102,31 @@ func PromptForConfirmation(ins io.Reader, outs io.Writer, message string) bool {
ins = streams.NewIn(os.Stdin)
}
reader := bufio.NewReader(ins)
answer, _, _ := reader.ReadLine()
return strings.ToLower(string(answer)) == "y"
result := make(chan bool)
// Catch the termination signal and exit the prompt gracefully.
// The caller is responsible for properly handling the termination.
notifyCtx, notifyCancel := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM)
defer notifyCancel()
go func() {
var res bool
scanner := bufio.NewScanner(ins)
if scanner.Scan() {
answer := strings.TrimSpace(scanner.Text())
if strings.EqualFold(answer, "y") {
res = true
}
}
result <- res
}()
select {
case <-notifyCtx.Done():
return false, ErrPromptTerminated
case r := <-result:
return r, nil
}
}
// PruneFilters returns consolidated prune filters obtained from config.json and cli

Some files were not shown because too many files have changed in this diff Show More