Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cli-plugins/manager: ignore broken symlinks #5922

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

thaJeztah
Copy link
Member

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

We should consider what the best approach is for these, as this patch will make them completely invisible, but we may still be iterating over them for discovery.

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.

- Human readable description for the release notes

- A picture of a cute animal (not mandatory but encouraged)

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

We should consider what the best approach is for these, as this
patch will make them completely invisible, but we may still be
iterating over them for discovery.

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 <[email protected]>
@codecov-commenter
Copy link

codecov-commenter commented Mar 11, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 59.35%. Comparing base (3d3f780) to head (d231cf6).
Report is 11 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5922      +/-   ##
==========================================
+ Coverage   59.32%   59.35%   +0.03%     
==========================================
  Files         358      358              
  Lines       29783    29787       +4     
==========================================
+ Hits        17669    17681      +12     
+ Misses      11145    11136       -9     
- Partials      969      970       +1     
🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@thaJeztah
Copy link
Member Author

cc @rumpl @Benehiko @vvoland @laurazard let me know if you think this is a good idea, or if we shouldn't ignore these broken links

@Benehiko
Copy link
Member

On the one hand some users might not even know they are executing a plugin since it's hidden under the docker command so the error might be confusing - "I didn't install any plugins? what is docker-feedback?"
On the other hand, printing an error is nice to debug issues caused by the user or us.

Perhaps we should rather update the error message with a clearer, "these are the next steps to get rid of this error"?

@thaJeztah
Copy link
Member Author

It's tricky; so in normal cases, this would not happen. In this specific case, it's not even an issue introduced by the user but a bug in Docker Desktop's installer/updater to not cleanup things it created. Ultimately, Docker Desktop should not create these symlinks at all because the CLI plugin search-paths were designed for that; we're currently doing more work than needed, and the CLI is also slower because of that (as it's iterating multiple times over plugins that it will find in multiple places!).

If you look at docker info, you'll see that it doesn't even use these symlinks, but found the actual ones because they had a higher priority;

docker info
Client:
 Version:    28.0.1
 Context:    desktop-linux
 Debug Mode: false
 Plugins:
  ...
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.21.1-desktop.1
    Path:     /Applications/Docker.app/Contents/Resources/cli-plugins/docker-buildx

The ~/.docker/cli-plugins/ directory should be empty, and be fore users to install custom plugins, or versions of plugins to override the defaults ()

It's als not something "solvable" in all cases; for example, bind-mounting the ~/.docker/ directory into a container will have all CLI plugins "found", but broken (because their symlinks are broken). They wouldn't work in either case, as they'd be macOS binaries in a Linux contianer (in Docker Desktop for Mac / Windows cases)

docker run --rm -v /var/run/docker.sock.raw:/var/run/docker.sock -v ~/.docker/:/root/.docker/ docker:cli info > /dev/null
WARNING: Plugin "/root/.docker/cli-plugins/docker-ai" is not valid: failed to fetch metadata: fork/exec /root/.docker/cli-plugins/docker-ai: no such file or directory
WARNING: Plugin "/root/.docker/cli-plugins/docker-buildx" is not valid: failed to fetch metadata: fork/exec /root/.docker/cli-plugins/docker-buildx: no such file or directory
WARNING: Plugin "/root/.docker/cli-plugins/docker-compose" is not valid: failed to fetch metadata: fork/exec /root/.docker/cli-plugins/docker-compose: no such file or directory
WARNING: Plugin "/root/.docker/cli-plugins/docker-debug" is not valid: failed to fetch metadata: fork/exec /root/.docker/cli-plugins/docker-debug: no such file or directory
WARNING: Plugin "/root/.docker/cli-plugins/docker-desktop" is not valid: failed to fetch metadata: fork/exec /root/.docker/cli-plugins/docker-desktop: no such file or directory
WARNING: Plugin "/root/.docker/cli-plugins/docker-dev" is not valid: failed to fetch metadata: fork/exec /root/.docker/cli-plugins/docker-dev: no such file or directory
WARNING: Plugin "/root/.docker/cli-plugins/docker-extension" is not valid: failed to fetch metadata: fork/exec /root/.docker/cli-plugins/docker-extension: no such file or directory
WARNING: Plugin "/root/.docker/cli-plugins/docker-feedback" is not valid: failed to fetch metadata: fork/exec /root/.docker/cli-plugins/docker-feedback: no such file or directory
WARNING: Plugin "/root/.docker/cli-plugins/docker-init" is not valid: failed to fetch metadata: fork/exec /root/.docker/cli-plugins/docker-init: no such file or directory
WARNING: Plugin "/root/.docker/cli-plugins/docker-sbom" is not valid: failed to fetch metadata: fork/exec /root/.docker/cli-plugins/docker-sbom: no such file or directory
WARNING: Plugin "/root/.docker/cli-plugins/docker-scout" is not valid: failed to fetch metadata: fork/exec /root/.docker/cli-plugins/docker-scout: no such file or directory

@thaJeztah
Copy link
Member Author

thaJeztah commented Mar 11, 2025

Having a quick peek at the situation in Docker Desktop, it looks like we make the CLI traverse the same plugins three times;

  • We have the actual location that we add as custom cliPluginsExtraDirs configuration in ~/.docker/config.json (/Applications/Docker.app/Contents/Resources/cli-plugins/)
  • We have symlinks for each plugin in ~/.docker/cli-plugins (which we likely shouldn't have, because this is the location where users could install their own plugins, and this location is not-unlikely to be bind-mounted into a container)
  • ☝️ as these are symlinks for each plugin, these are also the ones we tend to leave behind, causing warnings to be shown to the user.
  • We have /usr/local/lib/docker/cli-plugins that is symlinked to /Applications/Docker.app/Contents/Resources/cli-plugins/
./build/docker info > /dev/null
Listing plugins in /Applications/Docker.app/Contents/Resources/cli-plugins/
 - plugin:  docker-ai
 - plugin:  docker-buildx
 - plugin:  docker-cloud
 - plugin:  docker-compose
 - plugin:  docker-debug
 - plugin:  docker-desktop
 - plugin:  docker-dev
 - plugin:  docker-extension
 - plugin:  docker-init
 - plugin:  docker-sbom
 - plugin:  docker-scout
Listing plugins in /Users/thajeztah/.docker/cli-plugins
 - plugin: docker-ai 			(symlink to /Applications/Docker.app/Contents/Resources/cli-plugins/docker-ai)
 - plugin: docker-buildx 		(symlink to /Applications/Docker.app/Contents/Resources/cli-plugins/docker-buildx)
 - plugin: docker-compose 		(symlink to /Applications/Docker.app/Contents/Resources/cli-plugins/docker-compose)
 - plugin: docker-debug 		(symlink to /Applications/Docker.app/Contents/Resources/cli-plugins/docker-debug)
 - plugin: docker-desktop 		(symlink to /Applications/Docker.app/Contents/Resources/cli-plugins/docker-desktop)
 - plugin: docker-dev 			(symlink to /Applications/Docker.app/Contents/Resources/cli-plugins/docker-dev)
 - plugin: docker-extension 	(symlink to /Applications/Docker.app/Contents/Resources/cli-plugins/docker-extension)
 - plugin:  docker-feedback
 - plugin: docker-init 			(symlink to /Applications/Docker.app/Contents/Resources/cli-plugins/docker-init)
 - plugin: docker-sbom 			(symlink to /Applications/Docker.app/Contents/Resources/cli-plugins/docker-sbom)
 - plugin: docker-scout 		(symlink to /Applications/Docker.app/Contents/Resources/cli-plugins/docker-scout)
 - plugin:  docker-shell
Listing plugins in /usr/local/lib/docker/cli-plugins 	(symlink to /Applications/Docker.app/Contents/Resources/cli-plugins)
 - plugin: docker-ai 			(actual path /Applications/Docker.app/Contents/Resources/cli-plugins/docker-ai)
 - plugin: docker-buildx 		(actual path /Applications/Docker.app/Contents/Resources/cli-plugins/docker-buildx)
 - plugin: docker-cloud 		(actual path /Applications/Docker.app/Contents/Resources/cli-plugins/docker-cloud)
 - plugin: docker-compose 		(actual path /Applications/Docker.app/Contents/Resources/cli-plugins/docker-compose)
 - plugin: docker-debug 		(actual path /Applications/Docker.app/Contents/Resources/cli-plugins/docker-debug)
 - plugin: docker-desktop 		(actual path /Applications/Docker.app/Contents/Resources/cli-plugins/docker-desktop)
 - plugin: docker-dev 			(actual path /Applications/Docker.app/Contents/Resources/cli-plugins/docker-dev)
 - plugin: docker-extension 		(actual path /Applications/Docker.app/Contents/Resources/cli-plugins/docker-extension)
 - plugin: docker-init 			(actual path /Applications/Docker.app/Contents/Resources/cli-plugins/docker-init)
 - plugin: docker-sbom 			(actual path /Applications/Docker.app/Contents/Resources/cli-plugins/docker-sbom)
 - plugin: docker-scout 		(actual path /Applications/Docker.app/Contents/Resources/cli-plugins/docker-scout)
Listing plugins in /usr/local/libexec/docker/cli-plugins
Listing plugins in /usr/lib/docker/cli-plugins
Listing plugins in /usr/libexec/docker/cli-plugins
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

Which gets used in order of priority;

Plugin: docker desktop
  1. /Applications/Docker.app/Contents/Resources/cli-plugins/docker-desktop
  2. /Users/thajeztah/.docker/cli-plugins/docker-desktop
  3. /usr/local/lib/docker/cli-plugins/docker-desktop
Plugin: docker sbom
  1. /Applications/Docker.app/Contents/Resources/cli-plugins/docker-sbom
  2. /Users/thajeztah/.docker/cli-plugins/docker-sbom
  3. /usr/local/lib/docker/cli-plugins/docker-sbom
Plugin: docker feedback
  1. /Users/thajeztah/.docker/cli-plugins/docker-feedback
Plugin: docker ai
  1. /Applications/Docker.app/Contents/Resources/cli-plugins/docker-ai
  2. /Users/thajeztah/.docker/cli-plugins/docker-ai
  3. /usr/local/lib/docker/cli-plugins/docker-ai
Plugin: docker cloud
  1. /Applications/Docker.app/Contents/Resources/cli-plugins/docker-cloud
  2. /usr/local/lib/docker/cli-plugins/docker-cloud
Plugin: docker debug
  1. /Applications/Docker.app/Contents/Resources/cli-plugins/docker-debug
  2. /Users/thajeztah/.docker/cli-plugins/docker-debug
  3. /usr/local/lib/docker/cli-plugins/docker-debug
Plugin: docker dev
  1. /Applications/Docker.app/Contents/Resources/cli-plugins/docker-dev
  2. /Users/thajeztah/.docker/cli-plugins/docker-dev
  3. /usr/local/lib/docker/cli-plugins/docker-dev
Plugin: docker extension
  1. /Applications/Docker.app/Contents/Resources/cli-plugins/docker-extension
  2. /Users/thajeztah/.docker/cli-plugins/docker-extension
  3. /usr/local/lib/docker/cli-plugins/docker-extension
Plugin: docker init
  1. /Applications/Docker.app/Contents/Resources/cli-plugins/docker-init
  2. /Users/thajeztah/.docker/cli-plugins/docker-init
  3. /usr/local/lib/docker/cli-plugins/docker-init
Plugin: docker scout
  1. /Applications/Docker.app/Contents/Resources/cli-plugins/docker-scout
  2. /Users/thajeztah/.docker/cli-plugins/docker-scout
  3. /usr/local/lib/docker/cli-plugins/docker-scout
Plugin: docker shell
  1. /Users/thajeztah/.docker/cli-plugins/docker-shell
Plugin: docker buildx
  1. /Applications/Docker.app/Contents/Resources/cli-plugins/docker-buildx
  2. /Users/thajeztah/.docker/cli-plugins/docker-buildx
  3. /usr/local/lib/docker/cli-plugins/docker-buildx
Plugin: docker compose
  1. /Applications/Docker.app/Contents/Resources/cli-plugins/docker-compose
  2. /Users/thajeztah/.docker/cli-plugins/docker-compose
  3. /usr/local/lib/docker/cli-plugins/docker-compose
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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants