diff --git a/pkg/commands/docker.go b/pkg/commands/docker.go index e0accbf..95117cf 100644 --- a/pkg/commands/docker.go +++ b/pkg/commands/docker.go @@ -74,7 +74,7 @@ func (c *DockerCommand) NewCommandObject(obj CommandObject) CommandObject { // NewDockerCommand it runs docker commands func NewDockerCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.TranslationSet, config *config.AppConfig, errorChan chan error) (*DockerCommand, error) { - tunnelCloser, err := ssh.NewSSHHandler().HandleSSHDockerHost() + tunnelCloser, err := ssh.NewSSHHandler(osCommand).HandleSSHDockerHost() if err != nil { ogLog.Fatal(err) } @@ -237,7 +237,7 @@ func (c *DockerCommand) RefreshContainersAndServices() error { c.assignContainersToServices(containers, services) - var displayContainers = containers + displayContainers := containers if !c.Config.UserConfig.Gui.ShowAllContainers { displayContainers = c.obtainStandaloneContainers(containers, services) } @@ -468,7 +468,6 @@ func (c *DockerCommand) DockerComposeConfig() string { c.NewCommandObject(CommandObject{}), ), ) - if err != nil { output = err.Error() } diff --git a/pkg/commands/ssh/ssh.go b/pkg/commands/ssh/ssh.go index 474affa..9f57268 100644 --- a/pkg/commands/ssh/ssh.go +++ b/pkg/commands/ssh/ssh.go @@ -10,12 +10,18 @@ import ( "os" "os/exec" "path" - "syscall" "time" ) -type dependencies struct { - // storing all these dependencies as fields for the sake of testing +// we only need these two methods from our OSCommand struct, for killing commands +type CmdKiller interface { + Kill(cmd *exec.Cmd) error + PrepareForChildren(cmd *exec.Cmd) +} + +type SSHHandler struct { + oSCommand CmdKiller + dialContext func(ctx context.Context, network, addr string) (io.Closer, error) startCmd func(*exec.Cmd) error tempDir func(dir string, pattern string) (name string, err error) @@ -23,21 +29,17 @@ type dependencies struct { setenv func(key, value string) error } -type SSHHandler struct { - deps dependencies -} - -func NewSSHHandler() *SSHHandler { +func NewSSHHandler(oSCommand CmdKiller) *SSHHandler { return &SSHHandler{ - deps: dependencies{ - dialContext: func(ctx context.Context, network, addr string) (io.Closer, error) { - return (&net.Dialer{}).DialContext(ctx, network, addr) - }, - startCmd: func(cmd *exec.Cmd) error { return cmd.Start() }, - tempDir: ioutil.TempDir, - getenv: os.Getenv, - setenv: os.Setenv, + oSCommand: oSCommand, + + dialContext: func(ctx context.Context, network, addr string) (io.Closer, error) { + return (&net.Dialer{}).DialContext(ctx, network, addr) }, + startCmd: func(cmd *exec.Cmd) error { return cmd.Start() }, + tempDir: ioutil.TempDir, + getenv: os.Getenv, + setenv: os.Setenv, } } @@ -46,7 +48,7 @@ func NewSSHHandler() *SSHHandler { func (self *SSHHandler) HandleSSHDockerHost() (io.Closer, error) { const key = "DOCKER_HOST" ctx := context.Background() - u, err := url.Parse(self.deps.getenv(key)) + u, err := url.Parse(self.getenv(key)) if err != nil { // if no or an invalid docker host is specified, continue nominally return noopCloser{}, nil @@ -58,7 +60,7 @@ func (self *SSHHandler) HandleSSHDockerHost() (io.Closer, error) { if err != nil { return noopCloser{}, fmt.Errorf("tunnel ssh docker host: %w", err) } - err = self.deps.setenv(key, tunnel.socketPath) + err = self.setenv(key, tunnel.socketPath) if err != nil { return noopCloser{}, fmt.Errorf("override DOCKER_HOST to tunneled socket: %w", err) } @@ -75,16 +77,17 @@ func (noopCloser) Close() error { return nil } type tunneledDockerHost struct { socketPath string cmd *exec.Cmd + oSCommand CmdKiller } var _ io.Closer = (*tunneledDockerHost)(nil) func (t *tunneledDockerHost) Close() error { - return syscall.Kill(-t.cmd.Process.Pid, syscall.SIGKILL) + return t.oSCommand.Kill(t.cmd) } func (self *SSHHandler) createDockerHostTunnel(ctx context.Context, remoteHost string) (*tunneledDockerHost, error) { - socketDir, err := self.deps.tempDir("/tmp", "lazydocker-sshtunnel-") + socketDir, err := self.tempDir("/tmp", "lazydocker-sshtunnel-") if err != nil { return nil, fmt.Errorf("create ssh tunnel tmp file: %w", err) } @@ -111,6 +114,7 @@ func (self *SSHHandler) createDockerHostTunnel(ctx context.Context, remoteHost s return &tunneledDockerHost{ socketPath: newDockerHostURL.String(), cmd: cmd, + oSCommand: self.oSCommand, }, nil } @@ -137,7 +141,7 @@ func (self *SSHHandler) retrySocketDial(ctx context.Context, socketPath string) // Try to dial the specified unix socket, immediately close the connection if successfully created. func (self *SSHHandler) tryDial(ctx context.Context, socketPath string) error { - conn, err := self.deps.dialContext(ctx, "unix", socketPath) + conn, err := self.dialContext(ctx, "unix", socketPath) if err != nil { return err } @@ -147,8 +151,8 @@ func (self *SSHHandler) tryDial(ctx context.Context, socketPath string) error { func (self *SSHHandler) tunnelSSH(ctx context.Context, host, localSocket string) (*exec.Cmd, error) { cmd := exec.CommandContext(ctx, "ssh", "-L", localSocket+":/var/run/docker.sock", host, "-N") - cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} - err := self.deps.startCmd(cmd) + self.oSCommand.PrepareForChildren(cmd) + err := self.startCmd(cmd) if err != nil { return nil, err } diff --git a/pkg/commands/ssh/ssh_test.go b/pkg/commands/ssh/ssh_test.go index 5c16e22..f1ea1b9 100644 --- a/pkg/commands/ssh/ssh_test.go +++ b/pkg/commands/ssh/ssh_test.go @@ -65,7 +65,6 @@ func TestSSHHandlerHandleSSHDockerHost(t *testing.T) { startCmdCount := 0 startCmd := func(cmd *exec.Cmd) error { assert.EqualValues(t, []string{"ssh", "-L", "/tmp/lazydocker-ssh-tunnel-12345/dockerhost.sock:/var/run/docker.sock", "192.168.5.178", "-N"}, cmd.Args) - assert.Equal(t, true, cmd.SysProcAttr.Setpgid) startCmdCount++ @@ -83,13 +82,13 @@ func TestSSHHandlerHandleSSHDockerHost(t *testing.T) { } handler := &SSHHandler{ - deps: dependencies{ - dialContext: dialContext, - startCmd: startCmd, - tempDir: tempDir, - getenv: getenv, - setenv: setenv, - }, + oSCommand: &fakeCmdKiller{}, + + dialContext: dialContext, + startCmd: startCmd, + tempDir: tempDir, + getenv: getenv, + setenv: setenv, } _, err := handler.HandleSSHDockerHost() @@ -100,3 +99,11 @@ func TestSSHHandlerHandleSSHDockerHost(t *testing.T) { }) } } + +type fakeCmdKiller struct{} + +func (self *fakeCmdKiller) Kill(cmd *exec.Cmd) error { + return nil +} + +func (self *fakeCmdKiller) PrepareForChildren(cmd *exec.Cmd) {}