Before this patch, a broken symlink would print a warning;
docker info > /dev/null
WARNING: Plugin "/Users/thajeztah/.docker/cli-plugins/docker-feedback" is not valid: failed to fetch metadata: fork/exec /Users/thajeztah/.docker/cli-plugins/docker-feedback: no such file or directory
After this patch, such symlinks are ignored:
docker info > /dev/null
With debug enabled, we don't ignore the faulty plugin, which will
make the warning shown on docker info;
mkdir -p ~/.docker/cli-plugins
ln -s nosuchplugin ~/.docker/cli-plugins/docker-brokenplugin
docker --debug info
Client:
Version: 29.0.0-dev
Context: default
Debug Mode: true
Plugins:
buildx: Docker Buildx (Docker Inc.)
Version: v0.25.0
Path: /usr/libexec/docker/cli-plugins/docker-buildx
WARNING: Plugin "/Users/thajeztah/.docker/cli-plugins/docker-brokenplugin" is not valid: failed to fetch metadata: fork/exec /Users/thajeztah/.docker/cli-plugins/docker-brokenplugin: no such file or directory
# ...
We should als consider passing a "seen" map to de-duplicate entries.
Entries can be either a direct symlink or in a symlinked path (for
which we can filepath.EvalSymlinks). We need to benchmark the overhead
of resolving the symlink vs possibly calling the plugin (to get their
metadata) further down the line.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This uses the DefaultShellCompDirective feature which was added
in cobra to override the default (which would complete to use
files for commands and flags).
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
The pluginNameRe was a basic regular expression, effectively only checking
if the name consisted of lowercase alphanumeric characters. Replace it
with a minimal utility to do the same, without having to use regular
expressions (or the "lazyregexp" package).
Some quick benchmarking (not committed) show that the non-regex approach
is ~25x faster:
BenchmarkIsValidPluginName_Regex_Valid-10 13956240 81.39 ns/op 0 B/op 0 allocs/op
BenchmarkIsValidPluginName_Manual_Valid-10 360003060 3.318 ns/op 0 B/op 0 allocs/op
BenchmarkIsValidPluginName_Regex_Invalid-10 35281794 33.74 ns/op 0 B/op 0 allocs/op
BenchmarkIsValidPluginName_Manual_Invalid-10 906072663 1.320 ns/op 0 B/op 0 allocs/op
BenchmarkIsValidPluginName_Regex_Parallel-10 96595677 12.04 ns/op 0 B/op 0 allocs/op
BenchmarkIsValidPluginName_Manual_Parallel-10 1000000000 0.4541 ns/op 0 B/op 0 allocs/op
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
These consts and types were moved to a separate metadata package in commits
292713c887 and 4321293972,
and deprecated in 72f76f2720, 5876b2941c,
and 6fa7d18320.
This removes the deprecated aliases in `cli-plugins/manager` in favor of
their equivalent in `cli-plugins/manager/metadata`:
- `CommandAnnotationPlugin`
- `CommandAnnotationPluginVendor`
- `CommandAnnotationPluginVersion`
- `CommandAnnotationPluginInvalid`
- `CommandAnnotationPluginCommandPath`
- `NamePrefix`
- `MetadataSubcommandName`
- `HookSubcommandName`
- `Metadata`
- `ReexecEnvvar`
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
These errors satisfy errdefs.IsNotFound, which can be used instead. This
function was deprecated in 71460215d3 and
is no longer used.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This alias was added in 4321293972, which is
part of v28.0, but did not deprecate them. They are no longer used in the
CLI itself, but may be used by cli-plugin implementations.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
These aliases were added in 292713c887
(part of v28.0), but did not deprecate them. They are no longer used
in the CLI itself, but may be used by cli-plugin implementations.
This deprecates the aliases in `cli-plugins/manager` in favor of
their equivalent in `cli-plugins/manager/metadata`:
- `CommandAnnotationPlugin`
- `CommandAnnotationPluginVendor`
- `CommandAnnotationPluginVersion`
- `CommandAnnotationPluginInvalid`
- `CommandAnnotationPluginCommandPath`
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
These utilities were only used internally; create a local copy
where used, and deprecate the ones in cli.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
These aliases were added in 4321293972
(part of v28.0), but did not deprecate them. They are no longer used
in the CLI itself, but may be used by cli-plugin implementations.
This deprecates the aliases in `cli-plugins/manager` in favor of
their equivalent in `cli-plugins/manager/metadata`:
- `NamePrefix`
- `MetadataSubcommandName`
- `HookSubcommandName`
- `Metadata`
- `ReexecEnvvar`
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This was a pattern inheritted from pkg/errors.Wrapf, which ignored
nil errors for convenience. However, it is error-prone, as it is
not obvious when returning a nil-error.
All call-sites using `wrapAsPluginError` already do a check for
nil errors, so remove this code to prevent hard to find bugs.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
It is for internal use, and no longer needed for testing, now that
the `Plugin` type handles marshalling errors.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Go does not by default marshal `error` type fields to JSON. The manager
package therefore implemented a `pluginError` type that implements
[encoding.TextMarshaler]. However, the field was marked as a regular
`error`, which made it brittle; assining any other type of error would
result in the error being discarded in the marshaled JSON (as used in
`docker info` output), resulting in the error being marshaled as `{}`.
This patch adds a custom `MarshalJSON()` on the `Plugin` type itself
so that any error is rendered. It checks if the error used already
implements [encoding.TextMarshaler], otherwise wraps the error in
a `pluginError`.
[encoding.TextMarshaler]: https://pkg.go.dev/encoding#TextMarshaler
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Experimental is always enabled (977d3ae046),
and the `Experimental` field in plugin metadata was deprecated in
977d3ae046 and removed in commit
6a50c4f700.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
The WithInitializeClient looks redundant altogether, so let's
rewrite this function to not depend on it.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Go maintainers started to unconditionally update the minimum go version
for golang.org/x/ dependencies to go1.23, which means that we'll no longer
be able to support any version below that when updating those dependencies;
> all: upgrade go directive to at least 1.23.0 [generated]
>
> By now Go 1.24.0 has been released, and Go 1.22 is no longer supported
> per the Go Release Policy (https://go.dev/doc/devel/release#policy).
>
> For golang/go#69095.
This updates our minimum version to go1.23, as we won't be able to maintain
compatibility with older versions because of the above.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
- Add runtime.Gosched() calls to encourage goroutine scheduling
- Increase the timeout from 10ms to 500ms
- Use poll.WaitOn with appropriate delays to ensure the goroutine has
spawned before checking
- Lock the test goroutines to its own thread
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
This function returned an error (if any) from [config.Path]. However, the
only situation in which an error could be returned was if the given path
to append to `config.Dir` was outside of the config directory. This can
only happen if the path to append would try to traverse directories (e.g.,
passing `../../cli-plugins`).
Given that we're passing a hard-coded value, that would not be the case,
so we can simplify the code to join the path directly, and don't have to
handle errors.
[config.Path]: 2d74733942/cli/config/config.go (L100-L107)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Skip the other logic, which includes listing all commands provided; if
there's no plugin-candidates, those steps won't be needed.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This error-group was added in 89583b92b7, but
passed a context.TODO because the function didn't have a context as argument.
However, it does get the root-command passed, which holds the context, so
we can pass that.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
The manager only requires the CLI's configuration; define a shallow interface
for this so that we don't have to import cli/command.
In addition to the CLI's configuration, `runHooks` also used the CLI's configured
StdErr output. We set the Cobra input and output streams to be the same as the
DockerCLI outputs in [newDockerCommand] and [newPluginCommand], so we can
get this from the Cobra command.
[newDockerCommand]: ea1f10b440/cmd/docker/docker.go (L148-L150)
[newPluginCommand]: ea1f10b440/cli-plugins/plugin/plugin.go (L166-L168)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
These utility functions were added in 8890a1c929,
and are all related to OTEL. The ResourceAttributesEnvvar const defines
the "OTEL_RESOURCE_ATTRIBUTES" environment-variable to use, which is part
of the [OpenTelemetry specification], so should be considered a well-known
env-var, and not up to us to define a const for. These code-changes were not
yet included in a release, so we don't have to deprecate.
This patch:
- Moves the utility functions to the telemetry files, so that all code related
to OpenTelemetry is together.
- Un-exports the ResourceAttributesEnvvar to reduce our public API.
- Un-exports the DockerCliAttributePrefix to reduce depdency on cli/command
in CLI-plugins, but adds a TODO to move telemetry-related code to a common
(internal) package.
- Deprecates the cli-plugins/manager.ResourceAttributesEnvvar const. This
const has no known consumers, so we could skip deprecation, but just in
case some codebase uses this.
[OpenTelemetry specification]: https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#general-sdk-configuration
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Remove the `docker.cli` prefixed attributes from
`OTEL_RESOURCE_ATTRIBUTES` after the telemetry provider has been created
within a plugin. This prevents accidentally sending the attributes to
something downstream for the user.
This also fixes an issue with compose where the self-injected `OTEL_RESOURCE_ATTRIBUTES`
would override an existing attribute in the environment file because the
"user environment" overrode the environment file, but the "user
environment" was created by the `docker` tool rather than by the user's
environment.
When `OTEL_RESOURCE_ATTRIBUTES` is empty after pruning, the environment
variable is unset.
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
Merge `OTEL_RESOURCE_ATTRIBUTES` when there is one already in the
environment. This allows user-specified resource attributes to be passed
on to CLI plugins while still allowing the extra attributes added for
telemetry information.
This was the original intended use-case but it seems to have never made
it in. The reason `OTEL_RESOURCE_ATTRIBUTES` was used is because we
could combine it with user-centric ones.
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
cli-plugins/manager/manager.go:35:7: unused-receiver: method receiver 'e' is not referenced in method's body, consider removing or renaming it as _ (revive)
func (e errPluginNotFound) NotFound() {}
^
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
- use Println to print newline instead of custom format
- suppress some errors to make my IDE and linters happier
- use res.Assert() with icmd.Expected{} where possible to make
assertions not depend on newline / whitespace randomness
- use apiClient instead of client for the API client to
prevent shadowing imports.
- use dockerCLI with Go's standard camelCase casing.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This patch enables descriptions on the CLI completion script.
It used to be disabled due to the CLI historically not supporting
cobra v2 completions, as seen by this patch
cbec75e2f3.
As an escape hatch, the user can set the `DOCKER_CLI_DISABLE_COMPLETION_DESCRIPTION`
environment variable to disable the completion description when
generating the completion file with `docker completion <fish|bash|zsh>`.
Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com>
Fix a case where one inaccessible plugin search path stops the whole
search and prevents latter paths from being scanned.
Remove a preliminary `Stat` call that verifies whether path is an actual
directory and is accessible.
It's unneeded and doesn't actually check whether the directory can be
listed or not.
`os.ReadDir` will fail in such case anyway, so just attempt to do that
and ignore any encountered error, instead of erroring out the whole
plugin candidate listing.
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
commit 4a7b04d412 configured golangci-lint
to use go1.23 semantics, which enabled the copyloopvar linter.
go1.22 now creates a copy of variables when assigned in a loop; make sure we
don't have files that may downgrade semantics to go1.21 in case that also means
disabling that feature; https://go.dev/ref/spec#Go_1.22
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
go1.22 and up now produce a unique variable in loops, tehrefore no longer
requiring to capture the variable manually;
cli-plugins/manager/cobra.go:55:4: The copy of the 'for' variable "p" can be deleted (Go 1.22+) (copyloopvar)
p := p
^
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>