Compare commits

..
98 Commits
Author SHA1 Message Date
Sebastiaan van StijnandGitHub 0b9d1985db Merge pull request #6764 from vvoland/update-docker
vendor: github.com/moby/moby/api v1.53.0 & github.com/moby/moby/client v0.2.2
2026-01-26 20:20:51 +01:00
Paweł Gronowski 9c9ec73588 vendor: github.com/moby/moby/client v0.2.2
full diff: https://github.com/moby/moby/client/compare/v0.2.2-rc.2...v0.2.2

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-01-26 20:15:30 +01:00
Paweł Gronowski bab3e81e1d vendor: github.com/moby/moby/api v1.53.0
full diff: https://github.com/moby/moby/api/compare/v1.53.0-rc.2...v1.53.0

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-01-26 20:15:02 +01:00
Paweł GronowskiandGitHub 2e64fc162a Merge pull request #6367 from thaJeztah/template_slicejoin
templates: make "join" work with non-string slices and map values
2026-01-26 18:03:25 +00:00
Paweł GronowskiandGitHub 1f2ba2ac9d Merge pull request #6760 from thaJeztah/container_create_fix_error
cli/command/container: make injecting config.json failures a warning
2026-01-26 17:44:42 +00:00
Sebastiaan van Stijn e34a3422cc templates: make "join" work with non-string slices and map values
Add a custom join function that allows for non-string slices to be
joined, following the same rules as "fmt.Sprint", it will use the
fmt.Stringer interface if implemented, or "error" if the type has
an "Error()".

For maps, it joins the map-values, for example:

    docker image inspect --format '{{join .Config.Labels ", "}}' ubuntu
    24.04, ubuntu

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-26 18:35:58 +01:00
Paweł GronowskiandGitHub a86356d42f Merge pull request #6763 from thaJeztah/bump_mapstructure
vendor: github.com/go-viper/mapstructure/v2 v2.5.0
2026-01-26 17:21:29 +00:00
Sebastiaan van Stijn 771660a17e vendor: github.com/go-viper/mapstructure/v2 v2.5.0
full diff: https://github.com/go-viper/mapstructure/compare/v2.4.0...v2.5.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-26 12:32:10 +01:00
Sebastiaan van StijnandGitHub 9cff36b35a Merge pull request #6762 from thaJeztah/bump_x_deps
vendor: update golang.org/x/xxx deps
2026-01-26 12:28:34 +01:00
Sebastiaan van Stijn 08ed2bc6e8 cli/command/container: make injecting config.json failures a warning
Prior to 1a502e91c9, failing to write the
container-ID to a file would return an error. After that change, we could
end up in a situation where the container was created successfully, but
we failed to inject the `config.json`. This failure would be returned as
an error, but the container was created (but no ID returned due to the error).

This patch changes the error to a warning; while not "ideal" (the container
is created, but in a "partial" state), we also shouldn't consider it to be
a hard failure; proceed as normal, to allow the user to either use the
container as-is, or to delete the container and try again.

Alternatively, we could join these errors, but the result will be ambiguous
in either case (container created, but an error occurred after the fact).

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-26 12:11:35 +01:00
Sebastiaan van StijnandGitHub 0312e3d379 Merge pull request #6761 from thaJeztah/bump_compress
vendor: github.com/klauspost/compress v1.18.3
2026-01-26 12:07:38 +01:00
Sebastiaan van Stijn e9ceb2f5ad vendor: golang.org/x/net v0.49.0
full diff: https://cs.opensource.google/go/x/net/+/refs/tags/v0.48.0...refs/tags/v0.49.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-26 11:30:51 +01:00
Sebastiaan van Stijn faf8a0836e vendor: golang.org/x/term v0.39.0
full diff: https://cs.opensource.google/go/x/term/+/refs/tags/v0.38.0...refs/tags/v0.39.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-26 11:29:34 +01:00
Sebastiaan van Stijn daa4d4e4aa vendor: golang.org/x/text v0.33.0
full diff: https://cs.opensource.google/go/x/text/+/refs/tags/v0.32.0...refs/tags/v0.33.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-26 11:28:39 +01:00
Sebastiaan van Stijn a4aee9bf54 vendor: golang.org/x/sys v0.40.0
full diff: https://cs.opensource.google/go/x/sys/+/refs/tags/v0.39.0...refs/tags/v0.40.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-26 11:27:40 +01:00
Paweł GronowskiandGitHub 9f774c370f Merge pull request #6759 from thaJeztah/container_create_cleanups
cli/command/container: create: assorted cleanups and linting fixes
2026-01-26 10:25:51 +00:00
Paweł GronowskiandGitHub d0838292e1 Merge pull request #6758 from thaJeztah/cidfile_error
cli/command/container: improve CID-file errors
2026-01-26 10:25:27 +00:00
Sebastiaan van Stijn ce489e0dbb vendor: github.com/klauspost/compress v1.18.3
no changes in vendored code

- fixes / downstream CVE-2025-61728

full diff: https://github.com/klauspost/compress/compare/v1.18.2...v1.18.3

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-26 11:22:31 +01:00
Paweł GronowskiandGitHub 931f7a1f22 Merge pull request #6753 from thaJeztah/minor_nits
cli/command/containerd: parseSecurityOpts: remove redundant sprintf
2026-01-26 10:06:15 +00:00
Sebastiaan van Stijn ef08475961 cli/command/container: ignore "not found" error on cidfile.Close
Ignore errors when trying to remove a CID-file that no longer exists;
also remove the path from the custom error as os.Remove already returns
a os.PathError, which includes the path.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-26 09:24:08 +01:00
Sebastiaan van Stijn 16bbf5d07f cli/command/container: cidFile.Write: include CID in error message
Include the container-ID in the error message when failing to write
the ID to a file, so that the user can still find the ID of the container
that was created.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-26 09:02:32 +01:00
Sebastiaan van Stijn ed566e723f cli/command/container: createContainer: remove intermediate vars
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-24 14:33:06 +01:00
Sebastiaan van Stijn cfb71de7db cli/command/container: createContainer: remove redundant closure
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-24 14:17:05 +01:00
Sebastiaan van Stijn adfb40ceb1 cli/command/container: remove outdated TODO
This was addressed in 7bdb4df07d

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-24 14:16:06 +01:00
Sebastiaan van Stijn ceea57b46d cli/command/container: copyDockerConfigIntoContainer: close TarWriter
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-24 14:16:05 +01:00
Sebastiaan van Stijn effdf1b452 cli/command/container: rename vars to use correct camelCase
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-24 14:15:57 +01:00
Sebastiaan van Stijn ccbe206a8c cli/command/containerd: parseSecurityOpts: remove redundant sprintf
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-22 10:26:54 +01:00
Paweł GronowskiandGitHub d5ed037320 Merge pull request #6736 from thaJeztah/bump_modules
vendor: moby/api v1.53.0-rc.2, moby/client v0.2.2-rc.2
2026-01-19 12:00:25 +00:00
Sebastiaan van Stijn c8841ac1b2 vendor: moby/api v1.53.0-rc.2, moby/client v0.2.2-rc.2
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-19 12:55:39 +01:00
Paweł GronowskiandGitHub 714f5bfae4 Merge pull request #6744 from thaJeztah/registryclient_cleanups
internal/registryclient: minor cleanups
2026-01-16 11:33:23 +00:00
Paweł GronowskiandGitHub 49b7be0146 Merge pull request #6745 from thaJeztah/cleanup_RetrieveAuthTokenFromImage
cli/command: RetrieveAuthTokenFromImage: remove redundant conditions
2026-01-16 11:33:02 +00:00
Sebastiaan van StijnandGitHub 533934c063 Merge pull request #6750 from vvoland/update-go
update to go1.25.6
2026-01-16 10:00:51 +01:00
Paweł Gronowski 7e8457115b update to go1.25.6
This releases includes 6 security fixes following the security policy:

- archive/zip: denial of service when parsing arbitrary ZIP archives

    archive/zip used a super-linear file name indexing algorithm that is invoked the first time a file in an archive is opened. This can lead to a denial of service when consuming a maliciously constructed ZIP archive.

    Thanks to Thanks to Jakub Ciolek for reporting this issue.

    This is CVE-2025-61728 and Go issue https://go.dev/issue/77102.

- net/http: memory exhaustion in Request.ParseForm

    When parsing a URL-encoded form net/http may allocate an unexpected amount of
    memory when provided a large number of key-value pairs. This can result in a
    denial of service due to memory exhaustion.

    Thanks to jub0bs for reporting this issue.

    This is CVE-2025-61726 and Go issue https://go.dev/issue/77101.

- crypto/tls: Config.Clone copies automatically generated session ticket keys, session resumption does not account for the expiration of full certificate chain

    The Config.Clone methods allows cloning a Config which has already been passed
    to a TLS function, allowing it to be mutated and reused.

    If Config.SessionTicketKey has not been set, and Config.SetSessionTicketKeys has
    not been called, crypto/tls will generate random session ticket keys and
    automatically rotate them. Config.Clone would copy these automatically generated
    keys into the returned Config, meaning that the two Configs would share session
    ticket keys, allowing sessions created using one Config could be used to resume
    sessions with the other Config. This can allow clients to resume sessions even
    though the Config may be configured such that they should not be able to do so.

    Config.Clone no longer copies the automatically generated session ticket keys.
    Config.Clone still copies keys which are explicitly provided, either by setting
    Config.SessionTicketKey or by calling Config.SetSessionTicketKeys.

    This issue was discoverd by the Go Security team while investigating another
    issue reported by Coia Prant (github.com/rbqvq).

    Additionally, on the server side only the expiration of the leaf certificate, if
    one was provided during the initial handshake, was checked when considering if a
    session could be resumed. This allowed sessions to be resumed if an intermediate
    or root certificate in the chain had expired.

    Session resumption now takes into account of the full chain when determining if
    the session can be resumed.

    Thanks to Coia Prant (github.com/rbqvq) for reporting this issue.

    This is CVE-2025-68121 and Go issue https://go.dev/issue/77113.

- cmd/go: bypass of flag sanitization can lead to arbitrary code execution

    Usage of 'CgoPkgConfig' allowed execution of the pkg-config
    binary with flags that are not explicitly safe-listed.

    To prevent this behavior, compiler flags resulting from usage
    of 'CgoPkgConfig' are sanitized prior to invoking pkg-config.

    Thank you to RyotaK (https://ryotak.net) of GMO Flatt Security Inc.
    for reporting this issue.

    This is CVE-2025-61731 and go.dev/issue/77100.

- cmd/go: unexpected code execution when invoking toolchain

    The Go toolchain supports multiple VCS which are used retrieving modules and
    embedding build information into binaries.

    On systems with Mercurial installed (hg) downloading modules (e.g. via go get or
    go mod download) from non-standard sources (e.g. custom domains) can cause
    unexpected code execution due to how external VCS commands are constructed.

    On systems with Git installed, downloading and building modules with malicious
    version strings could allow an attacker to write to arbitrary files on the
    system the user has access to. This can only be triggered by explicitly
    providing the malicious version strings to the toolchain, and does not affect
    usage of @latest or bare module paths.

    The toolchain now uses safer VCS options to prevent misinterpretation of
    untrusted inputs. In addition, the toolchain now disallows module version
    strings prefixed with a "-" or "/" character.

    Thanks to splitline (@splitline) from DEVCORE Research Team for reporting this
    issue.

    This is CVE-2025-68119 and Go issue https://go.dev/issue/77099.

- crypto/tls: handshake messages may be processed at the incorrect encryption level

    During the TLS 1.3 handshake if multiple messages are sent in records that span
    encryption level boundaries (for instance the Client Hello and Encrypted
    Extensions messages), the subsequent messages may be processed before the
    encryption level changes. This can cause some minor information disclosure if a
    network-local attacker can inject messages during the handshake.

    Thanks to Coia Prant (github.com/rbqvq) for reporting this issue.

    This is CVE-2025-61730 and Go issue https://go.dev/issue/76443

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

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-01-16 09:46:08 +01:00
Sebastiaan van StijnandGitHub 7d2d923a5f Merge pull request #6746 from thaJeztah/bump_logrus
vendor: github.com/sirupsen/logrus v1.9.4
2026-01-15 18:07:25 +01:00
Paweł GronowskiandGitHub 560c3c8fa3 Merge pull request #6747 from vvoland/daemon-typo
docs: Fix daemon.json typo
2026-01-15 13:20:51 +00:00
Paweł Gronowski 86bd884ac7 docs: Fix daemon.json typo
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-01-15 12:50:14 +01:00
Sebastiaan van StijnandGitHub 5579335b82 Merge pull request #6295 from thaJeztah/less_jsonmessage
internal/jsonstream: TestDisplay use streamformatter
2026-01-15 12:10:19 +01:00
Sebastiaan van Stijn 16873675bd vendor: github.com/sirupsen/logrus v1.9.4
Notable changes:

- go.mod: update minimum supported go version to v1.17.
- go.mod: bump up dependencies.
- Touch-up godoc and add "doc" links.
- README: fix links, grammar, and update examples.
- Add GNU/Hurd support.
- Add WASI wasip1 support.
- Remove uses of deprecated `ioutil` package.
- CI: update actions and golangci-lint.
- CI: remove appveyor, add macOS.

full diff: https://github.com/sirupsen/logrus/compare/v1.9.3...v1.9.4

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-15 11:45:03 +01:00
Sebastiaan van Stijn b21139c30f internal/jsonstream: TestDisplay use streamformatter
Similar to 69854c4e08, but for the
internal/jsonstream package.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-15 01:38:24 +01:00
Sebastiaan van Stijn d6cdb71e2b cli/command: RetrieveAuthTokenFromImage: remove redundant conditions
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-15 00:45:50 +01:00
Sebastiaan van StijnandGitHub 32b983a26e Merge pull request #6089 from thaJeztah/man_wrap
man: reformat docker-run.1.md to prevent linting warnings
2026-01-15 00:26:43 +01:00
Sebastiaan van Stijn b13b774e24 man: reformat docker-run.1.md to prevent linting warnings
Before this patch, lintian would complain about some lines being too long:

    lintian ./*.deb
    ...
    W: docker-ce-cli: groff-message troff:<standard input>:642: warning [p 8, 10.2i, div '3tbd1,1', 0.0i]: cannot break line [usr/share/man/man1/docker-run.1.gz:1]

    groff -t -man ./docker-run.1 > /dev/null
    troff:./docker-run.1:602: warning [p 9, 2.8i]: cannot adjust line
    troff:./docker-run.1:669: warning [p 10, 2.5i, div '3tbd1,1', 0.0i]: cannot break line

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-15 00:16:14 +01:00
Sebastiaan van Stijn 816f4556ce internal/registryclient: simplify notFoundError
- remove constructor
- fix mixed pointer/non-pointer receivers
- just embed the error we want to produce

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-15 00:06:14 +01:00
Sebastiaan van Stijn d61519f99c internal/registryclient: allEndpoints: pass through context
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-15 00:06:08 +01:00
Sebastiaan van StijnandGitHub b43d4d8e7f Merge pull request #6742 from thaJeztah/validate_detachkeys
improve validation of "--detach-keys" options
2026-01-14 23:56:07 +01:00
Sebastiaan van Stijn fe3157419c improve validation of "--detach-keys" options
Before this change, the detach-keys were not validated, and the code either
fell back to the default sequence, or returned an obscure error if the
invalid sequence would produce an error on the daemon;

Before this patch:

    docker run -it --rm --detach-keys=shift-a,b busybox
    unable to upgrade to tcp, received 400

With this patch:

    docker run -it --rm --detach-keys=shift-a,b busybox
    invalid detach keys (shift-a,b): Unknown character: 'shift-a'

Note that the "unable to upgrade to tcp, received 400" error is still
something to be looked into; the client currently discards error messages
coming from the daemon.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-14 16:57:38 +01:00
Sebastiaan van StijnandGitHub 8f50791fef Merge pull request #6740 from thaJeztah/add_WithAPIClientOptions
cli/command: add WithAPIClientOptions option
2026-01-14 09:46:57 +01:00
Sebastiaan van Stijn 6a93e78038 cli/command: add WithAPIClientOptions option
This option allows setting custom options to use when constructing
the API client.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-13 16:31:58 +01:00
Sebastiaan van StijnandGitHub 07d7ef19f3 Merge pull request #6738 from thaJeztah/fix_TestSetGoDebug
cli/command: make TestSetGoDebug more predictable
2026-01-13 16:27:35 +01:00
Sebastiaan van StijnandGitHub 6050e2bff9 Merge pull request #6741 from thaJeztah/fix_err_grammar
login: touch-up error for non-TTY
2026-01-13 16:27:01 +01:00
Sebastiaan van StijnandGitHub 5d22eaae4b Merge pull request #6739 from thaJeztah/client_opts
cli/command: DockerCli: store API-client options as field
2026-01-13 16:18:57 +01:00
Sebastiaan van Stijn db762956d1 login: touch-up error for non-TTY
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-13 15:44:04 +01:00
Sebastiaan van Stijn 4b0ec0d4ea cli/command: DockerCli: store API-client options as field
Use a more generic "clientOptions" field to store options to apply
when constructing the API client, instead of a dedicated field for
user-agent.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-13 14:48:17 +01:00
Sebastiaan van Stijn f9f2d822b9 cli/command: make TestSetGoDebug more predictable
Prevent the test from failing if GODEBUG is set in the current
environment.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-13 14:24:33 +01:00
Paweł GronowskiandGitHub bd1b1a1590 Merge pull request #6735 from thaJeztah/bump_creds_helper
vendor: github.com/docker/docker-credential-helpers v0.9.5
2026-01-12 15:09:58 +00:00
Sebastiaan van StijnandGitHub bea585067e Merge pull request #6602 from ahopp/improve-env-vars-description
Improve clarity of environment variables description
2026-01-12 13:01:58 +01:00
Andrew HoppandSebastiaan van Stijn 391acef40f Improve clarity of environment variables description
Changed the environment variables section description from:
"The following list of environment variables are supported by the `docker` command line:"

To:
"The following environment variables control the behavior of the `docker` command-line client:"

This makes it clearer that these variables control Docker's behavior, and uses the more precise term "command-line client" instead of "command line".

Signed-off-by: Andrew Hopp <andrew.hopp@me.com>
2026-01-12 11:20:18 +01:00
Sebastiaan van Stijn a6f8391c9f vendor: github.com/docker/docker-credential-helpers v0.9.5
no code changes; full diff:

https://github.com/docker/docker-credential-helpers/compare/v0.9.4...v0.9.5

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-08 18:05:14 +01:00
Sebastiaan van StijnandGitHub debbf2d4f9 Merge pull request #6723 from thaJeztah/bump_go_archive
vendor: github.com/moby/go-archive v0.2.0
2026-01-07 11:09:39 +01:00
Sebastiaan van StijnandGitHub ee0951f0e7 Merge pull request #6724 from thaJeztah/bump_x_deps
vendor: update golang.org/x/xxx dependencies
2026-01-07 11:08:15 +01:00
Paweł GronowskiandGitHub 31c58f18a5 Merge pull request #6725 from thaJeztah/test_denoise
gha: run unit-tests in go modules mode, to prevent traversing nested modules
2026-01-07 09:27:45 +00:00
Paweł GronowskiandGitHub 263562efa8 Merge pull request #6722 from thaJeztah/compose_reflectfor
cli/compose/loader: rewrite with reflect.TypeFor
2026-01-07 09:26:57 +00:00
Sebastiaan van Stijn 14cffdbfab gha: run unit-tests in go modules mode, to prevent traversing nested modules
`go list` expects a module to be valid, which means that dependencies must
either be vendored, or downloaded in the module cache. However, when working
in GOPATH mode, `go.mod` files are ignored, which means that `go list` will
traverse subdirectories, even if those are a separate module, and those modules
may not have their dependencies present.

In our case, we try to exclude those modules from paths to be tested, but
do so based on the _result_ of `go list`, which already produces errors before
we filter.

These errors do not impact out tests, as we don't run tests for those paths,
but do produce noise in CI, which can be confusing;

    go test -coverprofile=/tmp/coverage.txt $(go list ./... | grep -vE '/vendor/|/e2e/|/cmd/docker-trust')
    cmd/docker-trust/internal/trust/trust.go:28:2: cannot find package "github.com/theupdateframework/notary" in any of:
        /go/src/github.com/docker/cli/vendor/github.com/theupdateframework/notary (vendor tree)
        /usr/local/go/src/github.com/theupdateframework/notary (from $GOROOT)
        /go/src/github.com/theupdateframework/notary (from $GOPATH)
    cmd/docker-trust/internal/trust/trust.go:29:2: cannot find package "github.com/theupdateframework/notary/client" in any of:
        /go/src/github.com/docker/cli/vendor/github.com/theupdateframework/notary/client (vendor tree)
        /usr/local/go/src/github.com/theupdateframework/notary/client (from $GOROOT)
        /go/src/github.com/theupdateframework/notary/client (from $GOPATH)

This patch adds a symlink for `go.mod` and `go.sum`, so that listing the
packages happens in go modules mode, and doesn't traverse to other modules,
such as `cmd/docker-trust`.

- updates 06914dd0ff, which attempted to
  exclude the docker-trust plugin
- similar to cee9ea67fc, which made this
  change for the linter.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-24 12:47:59 +01:00
Sebastiaan van Stijn 0cd2c18580 vendor: golang.org/x/net v0.48.0
- trace: fix data race in RenderEvents
- http2, webdav, websocket: fix %q verb uses with wrong type
- http2: don't PING a responsive server when resetting a stream
- http2: support net/http.Transport.NewClientConn

full diff: https://github.com/golang/net/compare/v0.47.0...v0.48.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-23 22:55:24 +01:00
Sebastiaan van Stijn 647ab775d0 vendor: golang.org/x/term v0.38.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-23 22:55:15 +01:00
Sebastiaan van Stijn a1799eacdb vendor: golang.org/x/text v0.32.0
full diff: https://github.com/golang/text/compare/v0.31.0...v0.32.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-23 22:50:11 +01:00
Sebastiaan van Stijn a785333731 vendor: golang.org/x/sync v0.19.0
- errgroup: use consistent read for SetLimit panic

full diff: https://github.com/golang/sync/compare/v0.18.0...v0.19.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-23 22:49:12 +01:00
Sebastiaan van Stijn e2a368fa4b vendor: golang.org/x/sys v0.39.0
- Revert "cpu: add HPDS, LOR, PAN detection for arm64"
- unix: add IOCTL_MEI_* constants
- unix: fix definition of Statvfs_t for netbsd-arm

full diff: https://github.com/golang/sys/compare/v0.38.0...v0.39.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-23 22:48:28 +01:00
Sebastiaan van Stijn ab5d4d4f8c cli/compose/loader: rewrite with reflect.TypeFor
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-23 22:46:54 +01:00
Sebastiaan van StijnandGitHub 874b831c0e Merge pull request #6721 from thaJeztah/less_reflect
reduce some uses of reflect package
2025-12-23 18:42:00 +01:00
Sebastiaan van Stijn 3ce8f1d80c vendor: github.com/moby/go-archive v0.2.0
- remove aliases for deprecated types and functions
- chrootarchive: remove redundant "init" mitigation for CVE-2019-14271
- xattr: Fix OS matching

full diff: https://github.com/moby/go-archive/compare/v0.1.0...v0.2.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-23 18:11:31 +01:00
Sebastiaan van Stijn 8205124d5b cli/command/node: nodeContext: remove uses of reflect
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-23 17:54:52 +01:00
Sebastiaan van Stijn 40f052c7e1 cli/command/container: use reflect IsZero
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-23 17:17:12 +01:00
Sebastiaan van Stijn f28565d173 cli/command/service: replace reflect for gotest.tools assertion
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-23 17:17:05 +01:00
Sebastiaan van Stijn e715dd5076 cli/command/volume: remove uses of reflect in test
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-23 15:52:40 +01:00
Sebastiaan van Stijn 3811f24f47 cli/connhelper: replace reflect for gotest.tools assertion
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-23 15:52:39 +01:00
Sebastiaan van Stijn a89b2e19f5 cli/command/formatter: rewrite some tests with gotest.tools
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-23 15:52:39 +01:00
Sebastiaan van Stijn 90ae5b8136 cli/command: replace reflect for gotest.tools assertion
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-23 15:52:39 +01:00
Sebastiaan van StijnandGitHub d20f30c648 Merge pull request #6720 from thaJeztah/build_tags
opts/swarmopts: add missing build-tag
2025-12-23 13:15:25 +01:00
Sebastiaan van Stijn a0e303a0ed opts/swarmopts: add missing build-tag
This was introduced in 9c10a9c9ac, which added
use of the network.ParsePortRange.All method, which uses an iterator and
requires go1.23;

    opts/swarmopts/port.go:172:18: cannot range over pr.All() (value of func type iter.Seq[network.Port]): requires go1.23 or later (-lang was set to go1.16; check go.mod)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-23 12:17:17 +01:00
Sebastiaan van StijnandGitHub 0e38eec554 Merge pull request #6718 from thaJeztah/archive_rm_deprecated
remove uses of deprecated go-archive consts
2025-12-19 19:51:48 +01:00
Sebastiaan van Stijn 03dfab4013 remove uses of deprecated go-archive consts
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-19 18:39:13 +01:00
Austin VazquezandGitHub 06818193c7 Merge pull request #6717 from thaJeztah/bump_cdi
vendor: tags.cncf.io/container-device-interface v1.1.0
2025-12-19 08:49:08 -06:00
Sebastiaan van Stijn dd6d0cd801 vendor: tags.cncf.io/container-device-interface v1.1.0
no changes in vendored files

full diff: https://github.com/cncf-tags/container-device-interface/compare/v1.0.1...v1.1.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-18 22:49:32 +01:00
Sebastiaan van StijnandGitHub 60f06cb2df Merge pull request #6716 from vvoland/yamldocs-tty
Makefile/yamldocs: Don't require TTY
2025-12-18 17:48:48 +01:00
Paweł Gronowski 4743d1d894 Makefile/yamldocs: Don't require TTY
Make it work in GHA

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-12-18 17:38:14 +01:00
Sebastiaan van StijnandGitHub 55d80cca36 Merge pull request #6714 from thaJeztah/fix_api_versions
cli/command/service: fix API version for memory-swap, memory-swappiness
2025-12-18 13:54:21 +01:00
Sebastiaan van StijnandGitHub 7c38d6b59c Merge pull request #6713 from thaJeztah/remove_legacy_plugin_path
cli-plugins/manager: remove legacy system-wide cli-plugin path
2025-12-18 13:53:55 +01:00
Sebastiaan van StijnandGitHub f13565257e Merge pull request #6715 from vvoland/work-docs
docs/container: Fix dead docs reference
2025-12-18 13:41:02 +01:00
Paweł Gronowski 4851066797 docs/container: Update dead link
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-12-18 13:18:19 +01:00
Sebastiaan van Stijn 226af68141 cli/command/service: fix API version for memory-swap, memory-swappiness
These flags were added in 71828f2792, but
copy/pasted the annotation from `--limit-pids`.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-18 12:21:52 +01:00
Sebastiaan van Stijn 13759330b1 cli-plugins/manager: remove legacy system-wide cli-plugin path
commit 4d3a76d71e updated the list of directories
for discovering CLI plugins, adding `%ProgramFiles%\Docker\cli-plugins` for
system-wide plugins.

For backward compatibility, the `%PROGRAMDATA%\Docker\cli-plugins` was kept,
however, this location is no longer used, and not generally recommended for
storing non-data content (such as CLI plugin binaries). From the [ProgramData]
documentation:

> ProgramData specifies the path to the program-data folder (normally C:\ProgramData).
> Unlike the Program Files folder, this folder can be used by applications to store
> data for standard users, because it does not require elevated permissions.

It also mentions "It can’t contain any serviceable components.", effectively
meaning that these paths should not contain data that is managed (through
updates etc.), making it a poor choice for installing "system wide" CLI plugins.

This patch removes the path from the list, given that this location is no longer
used by Docker Desktop, and the CLI-plugin API is considered an internal
implementation (since 459c6082f8).

[ProgramData]: https://learn.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-shell-setup-folderlocations-programdata

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-12-18 10:23:41 +01:00
Sebastiaan van StijnandGitHub 93fa57bbcd Merge pull request #6711 from vvoland/update-docker
vendor: github.com/moby/moby/api v1.53.0-rc.1
2025-12-17 17:01:14 +01:00
Paweł Gronowski 302498c33c vendor: github.com/moby/moby/client v0.2.2-rc.1
full diff: https://github.com/moby/moby/client/compare/b2d84a3ef5a9...v0.2.2-rc.1

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-12-17 16:45:43 +01:00
Paweł Gronowski def847be9a vendor: github.com/moby/moby/api v1.53.0-rc.1
full diff: https://github.com/moby/moby/api/compare/b2d84a3ef5a9...v1.53.0-rc.1

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-12-17 16:45:23 +01:00
Sebastiaan van StijnandGitHub b9095d09ab Merge pull request #6710 from robmry/nri-info
Include NRI in "info" output
2025-12-16 16:33:40 +01:00
Rob Murray 2a903c52d4 Include NRI in info output
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-12-16 13:50:03 +00:00
Rob Murray d8351dbe65 Vendor moby/[api|client] from moby master
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-12-16 13:49:49 +00:00
144 changed files with 1950 additions and 1107 deletions
+1 -1
View File
@@ -63,7 +63,7 @@ jobs:
name: Update Go
uses: actions/setup-go@v6
with:
go-version: "1.25.5"
go-version: "1.25.6"
-
name: Initialize CodeQL
uses: github/codeql-action/init@v4
+5 -2
View File
@@ -67,11 +67,14 @@ jobs:
name: Set up Go
uses: actions/setup-go@v6
with:
go-version: "1.25.5"
go-version: "1.25.6"
-
name: Test
run: |
go test -coverprofile=/tmp/coverage.txt $(go list ./... | grep -vE '/vendor/|/e2e/|/cmd/docker-trust')
# run in go modules mode to prevent traversing to nested modules
ln -s vendor.mod go.mod
ln -s vendor.sum go.sum
go test -coverprofile=/tmp/coverage.txt $(go list ./... | grep -vE '^github.com/docker/cli/e2e/')
go tool cover -func=/tmp/coverage.txt
working-directory: ${{ env.GOPATH }}/src/github.com/docker/cli
shell: bash
+1 -1
View File
@@ -5,7 +5,7 @@ run:
# which causes it to fallback to go1.17 semantics.
#
# TODO(thaJeztah): update "usetesting" settings to enable go1.24 features once our minimum version is go1.24
go: "1.25.5"
go: "1.25.6"
timeout: 5m
+1 -1
View File
@@ -8,7 +8,7 @@ ARG BASE_VARIANT=alpine
ARG ALPINE_VERSION=3.22
ARG BASE_DEBIAN_DISTRO=bookworm
ARG GO_VERSION=1.25.5
ARG GO_VERSION=1.25.6
# XX_VERSION specifies the version of the xx utility to use.
# It must be a valid tag in the docker.io/tonistiigi/xx image repository.
-1
View File
@@ -16,6 +16,5 @@ import (
//
// [ConfigFile.CLIPluginsExtraDirs]: https://pkg.go.dev/github.com/docker/cli@v26.1.4+incompatible/cli/config/configfile#ConfigFile.CLIPluginsExtraDirs
var defaultSystemPluginDirs = []string{
filepath.Join(os.Getenv("ProgramData"), "Docker", "cli-plugins"),
filepath.Join(os.Getenv("ProgramFiles"), "Docker", "cli-plugins"),
}
+2 -3
View File
@@ -60,6 +60,7 @@ type Cli interface {
type DockerCli struct {
configFile *configfile.ConfigFile
options *cliflags.ClientOptions
clientOpts []client.Opt
in *streams.In
out *streams.Out
err *streams.Out
@@ -72,7 +73,6 @@ type DockerCli struct {
dockerEndpoint docker.Endpoint
contextStoreConfig *store.Config
initTimeout time.Duration
userAgent string
res telemetryResource
// baseCtx is the base context used for internal operations. In the future
@@ -533,8 +533,7 @@ func (cli *DockerCli) initialize() error {
return
}
if cli.client == nil {
ops := []client.Opt{client.WithUserAgent(cli.userAgent)}
if cli.client, cli.initErr = newAPIClientFromEndpoint(cli.dockerEndpoint, cli.configFile, ops...); cli.initErr != nil {
if cli.client, cli.initErr = newAPIClientFromEndpoint(cli.dockerEndpoint, cli.configFile, cli.clientOpts...); cli.initErr != nil {
return
}
}
+11 -1
View File
@@ -104,6 +104,16 @@ func WithInitializeClient(makeClient func(*DockerCli) (client.APIClient, error))
}
}
// WithAPIClientOptions configures additional [client.Opt] to use when
// initializing the API client. These options have no effect if a custom
// client is set (through [WithAPIClient] or [WithInitializeClient]).
func WithAPIClientOptions(c ...client.Opt) CLIOption {
return func(cli *DockerCli) error {
cli.clientOpts = append(cli.clientOpts, c...)
return nil
}
}
// envOverrideHTTPHeaders is the name of the environment-variable that can be
// used to set custom HTTP headers to be sent by the client. This environment
// variable is the equivalent to the HttpHeaders field in the configuration
@@ -221,7 +231,7 @@ func WithUserAgent(userAgent string) CLIOption {
if userAgent == "" {
return errors.New("user agent cannot be blank")
}
cli.userAgent = userAgent
cli.clientOpts = append(cli.clientOpts, client.WithUserAgent(userAgent))
return nil
}
}
+24
View File
@@ -358,6 +358,7 @@ func TestSetGoDebug(t *testing.T) {
assert.Equal(t, "val1,val2", os.Getenv("GODEBUG"))
})
t.Run("GODEBUG in context metadata can set env", func(t *testing.T) {
t.Setenv("GODEBUG", "")
meta := store.Metadata{
Metadata: DockerContext{
AdditionalFields: map[string]any{
@@ -392,3 +393,26 @@ func TestNewDockerCliWithCustomUserAgent(t *testing.T) {
assert.NilError(t, err)
assert.DeepEqual(t, received, "fake-agent/0.0.1")
}
func TestNewDockerCliWithAPIClientOptions(t *testing.T) {
var received string
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
received = r.UserAgent()
w.WriteHeader(http.StatusOK)
}))
defer ts.Close()
host := strings.Replace(ts.URL, "http://", "tcp://", 1)
opts := &flags.ClientOptions{Hosts: []string{host}}
cli, err := NewDockerCli(
WithAPIClientOptions(client.WithUserAgent("fake-agent/0.0.1")),
)
assert.NilError(t, err)
cli.currentContext = DefaultContextName
cli.options = opts
cli.configFile = &configfile.ConfigFile{}
_, err = cli.Client().Ping(t.Context(), client.PingOptions{})
assert.NilError(t, err)
assert.DeepEqual(t, received, "fake-agent/0.0.1")
}
+8 -5
View File
@@ -70,6 +70,14 @@ func newAttachCommand(dockerCLI command.Cli) *cobra.Command {
// RunAttach executes an `attach` command
func RunAttach(ctx context.Context, dockerCLI command.Cli, containerID string, opts *AttachOptions) error {
detachKeys := opts.DetachKeys
if detachKeys == "" {
detachKeys = dockerCLI.ConfigFile().DetachKeys
}
if err := validateDetachKeys(detachKeys); err != nil {
return err
}
apiClient := dockerCLI.Client()
// request channel to wait for client
@@ -85,11 +93,6 @@ func RunAttach(ctx context.Context, dockerCLI command.Cli, containerID string, o
return err
}
detachKeys := dockerCLI.ConfigFile().DetachKeys
if opts.DetachKeys != "" {
detachKeys = opts.DetachKeys
}
options := client.ContainerAttachOptions{
Stream: true,
Stdin: !opts.NoStdin && c.Config.OpenStdin,
+8
View File
@@ -27,6 +27,14 @@ func TestNewAttachCommandErrors(t *testing.T) {
return client.ContainerInspectResult{}, errors.New("something went wrong")
},
},
{
name: "invalid-detach-keys",
args: []string{"--detach-keys", "shift-b", "5cb5bb5e4a3b"},
expectedError: "invalid detach keys (shift-b):",
containerInspectFunc: func(containerID string) (client.ContainerInspectResult, error) {
return client.ContainerInspectResult{}, errors.New("something went wrong")
},
},
{
name: "client-stopped",
args: []string{"5cb5bb5e4a3b"},
+30 -41
View File
@@ -132,7 +132,6 @@ func runCreate(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet,
return nil
}
// FIXME(thaJeztah): this is the only code-path that uses APIClient.ImageCreate. Rewrite this to use the regular "pull" code (or vice-versa).
func pullImage(ctx context.Context, dockerCLI command.Cli, img string, options *createOptions) error {
encodedAuth, err := command.RetrieveAuthTokenFromImage(dockerCLI.ConfigFile(), img)
if err != nil {
@@ -177,8 +176,8 @@ func (cid *cidFile) Close() error {
if cid.written {
return nil
}
if err := os.Remove(cid.path); err != nil {
return fmt.Errorf("failed to remove the CID file '%s': %w", cid.path, err)
if err := os.Remove(cid.path); err != nil && !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("failed to remove the CID file: %w", err)
}
return nil
@@ -188,8 +187,8 @@ func (cid *cidFile) Write(id string) error {
if cid.file == nil {
return nil
}
if _, err := cid.file.Write([]byte(id)); err != nil {
return fmt.Errorf("failed to write the container ID to the file: %w", err)
if _, err := cid.file.WriteString(id); err != nil {
return fmt.Errorf("failed to write the container ID (%s) to file: %w", id, err)
}
cid.written = true
return nil
@@ -212,7 +211,7 @@ func newCIDFile(cidPath string) (*cidFile, error) {
}
//nolint:gocyclo
func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *containerConfig, options *createOptions) (containerID string, err error) {
func createContainer(ctx context.Context, dockerCLI command.Cli, containerCfg *containerConfig, options *createOptions) (containerID string, _ error) {
config := containerCfg.Config
hostConfig := containerCfg.HostConfig
networkingConfig := containerCfg.NetworkingConfig
@@ -221,8 +220,7 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
// TODO(thaJeztah): add a platform option-type / flag-type.
if options.platform != "" {
_, err = platforms.Parse(options.platform)
if err != nil {
if _, err := platforms.Parse(options.platform); err != nil {
return "", err
}
}
@@ -248,10 +246,11 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
if options.useAPISocket {
// We'll create two new mounts to handle this flag:
//
// 1. Mount the actual docker socket.
// 2. A synthezised ~/.docker/config.json with resolved tokens.
// 2. A synthesized ~/.docker/config.json with resolved tokens.
if dockerCli.ServerInfo().OSType == "windows" {
if dockerCLI.ServerInfo().OSType == "windows" {
return "", errors.New("flag --use-api-socket can't be used with a Windows Docker Engine")
}
@@ -286,18 +285,18 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
})
*/
var envvarPresent bool
for _, envvar := range containerCfg.Config.Env {
if strings.HasPrefix(envvar, "DOCKER_CONFIG=") {
envvarPresent = true
var envVarPresent bool
for _, envVar := range containerCfg.Config.Env {
if strings.HasPrefix(envVar, "DOCKER_CONFIG=") {
envVarPresent = true
}
}
// If the DOCKER_CONFIG env var is already present, we assume the client knows
// what they're doing and don't inject the creds.
if !envvarPresent {
if !envVarPresent {
// Resolve this here for later, ensuring we error our before we create the container.
creds, err := readCredentials(dockerCli)
creds, err := readCredentials(dockerCLI)
if err != nil {
return "", fmt.Errorf("resolving credentials failed: %w", err)
}
@@ -319,22 +318,15 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
platform = &p
}
pullAndTagImage := func() error {
if err := pullImage(ctx, dockerCli, config.Image, options); err != nil {
return err
}
return nil
}
if options.pull == PullImageAlways {
if err := pullAndTagImage(); err != nil {
if err := pullImage(ctx, dockerCLI, config.Image, options); err != nil {
return "", err
}
}
hostConfig.ConsoleSize[0], hostConfig.ConsoleSize[1] = dockerCli.Out().GetTtySize()
hostConfig.ConsoleSize[0], hostConfig.ConsoleSize[1] = dockerCLI.Out().GetTtySize()
response, err := dockerCli.Client().ContainerCreate(ctx, client.ContainerCreateOptions{
response, err := dockerCLI.Client().ContainerCreate(ctx, client.ContainerCreateOptions{
Name: options.name,
// Image: config.Image, // TODO(thaJeztah): pass image-ref separate
Platform: platform,
@@ -347,15 +339,15 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
if errdefs.IsNotFound(err) && namedRef != nil && options.pull == PullImageMissing {
if !options.quiet {
// we don't want to write to stdout anything apart from container.ID
_, _ = fmt.Fprintf(dockerCli.Err(), "Unable to find image '%s' locally\n", reference.FamiliarString(namedRef))
_, _ = fmt.Fprintf(dockerCLI.Err(), "Unable to find image '%s' locally\n", reference.FamiliarString(namedRef))
}
if err := pullAndTagImage(); err != nil {
if err := pullImage(ctx, dockerCLI, config.Image, options); err != nil {
return "", err
}
var retryErr error
response, retryErr = dockerCli.Client().ContainerCreate(ctx, client.ContainerCreateOptions{
response, retryErr = dockerCLI.Client().ContainerCreate(ctx, client.ContainerCreateOptions{
Name: options.name,
// Image: config.Image, // TODO(thaJeztah): pass image-ref separate
Platform: platform,
@@ -371,24 +363,20 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
}
}
containerID = response.ID
for _, w := range response.Warnings {
_, _ = fmt.Fprintln(dockerCli.Err(), "WARNING:", w)
}
err = containerIDFile.Write(containerID)
if options.useAPISocket && len(apiSocketCreds) > 0 {
// Create a new config file with just the auth.
newConfig := &configfile.ConfigFile{
if err := copyDockerConfigIntoContainer(ctx, dockerCLI.Client(), response.ID, dockerConfigPathInContainer, &configfile.ConfigFile{
AuthConfigs: apiSocketCreds,
}
if err := copyDockerConfigIntoContainer(ctx, dockerCli.Client(), containerID, dockerConfigPathInContainer, newConfig); err != nil {
return "", fmt.Errorf("injecting docker config.json into container failed: %w", err)
}); err != nil {
response.Warnings = append(response.Warnings, fmt.Sprintf("injecting docker config.json into container failed: %v", err))
}
}
for _, w := range response.Warnings {
_, _ = fmt.Fprintln(dockerCLI.Err(), "WARNING:", w)
}
return containerID, err
err = containerIDFile.Write(response.ID)
return response.ID, err
}
func validatePullOpt(val string) error {
@@ -428,6 +416,7 @@ func copyDockerConfigIntoContainer(ctx context.Context, apiClient client.APIClie
})
if _, err := io.Copy(tarWriter, &configBuf); err != nil {
_ = tarWriter.Close()
return fmt.Errorf("writing config to tar file for config copy: %w", err)
}
+24 -9
View File
@@ -5,6 +5,7 @@ import (
"errors"
"io"
"os"
"path/filepath"
"runtime"
"sort"
"strings"
@@ -42,17 +43,31 @@ func TestNewCIDFileWhenFileAlreadyExists(t *testing.T) {
}
func TestCIDFileCloseWithNoWrite(t *testing.T) {
tempdir := fs.NewDir(t, "test-cid-file")
defer tempdir.Remove()
// Closing should remove the file if it was not written to.
t.Run("closing should remove file", func(t *testing.T) {
filename := filepath.Join(t.TempDir(), "cidfile-1")
file, err := newCIDFile(filename)
assert.NilError(t, err)
assert.Check(t, is.Equal(file.path, filename))
path := tempdir.Join("cidfile")
file, err := newCIDFile(path)
assert.NilError(t, err)
assert.Check(t, is.Equal(file.path, path))
assert.NilError(t, file.Close())
_, err = os.Stat(filename)
assert.Check(t, os.IsNotExist(err))
})
assert.NilError(t, file.Close())
_, err = os.Stat(path)
assert.Check(t, os.IsNotExist(err))
// Closing (and removing) the file should not produce an error if the file no longer exists.
t.Run("close should remove file", func(t *testing.T) {
filename := filepath.Join(t.TempDir(), "cidfile-2")
file, err := newCIDFile(filename)
assert.NilError(t, err)
assert.Check(t, is.Equal(file.path, filename))
assert.NilError(t, os.Remove(filename))
_, err = os.Stat(filename)
assert.Check(t, os.IsNotExist(err))
assert.NilError(t, file.Close())
})
}
func TestCIDFileCloseWithWrite(t *testing.T) {
+3
View File
@@ -248,5 +248,8 @@ func parseExec(execOpts ExecOptions, configFile *configfile.ConfigFile) (*client
} else {
execOptions.DetachKeys = configFile.DetachKeys
}
if err := validateDetachKeys(execOpts.DetachKeys); err != nil {
return nil, err
}
return execOptions, nil
}
+22 -12
View File
@@ -92,21 +92,21 @@ TWO=2
},
{
options: withDefaultOpts(ExecOptions{Detach: true}),
configFile: configfile.ConfigFile{DetachKeys: "de"},
configFile: configfile.ConfigFile{DetachKeys: "ctrl-d,e"},
expected: client.ExecCreateOptions{
Cmd: []string{"command"},
DetachKeys: "de",
DetachKeys: "ctrl-d,e",
},
},
{
options: withDefaultOpts(ExecOptions{
Detach: true,
DetachKeys: "ab",
DetachKeys: "ctrl-a,b",
}),
configFile: configfile.ConfigFile{DetachKeys: "de"},
configFile: configfile.ConfigFile{DetachKeys: "ctrl-d,e"},
expected: client.ExecCreateOptions{
Cmd: []string{"command"},
DetachKeys: "ab",
DetachKeys: "ctrl-a,b",
},
},
{
@@ -147,13 +147,23 @@ TWO=2
}
}
func TestParseExecNoSuchFile(t *testing.T) {
execOpts := withDefaultOpts(ExecOptions{})
assert.Check(t, execOpts.EnvFile.Set("no-such-env-file"))
execConfig, err := parseExec(execOpts, &configfile.ConfigFile{})
assert.ErrorContains(t, err, "no-such-env-file")
assert.Check(t, os.IsNotExist(err))
assert.Check(t, execConfig == nil)
func TestParseExecErrors(t *testing.T) {
t.Run("missing env-file", func(t *testing.T) {
execOpts := withDefaultOpts(ExecOptions{})
assert.Check(t, execOpts.EnvFile.Set("no-such-env-file"))
execConfig, err := parseExec(execOpts, &configfile.ConfigFile{})
assert.ErrorContains(t, err, "no-such-env-file")
assert.Check(t, os.IsNotExist(err))
assert.Check(t, execConfig == nil)
})
t.Run("invalid detach keys", func(t *testing.T) {
execOpts := withDefaultOpts(ExecOptions{
DetachKeys: "shift-a",
})
execConfig, err := parseExec(execOpts, &configfile.ConfigFile{})
assert.Check(t, is.ErrorContains(err, "invalid detach keys (shift-a):"))
assert.Check(t, is.Nil(execConfig))
})
}
func TestRunExec(t *testing.T) {
+18 -6
View File
@@ -30,6 +30,16 @@ func (r *readCloserWrapper) Close() error {
return r.closer()
}
func validateDetachKeys(keys string) error {
if keys == "" {
return nil
}
if _, err := term.ToBytes(keys); err != nil {
return invalidParameter(fmt.Errorf("invalid detach keys (%s): %w", keys, err))
}
return nil
}
// A hijackedIOStreamer handles copying input to and output from streams to the
// connection.
type hijackedIOStreamer struct {
@@ -82,13 +92,15 @@ func (h *hijackedIOStreamer) stream(ctx context.Context) error {
}
}
func (h *hijackedIOStreamer) setupInput() (restore func(), err error) {
func (h *hijackedIOStreamer) setupInput() (restore func(), _ error) {
if h.inputStream == nil || !h.tty {
// No need to setup input TTY.
// The restore func is a nop.
return func() {}, nil
}
if err := validateDetachKeys(h.detachKeys); err != nil {
return nil, err
}
if err := setRawTerminal(h.streams); err != nil {
return nil, fmt.Errorf("unable to set IO streams as raw terminal: %s", err)
}
@@ -103,11 +115,11 @@ func (h *hijackedIOStreamer) setupInput() (restore func(), err error) {
// Use default escape keys if an invalid sequence is given.
escapeKeys := defaultEscapeKeys
if h.detachKeys != "" {
customEscapeKeys, err := term.ToBytes(h.detachKeys)
var err error
escapeKeys, err = term.ToBytes(h.detachKeys)
if err != nil {
logrus.Warnf("invalid detach escape keys, using default: %s", err)
} else {
escapeKeys = customEscapeKeys
restore()
return nil, err
}
}
+4 -4
View File
@@ -795,7 +795,7 @@ func parseNetworkOpts(copts *containerOptions) (map[string]*network.EndpointSett
// and only a single network is specified, omit the endpoint-configuration
// on the client (the daemon will still create it when creating the container)
if i == 0 && len(copts.netMode.Value()) == 1 {
if ep == nil || reflect.DeepEqual(*ep, network.EndpointSettings{}) {
if ep == nil || reflect.ValueOf(*ep).IsZero() {
continue
}
}
@@ -947,11 +947,11 @@ func parseSecurityOpts(securityOpts []string) ([]string, error) {
if err != nil {
return securityOpts, fmt.Errorf("opening seccomp profile (%s) failed: %w", v, err)
}
b := bytes.NewBuffer(nil)
if err := json.Compact(b, f); err != nil {
var b bytes.Buffer
if err := json.Compact(&b, f); err != nil {
return securityOpts, fmt.Errorf("compacting json for seccomp profile (%s) failed: %w", v, err)
}
securityOpts[key] = fmt.Sprintf("seccomp=%s", b.Bytes())
securityOpts[key] = "seccomp=" + b.String()
}
}
}
+8 -5
View File
@@ -140,6 +140,14 @@ func runContainer(ctx context.Context, dockerCli command.Cli, runOpts *runOption
config.StdinOnce = false
}
detachKeys := runOpts.detachKeys
if detachKeys == "" {
detachKeys = dockerCli.ConfigFile().DetachKeys
}
if err := validateDetachKeys(runOpts.detachKeys); err != nil {
return err
}
containerID, err := createContainer(ctx, dockerCli, containerCfg, &runOpts.createOptions)
if err != nil {
return toStatusError(err)
@@ -172,11 +180,6 @@ func runContainer(ctx context.Context, dockerCli command.Cli, runOpts *runOption
}()
}
if attach {
detachKeys := dockerCli.ConfigFile().DetachKeys
if runOpts.detachKeys != "" {
detachKeys = runOpts.detachKeys
}
// ctx should not be cancellable here, as this would kill the stream to the container
// and we want to keep the stream open until the process in the container exits or until
// the user forcefully terminates the CLI.
+5
View File
@@ -34,6 +34,11 @@ func TestRunValidateFlags(t *testing.T) {
args: []string{"--attach", "stdin", "--detach", "myimage"},
expectedErr: "conflicting options: cannot specify both --attach and --detach",
},
{
name: "with invalid --detach-keys",
args: []string{"--detach-keys", "shift-a", "myimage"},
expectedErr: "invalid detach keys (shift-a):",
},
} {
t.Run(tc.name, func(t *testing.T) {
cmd := newRunCommand(test.NewFakeCli(&fakeClient{}))
+8 -5
View File
@@ -70,6 +70,14 @@ func RunStart(ctx context.Context, dockerCli command.Cli, opts *StartOptions) er
ctx, cancelFun := context.WithCancel(ctx)
defer cancelFun()
detachKeys := opts.DetachKeys
if detachKeys == "" {
detachKeys = dockerCli.ConfigFile().DetachKeys
}
if err := validateDetachKeys(detachKeys); err != nil {
return err
}
switch {
case opts.Attach || opts.OpenStdin:
// We're going to attach to a container.
@@ -93,11 +101,6 @@ func RunStart(ctx context.Context, dockerCli command.Cli, opts *StartOptions) er
defer signal.StopCatch(sigc)
}
detachKeys := dockerCli.ConfigFile().DetachKeys
if opts.DetachKeys != "" {
detachKeys = opts.DetachKeys
}
options := client.ContainerAttachOptions{
Stream: true,
Stdin: opts.OpenStdin && c.Container.Config.OpenStdin,
+38
View File
@@ -0,0 +1,38 @@
package container
import (
"io"
"testing"
"github.com/docker/cli/internal/test"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestStartValidateFlags(t *testing.T) {
for _, tc := range []struct {
name string
args []string
expectedErr string
}{
{
name: "with invalid --detach-keys",
args: []string{"--detach-keys", "shift-a", "myimage"},
expectedErr: "invalid detach keys (shift-a):",
},
} {
t.Run(tc.name, func(t *testing.T) {
cmd := newStartCommand(test.NewFakeCli(&fakeClient{}))
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
cmd.SetArgs(tc.args)
err := cmd.Execute()
if tc.expectedErr != "" {
assert.Check(t, is.ErrorContains(err, tc.expectedErr))
} else {
assert.Check(t, is.Nil(err))
}
})
}
}
+13 -17
View File
@@ -4,8 +4,10 @@
package formatter
import (
"reflect"
"testing"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
type dummy struct{}
@@ -45,24 +47,18 @@ var dummyExpected = map[string]any{
func TestMarshalMap(t *testing.T) {
d := dummy{}
m, err := marshalMap(&d)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(dummyExpected, m) {
t.Fatalf("expected %+v, got %+v",
dummyExpected, m)
}
assert.NilError(t, err)
assert.Check(t, is.DeepEqual(m, dummyExpected))
}
func TestMarshalMapBad(t *testing.T) {
if _, err := marshalMap(nil); err == nil {
t.Fatal("expected an error (argument is nil)")
}
if _, err := marshalMap(dummy{}); err == nil {
t.Fatal("expected an error (argument is non-pointer)")
}
_, err := marshalMap(nil)
assert.Check(t, is.Error(err, "expected a pointer to a struct, got invalid"), "expected an error (argument is nil)")
_, err = marshalMap(dummy{})
assert.Check(t, is.Error(err, "expected a pointer to a struct, got struct"), "expected an error (argument is non-pointer)")
x := 42
if _, err := marshalMap(&x); err == nil {
t.Fatal("expected an error (argument is a pointer to non-struct)")
}
_, err = marshalMap(&x)
assert.Check(t, is.Error(err, "expected a pointer to a struct, got a pointer to int"), "expected an error (argument is a pointer to non-struct)")
}
+1 -1
View File
@@ -480,7 +480,7 @@ func Compress(buildCtx io.ReadCloser) (io.ReadCloser, error) {
pipeReader, pipeWriter := io.Pipe()
go func() {
compressWriter, err := compression.CompressStream(pipeWriter, archive.Gzip)
compressWriter, err := compression.CompressStream(pipeWriter, compression.Gzip)
if err != nil {
_ = pipeWriter.CloseWithError(err)
}
+12 -5
View File
@@ -1,9 +1,9 @@
package node
import (
"bytes"
"encoding/base64"
"fmt"
"reflect"
"strings"
"github.com/docker/cli/cli/command/formatter"
@@ -170,15 +170,23 @@ func (c *nodeContext) ManagerStatus() string {
}
func (c *nodeContext) TLSStatus() string {
if c.info.Cluster == nil || reflect.DeepEqual(c.info.Cluster.TLSInfo, swarm.TLSInfo{}) || reflect.DeepEqual(c.n.Description.TLSInfo, swarm.TLSInfo{}) {
if c.info.Cluster == nil || isEmptyTLSInfo(c.info.Cluster.TLSInfo) || isEmptyTLSInfo(c.n.Description.TLSInfo) {
return "Unknown"
}
if reflect.DeepEqual(c.n.Description.TLSInfo, c.info.Cluster.TLSInfo) {
if equalTLSInfo(c.n.Description.TLSInfo, c.info.Cluster.TLSInfo) {
return "Ready"
}
return "Needs Rotation"
}
func isEmptyTLSInfo(t swarm.TLSInfo) bool {
return t.TrustRoot == "" && len(t.CertIssuerSubject) == 0 && len(t.CertIssuerPublicKey) == 0
}
func equalTLSInfo(t, o swarm.TLSInfo) bool {
return t.TrustRoot == o.TrustRoot && bytes.Equal(t.CertIssuerSubject, o.CertIssuerSubject) && bytes.Equal(t.CertIssuerPublicKey, o.CertIssuerPublicKey)
}
func (c *nodeContext) EngineVersion() string {
return c.n.Description.Engine.EngineVersion
}
@@ -320,8 +328,7 @@ func (ctx *nodeInspectContext) EngineVersion() string {
}
func (ctx *nodeInspectContext) HasTLSInfo() bool {
tlsInfo := ctx.Node.Description.TLSInfo
return !reflect.DeepEqual(tlsInfo, swarm.TLSInfo{})
return !isEmptyTLSInfo(ctx.Node.Description.TLSInfo)
}
func (ctx *nodeInspectContext) TLSInfoTrustRoot() string {
+1 -5
View File
@@ -200,7 +200,7 @@ func RetrieveAuthTokenFromImage(cfg *configfile.ConfigFile, image string) (strin
return "", err
}
encodedAuth, err := authconfig.Encode(registrytypes.AuthConfig{
return authconfig.Encode(registrytypes.AuthConfig{
Username: authConfig.Username,
Password: authConfig.Password,
ServerAddress: authConfig.ServerAddress,
@@ -210,10 +210,6 @@ func RetrieveAuthTokenFromImage(cfg *configfile.ConfigFile, image string) (strin
IdentityToken: authConfig.IdentityToken,
RegistryToken: authConfig.RegistryToken,
})
if err != nil {
return "", err
}
return encodedAuth, nil
}
// getAuthConfigKey special-cases using the full index address of the official
+1 -1
View File
@@ -197,7 +197,7 @@ func loginUser(ctx context.Context, dockerCLI command.Cli, opts loginOptions, de
// will hit this if you attempt docker login from mintty where stdin
// is a pipe, not a character based console.
if (opts.user == "" || opts.password == "") && !dockerCLI.In().IsTerminal() {
return "", errors.New("error: cannot perform an interactive login from a non TTY device")
return "", errors.New("error: cannot perform an interactive login from a non-TTY device")
}
// If we're logging into the index server and the user didn't provide a username or password, use the device flow
+6 -6
View File
@@ -127,7 +127,7 @@ func TestRunLogin(t *testing.T) {
input: loginOptions{
serverAddress: "reg1",
},
expectedErr: "error: cannot perform an interactive login from a non TTY device",
expectedErr: "error: cannot perform an interactive login from a non-TTY device",
},
{
doc: "store valid username and password",
@@ -334,19 +334,19 @@ func TestLoginNonInteractive(t *testing.T) {
doc: "error - w/o user w/o pass ",
username: false,
password: false,
expectedErr: "error: cannot perform an interactive login from a non TTY device",
expectedErr: "error: cannot perform an interactive login from a non-TTY device",
},
{
doc: "error - w/ user w/o pass",
username: true,
password: false,
expectedErr: "error: cannot perform an interactive login from a non TTY device",
expectedErr: "error: cannot perform an interactive login from a non-TTY device",
},
{
doc: "error - w/o user w/ pass",
username: false,
password: true,
expectedErr: "error: cannot perform an interactive login from a non TTY device",
expectedErr: "error: cannot perform an interactive login from a non-TTY device",
},
}
@@ -403,13 +403,13 @@ func TestLoginNonInteractive(t *testing.T) {
doc: "error - w/ user w/o pass",
username: true,
password: false,
expectedErr: "error: cannot perform an interactive login from a non TTY device",
expectedErr: "error: cannot perform an interactive login from a non-TTY device",
},
{
doc: "error - w/o user w/ pass",
username: false,
password: true,
expectedErr: "error: cannot perform an interactive login from a non TTY device",
expectedErr: "error: cannot perform an interactive login from a non-TTY device",
},
}
+2 -2
View File
@@ -905,9 +905,9 @@ func addServiceFlags(flags *pflag.FlagSet, options *serviceOptions, defaultFlagV
flags.Int64Var(&options.resources.limitPids, flagLimitPids, 0, "Limit maximum number of processes (default 0 = unlimited)")
flags.SetAnnotation(flagLimitPids, "version", []string{"1.41"})
flags.Var(&options.resources.swapBytes, flagSwapBytes, "Swap Bytes (-1 for unlimited)")
flags.SetAnnotation(flagLimitPids, "version", []string{"1.52"})
flags.SetAnnotation(flagSwapBytes, "version", []string{"1.52"})
flags.Int64Var(&options.resources.memSwappiness, flagMemSwappiness, -1, "Tune memory swappiness (0-100), -1 to reset to default")
flags.SetAnnotation(flagLimitPids, "version", []string{"1.52"})
flags.SetAnnotation(flagMemSwappiness, "version", []string{"1.52"})
flags.Var(&options.stopGrace, flagStopGracePeriod, flagDesc(flagStopGracePeriod, "Time to wait before force killing a container (ns|us|ms|s|m|h)"))
flags.Var(&options.replicas, flagReplicas, "Number of tasks")
+17 -17
View File
@@ -4,8 +4,8 @@ import (
"context"
"fmt"
"net/netip"
"reflect"
"sort"
"strconv"
"testing"
"time"
@@ -368,23 +368,23 @@ func TestUpdateHealthcheckTable(t *testing.T) {
err: "--no-healthcheck conflicts with --health-* options",
},
}
for i, c := range testCases {
flags := newUpdateCommand(nil).Flags()
for _, flag := range c.flags {
flags.Set(flag[0], flag[1])
}
cspec := &swarm.ContainerSpec{
Healthcheck: c.initial,
}
err := updateHealthcheck(flags, cspec)
if c.err != "" {
assert.Error(t, err, c.err)
} else {
assert.NilError(t, err)
if !reflect.DeepEqual(cspec.Healthcheck, c.expected) {
t.Errorf("incorrect result for test %d, expected health config:\n\t%#v\ngot:\n\t%#v", i, c.expected, cspec.Healthcheck)
for i, tc := range testCases {
t.Run(strconv.Itoa(i), func(t *testing.T) {
flags := newUpdateCommand(nil).Flags()
for _, flag := range tc.flags {
assert.Check(t, flags.Set(flag[0], flag[1]))
}
}
cspec := &swarm.ContainerSpec{
Healthcheck: tc.initial,
}
err := updateHealthcheck(flags, cspec)
if tc.err != "" {
assert.Error(t, err, tc.err)
} else {
assert.NilError(t, err)
assert.Check(t, is.DeepEqual(cspec.Healthcheck, tc.expected))
}
})
}
}
+7
View File
@@ -397,6 +397,13 @@ func prettyPrintServerInfo(streams command.Streams, info *dockerInfo) {
}
}
if info.NRI != nil {
fprintln(output, " NRI:")
for _, v := range info.NRI.Info {
fprintf(output, " %s: %s\n", v[0], v[1])
}
}
fprintln(output)
for _, w := range info.Warnings {
fprintln(streams.Err(), w)
+6
View File
@@ -126,6 +126,12 @@ var sampleInfoNoSwarm = system.Info{
{"ReloadedAt", "2025-07-16T16:59:14Z"},
},
},
NRI: &system.NRIInfo{
Info: [][2]string{
{"plugin-path", "/usr/libexec/docker/nri-plugins"},
{"plugin-config-path", "/etc/docker/nri/conf.d"},
},
},
CDISpecDirs: []string{"/etc/cdi", "/var/run/cdi"},
}
+3
View File
@@ -54,4 +54,7 @@ Server:
Base: 10.123.0.0/16, Size: 24
Firewall Backend: nftables+firewalld
ReloadedAt: 2025-07-16T16:59:14Z
NRI:
plugin-path: /usr/libexec/docker/nri-plugins
plugin-config-path: /etc/docker/nri/conf.d
+1 -1
View File
@@ -1 +1 @@
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"overlay2","DriverStatus":[["Backing Filesystem","extfs"],["Supports d_type","true"],["Using metacopy","false"],["Native Overlay Diff","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa"},"SecurityOptions":["foo="],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"FirewallBackend":{"Driver":"nftables+firewalld","Info":[["ReloadedAt","2025-07-16T16:59:14Z"]]},"CDISpecDirs":["/etc/cdi","/var/run/cdi"],"Warnings":null,"ServerErrors":["a server error occurred"],"ClientInfo":{"Debug":false,"Context":"","Plugins":[],"Warnings":null}}
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"overlay2","DriverStatus":[["Backing Filesystem","extfs"],["Supports d_type","true"],["Using metacopy","false"],["Native Overlay Diff","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa"},"SecurityOptions":["foo="],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"FirewallBackend":{"Driver":"nftables+firewalld","Info":[["ReloadedAt","2025-07-16T16:59:14Z"]]},"CDISpecDirs":["/etc/cdi","/var/run/cdi"],"NRI":{"Info":[["plugin-path","/usr/libexec/docker/nri-plugins"],["plugin-config-path","/etc/docker/nri/conf.d"]]},"Warnings":null,"ServerErrors":["a server error occurred"],"ClientInfo":{"Debug":false,"Context":"","Plugins":[],"Warnings":null}}
@@ -1 +1 @@
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"overlay2","DriverStatus":[["Backing Filesystem","extfs"],["Supports d_type","true"],["Using metacopy","false"],["Native Overlay Diff","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"FirewallBackend":{"Driver":"nftables+firewalld","Info":[["ReloadedAt","2025-07-16T16:59:14Z"]]},"CDISpecDirs":["/etc/cdi","/var/run/cdi"],"Warnings":["WARNING: No memory limit support","WARNING: No swap limit support","WARNING: No oom kill disable support","WARNING: No cpu cfs quota support","WARNING: No cpu cfs period support","WARNING: No cpu shares support","WARNING: No cpuset support","WARNING: IPv4 forwarding is disabled"],"ClientInfo":{"Debug":true,"Platform":{"Name":"Docker Engine - Community"},"Version":"24.0.0","Context":"default","Plugins":[],"Warnings":null}}
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"overlay2","DriverStatus":[["Backing Filesystem","extfs"],["Supports d_type","true"],["Using metacopy","false"],["Native Overlay Diff","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"FirewallBackend":{"Driver":"nftables+firewalld","Info":[["ReloadedAt","2025-07-16T16:59:14Z"]]},"CDISpecDirs":["/etc/cdi","/var/run/cdi"],"NRI":{"Info":[["plugin-path","/usr/libexec/docker/nri-plugins"],["plugin-config-path","/etc/docker/nri/conf.d"]]},"Warnings":["WARNING: No memory limit support","WARNING: No swap limit support","WARNING: No oom kill disable support","WARNING: No cpu cfs quota support","WARNING: No cpu cfs period support","WARNING: No cpu shares support","WARNING: No cpuset support","WARNING: IPv4 forwarding is disabled"],"ClientInfo":{"Debug":true,"Platform":{"Name":"Docker Engine - Community"},"Version":"24.0.0","Context":"default","Plugins":[],"Warnings":null}}
@@ -59,4 +59,7 @@ Server:
Base: 10.123.0.0/16, Size: 24
Firewall Backend: nftables+firewalld
ReloadedAt: 2025-07-16T16:59:14Z
NRI:
plugin-path: /usr/libexec/docker/nri-plugins
plugin-config-path: /etc/docker/nri/conf.d
@@ -1 +1 @@
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"overlay2","DriverStatus":[["Backing Filesystem","extfs"],["Supports d_type","true"],["Using metacopy","false"],["Native Overlay Diff","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"FirewallBackend":{"Driver":"nftables+firewalld","Info":[["ReloadedAt","2025-07-16T16:59:14Z"]]},"CDISpecDirs":["/etc/cdi","/var/run/cdi"],"Warnings":null,"ClientInfo":{"Debug":true,"Platform":{"Name":"Docker Engine - Community"},"Version":"24.0.0","Context":"default","Plugins":[],"Warnings":null}}
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"overlay2","DriverStatus":[["Backing Filesystem","extfs"],["Supports d_type","true"],["Using metacopy","false"],["Native Overlay Diff","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"FirewallBackend":{"Driver":"nftables+firewalld","Info":[["ReloadedAt","2025-07-16T16:59:14Z"]]},"CDISpecDirs":["/etc/cdi","/var/run/cdi"],"NRI":{"Info":[["plugin-path","/usr/libexec/docker/nri-plugins"],["plugin-config-path","/etc/docker/nri/conf.d"]]},"Warnings":null,"ClientInfo":{"Debug":true,"Platform":{"Name":"Docker Engine - Community"},"Version":"24.0.0","Context":"default","Plugins":[],"Warnings":null}}
@@ -64,4 +64,7 @@ Server:
Base: 10.123.0.0/16, Size: 24
Firewall Backend: nftables+firewalld
ReloadedAt: 2025-07-16T16:59:14Z
NRI:
plugin-path: /usr/libexec/docker/nri-plugins
plugin-config-path: /etc/docker/nri/conf.d
@@ -1 +1 @@
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"overlay2","DriverStatus":[["Backing Filesystem","extfs"],["Supports d_type","true"],["Using metacopy","false"],["Native Overlay Diff","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"FirewallBackend":{"Driver":"nftables+firewalld","Info":[["ReloadedAt","2025-07-16T16:59:14Z"]]},"CDISpecDirs":["/etc/cdi","/var/run/cdi"],"Warnings":null,"ClientInfo":{"Debug":false,"Context":"default","Plugins":[{"SchemaVersion":"0.1.0","Vendor":"ACME Corp","Version":"0.1.0","ShortDescription":"unit test is good","Name":"goodplugin","Path":"/path/to/docker-goodplugin"},{"SchemaVersion":"0.1.0","Vendor":"ACME Corp","ShortDescription":"this plugin has no version","Name":"unversionedplugin","Path":"/path/to/docker-unversionedplugin"},{"Name":"badplugin","Path":"/path/to/docker-badplugin","Err":"something wrong"}],"Warnings":null}}
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"overlay2","DriverStatus":[["Backing Filesystem","extfs"],["Supports d_type","true"],["Using metacopy","false"],["Native Overlay Diff","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"FirewallBackend":{"Driver":"nftables+firewalld","Info":[["ReloadedAt","2025-07-16T16:59:14Z"]]},"CDISpecDirs":["/etc/cdi","/var/run/cdi"],"NRI":{"Info":[["plugin-path","/usr/libexec/docker/nri-plugins"],["plugin-config-path","/etc/docker/nri/conf.d"]]},"Warnings":null,"ClientInfo":{"Debug":false,"Context":"default","Plugins":[{"SchemaVersion":"0.1.0","Vendor":"ACME Corp","Version":"0.1.0","ShortDescription":"unit test is good","Name":"goodplugin","Path":"/path/to/docker-goodplugin"},{"SchemaVersion":"0.1.0","Vendor":"ACME Corp","ShortDescription":"this plugin has no version","Name":"unversionedplugin","Path":"/path/to/docker-unversionedplugin"},{"Name":"badplugin","Path":"/path/to/docker-badplugin","Err":"something wrong"}],"Warnings":null}}
@@ -59,4 +59,7 @@ Server:
Base: 10.123.0.0/16, Size: 24
Firewall Backend: nftables+firewalld
ReloadedAt: 2025-07-16T16:59:14Z
NRI:
plugin-path: /usr/libexec/docker/nri-plugins
plugin-config-path: /etc/docker/nri/conf.d
@@ -1 +1 @@
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"overlay2","DriverStatus":[["Backing Filesystem","extfs"],["Supports d_type","true"],["Using metacopy","false"],["Native Overlay Diff","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"FirewallBackend":{"Driver":"nftables+firewalld","Info":[["ReloadedAt","2025-07-16T16:59:14Z"]]},"CDISpecDirs":["/etc/cdi","/var/run/cdi"],"DiscoveredDevices":[{"Source":"cdi","ID":"com.example.device1"},{"Source":"cdi","ID":"nvidia.com/gpu=gpu0"}],"Warnings":null}
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"overlay2","DriverStatus":[["Backing Filesystem","extfs"],["Supports d_type","true"],["Using metacopy","false"],["Native Overlay Diff","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"FirewallBackend":{"Driver":"nftables+firewalld","Info":[["ReloadedAt","2025-07-16T16:59:14Z"]]},"CDISpecDirs":["/etc/cdi","/var/run/cdi"],"DiscoveredDevices":[{"Source":"cdi","ID":"com.example.device1"},{"Source":"cdi","ID":"nvidia.com/gpu=gpu0"}],"NRI":{"Info":[["plugin-path","/usr/libexec/docker/nri-plugins"],["plugin-config-path","/etc/docker/nri/conf.d"]]},"Warnings":null}
@@ -56,4 +56,7 @@ Server:
Base: 10.123.0.0/16, Size: 24
Firewall Backend: nftables+firewalld
ReloadedAt: 2025-07-16T16:59:14Z
NRI:
plugin-path: /usr/libexec/docker/nri-plugins
plugin-config-path: /etc/docker/nri/conf.d
@@ -56,4 +56,7 @@ Server:
Base: 10.123.0.0/16, Size: 24
Firewall Backend: nftables+firewalld
ReloadedAt: 2025-07-16T16:59:14Z
NRI:
plugin-path: /usr/libexec/docker/nri-plugins
plugin-config-path: /etc/docker/nri/conf.d
@@ -80,4 +80,7 @@ Server:
Base: 10.123.0.0/16, Size: 24
Firewall Backend: nftables+firewalld
ReloadedAt: 2025-07-16T16:59:14Z
NRI:
plugin-path: /usr/libexec/docker/nri-plugins
plugin-config-path: /etc/docker/nri/conf.d
@@ -1 +1 @@
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"overlay2","DriverStatus":[["Backing Filesystem","extfs"],["Supports d_type","true"],["Using metacopy","false"],["Native Overlay Diff","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"qo2dfdig9mmxqkawulggepdih","NodeAddr":"165.227.107.89","LocalNodeState":"active","ControlAvailable":true,"Error":"","RemoteManagers":[{"NodeID":"qo2dfdig9mmxqkawulggepdih","Addr":"165.227.107.89:2377"}],"Nodes":1,"Managers":1,"Cluster":{"ID":"9vs5ygs0gguyyec4iqf2314c0","Version":{"Index":11},"CreatedAt":"2017-08-24T17:34:19.278062352Z","UpdatedAt":"2017-08-24T17:34:42.398815481Z","Spec":{"Name":"default","Labels":null,"Orchestration":{"TaskHistoryRetentionLimit":5},"Raft":{"SnapshotInterval":10000,"KeepOldSnapshots":0,"LogEntriesForSlowFollowers":500,"ElectionTick":3,"HeartbeatTick":1},"Dispatcher":{"HeartbeatPeriod":5000000000},"CAConfig":{"NodeCertExpiry":7776000000000000},"TaskDefaults":{},"EncryptionConfig":{"AutoLockManagers":true}},"TLSInfo":{"TrustRoot":"\n-----BEGIN CERTIFICATE-----\nMIIBajCCARCgAwIBAgIUaFCW5xsq8eyiJ+Pmcv3MCflMLnMwCgYIKoZIzj0EAwIw\nEzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTcwODI0MTcyOTAwWhcNMzcwODE5MTcy\nOTAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH\nA0IABDy7NebyUJyUjWJDBUdnZoV6GBxEGKO4TZPNDwnxDxJcUdLVaB7WGa4/DLrW\nUfsVgh1JGik2VTiLuTMA1tLlNPOjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB\nAf8EBTADAQH/MB0GA1UdDgQWBBQl16XFtaaXiUAwEuJptJlDjfKskDAKBggqhkjO\nPQQDAgNIADBFAiEAo9fTQNM5DP9bHVcTJYfl2Cay1bFu1E+lnpmN+EYJfeACIGKH\n1pCUkZ+D0IB6CiEZGWSHyLuXPM1rlP+I5KuS7sB8\n-----END CERTIFICATE-----\n","CertIssuerSubject":"MBMxETAPBgNVBAMTCHN3YXJtLWNh","CertIssuerPublicKey":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPLs15vJQnJSNYkMFR2dmhXoYHEQYo7hNk80PCfEPElxR0tVoHtYZrj8MutZR+xWCHUkaKTZVOIu5MwDW0uU08w=="},"RootRotationInProgress":false,"DefaultAddrPool":null,"SubnetSize":0,"DataPathPort":0}},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"FirewallBackend":{"Driver":"nftables+firewalld","Info":[["ReloadedAt","2025-07-16T16:59:14Z"]]},"CDISpecDirs":["/etc/cdi","/var/run/cdi"],"Warnings":null,"ClientInfo":{"Debug":false,"Context":"default","Plugins":[],"Warnings":null}}
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"overlay2","DriverStatus":[["Backing Filesystem","extfs"],["Supports d_type","true"],["Using metacopy","false"],["Native Overlay Diff","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"qo2dfdig9mmxqkawulggepdih","NodeAddr":"165.227.107.89","LocalNodeState":"active","ControlAvailable":true,"Error":"","RemoteManagers":[{"NodeID":"qo2dfdig9mmxqkawulggepdih","Addr":"165.227.107.89:2377"}],"Nodes":1,"Managers":1,"Cluster":{"ID":"9vs5ygs0gguyyec4iqf2314c0","Version":{"Index":11},"CreatedAt":"2017-08-24T17:34:19.278062352Z","UpdatedAt":"2017-08-24T17:34:42.398815481Z","Spec":{"Name":"default","Labels":null,"Orchestration":{"TaskHistoryRetentionLimit":5},"Raft":{"SnapshotInterval":10000,"KeepOldSnapshots":0,"LogEntriesForSlowFollowers":500,"ElectionTick":3,"HeartbeatTick":1},"Dispatcher":{"HeartbeatPeriod":5000000000},"CAConfig":{"NodeCertExpiry":7776000000000000},"TaskDefaults":{},"EncryptionConfig":{"AutoLockManagers":true}},"TLSInfo":{"TrustRoot":"\n-----BEGIN CERTIFICATE-----\nMIIBajCCARCgAwIBAgIUaFCW5xsq8eyiJ+Pmcv3MCflMLnMwCgYIKoZIzj0EAwIw\nEzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTcwODI0MTcyOTAwWhcNMzcwODE5MTcy\nOTAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH\nA0IABDy7NebyUJyUjWJDBUdnZoV6GBxEGKO4TZPNDwnxDxJcUdLVaB7WGa4/DLrW\nUfsVgh1JGik2VTiLuTMA1tLlNPOjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB\nAf8EBTADAQH/MB0GA1UdDgQWBBQl16XFtaaXiUAwEuJptJlDjfKskDAKBggqhkjO\nPQQDAgNIADBFAiEAo9fTQNM5DP9bHVcTJYfl2Cay1bFu1E+lnpmN+EYJfeACIGKH\n1pCUkZ+D0IB6CiEZGWSHyLuXPM1rlP+I5KuS7sB8\n-----END CERTIFICATE-----\n","CertIssuerSubject":"MBMxETAPBgNVBAMTCHN3YXJtLWNh","CertIssuerPublicKey":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPLs15vJQnJSNYkMFR2dmhXoYHEQYo7hNk80PCfEPElxR0tVoHtYZrj8MutZR+xWCHUkaKTZVOIu5MwDW0uU08w=="},"RootRotationInProgress":false,"DefaultAddrPool":null,"SubnetSize":0,"DataPathPort":0}},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"FirewallBackend":{"Driver":"nftables+firewalld","Info":[["ReloadedAt","2025-07-16T16:59:14Z"]]},"CDISpecDirs":["/etc/cdi","/var/run/cdi"],"NRI":{"Info":[["plugin-path","/usr/libexec/docker/nri-plugins"],["plugin-config-path","/etc/docker/nri/conf.d"]]},"Warnings":null,"ClientInfo":{"Debug":false,"Context":"default","Plugins":[],"Warnings":null}}
+4 -3
View File
@@ -4,14 +4,15 @@ import (
"bytes"
"context"
"io"
"reflect"
"strings"
"testing"
"github.com/docker/cli/cli/streams"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/spf13/cobra"
"go.opentelemetry.io/otel/attribute"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func setupCobraCommands() (*cobra.Command, *cobra.Command, *cobra.Command) {
@@ -139,7 +140,7 @@ func TestStdioAttributes(t *testing.T) {
cli.Out().SetIsTerminal(tc.stdoutTty)
actual := stdioAttributes(cli)
assert.Check(t, reflect.DeepEqual(actual, tc.expected))
assert.Check(t, is.DeepEqual(actual, tc.expected, cmpopts.EquateComparable(attribute.Value{})))
})
}
}
@@ -179,7 +180,7 @@ func TestAttributesFromError(t *testing.T) {
t.Run(tc.testName, func(t *testing.T) {
t.Parallel()
actual := attributesFromError(tc.err)
assert.Check(t, reflect.DeepEqual(actual, tc.expected))
assert.Check(t, is.DeepEqual(actual, tc.expected, cmpopts.EquateComparable(attribute.Value{})))
})
}
}
+6 -3
View File
@@ -1,10 +1,13 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.24
package volume
import (
"errors"
"fmt"
"io"
"reflect"
"maps"
"sort"
"strings"
"testing"
@@ -124,10 +127,10 @@ func TestVolumeCreateWithFlags(t *testing.T) {
if options.Driver != expectedDriver {
return client.VolumeCreateResult{}, fmt.Errorf("expected driver %q, got %q", expectedDriver, options.Driver)
}
if !reflect.DeepEqual(options.DriverOpts, expectedOpts) {
if !maps.Equal(options.DriverOpts, expectedOpts) {
return client.VolumeCreateResult{}, fmt.Errorf("expected drivers opts %v, got %v", expectedOpts, options.DriverOpts)
}
if !reflect.DeepEqual(options.Labels, expectedLabels) {
if !maps.Equal(options.Labels, expectedLabels) {
return client.VolumeCreateResult{}, fmt.Errorf("expected labels %v, got %v", expectedLabels, options.Labels)
}
return client.VolumeCreateResult{
+20 -20
View File
@@ -322,26 +322,26 @@ type Transformer struct {
func createTransformHook(additionalTransformers ...Transformer) mapstructure.DecodeHookFuncType {
transforms := map[reflect.Type]func(any) (any, error){
reflect.TypeOf(types.External{}): transformExternal,
reflect.TypeOf(types.HealthCheckTest{}): transformHealthCheckTest,
reflect.TypeOf(types.ShellCommand{}): transformShellCommand,
reflect.TypeOf(types.StringList{}): transformStringList,
reflect.TypeOf(map[string]string{}): transformMapStringString,
reflect.TypeOf(types.UlimitsConfig{}): transformUlimits,
reflect.TypeOf(types.UnitBytes(0)): transformSize,
reflect.TypeOf([]types.ServicePortConfig{}): transformServicePort,
reflect.TypeOf(types.ServiceSecretConfig{}): transformStringSourceMap,
reflect.TypeOf(types.ServiceConfigObjConfig{}): transformStringSourceMap,
reflect.TypeOf(types.StringOrNumberList{}): transformStringOrNumberList,
reflect.TypeOf(map[string]*types.ServiceNetworkConfig{}): transformServiceNetworkMap,
reflect.TypeOf(types.Mapping{}): transformMappingOrListFunc("=", false),
reflect.TypeOf(types.MappingWithEquals{}): transformMappingOrListFunc("=", true),
reflect.TypeOf(types.Labels{}): transformMappingOrListFunc("=", false),
reflect.TypeOf(types.MappingWithColon{}): transformMappingOrListFunc(":", false),
reflect.TypeOf(types.HostsList{}): transformHostsList,
reflect.TypeOf(types.ServiceVolumeConfig{}): transformServiceVolumeConfig,
reflect.TypeOf(types.BuildConfig{}): transformBuildConfig,
reflect.TypeOf(types.Duration(0)): transformStringToDuration,
reflect.TypeFor[types.External](): transformExternal,
reflect.TypeFor[types.HealthCheckTest](): transformHealthCheckTest,
reflect.TypeFor[types.ShellCommand](): transformShellCommand,
reflect.TypeFor[types.StringList](): transformStringList,
reflect.TypeFor[map[string]string](): transformMapStringString,
reflect.TypeFor[types.UlimitsConfig](): transformUlimits,
reflect.TypeFor[types.UnitBytes](): transformSize,
reflect.TypeFor[[]types.ServicePortConfig](): transformServicePort,
reflect.TypeFor[types.ServiceSecretConfig](): transformStringSourceMap,
reflect.TypeFor[types.ServiceConfigObjConfig](): transformStringSourceMap,
reflect.TypeFor[types.StringOrNumberList](): transformStringOrNumberList,
reflect.TypeFor[map[string]*types.ServiceNetworkConfig](): transformServiceNetworkMap,
reflect.TypeFor[types.Mapping](): transformMappingOrListFunc("=", false),
reflect.TypeFor[types.MappingWithEquals](): transformMappingOrListFunc("=", true),
reflect.TypeFor[types.Labels](): transformMappingOrListFunc("=", false),
reflect.TypeFor[types.MappingWithColon](): transformMappingOrListFunc(":", false),
reflect.TypeFor[types.HostsList](): transformHostsList,
reflect.TypeFor[types.ServiceVolumeConfig](): transformServiceVolumeConfig,
reflect.TypeFor[types.BuildConfig](): transformBuildConfig,
reflect.TypeFor[types.Duration](): transformStringToDuration,
}
for _, transformer := range additionalTransformers {
+10 -10
View File
@@ -56,15 +56,15 @@ func mergeServices(base, override []types.ServiceConfig) ([]types.ServiceConfig,
overrideServices := mapByName(override)
specials := &specials{
m: map[reflect.Type]func(dst, src reflect.Value) error{
reflect.TypeOf(&types.LoggingConfig{}): safelyMerge(mergeLoggingConfig),
reflect.TypeOf([]types.ServicePortConfig{}): mergeSlice(toServicePortConfigsMap, toServicePortConfigsSlice),
reflect.TypeOf([]types.ServiceSecretConfig{}): mergeSlice(toServiceSecretConfigsMap, toServiceSecretConfigsSlice),
reflect.TypeOf([]types.ServiceConfigObjConfig{}): mergeSlice(toServiceConfigObjConfigsMap, toSServiceConfigObjConfigsSlice),
reflect.TypeOf(&types.UlimitsConfig{}): mergeUlimitsConfig,
reflect.TypeOf([]types.ServiceVolumeConfig{}): mergeSlice(toServiceVolumeConfigsMap, toServiceVolumeConfigsSlice),
reflect.TypeOf(types.ShellCommand{}): mergeShellCommand,
reflect.TypeOf(&types.ServiceNetworkConfig{}): mergeServiceNetworkConfig,
reflect.PointerTo(reflect.TypeOf(uint64(1))): mergeUint64,
reflect.PointerTo(reflect.TypeFor[types.LoggingConfig]()): safelyMerge(mergeLoggingConfig),
reflect.TypeFor[[]types.ServicePortConfig](): mergeSlice(toServicePortConfigsMap, toServicePortConfigsSlice),
reflect.TypeFor[[]types.ServiceSecretConfig](): mergeSlice(toServiceSecretConfigsMap, toServiceSecretConfigsSlice),
reflect.TypeFor[[]types.ServiceConfigObjConfig](): mergeSlice(toServiceConfigObjConfigsMap, toSServiceConfigObjConfigsSlice),
reflect.PointerTo(reflect.TypeFor[types.UlimitsConfig]()): mergeUlimitsConfig,
reflect.TypeFor[[]types.ServiceVolumeConfig](): mergeSlice(toServiceVolumeConfigsMap, toServiceVolumeConfigsSlice),
reflect.TypeFor[types.ShellCommand](): mergeShellCommand,
reflect.PointerTo(reflect.TypeFor[types.ServiceNetworkConfig]()): mergeServiceNetworkConfig,
reflect.PointerTo(reflect.TypeFor[uint64]()): mergeUint64,
},
}
for name, overrideService := range overrideServices {
@@ -77,7 +77,7 @@ func mergeServices(base, override []types.ServiceConfig) ([]types.ServiceConfig,
}
baseServices[name] = overrideService
}
services := []types.ServiceConfig{}
services := make([]types.ServiceConfig, 0, len(baseServices))
for _, baseService := range baseServices {
services = append(services, baseService)
}
+3 -5
View File
@@ -1,7 +1,6 @@
package connhelper
import (
"reflect"
"testing"
"gotest.tools/v3/assert"
@@ -27,7 +26,8 @@ func TestSSHFlags(t *testing.T) {
}
for _, tc := range testCases {
assert.DeepEqual(t, addSSHTimeout(tc.in), tc.out)
result := addSSHTimeout(tc.in)
assert.DeepEqual(t, result, tc.out)
}
}
@@ -57,9 +57,7 @@ func TestDisablePseudoTerminalAllocation(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := disablePseudoTerminalAllocation(tc.sshFlags)
if !reflect.DeepEqual(result, tc.expected) {
t.Errorf("expected %v, got %v", tc.expected, result)
}
assert.DeepEqual(t, result, tc.expected)
})
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
variable "GO_VERSION" {
default = "1.25.5"
default = "1.25.6"
}
variable "VERSION" {
default = ""
+1 -1
View File
@@ -109,7 +109,7 @@ mddocs: build_docker_image ## generate markdown files from go source
.PHONY: yamldocs
yamldocs: build_docker_image ## generate documentation YAML files consumed by docs repo
$(DOCKER_RUN) -it $(DEV_DOCKER_IMAGE_NAME) make yamldocs
$(DOCKER_RUN) $(DEV_DOCKER_IMAGE_NAME) make yamldocs
.PHONY: test ## run unit and e2e tests
test: test-unit test-e2e
+1 -1
View File
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.25.5
ARG GO_VERSION=1.25.6
# ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image.
# It must be a supported tag in the docker.io/library/alpine image repository
+1 -1
View File
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.25.5
ARG GO_VERSION=1.25.6
# ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image.
# It must be a supported tag in the docker.io/library/alpine image repository
+1 -1
View File
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.25.5
ARG GO_VERSION=1.25.6
# ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image.
# It must be a supported tag in the docker.io/library/alpine image repository
+3 -1
View File
@@ -1282,7 +1282,9 @@ connect to services running on the host machine.
It's conventional to use `host.docker.internal` as the hostname referring to
`host-gateway`. Docker Desktop automatically resolves this hostname, see
[Explore networking features](https://docs.docker.com/desktop/features/networking/networking-how-tos/#i-want-to-connect-from-a-container-to-a-service-on-the-host).
[Explore networking how-tos on Docker Desktop](https://docs.docker.com/desktop/features/networking/networking-how-tos/#connect-a-container-to-a-service-on-the-host)
and
[Configure host gateway IP](https://docs.docker.com/reference/cli/dockerd/#configure-host-gateway-ip).
The following example shows how the special `host-gateway` value works. The
example runs an HTTP server that serves a file from host to container over the
+1 -2
View File
@@ -114,8 +114,7 @@ Options:
### Environment variables
The following list of environment variables are supported by the `docker` command
line:
The following environment variables control the behavior of the `docker` command-line client:
| Variable | Description |
| :---------------------------- |:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+1 -1
View File
@@ -876,7 +876,7 @@ You can view the configured CDI specification directories using the `docker info
#### Disable CDI devices
The feature in enabled by default. To disable it, use the `cdi` options in the `deamon.json` file:
The feature in enabled by default. To disable it, use the `cdi` options in the `daemon.json` file:
```json
"features": {
+10 -12
View File
@@ -2,14 +2,14 @@ package jsonstream
import (
"context"
"encoding/json"
"fmt"
"io"
"testing"
"time"
"github.com/docker/cli/cli/streams"
"github.com/moby/moby/api/types/jsonstream"
"github.com/docker/cli/internal/test"
"github.com/moby/moby/client/pkg/progress"
"github.com/moby/moby/client/pkg/streamformatter"
"gotest.tools/v3/assert"
)
@@ -23,21 +23,19 @@ func TestDisplay(t *testing.T) {
})
go func() {
enc := json.NewEncoder(server)
id := test.RandomID()[:12] // short-ID
progressOutput := streamformatter.NewJSONProgressOutput(server, true)
for i := 0; i < 100; i++ {
select {
case <-ctx.Done():
assert.NilError(t, server.Close(), "failed to close jsonmessage server")
return
default:
err := enc.Encode(JSONMessage{
Status: "Downloading",
ID: fmt.Sprintf("id-%d", i),
Progress: &jsonstream.Progress{
Current: int64(i),
Total: 100,
Start: 0,
},
err := progressOutput.WriteProgress(progress.Progress{
ID: id,
Message: "Downloading",
Current: int64(i),
Total: 100,
})
if err != nil {
break
+5 -16
View File
@@ -216,7 +216,7 @@ func continueOnError(err error) bool {
}
func (c *client) iterateEndpoints(ctx context.Context, namedRef reference.Named, each func(context.Context, distribution.Repository, reference.Named) (bool, error)) error {
endpoints, err := allEndpoints(namedRef, c.insecureRegistry)
endpoints, err := allEndpoints(ctx, namedRef, c.insecureRegistry)
if err != nil {
return err
}
@@ -271,11 +271,11 @@ func (c *client) iterateEndpoints(ctx context.Context, namedRef reference.Named,
return nil
}
}
return newNotFoundError(namedRef.String())
return notFoundError{errors.New("no such manifest: " + namedRef.String())}
}
// allEndpoints returns a list of endpoints ordered by priority (v2, http).
func allEndpoints(namedRef reference.Named, insecure bool) ([]registry.APIEndpoint, error) {
func allEndpoints(ctx context.Context, namedRef reference.Named, insecure bool) ([]registry.APIEndpoint, error) {
var serviceOpts registry.ServiceOptions
if insecure {
logrus.Debugf("allowing insecure registry for: %s", reference.Domain(namedRef))
@@ -285,22 +285,11 @@ func allEndpoints(namedRef reference.Named, insecure bool) ([]registry.APIEndpoi
if err != nil {
return nil, err
}
endpoints, err := registryService.Endpoints(context.TODO(), reference.Domain(namedRef))
endpoints, err := registryService.Endpoints(ctx, reference.Domain(namedRef))
logrus.Debugf("endpoints for %s: %v", namedRef, endpoints)
return endpoints, err
}
func newNotFoundError(ref string) *notFoundError {
return &notFoundError{err: errors.New("no such manifest: " + ref)}
}
type notFoundError struct{ error }
type notFoundError struct {
err error
}
func (n *notFoundError) Error() string {
return n.err.Error()
}
// NotFound satisfies interface github.com/docker/docker/errdefs.ErrNotFound
func (notFoundError) NotFound() {}
+189 -144
View File
@@ -113,12 +113,11 @@ pull** IMAGE, before it starts the container from that image.
**-a**, **--attach**=[]
Attach to STDIN, STDOUT or STDERR.
In foreground mode (the default when **-d**
is not specified), **docker run** can start the process in the container
and attach the console to the process's standard input, output, and standard
error. It can even pretend to be a TTY (this is what most commandline
executables expect) and pass along signals. The **-a** option can be set for
each of stdin, stdout, and stderr.
In foreground mode (the default when **-d** is not specified), **docker run**
can start the process in the container and attach the console to the process's
standard input, output, and standard error. It can even pretend to be a TTY
(this is what most commandline executables expect) and pass along signals.
The **-a** option can be set for each of stdin, stdout, and stderr.
**--add-host**=[]
Add a custom host-to-IP mapping (host=ip, or host:ip)
@@ -141,32 +140,32 @@ each of stdin, stdout, and stderr.
CPU shares (relative weight)
By default, all containers get the same proportion of CPU cycles. This proportion
can be modified by changing the container's CPU share weighting relative
to the weighting of all other running containers.
can be modified by changing the container's CPU share weighting relative
to the weighting of all other running containers.
To modify the proportion from the default of 1024, use the **-c** or **--cpu-shares**
flag to set the weighting to 2 or higher.
To modify the proportion from the default of 1024, use the **-c** or **--cpu-shares**
flag to set the weighting to 2 or higher.
The proportion will only apply when CPU-intensive processes are running.
When tasks in one container are idle, other containers can use the
left-over CPU time. The actual amount of CPU time will vary depending on
the number of containers running on the system.
The proportion will only apply when CPU-intensive processes are running.
When tasks in one container are idle, other containers can use the
left-over CPU time. The actual amount of CPU time will vary depending on
the number of containers running on the system.
For example, consider three containers, one has a cpu-share of 1024 and
two others have a cpu-share setting of 512. When processes in all three
containers attempt to use 100% of CPU, the first container would receive
50% of the total CPU time. If you add a fourth container with a cpu-share
of 1024, the first container only gets 33% of the CPU. The remaining containers
receive 16.5%, 16.5% and 33% of the CPU.
For example, consider three containers, one has a cpu-share of 1024 and
two others have a cpu-share setting of 512. When processes in all three
containers attempt to use 100% of CPU, the first container would receive
50% of the total CPU time. If you add a fourth container with a cpu-share
of 1024, the first container only gets 33% of the CPU. The remaining containers
receive 16.5%, 16.5% and 33% of the CPU.
On a multi-core system, the shares of CPU time are distributed over all CPU
cores. Even if a container is limited to less than 100% of CPU time, it can
use 100% of each individual CPU core.
On a multi-core system, the shares of CPU time are distributed over all CPU
cores. Even if a container is limited to less than 100% of CPU time, it can
use 100% of each individual CPU core.
For example, consider a system with more than three cores. If you start one
container **{C0}** with **-c=512** running one process, and another container
**{C1}** with **-c=1024** running two processes, this can result in the following
division of CPU shares:
For example, consider a system with more than three cores. If you start one
container **{C0}** with **-c=512** running one process, and another container
**{C1}** with **-c=1024** running two processes, this can result in the following
division of CPU shares:
PID container CPU CPU share
100 {C0} 0 100% of CPU0
@@ -186,33 +185,42 @@ division of CPU shares:
**""**: (unset) use the daemon's default configuration (**host** on cgroup v1, **private** on cgroup v2)
**--cgroup-parent**=""
Path to cgroups under which the cgroup for the container will be created. If the path is not absolute, the path is considered to be relative to the cgroups path of the init process. Cgroups will be created if they do not already exist.
Path to cgroups under which the cgroup for the container will be created.
If the path is not absolute, the path is considered to be relative to the
cgroups path of the init process. Cgroups will be created if they do not
already exist.
**--cidfile**=""
Write the container ID to the file
**--cpu-count**=*0*
Limit the number of CPUs available for execution by the container.
On Windows Server containers, this is approximated as a percentage of total CPU usage.
Limit the number of CPUs available for execution by the container.
On Windows Server containers, the processor resource controls are mutually exclusive, the order of precedence is CPUCount first, then CPUShares, and CPUPercent last.
On Windows Server containers, this is approximated as a percentage of total
CPU usage. On Windows Server containers, the processor resource controls
are mutually exclusive, the order of precedence is CPUCount first, then
CPUShares, and CPUPercent last.
**--cpu-percent**=*0*
Limit the percentage of CPU available for execution by a container running on a Windows daemon.
Limit the percentage of CPU available for execution by a container running
on a Windows daemon.
On Windows Server containers, the processor resource controls are mutually exclusive, the order of precedence is CPUCount first, then CPUShares, and CPUPercent last.
On Windows Server containers, the processor resource controls are mutually
exclusive, the order of precedence is CPUCount first, then CPUShares, and
CPUPercent last.
**--cpu-period**=*0*
Limit the CPU CFS (Completely Fair Scheduler) period
Limit the container's CPU usage. This flag tell the kernel to restrict the container's CPU usage to the period you specify.
Limit the container's CPU usage. This flag tell the kernel to restrict the
container's CPU usage to the period you specify.
**--cpuset-cpus**=""
CPUs in which to allow execution (0-3, 0,1)
**--cpuset-mems**=""
Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.
Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective
on NUMA systems.
If you have four memory nodes on your system (0-3), use `--cpuset-mems=0,1`
then processes in your Docker container will only use memory from the first
@@ -222,55 +230,70 @@ two memory nodes.
Limit the CPU CFS (Completely Fair Scheduler) quota
Limit the container's CPU usage. By default, containers run with the full
CPU resource. This flag tell the kernel to restrict the container's CPU usage
to the quota you specify.
CPU resource. This flag tell the kernel to restrict the container's CPU
usage to the quota you specify.
**--cpu-rt-period**=0
Limit the CPU real-time period in microseconds
Limit the container's Real Time CPU usage. This flag tell the kernel to restrict the container's Real Time CPU usage to the period you specify.
Limit the container's Real Time CPU usage. This flag tell the kernel to
restrict the container's Real Time CPU usage to the period you specify.
**--cpu-rt-runtime**=0
Limit the CPU real-time runtime in microseconds
Limit the containers Real Time CPU usage. This flag tells the kernel to limit the amount of time in a given CPU period Real Time tasks may consume. Ex:
Period of 1,000,000us and Runtime of 950,000us means that this container could consume 95% of available CPU and leave the remaining 5% to normal priority tasks.
Limit the containers Real Time CPU usage. This flag tells the kernel to
limit the amount of time in a given CPU period Real Time tasks may consume.
For example, a period of 1,000,000us and Runtime of 950,000us means that
this container could consume 95% of available CPU and leave the remaining
5% to normal priority tasks.
The sum of all runtimes across containers cannot exceed the amount allotted to the parent cgroup.
The sum of all runtimes across containers cannot exceed the amount allotted
to the parent cgroup.
**--cpus**=0.0
Number of CPUs. The default is *0.0* which means no limit.
**-d**, **--detach**=*true*|*false*
Detached mode: run the container in the background and print the new container ID. The default is *false*.
Detached mode: run the container in the background and print the new
container ID. The default is *false*.
At any time you can run **docker ps** in
the other shell to view a list of the running containers. You can reattach to a
detached container with **docker attach**.
At any time you can run **docker ps** in the other shell to view a list
of the running containers. You can reattach to a detached container with
**docker attach**.
When attached in the tty mode, you can detach from the container (and leave it
running) using a configurable key sequence. The default sequence is `CTRL-p CTRL-q`.
You configure the key sequence using the **--detach-keys** option or a configuration file.
See **config-json(5)** for documentation on using a configuration file.
When attached in the tty mode, you can detach from the container (and leave
it running) using a configurable key sequence. The default sequence is
`CTRL-p CTRL-q`.
You configure the key sequence using the **--detach-keys** option or a
configuration file. See **config-json(5)** for documentation on using a
configuration file.
**--detach-keys**=*key*
Override the key sequence for detaching a container; *key* is a single character from the [a-Z] range, or **ctrl**-*value*, where *value* is one of: **a-z**, **@**, **^**, **[**, **,**, or **_**.
Override the key sequence for detaching a container; *key* is a single
character from the [a-Z] range, or **ctrl**-*value*, where *value* is
one of: **a-z**, **@**, **^**, **[**, **,**, or **_**.
**--device**=*onhost*:*incontainer*[:*mode*]
Add a host device *onhost* to the container under the *incontainer* name.
Optional *mode* parameter can be used to specify device permissions, it is
a combination of **r** (for read), **w** (for write), and **m** (for **mknod**(2)).
Optional *mode* parameter can be used to specify device permissions, it is
a combination of **r** (for read), **w** (for write), and **m** (for
**mknod**(2)).
For example, **--device=/dev/sdc:/dev/xvdc:rwm** will give a container all
permissions for the host device **/dev/sdc**, seen as **/dev/xvdc** inside the container.
For example, **--device=/dev/sdc:/dev/xvdc:rwm** will give a container all
permissions for the host device **/dev/sdc**, seen as **/dev/xvdc** inside
the container.
**--device-cgroup-rule**="*type* *major*:*minor* *mode*"
Add a rule to the cgroup allowed devices list. The rule is expected to be in the format specified in the Linux kernel documentation (Documentation/cgroup-v1/devices.txt):
Add a rule to the cgroup allowed devices list. The rule is expected to be
in the format specified in the Linux kernel documentation
(Documentation/cgroup-v1/devices.txt):
- *type*: **a** (all), **c** (char), or **b** (block);
- *major* and *minor*: either a number, or __*__ for all;
- *mode*: a composition of **r** (read), **w** (write), and **m** (**mknod**(2)).
Example: **--device-cgroup-rule "c 1:3 mr"**: allow for a character device idendified by **1:3** to be created and read.
Example: **--device-cgroup-rule "c 1:3 mr"**: allow for a character device
identified by **1:3** to be created and read.
**--device-read-bps**=[]
Limit read rate from a device (e.g. --device-read-bps=/dev/sda:1mb)
@@ -285,7 +308,8 @@ permissions for the host device **/dev/sdc**, seen as **/dev/xvdc** inside the c
Limit write rate to a device (e.g. --device-write-iops=/dev/sda:1000)
**--dns-search**=[]
Set custom DNS search domains (Use --dns-search=. if you don't wish to set the search domain)
Set custom DNS search domains (Use --dns-search=. if you don't wish to set
the search domain)
**--dns-option**=[]
Set custom DNS options
@@ -293,10 +317,10 @@ permissions for the host device **/dev/sdc**, seen as **/dev/xvdc** inside the c
**--dns**=[]
Set custom DNS servers
This option can be used to override the DNS
configuration passed to the container. Typically this is necessary when the
host DNS configuration is invalid for the container (e.g., 127.0.0.1). When this
is the case the **--dns** flags is necessary for every run.
This option can be used to override the DNS configuration passed to the
container. Typically this is necessary when the host DNS configuration
is invalid for the container (e.g., 127.0.0.1). When this is the case
the **--dns** flags is necessary for every run.
**--domainname**=""
Container NIS domain name
@@ -315,24 +339,24 @@ inside of the container.
Overwrite the default ENTRYPOINT of the image
This option allows you to overwrite the default entrypoint of the image that
is set in the Dockerfile. The ENTRYPOINT of an image is similar to a COMMAND
because it specifies what executable to run when the container starts, but it is
(purposely) more difficult to override. The ENTRYPOINT gives a container its
default nature or behavior, so that when you set an ENTRYPOINT you can run the
container as if it were that binary, complete with default options, and you can
pass in more options via the COMMAND. But, sometimes an operator may want to run
something else inside the container, so you can override the default ENTRYPOINT
at runtime by using a **--entrypoint** and a string to specify the new
ENTRYPOINT.
is set in the Dockerfile. The ENTRYPOINT of an image is similar to a COMMAND
because it specifies what executable to run when the container starts, but it is
(purposely) more difficult to override. The ENTRYPOINT gives a container its
default nature or behavior, so that when you set an ENTRYPOINT you can run the
container as if it were that binary, complete with default options, and you can
pass in more options via the COMMAND. But, sometimes an operator may want to run
something else inside the container, so you can override the default ENTRYPOINT
at runtime by using a **--entrypoint** and a string to specify the new
ENTRYPOINT.
**--env-file**=[]
Read in a line delimited file of environment variables
**--expose**=[]
Expose a port, or a range of ports (e.g. --expose=3300-3310) informs Docker
that the container listens on the specified network ports at runtime. Docker
uses this information to interconnect containers using links and to set up port
redirection on the host system.
Expose a port, or a range of ports (e.g. --expose=3300-3310) informs the
docker daemon that the container listens on the specified network ports at
runtime. The docker daemon uses this information to interconnect containers
using links and to set up port redirection on the host system.
**--group-add**=[]
Add additional groups to run as
@@ -390,10 +414,10 @@ is `hyperv`. Linux only supports `default`.
Kernel memory limit; *S* is an optional suffix which can be one of **b**, **k**, **m**, or **g**.
Constrains the kernel memory available to a container. If a limit of 0
is specified (not using **--kernel-memory**), the container's kernel memory
is not limited. If you specify a limit, it may be rounded up to a multiple
of the operating system's page size and the value can be very large,
millions of trillions.
is specified (not using **--kernel-memory**), the container's kernel memory
is not limited. If you specify a limit, it may be rounded up to a multiple
of the operating system's page size and the value can be very large,
millions of trillions.
**--label-file**=[]
Read in a line delimited file of labels
@@ -422,24 +446,27 @@ which interface and port to use.
Memory limit; *S* is an optional suffix which can be one of **b**, **k**, **m**, or **g**.
Allows you to constrain the memory available to a container. If the host
supports swap memory, then the **-m** memory setting can be larger than physical
RAM. If a limit of 0 is specified (not using **-m**), the container's memory is
not limited. The actual limit may be rounded up to a multiple of the operating
system's page size (the value would be very large, that's millions of trillions).
supports swap memory, then the **-m** memory setting can be larger than physical
RAM. If a limit of 0 is specified (not using **-m**), the container's memory is
not limited. The actual limit may be rounded up to a multiple of the operating
system's page size (the value would be very large, that's millions of trillions).
**--memory-reservation**=*number*[*S]
Memory soft limit; *S* is an optional suffix which can be one of **b**, **k**, **m**, or **g**.
After setting memory reservation, when the system detects memory contention
or low memory, containers are forced to restrict their consumption to their
reservation. So you should always set the value below **--memory**, otherwise the
hard limit will take precedence. By default, memory reservation will be the same
as memory limit.
or low memory, containers are forced to restrict their consumption to their
reservation. So you should always set the value below **--memory**, otherwise the
hard limit will take precedence. By default, memory reservation will be the same
as memory limit.
**--memory-swap**=*number*[*S*]
Combined memory plus swap limit; *S* is an optional suffix which can be one of **b**, **k**, **m**, or **g**.
Combined memory plus swap limit; *S* is an optional suffix which can be
one of **b**, **k**, **m**, or **g**.
This option can only be used together with **--memory**. The argument should always be larger than that of **--memory**. Default is double the value of **--memory**. Set to **-1** to enable unlimited swap.
This option can only be used together with **--memory**. The argument
should always be larger than that of **--memory**. Default is double the
value of **--memory**. Set to **-1** to enable unlimited swap.
**--mac-address**=""
Container MAC address (e.g., **92:d0:c6:0a:29:33**)
@@ -453,11 +480,11 @@ according to RFC4862.
Current supported mount `TYPES` are `bind`, `volume`, and `tmpfs`.
e.g.
For example;
`type=bind,source=/path/on/host,destination=/path/in/container`
`type=volume,source=my-volume,destination=/path/in/container,volume-label="color=red",volume-label="shape=round"`
`type=volume,source=my-volume,destination=/path/in/container,volume-label="color=red"`
`type=tmpfs,tmpfs-size=512M,destination=/path/in/container`
@@ -484,7 +511,9 @@ according to RFC4862.
* `volume-driver`: Name of the volume-driver plugin.
* `volume-label`: Custom metadata.
* `volume-nocopy`: `true`(default) or `false`. If set to `false`, the Engine copies existing files and directories under the mount-path into the volume, allowing the host to access them.
* `volume-nocopy`: `true`(default) or `false`. If set to `false`, the Engine
copies existing files and directories under the mount-path into the volume,
allowing the host to access them.
* `volume-opt`: specific to a given volume driver.
Options specific to `tmpfs`:
@@ -497,17 +526,15 @@ according to RFC4862.
The operator can identify a container in three ways:
| Identifier type | Example value |
|:----------------------|:-------------------------------------------------------------------|
| UUID long identifier | "f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778" |
| UUID short identifier | "f78375b1c487" |
| Name | "evil_ptolemy" |
- **long ID**: `f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778`
- **short ID**: `f78375b1c487`
- **Name**: `evil_ptolemy`
The UUID identifiers come from the Docker daemon, and if a name is not assigned
to the container with **--name** then the daemon will also generate a random
string name. The name is useful when defining links (see **--link**) (or any
other place you need to identify a container). This works for both background
and foreground Docker containers.
The ID identifiers come from the Docker daemon, and if a name is not assigned
to the container with **--name** then the daemon will also generate a random
string name. The name is useful when defining links (see **--link**) (or any
other place you need to identify a container). This works for both background
and foreground Docker containers.
**--network**=*type*
Set the Network mode for the container. Supported values are:
@@ -555,8 +582,9 @@ Use `docker port`(1) to see the actual mapping, e.g. `docker port CONTAINER $CON
**--pid**=""
Set the PID mode for the container
Default is to create a private PID namespace for the container
'container:<name|id>': join another container's PID namespace
'host': use the host's PID namespace for the container. Note: the host mode gives the container full access to local PID and is therefore considered insecure.
'container:<name|id>': join another container's PID namespace
'host': use the host's PID namespace for the container. Note: the host mode
gives the container full access to local PID and is therefore considered insecure.
**--userns**=""
Set the usernamespace mode for the container when `userns-remap` option is enabled.
@@ -566,9 +594,11 @@ Use `docker port`(1) to see the actual mapping, e.g. `docker port CONTAINER $CON
Tune the container's pids (process IDs) limit. Set to `-1` to have unlimited pids for the container.
**--uts**=*type*
Set the UTS mode for the container. The only possible *type* is **host**, meaning to
use the host's UTS namespace inside the container.
Note: the host mode gives the container access to changing the host's hostname and is therefore considered insecure.
Set the UTS mode for the container. The only possible *type* is **host**,
meaning to use the host's UTS namespace inside the container.
Note: the host mode gives the container access to changing the host's hostname
and is therefore considered insecure.
**--privileged** [**true**|**false**]
Give extended privileges to this container. A "privileged" container is given access to all devices.
@@ -588,46 +618,50 @@ its root filesystem mounted as read only prohibiting any writes.
**--restart** *policy*
Restart policy to apply when a container exits. Supported values are:
| Policy | Result |
|:-------------------------------|:----------------------|
| **no** | Do not automatically restart the container when it exits. |
| **on-failure**[:_max-retries_] | Restart only if the container exits with a non-zero exit status. Optionally, limit the number of restart retries the Docker daemon attempts. |
| **always** | Always restart the container regardless of the exit status. When you specify always, the Docker daemon will try to restart the container indefinitely. The container will also always start on daemon startup, regardless of the current state of the container. |
| **unless-stopped** | Always restart the container regardless of the exit status, but do not start it on daemon startup if the container has been put to a stopped state before. |
| Policy | Result |
|:-------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **no** | Do not automatically restart the container when it exits. |
| **on-failure**[:_max-retries_] | Restart only if the container exits with a non-zero exit status. Optionally, limit the number of restart retries the Docker daemon attempts. |
| **always** | Always restart the container regardless of the exit status. When you specify always, the Docker daemon tries to restart the container indefinitely. The container always start on daemon startup, regardless of the current state of the container. |
| **unless-stopped** | Always restart the container regardless of the exit status, but do not start it on daemon startup if the container has been put to a stopped state before. |
Default is **no**.
**--rm** **true**|**false**
Automatically remove the container when it exits. The default is **false**.
`--rm` flag can work together with `-d`, and auto-removal will be done on daemon side. Note that it's
incompatible with any restart policy other than `none`.
`--rm` flag can work together with `-d`, and auto-removal will be done on
daemon side. Note that it's incompatible with any restart policy other than
`none`.
**--security-opt** *value*[,...]
Security Options for the container. The following options can be given:
"label=user:USER" : Set the label user for the container
"label=role:ROLE" : Set the label role for the container
"label=type:TYPE" : Set the label type for the container
"label=level:LEVEL" : Set the label level for the container
"label=disable" : Turn off label confinement for the container
"no-new-privileges" : Disable container processes from gaining additional privileges
"seccomp=unconfined" : Turn off seccomp confinement for the container
"seccomp=profile.json : White listed syscalls seccomp Json file to be used as a seccomp filter
"apparmor=unconfined" : Turn off apparmor confinement for the container
"apparmor=your-profile" : Set the apparmor confinement profile for the container
| Option | Description |
|:-------------------------|:-----------------------------------------------------------------------|
| "label=user:USER" | Set the label user for the container |
| "label=role:ROLE" | Set the label role for the container |
| "label=type:TYPE" | Set the label type for the container |
| "label=level:LEVEL" | Set the label level for the container |
| "label=disable" | Turn off label confinement for the container |
| "no-new-privileges" | Disable container processes from gaining additional privileges |
| "seccomp=unconfined" | Turn off seccomp confinement for the container |
| "seccomp=profile.json" | White listed syscalls seccomp Json file to be used as a seccomp filter |
| "apparmor=unconfined" | Turn off apparmor confinement for the container |
| "apparmor=your-profile" | Set the apparmor confinement profile for the container |
**--storage-opt**
Storage driver options per container
$ docker run -it --storage-opt size=120G fedora /bin/bash
This (size) will allow to set the container rootfs size to 120G at creation time.
This option is only available for the `btrfs`, `overlay2` and `zfs` graph drivers.
For the `btrfs` and `zfs` storage drivers, user cannot pass a size less than the Default BaseFS Size.
For the `overlay2` storage driver, the size option is only available if the backing fs is `xfs` and mounted with the `pquota` mount option.
Under these conditions, user can pass any size less than the backing fs size.
This (size) will allow to set the container rootfs size to 120G at creation
time. This option is only available for the `btrfs`, `overlay2` and `zfs`
graph drivers.
For the `btrfs` and `zfs` storage drivers, user cannot pass a size less than
the Default BaseFS Size. For the `overlay2` storage driver, the size option
is only available if the backing fs is `xfs` and mounted with the `pquota`
mount option. Under these conditions, user can pass any size less than the
backing fs size.
**--stop-signal**=""
Signal to stop the container.
@@ -656,16 +690,18 @@ incompatible with any restart policy other than `none`.
**--shm-size**=""
Size of `/dev/shm`. The format is `<number><unit>`.
`number` must be greater than `0`. Unit is optional and can be `b` (bytes), `k` (kilobytes), `m`(megabytes), or `g` (gigabytes).
If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`.
`number` must be greater than `0`. Unit is optional and can be `b` (bytes),
`k` (kilobytes), `m`(megabytes), or `g` (gigabytes). If you omit the unit,
the system uses bytes. If you omit the size entirely, the system uses `64m`.
**--sysctl**=SYSCTL
Configure namespaced kernel parameters at runtime
IPC Namespace - current sysctls allowed:
kernel.msgmax, kernel.msgmnb, kernel.msgmni, kernel.sem, kernel.shmall, kernel.shmmax, kernel.shmmni, kernel.shm_rmid_forced
Sysctls beginning with fs.mqueue.*
kernel.msgmax, kernel.msgmnb, kernel.msgmni, kernel.sem, kernel.shmall,
kernel.shmmax, kernel.shmmni, kernel.shm_rmid_forced, and sysctls beginning
with fs.mqueue.*
If you use the `--ipc=host` option these sysctls will not be allowed.
@@ -675,7 +711,8 @@ incompatible with any restart policy other than `none`.
If you use the `--network=host` option these sysctls will not be allowed.
**--sig-proxy**=*true*|*false*
Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied. The default is *true*.
Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP,
and SIGKILL are not proxied. The default is *true*.
**--memory-swappiness**=""
Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100.
@@ -928,7 +965,8 @@ Host shows a shared memory segment with 7 pids attached, happens to be from http
0x01128e25 0 root 600 1000 7
```
Now run a regular container, and it correctly does NOT see the shared memory segment from the host:
Now run a regular container, and it correctly does NOT see the shared memory
segment from the host:
```
$ docker run -it shm ipcs -m
@@ -937,7 +975,8 @@ Now run a regular container, and it correctly does NOT see the shared memory seg
key shmid owner perms bytes nattch status
```
Run a container with the new `--ipc=host` option, and it now sees the shared memory segment from the host httpd:
Run a container with the new `--ipc=host` option, and it now sees the shared
memory segment from the host httpd:
```
$ docker run -it --ipc=host shm ipcs -m
@@ -958,7 +997,8 @@ Start a container with a program to create a shared memory segment:
key shmid owner perms bytes nattch status
0x0000162e 0 root 666 27 1
```
Create a 2nd container correctly shows no shared memory segment from 1st container:
Create a second container correctly shows no shared memory segment from first
container:
```
$ docker run shm ipcs -m
@@ -966,7 +1006,8 @@ Create a 2nd container correctly shows no shared memory segment from 1st contain
key shmid owner perms bytes nattch status
```
Create a 3rd container using the new --ipc=container:CONTAINERID option, now it shows the shared memory segment from the first:
Create a 3rd container using the new --ipc=container:CONTAINERID option,
now it shows the shared memory segment from the first:
```
$ docker run -it --ipc=container:ed735b2264ac shm ipcs -m
@@ -1129,18 +1170,22 @@ $ docker run -d --isolation default busybox top
On Microsoft Windows, can take any of these values:
* `default`: Use the value specified by the Docker daemon's `--exec-opt` . If the `daemon` does not specify an isolation technology, Microsoft Windows uses `process` as its default value.
* `default`: Use the value specified by the Docker daemon's `--exec-opt` . If the
`daemon` does not specify an isolation technology, Microsoft Windows uses
`process` as its default value.
* `process`: Namespace isolation only.
* `hyperv`: Hyper-V hypervisor partition-based isolation.
In practice, when running on Microsoft Windows without a `daemon` option set, these two commands are equivalent:
In practice, when running on Microsoft Windows without a `daemon` option set,
these two commands are equivalent:
```
$ docker run -d --isolation default busybox top
$ docker run -d --isolation process busybox top
```
If you have set the `--exec-opt isolation=hyperv` option on the Docker `daemon`, any of these commands also result in `hyperv` isolation:
If you have set the `--exec-opt isolation=hyperv` option on the Docker `daemon`,
any of these commands also result in `hyperv` isolation:
```
$ docker run -d --isolation default busybox top
+3
View File
@@ -1,3 +1,6 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.24
package swarmopts
import (
+41 -1
View File
@@ -6,6 +6,9 @@ package templates
import (
"bytes"
"encoding/json"
"fmt"
"reflect"
"sort"
"strings"
"text/template"
)
@@ -15,7 +18,7 @@ import (
var basicFunctions = template.FuncMap{
"json": formatJSON,
"split": strings.Split,
"join": strings.Join,
"join": joinElements,
"title": strings.Title, //nolint:nolintlint,staticcheck // strings.Title is deprecated, but we only use it for ASCII, so replacing with golang.org/x/text is out of scope
"lower": strings.ToLower,
"upper": strings.ToUpper,
@@ -97,3 +100,40 @@ func formatJSON(v any) string {
// Remove the trailing new line added by the encoder
return strings.TrimSpace(buf.String())
}
// joinElements joins a slice of items with the given separator. It uses
// [strings.Join] if it's a slice of strings, otherwise uses [fmt.Sprint]
// to join each item to the output.
func joinElements(elems any, sep string) (string, error) {
if elems == nil {
return "", nil
}
if ss, ok := elems.([]string); ok {
return strings.Join(ss, sep), nil
}
switch rv := reflect.ValueOf(elems); rv.Kind() { //nolint:exhaustive // ignore: too many options to make exhaustive
case reflect.Array, reflect.Slice:
var b strings.Builder
for i := range rv.Len() {
if i > 0 {
b.WriteString(sep)
}
_, _ = fmt.Fprint(&b, rv.Index(i).Interface())
}
return b.String(), nil
case reflect.Map:
var out []string
for _, k := range rv.MapKeys() {
out = append(out, fmt.Sprint(rv.MapIndex(k).Interface()))
}
// Not ideal, but trying to keep a consistent order
sort.Strings(out)
return strings.Join(out, sep), nil
default:
return "", fmt.Errorf("expected slice, got %T", elems)
}
}
+90
View File
@@ -3,6 +3,7 @@ package templates
import (
"bytes"
"testing"
"text/template"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -139,3 +140,92 @@ func TestHeaderFunctions(t *testing.T) {
})
}
}
type stringerString string
func (s stringerString) String() string {
return "stringer" + string(s)
}
type stringerAndError string
func (s stringerAndError) String() string {
return "stringer" + string(s)
}
func (s stringerAndError) Error() string {
return "error" + string(s)
}
func TestJoinElements(t *testing.T) {
tests := []struct {
doc string
data any
expOut string
expErr string
}{
{
doc: "nil",
data: nil,
expOut: `output: ""`,
},
{
doc: "non-slice",
data: "hello",
expOut: `output: "`,
expErr: `error calling join: expected slice, got string`,
},
{
doc: "structs",
data: []struct{ A, B string }{{"1", "2"}, {"3", "4"}},
expOut: `output: "{1 2}, {3 4}"`,
},
{
doc: "map with strings",
data: map[string]string{"A": "1", "B": "2", "C": "3"},
expOut: `output: "1, 2, 3"`,
},
{
doc: "map with stringers",
data: map[string]stringerString{"A": "1", "B": "2", "C": "3"},
expOut: `output: "stringer1, stringer2, stringer3"`,
},
{
doc: "map with errors",
data: []stringerAndError{"1", "2", "3"},
expOut: `output: "error1, error2, error3"`,
},
{
doc: "stringers",
data: []stringerString{"1", "2", "3"},
expOut: `output: "stringer1, stringer2, stringer3"`,
},
{
doc: "stringer with errors",
data: []stringerAndError{"1", "2", "3"},
expOut: `output: "error1, error2, error3"`,
},
{
doc: "slice of bools",
data: []bool{true, false, true},
expOut: `output: "true, false, true"`,
},
}
const formatStr = `output: "{{- join . ", " -}}"`
tmpl, err := New("my-template").Funcs(template.FuncMap{"join": joinElements}).Parse(formatStr)
assert.NilError(t, err)
for _, tc := range tests {
t.Run(tc.doc, func(t *testing.T) {
var b bytes.Buffer
err := tmpl.Execute(&b, tc.data)
if tc.expErr != "" {
assert.ErrorContains(t, err, tc.expErr)
} else {
assert.NilError(t, err)
}
assert.Equal(t, b.String(), tc.expOut)
})
}
}
+13 -13
View File
@@ -16,20 +16,20 @@ require (
github.com/distribution/reference v0.6.0
github.com/docker/cli-docs-tool v0.11.0
github.com/docker/distribution v2.8.3+incompatible
github.com/docker/docker-credential-helpers v0.9.4
github.com/docker/docker-credential-helpers v0.9.5
github.com/docker/go-connections v0.6.0
github.com/docker/go-units v0.5.0
github.com/fvbommel/sortorder v1.1.0
github.com/go-jose/go-jose/v4 v4.1.3
github.com/go-viper/mapstructure/v2 v2.4.0
github.com/go-viper/mapstructure/v2 v2.5.0
github.com/gogo/protobuf v1.3.2
github.com/google/go-cmp v0.7.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/google/uuid v1.6.0
github.com/mattn/go-runewidth v0.0.19
github.com/moby/go-archive v0.1.0
github.com/moby/moby/api v1.52.0
github.com/moby/moby/client v0.2.1
github.com/moby/go-archive v0.2.0
github.com/moby/moby/api v1.53.0
github.com/moby/moby/client v0.2.2
github.com/moby/patternmatcher v0.6.0
github.com/moby/swarmkit/v2 v2.1.1
github.com/moby/sys/atomicwriter v0.1.0
@@ -42,7 +42,7 @@ require (
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.1
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
github.com/sirupsen/logrus v1.9.3
github.com/sirupsen/logrus v1.9.4
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10
github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346
@@ -56,12 +56,12 @@ require (
go.opentelemetry.io/otel/sdk/metric v1.38.0
go.opentelemetry.io/otel/trace v1.38.0
go.yaml.in/yaml/v3 v3.0.4
golang.org/x/sync v0.18.0
golang.org/x/sys v0.38.0
golang.org/x/term v0.37.0
golang.org/x/text v0.31.0
golang.org/x/sync v0.19.0
golang.org/x/sys v0.40.0
golang.org/x/term v0.39.0
golang.org/x/text v0.33.0
gotest.tools/v3 v3.5.2
tags.cncf.io/container-device-interface v1.0.1
tags.cncf.io/container-device-interface v1.1.0
)
require (
@@ -82,7 +82,7 @@ require (
github.com/gorilla/mux v1.8.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.18.2 // indirect
github.com/klauspost/compress v1.18.3 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/sys/user v0.4.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
@@ -98,7 +98,7 @@ require (
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
golang.org/x/net v0.47.0 // indirect
golang.org/x/net v0.49.0 // indirect
golang.org/x/time v0.14.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
+26 -29
View File
@@ -40,8 +40,8 @@ github.com/docker/cli-docs-tool v0.11.0 h1:7d8QARFb7QEobizqxmEM7fOteZEHwH/zWgHQt
github.com/docker/cli-docs-tool v0.11.0/go.mod h1:ma8BKiisUo8D6W05XEYIh3oa1UbgrZhi1nowyKFJa8Q=
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-credential-helpers v0.9.4 h1:76ItO69/AP/V4yT9V4uuuItG0B1N8hvt0T0c0NN/DzI=
github.com/docker/docker-credential-helpers v0.9.4/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
github.com/docker/docker-credential-helpers v0.9.5 h1:EFNN8DHvaiK8zVqFA2DT6BjXE0GzfLOZ38ggPTKePkY=
github.com/docker/docker-credential-helpers v0.9.5/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/docker/go-events v0.0.0-20250808211157-605354379745 h1:yOn6Ze6IbYI/KAw2lw/83ELYvZh6hvsygTVkD0dzMC4=
@@ -67,8 +67,8 @@ github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -96,8 +96,8 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw=
github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -111,12 +111,12 @@ github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhg
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
github.com/moby/moby/api v1.52.0 h1:00BtlJY4MXkkt84WhUZPRqt5TvPbgig2FZvTbe3igYg=
github.com/moby/moby/api v1.52.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc=
github.com/moby/moby/client v0.2.1 h1:1Grh1552mvv6i+sYOdY+xKKVTvzJegcVMhuXocyDz/k=
github.com/moby/moby/client v0.2.1/go.mod h1:O+/tw5d4a1Ha/ZA/tPxIZJapJRUS6LNZ1wiVRxYHyUE=
github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8=
github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU=
github.com/moby/moby/api v1.53.0 h1:PihqG1ncw4W+8mZs69jlwGXdaYBeb5brF6BL7mPIS/w=
github.com/moby/moby/api v1.53.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc=
github.com/moby/moby/client v0.2.2 h1:Pt4hRMCAIlyjL3cr8M5TrXCwKzguebPAc2do2ur7dEM=
github.com/moby/moby/client v0.2.2/go.mod h1:2EkIPVNCqR05CMIzL1mfA07t0HvVUUOl85pasRz/GmQ=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/swarmkit/v2 v2.1.1 h1:yvTJ8MMCc3f0qTA44J6R59EZ5yZawdYopkpuLk4+ICU=
@@ -178,8 +178,8 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
@@ -189,7 +189,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346 h1:TvtdmeYsYEij78hS4oxnwikoiLdIrgav3BA+CbhaDAI=
@@ -243,15 +242,15 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -259,16 +258,15 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -294,12 +292,11 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=
pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
tags.cncf.io/container-device-interface v1.0.1 h1:KqQDr4vIlxwfYh0Ed/uJGVgX+CHAkahrgabg6Q8GYxc=
tags.cncf.io/container-device-interface v1.0.1/go.mod h1:JojJIOeW3hNbcnOH2q0NrWNha/JuHoDZcmYxAZwb2i0=
tags.cncf.io/container-device-interface v1.1.0 h1:RnxNhxF1JOu6CJUVpetTYvrXHdxw9j9jFYgZpI+anSY=
tags.cncf.io/container-device-interface v1.1.0/go.mod h1:76Oj0Yqp9FwTx/pySDc8Bxjpg+VqXfDb50cKAXVJ34Q=
+7 -4
View File
@@ -1,4 +1,7 @@
if ! has nix_direnv_version || ! nix_direnv_version 3.0.4; then
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.4/direnvrc" "sha256-DzlYZ33mWF/Gs8DDeyjr8mnVmQGx7ASYqA5WlxwvBG4="
fi
use flake . --impure
#!/usr/bin/env bash
export DIRENV_WARN_TIMEOUT=20s
eval "$(devenv direnvrc)"
use devenv
+7 -3
View File
@@ -1,6 +1,10 @@
/.devenv/
/.direnv/
/.pre-commit-config.yaml
/bin/
/build/
/var/
# Devenv
.devenv*
devenv.local.nix
devenv.local.yaml
.direnv
.pre-commit-config.yaml
+103
View File
@@ -0,0 +1,103 @@
{
"nodes": {
"devenv": {
"locked": {
"dir": "src/modules",
"lastModified": 1765288076,
"owner": "cachix",
"repo": "devenv",
"rev": "93c055af1e8fcac49251f1b2e1c57f78620ad351",
"type": "github"
},
"original": {
"dir": "src/modules",
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1765121682,
"owner": "edolstra",
"repo": "flake-compat",
"rev": "65f23138d8d09a92e30f1e5c87611b23ef451bf3",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"git-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1765016596,
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "548fc44fca28a5e81c5d6b846e555e6b9c2a5a3c",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1762808025,
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "cb5e3fdca1de58ccbc3ef53de65bd372b48f567c",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1764580874,
"owner": "cachix",
"repo": "devenv-nixpkgs",
"rev": "dcf61356c3ab25f1362b4a4428a6d871e84f1d1d",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "rolling",
"repo": "devenv-nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"git-hooks": "git-hooks",
"nixpkgs": "nixpkgs",
"pre-commit-hooks": [
"git-hooks"
]
}
}
},
"root": "root",
"version": 7
}
+14
View File
@@ -0,0 +1,14 @@
{
pkgs,
...
}:
{
languages = {
go.enable = true;
};
packages = with pkgs; [
golangci-lint
];
}
+4
View File
@@ -0,0 +1,4 @@
# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json
inputs:
nixpkgs:
url: github:cachix/devenv-nixpkgs/rolling
-294
View File
@@ -1,294 +0,0 @@
{
"nodes": {
"cachix": {
"inputs": {
"devenv": [
"devenv"
],
"flake-compat": [
"devenv"
],
"git-hooks": [
"devenv"
],
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1742042642,
"narHash": "sha256-D0gP8srrX0qj+wNYNPdtVJsQuFzIng3q43thnHXQ/es=",
"owner": "cachix",
"repo": "cachix",
"rev": "a624d3eaf4b1d225f918de8543ed739f2f574203",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "latest",
"repo": "cachix",
"type": "github"
}
},
"devenv": {
"inputs": {
"cachix": "cachix",
"flake-compat": "flake-compat",
"git-hooks": "git-hooks",
"nix": "nix",
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1744876578,
"narHash": "sha256-8MTBj2REB8t29sIBLpxbR0+AEGJ7f+RkzZPAGsFd40c=",
"owner": "cachix",
"repo": "devenv",
"rev": "7ff7c351bba20d0615be25ecdcbcf79b57b85fe1",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1733328505,
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
"devenv",
"nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1712014858,
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_2": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1743550720,
"narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "c621e8422220273271f52058f618c94e405bb0f5",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"git-hooks": {
"inputs": {
"flake-compat": [
"devenv"
],
"gitignore": "gitignore",
"nixpkgs": [
"devenv",
"nixpkgs"
]
},
"locked": {
"lastModified": 1742649964,
"narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"devenv",
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"libgit2": {
"flake": false,
"locked": {
"lastModified": 1697646580,
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
"owner": "libgit2",
"repo": "libgit2",
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
"type": "github"
},
"original": {
"owner": "libgit2",
"repo": "libgit2",
"type": "github"
}
},
"nix": {
"inputs": {
"flake-compat": [
"devenv"
],
"flake-parts": "flake-parts",
"libgit2": "libgit2",
"nixpkgs": "nixpkgs_2",
"nixpkgs-23-11": [
"devenv"
],
"nixpkgs-regression": [
"devenv"
],
"pre-commit-hooks": [
"devenv"
]
},
"locked": {
"lastModified": 1741798497,
"narHash": "sha256-E3j+3MoY8Y96mG1dUIiLFm2tZmNbRvSiyN7CrSKuAVg=",
"owner": "domenkozar",
"repo": "nix",
"rev": "f3f44b2baaf6c4c6e179de8cbb1cc6db031083cd",
"type": "github"
},
"original": {
"owner": "domenkozar",
"ref": "devenv-2.24",
"repo": "nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1733212471,
"narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "55d15ad12a74eb7d4646254e13638ad0c4128776",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1743296961,
"narHash": "sha256-b1EdN3cULCqtorQ4QeWgLMrd5ZGOjLSLemfa00heasc=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "e4822aea2a6d1cdd36653c134cacfd64c97ff4fa",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1717432640,
"narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "88269ab3044128b7c2f4c7d68448b2fb50456870",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "release-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1733477122,
"narHash": "sha256-qamMCz5mNpQmgBwc8SB5tVMlD5sbwVIToVZtSxMph9s=",
"owner": "cachix",
"repo": "devenv-nixpkgs",
"rev": "7bd9e84d0452f6d2e63b6e6da29fe73fac951857",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "rolling",
"repo": "devenv-nixpkgs",
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1744536153,
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"flake-parts": "flake-parts_2",
"nixpkgs": "nixpkgs_4"
}
}
},
"root": "root",
"version": 7
}
-46
View File
@@ -1,46 +0,0 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
flake-parts.url = "github:hercules-ci/flake-parts";
devenv.url = "github:cachix/devenv";
};
outputs =
inputs@{ flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
imports = [
inputs.devenv.flakeModule
];
systems = [
"x86_64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
perSystem =
{ pkgs, ... }:
rec {
devenv.shells = {
default = {
languages = {
go.enable = true;
};
pre-commit.hooks = {
nixpkgs-fmt.enable = true;
};
packages = with pkgs; [
golangci-lint
];
# https://github.com/cachix/devenv/issues/528#issuecomment-1556108767
containers = pkgs.lib.mkForce { };
};
ci = devenv.shells.default;
};
};
};
}
+284 -48
View File
@@ -173,6 +173,25 @@
// Public: "I made it through!"
// }
//
// # Custom Decoding with Unmarshaler
//
// Types can implement the Unmarshaler interface to control their own decoding. The interface
// behaves similarly to how UnmarshalJSON does in the standard library. It can be used as an
// alternative or companion to a DecodeHook.
//
// type TrimmedString string
//
// func (t *TrimmedString) UnmarshalMapstructure(input any) error {
// str, ok := input.(string)
// if !ok {
// return fmt.Errorf("expected string, got %T", input)
// }
// *t = TrimmedString(strings.TrimSpace(str))
// return nil
// }
//
// See the Unmarshaler interface documentation for more details.
//
// # Other Configuration
//
// mapstructure is highly configurable. See the DecoderConfig struct
@@ -218,6 +237,17 @@ type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, any) (any, error)
// values.
type DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (any, error)
// Unmarshaler is the interface implemented by types that can unmarshal
// themselves. UnmarshalMapstructure receives the input data (potentially
// transformed by DecodeHook) and should populate the receiver with the
// decoded values.
//
// The Unmarshaler interface takes precedence over the default decoding
// logic for any type (structs, slices, maps, primitives, etc.).
type Unmarshaler interface {
UnmarshalMapstructure(any) error
}
// DecoderConfig is the configuration that is used to create a new decoder
// and allows customization of various aspects of decoding.
type DecoderConfig struct {
@@ -281,6 +311,13 @@ type DecoderConfig struct {
// }
Squash bool
// Deep will map structures in slices instead of copying them
//
// type Parent struct {
// Children []Child `mapstructure:",deep"`
// }
Deep bool
// Metadata is the struct that will contain extra metadata about
// the decoding. If this is nil, then no metadata will be tracked.
Metadata *Metadata
@@ -290,9 +327,15 @@ type DecoderConfig struct {
Result any
// The tag name that mapstructure reads for field names. This
// defaults to "mapstructure"
// defaults to "mapstructure". Multiple tag names can be specified
// as a comma-separated list (e.g., "yaml,json"), and the first
// matching non-empty tag will be used.
TagName string
// RootName specifies the name to use for the root element in error messages. For example:
// '<rootName>' has unset fields: <fieldName>
RootName string
// The option of the value in the tag that indicates a field should
// be squashed. This defaults to "squash".
SquashTagOption string
@@ -304,11 +347,34 @@ type DecoderConfig struct {
// MatchName is the function used to match the map key to the struct
// field name or tag. Defaults to `strings.EqualFold`. This can be used
// to implement case-sensitive tag values, support snake casing, etc.
//
// MatchName is used as a fallback comparison when the direct key lookup fails.
// See also MapFieldName for transforming field names before lookup.
MatchName func(mapKey, fieldName string) bool
// DecodeNil, if set to true, will cause the DecodeHook (if present) to run
// even if the input is nil. This can be used to provide default values.
DecodeNil bool
// MapFieldName is the function used to convert the struct field name to the map's key name.
//
// This is useful for automatically converting between naming conventions without
// explicitly tagging each field. For example, to convert Go's PascalCase field names
// to snake_case map keys:
//
// MapFieldName: func(s string) string {
// return strcase.ToSnake(s)
// }
//
// When decoding from a map to a struct, the transformed field name is used for
// the initial lookup. If not found, MatchName is used as a fallback comparison.
// Explicit struct tags always take precedence over MapFieldName.
MapFieldName func(string) string
// DisableUnmarshaler, if set to true, disables the use of the Unmarshaler
// interface. Types implementing Unmarshaler will be decoded using the
// standard struct decoding logic instead.
DisableUnmarshaler bool
}
// A Decoder takes a raw interface value and turns it into structured
@@ -445,6 +511,12 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
config.MatchName = strings.EqualFold
}
if config.MapFieldName == nil {
config.MapFieldName = func(s string) string {
return s
}
}
result := &Decoder{
config: config,
}
@@ -458,7 +530,7 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
// Decode decodes the given raw interface to the target pointer specified
// by the configuration.
func (d *Decoder) Decode(input any) error {
err := d.decode("", input, reflect.ValueOf(d.config.Result).Elem())
err := d.decode(d.config.RootName, input, reflect.ValueOf(d.config.Result).Elem())
// Retain some of the original behavior when multiple errors ocurr
var joinedErr interface{ Unwrap() []error }
@@ -540,36 +612,50 @@ func (d *Decoder) decode(name string, input any, outVal reflect.Value) error {
var err error
addMetaKey := true
switch outputKind {
case reflect.Bool:
err = d.decodeBool(name, input, outVal)
case reflect.Interface:
err = d.decodeBasic(name, input, outVal)
case reflect.String:
err = d.decodeString(name, input, outVal)
case reflect.Int:
err = d.decodeInt(name, input, outVal)
case reflect.Uint:
err = d.decodeUint(name, input, outVal)
case reflect.Float32:
err = d.decodeFloat(name, input, outVal)
case reflect.Complex64:
err = d.decodeComplex(name, input, outVal)
case reflect.Struct:
err = d.decodeStruct(name, input, outVal)
case reflect.Map:
err = d.decodeMap(name, input, outVal)
case reflect.Ptr:
addMetaKey, err = d.decodePtr(name, input, outVal)
case reflect.Slice:
err = d.decodeSlice(name, input, outVal)
case reflect.Array:
err = d.decodeArray(name, input, outVal)
case reflect.Func:
err = d.decodeFunc(name, input, outVal)
default:
// If we reached this point then we weren't able to decode it
return newDecodeError(name, fmt.Errorf("unsupported type: %s", outputKind))
// Check if the target implements Unmarshaler and use it if not disabled
unmarshaled := false
if !d.config.DisableUnmarshaler {
if unmarshaler, ok := getUnmarshaler(outVal); ok {
if err = unmarshaler.UnmarshalMapstructure(input); err != nil {
err = newDecodeError(name, err)
}
unmarshaled = true
}
}
if !unmarshaled {
switch outputKind {
case reflect.Bool:
err = d.decodeBool(name, input, outVal)
case reflect.Interface:
err = d.decodeBasic(name, input, outVal)
case reflect.String:
err = d.decodeString(name, input, outVal)
case reflect.Int:
err = d.decodeInt(name, input, outVal)
case reflect.Uint:
err = d.decodeUint(name, input, outVal)
case reflect.Float32:
err = d.decodeFloat(name, input, outVal)
case reflect.Complex64:
err = d.decodeComplex(name, input, outVal)
case reflect.Struct:
err = d.decodeStruct(name, input, outVal)
case reflect.Map:
err = d.decodeMap(name, input, outVal)
case reflect.Ptr:
addMetaKey, err = d.decodePtr(name, input, outVal)
case reflect.Slice:
err = d.decodeSlice(name, input, outVal)
case reflect.Array:
err = d.decodeArray(name, input, outVal)
case reflect.Func:
err = d.decodeFunc(name, input, outVal)
default:
// If we reached this point then we weren't able to decode it
return newDecodeError(name, fmt.Errorf("unsupported type: %s", outputKind))
}
}
// If we reached here, then we successfully decoded SOMETHING, so
@@ -668,7 +754,7 @@ func (d *Decoder) decodeString(name string, data any, val reflect.Value) error {
case reflect.Uint8:
var uints []uint8
if dataKind == reflect.Array {
uints = make([]uint8, dataVal.Len(), dataVal.Len())
uints = make([]uint8, dataVal.Len())
for i := range uints {
uints[i] = dataVal.Index(i).Interface().(uint8)
}
@@ -1060,8 +1146,8 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
)
}
tagValue := f.Tag.Get(d.config.TagName)
keyName := f.Name
tagValue, _ := getTagValue(f, d.config.TagName)
keyName := d.config.MapFieldName(f.Name)
if tagValue == "" && d.config.IgnoreUntaggedFields {
continue
@@ -1070,6 +1156,9 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
// If Squash is set in the config, we squash the field down.
squash := d.config.Squash && v.Kind() == reflect.Struct && f.Anonymous
// If Deep is set in the config, set as default value.
deep := d.config.Deep
v = dereferencePtrToStructIfNeeded(v, d.config.TagName)
// Determine the name of the key in the map
@@ -1078,12 +1167,12 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
continue
}
// If "omitempty" is specified in the tag, it ignores empty values.
if strings.Index(tagValue[index+1:], "omitempty") != -1 && isEmptyValue(v) {
if strings.Contains(tagValue[index+1:], "omitempty") && isEmptyValue(v) {
continue
}
// If "omitzero" is specified in the tag, it ignores zero values.
if strings.Index(tagValue[index+1:], "omitzero") != -1 && v.IsZero() {
if strings.Contains(tagValue[index+1:], "omitzero") && v.IsZero() {
continue
}
@@ -1103,7 +1192,7 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
)
}
} else {
if strings.Index(tagValue[index+1:], "remain") != -1 {
if strings.Contains(tagValue[index+1:], "remain") {
if v.Kind() != reflect.Map {
return newDecodeError(
name+"."+f.Name,
@@ -1118,6 +1207,9 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
continue
}
}
deep = deep || strings.Contains(tagValue[index+1:], "deep")
if keyNameTagValue := tagValue[:index]; keyNameTagValue != "" {
keyName = keyNameTagValue
}
@@ -1164,6 +1256,41 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
valMap.SetMapIndex(reflect.ValueOf(keyName), vMap)
}
case reflect.Slice:
if deep {
var childType reflect.Type
switch v.Type().Elem().Kind() {
case reflect.Struct:
childType = reflect.TypeOf(map[string]any{})
default:
childType = v.Type().Elem()
}
sType := reflect.SliceOf(childType)
addrVal := reflect.New(sType)
vSlice := reflect.MakeSlice(sType, v.Len(), v.Cap())
if v.Len() > 0 {
reflect.Indirect(addrVal).Set(vSlice)
err := d.decode(keyName, v.Interface(), reflect.Indirect(addrVal))
if err != nil {
return err
}
}
vSlice = reflect.Indirect(addrVal)
valMap.SetMapIndex(reflect.ValueOf(keyName), vSlice)
break
}
// When deep mapping is not needed, fallthrough to normal copy
fallthrough
default:
valMap.SetMapIndex(reflect.ValueOf(keyName), v)
}
@@ -1471,7 +1598,10 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
remain := false
// We always parse the tags cause we're looking for other tags too
tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",")
tagParts := getTagParts(fieldType, d.config.TagName)
if len(tagParts) == 0 {
tagParts = []string{""}
}
for _, tag := range tagParts[1:] {
if tag == d.config.SquashTagOption {
squash = true
@@ -1492,6 +1622,18 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
if !fieldVal.IsNil() {
structs = append(structs, fieldVal.Elem().Elem())
}
case reflect.Ptr:
if fieldVal.Type().Elem().Kind() == reflect.Struct {
if fieldVal.IsNil() {
fieldVal.Set(reflect.New(fieldVal.Type().Elem()))
}
structs = append(structs, fieldVal.Elem())
} else {
errs = append(errs, newDecodeError(
name+"."+fieldType.Name,
fmt.Errorf("unsupported type for squashed pointer: %s", fieldVal.Type().Elem().Kind()),
))
}
default:
errs = append(errs, newDecodeError(
name+"."+fieldType.Name,
@@ -1516,13 +1658,15 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
field, fieldValue := f.field, f.val
fieldName := field.Name
tagValue := field.Tag.Get(d.config.TagName)
tagValue, _ := getTagValue(field, d.config.TagName)
if tagValue == "" && d.config.IgnoreUntaggedFields {
continue
}
tagValue = strings.SplitN(tagValue, ",", 2)[0]
if tagValue != "" {
fieldName = tagValue
} else {
fieldName = d.config.MapFieldName(fieldName)
}
rawMapKey := reflect.ValueOf(fieldName)
@@ -1605,8 +1749,14 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
}
sort.Strings(keys)
// Improve error message when name is empty by showing the target struct type
// in the case where it is empty for embedded structs.
errorName := name
if errorName == "" {
errorName = val.Type().String()
}
errs = append(errs, newDecodeError(
name,
errorName,
fmt.Errorf("has invalid keys: %s", strings.Join(keys, ", ")),
))
}
@@ -1692,7 +1842,7 @@ func isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool,
if f.PkgPath == "" && !checkMapstructureTags { // check for unexported fields
return true
}
if checkMapstructureTags && f.Tag.Get(tagName) != "" { // check for mapstructure tags inside
if checkMapstructureTags && hasAnyTag(f, tagName) { // check for mapstructure tags inside
return true
}
}
@@ -1700,13 +1850,99 @@ func isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool,
}
func dereferencePtrToStructIfNeeded(v reflect.Value, tagName string) reflect.Value {
if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
if v.Kind() != reflect.Ptr {
return v
}
deref := v.Elem()
derefT := deref.Type()
if isStructTypeConvertibleToMap(derefT, true, tagName) {
return deref
switch v.Elem().Kind() {
case reflect.Slice:
return v.Elem()
case reflect.Struct:
deref := v.Elem()
derefT := deref.Type()
if isStructTypeConvertibleToMap(derefT, true, tagName) {
return deref
}
return v
default:
return v
}
return v
}
func hasAnyTag(field reflect.StructField, tagName string) bool {
_, ok := getTagValue(field, tagName)
return ok
}
func getTagParts(field reflect.StructField, tagName string) []string {
tagValue, ok := getTagValue(field, tagName)
if !ok {
return nil
}
return strings.Split(tagValue, ",")
}
func getTagValue(field reflect.StructField, tagName string) (string, bool) {
for _, name := range splitTagNames(tagName) {
if tag := field.Tag.Get(name); tag != "" {
return tag, true
}
}
return "", false
}
func splitTagNames(tagName string) []string {
if tagName == "" {
return []string{"mapstructure"}
}
parts := strings.Split(tagName, ",")
result := make([]string, 0, len(parts))
for _, name := range parts {
name = strings.TrimSpace(name)
if name != "" {
result = append(result, name)
}
}
return result
}
// unmarshalerType is cached for performance
var unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
// getUnmarshaler checks if the value implements Unmarshaler and returns
// the Unmarshaler and a boolean indicating if it was found. It handles both
// pointer and value receivers.
func getUnmarshaler(val reflect.Value) (Unmarshaler, bool) {
// Skip invalid or nil values
if !val.IsValid() {
return nil, false
}
switch val.Kind() {
case reflect.Pointer, reflect.Interface:
if val.IsNil() {
return nil, false
}
}
// Check pointer receiver first (most common case)
if val.CanAddr() {
ptrVal := val.Addr()
// Quick check: if no methods, can't implement any interface
if ptrVal.Type().NumMethod() > 0 && ptrVal.Type().Implements(unmarshalerType) {
return ptrVal.Interface().(Unmarshaler), true
}
}
// Check value receiver
// Quick check: if no methods, can't implement any interface
if val.Type().NumMethod() > 0 && val.CanInterface() && val.Type().Implements(unmarshalerType) {
return val.Interface().(Unmarshaler), true
}
return nil, false
}
-40
View File
@@ -36,10 +36,6 @@ import (
const ImpliedDirectoryMode = 0o755
type (
// Compression is the state represents if compressed or not.
//
// Deprecated: use [compression.Compression].
Compression = compression.Compression
// WhiteoutFormat is the format of whiteouts unpacked
WhiteoutFormat int
@@ -95,14 +91,6 @@ func NewDefaultArchiver() *Archiver {
// in order for the test to pass.
type breakoutError error
const (
Uncompressed = compression.None // Deprecated: use [compression.None].
Bzip2 = compression.Bzip2 // Deprecated: use [compression.Bzip2].
Gzip = compression.Gzip // Deprecated: use [compression.Gzip].
Xz = compression.Xz // Deprecated: use [compression.Xz].
Zstd = compression.Zstd // Deprecated: use [compression.Zstd].
)
const (
AUFSWhiteoutFormat WhiteoutFormat = 0 // AUFSWhiteoutFormat is the default format for whiteouts
OverlayWhiteoutFormat WhiteoutFormat = 1 // OverlayWhiteoutFormat formats whiteout according to the overlay standard.
@@ -126,27 +114,6 @@ func IsArchivePath(path string) bool {
return err == nil
}
// DetectCompression detects the compression algorithm of the source.
//
// Deprecated: use [compression.Detect].
func DetectCompression(source []byte) compression.Compression {
return compression.Detect(source)
}
// DecompressStream decompresses the archive and returns a ReaderCloser with the decompressed archive.
//
// Deprecated: use [compression.DecompressStream].
func DecompressStream(archive io.Reader) (io.ReadCloser, error) {
return compression.DecompressStream(archive)
}
// CompressStream compresses the dest with specified compression algorithm.
//
// Deprecated: use [compression.CompressStream].
func CompressStream(dest io.Writer, comp compression.Compression) (io.WriteCloser, error) {
return compression.CompressStream(dest, comp)
}
// TarModifierFunc is a function that can be passed to ReplaceFileTarWrapper to
// modify the contents or header of an entry in the archive. If the file already
// exists in the archive the TarModifierFunc will be called with the Header and
@@ -235,13 +202,6 @@ func ReplaceFileTarWrapper(inputTarStream io.ReadCloser, mods map[string]TarModi
return pipeReader
}
// FileInfoHeaderNoLookups creates a partially-populated tar.Header from fi.
//
// Deprecated: use [tarheader.FileInfoHeaderNoLookups].
func FileInfoHeaderNoLookups(fi os.FileInfo, link string) (*tar.Header, error) {
return tarheader.FileInfoHeaderNoLookups(fi, link)
}
// FileInfoHeader creates a populated Header from fi.
//
// Compared to the archive/tar package, this function fills in less information
+1 -1
View File
@@ -1,4 +1,4 @@
//go:build !linux && !windows
//go:build darwin || freebsd || netbsd
package archive
+14 -3
View File
@@ -1,7 +1,7 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
@@ -176,13 +176,24 @@
END OF TERMS AND CONDITIONS
Copyright 2013-2018 Docker, Inc.
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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
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,
+5 -1
View File
@@ -71,11 +71,15 @@ func DecodeRequestBody(r io.ReadCloser) (*registry.AuthConfig, error) {
func decode(r io.Reader) (*registry.AuthConfig, error) {
authConfig := &registry.AuthConfig{}
if err := json.NewDecoder(r).Decode(authConfig); err != nil {
dec := json.NewDecoder(r)
if err := dec.Decode(authConfig); err != nil {
// always return an (empty) AuthConfig to increase compatibility with
// the existing API.
return &registry.AuthConfig{}, invalid(fmt.Errorf("invalid JSON: %w", err))
}
if dec.More() {
return &registry.AuthConfig{}, invalid(errors.New("multiple JSON documents not allowed"))
}
return authConfig, nil
}
+15
View File
@@ -0,0 +1,15 @@
package image
import (
"time"
)
// BuildIdentity contains build reference information if image was created via build.
type BuildIdentity struct {
// Ref is the identifier for the build request. This reference can be used to
// look up the build details in BuildKit history API.
Ref string `json:"Ref,omitempty"`
// CreatedAt is the time when the build ran.
CreatedAt time.Time `json:"CreatedAt,omitempty"`
}
@@ -2,13 +2,12 @@
package image
// ----------------------------------------------------------------------------
// Code generated by `swagger generate operation`.
//
// See hack/generate-swagger-api.sh
// ----------------------------------------------------------------------------
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// HistoryResponseItem individual image layer information in response to ImageHistory operation
// HistoryResponseItem HistoryResponseItem
//
// individual image layer information in response to ImageHistory operation
//
// swagger:model HistoryResponseItem
type HistoryResponseItem struct {
+15
View File
@@ -0,0 +1,15 @@
package image
// Identity holds information about the identity and origin of the image.
// This is trusted information verified by the daemon and cannot be modified
// by tagging an image to a different name.
type Identity struct {
// Signature contains the properties of verified signatures for the image.
Signature []SignatureIdentity `json:"Signature,omitzero"`
// Pull contains remote location information if image was created via pull.
// If image was pulled via mirror, this contains the original repository location.
// After successful push this images also contains the pushed repository location.
Pull []PullIdentity `json:"Pull,omitzero"`
// Build contains build reference information if image was created via build.
Build []BuildIdentity `json:"Build,omitzero"`
}
+29
View File
@@ -105,4 +105,33 @@ type InspectResponse struct {
// WARNING: This is experimental and may change at any time without any backward
// compatibility.
Manifests []ManifestSummary `json:"Manifests,omitempty"`
// Identity holds information about the identity and origin of the image.
// This is trusted information verified by the daemon and cannot be modified
// by tagging an image to a different name.
Identity *Identity `json:"Identity,omitempty"`
}
// SignatureTimestampType is the type of timestamp used in the signature.
type SignatureTimestampType string
const (
SignatureTimestampTlog SignatureTimestampType = "Tlog"
SignatureTimestampAuthority SignatureTimestampType = "TimestampAuthority"
)
// SignatureType is the type of signature format.
type SignatureType string
const (
SignatureTypeBundleV03 SignatureType = "bundle-v0.3"
SignatureTypeSimpleSigningV1 SignatureType = "simplesigning-v1"
)
// KnownSignerIdentity is an identifier for a special signer identity that is known to the implementation.
type KnownSignerIdentity string
const (
// KnownSignerDHI is the known identity for Docker Hardened Images.
KnownSignerDHI KnownSignerIdentity = "DHI"
)
+8
View File
@@ -0,0 +1,8 @@
package image
// PullIdentity contains remote location information if image was created via pull.
// If image was pulled via mirror, this contains the original repository location.
type PullIdentity struct {
// Repository is the remote repository location the image was pulled from.
Repository string `json:"Repository,omitempty"`
}
+26
View File
@@ -0,0 +1,26 @@
package image
// SignatureIdentity contains the properties of verified signatures for the image.
type SignatureIdentity struct {
// Name is a textual description summarizing the type of signature.
Name string `json:"Name,omitempty"`
// Timestamps contains a list of verified signed timestamps for the signature.
Timestamps []SignatureTimestamp `json:"Timestamps,omitzero"`
// KnownSigner is an identifier for a special signer identity that is known to the implementation.
KnownSigner KnownSignerIdentity `json:"KnownSigner,omitempty"`
// DockerReference is the Docker image reference associated with the signature.
// This is an optional field only present in older hashedrecord signatures.
DockerReference string `json:"DockerReference,omitempty"`
// Signer contains information about the signer certificate used to sign the image.
Signer *SignerIdentity `json:"Signer,omitempty"`
// SignatureType is the type of signature format. E.g. "bundle-v0.3" or "hashedrecord".
SignatureType SignatureType `json:"SignatureType,omitempty"`
// Error contains error information if signature verification failed.
// Other fields will be empty in this case.
Error string `json:"Error,omitempty"`
// Warnings contains any warnings that occurred during signature verification.
// For example, if there was no internet connectivity and cached trust roots were used.
// Warning does not indicate a failed verification but may point to configuration issues.
Warnings []string `json:"Warnings,omitzero"`
}
+12
View File
@@ -0,0 +1,12 @@
package image
import (
"time"
)
// SignatureTimestamp contains information about a verified signed timestamp for an image signature.
type SignatureTimestamp struct {
Type SignatureTimestampType `json:"Type"`
URI string `json:"URI"`
Timestamp time.Time `json:"Timestamp"`
}
+57
View File
@@ -0,0 +1,57 @@
package image
// SignerIdentity contains information about the signer certificate used to sign the image.
// This is [certificate.Summary] with deprecated fields removed and keys in Moby uppercase style.
//
// [certificate.Summary]: https://pkg.go.dev/github.com/sigstore/sigstore-go/pkg/fulcio/certificate#Summary
type SignerIdentity struct {
CertificateIssuer string `json:"CertificateIssuer"`
SubjectAlternativeName string `json:"SubjectAlternativeName"`
// The OIDC issuer. Should match `iss` claim of ID token or, in the case of
// a federated login like Dex it should match the issuer URL of the
// upstream issuer. The issuer is not set the extensions are invalid and
// will fail to render.
Issuer string `json:"Issuer,omitempty"` // OID 1.3.6.1.4.1.57264.1.8 and 1.3.6.1.4.1.57264.1.1 (Deprecated)
// Reference to specific build instructions that are responsible for signing.
BuildSignerURI string `json:"BuildSignerURI,omitempty"` // 1.3.6.1.4.1.57264.1.9
// Immutable reference to the specific version of the build instructions that is responsible for signing.
BuildSignerDigest string `json:"BuildSignerDigest,omitempty"` // 1.3.6.1.4.1.57264.1.10
// Specifies whether the build took place in platform-hosted cloud infrastructure or customer/self-hosted infrastructure.
RunnerEnvironment string `json:"RunnerEnvironment,omitempty"` // 1.3.6.1.4.1.57264.1.11
// Source repository URL that the build was based on.
SourceRepositoryURI string `json:"SourceRepositoryURI,omitempty"` // 1.3.6.1.4.1.57264.1.12
// Immutable reference to a specific version of the source code that the build was based upon.
SourceRepositoryDigest string `json:"SourceRepositoryDigest,omitempty"` // 1.3.6.1.4.1.57264.1.13
// Source Repository Ref that the build run was based upon.
SourceRepositoryRef string `json:"SourceRepositoryRef,omitempty"` // 1.3.6.1.4.1.57264.1.14
// Immutable identifier for the source repository the workflow was based upon.
SourceRepositoryIdentifier string `json:"SourceRepositoryIdentifier,omitempty"` // 1.3.6.1.4.1.57264.1.15
// Source repository owner URL of the owner of the source repository that the build was based on.
SourceRepositoryOwnerURI string `json:"SourceRepositoryOwnerURI,omitempty"` // 1.3.6.1.4.1.57264.1.16
// Immutable identifier for the owner of the source repository that the workflow was based upon.
SourceRepositoryOwnerIdentifier string `json:"SourceRepositoryOwnerIdentifier,omitempty"` // 1.3.6.1.4.1.57264.1.17
// Build Config URL to the top-level/initiating build instructions.
BuildConfigURI string `json:"BuildConfigURI,omitempty"` // 1.3.6.1.4.1.57264.1.18
// Immutable reference to the specific version of the top-level/initiating build instructions.
BuildConfigDigest string `json:"BuildConfigDigest,omitempty"` // 1.3.6.1.4.1.57264.1.19
// Event or action that initiated the build.
BuildTrigger string `json:"BuildTrigger,omitempty"` // 1.3.6.1.4.1.57264.1.20
// Run Invocation URL to uniquely identify the build execution.
RunInvocationURI string `json:"RunInvocationURI,omitempty"` // 1.3.6.1.4.1.57264.1.21
// Source repository visibility at the time of signing the certificate.
SourceRepositoryVisibilityAtSigning string `json:"SourceRepositoryVisibilityAtSigning,omitempty"` // 1.3.6.1.4.1.57264.1.22
}
+2 -2
View File
@@ -2,9 +2,9 @@ package jsonstream
import "encoding/json"
// JSONMessage defines a message struct. It describes
// Message defines a message struct. It describes
// the created time, where it from, status, ID of the
// message. It's used for docker events.
// message.
type Message struct {
Stream string `json:"stream,omitempty"`
Status string `json:"status,omitempty"`
+3 -3
View File
@@ -58,9 +58,9 @@ func (es *EndpointSettings) Copy() *EndpointSettings {
// EndpointIPAMConfig represents IPAM configurations for the endpoint
type EndpointIPAMConfig struct {
IPv4Address netip.Addr `json:",omitempty"`
IPv6Address netip.Addr `json:",omitempty"`
LinkLocalIPs []netip.Addr `json:",omitempty"`
IPv4Address netip.Addr `json:"IPv4Address,omitzero"`
IPv6Address netip.Addr `json:"IPv6Address,omitzero"`
LinkLocalIPs []netip.Addr `json:"LinkLocalIPs,omitempty"`
}
// Copy makes a copy of the endpoint ipam config
+5 -3
View File
@@ -11,9 +11,11 @@ import (
// in the absence of go.dev/issue/29678.
type HardwareAddr net.HardwareAddr
var _ encoding.TextMarshaler = (HardwareAddr)(nil)
var _ encoding.TextUnmarshaler = (*HardwareAddr)(nil)
var _ fmt.Stringer = (HardwareAddr)(nil)
var (
_ encoding.TextMarshaler = (HardwareAddr)(nil)
_ encoding.TextUnmarshaler = (*HardwareAddr)(nil)
_ fmt.Stringer = (HardwareAddr)(nil)
)
func (m *HardwareAddr) UnmarshalText(text []byte) error {
if len(text) == 0 {
+3 -3
View File
@@ -13,9 +13,9 @@ type IPAM struct {
// IPAMConfig represents IPAM configurations
type IPAMConfig struct {
Subnet netip.Prefix `json:",omitempty"`
IPRange netip.Prefix `json:",omitempty"`
Gateway netip.Addr `json:",omitempty"`
Subnet netip.Prefix `json:"Subnet,omitzero"`
IPRange netip.Prefix `json:"IPRange,omitzero"`
Gateway netip.Addr `json:"Gateway,omitzero"`
AuxAddress map[string]netip.Addr `json:"AuxiliaryAddresses,omitempty"`
}
+4 -4
View File
@@ -61,7 +61,7 @@ type EndpointVirtualIP struct {
// Addr is the virtual ip address.
// This field accepts CIDR notation, for example `10.0.0.1/24`, to maintain backwards
// compatibility, but only the IP address is used.
Addr netip.Prefix `json:",omitempty"`
Addr netip.Prefix `json:"Addr,omitzero"`
}
// Network represents a network.
@@ -111,7 +111,7 @@ type IPAMOptions struct {
// IPAMConfig represents ipam configuration.
type IPAMConfig struct {
Subnet netip.Prefix `json:",omitempty"`
Range netip.Prefix `json:",omitempty"`
Gateway netip.Addr `json:",omitempty"`
Subnet netip.Prefix `json:"Subnet,omitzero"`
Range netip.Prefix `json:"Range,omitzero"`
Gateway netip.Addr `json:"Gateway,omitzero"`
}
+4 -4
View File
@@ -109,14 +109,14 @@ type Limit struct {
Pids int64 `json:",omitempty"`
}
// GenericResource represents a "user defined" resource which can
// GenericResource represents a "user-defined" resource which can
// be either an integer (e.g: SSD=3) or a string (e.g: SSD=sda1)
type GenericResource struct {
NamedResourceSpec *NamedGenericResource `json:",omitempty"`
DiscreteResourceSpec *DiscreteGenericResource `json:",omitempty"`
}
// NamedGenericResource represents a "user defined" resource which is defined
// NamedGenericResource represents a "user-defined" resource which is defined
// as a string.
// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
// Value is used to identify the resource (GPU="UUID-1", FPGA="/dev/sdb5", ...)
@@ -125,7 +125,7 @@ type NamedGenericResource struct {
Value string `json:",omitempty"`
}
// DiscreteGenericResource represents a "user defined" resource which is defined
// DiscreteGenericResource represents a "user-defined" resource which is defined
// as an integer
// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
// Value is used to count the resource (SSD=5, HDD=3, ...)
@@ -148,7 +148,7 @@ type ResourceRequirements struct {
// Tune container memory swappiness (0 to 100) - if not specified, defaults
// to the container OS's default - generally 60, or the value predefined in
// the image; set to -1 to unset a previously set value
MemorySwappiness *int64 `json:MemorySwappiness,omitzero"`
MemorySwappiness *int64 `json:"MemorySwappiness,omitzero"`
}
// Placement represents orchestration parameters.
+6
View File
@@ -74,6 +74,7 @@ type Info struct {
FirewallBackend *FirewallInfo `json:"FirewallBackend,omitempty"`
CDISpecDirs []string
DiscoveredDevices []DeviceInfo `json:",omitempty"`
NRI *NRIInfo `json:",omitempty"`
Containerd *ContainerdInfo `json:",omitempty"`
@@ -163,3 +164,8 @@ type DeviceInfo struct {
// Example: CDI FQDN like "vendor.com/gpu=0", or other driver-specific device ID
ID string `json:"ID"`
}
// NRIInfo describes the NRI configuration.
type NRIInfo struct {
Info [][2]string `json:"Info,omitempty"`
}
+4 -1
View File
@@ -10,9 +10,12 @@ const (
// MediaTypeJSON is the MIME-Type for JSON objects.
MediaTypeJSON = "application/json"
// MediaTypeNDJSON is the MIME-Type for Newline Delimited JSON objects streams.
// MediaTypeNDJSON is the MIME-Type for Newline Delimited JSON objects streams (https://github.com/ndjson/ndjson-spec).
MediaTypeNDJSON = "application/x-ndjson"
// MediaTypeJSONLines is the MIME-Type for JSONLines objects streams (https://jsonlines.org/).
MediaTypeJSONLines = "application/jsonl"
// MediaTypeJSONSequence is the MIME-Type for JSON Text Sequences (RFC7464).
MediaTypeJSONSequence = "application/json-seq"
)
+14 -3
View File
@@ -1,7 +1,7 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
@@ -176,13 +176,24 @@
END OF TERMS AND CONDITIONS
Copyright 2013-2018 Docker, Inc.
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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
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,
+9 -1
View File
@@ -59,6 +59,7 @@ import (
"net/http"
"net/url"
"path"
"slices"
"strings"
"sync"
"sync/atomic"
@@ -106,7 +107,7 @@ const DummyHost = "api.moby.localhost"
// overriding the version and disable API-version negotiation.
//
// This version may be lower than the version of the api library module used.
const MaxAPIVersion = "1.52"
const MaxAPIVersion = "1.53"
// MinAPIVersion is the minimum API version supported by the client. API versions
// below this version are not considered when performing API-version negotiation.
@@ -241,6 +242,13 @@ func New(ops ...Opt) (*Client, error) {
c.client.Transport = otelhttp.NewTransport(c.client.Transport, c.traceOpts...)
if len(cfg.responseHooks) > 0 {
c.client.Transport = &responseHookTransport{
base: c.client.Transport,
hooks: slices.Clone(cfg.responseHooks),
}
}
return c, nil
}
+35 -3
View File
@@ -2,6 +2,7 @@ package client
import (
"context"
"errors"
"fmt"
"net"
"net/http"
@@ -55,10 +56,19 @@ type clientConfig struct {
// takes precedence. Either field disables API-version negotiation.
envAPIVersion string
// responseHooks is a list of custom response hooks to call on responses.
responseHooks []ResponseHook
// traceOpts is a list of options to configure the tracing span.
traceOpts []otelhttp.Option
}
// ResponseHook is called for each HTTP response returned by the daemon.
// Hooks are invoked in the order they were added.
//
// Hooks must not read or close resp.Body.
type ResponseHook func(*http.Response)
// Opt is a configuration option to initialize a [Client].
type Opt func(*clientConfig) error
@@ -133,8 +143,6 @@ func (tf testRoundTripper) RoundTrip(req *http.Request) (*http.Response, error)
return tf(req)
}
func (testRoundTripper) skipConfigureTransport() bool { return true }
// WithHostFromEnv overrides the client host with the host specified in the
// DOCKER_HOST ([EnvOverrideHost]) environment variable. If DOCKER_HOST is not set,
// or set to an empty value, the host is not modified.
@@ -151,7 +159,16 @@ func WithHostFromEnv() Opt {
func WithHTTPClient(client *http.Client) Opt {
return func(c *clientConfig) error {
if client != nil {
c.client = client
// Make a clone of client so modifications do not affect
// the caller's client. Clone here instead of in New()
// as other options (WithHost) also mutate c.client.
// Cloned clients share the same CookieJar as the
// original.
hc := *client
if ht, ok := hc.Transport.(*http.Transport); ok {
hc.Transport = ht.Clone()
}
c.client = &hc
}
return nil
}
@@ -341,3 +358,18 @@ func WithTraceOptions(opts ...otelhttp.Option) Opt {
return nil
}
}
// WithResponseHook adds a ResponseHook to the client. ResponseHooks are called
// for each HTTP response returned by the daemon. Hooks are invoked in the order
// they were added.
//
// Hooks must not read or close resp.Body.
func WithResponseHook(h ResponseHook) Opt {
return func(c *clientConfig) error {
if h == nil {
return errors.New("invalid response hook: hook is nil")
}
c.responseHooks = append(c.responseHooks, h)
return nil
}
}
+23
View File
@@ -0,0 +1,23 @@
package client
import (
"net/http"
)
type responseHookTransport struct {
base http.RoundTripper
hooks []ResponseHook
}
func (t *responseHookTransport) RoundTrip(req *http.Request) (*http.Response, error) {
resp, err := t.base.RoundTrip(req)
if err != nil {
return resp, err
}
for _, h := range t.hooks {
h(resp)
}
return resp, nil
}
+1 -1
View File
@@ -23,7 +23,7 @@ type ContainerAttachResult struct {
// ContainerAttach attaches a connection to a container in the server.
// It returns a [HijackedResponse] with the hijacked connection
// and a reader to get output. It's up to the called to close
// and a reader to get output. It's up to the caller to close
// the hijacked connection by calling [HijackedResponse.Close].
//
// The stream format on the response uses one of two formats:
+5 -7
View File
@@ -5,7 +5,7 @@ import (
"encoding/json"
"net/http"
"github.com/containerd/errdefs"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/container"
)
@@ -82,8 +82,7 @@ type ExecStartOptions struct {
}
// ExecStartResult holds the result of starting a container exec.
type ExecStartResult struct {
}
type ExecStartResult struct{}
// ExecStart starts an exec process already created in the docker host.
func (cli *Client) ExecStart(ctx context.Context, execID string, options ExecStartOptions) (ExecStartResult, error) {
@@ -118,7 +117,7 @@ type ExecAttachResult struct {
// ExecAttach attaches a connection to an exec process in the server.
//
// It returns a [HijackedResponse] with the hijacked connection
// and a reader to get output. It's up to the called to close
// and a reader to get output. It's up to the caller to close
// the hijacked connection by calling [HijackedResponse.Close].
//
// The stream format on the response uses one of two formats:
@@ -152,7 +151,7 @@ func (cli *Client) ExecAttach(ctx context.Context, execID string, options ExecAt
func getConsoleSize(hasTTY bool, consoleSize ConsoleSize) (*[2]uint, error) {
if consoleSize.Height != 0 || consoleSize.Width != 0 {
if !hasTTY {
return nil, errdefs.ErrInvalidArgument.WithMessage("console size is only supported when TTY is enabled")
return nil, cerrdefs.ErrInvalidArgument.WithMessage("console size is only supported when TTY is enabled")
}
return &[2]uint{consoleSize.Height, consoleSize.Width}, nil
}
@@ -160,8 +159,7 @@ func getConsoleSize(hasTTY bool, consoleSize ConsoleSize) (*[2]uint, error) {
}
// ExecInspectOptions holds options for inspecting a container exec.
type ExecInspectOptions struct {
}
type ExecInspectOptions struct{}
// ExecInspectResult holds the result of inspecting a container exec.
//
+15 -11
View File
@@ -13,11 +13,23 @@ import (
type ContainerListOptions struct {
Size bool
All bool
Latest bool
Since string
Before string
Limit int
Filters Filters
// Latest is non-functional and should not be used. Use Limit: 1 instead.
//
// Deprecated: the Latest option is non-functional and should not be used. Use Limit: 1 instead.
Latest bool
// Since is no longer supported. Use the "since" filter instead.
//
// Deprecated: the Since option is no longer supported since docker 1.12 (API 1.24). Use the "since" filter instead.
Since string
// Before is no longer supported. Use the "since" filter instead.
//
// Deprecated: the Before option is no longer supported since docker 1.12 (API 1.24). Use the "before" filter instead.
Before string
}
type ContainerListResult struct {
@@ -36,14 +48,6 @@ func (cli *Client) ContainerList(ctx context.Context, options ContainerListOptio
query.Set("limit", strconv.Itoa(options.Limit))
}
if options.Since != "" {
query.Set("since", options.Since)
}
if options.Before != "" {
query.Set("before", options.Before)
}
if options.Size {
query.Set("size", "1")
}
+2 -2
View File
@@ -5,7 +5,7 @@ import (
"net/url"
"strings"
"github.com/containerd/errdefs"
cerrdefs "github.com/containerd/errdefs"
)
// ContainerRenameOptions represents the options for renaming a container.
@@ -28,7 +28,7 @@ func (cli *Client) ContainerRename(ctx context.Context, containerID string, opti
if options.NewName == "" || strings.TrimPrefix(options.NewName, "/") == "" {
// daemons before v29.0 did not handle the canonical name ("/") well
// let's be nice and validate it here before sending
return ContainerRenameResult{}, errdefs.ErrInvalidArgument.WithMessage("new name cannot be blank")
return ContainerRenameResult{}, cerrdefs.ErrInvalidArgument.WithMessage("new name cannot be blank")
}
query := url.Values{}

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