diff --git a/go.mod b/go.mod index 8e342849..16863080 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/containerd/typeurl/v2 v2.1.1 github.com/creack/pty v1.1.18 github.com/distribution/reference v0.5.0 - github.com/docker/cli v25.0.0-rc.1+incompatible + github.com/docker/cli v25.0.1+incompatible github.com/docker/cli-docs-tool v0.6.0 github.com/docker/docker v25.0.1+incompatible github.com/docker/go-units v0.5.0 diff --git a/go.sum b/go.sum index d4b0ad65..caf135d9 100644 --- a/go.sum +++ b/go.sum @@ -119,8 +119,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/cli v25.0.0-rc.1+incompatible h1:TRaJCO3nQ0XvMWa8gUeIKRO8Dq61QQClpMWV0PmSDHA= -github.com/docker/cli v25.0.0-rc.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v25.0.1+incompatible h1:mFpqnrS6Hsm3v1k7Wa/BO23oz0k121MTbTO1lpcGSkU= +github.com/docker/cli v25.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli-docs-tool v0.6.0 h1:Z9x10SaZgFaB6jHgz3OWooynhSa40CsWkpe5hEnG/qA= github.com/docker/cli-docs-tool v0.6.0/go.mod h1:zMjqTFCU361PRh8apiXzeAZ1Q/xupbIwTusYpzCXS/o= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= diff --git a/vendor/github.com/docker/cli/cli-plugins/manager/manager.go b/vendor/github.com/docker/cli/cli-plugins/manager/manager.go index bcf15054..d2393494 100644 --- a/vendor/github.com/docker/cli/cli-plugins/manager/manager.go +++ b/vendor/github.com/docker/cli/cli-plugins/manager/manager.go @@ -11,6 +11,7 @@ import ( "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/config" + "github.com/docker/cli/cli/config/configfile" "github.com/fvbommel/sortorder" "github.com/spf13/cobra" "golang.org/x/sync/errgroup" @@ -42,10 +43,10 @@ func IsNotFound(err error) bool { return ok } -func getPluginDirs(dockerCli command.Cli) ([]string, error) { +func getPluginDirs(cfg *configfile.ConfigFile) ([]string, error) { var pluginDirs []string - if cfg := dockerCli.ConfigFile(); cfg != nil { + if cfg != nil { pluginDirs = append(pluginDirs, cfg.CLIPluginsExtraDirs...) } pluginDir, err := config.Path("cli-plugins") @@ -108,7 +109,7 @@ func listPluginCandidates(dirs []string) (map[string][]string, error) { // GetPlugin returns a plugin on the system by its name func GetPlugin(name string, dockerCli command.Cli, rootcmd *cobra.Command) (*Plugin, error) { - pluginDirs, err := getPluginDirs(dockerCli) + pluginDirs, err := getPluginDirs(dockerCli.ConfigFile()) if err != nil { return nil, err } @@ -138,7 +139,7 @@ func GetPlugin(name string, dockerCli command.Cli, rootcmd *cobra.Command) (*Plu // ListPlugins produces a list of the plugins available on the system func ListPlugins(dockerCli command.Cli, rootcmd *cobra.Command) ([]Plugin, error) { - pluginDirs, err := getPluginDirs(dockerCli) + pluginDirs, err := getPluginDirs(dockerCli.ConfigFile()) if err != nil { return nil, err } @@ -198,7 +199,7 @@ func PluginRunCommand(dockerCli command.Cli, name string, rootcmd *cobra.Command return nil, errPluginNotFound(name) } exename := addExeSuffix(NamePrefix + name) - pluginDirs, err := getPluginDirs(dockerCli) + pluginDirs, err := getPluginDirs(dockerCli.ConfigFile()) if err != nil { return nil, err } diff --git a/vendor/github.com/docker/cli/cli-plugins/plugin/plugin.go b/vendor/github.com/docker/cli/cli-plugins/plugin/plugin.go index 829e1baa..54471b41 100644 --- a/vendor/github.com/docker/cli/cli-plugins/plugin/plugin.go +++ b/vendor/github.com/docker/cli/cli-plugins/plugin/plugin.go @@ -3,26 +3,19 @@ package plugin import ( "context" "encoding/json" - "errors" "fmt" - "io" - "net" "os" "sync" "github.com/docker/cli/cli" "github.com/docker/cli/cli-plugins/manager" + "github.com/docker/cli/cli-plugins/socket" "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/connhelper" "github.com/docker/docker/client" "github.com/spf13/cobra" ) -// CLIPluginSocketEnvKey is used to pass the plugin being -// executed the abstract socket name it should listen on to know -// when the CLI has exited. -const CLIPluginSocketEnvKey = "DOCKER_CLI_PLUGIN_SOCKET" - // PersistentPreRunE must be called by any plugin command (or // subcommand) which uses the cobra `PersistentPreRun*` hook. Plugins // which do not make use of `PersistentPreRun*` do not need to call @@ -33,38 +26,6 @@ const CLIPluginSocketEnvKey = "DOCKER_CLI_PLUGIN_SOCKET" // called. var PersistentPreRunE func(*cobra.Command, []string) error -// closeOnCLISocketClose connects to the socket specified -// by the DOCKER_CLI_PLUGIN_SOCKET env var, if present, and attempts -// to read from it until it receives an EOF, which signals that -// the CLI is going to exit and the plugin should also exit. -func closeOnCLISocketClose(cancel func()) { - socketAddr, ok := os.LookupEnv(CLIPluginSocketEnvKey) - if !ok { - // if a plugin compiled against a more recent version of docker/cli - // is executed by an older CLI binary, ignore missing environment - // variable and behave as usual - return - } - addr, err := net.ResolveUnixAddr("unix", socketAddr) - if err != nil { - return - } - cliCloseConn, err := net.DialUnix("unix", nil, addr) - if err != nil { - return - } - - go func() { - b := make([]byte, 1) - for { - _, err := cliCloseConn.Read(b) - if errors.Is(err, io.EOF) { - cancel() - } - } - }() -} - // RunPlugin executes the specified plugin command func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager.Metadata) error { tcmd := newPluginCommand(dockerCli, plugin, meta) @@ -81,7 +42,8 @@ func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager } ctx, cancel := context.WithCancel(cmdContext) cmd.SetContext(ctx) - closeOnCLISocketClose(cancel) + // Set up the context to cancel based on signalling via CLI socket. + socket.ConnectAndWait(cancel) var opts []command.CLIOption if os.Getenv("DOCKER_CLI_PLUGIN_USE_DIAL_STDIO") != "" { diff --git a/vendor/github.com/docker/cli/cli-plugins/socket/socket.go b/vendor/github.com/docker/cli/cli-plugins/socket/socket.go new file mode 100644 index 00000000..93d7a87b --- /dev/null +++ b/vendor/github.com/docker/cli/cli-plugins/socket/socket.go @@ -0,0 +1,72 @@ +package socket + +import ( + "errors" + "io" + "net" + "os" + + "github.com/docker/distribution/uuid" +) + +// EnvKey represents the well-known environment variable used to pass the plugin being +// executed the socket name it should listen on to coordinate with the host CLI. +const EnvKey = "DOCKER_CLI_PLUGIN_SOCKET" + +// SetupConn sets up a Unix socket listener, establishes a goroutine to handle connections +// and update the conn pointer, and returns the listener for the socket (which the caller +// is responsible for closing when it's no longer needed). +func SetupConn(conn **net.UnixConn) (*net.UnixListener, error) { + listener, err := listen("docker_cli_" + uuid.Generate().String()) + if err != nil { + return nil, err + } + + accept(listener, conn) + + return listener, nil +} + +func accept(listener *net.UnixListener, conn **net.UnixConn) { + go func() { + for { + // ignore error here, if we failed to accept a connection, + // conn is nil and we fallback to previous behavior + *conn, _ = listener.AcceptUnix() + // perform any platform-specific actions on accept (e.g. unlink non-abstract sockets) + onAccept(*conn, listener) + } + }() +} + +// ConnectAndWait connects to the socket passed via well-known env var, +// if present, and attempts to read from it until it receives an EOF, at which +// point cb is called. +func ConnectAndWait(cb func()) { + socketAddr, ok := os.LookupEnv(EnvKey) + if !ok { + // if a plugin compiled against a more recent version of docker/cli + // is executed by an older CLI binary, ignore missing environment + // variable and behave as usual + return + } + addr, err := net.ResolveUnixAddr("unix", socketAddr) + if err != nil { + return + } + conn, err := net.DialUnix("unix", nil, addr) + if err != nil { + return + } + + go func() { + b := make([]byte, 1) + for { + _, err := conn.Read(b) + if errors.Is(err, io.EOF) { + cb() + return + } + } + }() +} diff --git a/vendor/github.com/docker/cli/cli-plugins/socket/socket_darwin.go b/vendor/github.com/docker/cli/cli-plugins/socket/socket_darwin.go new file mode 100644 index 00000000..17ab6aa6 --- /dev/null +++ b/vendor/github.com/docker/cli/cli-plugins/socket/socket_darwin.go @@ -0,0 +1,19 @@ +package socket + +import ( + "net" + "os" + "path/filepath" + "syscall" +) + +func listen(socketname string) (*net.UnixListener, error) { + return net.ListenUnix("unix", &net.UnixAddr{ + Name: filepath.Join(os.TempDir(), socketname), + Net: "unix", + }) +} + +func onAccept(conn *net.UnixConn, listener *net.UnixListener) { + syscall.Unlink(listener.Addr().String()) +} diff --git a/vendor/github.com/docker/cli/cli-plugins/socket/socket_nodarwin.go b/vendor/github.com/docker/cli/cli-plugins/socket/socket_nodarwin.go new file mode 100644 index 00000000..893e465e --- /dev/null +++ b/vendor/github.com/docker/cli/cli-plugins/socket/socket_nodarwin.go @@ -0,0 +1,19 @@ +//go:build !darwin + +package socket + +import ( + "net" +) + +func listen(socketname string) (*net.UnixListener, error) { + return net.ListenUnix("unix", &net.UnixAddr{ + Name: "@" + socketname, + Net: "unix", + }) +} + +func onAccept(conn *net.UnixConn, listener *net.UnixListener) { + // do nothing + // while on darwin we would unlink here; on non-darwin the socket is abstract and not present on the filesystem +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 1b4271c6..aaa978cf 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -199,11 +199,12 @@ github.com/davecgh/go-spew/spew # github.com/distribution/reference v0.5.0 ## explicit; go 1.20 github.com/distribution/reference -# github.com/docker/cli v25.0.0-rc.1+incompatible +# github.com/docker/cli v25.0.1+incompatible ## explicit github.com/docker/cli/cli github.com/docker/cli/cli-plugins/manager github.com/docker/cli/cli-plugins/plugin +github.com/docker/cli/cli-plugins/socket github.com/docker/cli/cli/command github.com/docker/cli/cli/command/formatter github.com/docker/cli/cli/command/formatter/tabwriter