Compare commits

...

65 Commits

Author SHA1 Message Date
e6534b4eb7 Merge pull request #6116 from vvoland/vendor-docker
Some checks failed
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 / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (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 v28.2.2-dev (45873be4ae3f)
2025-05-30 09:39:08 +00:00
5c3128e95e vendor: github.com/docker/docker v28.2.2-dev (45873be4ae3f)
full diff: 0e2cc22d36...45873be4ae

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-05-30 11:15:35 +02:00
879ac3f88f Merge pull request #6110 from thaJeztah/bump_engine
Some checks failed
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 / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (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 0e2cc22d36ae (v28.2-dev)
2025-05-28 13:17:56 +00:00
92fa1e1fc9 vendor: github.com/docker/docker 0e2cc22d36ae (v28.2-dev)
no changes in vendored code

full diff: 26db31fdab...0e2cc22d36

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-28 15:05:58 +02:00
4bec3a6795 Merge pull request #6114 from thaJeztah/deprecate_non_compliant_registries
docs: deprecated: fallback for non-OCI-compliant registries is removed
2025-05-28 14:28:52 +02:00
a007d1ae24 Merge pull request #6113 from thaJeztah/config_suppress_err
cli/config/configfile: explicitly ignore error
2025-05-28 12:08:37 +00:00
bbfbd54f4d docs: deprecated: fallback for non-OCI-compliant registries is removed
GitHub deprecated the legacy registry, and it was [sunset on Feb 24th, 2025][1]
in favor of GitHub Container Registry (GHCR) (ghcr.io), so the fallback
was removed.

[1]: https://github.blog/changelog/2025-01-23-legacy-docker-registry-closing-down/

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-28 10:05:40 +02:00
2d21e1f7a5 cli/config/configfile: explicitly ignore error
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-28 09:55:33 +02:00
bc9be0bdea Merge pull request #6112 from thaJeztah/bump_tools
Dockerfile: bump buildx v0.24.0, compose v2.36.2
2025-05-28 09:09:24 +02:00
3fe7dc5cb4 Dockerfile: update compose to v2.36.2
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-27 22:50:20 +02:00
9eae2a8976 Dockerfile: update buildx to v0.24.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-27 22:49:34 +02:00
a29e53dab7 Merge pull request #6111 from thaJeztah/update_deprecations
docs: deprecated: update status for non-standard fields in image inspect
2025-05-27 16:57:52 +02:00
da0c976fb0 docs: deprecated: update status for non-standard fields in image inspect
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-27 16:14:00 +02:00
17dc2880fa Merge pull request #6109 from thaJeztah/image_rm_platform
image rm: add --platform option
2025-05-27 12:11:26 +02:00
bb0ca9f9ef image rm: add --platform option
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-27 10:58:11 +02:00
f567263802 Merge pull request #6099 from thaJeztah/bump_engine
vendor: github.com/docker/docker 26db31fdab62 (v28.2-dev)
2025-05-27 10:49:43 +02:00
7775f01caa vendor: github.com/docker/docker 26db31fdab62 (v28.2-dev)
full diff: https://github.com/docker/docker/compare/v28.2.0-rc.2...26db31fdab628a2345ed8f179e575099384166a9

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-27 09:20:06 +02:00
908ff04d6e Merge pull request #6108 from thaJeztah/bump_engine_28.2
vendor: github.com/docker/docker v28.2.0-rc.2
2025-05-26 13:17:15 +00:00
519bc2daa1 vendor: github.com/docker/docker v28.2.0-rc.2
no changes in vendored code

full diff: https://github.com/docker/docker/compare/f4ffeb8c38b3...v28.2.0-rc.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-26 14:06:52 +02:00
b2c4452acb Merge pull request #6101 from thaJeztah/deprecated_api_versions_removed
Some checks failed
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 / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (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: deprecated: mark API < v1.24 as "removed"
2025-05-22 12:09:34 +00:00
3e287df661 Merge pull request #6100 from thaJeztah/fluentd_async_connect_removed
docs: deprecated: mark `fluentd-async-connect` as "removed"
2025-05-22 14:09:24 +02:00
f1fb3e3011 Merge pull request #5282 from willww64/fix-configfile-relative-symlink
correctly handle configuration file saving when it is a relative symlink
2025-05-22 12:08:40 +00:00
9c8666c106 docs: deprecated: mark API < v1.24 as "removed"
Support for API versions lower than v1.24 was removed in v26.0.
The DOCKER_MIN_API_VERSION environment-variable is still present
in the docker daemon, but can currently only be used to raise the
minimum version.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-22 13:37:44 +02:00
21d0466ff1 docs: deprecated: mark fluentd-async-connect as "removed"
The daemon still has migration code in place, but no longer accepts
the option for new containers, so marking it as "removed";
49ec488036

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-22 13:28:18 +02:00
1d3b933ac3 Merge pull request #6098 from thaJeztah/deprecated_inspect_fields
docs: deprecated: set Container and ContainerConfig fields to "removed"
2025-05-22 11:54:10 +02:00
649d088ddf Merge pull request #6096 from thaJeztah/graphdriver_plugin_deprecation
docs: update deprecation status of graphdriver-plugins to "removed"
2025-05-22 11:49:53 +02:00
e135563c1f Merge pull request #6097 from vvoland/28.x
vendor: github.com/docker/docker v28.2.0-dev (f4ffeb8c38b3)
2025-05-22 09:48:20 +00:00
026ae7a11f docs: deprecated: set Container and ContainerConfig fields to "removed"
These fields have been removed in v26.0 (API v1.45 and up), and are always
omitted when using the containerd image store;
03cddc62f4

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-22 11:45:57 +02:00
681c705be6 vendor: github.com/docker/docker v28.2.0-dev (f4ffeb8c38b3)
full diff: b590eff717...f4ffeb8c38

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-05-22 11:38:51 +02:00
bdd994b79a docs: update deprecation status of graphdriver-plugins to "removed"
This functionality, was removed and the DOCKERD_DEPRECATED_GRAPHDRIVER_PLUGINS
no longer can be used in v28.0;
42ca9154e9

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-22 11:29:37 +02:00
1015d15621 fix bug with config file being a relative symlink
- use filepath.EvalSymlink instead of check with filepath.IsAbs
- allow for dangling symlinks
- extract path from error when NotExist error occurs

Co-authored-by: Paweł Gronowski <me@woland.xyz>
Co-authored-by: Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: Will Wang <willww64@gmail.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-22 11:11:07 +02:00
ae922ec177 Merge pull request #6092 from thaJeztah/hijack_oncefunc
cli/command/container: hijackedIOStreamer.setupInput: use sync.OnceFunc
2025-05-22 10:02:11 +02:00
881c68f690 Merge pull request #4966 from Benehiko/relative-mount-path
feat: relative parent paths on bind mount src
2025-05-22 08:38:06 +02:00
761285bfee feat: relative parent paths on bind mount src
Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com>
2025-05-22 08:15:32 +02:00
f23ec25a12 Merge pull request #6095 from thaJeztah/update_schema1_deprecation
docs: move deprecation status of legacy schema1 images to "removed"
2025-05-22 08:06:45 +02:00
565b0a2822 Merge pull request #6094 from thaJeztah/fix_isautomated_status
docs: fix deprecation status for IsAutomated
2025-05-22 07:58:53 +02:00
4be9afb801 Merge pull request #6086 from thaJeztah/golangci_tweaks
golangci-lint: enable more linters, and some minor linting fixes
2025-05-22 07:57:53 +02:00
f05025caf9 docs: move deprecation status of legacy schema1 images to "removed"
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-22 01:10:13 +02:00
32a8f4c420 docs: fix deprecation status for IsAutomated
Follow-up to 6e4315f599, where
I forgot to update the status column.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-22 00:34:13 +02:00
68ef98d801 Merge pull request #6093 from vvoland/vendor-docker
vendor: github.com/docker/docker v28.2.0-dev (b590eff717b3)
2025-05-21 17:51:04 +00:00
63f2984336 vendor: github.com/docker/docker v28.2.0-dev (b590eff717b3)
full diff: 8601b22f5d...b590eff717

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-05-21 19:45:33 +02:00
0ee20b8543 Merge pull request #5995 from vvoland/swarm-init-cacert
swarm/init: Fix `--external-ca` ignoring `cacert` option
2025-05-21 18:31:14 +02:00
c07cd8aaad Merge pull request #6091 from thaJeztah/remove_deprecated_isautomated
search: remove deprecated "IsAutomated" placeholder
2025-05-21 15:43:36 +00:00
bf2eea31b5 cli/command/container: hijackedIOStreamer.setupInput: use sync.OnceFunc
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-21 17:34:51 +02:00
6e4315f599 search: remove deprecated "IsAutomated" placeholder
IsAutomated was deprecated in 4fc3f0e6f6
(docker v25.0), and marked for removal in docker 26.0 (which we missed).
This removes it.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-21 17:13:59 +02:00
97e060e7b1 Merge pull request #6042 from thaJeztah/carry_5804_docker_ps_platform
docker ps: add "Platform" as formatting option
2025-05-21 12:28:57 +00:00
67c0be4b05 docker ps: allow formatting as JSON
With this patch:

    docker ps --format 'table {{.Names}}\t{{.Platform}}'
    NAMES                    PLATFORM
    optimistic_nightingale   linux/arm64
    mycontainer              linux/arm64/v8
    trusting_goldstine       linux/arm64

    docker ps --format '{{.Platform}}'
    linux/arm64
    linux/arm64/v8
    linux/arm64

    docker ps --format '{{json .Platform}}'
    {"architecture":"arm64","os":"linux"}
    {"architecture":"arm64","os":"linux","variant":"v8"}
    {"architecture":"arm64","os":"linux"}

    docker ps --format 'json'
    {"Command":"\"/bin/bash\"","CreatedAt":"2025-05-13 10:12:19 +0000 UTC","ID":"e8b3b2d604f1","Image":"docker-cli-dev","Labels":"desktop.docker.io/binds/0/Source=/Users/thajeztah/go/src/github.com/docker/cli,desktop.docker.io/binds/0/SourceKind=hostFile,desktop.docker.io/binds/0/Target=/go/src/github.com/docker/cli,desktop.docker.io/mounts/0/Source=/var/run/docker.sock,desktop.docker.io/mounts/0/SourceKind=dockerSocketProxied,desktop.docker.io/mounts/0/Target=/var/run/docker.sock,desktop.docker.io/ports.scheme=v2","LocalVolumes":"1","Mounts":"/host_mnt/User…,docker-cli-dev…,/run/host-serv…","Names":"optimistic_nightingale","Networks":"bridge","Platform":{"architecture":"arm64","os":"linux"},"Ports":"","RunningFor":"38 minutes ago","Size":"0B","State":"running","Status":"Up 38 minutes"}
    {"Command":"\"/docker-entrypoint.…\"","CreatedAt":"2025-05-13 09:58:01 +0000 UTC","ID":"c93b808dd54e","Image":"nginx:alpine","Labels":"desktop.docker.io/ports.scheme=v2,maintainer=NGINX Docker Maintainers \u003cdocker-maint@nginx.com\u003e","LocalVolumes":"0","Mounts":"","Names":"mycontainer","Networks":"bridge","Platform":{"architecture":"arm64","os":"linux","variant":"v8"},"Ports":"80/tcp","RunningFor":"53 minutes ago","Size":"0B","State":"running","Status":"Up 53 minutes"}
    {"Command":"\"/usr/bin/gotty --ti…\"","CreatedAt":"2025-05-13 07:31:18 +0000 UTC","ID":"cbb981b06e46","Image":"thajeztah/dockershell:latest","Labels":"desktop.docker.io/ports.scheme=v2,com.thajeztah.docker-shell=1","LocalVolumes":"0","Mounts":"","Names":"trusting_goldstine","Networks":"bridge","Platform":{"architecture":"arm64","os":"linux"},"Ports":"0.0.0.0:55000-\u003e8080/tcp","RunningFor":"3 hours ago","Size":"0B","State":"running","Status":"Up 3 hours"}

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-21 12:44:38 +02:00
7aa6c79c0a docker ps: add "Platform" as formatting option
docker ps --format 'table {{.ID}}\t{{.Image}}{{.Command}}\t{{.RunningFor}}\t{{.Status}}\t{{.Ports}}\t{{.Names}}\t{{.Platform}}'
    CONTAINER ID   IMAGECOMMAND                CREATED          STATUS          PORTS     NAMES              PLATFORM
    e422855eac55   docker-cli-dev"/bin/bash"   12 minutes ago   Up 12 minutes             strange_jennings   linux/arm64

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-21 12:43:01 +02:00
af090512a6 Merge pull request #6084 from thaJeztah/bump_engine
vendor: github.com/docker/docker 8601b22f5db5 (v28.2-dev)
2025-05-20 10:57:13 +02:00
067587bf15 Merge pull request #6085 from thaJeztah/bump_cli_docs_tool
vendor: github.com/docker/cli-docs-tool v0.10.0
2025-05-20 09:30:29 +02:00
ed5d9757c9 vendor: github.com/docker/docker 8601b22f5db5 (v28.2-dev)
full diff: https://github.com/docker/docker/compare/v28.2.0-rc.1...8601b22f5db511354d643a7722d11d33aa7ae13f

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 22:47:14 +02:00
89f38282fd vendor: github.com/docker/docker v28.2.0-rc.1
no diff: same commit, but tagged

full diff: https://github.com/docker/docker/compare/7937f0846c13...v28.2.0-rc.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 22:40:55 +02:00
9d027dff40 Dockerfile: update golangci-lint to v2.1.5
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 20:16:23 +02:00
d1e9946ab8 golangci-lint: enable more linters
Enables the asasalint, exptostd, fatcontext, gocheckcompilerdirectives,
iface, makezero, and spancheck linters.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 20:14:13 +02:00
615ffee13b golangci-lint: enable nosprintfhostport linter
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 20:14:12 +02:00
c1313a92a0 golangci-lint: enable makezero linter
cli/command/container/formatter_stats_test.go:339:11: append to slice `stats` with non-zero initialized length (makezero)
            stats = append(stats, entry)
                    ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 20:14:12 +02:00
18e911c958 cli/command/container: TestContainerStatsContextWriteTrunc: use subtests
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 20:14:12 +02:00
d65f0c9bbf golangci-lint: enable exhaustive linter
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 20:14:04 +02:00
b64d9b3b19 golangci-lint: replace nilerr for nilnesserr
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 20:07:15 +02:00
062ad57ce2 golangci-lint: enable mirror linter
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 20:07:05 +02:00
915b3fe992 vendor: github.com/docker/cli-docs-tool v0.10.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 17:44:21 +02:00
2ef9ab4494 golangci-lint: align comments
Format comments to be the same as in moby/moby for easier comparing.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 15:36:11 +02:00
d14b7e8d09 golangci-lint: remove exclusions for ST1020, ST1022
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 15:33:44 +02:00
6c2d023d87 swarm/init: Fix --external-ca ignoring cacert option
31d6292458 mistakenly changed the `ToSpec`
function to set all certs passed via `external-ca` to empty strings.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-04-10 11:41:13 +02:00
a0385bf042 swarm/init: Test init --external-ca with custom cert
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-04-09 16:56:26 +02:00
121 changed files with 1270 additions and 1251 deletions

View File

@ -26,39 +26,49 @@ formatters:
linters:
enable:
- asasalint # Detects "[]any" used as argument for variadic "func(...any)".
- bodyclose
- copyloopvar # Detects places where loop variables are copied.
- copyloopvar # Detects places where loop variables are copied.
- depguard
- dogsled
- dupword # Detects duplicate words.
- durationcheck
- dogsled # Detects assignments with too many blank identifiers.
- dupword # Detects duplicate words.
- durationcheck # Detect cases where two time.Duration values are being multiplied in possibly erroneous ways.
- errcheck
- errchkjson
- errchkjson # Detects unsupported types passed to json encoding functions and reports if checks for the returned error can be omitted.
- exhaustive # Detects missing options in enum switch statements.
- exptostd # Detects functions from golang.org/x/exp/ that can be replaced by std functions.
- fatcontext # Detects nested contexts in loops and function literals.
- forbidigo
- gocritic # Metalinter; detects bugs, performance, and styling issues.
- gocheckcompilerdirectives # Detects invalid go compiler directive comments (//go:).
- gocritic # Metalinter; detects bugs, performance, and styling issues.
- gocyclo
- gosec # Detects security problems.
- gosec # Detects security problems.
- govet
- iface # Detects incorrect use of interfaces. Currently only used for "identical" interfaces in the same package.
- importas # Enforces consistent import aliases.
- ineffassign
- importas # Enforces consistent import aliases.
- misspell # Detects commonly misspelled English words in comments.
- nakedret # Detects uses of naked returns.
- nilerr # Detects code that returns nil even if it checks that the error is not nil.
- nolintlint # Detects ill-formed or insufficient nolint directives.
- perfsprint # Detects fmt.Sprintf uses that can be replaced with a faster alternative.
- prealloc # Detects slice declarations that could potentially be pre-allocated.
- predeclared # Detects code that shadows one of Go's predeclared identifiers
- reassign
- revive # Metalinter; drop-in replacement for golint.
- makezero # Finds slice declarations with non-zero initial length.
- mirror # Detects wrong mirror patterns of bytes/strings usage.
- misspell # Detects commonly misspelled English words in comments.
- nakedret # Detects uses of naked returns.
- nilnesserr # Detects returning nil errors. It combines the features of nilness and nilerr,
- nosprintfhostport # Detects misuse of Sprintf to construct a host with port in a URL.
- nolintlint # Detects ill-formed or insufficient nolint directives.
- perfsprint # Detects fmt.Sprintf uses that can be replaced with a faster alternative.
- prealloc # Detects slice declarations that could potentially be pre-allocated.
- predeclared # Detects code that shadows one of Go's predeclared identifiers
- reassign # Detects reassigning a top-level variable in another package.
- revive # Metalinter; drop-in replacement for golint.
- spancheck # Detects mistakes with OpenTelemetry/Census spans.
- staticcheck
- thelper # Detects test helpers without t.Helper().
- tparallel # Detects inappropriate usage of t.Parallel().
- unconvert # Detects unnecessary type conversions.
- thelper # Detects test helpers without t.Helper().
- tparallel # Detects inappropriate usage of t.Parallel().
- unconvert # Detects unnecessary type conversions.
- unparam
- unused
- usestdlibvars
- usetesting # Reports uses of functions with replacement inside the testing package.
- wastedassign
- usestdlibvars # Detects the possibility to use variables/constants from the Go standard library.
- usetesting # Reports uses of functions with replacement inside the testing package.
- wastedassign # Detects wasted assignment statements.
disable:
- errcheck
@ -132,9 +142,7 @@ linters:
staticcheck:
checks:
- all
- -QF1008 # Omit embedded fields from selector expression
- -ST1020 # The documentation of an exported function should start with the functions name
- -ST1022 # The documentation of an exported variable or constant should start with variables name
- -QF1008 # Omit embedded fields from selector expression; https://staticcheck.dev/docs/checks/#QF1008
revive:
rules:
@ -159,8 +167,8 @@ linters:
# (unlike the "include" option), the "exclude" option does not take exclusion
# ID's.
#
# These exclusion patterns are copied from the default excluses at:
# https://github.com/golangci/golangci-lint/blob/v1.44.0/pkg/config/issues.go#L10-L104
# These exclusion patterns are copied from the default excludes at:
# https://github.com/golangci/golangci-lint/blob/v1.61.0/pkg/config/issues.go#L11-L104
#
# The default list of exclusions can be found at:
# https://golangci-lint.run/usage/false-positives/#default-exclusions
@ -207,6 +215,12 @@ linters:
linters:
- govet
# Ignore for cli/command/formatter/tabwriter, which is forked from go stdlib, so we want to align with it.
- text: '^(ST1020|ST1022): comment on exported'
path: "cli/command/formatter/tabwriter"
linters:
- staticcheck
# Log a warning if an exclusion rule is unused.
# Default: false
warn-unused: true

View File

@ -12,8 +12,8 @@ ARG GOTESTSUM_VERSION=v1.12.0
# BUILDX_VERSION sets the version of buildx to use for the e2e tests.
# It must be a tag in the docker.io/docker/buildx-bin image repository
# on Docker Hub.
ARG BUILDX_VERSION=0.23.0
ARG COMPOSE_VERSION=v2.35.1
ARG BUILDX_VERSION=0.24.0
ARG COMPOSE_VERSION=v2.36.2
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx

View File

@ -81,7 +81,7 @@ func addPluginCandidatesFromDir(res map[string][]string, d string) {
return
}
for _, dentry := range dentries {
switch dentry.Type() & os.ModeType {
switch dentry.Type() & os.ModeType { //nolint:exhaustive,nolintlint // no need to include all possible file-modes in this list
case 0, os.ModeSymlink:
// Regular file or symlink, keep going
default:

View File

@ -148,7 +148,7 @@ container2 -- --
`,
},
}
stats := []StatsEntry{
entries := []StatsEntry{
{
Container: "container1",
CPUPercentage: 20,
@ -181,7 +181,7 @@ container2 -- --
t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer
tc.context.Output = &out
err := statsFormatWrite(tc.context, stats, "windows", false)
err := statsFormatWrite(tc.context, entries, "windows", false)
if err != nil {
assert.Error(t, err, tc.expected)
} else {
@ -273,45 +273,46 @@ func TestContainerStatsContextWriteWithNoStatsWindows(t *testing.T) {
}
func TestContainerStatsContextWriteTrunc(t *testing.T) {
var out bytes.Buffer
contexts := []struct {
tests := []struct {
doc string
context formatter.Context
trunc bool
expected string
}{
{
formatter.Context{
doc: "non-truncated",
context: formatter.Context{
Format: "{{.ID}}",
Output: &out,
},
false,
"b95a83497c9161c9b444e3d70e1a9dfba0c1840d41720e146a95a08ebf938afc\n",
expected: "b95a83497c9161c9b444e3d70e1a9dfba0c1840d41720e146a95a08ebf938afc\n",
},
{
formatter.Context{
doc: "truncated",
context: formatter.Context{
Format: "{{.ID}}",
Output: &out,
},
true,
"b95a83497c91\n",
trunc: true,
expected: "b95a83497c91\n",
},
}
for _, context := range contexts {
statsFormatWrite(context.context, []StatsEntry{{ID: "b95a83497c9161c9b444e3d70e1a9dfba0c1840d41720e146a95a08ebf938afc"}}, "linux", context.trunc)
assert.Check(t, is.Equal(context.expected, out.String()))
// Clean buffer
out.Reset()
for _, tc := range tests {
t.Run(tc.doc, func(t *testing.T) {
var out bytes.Buffer
tc.context.Output = &out
err := statsFormatWrite(tc.context, []StatsEntry{{ID: "b95a83497c9161c9b444e3d70e1a9dfba0c1840d41720e146a95a08ebf938afc"}}, "linux", tc.trunc)
assert.NilError(t, err)
assert.Check(t, is.Equal(tc.expected, out.String()))
})
}
}
func BenchmarkStatsFormat(b *testing.B) {
b.ReportAllocs()
stats := genStats()
entries := genStats()
for i := 0; i < b.N; i++ {
for _, s := range stats {
for _, s := range entries {
_ = s.CPUPerc()
_ = s.MemUsage()
_ = s.MemPerc()
@ -334,9 +335,9 @@ func genStats() []statsContext {
NetworkTx: 987.654321,
PidsCurrent: 123456789,
}}
stats := make([]statsContext, 100)
for i := 0; i < 100; i++ {
stats = append(stats, entry)
entries := make([]statsContext, 0, 100)
for range 100 {
entries = append(entries, entry)
}
return stats
return entries
}

View File

@ -84,12 +84,9 @@ func (h *hijackedIOStreamer) setupInput() (restore func(), err error) {
// Use sync.Once so we may call restore multiple times but ensure we
// only restore the terminal once.
var restoreOnce sync.Once
restore = func() {
restoreOnce.Do(func() {
_ = restoreTerminal(h.streams, h.inputStream)
})
}
restore = sync.OnceFunc(func() {
_ = restoreTerminal(h.streams, h.inputStream)
})
// Wrap the input to detect detach escape sequence.
// Use default escape keys if an invalid sequence is given.

View File

@ -375,7 +375,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
if parsed.Type == string(mounttypes.TypeBind) {
if hostPart, targetPath, ok := strings.Cut(bind, ":"); ok {
if strings.HasPrefix(hostPart, "."+string(filepath.Separator)) || hostPart == "." {
if !filepath.IsAbs(hostPart) && strings.HasPrefix(hostPart, ".") {
if absHostPart, err := filepath.Abs(hostPart); err == nil {
hostPart = absHostPart
}

View File

@ -11,10 +11,12 @@ import (
"strings"
"time"
"github.com/containerd/platforms"
"github.com/distribution/reference"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/go-units"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
const (
@ -26,8 +28,18 @@ const (
mountsHeader = "MOUNTS"
localVolumes = "LOCAL VOLUMES"
networksHeader = "NETWORKS"
platformHeader = "PLATFORM"
)
// Platform wraps a [ocispec.Platform] to implement the stringer interface.
type Platform struct {
ocispec.Platform
}
func (p Platform) String() string {
return platforms.FormatAll(p.Platform)
}
// NewContainerFormat returns a Format for rendering using a Context
func NewContainerFormat(source string, quiet bool, size bool) Format {
switch source {
@ -109,6 +121,7 @@ func NewContainerContext() *ContainerContext {
"Mounts": mountsHeader,
"LocalVolumes": localVolumes,
"Networks": networksHeader,
"Platform": platformHeader,
}
return &containerCtx
}
@ -208,6 +221,16 @@ func (c *ContainerContext) RunningFor() string {
return units.HumanDuration(time.Now().UTC().Sub(createdAt)) + " ago"
}
// Platform returns a human-readable representation of the container's
// platform if it is available.
func (c *ContainerContext) Platform() *Platform {
p := c.c.ImageManifestDescriptor
if p == nil || p.Platform == nil {
return nil
}
return &Platform{*p.Platform}
}
// Ports returns a comma-separated string representing open ports of the container
// e.g. "0.0.0.0:80->9090/tcp, 9988/tcp"
// it's used by command 'docker ps'

View File

@ -14,6 +14,7 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/stringid"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/golden"
@ -425,13 +426,36 @@ func TestContainerContextWriteWithNoContainers(t *testing.T) {
func TestContainerContextWriteJSON(t *testing.T) {
unix := time.Now().Add(-65 * time.Second).Unix()
containers := []container.Summary{
{ID: "containerID1", Names: []string{"/foobar_baz"}, Image: "ubuntu", Created: unix, State: container.StateRunning},
{ID: "containerID2", Names: []string{"/foobar_bar"}, Image: "ubuntu", Created: unix, State: container.StateRunning},
{
ID: "containerID1",
Names: []string{"/foobar_baz"},
Image: "ubuntu",
Created: unix,
State: container.StateRunning,
},
{
ID: "containerID2",
Names: []string{"/foobar_bar"},
Image: "ubuntu",
Created: unix,
State: container.StateRunning,
ImageManifestDescriptor: &ocispec.Descriptor{Platform: &ocispec.Platform{Architecture: "amd64", OS: "linux"}},
},
{
ID: "containerID3",
Names: []string{"/foobar_bar"},
Image: "ubuntu",
Created: unix,
State: container.StateRunning,
ImageManifestDescriptor: &ocispec.Descriptor{Platform: &ocispec.Platform{}},
},
}
expectedCreated := time.Unix(unix, 0).String()
expectedJSONs := []map[string]any{
{
"Command": "\"\"",
"Command": `""`,
"CreatedAt": expectedCreated,
"ID": "containerID1",
"Image": "ubuntu",
@ -440,6 +464,7 @@ func TestContainerContextWriteJSON(t *testing.T) {
"Mounts": "",
"Names": "foobar_baz",
"Networks": "",
"Platform": nil,
"Ports": "",
"RunningFor": "About a minute ago",
"Size": "0B",
@ -447,7 +472,7 @@ func TestContainerContextWriteJSON(t *testing.T) {
"Status": "",
},
{
"Command": "\"\"",
"Command": `""`,
"CreatedAt": expectedCreated,
"ID": "containerID2",
"Image": "ubuntu",
@ -456,6 +481,24 @@ func TestContainerContextWriteJSON(t *testing.T) {
"Mounts": "",
"Names": "foobar_bar",
"Networks": "",
"Platform": map[string]any{"architecture": "amd64", "os": "linux"},
"Ports": "",
"RunningFor": "About a minute ago",
"Size": "0B",
"State": "running",
"Status": "",
},
{
"Command": `""`,
"CreatedAt": expectedCreated,
"ID": "containerID3",
"Image": "ubuntu",
"Labels": "",
"LocalVolumes": "0",
"Mounts": "",
"Names": "foobar_bar",
"Networks": "",
"Platform": map[string]any{"architecture": "", "os": ""},
"Ports": "",
"RunningFor": "About a minute ago",
"Size": "0B",

View File

@ -20,6 +20,8 @@ func charWidth(r rune) int {
switch width.LookupRune(r).Kind() {
case width.EastAsianWide, width.EastAsianFullwidth:
return 2
case width.Neutral, width.EastAsianAmbiguous, width.EastAsianNarrow, width.EastAsianHalfwidth:
return 1
default:
return 1
}

View File

@ -3,7 +3,6 @@ package idresolver
import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
)
@ -21,7 +20,7 @@ func (cli *fakeClient) NodeInspectWithRaw(_ context.Context, nodeID string) (swa
return swarm.Node{}, []byte{}, nil
}
func (cli *fakeClient) ServiceInspectWithRaw(_ context.Context, serviceID string, _ types.ServiceInspectOptions) (swarm.Service, []byte, error) {
func (cli *fakeClient) ServiceInspectWithRaw(_ context.Context, serviceID string, _ swarm.ServiceInspectOptions) (swarm.Service, []byte, error) {
if cli.serviceInspectFunc != nil {
return cli.serviceInspectFunc(serviceID)
}

View File

@ -6,7 +6,6 @@ package idresolver
import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
"github.com/pkg/errors"
@ -44,7 +43,7 @@ func (r *IDResolver) get(ctx context.Context, t any, id string) (string, error)
}
return id, nil
case swarm.Service:
service, _, err := r.client.ServiceInspectWithRaw(ctx, id, types.ServiceInspectOptions{})
service, _, err := r.client.ServiceInspectWithRaw(ctx, id, swarm.ServiceInspectOptions{})
if err != nil {
// TODO(thaJeztah): should error-handling be more specific, or is it ok to ignore any error?
return id, nil //nolint:nilerr // ignore nil-error being returned, as this is a best-effort.

View File

@ -6,6 +6,7 @@ import (
"fmt"
cerrdefs "github.com/containerd/errdefs"
"github.com/containerd/platforms"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
@ -14,22 +15,23 @@ import (
)
type removeOptions struct {
force bool
noPrune bool
force bool
noPrune bool
platforms []string
}
// NewRemoveCommand creates a new `docker remove` command
func NewRemoveCommand(dockerCli command.Cli) *cobra.Command {
var opts removeOptions
func NewRemoveCommand(dockerCLI command.Cli) *cobra.Command {
var options removeOptions
cmd := &cobra.Command{
Use: "rmi [OPTIONS] IMAGE [IMAGE...]",
Short: "Remove one or more images",
Args: cli.RequiresMinArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return runRemove(cmd.Context(), dockerCli, opts, args)
return runRemove(cmd.Context(), dockerCLI, options, args)
},
ValidArgsFunction: completion.ImageNames(dockerCli, -1),
ValidArgsFunction: completion.ImageNames(dockerCLI, -1),
Annotations: map[string]string{
"aliases": "docker image rm, docker image remove, docker rmi",
},
@ -37,9 +39,14 @@ func NewRemoveCommand(dockerCli command.Cli) *cobra.Command {
flags := cmd.Flags()
flags.BoolVarP(&opts.force, "force", "f", false, "Force removal of the image")
flags.BoolVar(&opts.noPrune, "no-prune", false, "Do not delete untagged parents")
flags.BoolVarP(&options.force, "force", "f", false, "Force removal of the image")
flags.BoolVar(&options.noPrune, "no-prune", false, "Do not delete untagged parents")
// TODO(thaJeztah): create a "platforms" option for this (including validation / parsing).
flags.StringSliceVar(&options.platforms, "platform", nil, `Remove only the given platform variant. Formatted as "os[/arch[/variant]]" (e.g., "linux/amd64")`)
_ = flags.SetAnnotation("platform", "version", []string{"1.50"})
_ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms)
return cmd
}
@ -58,6 +65,14 @@ func runRemove(ctx context.Context, dockerCLI command.Cli, opts removeOptions, i
PruneChildren: !opts.noPrune,
}
for _, v := range opts.platforms {
p, err := platforms.Parse(v)
if err != nil {
return err
}
options.Platforms = append(options.Platforms, p)
}
// TODO(thaJeztah): this logic can likely be simplified: do we want to print "not found" errors at all when using "force"?
fatalErr := false
var errs []error

View File

@ -3,7 +3,6 @@ package node
import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/system"
"github.com/docker/docker/client"
@ -17,8 +16,8 @@ type fakeClient struct {
nodeRemoveFunc func() error
nodeUpdateFunc func(nodeID string, version swarm.Version, node swarm.NodeSpec) error
taskInspectFunc func(taskID string) (swarm.Task, []byte, error)
taskListFunc func(options types.TaskListOptions) ([]swarm.Task, error)
serviceInspectFunc func(ctx context.Context, serviceID string, opts types.ServiceInspectOptions) (swarm.Service, []byte, error)
taskListFunc func(options swarm.TaskListOptions) ([]swarm.Task, error)
serviceInspectFunc func(ctx context.Context, serviceID string, opts swarm.ServiceInspectOptions) (swarm.Service, []byte, error)
}
func (cli *fakeClient) NodeInspectWithRaw(context.Context, string) (swarm.Node, []byte, error) {
@ -28,14 +27,14 @@ func (cli *fakeClient) NodeInspectWithRaw(context.Context, string) (swarm.Node,
return swarm.Node{}, []byte{}, nil
}
func (cli *fakeClient) NodeList(context.Context, types.NodeListOptions) ([]swarm.Node, error) {
func (cli *fakeClient) NodeList(context.Context, swarm.NodeListOptions) ([]swarm.Node, error) {
if cli.nodeListFunc != nil {
return cli.nodeListFunc()
}
return []swarm.Node{}, nil
}
func (cli *fakeClient) NodeRemove(context.Context, string, types.NodeRemoveOptions) error {
func (cli *fakeClient) NodeRemove(context.Context, string, swarm.NodeRemoveOptions) error {
if cli.nodeRemoveFunc != nil {
return cli.nodeRemoveFunc()
}
@ -63,14 +62,14 @@ func (cli *fakeClient) TaskInspectWithRaw(_ context.Context, taskID string) (swa
return swarm.Task{}, []byte{}, nil
}
func (cli *fakeClient) TaskList(_ context.Context, options types.TaskListOptions) ([]swarm.Task, error) {
func (cli *fakeClient) TaskList(_ context.Context, options swarm.TaskListOptions) ([]swarm.Task, error) {
if cli.taskListFunc != nil {
return cli.taskListFunc(options)
}
return []swarm.Task{}, nil
}
func (cli *fakeClient) ServiceInspectWithRaw(ctx context.Context, serviceID string, opts types.ServiceInspectOptions) (swarm.Service, []byte, error) {
func (cli *fakeClient) ServiceInspectWithRaw(ctx context.Context, serviceID string, opts swarm.ServiceInspectOptions) (swarm.Service, []byte, error) {
if cli.serviceInspectFunc != nil {
return cli.serviceInspectFunc(ctx, serviceID, opts)
}

View File

@ -6,7 +6,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/swarm"
"github.com/docker/docker/client"
"github.com/spf13/cobra"
)
@ -48,7 +48,7 @@ func Reference(ctx context.Context, apiClient client.APIClient, ref string) (str
// If there's no node ID in /info, the node probably
// isn't a manager. Call a swarm-specific endpoint to
// get a more specific error message.
_, err = apiClient.NodeList(ctx, types.NodeListOptions{})
_, err = apiClient.NodeList(ctx, swarm.NodeListOptions{})
if err != nil {
return "", err
}

View File

@ -4,7 +4,7 @@ import (
"os"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/spf13/cobra"
)
@ -17,7 +17,7 @@ func completeNodeNames(dockerCLI completion.APIClientProvider) cobra.CompletionF
// https://github.com/docker/cli/blob/f9ced58158d5e0b358052432244b483774a1983d/contrib/completion/bash/docker#L41-L43
showIDs := os.Getenv("DOCKER_COMPLETION_SHOW_NODE_IDS") == "yes"
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
list, err := dockerCLI.Client().NodeList(cmd.Context(), types.NodeListOptions{})
list, err := dockerCLI.Client().NodeList(cmd.Context(), swarm.NodeListOptions{})
if err != nil {
return nil, cobra.ShellCompDirectiveError
}

View File

@ -10,7 +10,7 @@ import (
"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/swarm"
"github.com/docker/docker/api/types/system"
"github.com/fvbommel/sortorder"
"github.com/spf13/cobra"
@ -55,7 +55,7 @@ func runList(ctx context.Context, dockerCli command.Cli, options listOptions) er
nodes, err := client.NodeList(
ctx,
types.NodeListOptions{Filters: options.filter.Value()})
swarm.NodeListOptions{Filters: options.filter.Value()})
if err != nil {
return err
}

View File

@ -10,7 +10,6 @@ import (
"github.com/docker/cli/cli/command/idresolver"
"github.com/docker/cli/cli/command/task"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -84,7 +83,7 @@ func runPs(ctx context.Context, dockerCli command.Cli, options psOptions) error
filter := options.filter.Value()
filter.Add("node", node.ID)
nodeTasks, err := client.TaskList(ctx, types.TaskListOptions{Filters: filter})
nodeTasks, err := client.TaskList(ctx, swarm.TaskListOptions{Filters: filter})
if err != nil {
errs = append(errs, err.Error())
continue

View File

@ -10,7 +10,6 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/builders"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/system"
"gotest.tools/v3/assert"
@ -23,7 +22,7 @@ func TestNodePsErrors(t *testing.T) {
flags map[string]string
infoFunc func() (system.Info, error)
nodeInspectFunc func() (swarm.Node, []byte, error)
taskListFunc func(options types.TaskListOptions) ([]swarm.Task, error)
taskListFunc func(options swarm.TaskListOptions) ([]swarm.Task, error)
taskInspectFunc func(taskID string) (swarm.Task, []byte, error)
expectedError string
}{
@ -42,7 +41,7 @@ func TestNodePsErrors(t *testing.T) {
},
{
args: []string{"nodeID"},
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
taskListFunc: func(options swarm.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{}, errors.New("error returning the task list")
},
expectedError: "error returning the task list",
@ -73,9 +72,9 @@ func TestNodePs(t *testing.T) {
flags map[string]string
infoFunc func() (system.Info, error)
nodeInspectFunc func() (swarm.Node, []byte, error)
taskListFunc func(options types.TaskListOptions) ([]swarm.Task, error)
taskListFunc func(options swarm.TaskListOptions) ([]swarm.Task, error)
taskInspectFunc func(taskID string) (swarm.Task, []byte, error)
serviceInspectFunc func(ctx context.Context, serviceID string, opts types.ServiceInspectOptions) (swarm.Service, []byte, error)
serviceInspectFunc func(ctx context.Context, serviceID string, opts swarm.ServiceInspectOptions) (swarm.Service, []byte, error)
}{
{
name: "simple",
@ -83,7 +82,7 @@ func TestNodePs(t *testing.T) {
nodeInspectFunc: func() (swarm.Node, []byte, error) {
return *builders.Node(), []byte{}, nil
},
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
taskListFunc: func(options swarm.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{
*builders.Task(builders.WithStatus(builders.Timestamp(time.Now().Add(-2*time.Hour)), builders.PortStatus([]swarm.PortConfig{
{
@ -94,7 +93,7 @@ func TestNodePs(t *testing.T) {
}))),
}, nil
},
serviceInspectFunc: func(ctx context.Context, serviceID string, opts types.ServiceInspectOptions) (swarm.Service, []byte, error) {
serviceInspectFunc: func(ctx context.Context, serviceID string, opts swarm.ServiceInspectOptions) (swarm.Service, []byte, error) {
return swarm.Service{
ID: serviceID,
Spec: swarm.ServiceSpec{
@ -111,7 +110,7 @@ func TestNodePs(t *testing.T) {
nodeInspectFunc: func() (swarm.Node, []byte, error) {
return *builders.Node(), []byte{}, nil
},
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
taskListFunc: func(options swarm.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{
*builders.Task(builders.TaskID("taskID1"), builders.TaskServiceID("failure"),
builders.WithStatus(builders.Timestamp(time.Now().Add(-2*time.Hour)), builders.StatusErr("a task error"))),
@ -121,7 +120,7 @@ func TestNodePs(t *testing.T) {
builders.WithStatus(builders.Timestamp(time.Now().Add(-4*time.Hour)), builders.StatusErr("a task error"))),
}, nil
},
serviceInspectFunc: func(ctx context.Context, serviceID string, opts types.ServiceInspectOptions) (swarm.Service, []byte, error) {
serviceInspectFunc: func(ctx context.Context, serviceID string, opts swarm.ServiceInspectOptions) (swarm.Service, []byte, error) {
return swarm.Service{
ID: serviceID,
Spec: swarm.ServiceSpec{

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/swarm"
"github.com/spf13/cobra"
)
@ -38,7 +38,7 @@ func runRemove(ctx context.Context, dockerCLI command.Cli, nodeIDs []string, opt
var errs []error
for _, id := range nodeIDs {
if err := apiClient.NodeRemove(ctx, id, types.NodeRemoveOptions{Force: opts.force}); err != nil {
if err := apiClient.NodeRemove(ctx, id, swarm.NodeRemoveOptions{Force: opts.force}); err != nil {
errs = append(errs, err)
continue
}

View File

@ -42,7 +42,6 @@ func SearchWrite(ctx formatter.Context, results []registrytypes.SearchResult) er
"Description": formatter.DescriptionHeader,
"StarCount": starsHeader,
"IsOfficial": officialHeader,
"IsAutomated": automatedHeader,
}
return ctx.Write(&searchCtx, render)
}
@ -92,10 +91,3 @@ func (c *searchContext) formatBool(value bool) string {
func (c *searchContext) IsOfficial() string {
return c.formatBool(c.s.IsOfficial)
}
// IsAutomated formats the IsAutomated field for printing.
//
// Deprecated: the "is_automated" field is deprecated and will always be "false" in the future.
func (c *searchContext) IsAutomated() string {
return c.formatBool(c.s.IsAutomated) //nolint:nolintlint,staticcheck // ignore SA1019 (IsAutomated is deprecated).
}

View File

@ -45,19 +45,6 @@ func TestSearchContext(t *testing.T) {
},
call: ctx.IsOfficial,
},
{
searchCtx: searchContext{
s: registrytypes.SearchResult{IsAutomated: true}, //nolint:nolintlint,staticcheck // ignore SA1019 (IsAutomated is deprecated).
},
expValue: "[OK]",
call: ctx.IsAutomated, //nolint:nolintlint,staticcheck // ignore SA1019 (IsAutomated is deprecated).
},
{
searchCtx: searchContext{
s: registrytypes.SearchResult{},
},
call: ctx.IsAutomated, //nolint:nolintlint,staticcheck // ignore SA1019 (IsAutomated is deprecated).
},
}
for _, c := range cases {
@ -157,8 +144,8 @@ func TestSearchContextWrite(t *testing.T) {
{
doc: "JSON format",
format: "{{json .}}",
expected: `{"Description":"Official build","IsAutomated":"false","IsOfficial":"true","Name":"result1","StarCount":"5000"}
{"Description":"Not official","IsAutomated":"true","IsOfficial":"false","Name":"result2","StarCount":"5"}
expected: `{"Description":"Official build","IsOfficial":"true","Name":"result1","StarCount":"5000"}
{"Description":"Not official","IsOfficial":"false","Name":"result2","StarCount":"5"}
`,
},
{
@ -199,7 +186,7 @@ result2 5
results := []registrytypes.SearchResult{
{Name: "result1", Description: "Official build", StarCount: 5000, IsOfficial: true},
{Name: "result2", Description: "Not official", StarCount: 5, IsAutomated: true},
{Name: "result2", Description: "Not official", StarCount: 5},
}
for _, tc := range cases {

View File

@ -4,7 +4,6 @@ import (
"context"
"github.com/docker/cli/internal/test/builders"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/system"
@ -13,30 +12,30 @@ import (
type fakeClient struct {
client.Client
serviceInspectWithRawFunc func(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error)
serviceUpdateFunc func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error)
serviceListFunc func(context.Context, types.ServiceListOptions) ([]swarm.Service, error)
taskListFunc func(context.Context, types.TaskListOptions) ([]swarm.Task, error)
serviceInspectWithRawFunc func(ctx context.Context, serviceID string, options swarm.ServiceInspectOptions) (swarm.Service, []byte, error)
serviceUpdateFunc func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options swarm.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error)
serviceListFunc func(context.Context, swarm.ServiceListOptions) ([]swarm.Service, error)
taskListFunc func(context.Context, swarm.TaskListOptions) ([]swarm.Task, error)
infoFunc func(ctx context.Context) (system.Info, error)
networkInspectFunc func(ctx context.Context, networkID string, options network.InspectOptions) (network.Inspect, error)
nodeListFunc func(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error)
nodeListFunc func(ctx context.Context, options swarm.NodeListOptions) ([]swarm.Node, error)
}
func (f *fakeClient) NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) {
func (f *fakeClient) NodeList(ctx context.Context, options swarm.NodeListOptions) ([]swarm.Node, error) {
if f.nodeListFunc != nil {
return f.nodeListFunc(ctx, options)
}
return nil, nil
}
func (f *fakeClient) TaskList(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error) {
func (f *fakeClient) TaskList(ctx context.Context, options swarm.TaskListOptions) ([]swarm.Task, error) {
if f.taskListFunc != nil {
return f.taskListFunc(ctx, options)
}
return nil, nil
}
func (f *fakeClient) ServiceInspectWithRaw(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) {
func (f *fakeClient) ServiceInspectWithRaw(ctx context.Context, serviceID string, options swarm.ServiceInspectOptions) (swarm.Service, []byte, error) {
if f.serviceInspectWithRawFunc != nil {
return f.serviceInspectWithRawFunc(ctx, serviceID, options)
}
@ -44,7 +43,7 @@ func (f *fakeClient) ServiceInspectWithRaw(ctx context.Context, serviceID string
return *builders.Service(builders.ServiceID(serviceID)), []byte{}, nil
}
func (f *fakeClient) ServiceList(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) {
func (f *fakeClient) ServiceList(ctx context.Context, options swarm.ServiceListOptions) ([]swarm.Service, error) {
if f.serviceListFunc != nil {
return f.serviceListFunc(ctx, options)
}
@ -52,7 +51,7 @@ func (f *fakeClient) ServiceList(ctx context.Context, options types.ServiceListO
return nil, nil
}
func (f *fakeClient) ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error) {
func (f *fakeClient) ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options swarm.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error) {
if f.serviceUpdateFunc != nil {
return f.serviceUpdateFunc(ctx, serviceID, version, service, options)
}

View File

@ -4,7 +4,7 @@ import (
"os"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/spf13/cobra"
)
@ -15,7 +15,7 @@ func completeServiceNames(dockerCLI completion.APIClientProvider) cobra.Completi
// https://github.com/docker/cli/blob/f9ced58158d5e0b358052432244b483774a1983d/contrib/completion/bash/docker#L41-L43
showIDs := os.Getenv("DOCKER_COMPLETION_SHOW_SERVICE_IDS") == "yes"
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
list, err := dockerCLI.Client().ServiceList(cmd.Context(), types.ServiceListOptions{})
list, err := dockerCLI.Client().ServiceList(cmd.Context(), swarm.ServiceListOptions{})
if err != nil {
return nil, cobra.ShellCompDirectiveError
}

View File

@ -8,7 +8,6 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
cliopts "github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/client"
@ -102,7 +101,7 @@ func newCreateCommand(dockerCLI command.Cli) *cobra.Command {
func runCreate(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet, opts *serviceOptions) error {
apiClient := dockerCLI.Client()
createOpts := types.ServiceCreateOptions{}
createOpts := swarm.ServiceCreateOptions{}
service, err := opts.ToService(ctx, apiClient, flags)
if err != nil {

View File

@ -13,8 +13,8 @@ import (
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/swarm"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
@ -66,7 +66,7 @@ func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions)
getRef := func(ref string) (any, []byte, error) {
// Service inspect shows defaults values in empty fields.
service, _, err := client.ServiceInspectWithRaw(ctx, ref, types.ServiceInspectOptions{InsertDefaults: true})
service, _, err := client.ServiceInspectWithRaw(ctx, ref, swarm.ServiceInspectOptions{InsertDefaults: true})
if err == nil || !cerrdefs.IsNotFound(err) {
return service, nil, err
}

View File

@ -9,7 +9,6 @@ import (
"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/filters"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
@ -57,7 +56,7 @@ func runList(ctx context.Context, dockerCLI command.Cli, options listOptions) er
err error
)
listOpts := types.ServiceListOptions{
listOpts := swarm.ServiceListOptions{
Filters: options.filter.Value(),
// When not running "quiet", also get service status (number of running
// and desired tasks). Note that this is only supported on API v1.41 and
@ -147,7 +146,7 @@ func AppendServiceStatus(ctx context.Context, c client.APIClient, services []swa
return services, nil
}
tasks, err := c.TaskList(ctx, types.TaskListOptions{Filters: taskFilter})
tasks, err := c.TaskList(ctx, swarm.TaskListOptions{Filters: taskFilter})
if err != nil {
return nil, err
}
@ -184,7 +183,7 @@ func AppendServiceStatus(ctx context.Context, c client.APIClient, services []swa
}
func getActiveNodes(ctx context.Context, c client.NodeAPIClient) (map[string]struct{}, error) {
nodes, err := c.NodeList(ctx, types.NodeListOptions{})
nodes, err := c.NodeList(ctx, swarm.NodeListOptions{})
if err != nil {
return nil, err
}

View File

@ -9,7 +9,6 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/builders"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/versions"
"gotest.tools/v3/assert"
@ -19,7 +18,7 @@ import (
func TestServiceListOrder(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
serviceListFunc: func(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(ctx context.Context, options swarm.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{
newService("a57dbe8", "service-1-foo"),
newService("a57dbdd", "service-10-foo"),
@ -173,7 +172,7 @@ func TestServiceListServiceStatus(t *testing.T) {
tc.cluster = generateCluster(t, tc.opts)
}
cli := test.NewFakeCli(&fakeClient{
serviceListFunc: func(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(ctx context.Context, options swarm.ServiceListOptions) ([]swarm.Service, error) {
if !options.Status || versions.LessThan(tc.opts.apiVersion, "1.41") {
// Don't return "ServiceStatus" if not requested, or on older API versions
for i := range tc.cluster.services {
@ -182,10 +181,10 @@ func TestServiceListServiceStatus(t *testing.T) {
}
return tc.cluster.services, nil
},
taskListFunc: func(context.Context, types.TaskListOptions) ([]swarm.Task, error) {
taskListFunc: func(context.Context, swarm.TaskListOptions) ([]swarm.Task, error) {
return tc.cluster.tasks, nil
},
nodeListFunc: func(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) {
nodeListFunc: func(ctx context.Context, options swarm.NodeListOptions) ([]swarm.Node, error) {
return tc.cluster.nodes, nil
},
})

View File

@ -15,7 +15,6 @@ import (
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/idresolver"
"github.com/docker/cli/internal/logdetails"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
@ -91,7 +90,7 @@ func runLogs(ctx context.Context, dockerCli command.Cli, opts *logsOptions) erro
logfunc func(context.Context, string, container.LogsOptions) (io.ReadCloser, error)
)
service, _, err := apiClient.ServiceInspectWithRaw(ctx, opts.target, types.ServiceInspectOptions{})
service, _, err := apiClient.ServiceInspectWithRaw(ctx, opts.target, swarm.ServiceInspectOptions{})
if err != nil {
// if it's any error other than service not found, it's Real
if !cerrdefs.IsNotFound(err) {

View File

@ -11,7 +11,6 @@ import (
"strings"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
@ -89,7 +88,7 @@ func ServiceProgress(ctx context.Context, apiClient client.APIClient, serviceID
)
for {
service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID, swarm.ServiceInspectOptions{})
if err != nil {
return err
}
@ -143,7 +142,7 @@ func ServiceProgress(ctx context.Context, apiClient client.APIClient, serviceID
return nil
}
tasks, err := apiClient.TaskList(ctx, types.TaskListOptions{Filters: filters.NewArgs(
tasks, err := apiClient.TaskList(ctx, swarm.TaskListOptions{Filters: filters.NewArgs(
filters.KeyValuePair{Key: "service", Value: service.ID},
filters.KeyValuePair{Key: "_up-to-date", Value: "true"},
)})
@ -217,7 +216,7 @@ func ServiceProgress(ctx context.Context, apiClient client.APIClient, serviceID
//
// TODO(thaJeztah): this should really be a filter on [apiClient.NodeList] instead of being filtered on the client side.
func getActiveNodes(ctx context.Context, apiClient client.NodeAPIClient) (map[string]struct{}, error) {
nodes, err := apiClient.NodeList(ctx, types.NodeListOptions{})
nodes, err := apiClient.NodeList(ctx, swarm.NodeListOptions{})
if err != nil {
return nil, err
}

View File

@ -11,8 +11,8 @@ import (
"github.com/docker/cli/cli/command/node"
"github.com/docker/cli/cli/command/task"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -68,7 +68,7 @@ func runPS(ctx context.Context, dockerCli command.Cli, options psOptions) error
return err
}
tasks, err := apiClient.TaskList(ctx, types.TaskListOptions{Filters: filter})
tasks, err := apiClient.TaskList(ctx, swarm.TaskListOptions{Filters: filter})
if err != nil {
return err
}
@ -98,11 +98,11 @@ func createFilter(ctx context.Context, apiClient client.APIClient, options psOpt
serviceIDFilter.Add("id", service)
serviceNameFilter.Add("name", service)
}
serviceByIDList, err := apiClient.ServiceList(ctx, types.ServiceListOptions{Filters: serviceIDFilter})
serviceByIDList, err := apiClient.ServiceList(ctx, swarm.ServiceListOptions{Filters: serviceIDFilter})
if err != nil {
return filter, nil, err
}
serviceByNameList, err := apiClient.ServiceList(ctx, types.ServiceListOptions{Filters: serviceNameFilter})
serviceByNameList, err := apiClient.ServiceList(ctx, swarm.ServiceListOptions{Filters: serviceNameFilter})
if err != nil {
return filter, nil, err
}

View File

@ -6,7 +6,6 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/system"
@ -17,7 +16,7 @@ import (
func TestCreateFilter(t *testing.T) {
client := &fakeClient{
serviceListFunc: func(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(ctx context.Context, options swarm.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{
{ID: "idmatch"},
{ID: "idprefixmatch"},
@ -49,7 +48,7 @@ func TestCreateFilter(t *testing.T) {
func TestCreateFilterWithAmbiguousIDPrefixError(t *testing.T) {
client := &fakeClient{
serviceListFunc: func(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(ctx context.Context, options swarm.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{
{ID: "aaaone"},
{ID: "aaatwo"},
@ -76,7 +75,7 @@ func TestCreateFilterNoneFound(t *testing.T) {
func TestRunPSWarnsOnNotFound(t *testing.T) {
client := &fakeClient{
serviceListFunc: func(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(ctx context.Context, options swarm.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{
{ID: "foo"},
}, nil
@ -97,10 +96,10 @@ func TestRunPSWarnsOnNotFound(t *testing.T) {
func TestRunPSQuiet(t *testing.T) {
client := &fakeClient{
serviceListFunc: func(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(ctx context.Context, options swarm.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{{ID: "foo"}}, nil
},
taskListFunc: func(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error) {
taskListFunc: func(ctx context.Context, options swarm.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{{ID: "sxabyp0obqokwekpun4rjo0b3"}}, nil
},
}

View File

@ -7,7 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/versions"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
@ -43,12 +43,12 @@ func newRollbackCommand(dockerCli command.Cli) *cobra.Command {
func runRollback(ctx context.Context, dockerCLI command.Cli, options *serviceOptions, serviceID string) error {
apiClient := dockerCLI.Client()
service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID, swarm.ServiceInspectOptions{})
if err != nil {
return err
}
response, err := apiClient.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, types.ServiceUpdateOptions{
response, err := apiClient.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, swarm.ServiceUpdateOptions{
Rollback: "previous", // TODO(thaJeztah): this should have a const defined
})
if err != nil {

View File

@ -8,7 +8,6 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@ -18,7 +17,7 @@ func TestRollback(t *testing.T) {
testCases := []struct {
name string
args []string
serviceUpdateFunc func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error)
serviceUpdateFunc func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options swarm.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error)
expectedDockerCliErr string
}{
{
@ -28,7 +27,7 @@ func TestRollback(t *testing.T) {
{
name: "rollback-service-with-warnings",
args: []string{"service-id"},
serviceUpdateFunc: func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error) {
serviceUpdateFunc: func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options swarm.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error) {
response := swarm.ServiceUpdateResponse{}
response.Warnings = []string{
@ -59,8 +58,8 @@ func TestRollbackWithErrors(t *testing.T) {
testCases := []struct {
name string
args []string
serviceInspectWithRawFunc func(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error)
serviceUpdateFunc func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error)
serviceInspectWithRawFunc func(ctx context.Context, serviceID string, options swarm.ServiceInspectOptions) (swarm.Service, []byte, error)
serviceUpdateFunc func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options swarm.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error)
expectedError string
}{
{
@ -75,7 +74,7 @@ func TestRollbackWithErrors(t *testing.T) {
{
name: "service-does-not-exists",
args: []string{"service-id"},
serviceInspectWithRawFunc: func(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) {
serviceInspectWithRawFunc: func(ctx context.Context, serviceID string, options swarm.ServiceInspectOptions) (swarm.Service, []byte, error) {
return swarm.Service{}, []byte{}, fmt.Errorf("no such services: %s", serviceID)
},
expectedError: "no such services: service-id",
@ -83,7 +82,7 @@ func TestRollbackWithErrors(t *testing.T) {
{
name: "service-update-failed",
args: []string{"service-id"},
serviceUpdateFunc: func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error) {
serviceUpdateFunc: func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options swarm.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error) {
return swarm.ServiceUpdateResponse{}, fmt.Errorf("no such services: %s", serviceID)
},
expectedError: "no such services: service-id",

View File

@ -9,7 +9,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/swarm"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/client"
"github.com/spf13/cobra"
@ -94,7 +94,7 @@ func runScale(ctx context.Context, dockerCLI command.Cli, options *scaleOptions,
}
func runServiceScale(ctx context.Context, apiClient client.ServiceAPIClient, serviceID string, scale uint64) (warnings []string, _ error) {
service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID, swarm.ServiceInspectOptions{})
if err != nil {
return nil, err
}
@ -109,7 +109,7 @@ func runServiceScale(ctx context.Context, apiClient client.ServiceAPIClient, ser
return nil, errors.New("scale can only be used with replicated or replicated-job mode")
}
response, err := apiClient.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, types.ServiceUpdateOptions{})
response, err := apiClient.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, swarm.ServiceUpdateOptions{})
if err != nil {
return nil, err
}

View File

@ -12,7 +12,6 @@ import (
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts"
"github.com/docker/cli/opts/swarmopts"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
mounttypes "github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/network"
@ -156,7 +155,7 @@ func newListOptsVarWithValidator(validator opts.ValidatorFctType) *opts.ListOpts
func runUpdate(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet, options *serviceOptions, serviceID string) error {
apiClient := dockerCLI.Client()
service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID, swarm.ServiceInspectOptions{})
if err != nil {
return err
}
@ -201,7 +200,7 @@ func runUpdate(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet,
}
}
updateOpts := types.ServiceUpdateOptions{}
updateOpts := swarm.ServiceUpdateOptions{}
if serverSideRollback {
updateOpts.Rollback = "previous"
}
@ -255,9 +254,9 @@ func runUpdate(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet,
}
updateOpts.EncodedRegistryAuth = encodedAuth
case clientSideRollback:
updateOpts.RegistryAuthFrom = types.RegistryAuthFromPreviousSpec
updateOpts.RegistryAuthFrom = swarm.RegistryAuthFromPreviousSpec
default:
updateOpts.RegistryAuthFrom = types.RegistryAuthFromSpec
updateOpts.RegistryAuthFrom = swarm.RegistryAuthFromSpec
}
response, err := apiClient.ServiceUpdate(ctx, service.ID, service.Version, *spec, updateOpts)

View File

@ -28,15 +28,15 @@ type fakeClient struct {
removedSecrets []string
removedConfigs []string
serviceListFunc func(options types.ServiceListOptions) ([]swarm.Service, error)
serviceListFunc func(options swarm.ServiceListOptions) ([]swarm.Service, error)
networkListFunc func(options network.ListOptions) ([]network.Summary, error)
secretListFunc func(options swarm.SecretListOptions) ([]swarm.Secret, error)
configListFunc func(options swarm.ConfigListOptions) ([]swarm.Config, error)
nodeListFunc func(options types.NodeListOptions) ([]swarm.Node, error)
taskListFunc func(options types.TaskListOptions) ([]swarm.Task, error)
nodeListFunc func(options swarm.NodeListOptions) ([]swarm.Node, error)
taskListFunc func(options swarm.TaskListOptions) ([]swarm.Task, error)
nodeInspectWithRaw func(ref string) (swarm.Node, []byte, error)
serviceUpdateFunc func(serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error)
serviceUpdateFunc func(serviceID string, version swarm.Version, service swarm.ServiceSpec, options swarm.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error)
serviceRemoveFunc func(serviceID string) error
networkRemoveFunc func(networkID string) error
@ -55,7 +55,7 @@ func (cli *fakeClient) ClientVersion() string {
return cli.version
}
func (cli *fakeClient) ServiceList(_ context.Context, options types.ServiceListOptions) ([]swarm.Service, error) {
func (cli *fakeClient) ServiceList(_ context.Context, options swarm.ServiceListOptions) ([]swarm.Service, error) {
if cli.serviceListFunc != nil {
return cli.serviceListFunc(options)
}
@ -115,14 +115,14 @@ func (cli *fakeClient) ConfigList(_ context.Context, options swarm.ConfigListOpt
return configsList, nil
}
func (cli *fakeClient) TaskList(_ context.Context, options types.TaskListOptions) ([]swarm.Task, error) {
func (cli *fakeClient) TaskList(_ context.Context, options swarm.TaskListOptions) ([]swarm.Task, error) {
if cli.taskListFunc != nil {
return cli.taskListFunc(options)
}
return []swarm.Task{}, nil
}
func (cli *fakeClient) NodeList(_ context.Context, options types.NodeListOptions) ([]swarm.Node, error) {
func (cli *fakeClient) NodeList(_ context.Context, options swarm.NodeListOptions) ([]swarm.Node, error) {
if cli.nodeListFunc != nil {
return cli.nodeListFunc(options)
}
@ -136,7 +136,7 @@ func (cli *fakeClient) NodeInspectWithRaw(_ context.Context, ref string) (swarm.
return swarm.Node{}, nil, nil
}
func (cli *fakeClient) ServiceUpdate(_ context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error) {
func (cli *fakeClient) ServiceUpdate(_ context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options swarm.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error) {
if cli.serviceUpdateFunc != nil {
return cli.serviceUpdateFunc(serviceID, version, service, options)
}
@ -180,7 +180,7 @@ func (cli *fakeClient) ConfigRemove(_ context.Context, configID string) error {
return nil
}
func (*fakeClient) ServiceInspectWithRaw(_ context.Context, serviceID string, _ types.ServiceInspectOptions) (swarm.Service, []byte, error) {
func (*fakeClient) ServiceInspectWithRaw(_ context.Context, serviceID string, _ swarm.ServiceInspectOptions) (swarm.Service, []byte, error) {
return swarm.Service{
ID: serviceID,
Spec: swarm.ServiceSpec{

View File

@ -7,7 +7,6 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/builders"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"gotest.tools/v3/assert"
"gotest.tools/v3/golden"
@ -17,7 +16,7 @@ func TestListErrors(t *testing.T) {
testCases := []struct {
args []string
flags map[string]string
serviceListFunc func(options types.ServiceListOptions) ([]swarm.Service, error)
serviceListFunc func(options swarm.ServiceListOptions) ([]swarm.Service, error)
expectedError string
}{
{
@ -33,14 +32,14 @@ func TestListErrors(t *testing.T) {
},
{
args: []string{},
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(options swarm.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{}, errors.New("error getting services")
},
expectedError: "error getting services",
},
{
args: []string{},
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(options swarm.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{*builders.Service()}, nil
},
expectedError: "cannot get label",
@ -115,7 +114,7 @@ func TestStackList(t *testing.T) {
)
}
cli := test.NewFakeCli(&fakeClient{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(options swarm.ServiceListOptions) ([]swarm.Service, error) {
return services, nil
},
})

View File

@ -9,7 +9,6 @@ import (
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/builders"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@ -19,7 +18,7 @@ import (
func TestStackPsErrors(t *testing.T) {
testCases := []struct {
args []string
taskListFunc func(options types.TaskListOptions) ([]swarm.Task, error)
taskListFunc func(options swarm.TaskListOptions) ([]swarm.Task, error)
expectedError string
}{
{
@ -32,7 +31,7 @@ func TestStackPsErrors(t *testing.T) {
},
{
args: []string{"foo"},
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
taskListFunc: func(options swarm.TaskListOptions) ([]swarm.Task, error) {
return nil, errors.New("error getting tasks")
},
expectedError: "error getting tasks",
@ -55,7 +54,7 @@ func TestStackPsErrors(t *testing.T) {
func TestStackPs(t *testing.T) {
testCases := []struct {
doc string
taskListFunc func(types.TaskListOptions) ([]swarm.Task, error)
taskListFunc func(swarm.TaskListOptions) ([]swarm.Task, error)
nodeInspectWithRaw func(string) (swarm.Node, []byte, error)
config configfile.ConfigFile
args []string
@ -70,7 +69,7 @@ func TestStackPs(t *testing.T) {
},
{
doc: "WithEmptyStack",
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
taskListFunc: func(options swarm.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{}, nil
},
args: []string{"foo"},
@ -78,7 +77,7 @@ func TestStackPs(t *testing.T) {
},
{
doc: "WithQuietOption",
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
taskListFunc: func(options swarm.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{*builders.Task(builders.TaskID("id-foo"))}, nil
},
args: []string{"foo"},
@ -89,7 +88,7 @@ func TestStackPs(t *testing.T) {
},
{
doc: "WithNoTruncOption",
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
taskListFunc: func(options swarm.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{*builders.Task(builders.TaskID("xn4cypcov06f2w8gsbaf2lst3"))}, nil
},
args: []string{"foo"},
@ -101,7 +100,7 @@ func TestStackPs(t *testing.T) {
},
{
doc: "WithNoResolveOption",
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
taskListFunc: func(options swarm.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{*builders.Task(
builders.TaskNodeID("id-node-foo"),
)}, nil
@ -118,7 +117,7 @@ func TestStackPs(t *testing.T) {
},
{
doc: "WithFormat",
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
taskListFunc: func(options swarm.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{*builders.Task(builders.TaskServiceID("service-id-foo"))}, nil
},
args: []string{"foo"},
@ -129,7 +128,7 @@ func TestStackPs(t *testing.T) {
},
{
doc: "WithConfigFormat",
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
taskListFunc: func(options swarm.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{*builders.Task(builders.TaskServiceID("service-id-foo"))}, nil
},
config: configfile.ConfigFile{
@ -140,7 +139,7 @@ func TestStackPs(t *testing.T) {
},
{
doc: "WithoutFormat",
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
taskListFunc: func(options swarm.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{*builders.Task(
builders.TaskID("id-foo"),
builders.TaskServiceID("service-id-foo"),

View File

@ -8,7 +8,6 @@ import (
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/builders"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@ -19,37 +18,37 @@ func TestStackServicesErrors(t *testing.T) {
testCases := []struct {
args []string
flags map[string]string
serviceListFunc func(options types.ServiceListOptions) ([]swarm.Service, error)
nodeListFunc func(options types.NodeListOptions) ([]swarm.Node, error)
taskListFunc func(options types.TaskListOptions) ([]swarm.Task, error)
serviceListFunc func(options swarm.ServiceListOptions) ([]swarm.Service, error)
nodeListFunc func(options swarm.NodeListOptions) ([]swarm.Node, error)
taskListFunc func(options swarm.TaskListOptions) ([]swarm.Task, error)
expectedError string
}{
{
args: []string{"foo"},
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(options swarm.ServiceListOptions) ([]swarm.Service, error) {
return nil, errors.New("error getting services")
},
expectedError: "error getting services",
},
{
args: []string{"foo"},
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(options swarm.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{*builders.Service(builders.GlobalService())}, nil
},
nodeListFunc: func(options types.NodeListOptions) ([]swarm.Node, error) {
nodeListFunc: func(options swarm.NodeListOptions) ([]swarm.Node, error) {
return nil, errors.New("error getting nodes")
},
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
taskListFunc: func(options swarm.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{*builders.Task()}, nil
},
expectedError: "error getting nodes",
},
{
args: []string{"foo"},
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(options swarm.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{*builders.Service(builders.GlobalService())}, nil
},
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
taskListFunc: func(options swarm.TaskListOptions) ([]swarm.Task, error) {
return nil, errors.New("error getting tasks")
},
expectedError: "error getting tasks",
@ -59,7 +58,7 @@ func TestStackServicesErrors(t *testing.T) {
flags: map[string]string{
"format": "{{invalid format}}",
},
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(options swarm.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{*builders.Service()}, nil
},
expectedError: "template parsing error",
@ -96,7 +95,7 @@ func TestRunServicesWithEmptyName(t *testing.T) {
func TestStackServicesEmptyServiceList(t *testing.T) {
fakeCli := test.NewFakeCli(&fakeClient{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(options swarm.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{}, nil
},
})
@ -109,7 +108,7 @@ func TestStackServicesEmptyServiceList(t *testing.T) {
func TestStackServicesWithQuietOption(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(options swarm.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{*builders.Service(builders.ServiceID("id-foo"))}, nil
},
})
@ -122,7 +121,7 @@ func TestStackServicesWithQuietOption(t *testing.T) {
func TestStackServicesWithFormat(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(options swarm.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{
*builders.Service(builders.ServiceName("service-name-foo")),
}, nil
@ -137,7 +136,7 @@ func TestStackServicesWithFormat(t *testing.T) {
func TestStackServicesWithConfigFormat(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(options swarm.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{
*builders.Service(builders.ServiceName("service-name-foo")),
}, nil
@ -154,7 +153,7 @@ func TestStackServicesWithConfigFormat(t *testing.T) {
func TestStackServicesWithoutFormat(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(options swarm.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{*builders.Service(
builders.ServiceName("name-foo"),
builders.ServiceID("id-foo"),

View File

@ -28,15 +28,15 @@ type fakeClient struct {
removedSecrets []string
removedConfigs []string
serviceListFunc func(options types.ServiceListOptions) ([]swarm.Service, error)
serviceListFunc func(options swarm.ServiceListOptions) ([]swarm.Service, error)
networkListFunc func(options network.ListOptions) ([]network.Summary, error)
secretListFunc func(options swarm.SecretListOptions) ([]swarm.Secret, error)
configListFunc func(options swarm.ConfigListOptions) ([]swarm.Config, error)
nodeListFunc func(options types.NodeListOptions) ([]swarm.Node, error)
taskListFunc func(options types.TaskListOptions) ([]swarm.Task, error)
nodeListFunc func(options swarm.NodeListOptions) ([]swarm.Node, error)
taskListFunc func(options swarm.TaskListOptions) ([]swarm.Task, error)
nodeInspectWithRaw func(ref string) (swarm.Node, []byte, error)
serviceUpdateFunc func(serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error)
serviceUpdateFunc func(serviceID string, version swarm.Version, service swarm.ServiceSpec, options swarm.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error)
serviceRemoveFunc func(serviceID string) error
networkRemoveFunc func(networkID string) error
@ -55,7 +55,7 @@ func (cli *fakeClient) ClientVersion() string {
return cli.version
}
func (cli *fakeClient) ServiceList(_ context.Context, options types.ServiceListOptions) ([]swarm.Service, error) {
func (cli *fakeClient) ServiceList(_ context.Context, options swarm.ServiceListOptions) ([]swarm.Service, error) {
if cli.serviceListFunc != nil {
return cli.serviceListFunc(options)
}
@ -115,14 +115,14 @@ func (cli *fakeClient) ConfigList(_ context.Context, options swarm.ConfigListOpt
return configsList, nil
}
func (cli *fakeClient) TaskList(_ context.Context, options types.TaskListOptions) ([]swarm.Task, error) {
func (cli *fakeClient) TaskList(_ context.Context, options swarm.TaskListOptions) ([]swarm.Task, error) {
if cli.taskListFunc != nil {
return cli.taskListFunc(options)
}
return []swarm.Task{}, nil
}
func (cli *fakeClient) NodeList(_ context.Context, options types.NodeListOptions) ([]swarm.Node, error) {
func (cli *fakeClient) NodeList(_ context.Context, options swarm.NodeListOptions) ([]swarm.Node, error) {
if cli.nodeListFunc != nil {
return cli.nodeListFunc(options)
}
@ -136,7 +136,7 @@ func (cli *fakeClient) NodeInspectWithRaw(_ context.Context, ref string) (swarm.
return swarm.Node{}, nil, nil
}
func (cli *fakeClient) ServiceUpdate(_ context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error) {
func (cli *fakeClient) ServiceUpdate(_ context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options swarm.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error) {
if cli.serviceUpdateFunc != nil {
return cli.serviceUpdateFunc(serviceID, version, service, options)
}

View File

@ -5,7 +5,6 @@ import (
"github.com/docker/cli/cli/compose/convert"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/swarm"
@ -31,7 +30,7 @@ func getAllStacksFilter() filters.Args {
}
func getStackServices(ctx context.Context, apiclient client.APIClient, namespace string) ([]swarm.Service, error) {
return apiclient.ServiceList(ctx, types.ServiceListOptions{Filters: getStackFilter(namespace)})
return apiclient.ServiceList(ctx, swarm.ServiceListOptions{Filters: getStackFilter(namespace)})
}
func getStackNetworks(ctx context.Context, apiclient client.APIClient, namespace string) ([]network.Summary, error) {
@ -47,5 +46,5 @@ func getStackConfigs(ctx context.Context, apiclient client.APIClient, namespace
}
func getStackTasks(ctx context.Context, apiclient client.APIClient, namespace string) ([]swarm.Task, error) {
return apiclient.TaskList(ctx, types.TaskListOptions{Filters: getStackFilter(namespace)})
return apiclient.TaskList(ctx, swarm.TaskListOptions{Filters: getStackFilter(namespace)})
}

View File

@ -11,7 +11,6 @@ import (
"github.com/docker/cli/cli/command/stack/options"
"github.com/docker/cli/cli/compose/convert"
composetypes "github.com/docker/cli/cli/compose/types"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/swarm"
@ -221,7 +220,7 @@ func deployServices(ctx context.Context, dockerCLI command.Cli, services map[str
if service, exists := existingServiceMap[name]; exists {
_, _ = fmt.Fprintf(out, "Updating service %s (id: %s)\n", name, service.ID)
updateOpts := types.ServiceUpdateOptions{EncodedRegistryAuth: encodedAuth}
updateOpts := swarm.ServiceUpdateOptions{EncodedRegistryAuth: encodedAuth}
switch resolveImage {
case ResolveImageAlways:
@ -266,7 +265,7 @@ func deployServices(ctx context.Context, dockerCLI command.Cli, services map[str
} else {
_, _ = fmt.Fprintln(out, "Creating service", name)
createOpts := types.ServiceCreateOptions{EncodedRegistryAuth: encodedAuth}
createOpts := swarm.ServiceCreateOptions{EncodedRegistryAuth: encodedAuth}
// query registry if flag disabling it was not set
if resolveImage == ResolveImageAlways || resolveImage == ResolveImageChanged {

View File

@ -6,7 +6,6 @@ import (
"github.com/docker/cli/cli/compose/convert"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@ -33,12 +32,12 @@ func TestServiceUpdateResolveImageChanged(t *testing.T) {
namespace := convert.NewNamespace("mystack")
var (
receivedOptions types.ServiceUpdateOptions
receivedOptions swarm.ServiceUpdateOptions
receivedService swarm.ServiceSpec
)
client := test.NewFakeCli(&fakeClient{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
serviceListFunc: func(options swarm.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{
{
Spec: swarm.ServiceSpec{
@ -56,7 +55,7 @@ func TestServiceUpdateResolveImageChanged(t *testing.T) {
},
}, nil
},
serviceUpdateFunc: func(serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error) {
serviceUpdateFunc: func(serviceID string, version swarm.Version, service swarm.ServiceSpec, options swarm.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error) {
receivedOptions = options
receivedService = service
return swarm.ServiceUpdateResponse{}, nil
@ -105,7 +104,7 @@ func TestServiceUpdateResolveImageChanged(t *testing.T) {
assert.Check(t, is.Equal(receivedService.TaskTemplate.ForceUpdate, tc.expectedForceUpdate))
receivedService = swarm.ServiceSpec{}
receivedOptions = types.ServiceUpdateOptions{}
receivedOptions = swarm.ServiceUpdateOptions{}
})
}
}

View File

@ -5,7 +5,7 @@ import (
"github.com/docker/cli/cli/command/stack/formatter"
"github.com/docker/cli/cli/compose/convert"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
"github.com/pkg/errors"
)
@ -14,7 +14,7 @@ import (
func GetStacks(ctx context.Context, apiClient client.ServiceAPIClient) ([]*formatter.Stack, error) {
services, err := apiClient.ServiceList(
ctx,
types.ServiceListOptions{Filters: getAllStacksFilter()})
swarm.ServiceListOptions{Filters: getAllStacksFilter()})
if err != nil {
return nil, err
}

View File

@ -8,7 +8,7 @@ import (
"github.com/docker/cli/cli/command/idresolver"
"github.com/docker/cli/cli/command/stack/options"
"github.com/docker/cli/cli/command/task"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
)
// RunPS is the swarm implementation of docker stack ps
@ -16,7 +16,7 @@ func RunPS(ctx context.Context, dockerCli command.Cli, opts options.PS) error {
filter := getStackFilterFromOpt(opts.Namespace, opts.Filter)
client := dockerCli.Client()
tasks, err := client.TaskList(ctx, types.TaskListOptions{Filters: filter})
tasks, err := client.TaskList(ctx, swarm.TaskListOptions{Filters: filter})
if err != nil {
return err
}

View File

@ -6,7 +6,6 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/service"
"github.com/docker/cli/cli/command/stack/options"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
)
@ -17,7 +16,7 @@ func GetServices(ctx context.Context, dockerCli command.Cli, opts options.Servic
client = dockerCli.Client()
)
listOpts := types.ServiceListOptions{
listOpts := swarm.ServiceListOptions{
Filters: getStackFilterFromOpt(opts.Namespace, opts.Filter),
// When not running "quiet", also get service status (number of running
// and desired tasks). Note that this is only supported on API v1.41 and

View File

@ -96,7 +96,7 @@ func runCA(ctx context.Context, dockerCli command.Cli, flags *pflag.FlagSet, opt
func updateSwarmSpec(spec *swarm.Spec, flags *pflag.FlagSet, opts caOptions) {
caCert := opts.rootCACert.Contents()
caKey := opts.rootCAKey.Contents()
opts.mergeSwarmSpecCAFlags(spec, flags, caCert)
opts.mergeSwarmSpecCAFlags(spec, flags, &caCert)
spec.CAConfig.SigningCACert = caCert
spec.CAConfig.SigningCAKey = caKey

View File

@ -69,7 +69,7 @@ func writeFile(data string) (string, error) {
if err != nil {
return "", err
}
_, err = tmpfile.Write([]byte(data))
_, err = tmpfile.WriteString(data)
if err != nil {
return "", err
}

View File

@ -3,7 +3,6 @@ package swarm
import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/system"
"github.com/docker/docker/client"
@ -12,10 +11,10 @@ import (
type fakeClient struct {
client.Client
infoFunc func() (system.Info, error)
swarmInitFunc func() (string, error)
swarmInitFunc func(req swarm.InitRequest) (string, error)
swarmInspectFunc func() (swarm.Swarm, error)
nodeInspectFunc func() (swarm.Node, []byte, error)
swarmGetUnlockKeyFunc func() (types.SwarmUnlockKeyResponse, error)
swarmGetUnlockKeyFunc func() (swarm.UnlockKeyResponse, error)
swarmJoinFunc func() error
swarmLeaveFunc func() error
swarmUpdateFunc func(swarm swarm.Spec, flags swarm.UpdateFlags) error
@ -36,9 +35,9 @@ func (cli *fakeClient) NodeInspectWithRaw(context.Context, string) (swarm.Node,
return swarm.Node{}, []byte{}, nil
}
func (cli *fakeClient) SwarmInit(context.Context, swarm.InitRequest) (string, error) {
func (cli *fakeClient) SwarmInit(_ context.Context, req swarm.InitRequest) (string, error) {
if cli.swarmInitFunc != nil {
return cli.swarmInitFunc()
return cli.swarmInitFunc(req)
}
return "", nil
}
@ -50,11 +49,11 @@ func (cli *fakeClient) SwarmInspect(context.Context) (swarm.Swarm, error) {
return swarm.Swarm{}, nil
}
func (cli *fakeClient) SwarmGetUnlockKey(context.Context) (types.SwarmUnlockKeyResponse, error) {
func (cli *fakeClient) SwarmGetUnlockKey(context.Context) (swarm.UnlockKeyResponse, error) {
if cli.swarmGetUnlockKeyFunc != nil {
return cli.swarmGetUnlockKeyFunc()
}
return types.SwarmUnlockKeyResponse{}, nil
return swarm.UnlockKeyResponse{}, nil
}
func (cli *fakeClient) SwarmJoin(context.Context, swarm.JoinRequest) error {

View File

@ -4,12 +4,14 @@ import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/golden"
)
@ -17,22 +19,22 @@ func TestSwarmInitErrorOnAPIFailure(t *testing.T) {
testCases := []struct {
name string
flags map[string]string
swarmInitFunc func() (string, error)
swarmInitFunc func(swarm.InitRequest) (string, error)
swarmInspectFunc func() (swarm.Swarm, error)
swarmGetUnlockKeyFunc func() (types.SwarmUnlockKeyResponse, error)
swarmGetUnlockKeyFunc func() (swarm.UnlockKeyResponse, error)
nodeInspectFunc func() (swarm.Node, []byte, error)
expectedError string
}{
{
name: "init-failed",
swarmInitFunc: func() (string, error) {
swarmInitFunc: func(swarm.InitRequest) (string, error) {
return "", errors.New("error initializing the swarm")
},
expectedError: "error initializing the swarm",
},
{
name: "init-failed-with-ip-choice",
swarmInitFunc: func() (string, error) {
swarmInitFunc: func(swarm.InitRequest) (string, error) {
return "", errors.New("could not choose an IP address to advertise")
},
expectedError: "could not choose an IP address to advertise - specify one with --advertise-addr",
@ -56,8 +58,8 @@ func TestSwarmInitErrorOnAPIFailure(t *testing.T) {
flags: map[string]string{
flagAutolock: "true",
},
swarmGetUnlockKeyFunc: func() (types.SwarmUnlockKeyResponse, error) {
return types.SwarmUnlockKeyResponse{}, errors.New("error getting swarm unlock key")
swarmGetUnlockKeyFunc: func() (swarm.UnlockKeyResponse, error) {
return swarm.UnlockKeyResponse{}, errors.New("error getting swarm unlock key")
},
expectedError: "could not fetch unlock key: error getting swarm unlock key",
},
@ -86,14 +88,14 @@ func TestSwarmInit(t *testing.T) {
testCases := []struct {
name string
flags map[string]string
swarmInitFunc func() (string, error)
swarmInitFunc func(req swarm.InitRequest) (string, error)
swarmInspectFunc func() (swarm.Swarm, error)
swarmGetUnlockKeyFunc func() (types.SwarmUnlockKeyResponse, error)
swarmGetUnlockKeyFunc func() (swarm.UnlockKeyResponse, error)
nodeInspectFunc func() (swarm.Node, []byte, error)
}{
{
name: "init",
swarmInitFunc: func() (string, error) {
swarmInitFunc: func(swarm.InitRequest) (string, error) {
return "nodeID", nil
},
},
@ -102,11 +104,11 @@ func TestSwarmInit(t *testing.T) {
flags: map[string]string{
flagAutolock: "true",
},
swarmInitFunc: func() (string, error) {
swarmInitFunc: func(swarm.InitRequest) (string, error) {
return "nodeID", nil
},
swarmGetUnlockKeyFunc: func() (types.SwarmUnlockKeyResponse, error) {
return types.SwarmUnlockKeyResponse{
swarmGetUnlockKeyFunc: func() (swarm.UnlockKeyResponse, error) {
return swarm.UnlockKeyResponse{
UnlockKey: "unlock-key",
}, nil
},
@ -132,3 +134,28 @@ func TestSwarmInit(t *testing.T) {
})
}
}
func TestSwarmInitWithExternalCA(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
swarmInitFunc: func(req swarm.InitRequest) (string, error) {
if assert.Check(t, is.Len(req.Spec.CAConfig.ExternalCAs, 1)) {
assert.Equal(t, req.Spec.CAConfig.ExternalCAs[0].CACert, cert)
assert.Equal(t, req.Spec.CAConfig.ExternalCAs[0].Protocol, swarm.ExternalCAProtocolCFSSL)
assert.Equal(t, req.Spec.CAConfig.ExternalCAs[0].URL, "https://example.com")
}
return "nodeID", nil
},
})
tempDir := t.TempDir()
certFile := filepath.Join(tempDir, "cert.pem")
err := os.WriteFile(certFile, []byte(cert), 0o644)
assert.NilError(t, err)
cmd := newInitCommand(cli)
cmd.SetArgs([]string{})
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
assert.NilError(t, cmd.Flags().Set(flagExternalCA, "protocol=cfssl,url=https://example.com,cacert="+certFile))
assert.NilError(t, cmd.Execute())
}

View File

@ -231,7 +231,7 @@ func addSwarmFlags(flags *pflag.FlagSet, options *swarmOptions) {
addSwarmCAFlags(flags, &options.swarmCAOptions)
}
func (o *swarmOptions) mergeSwarmSpec(spec *swarm.Spec, flags *pflag.FlagSet, caCert string) {
func (o *swarmOptions) mergeSwarmSpec(spec *swarm.Spec, flags *pflag.FlagSet, caCert *string) {
if flags.Changed(flagTaskHistoryLimit) {
spec.Orchestration.TaskHistoryRetentionLimit = &o.taskHistoryLimit
}
@ -255,20 +255,24 @@ type swarmCAOptions struct {
externalCA ExternalCAOption
}
func (o *swarmCAOptions) mergeSwarmSpecCAFlags(spec *swarm.Spec, flags *pflag.FlagSet, caCert string) {
func (o *swarmCAOptions) mergeSwarmSpecCAFlags(spec *swarm.Spec, flags *pflag.FlagSet, caCert *string) {
if flags.Changed(flagCertExpiry) {
spec.CAConfig.NodeCertExpiry = o.nodeCertExpiry
}
if flags.Changed(flagExternalCA) {
spec.CAConfig.ExternalCAs = o.externalCA.Value()
for _, ca := range spec.CAConfig.ExternalCAs {
ca.CACert = caCert
if caCert != nil {
for _, ca := range spec.CAConfig.ExternalCAs {
if ca.CACert == "" {
ca.CACert = *caCert
}
}
}
}
}
func (o *swarmOptions) ToSpec(flags *pflag.FlagSet) swarm.Spec {
var spec swarm.Spec
o.mergeSwarmSpec(&spec, flags, "")
o.mergeSwarmSpec(&spec, flags, nil)
return spec
}

View File

@ -8,7 +8,6 @@ import (
"os/signal"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/progress"
@ -52,7 +51,7 @@ func RootRotationProgress(ctx context.Context, dclient client.APIClient, progres
return nil
}
nodes, err := dclient.NodeList(ctx, types.NodeListOptions{})
nodes, err := dclient.NodeList(ctx, swarm.NodeListOptions{})
if err != nil {
return err
}

View File

@ -50,7 +50,7 @@ func runUnlock(ctx context.Context, dockerCli command.Cli) error {
return errors.New("Error: This node is not part of a swarm")
case swarm.LocalNodeStateLocked:
break
default:
case swarm.LocalNodeStatePending, swarm.LocalNodeStateActive, swarm.LocalNodeStateError:
return errors.New("Error: swarm is not locked")
}
@ -58,11 +58,10 @@ func runUnlock(ctx context.Context, dockerCli command.Cli) error {
if err != nil {
return err
}
req := swarm.UnlockRequest{
UnlockKey: key,
}
return client.SwarmUnlock(ctx, req)
return client.SwarmUnlock(ctx, swarm.UnlockRequest{
UnlockKey: key,
})
}
func readKey(in *streams.In, prompt string) (string, error) {

View File

@ -8,7 +8,6 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/builders"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"gotest.tools/v3/assert"
"gotest.tools/v3/golden"
@ -21,7 +20,7 @@ func TestSwarmUnlockKeyErrors(t *testing.T) {
flags map[string]string
swarmInspectFunc func() (swarm.Swarm, error)
swarmUpdateFunc func(swarm swarm.Spec, flags swarm.UpdateFlags) error
swarmGetUnlockKeyFunc func() (types.SwarmUnlockKeyResponse, error)
swarmGetUnlockKeyFunc func() (swarm.UnlockKeyResponse, error)
expectedError string
}{
{
@ -64,17 +63,15 @@ func TestSwarmUnlockKeyErrors(t *testing.T) {
},
{
name: "swarm-get-unlock-key-failed",
swarmGetUnlockKeyFunc: func() (types.SwarmUnlockKeyResponse, error) {
return types.SwarmUnlockKeyResponse{}, errors.New("error getting unlock key")
swarmGetUnlockKeyFunc: func() (swarm.UnlockKeyResponse, error) {
return swarm.UnlockKeyResponse{}, errors.New("error getting unlock key")
},
expectedError: "error getting unlock key",
},
{
name: "swarm-no-unlock-key-failed",
swarmGetUnlockKeyFunc: func() (types.SwarmUnlockKeyResponse, error) {
return types.SwarmUnlockKeyResponse{
UnlockKey: "",
}, nil
swarmGetUnlockKeyFunc: func() (swarm.UnlockKeyResponse, error) {
return swarm.UnlockKeyResponse{}, nil
},
expectedError: "no unlock key is set",
},
@ -108,12 +105,12 @@ func TestSwarmUnlockKey(t *testing.T) {
flags map[string]string
swarmInspectFunc func() (swarm.Swarm, error)
swarmUpdateFunc func(swarm swarm.Spec, flags swarm.UpdateFlags) error
swarmGetUnlockKeyFunc func() (types.SwarmUnlockKeyResponse, error)
swarmGetUnlockKeyFunc func() (swarm.UnlockKeyResponse, error)
}{
{
name: "unlock-key",
swarmGetUnlockKeyFunc: func() (types.SwarmUnlockKeyResponse, error) {
return types.SwarmUnlockKeyResponse{
swarmGetUnlockKeyFunc: func() (swarm.UnlockKeyResponse, error) {
return swarm.UnlockKeyResponse{
UnlockKey: "unlock-key",
}, nil
},
@ -123,8 +120,8 @@ func TestSwarmUnlockKey(t *testing.T) {
flags: map[string]string{
flagQuiet: "true",
},
swarmGetUnlockKeyFunc: func() (types.SwarmUnlockKeyResponse, error) {
return types.SwarmUnlockKeyResponse{
swarmGetUnlockKeyFunc: func() (swarm.UnlockKeyResponse, error) {
return swarm.UnlockKeyResponse{
UnlockKey: "unlock-key",
}, nil
},
@ -137,8 +134,8 @@ func TestSwarmUnlockKey(t *testing.T) {
swarmInspectFunc: func() (swarm.Swarm, error) {
return *builders.Swarm(builders.Autolock()), nil
},
swarmGetUnlockKeyFunc: func() (types.SwarmUnlockKeyResponse, error) {
return types.SwarmUnlockKeyResponse{
swarmGetUnlockKeyFunc: func() (swarm.UnlockKeyResponse, error) {
return swarm.UnlockKeyResponse{
UnlockKey: "unlock-key",
}, nil
},
@ -152,8 +149,8 @@ func TestSwarmUnlockKey(t *testing.T) {
swarmInspectFunc: func() (swarm.Swarm, error) {
return *builders.Swarm(builders.Autolock()), nil
},
swarmGetUnlockKeyFunc: func() (types.SwarmUnlockKeyResponse, error) {
return types.SwarmUnlockKeyResponse{
swarmGetUnlockKeyFunc: func() (swarm.UnlockKeyResponse, error) {
return swarm.UnlockKeyResponse{
UnlockKey: "unlock-key",
}, nil
},

View File

@ -53,7 +53,7 @@ func runUpdate(ctx context.Context, dockerCli command.Cli, flags *pflag.FlagSet,
prevAutoLock := swarmInspect.Spec.EncryptionConfig.AutoLockManagers
opts.mergeSwarmSpec(&swarmInspect.Spec, flags, swarmInspect.ClusterInfo.TLSInfo.TrustRoot)
opts.mergeSwarmSpec(&swarmInspect.Spec, flags, &swarmInspect.ClusterInfo.TLSInfo.TrustRoot)
curAutoLock := swarmInspect.Spec.EncryptionConfig.AutoLockManagers

View File

@ -9,7 +9,6 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/builders"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"gotest.tools/v3/assert"
"gotest.tools/v3/golden"
@ -22,7 +21,7 @@ func TestSwarmUpdateErrors(t *testing.T) {
flags map[string]string
swarmInspectFunc func() (swarm.Swarm, error)
swarmUpdateFunc func(swarm swarm.Spec, flags swarm.UpdateFlags) error
swarmGetUnlockKeyFunc func() (types.SwarmUnlockKeyResponse, error)
swarmGetUnlockKeyFunc func() (swarm.UnlockKeyResponse, error)
expectedError string
}{
{
@ -58,8 +57,8 @@ func TestSwarmUpdateErrors(t *testing.T) {
swarmInspectFunc: func() (swarm.Swarm, error) {
return *builders.Swarm(), nil
},
swarmGetUnlockKeyFunc: func() (types.SwarmUnlockKeyResponse, error) {
return types.SwarmUnlockKeyResponse{}, errors.New("error getting unlock key")
swarmGetUnlockKeyFunc: func() (swarm.UnlockKeyResponse, error) {
return swarm.UnlockKeyResponse{}, errors.New("error getting unlock key")
},
expectedError: "error getting unlock key",
},
@ -97,7 +96,7 @@ func TestSwarmUpdate(t *testing.T) {
flags map[string]string
swarmInspectFunc func() (swarm.Swarm, error)
swarmUpdateFunc func(swarm swarm.Spec, flags swarm.UpdateFlags) error
swarmGetUnlockKeyFunc func() (types.SwarmUnlockKeyResponse, error)
swarmGetUnlockKeyFunc func() (swarm.UnlockKeyResponse, error)
}{
{
name: "noargs",
@ -164,8 +163,8 @@ func TestSwarmUpdate(t *testing.T) {
swarmInspectFunc: func() (swarm.Swarm, error) {
return *builders.Swarm(), nil
},
swarmGetUnlockKeyFunc: func() (types.SwarmUnlockKeyResponse, error) {
return types.SwarmUnlockKeyResponse{
swarmGetUnlockKeyFunc: func() (swarm.UnlockKeyResponse, error) {
return swarm.UnlockKeyResponse{
UnlockKey: "unlock-key",
}, nil
},

View File

@ -26,7 +26,7 @@ type fakeClient struct {
infoFunc func(ctx context.Context) (system.Info, error)
networkListFunc func(ctx context.Context, options network.ListOptions) ([]network.Summary, error)
networkPruneFunc func(ctx context.Context, pruneFilter filters.Args) (network.PruneReport, error)
nodeListFunc func(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error)
nodeListFunc func(ctx context.Context, options swarm.NodeListOptions) ([]swarm.Node, error)
serverVersion func(ctx context.Context) (types.Version, error)
volumeListFunc func(ctx context.Context, options volume.ListOptions) (volume.ListResponse, error)
}
@ -81,7 +81,7 @@ func (cli *fakeClient) NetworksPrune(ctx context.Context, pruneFilter filters.Ar
return network.PruneReport{}, nil
}
func (cli *fakeClient) NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) {
func (cli *fakeClient) NodeList(ctx context.Context, options swarm.NodeListOptions) ([]swarm.Node, error) {
if cli.nodeListFunc != nil {
return cli.nodeListFunc(ctx, options)
}

View File

@ -4,10 +4,10 @@ import (
"strings"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/volume"
"github.com/spf13/cobra"
)
@ -211,7 +211,7 @@ func networkNames(dockerCLI completion.APIClientProvider, cmd *cobra.Command) []
// nodeNames contacts the API to get a list of node names.
// In case of an error, an empty list is returned.
func nodeNames(dockerCLI completion.APIClientProvider, cmd *cobra.Command) []string {
list, err := dockerCLI.Client().NodeList(cmd.Context(), types.NodeListOptions{})
list, err := dockerCLI.Client().NodeList(cmd.Context(), swarm.NodeListOptions{})
if err != nil {
return []string{}
}

View File

@ -8,7 +8,6 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/builders"
"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"
@ -111,7 +110,7 @@ func TestCompleteEventFilter(t *testing.T) {
},
{
client: &fakeClient{
nodeListFunc: func(_ context.Context, _ types.NodeListOptions) ([]swarm.Node, error) {
nodeListFunc: func(_ context.Context, _ swarm.NodeListOptions) ([]swarm.Node, error) {
return []swarm.Node{
*builders.Node(builders.Hostname("n1")),
}, nil
@ -122,7 +121,7 @@ func TestCompleteEventFilter(t *testing.T) {
},
{
client: &fakeClient{
nodeListFunc: func(_ context.Context, _ types.NodeListOptions) ([]swarm.Node, error) {
nodeListFunc: func(_ context.Context, _ swarm.NodeListOptions) ([]swarm.Node, error) {
return []swarm.Node{}, errors.New("API error")
},
},

View File

@ -15,9 +15,9 @@ import (
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/inspect"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -137,7 +137,7 @@ func inspectNode(ctx context.Context, dockerCli command.Cli) inspect.GetRefFunc
func inspectService(ctx context.Context, dockerCli command.Cli) inspect.GetRefFunc {
return func(ref string) (any, []byte, error) {
// Service inspect shows defaults values in empty fields.
return dockerCli.Client().ServiceInspectWithRaw(ctx, ref, types.ServiceInspectOptions{InsertDefaults: true})
return dockerCli.Client().ServiceInspectWithRaw(ctx, ref, swarm.ServiceInspectOptions{InsertDefaults: true})
}
}

View File

@ -3,7 +3,6 @@ package task
import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
)
@ -11,7 +10,7 @@ import (
type fakeClient struct {
client.APIClient
nodeInspectWithRaw func(ref string) (swarm.Node, []byte, error)
serviceInspectWithRaw func(ref string, options types.ServiceInspectOptions) (swarm.Service, []byte, error)
serviceInspectWithRaw func(ref string, options swarm.ServiceInspectOptions) (swarm.Service, []byte, error)
}
func (cli *fakeClient) NodeInspectWithRaw(_ context.Context, ref string) (swarm.Node, []byte, error) {
@ -21,7 +20,7 @@ func (cli *fakeClient) NodeInspectWithRaw(_ context.Context, ref string) (swarm.
return swarm.Node{}, nil, nil
}
func (cli *fakeClient) ServiceInspectWithRaw(_ context.Context, ref string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) {
func (cli *fakeClient) ServiceInspectWithRaw(_ context.Context, ref string, options swarm.ServiceInspectOptions) (swarm.Service, []byte, error) {
if cli.serviceInspectWithRaw != nil {
return cli.serviceInspectWithRaw(ref, options)
}

View File

@ -9,7 +9,6 @@ import (
"github.com/docker/cli/cli/command/idresolver"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/builders"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"gotest.tools/v3/assert"
"gotest.tools/v3/golden"
@ -17,7 +16,7 @@ import (
func TestTaskPrintSorted(t *testing.T) {
apiClient := &fakeClient{
serviceInspectWithRaw: func(ref string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) {
serviceInspectWithRaw: func(ref string, options swarm.ServiceInspectOptions) (swarm.Service, []byte, error) {
if ref == "service-id-one" {
return *builders.Service(builders.ServiceName("service-name-1")), nil, nil
}
@ -109,7 +108,7 @@ func TestTaskPrintWithIndentation(t *testing.T) {
const trunc = false
const noResolve = false
apiClient := &fakeClient{
serviceInspectWithRaw: func(ref string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) {
serviceInspectWithRaw: func(ref string, options swarm.ServiceInspectOptions) (swarm.Service, []byte, error) {
return *builders.Service(builders.ServiceName("service-name-foo")), nil, nil
},
nodeInspectWithRaw: func(ref string) (swarm.Node, []byte, error) {
@ -145,7 +144,7 @@ func TestTaskPrintWithResolution(t *testing.T) {
const trunc = false
const noResolve = false
apiClient := &fakeClient{
serviceInspectWithRaw: func(ref string, options types.ServiceInspectOptions) (swarm.Service, []byte, error) {
serviceInspectWithRaw: func(ref string, options swarm.ServiceInspectOptions) (swarm.Service, []byte, error) {
return *builders.Service(builders.ServiceName("service-name-foo")), nil, nil
},
nodeInspectWithRaw: func(ref string) (swarm.Node, []byte, error) {

View File

@ -152,7 +152,8 @@ func (configFile *ConfigFile) Save() (retErr error) {
return err
}
defer func() {
temp.Close()
// ignore error as the file may already be closed when we reach this.
_ = temp.Close()
if retErr != nil {
if err := os.Remove(temp.Name()); err != nil {
logrus.WithError(err).WithField("file", temp.Name()).Debug("Error cleaning up temp file")
@ -169,10 +170,16 @@ func (configFile *ConfigFile) Save() (retErr error) {
return errors.Wrap(err, "error closing temp file")
}
// Handle situation where the configfile is a symlink
// Handle situation where the configfile is a symlink, and allow for dangling symlinks
cfgFile := configFile.Filename
if f, err := os.Readlink(cfgFile); err == nil {
if f, err := filepath.EvalSymlinks(cfgFile); err == nil {
cfgFile = f
} else if os.IsNotExist(err) {
// extract the path from the error if the configfile does not exist or is a dangling symlink
var pathError *os.PathError
if errors.As(err, &pathError) {
cfgFile = pathError.Path
}
}
// Try copying the current config file (if any) ownership and permissions

View File

@ -538,6 +538,34 @@ func TestSaveWithSymlink(t *testing.T) {
assert.Check(t, is.Equal(string(cfg), "{\n \"auths\": {}\n}"))
}
func TestSaveWithRelativeSymlink(t *testing.T) {
dir := fs.NewDir(t, t.Name(), fs.WithFile("real-config.json", `{}`))
defer dir.Remove()
symLink := dir.Join("config.json")
relativeRealFile := "real-config.json"
realFile := dir.Join(relativeRealFile)
err := os.Symlink(relativeRealFile, symLink)
assert.NilError(t, err)
configFile := New(symLink)
err = configFile.Save()
assert.NilError(t, err)
fi, err := os.Lstat(symLink)
assert.NilError(t, err)
assert.Assert(t, fi.Mode()&os.ModeSymlink != 0, "expected %s to be a symlink", symLink)
cfg, err := os.ReadFile(symLink)
assert.NilError(t, err)
assert.Check(t, is.Equal(string(cfg), "{\n \"auths\": {}\n}"))
cfg, err = os.ReadFile(realFile)
assert.NilError(t, err)
assert.Check(t, is.Equal(string(cfg), "{\n \"auths\": {}\n}"))
}
func TestPluginConfig(t *testing.T) {
configFile := New("test-plugin")
defer os.Remove("test-plugin")

View File

@ -6,7 +6,7 @@ ARG ALPINE_VERSION=3.21
# BUILDX_VERSION sets the version of buildx to install in the dev container.
# It must be a valid tag in the docker.io/docker/buildx-bin image repository
# on Docker Hub.
ARG BUILDX_VERSION=0.23.0
ARG BUILDX_VERSION=0.24.0
FROM docker/buildx-bin:${BUILDX_VERSION} AS buildx
FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS golang

View File

@ -2,7 +2,7 @@
ARG GO_VERSION=1.24.3
ARG ALPINE_VERSION=3.21
ARG GOLANGCI_LINT_VERSION=v2.1.2
ARG GOLANGCI_LINT_VERSION=v2.1.5
FROM golangci/golangci-lint:${GOLANGCI_LINT_VERSION}-alpine AS golangci-lint

View File

@ -55,14 +55,14 @@ The following table provides an overview of the current status of deprecated fea
|------------|------------------------------------------------------------------------------------------------------------------------------------|------------|--------|
| Deprecated | [Configuration for pushing non-distributable artifacts](#configuration-for-pushing-non-distributable-artifacts) | v28.0 | v29.0 |
| Deprecated | [`--time` option on `docker stop` and `docker restart`](#--time-option-on-docker-stop-and-docker-restart) | v28.0 | - |
| Deprecated | [Non-standard fields in image inspect](#non-standard-fields-in-image-inspect) | v27.0 | v28.0 |
| Removed | [Non-standard fields in image inspect](#non-standard-fields-in-image-inspect) | v27.0 | v28.2 |
| Removed | [API CORS headers](#api-cors-headers) | v27.0 | v28.0 |
| Deprecated | [Graphdriver plugins (experimental)](#graphdriver-plugins-experimental) | v27.0 | v28.0 |
| Removed | [Graphdriver plugins (experimental)](#graphdriver-plugins-experimental) | v27.0 | v28.0 |
| Deprecated | [Unauthenticated TCP connections](#unauthenticated-tcp-connections) | v26.0 | v28.0 |
| Deprecated | [`Container` and `ContainerConfig` fields in Image inspect](#container-and-containerconfig-fields-in-image-inspect) | v25.0 | v26.0 |
| Deprecated | [Deprecate legacy API versions](#deprecate-legacy-api-versions) | v25.0 | v26.0 |
| Removed | [`Container` and `ContainerConfig` fields in Image inspect](#container-and-containerconfig-fields-in-image-inspect) | v25.0 | v26.0 |
| Removed | [Deprecate legacy API versions](#deprecate-legacy-api-versions) | v25.0 | v26.0 |
| Removed | [Container short ID in network Aliases field](#container-short-id-in-network-aliases-field) | v25.0 | v26.0 |
| Deprecated | [IsAutomated field, and `is-automated` filter on `docker search`](#isautomated-field-and-is-automated-filter-on-docker-search) | v25.0 | v26.0 |
| Removed | [IsAutomated field, and `is-automated` filter on `docker search`](#isautomated-field-and-is-automated-filter-on-docker-search) | v25.0 | v28.2 |
| Removed | [logentries logging driver](#logentries-logging-driver) | v24.0 | v25.0 |
| Removed | [OOM-score adjust for the daemon](#oom-score-adjust-for-the-daemon) | v24.0 | v25.0 |
| Removed | [BuildKit build information](#buildkit-build-information) | v23.0 | v24.0 |
@ -71,7 +71,7 @@ The following table provides an overview of the current status of deprecated fea
| Removed | [Btrfs storage driver on CentOS 7 and RHEL 7](#btrfs-storage-driver-on-centos-7-and-rhel-7) | v20.10 | v23.0 |
| Removed | [Support for encrypted TLS private keys](#support-for-encrypted-tls-private-keys) | v20.10 | v23.0 |
| Removed | [Kubernetes stack and context support](#kubernetes-stack-and-context-support) | v20.10 | v23.0 |
| Deprecated | [Pulling images from non-compliant image registries](#pulling-images-from-non-compliant-image-registries) | v20.10 | - |
| Removed | [Pulling images from non-compliant image registries](#pulling-images-from-non-compliant-image-registries) | v20.10 | v28.2 |
| Removed | [Linux containers on Windows (LCOW)](#linux-containers-on-windows-lcow-experimental) | v20.10 | v23.0 |
| Deprecated | [BLKIO weight options with cgroups v1](#blkio-weight-options-with-cgroups-v1) | v20.10 | - |
| Removed | [Kernel memory limit](#kernel-memory-limit) | v20.10 | v23.0 |
@ -80,9 +80,9 @@ The following table provides an overview of the current status of deprecated fea
| Deprecated | [CLI plugins support](#cli-plugins-support) | v20.10 | - |
| Deprecated | [Dockerfile legacy `ENV name value` syntax](#dockerfile-legacy-env-name-value-syntax) | v20.10 | - |
| Removed | [`docker build --stream` flag (experimental)](#docker-build---stream-flag-experimental) | v20.10 | v20.10 |
| Deprecated | [`fluentd-async-connect` log opt](#fluentd-async-connect-log-opt) | v20.10 | v28.0 |
| Removed | [`fluentd-async-connect` log opt](#fluentd-async-connect-log-opt) | v20.10 | v28.0 |
| Removed | [Configuration options for experimental CLI features](#configuration-options-for-experimental-cli-features) | v19.03 | v23.0 |
| Deprecated | [Pushing and pulling with image manifest v2 schema 1](#pushing-and-pulling-with-image-manifest-v2-schema-1) | v19.03 | v27.0 |
| Removed | [Pushing and pulling with image manifest v2 schema 1](#pushing-and-pulling-with-image-manifest-v2-schema-1) | v19.03 | v28.2 |
| Removed | [`docker engine` subcommands](#docker-engine-subcommands) | v19.03 | v20.10 |
| Removed | [Top-level `docker deploy` subcommand (experimental)](#top-level-docker-deploy-subcommand-experimental) | v19.03 | v20.10 |
| Removed | [`docker stack deploy` using "dab" files (experimental)](#docker-stack-deploy-using-dab-files-experimental) | v19.03 | v20.10 |
@ -172,7 +172,7 @@ Users are encouraged to migrate to using the `--timeout` option instead.
### Non-standard fields in image inspect
**Deprecated in Release: v27.0**
**Target For Removal In Release: v28.0**
**Removed In Release: v28.2**
The `Config` field returned shown in `docker image inspect` (and as returned by
the `GET /images/{name}/json` API endpoint) returns additional fields that are
@ -184,8 +184,9 @@ but are not omitted in the response when left empty. As these fields were not
intended to be part of the image configuration response, they are deprecated,
and will be removed from the API in thee next release.
The following fields are currently included in the API response, but are not
part of the underlying image's `Config` field, and deprecated:
The following fields are not part of the underlying image's `Config` field, and
removed in the API response for API v1.50 and newer, corresponding with v28.2.
They continue to be included when using clients that use an older API version:
- `Hostname`
- `Domainname`
@ -196,9 +197,9 @@ part of the underlying image's `Config` field, and deprecated:
- `OpenStdin`
- `StdinOnce`
- `Image`
- `NetworkDisabled` (already omitted unless set)
- `MacAddress` (already omitted unless set)
- `StopTimeout` (already omitted unless set)
- `NetworkDisabled` (omitted unless set on older API versions)
- `MacAddress` (omitted unless set on older API versions)
- `StopTimeout` (omitted unless set on older API versions)
[Docker image specification]: https://github.com/moby/docker-image-spec/blob/v1.3.1/specs-go/v1/image.go#L19-L32
[OCI image specification]: https://github.com/opencontainers/image-spec/blob/v1.1.0/specs-go/v1/config.go#L24-L62
@ -210,19 +211,13 @@ part of the underlying image's `Config` field, and deprecated:
**Target For Removal In Release: v28.0**
[Graphdriver plugins](https://github.com/docker/cli/blob/v26.1.4/docs/extend/plugins_graphdriver.md)
are an experimental feature that allow extending the Docker Engine with custom
were an experimental feature that allowed extending the Docker Engine with custom
storage drivers for storing images and containers. This feature was not
maintained since its inception, and will no longer be supported in upcoming
releases.
maintained since its inception.
Support for graphdriver plugins is disabled by default in v27.0, and will be
removed v28.0. An `DOCKERD_DEPRECATED_GRAPHDRIVER_PLUGINS` environment variable
is provided in v27.0 to re-enable the feature. This environment variable must
be set to a non-empty value in the daemon's environment.
The `DOCKERD_DEPRECATED_GRAPHDRIVER_PLUGINS` environment variable, along with
support for graphdriver plugins, will be removed in v28.0. Users of this feature
are recommended to instead configure the Docker Engine to use the [containerd image store](https://docs.docker.com/storage/containerd/)
Support for graphdriver plugins was disabled by default in v27.0, and removed
in v28.0. Users of this feature are recommended to instead configure the Docker
Engine to use the [containerd image store](https://docs.docker.com/storage/containerd/)
and a custom [snapshotter](https://github.com/containerd/containerd/tree/v1.7.18/docs/snapshotters)
### API CORS headers
@ -276,15 +271,15 @@ configuring TLS (or SSH) for the Docker daemon, refer to
### `Container` and `ContainerConfig` fields in Image inspect
**Deprecated in Release: v25.0**
**Target For Removal In Release: v26.0**
**Removed In Release: v26.0**
The `Container` and `ContainerConfig` fields returned by `docker inspect` are
mostly an implementation detail of the classic (non-BuildKit) image builder.
These fields are not portable and are empty when using the
BuildKit-based builder (enabled by default since v23.0).
These fields are deprecated in v25.0 and will be omitted starting from v26.0.
If image configuration of an image is needed, you can obtain it from the
`Config` field.
These fields are deprecated in v25.0 and are omitted starting from v26.0 (
API version v1.45 and up). If image configuration of an image is needed,
you can obtain it from the `Config` field.
### Deprecate legacy API versions
@ -326,20 +321,22 @@ Error response from daemon: client version 1.23 is too old. Minimum supported AP
upgrade your client to a newer version
```
Support for API versions lower than `1.24` has been permanently removed in Docker
Engine v26, and the minimum supported API version will be incrementally raised
in releases following that.
<!-- keeping the paragraphs below for when we incrementally raise the minimum API 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.
API version must be supported by the daemon (`1.24` or higher).
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.
-->
### Container short ID in network Aliases field
@ -359,7 +356,7 @@ introduced in v25.0 and should be used instead of the `Aliases` field.
### IsAutomated field, and `is-automated` filter on `docker search`
**Deprecated in Release: v25.0**
**Target For Removal In Release: v26.0**
**Removed In Release: v28.2**
The `is_automated` field has been deprecated by Docker Hub's search API.
Consequently, the `IsAutomated` field in image search will always be set
@ -368,7 +365,7 @@ results.
The `AUTOMATED` column has been removed from the default `docker search`
and `docker image search` output in v25.0, and the corresponding `IsAutomated`
templating option will be removed in v26.0.
templating has been removed in v28.2.
### Logentries logging driver
@ -550,6 +547,7 @@ CLI configuration file are no longer used, and ignored.
### Pulling images from non-compliant image registries
**Deprecated in Release: v20.10**
**Removed in Release: v28.2**
Docker Engine v20.10 and up includes optimizations to verify if images in the
local image cache need updating before pulling, preventing the Docker Engine
@ -559,7 +557,7 @@ image registry to conform to the [Open Container Initiative Distribution Specifi
While most registries conform to the specification, we encountered some registries
to be non-compliant, resulting in `docker pull` to fail.
As a temporary solution, Docker Engine v20.10 includes a fallback mechanism to
As a temporary solution, Docker Engine v20.10 added a fallback mechanism to
allow `docker pull` to be functional when using a non-compliant registry. A
warning message is printed in this situation:
@ -568,16 +566,13 @@ warning message is printed in this situation:
pull by tag. This fallback is DEPRECATED, and will be removed in a future
release.
The fallback is added to allow users to either migrate their images to a compliant
registry, or for these registries to become compliant.
The fallback was added to allow users to either migrate their images to a
compliant registry, or for these registries to become compliant.
Note that this fallback only addresses failures on `docker pull`. Other commands,
such as `docker stack deploy`, or pulling images with `containerd` will continue
to fail.
Given that other functionality is still broken with these registries, we consider
this fallback a _temporary_ solution, and will remove the fallback in an upcoming
major release.
GitHub deprecated the legacy `docker.pkg.github.com` registry, and it was
[sunset on Feb 24th, 2025](https://github.blog/changelog/2025-01-23-legacy-docker-registry-closing-down/)
in favor of GitHub Container Registry (GHCR, ghcr.io), making this fallback
no longer needed.
### Linux containers on Windows (LCOW) (experimental)
@ -729,7 +724,7 @@ fluent#New: AsyncConnect is now deprecated, use Async instead
```
Users are encouraged to use the `fluentd-async` option going forward, as support
for the old option will be removed in a future release.
for the old option has been removed.
### Pushing and pulling with image manifest v2 schema 1
@ -737,7 +732,8 @@ for the old option will be removed in a future release.
**Disabled by default in Release: v26.0**
**Target For Removal In Release: v27.0**
**Removed in Release: v28.2**
The image manifest [v2 schema 1](https://distribution.github.io/distribution/spec/deprecated-schema-v1/)
and "Docker Image v1" formats were deprecated in favor of the
@ -748,23 +744,17 @@ formats.
These legacy formats should no longer be used, and users are recommended to
update images to use current formats, or to upgrade to more current images.
Starting with Docker v26.0, pulling these images is disabled by default, and
produces an error when attempting to pull the image:
support has been removed in v28.2. Attempting to pull a legacy image now
produces an error:
```console
$ docker pull ubuntu:10.04
Error response from daemon:
[DEPRECATION NOTICE] Docker Image Format v1 and Docker Image manifest version 2, schema 1 support is disabled by default and will be removed in an upcoming release.
Docker Image Format v1 and Docker Image manifest version 2, schema 1 support has been removed.
Suggest the author of docker.io/library/ubuntu:10.04 to upgrade the image to the OCI Format or Docker Image manifest v2, schema 2.
More information at https://docs.docker.com/go/deprecated-image-specs/
```
An environment variable (`DOCKER_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE`) is
added in Docker v26.0 that allows re-enabling support for these image formats
in the daemon. This environment variable must be set to a non-empty value in
the daemon's environment (for example, through a [systemd override file](https://docs.docker.com/config/daemon/systemd/)).
Support for the `DOCKER_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE` environment variable
will be removed in Docker v27.0 after which this functionality is removed permanently.
### `docker engine` subcommands
**Deprecated in Release: v19.03**

View File

@ -9,10 +9,11 @@ Remove one or more images
### Options
| Name | Type | Default | Description |
|:----------------|:-------|:--------|:-------------------------------|
| `-f`, `--force` | `bool` | | Force removal of the image |
| `--no-prune` | `bool` | | Do not delete untagged parents |
| Name | Type | Default | Description |
|:--------------------------|:--------------|:--------|:-------------------------------------------------------------------------------------------------|
| `-f`, `--force` | `bool` | | Force removal of the image |
| `--no-prune` | `bool` | | Do not delete untagged parents |
| [`--platform`](#platform) | `stringSlice` | | Remove only the given platform variant. Formatted as `os[/arch[/variant]]` (e.g., `linux/amd64`) |
<!---MARKER_GEN_END-->
@ -105,3 +106,73 @@ Deleted: 4986bf8c15363d1c5d15512d5266f8777bfba4974ac56e3270e7760f6f0a8125
Deleted: ea13149945cb6b1e746bf28032f02e9b5a793523481a0a18645fc77ad53c4ea2
Deleted: df7546f9f060a2268024c8a230d8639878585defcc1bc6f79d2728a13957871b
```
### <a name="platform"></a> Remove specific platforms (`--platform`)
The `--platform` option allows you to specify which platform variants of the
image to remove. By default, `docker image remove` removes all platform variants
that are present. Use the `--platform` option to specify which platform variant
of the image to remove.
Removing a specific platform removes the image from all images that reference
the same content, and requires the `--force` option to be used. Omitting the
`--force` option produces a warning, and the remove is canceled:
```console
$ docker image rm --platform=linux/amd64 alpine
Error response from daemon: Content will be removed from all images referencing this variant. Use —-force to force delete.
```
The platform option takes the `os[/arch[/variant]]` format; for example,
`linux/amd64` or `linux/arm64/v8`. Architecture and variant are optional,
and default to the daemon's native architecture if omitted.
You can pass multiple platforms either by passing the `--platform` flag
multiple times, or by passing a comma-separated list of platforms to remove.
The following uses of this option are equivalent;
```console
$ docker image rm --plaform linux/amd64 --platform linux/ppc64le myimage
$ docker image rm --plaform linux/amd64,linux/ppc64le myimage
```
The following example removes the `linux/amd64` and `linux/ppc64le` variants
of an `alpine` image that contains multiple platform variants in the image
cache:
```console
$ docker image ls --tree
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
alpine:latest a8560b36e8b8 37.8MB 11.2MB U
├─ linux/amd64 1c4eef651f65 12.1MB 3.64MB U
├─ linux/arm/v6 903bfe2ae994 0B 0B
├─ linux/arm/v7 9c2d245b3c01 0B 0B
├─ linux/arm64/v8 757d680068d7 12.8MB 3.99MB
├─ linux/386 2436f2b3b7d2 0B 0B
├─ linux/ppc64le 9ed53fd3b831 12.8MB 3.58MB
├─ linux/riscv64 1de5eb4a9a67 0B 0B
└─ linux/s390x fe0dcdd1f783 0B 0B
$ docker image --platform=linux/amd64,linux/ppc64le --force alpine
Deleted: sha256:1c4eef651f65e2f7daee7ee785882ac164b02b78fb74503052a26dc061c90474
Deleted: sha256:9ed53fd3b83120f78b33685d930ce9bf5aa481f6e2d165c42cbbddbeaa196f6f
```
After the command completes, the given variants of the `alpine` image are removed
from the image cache:
```console
$ docker image ls --tree
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
alpine:latest a8560b36e8b8 12.8MB 3.99MB
├─ linux/amd64 1c4eef651f65 0B 0B
├─ linux/arm/v6 903bfe2ae994 0B 0B
├─ linux/arm/v7 9c2d245b3c01 0B 0B
├─ linux/arm64/v8 757d680068d7 12.8MB 3.99MB
├─ linux/386 2436f2b3b7d2 0B 0B
├─ linux/ppc64le 9ed53fd3b831 0B 0B
├─ linux/riscv64 1de5eb4a9a67 0B 0B
└─ linux/s390x fe0dcdd1f783 0B 0B
```

View File

@ -9,10 +9,11 @@ Remove one or more images
### Options
| Name | Type | Default | Description |
|:----------------|:-------|:--------|:-------------------------------|
| `-f`, `--force` | `bool` | | Force removal of the image |
| `--no-prune` | `bool` | | Do not delete untagged parents |
| Name | Type | Default | Description |
|:----------------|:--------------|:--------|:-------------------------------------------------------------------------------------------------|
| `-f`, `--force` | `bool` | | Force removal of the image |
| `--no-prune` | `bool` | | Do not delete untagged parents |
| `--platform` | `stringSlice` | | Remove only the given platform variant. Formatted as `os[/arch[/variant]]` (e.g., `linux/amd64`) |
<!---MARKER_GEN_END-->

View File

@ -58,7 +58,7 @@ func TestPluginSocketBackwardsCompatible(t *testing.T) {
ptmx, err := pty.Start(command)
assert.NilError(t, err, "failed to launch command with fake TTY")
_, _ = ptmx.Write([]byte("hello!"))
_, _ = ptmx.WriteString("hello!")
done := make(chan error)
go func() {

View File

@ -1,7 +1,7 @@
package opts
import (
"fmt"
"net"
"testing"
"gotest.tools/v3/assert"
@ -25,13 +25,13 @@ func TestParseHost(t *testing.T) {
"fd://something": "fd://something",
"tcp://host:": "tcp://host:" + defaultHTTPPort,
"tcp://": defaultTCPHost,
"tcp://:2375": fmt.Sprintf("tcp://%s:%s", defaultHTTPHost, defaultHTTPPort),
"tcp://:2376": fmt.Sprintf("tcp://%s:%s", defaultHTTPHost, defaultTLSHTTPPort),
"tcp://:2375": "tcp://" + net.JoinHostPort(defaultHTTPHost, defaultHTTPPort),
"tcp://:2376": "tcp://" + net.JoinHostPort(defaultHTTPHost, defaultTLSHTTPPort),
"tcp://0.0.0.0:8080": "tcp://0.0.0.0:8080",
"tcp://192.168.0.0:12000": "tcp://192.168.0.0:12000",
"tcp://192.168:8080": "tcp://192.168:8080",
"tcp://0.0.0.0:1234567890": "tcp://0.0.0.0:1234567890", // yeah it's valid :P
" tcp://:7777/path ": fmt.Sprintf("tcp://%s:7777/path", defaultHTTPHost),
" tcp://:7777/path ": "tcp://" + net.JoinHostPort(defaultHTTPHost, "7777") + "/path",
"tcp://docker.com:2375": "tcp://docker.com:2375",
"unix://": "unix://" + defaultUnixSocket,
"unix://path/to/socket": "unix://path/to/socket",
@ -70,11 +70,11 @@ func TestParseDockerDaemonHost(t *testing.T) {
"[::1]:5555/path": "tcp://[::1]:5555/path",
"[0:0:0:0:0:0:0:1]:": "tcp://[0:0:0:0:0:0:0:1]:2375",
"[0:0:0:0:0:0:0:1]:5555/path": "tcp://[0:0:0:0:0:0:0:1]:5555/path",
":6666": fmt.Sprintf("tcp://%s:6666", defaultHTTPHost),
":6666/path": fmt.Sprintf("tcp://%s:6666/path", defaultHTTPHost),
":6666": "tcp://" + net.JoinHostPort(defaultHTTPHost, "6666"),
":6666/path": "tcp://" + net.JoinHostPort(defaultHTTPHost, "6666") + "/path",
"tcp://": defaultTCPHost,
"tcp://:7777": fmt.Sprintf("tcp://%s:7777", defaultHTTPHost),
"tcp://:7777/path": fmt.Sprintf("tcp://%s:7777/path", defaultHTTPHost),
"tcp://:7777": "tcp://" + net.JoinHostPort(defaultHTTPHost, "7777"),
"tcp://:7777/path": "tcp://" + net.JoinHostPort(defaultHTTPHost, "7777") + "/path",
"unix:///run/docker.sock": "unix:///run/docker.sock",
"unix://": "unix://" + defaultUnixSocket,
"fd://": "fd://",
@ -96,7 +96,7 @@ func TestParseDockerDaemonHost(t *testing.T) {
}
func TestParseTCP(t *testing.T) {
defaultHTTPHost := "tcp://127.0.0.1:2376"
const defaultHost = "tcp://127.0.0.1:2376"
invalids := map[string]string{
"tcp:a.b.c.d": "",
"tcp:a.b.c.d/path": "",
@ -104,8 +104,8 @@ func TestParseTCP(t *testing.T) {
"udp://127.0.0.1:2375": "invalid proto, expected tcp: udp://127.0.0.1:2375",
}
valids := map[string]string{
"": defaultHTTPHost,
"tcp://": defaultHTTPHost,
"": defaultHost,
"tcp://": defaultHost,
"0.0.0.1:": "tcp://0.0.0.1:2376",
"0.0.0.1:5555": "tcp://0.0.0.1:5555",
"0.0.0.1:5555/path": "tcp://0.0.0.1:5555/path",
@ -124,12 +124,12 @@ func TestParseTCP(t *testing.T) {
"localhost:5555/path": "tcp://localhost:5555/path",
}
for invalidAddr, expectedError := range invalids {
if addr, err := ParseTCPAddr(invalidAddr, defaultHTTPHost); err == nil || expectedError != "" && err.Error() != expectedError {
if addr, err := ParseTCPAddr(invalidAddr, defaultHost); err == nil || expectedError != "" && err.Error() != expectedError {
t.Errorf("tcp %v address expected error %v return, got %s and addr %v", invalidAddr, expectedError, err, addr)
}
}
for validAddr, expectedAddr := range valids {
if addr, err := ParseTCPAddr(validAddr, defaultHTTPHost); err != nil || addr != expectedAddr {
if addr, err := ParseTCPAddr(validAddr, defaultHost); err != nil || addr != expectedAddr {
t.Errorf("%v -> expected %v, got %v and addr %v", validAddr, expectedAddr, err, addr)
}
}

View File

@ -100,7 +100,7 @@ func (m *MountOpt) Set(value string) error {
mount.Type = mounttypes.Type(strings.ToLower(val))
case "source", "src":
mount.Source = val
if strings.HasPrefix(val, "."+string(filepath.Separator)) || val == "." {
if !filepath.IsAbs(val) && strings.HasPrefix(val, ".") {
if abs, err := filepath.Abs(val); err == nil {
mount.Source = abs
}

View File

@ -39,11 +39,22 @@ func TestMountRelative(t *testing.T) {
name: "Current path",
path: ".",
bind: "type=bind,source=.,target=/target",
}, {
},
{
name: "Current path with slash",
path: "./",
bind: "type=bind,source=./,target=/target",
},
{
name: "Parent path with slash",
path: "../",
bind: "type=bind,source=../,target=/target",
},
{
name: "Parent path",
path: "..",
bind: "type=bind,source=..,target=/target",
},
} {
t.Run(testcase.name, func(t *testing.T) {
var mount MountOpt

View File

@ -13,9 +13,9 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.7
github.com/creack/pty v1.1.24
github.com/distribution/reference v0.6.0
github.com/docker/cli-docs-tool v0.9.0
github.com/docker/cli-docs-tool v0.10.0
github.com/docker/distribution v2.8.3+incompatible
github.com/docker/docker v28.1.2-0.20250519114040-7937f0846c13+incompatible // master, v28.x dev
github.com/docker/docker v28.2.2-0.20250530085359-45873be4ae3f+incompatible // v28.2-dev
github.com/docker/docker-credential-helpers v0.9.3
github.com/docker/go-connections v0.5.0
github.com/docker/go-units v0.5.0
@ -68,6 +68,7 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect

View File

@ -34,6 +34,8 @@ github.com/cloudflare/cfssl v1.6.4 h1:NMOvfrEjFfC63K3SGXgAnFdsgkmiq4kATme5BfcqrO
github.com/cloudflare/cfssl v1.6.4/go.mod h1:8b3CQMxfWPAeom3zBnGJ6sd+G1NkL5TXqmDXacb+1J0=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/platforms v1.0.0-rc.1 h1:83KIq4yy1erSRgOVHNk1HYdPvzdJ5CnsWaRoJX4C41E=
@ -50,13 +52,13 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli-docs-tool v0.9.0 h1:CVwQbE+ZziwlPqrJ7LRyUF6GvCA+6gj7MTCsayaK9t0=
github.com/docker/cli-docs-tool v0.9.0/go.mod h1:ClrwlNW+UioiRyH9GiAOe1o3J/TsY3Tr1ipoypjAUtc=
github.com/docker/cli-docs-tool v0.10.0 h1:bOD6mKynPQgojQi3s2jgcUWGp/Ebqy1SeCr9VfKQLLU=
github.com/docker/cli-docs-tool v0.10.0/go.mod h1:5EM5zPnT2E7yCLERZmrDA234Vwn09fzRHP4aX1qwp1U=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v28.1.2-0.20250519114040-7937f0846c13+incompatible h1:hQ0dI0strJB2gjh/Sx+WthVEhOe89DPjAwiZVwjbpIg=
github.com/docker/docker v28.1.2-0.20250519114040-7937f0846c13+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v28.2.2-0.20250530085359-45873be4ae3f+incompatible h1:Pv7Z5UMmGkOzACssMUwY4HlxQ9sd5lyLnoaLDbj3Mec=
github.com/docker/docker v28.2.2-0.20250530085359-45873be4ae3f+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=

191
vendor/github.com/containerd/errdefs/pkg/LICENSE generated vendored Normal file
View File

@ -0,0 +1,191 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright The containerd Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,96 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package errhttp provides utility functions for translating errors to
// and from a HTTP context.
//
// The functions ToHTTP and ToNative can be used to map server-side and
// client-side errors to the correct types.
package errhttp
import (
"errors"
"net/http"
"github.com/containerd/errdefs"
"github.com/containerd/errdefs/pkg/internal/cause"
)
// ToHTTP returns the best status code for the given error
func ToHTTP(err error) int {
switch {
case errdefs.IsNotFound(err):
return http.StatusNotFound
case errdefs.IsInvalidArgument(err):
return http.StatusBadRequest
case errdefs.IsConflict(err):
return http.StatusConflict
case errdefs.IsNotModified(err):
return http.StatusNotModified
case errdefs.IsFailedPrecondition(err):
return http.StatusPreconditionFailed
case errdefs.IsUnauthorized(err):
return http.StatusUnauthorized
case errdefs.IsPermissionDenied(err):
return http.StatusForbidden
case errdefs.IsResourceExhausted(err):
return http.StatusTooManyRequests
case errdefs.IsInternal(err):
return http.StatusInternalServerError
case errdefs.IsNotImplemented(err):
return http.StatusNotImplemented
case errdefs.IsUnavailable(err):
return http.StatusServiceUnavailable
case errdefs.IsUnknown(err):
var unexpected cause.ErrUnexpectedStatus
if errors.As(err, &unexpected) && unexpected.Status >= 200 && unexpected.Status < 600 {
return unexpected.Status
}
return http.StatusInternalServerError
default:
return http.StatusInternalServerError
}
}
// ToNative returns the error best matching the HTTP status code
func ToNative(statusCode int) error {
switch statusCode {
case http.StatusNotFound:
return errdefs.ErrNotFound
case http.StatusBadRequest:
return errdefs.ErrInvalidArgument
case http.StatusConflict:
return errdefs.ErrConflict
case http.StatusPreconditionFailed:
return errdefs.ErrFailedPrecondition
case http.StatusUnauthorized:
return errdefs.ErrUnauthenticated
case http.StatusForbidden:
return errdefs.ErrPermissionDenied
case http.StatusNotModified:
return errdefs.ErrNotModified
case http.StatusTooManyRequests:
return errdefs.ErrResourceExhausted
case http.StatusInternalServerError:
return errdefs.ErrInternal
case http.StatusNotImplemented:
return errdefs.ErrNotImplemented
case http.StatusServiceUnavailable:
return errdefs.ErrUnavailable
default:
return cause.ErrUnexpectedStatus{Status: statusCode}
}
}

View File

@ -0,0 +1,33 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package cause is used to define root causes for errors
// common to errors packages like grpc and http.
package cause
import "fmt"
type ErrUnexpectedStatus struct {
Status int
}
const UnexpectedStatusPrefix = "unexpected status "
func (e ErrUnexpectedStatus) Error() string {
return fmt.Sprintf("%s%d", UnexpectedStatusPrefix, e.Status)
}
func (ErrUnexpectedStatus) Unknown() {}

View File

@ -1,34 +1,38 @@
run:
timeout: 10m
version: "2"
linters:
default: none
enable:
- depguard
- gofmt
- goimports
- revive
- govet
- importas
- ineffassign
- misspell
- typecheck
- errname
- makezero
- whitespace
disable-all: true
linters-settings:
depguard:
settings:
depguard:
rules:
main:
deny:
- pkg: io/ioutil
desc: The io/ioutil package has been deprecated, see https://go.dev/doc/go1.16#ioutil
importas:
no-unaliased: true
exclusions:
generated: lax
rules:
main:
deny:
- pkg: io/ioutil
desc: The io/ioutil package has been deprecated, see https://go.dev/doc/go1.16#ioutil
importas:
no-unaliased: true
- linters:
- revive
text: stutters
formatters:
enable:
- gofmt
- goimports
issues:
exclude-rules:
- linters:
- revive
text: "stutters"
max-issues-per-linter: 0
max-same-issues: 0

View File

@ -14,9 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
ARG GO_VERSION="1.23"
ARG GO_VERSION="1.24"
ARG XX_VERSION="1.6.1"
ARG GOLANGCI_LINT_VERSION="v1.62"
ARG GOLANGCI_LINT_VERSION="v2.1.5"
ARG ADDLICENSE_VERSION="v1.1.1"
ARG LICENSE_ARGS="-c cli-docs-tool -l apache"

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package annotation handles annotations for CLI commands.
package annotation
const (

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package clidocstool provides tools for generating CLI documentation.
package clidocstool
import (

View File

@ -64,6 +64,14 @@ func (c *Client) genManTreeCustom(cmd *cobra.Command) error {
return nil
}
// Skip hidden command recursively
for curr := cmd; curr != nil; curr = curr.Parent() {
if curr.Hidden {
log.Printf("INFO: Skipping Man for %q (hidden command)", curr.CommandPath())
return nil
}
}
log.Printf("INFO: Generating Man for %q", cmd.CommandPath())
return doc.GenManTreeFromOpts(cmd, doc.GenManTreeOptions{

View File

@ -53,10 +53,12 @@ func (c *Client) GenMarkdownTree(cmd *cobra.Command) error {
return nil
}
// Skip hidden command
if cmd.Hidden {
log.Printf("INFO: Skipping Markdown for %q (hidden command)", cmd.CommandPath())
return nil
// Skip hidden command recursively
for curr := cmd; curr != nil; curr = curr.Parent() {
if curr.Hidden {
log.Printf("INFO: Skipping Markdown for %q (hidden command)", curr.CommandPath())
return nil
}
}
log.Printf("INFO: Generating Markdown for %q", cmd.CommandPath())

View File

@ -169,6 +169,9 @@ func (c *Client) genYamlCustom(cmd *cobra.Command, w io.Writer) error {
// check recursively to handle inherited annotations
for curr := cmd; curr != nil; curr = curr.Parent() {
if curr.Hidden {
cliDoc.Hidden = true
}
if v, ok := curr.Annotations["version"]; ok && cliDoc.MinAPIVersion == "" {
cliDoc.MinAPIVersion = v
}
@ -349,9 +352,9 @@ func genFlagResult(cmd *cobra.Command, flags *pflag.FlagSet, anchors map[string]
//
// This makes the generated YAML more readable, and easier to review changes.
// max can be used to customize the width to keep the whole line < 80 chars.
func forceMultiLine(s string, max int) string {
func forceMultiLine(s string, maxWidth int) string {
s = strings.TrimSpace(s)
if len(s) > max && !strings.Contains(s, "\n") {
if len(s) > maxWidth && !strings.Contains(s, "\n") {
s = s + "\n"
}
return s

View File

@ -1428,63 +1428,10 @@ definitions:
when starting a container from the image.
type: "object"
properties:
Hostname:
description: |
The hostname to use for the container, as a valid RFC 1123 hostname.
<p><br /></p>
> **Deprecated**: this field is not part of the image specification and is
> always empty. It must not be used, and will be removed in API v1.48.
type: "string"
example: ""
Domainname:
description: |
The domain name to use for the container.
<p><br /></p>
> **Deprecated**: this field is not part of the image specification and is
> always empty. It must not be used, and will be removed in API v1.48.
type: "string"
example: ""
User:
description: "The user that commands are run as inside the container."
type: "string"
example: "web:web"
AttachStdin:
description: |
Whether to attach to `stdin`.
<p><br /></p>
> **Deprecated**: this field is not part of the image specification and is
> always false. It must not be used, and will be removed in API v1.48.
type: "boolean"
default: false
example: false
AttachStdout:
description: |
Whether to attach to `stdout`.
<p><br /></p>
> **Deprecated**: this field is not part of the image specification and is
> always false. It must not be used, and will be removed in API v1.48.
type: "boolean"
default: false
example: false
AttachStderr:
description: |
Whether to attach to `stderr`.
<p><br /></p>
> **Deprecated**: this field is not part of the image specification and is
> always false. It must not be used, and will be removed in API v1.48.
type: "boolean"
default: false
example: false
ExposedPorts:
description: |
An object mapping ports to an empty object in the form:
@ -1501,39 +1448,6 @@ definitions:
"80/tcp": {},
"443/tcp": {}
}
Tty:
description: |
Attach standard streams to a TTY, including `stdin` if it is not closed.
<p><br /></p>
> **Deprecated**: this field is not part of the image specification and is
> always false. It must not be used, and will be removed in API v1.48.
type: "boolean"
default: false
example: false
OpenStdin:
description: |
Open `stdin`
<p><br /></p>
> **Deprecated**: this field is not part of the image specification and is
> always false. It must not be used, and will be removed in API v1.48.
type: "boolean"
default: false
example: false
StdinOnce:
description: |
Close `stdin` after one attached client disconnects.
<p><br /></p>
> **Deprecated**: this field is not part of the image specification and is
> always false. It must not be used, and will be removed in API v1.48.
type: "boolean"
default: false
example: false
Env:
description: |
A list of environment variables to set inside the container in the
@ -1559,18 +1473,6 @@ definitions:
default: false
example: false
x-nullable: true
Image:
description: |
The name (or reference) of the image to use when creating the container,
or which was used when the container was created.
<p><br /></p>
> **Deprecated**: this field is not part of the image specification and is
> always empty. It must not be used, and will be removed in API v1.48.
type: "string"
default: ""
example: ""
Volumes:
description: |
An object mapping mount point paths inside the container to empty
@ -1599,30 +1501,6 @@ definitions:
items:
type: "string"
example: []
NetworkDisabled:
description: |
Disable networking for the container.
<p><br /></p>
> **Deprecated**: this field is not part of the image specification and is
> always omitted. It must not be used, and will be removed in API v1.48.
type: "boolean"
default: false
example: false
x-nullable: true
MacAddress:
description: |
MAC address of the container.
<p><br /></p>
> **Deprecated**: this field is not part of the image specification and is
> always omitted. It must not be used, and will be removed in API v1.48.
type: "string"
default: ""
example: ""
x-nullable: true
OnBuild:
description: |
`ONBUILD` metadata that were defined in the image's `Dockerfile`.
@ -1645,17 +1523,6 @@ definitions:
type: "string"
example: "SIGTERM"
x-nullable: true
StopTimeout:
description: |
Timeout to stop a container in seconds.
<p><br /></p>
> **Deprecated**: this field is not part of the image specification and is
> always omitted. It must not be used, and will be removed in API v1.48.
type: "integer"
default: 10
x-nullable: true
Shell:
description: |
Shell for when `RUN`, `CMD`, and `ENTRYPOINT` uses a shell.
@ -1666,19 +1533,11 @@ definitions:
example: ["/bin/sh", "-c"]
# FIXME(thaJeztah): temporarily using a full example to remove some "omitempty" fields. Remove once the fields are removed.
example:
"Hostname": ""
"Domainname": ""
"User": "web:web"
"AttachStdin": false
"AttachStdout": false
"AttachStderr": false
"ExposedPorts": {
"80/tcp": {},
"443/tcp": {}
}
"Tty": false
"OpenStdin": false
"StdinOnce": false
"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"]
"Cmd": ["/bin/sh"]
"Healthcheck": {
@ -1690,7 +1549,6 @@ definitions:
"StartInterval": 0
}
"ArgsEscaped": true
"Image": ""
"Volumes": {
"/app/data": {},
"/app/config": {}
@ -9960,6 +9818,18 @@ paths:
description: "Do not delete untagged parent images"
type: "boolean"
default: false
- name: "platforms"
in: "query"
description: |
Select platform-specific content to delete.
Multiple values are accepted.
Each platform is a OCI platform encoded as a JSON string.
type: "array"
items:
# This should be OCIPlatform
# but $ref is not supported for array in query in Swagger 2.0
# $ref: "#/definitions/OCIPlatform"
type: "string"
tags: ["Image"]
/images/search:
get:

View File

@ -4,8 +4,6 @@ import (
"bufio"
"context"
"net"
"github.com/docker/docker/api/types/filters"
)
// NewHijackedResponse initializes a [HijackedResponse] type.
@ -48,87 +46,6 @@ func (h *HijackedResponse) CloseWrite() error {
return nil
}
// NodeListOptions holds parameters to list nodes with.
type NodeListOptions struct {
Filters filters.Args
}
// NodeRemoveOptions holds parameters to remove nodes with.
type NodeRemoveOptions struct {
Force bool
}
// ServiceCreateOptions contains the options to use when creating a service.
type ServiceCreateOptions struct {
// EncodedRegistryAuth is the encoded registry authorization credentials to
// use when updating the service.
//
// This field follows the format of the X-Registry-Auth header.
EncodedRegistryAuth string
// QueryRegistry indicates whether the service update requires
// contacting a registry. A registry may be contacted to retrieve
// the image digest and manifest, which in turn can be used to update
// platform or other information about the service.
QueryRegistry bool
}
// Values for RegistryAuthFrom in ServiceUpdateOptions
const (
RegistryAuthFromSpec = "spec"
RegistryAuthFromPreviousSpec = "previous-spec"
)
// ServiceUpdateOptions contains the options to be used for updating services.
type ServiceUpdateOptions struct {
// EncodedRegistryAuth is the encoded registry authorization credentials to
// use when updating the service.
//
// This field follows the format of the X-Registry-Auth header.
EncodedRegistryAuth string
// TODO(stevvooe): Consider moving the version parameter of ServiceUpdate
// into this field. While it does open API users up to racy writes, most
// users may not need that level of consistency in practice.
// RegistryAuthFrom specifies where to find the registry authorization
// credentials if they are not given in EncodedRegistryAuth. Valid
// values are "spec" and "previous-spec".
RegistryAuthFrom string
// Rollback indicates whether a server-side rollback should be
// performed. When this is set, the provided spec will be ignored.
// The valid values are "previous" and "none". An empty value is the
// same as "none".
Rollback string
// QueryRegistry indicates whether the service update requires
// contacting a registry. A registry may be contacted to retrieve
// the image digest and manifest, which in turn can be used to update
// platform or other information about the service.
QueryRegistry bool
}
// ServiceListOptions holds parameters to list services with.
type ServiceListOptions struct {
Filters filters.Args
// Status indicates whether the server should include the service task
// count of running and desired tasks.
Status bool
}
// ServiceInspectOptions holds parameters related to the "service inspect"
// operation.
type ServiceInspectOptions struct {
InsertDefaults bool
}
// TaskListOptions holds parameters to list tasks with.
type TaskListOptions struct {
Filters filters.Args
}
// PluginRemoveOptions holds parameters to remove plugins.
type PluginRemoveOptions struct {
Force bool
@ -162,13 +79,6 @@ type PluginInstallOptions struct {
Args []string
}
// SwarmUnlockKeyResponse contains the response for Engine API:
// GET /swarm/unlockkey
type SwarmUnlockKeyResponse struct {
// UnlockKey is the unlock key in ASCII-armored format.
UnlockKey string
}
// PluginCreateOptions hold all options to plugin create.
type PluginCreateOptions struct {
RepoName string

View File

@ -3,6 +3,7 @@ package image
import (
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/storage"
dockerspec "github.com/moby/docker-image-spec/specs-go/v1"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
@ -84,7 +85,7 @@ type InspectResponse struct {
// Author is the name of the author that was specified when committing the
// image, or as specified through MAINTAINER (deprecated) in the Dockerfile.
Author string
Config *container.Config
Config *dockerspec.DockerOCIImageConfig
// Architecture is the hardware CPU architecture that the image runs on.
Architecture string

View File

@ -83,6 +83,7 @@ type ListOptions struct {
// RemoveOptions holds parameters to remove images.
type RemoveOptions struct {
Platforms []ocispec.Platform
Force bool
PruneChildren bool
}

View File

@ -1,4 +1,5 @@
package swarm // import "github.com/docker/docker/api/types/swarm"
import "github.com/docker/docker/api/types/filters"
// Node represents a node.
type Node struct {
@ -137,3 +138,13 @@ const (
type Topology struct {
Segments map[string]string `json:",omitempty"`
}
// NodeListOptions holds parameters to list nodes with.
type NodeListOptions struct {
Filters filters.Args
}
// NodeRemoveOptions holds parameters to remove nodes with.
type NodeRemoveOptions struct {
Force bool
}

View File

@ -1,6 +1,10 @@
package swarm // import "github.com/docker/docker/api/types/swarm"
import "time"
import (
"time"
"github.com/docker/docker/api/types/filters"
)
// Service represents a service.
type Service struct {
@ -200,3 +204,69 @@ type JobStatus struct {
// Swarm manager.
LastExecution time.Time `json:",omitempty"`
}
// ServiceCreateOptions contains the options to use when creating a service.
type ServiceCreateOptions struct {
// EncodedRegistryAuth is the encoded registry authorization credentials to
// use when updating the service.
//
// This field follows the format of the X-Registry-Auth header.
EncodedRegistryAuth string
// QueryRegistry indicates whether the service update requires
// contacting a registry. A registry may be contacted to retrieve
// the image digest and manifest, which in turn can be used to update
// platform or other information about the service.
QueryRegistry bool
}
// Values for RegistryAuthFrom in ServiceUpdateOptions
const (
RegistryAuthFromSpec = "spec"
RegistryAuthFromPreviousSpec = "previous-spec"
)
// ServiceUpdateOptions contains the options to be used for updating services.
type ServiceUpdateOptions struct {
// EncodedRegistryAuth is the encoded registry authorization credentials to
// use when updating the service.
//
// This field follows the format of the X-Registry-Auth header.
EncodedRegistryAuth string
// TODO(stevvooe): Consider moving the version parameter of ServiceUpdate
// into this field. While it does open API users up to racy writes, most
// users may not need that level of consistency in practice.
// RegistryAuthFrom specifies where to find the registry authorization
// credentials if they are not given in EncodedRegistryAuth. Valid
// values are "spec" and "previous-spec".
RegistryAuthFrom string
// Rollback indicates whether a server-side rollback should be
// performed. When this is set, the provided spec will be ignored.
// The valid values are "previous" and "none". An empty value is the
// same as "none".
Rollback string
// QueryRegistry indicates whether the service update requires
// contacting a registry. A registry may be contacted to retrieve
// the image digest and manifest, which in turn can be used to update
// platform or other information about the service.
QueryRegistry bool
}
// ServiceListOptions holds parameters to list services with.
type ServiceListOptions struct {
Filters filters.Args
// Status indicates whether the server should include the service task
// count of running and desired tasks.
Status bool
}
// ServiceInspectOptions holds parameters related to the "service inspect"
// operation.
type ServiceInspectOptions struct {
InsertDefaults bool
}

View File

@ -235,3 +235,10 @@ type UpdateFlags struct {
RotateManagerToken bool
RotateManagerUnlockKey bool
}
// UnlockKeyResponse contains the response for Engine API:
// GET /swarm/unlockkey
type UnlockKeyResponse struct {
// UnlockKey is the unlock key in ASCII-armored format.
UnlockKey string
}

View File

@ -3,6 +3,7 @@ package swarm // import "github.com/docker/docker/api/types/swarm"
import (
"time"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm/runtime"
)
@ -223,3 +224,8 @@ type VolumeAttachment struct {
// in the ContainerSpec, that this volume fulfills.
Target string `json:",omitempty"`
}
// TaskListOptions holds parameters to list tasks with.
type TaskListOptions struct {
Filters filters.Args
}

View File

@ -138,6 +138,53 @@ type ConfigCreateResponse = swarm.ConfigCreateResponse
// Deprecated: use [swarm.ConfigListOptions].
type ConfigListOptions = swarm.ConfigListOptions
// NodeListOptions holds parameters to list nodes with.
//
// Deprecated: use [swarm.NodeListOptions].
type NodeListOptions = swarm.NodeListOptions
// NodeRemoveOptions holds parameters to remove nodes with.
//
// Deprecated: use [swarm.NodeRemoveOptions].
type NodeRemoveOptions = swarm.NodeRemoveOptions
// TaskListOptions holds parameters to list tasks with.
//
// Deprecated: use [swarm.TaskListOptions].
type TaskListOptions = swarm.TaskListOptions
// ServiceCreateOptions contains the options to use when creating a service.
//
// Deprecated: use [swarm.ServiceCreateOptions].
type ServiceCreateOptions = swarm.ServiceCreateOptions
// ServiceUpdateOptions contains the options to be used for updating services.
//
// Deprecated: use [swarm.ServiceCreateOptions].
type ServiceUpdateOptions = swarm.ServiceUpdateOptions
const (
RegistryAuthFromSpec = swarm.RegistryAuthFromSpec // Deprecated: use [swarm.RegistryAuthFromSpec].
RegistryAuthFromPreviousSpec = swarm.RegistryAuthFromPreviousSpec // Deprecated: use [swarm.RegistryAuthFromPreviousSpec].
)
// ServiceListOptions holds parameters to list services with.
//
// Deprecated: use [swarm.ServiceListOptions].
type ServiceListOptions = swarm.ServiceListOptions
// ServiceInspectOptions holds parameters related to the "service inspect"
// operation.
//
// Deprecated: use [swarm.ServiceInspectOptions].
type ServiceInspectOptions = swarm.ServiceInspectOptions
// SwarmUnlockKeyResponse contains the response for Engine API:
// GET /swarm/unlockkey
//
// Deprecated: use [swarm.UnlockKeyResponse].
type SwarmUnlockKeyResponse = swarm.UnlockKeyResponse
// BuildCache contains information about a build cache record.
//
// Deprecated: deprecated in API 1.49. Use [build.CacheRecord] instead.

View File

@ -155,8 +155,8 @@ type NetworkAPIClient interface {
// NodeAPIClient defines API client methods for the nodes
type NodeAPIClient interface {
NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm.Node, []byte, error)
NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error)
NodeRemove(ctx context.Context, nodeID string, options types.NodeRemoveOptions) error
NodeList(ctx context.Context, options swarm.NodeListOptions) ([]swarm.Node, error)
NodeRemove(ctx context.Context, nodeID string, options swarm.NodeRemoveOptions) error
NodeUpdate(ctx context.Context, nodeID string, version swarm.Version, node swarm.NodeSpec) error
}
@ -176,22 +176,22 @@ type PluginAPIClient interface {
// ServiceAPIClient defines API client methods for the services
type ServiceAPIClient interface {
ServiceCreate(ctx context.Context, service swarm.ServiceSpec, options types.ServiceCreateOptions) (swarm.ServiceCreateResponse, error)
ServiceInspectWithRaw(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error)
ServiceList(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error)
ServiceCreate(ctx context.Context, service swarm.ServiceSpec, options swarm.ServiceCreateOptions) (swarm.ServiceCreateResponse, error)
ServiceInspectWithRaw(ctx context.Context, serviceID string, options swarm.ServiceInspectOptions) (swarm.Service, []byte, error)
ServiceList(ctx context.Context, options swarm.ServiceListOptions) ([]swarm.Service, error)
ServiceRemove(ctx context.Context, serviceID string) error
ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error)
ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options swarm.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error)
ServiceLogs(ctx context.Context, serviceID string, options container.LogsOptions) (io.ReadCloser, error)
TaskLogs(ctx context.Context, taskID string, options container.LogsOptions) (io.ReadCloser, error)
TaskInspectWithRaw(ctx context.Context, taskID string) (swarm.Task, []byte, error)
TaskList(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error)
TaskList(ctx context.Context, options swarm.TaskListOptions) ([]swarm.Task, error)
}
// SwarmAPIClient defines API client methods for the swarm
type SwarmAPIClient interface {
SwarmInit(ctx context.Context, req swarm.InitRequest) (string, error)
SwarmJoin(ctx context.Context, req swarm.JoinRequest) error
SwarmGetUnlockKey(ctx context.Context) (types.SwarmUnlockKeyResponse, error)
SwarmGetUnlockKey(ctx context.Context) (swarm.UnlockKeyResponse, error)
SwarmUnlock(ctx context.Context, req swarm.UnlockRequest) error
SwarmLeave(ctx context.Context, force bool) error
SwarmInspect(ctx context.Context) (swarm.Swarm, error)

View File

@ -4,8 +4,10 @@ import (
"context"
"errors"
"fmt"
"net/http"
cerrdefs "github.com/containerd/errdefs"
"github.com/containerd/errdefs/pkg/errhttp"
"github.com/docker/docker/api/types/versions"
)
@ -85,3 +87,43 @@ func (cli *Client) NewVersionError(ctx context.Context, APIrequired, feature str
}
return nil
}
type httpError struct {
err error
errdef error
}
func (e *httpError) Error() string {
return e.err.Error()
}
func (e *httpError) Unwrap() error {
return e.err
}
func (e *httpError) Is(target error) bool {
return errors.Is(e.errdef, target)
}
// httpErrorFromStatusCode creates an errdef error, based on the provided HTTP status-code
func httpErrorFromStatusCode(err error, statusCode int) error {
if err == nil {
return nil
}
base := errhttp.ToNative(statusCode)
if base != nil {
return &httpError{err: err, errdef: base}
}
switch {
case statusCode >= http.StatusOK && statusCode < http.StatusBadRequest:
// it's a client error
return err
case statusCode >= http.StatusBadRequest && statusCode < http.StatusInternalServerError:
return &httpError{err: err, errdef: cerrdefs.ErrInvalidArgument}
case statusCode >= http.StatusInternalServerError && statusCode < 600:
return &httpError{err: err, errdef: cerrdefs.ErrInternal}
default:
return &httpError{err: err, errdef: cerrdefs.ErrUnknown}
}
}

View File

@ -6,9 +6,9 @@ import (
"net/url"
"strings"
cerrdefs "github.com/containerd/errdefs"
"github.com/distribution/reference"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/errdefs"
)
// ImagePull requests the docker host to pull an image from a remote registry.
@ -35,7 +35,7 @@ func (cli *Client) ImagePull(ctx context.Context, refStr string, options image.P
}
resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth)
if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
if cerrdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
newAuthHeader, privilegeErr := options.PrivilegeFunc(ctx)
if privilegeErr != nil {
return nil, privilegeErr

View File

@ -9,10 +9,10 @@ import (
"net/http"
"net/url"
cerrdefs "github.com/containerd/errdefs"
"github.com/distribution/reference"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/errdefs"
)
// ImagePush requests the docker host to push an image to a remote registry.
@ -52,7 +52,7 @@ func (cli *Client) ImagePush(ctx context.Context, image string, options image.Pu
}
resp, err := cli.tryImagePush(ctx, ref.Name(), query, options.RegistryAuth)
if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
if cerrdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
newAuthHeader, privilegeErr := options.PrivilegeFunc(ctx)
if privilegeErr != nil {
return nil, privilegeErr

View File

@ -19,6 +19,14 @@ func (cli *Client) ImageRemove(ctx context.Context, imageID string, options imag
query.Set("noprune", "1")
}
if len(options.Platforms) > 0 {
p, err := encodePlatforms(options.Platforms...)
if err != nil {
return nil, err
}
query["platforms"] = p
}
resp, err := cli.delete(ctx, "/images/"+imageID, query, nil)
defer ensureReaderClosed(resp)
if err != nil {

View File

@ -7,9 +7,9 @@ import (
"net/url"
"strconv"
cerrdefs "github.com/containerd/errdefs"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/errdefs"
)
// ImageSearch makes the docker host search by a term in a remote registry.
@ -32,7 +32,7 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options registr
resp, err := cli.tryImageSearch(ctx, query, options.RegistryAuth)
defer ensureReaderClosed(resp)
if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
if cerrdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
newAuthHeader, privilegeErr := options.PrivilegeFunc(ctx)
if privilegeErr != nil {
return results, privilegeErr

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