From 099ae97e687b12d4aea53166504623e106f0ca17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=89AU?= Date: Sun, 4 May 2025 13:39:11 +0200 Subject: [PATCH] rewrote ssh handling to make it clearer --- pkg/commands/docker.go | 18 +++++++++--------- pkg/commands/ssh/ssh.go | 28 ++++++++++++++++------------ 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/pkg/commands/docker.go b/pkg/commands/docker.go index 43beaaf9..a6e702d7 100644 --- a/pkg/commands/docker.go +++ b/pkg/commands/docker.go @@ -72,26 +72,26 @@ func (c *DockerCommand) NewCommandObject(obj CommandObject) CommandObject { } // NewDockerCommand creates a DockerCommand struct that wraps the docker client. -// Able to run docker commands. And handles SSH docker hosts +// Able to run docker commands and handles SSH docker hosts func NewDockerCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.TranslationSet, config *config.AppConfig, errorChan chan error) (*DockerCommand, error) { dockerHost, err := determineDockerHost() if err != nil { ogLog.Printf("> could not determine host %v", err) } - tunnelCloser, err := ssh.NewSSHHandler(osCommand).HandleSSHDockerHost(dockerHost) + tunnelResult, err := ssh.NewSSHHandler(osCommand).HandleSSHDockerHost(dockerHost) if err != nil { ogLog.Fatal(err) } + // If we created a tunnel to the remote ssh host, we then override the dockerhost to point to the tunnel + if tunnelResult.Created { + dockerHost = tunnelResult.SocketPath + } clientOpts := []client.Opt{ - client.FromEnv, + client.WithTLSClientConfigFromEnv(), client.WithVersion(APIVersion), - } - // For an ssh connection the DOCKER_HOST env variable has been overridden. - // Discard the previously determined dockerHost - if !strings.HasPrefix(dockerHost, "ssh://") { - clientOpts = append(clientOpts, client.WithHost(dockerHost)) + client.WithHost(dockerHost), } cli, err := client.NewClientWithOpts(clientOpts...) @@ -107,7 +107,7 @@ func NewDockerCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.Translat Client: cli, ErrorChan: errorChan, InDockerComposeProject: true, - Closers: []io.Closer{tunnelCloser}, + Closers: []io.Closer{tunnelResult.Closer}, } dockerCommand.setDockerComposeCommand(config) diff --git a/pkg/commands/ssh/ssh.go b/pkg/commands/ssh/ssh.go index 4e78405d..fb85953c 100644 --- a/pkg/commands/ssh/ssh.go +++ b/pkg/commands/ssh/ssh.go @@ -42,32 +42,36 @@ func NewSSHHandler(oSCommand CmdKiller) *SSHHandler { } } +type TunnelResult struct { + Closer io.Closer + SocketPath string + Created bool +} + // HandleSSHDockerHost overrides the DOCKER_HOST environment variable // to point towards a local unix socket tunneled over SSH to the specified ssh host. -func (self *SSHHandler) HandleSSHDockerHost(dockerHost string) (io.Closer, error) { - const key = "DOCKER_HOST" - ctx := context.Background() - +func (self *SSHHandler) HandleSSHDockerHost(dockerHost string) (TunnelResult, error) { u, err := url.Parse(dockerHost) if err != nil { // if no or an invalid docker host is specified, continue nominally - return noopCloser{}, nil + return TunnelResult{Closer: noopCloser{}}, nil } // if the docker host scheme is "ssh", forward the docker socket before creating the client if u.Scheme == "ssh" { + ctx := context.Background() tunnel, err := self.createDockerHostTunnel(ctx, u.String()) if err != nil { - return noopCloser{}, fmt.Errorf("tunnel ssh docker host: %w", err) - } - err = self.setenv(key, tunnel.socketPath) - if err != nil { - return noopCloser{}, fmt.Errorf("override DOCKER_HOST to tunneled socket: %w", err) + return TunnelResult{Closer: noopCloser{}}, fmt.Errorf("tunnel ssh docker host: %w", err) } - return tunnel, nil + return TunnelResult{ + Closer: tunnel, + SocketPath: tunnel.socketPath, + Created: true, + }, nil } - return noopCloser{}, nil + return TunnelResult{Closer: noopCloser{}}, nil } type noopCloser struct{}