From 951dceebf648a656533bebf9df54122859660118 Mon Sep 17 00:00:00 2001 From: Matthew MacLeod Date: Sat, 16 Nov 2024 20:41:47 +0000 Subject: [PATCH] cli/connhelper: support overriding the docker binary over SSH This change adds the ability to override the docker binary used when executing commands over SSH. This is useful when the docker binary is not in the PATH of the SSH user, or when the binary is not named `docker`. If `DOCKER_SSH_REMOTE_BINARY` is set in the environment, the value will be used as the docker binary when executing commands over SSH. If the environment variable is not set, the default value of `docker` will be used. --- cli/connhelper/connhelper.go | 21 ++++++++++++++++++++- cli/connhelper/connhelper_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/cli/connhelper/connhelper.go b/cli/connhelper/connhelper.go index 152d3e2953a8..e93bf5f61a5e 100644 --- a/cli/connhelper/connhelper.go +++ b/cli/connhelper/connhelper.go @@ -5,6 +5,7 @@ import ( "context" "net" "net/url" + "os" "strings" "github.com/docker/cli/cli/connhelper/commandconn" @@ -12,6 +13,12 @@ import ( "github.com/pkg/errors" ) +const ( + // DockerSSHRemoteBinaryEnv is the environment variable that can be used to + // override the default Docker binary called over SSH + DockerSSHRemoteBinaryEnv = "DOCKER_SSH_REMOTE_BINARY" +) + // ConnectionHelper allows to connect to a remote host with custom stream provider binary. type ConnectionHelper struct { Dialer func(ctx context.Context, network, addr string) (net.Conn, error) @@ -49,7 +56,7 @@ func getConnectionHelper(daemonURL string, sshFlags []string) (*ConnectionHelper sshFlags = disablePseudoTerminalAllocation(sshFlags) return &ConnectionHelper{ Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) { - args := []string{"docker"} + args := []string{dockerSSHRemoteBinary()} if sp.Path != "" { args = append(args, "--host", "unix://"+sp.Path) } @@ -91,3 +98,15 @@ func disablePseudoTerminalAllocation(sshFlags []string) []string { } return append(sshFlags, "-T") } + +// dockerSSHRemoteBinary returns the binary to use when executing Docker +// commands over SSH. It defaults to "docker" if the DOCKER_SSH_REMOTE_BINARY +// environment variable is not set. +func dockerSSHRemoteBinary() string { + value := os.Getenv(DockerSSHRemoteBinaryEnv) + if value == "" { + return "docker" + } + + return value +} diff --git a/cli/connhelper/connhelper_test.go b/cli/connhelper/connhelper_test.go index 0d9aee0fb2c6..a5de3db5ac36 100644 --- a/cli/connhelper/connhelper_test.go +++ b/cli/connhelper/connhelper_test.go @@ -63,3 +63,32 @@ func TestDisablePseudoTerminalAllocation(t *testing.T) { }) } } + +func TestDockerSSHBinaryOverride(t *testing.T) { + testCases := []struct { + name string + env string + expected string + }{ + { + name: "Default", + env: "", + expected: "docker", + }, + { + name: "Override", + env: "other-binary", + expected: "other-binary", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Setenv(DockerSSHRemoteBinaryEnv, tc.env) + result := dockerSSHRemoteBinary() + if result != tc.expected { + t.Errorf("expected %q, got %q", tc.expected, result) + } + }) + } +}