rewrote ssh handling to make it clearer

This commit is contained in:
Clément PÉAU 2025-05-04 13:39:11 +02:00
parent 6acacc7a3e
commit 099ae97e68
2 changed files with 25 additions and 21 deletions

View file

@ -72,26 +72,26 @@ func (c *DockerCommand) NewCommandObject(obj CommandObject) CommandObject {
} }
// NewDockerCommand creates a DockerCommand struct that wraps the docker client. // 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) { func NewDockerCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.TranslationSet, config *config.AppConfig, errorChan chan error) (*DockerCommand, error) {
dockerHost, err := determineDockerHost() dockerHost, err := determineDockerHost()
if err != nil { if err != nil {
ogLog.Printf("> could not determine host %v", err) 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 { if err != nil {
ogLog.Fatal(err) 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{ clientOpts := []client.Opt{
client.FromEnv, client.WithTLSClientConfigFromEnv(),
client.WithVersion(APIVersion), client.WithVersion(APIVersion),
} client.WithHost(dockerHost),
// 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))
} }
cli, err := client.NewClientWithOpts(clientOpts...) cli, err := client.NewClientWithOpts(clientOpts...)
@ -107,7 +107,7 @@ func NewDockerCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.Translat
Client: cli, Client: cli,
ErrorChan: errorChan, ErrorChan: errorChan,
InDockerComposeProject: true, InDockerComposeProject: true,
Closers: []io.Closer{tunnelCloser}, Closers: []io.Closer{tunnelResult.Closer},
} }
dockerCommand.setDockerComposeCommand(config) dockerCommand.setDockerComposeCommand(config)

View file

@ -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 // HandleSSHDockerHost overrides the DOCKER_HOST environment variable
// to point towards a local unix socket tunneled over SSH to the specified ssh host. // to point towards a local unix socket tunneled over SSH to the specified ssh host.
func (self *SSHHandler) HandleSSHDockerHost(dockerHost string) (io.Closer, error) { func (self *SSHHandler) HandleSSHDockerHost(dockerHost string) (TunnelResult, error) {
const key = "DOCKER_HOST"
ctx := context.Background()
u, err := url.Parse(dockerHost) u, err := url.Parse(dockerHost)
if err != nil { if err != nil {
// if no or an invalid docker host is specified, continue nominally // 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 the docker host scheme is "ssh", forward the docker socket before creating the client
if u.Scheme == "ssh" { if u.Scheme == "ssh" {
ctx := context.Background()
tunnel, err := self.createDockerHostTunnel(ctx, u.String()) tunnel, err := self.createDockerHostTunnel(ctx, u.String())
if err != nil { if err != nil {
return noopCloser{}, fmt.Errorf("tunnel ssh docker host: %w", err) return TunnelResult{Closer: 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 tunnel, nil return TunnelResult{
Closer: tunnel,
SocketPath: tunnel.socketPath,
Created: true,
}, nil
} }
return noopCloser{}, nil return TunnelResult{Closer: noopCloser{}}, nil
} }
type noopCloser struct{} type noopCloser struct{}