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.

Signed-off-by: Matthew MacLeod <matt@umm.io>
This commit is contained in:
Matthew MacLeod 2024-11-16 20:41:47 +00:00
parent 9861ce90fd
commit 43dbdcfe1e
2 changed files with 49 additions and 1 deletions

View File

@ -5,6 +5,7 @@ import (
"context" "context"
"net" "net"
"net/url" "net/url"
"os"
"strings" "strings"
"github.com/docker/cli/cli/connhelper/commandconn" "github.com/docker/cli/cli/connhelper/commandconn"
@ -12,6 +13,12 @@ import (
"github.com/pkg/errors" "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. // ConnectionHelper allows to connect to a remote host with custom stream provider binary.
type ConnectionHelper struct { type ConnectionHelper struct {
Dialer func(ctx context.Context, network, addr string) (net.Conn, error) 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) sshFlags = disablePseudoTerminalAllocation(sshFlags)
return &ConnectionHelper{ return &ConnectionHelper{
Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) { Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) {
args := []string{"docker"} args := []string{dockerSSHRemoteBinary()}
if sp.Path != "" { if sp.Path != "" {
args = append(args, "--host", "unix://"+sp.Path) args = append(args, "--host", "unix://"+sp.Path)
} }
@ -91,3 +98,15 @@ func disablePseudoTerminalAllocation(sshFlags []string) []string {
} }
return append(sshFlags, "-T") 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
}

View File

@ -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)
}
})
}
}