Skip to content
This repository has been archived by the owner on Jan 17, 2021. It is now read-only.

Commit

Permalink
move SSH master process tidyup to a deferred func
Browse files Browse the repository at this point in the history
- Replace the `ssh -O exit` tidyup command with just a SIGTERM on the
  master
- Add `exec` to the front of the SSH master cmd so it replaces the `sh`
  process (so we can send SIGTERM to it easier)
  • Loading branch information
deansheather committed Jun 13, 2019
1 parent e646d57 commit 3141f7f
Showing 1 changed file with 27 additions and 39 deletions.
66 changes: 27 additions & 39 deletions sshcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"os/signal"
"path/filepath"
"strconv"
"syscall"
"strings"
"time"

Expand Down Expand Up @@ -57,32 +58,36 @@ func sshCode(host, dir string, o options) error {

// Start SSH master connection socket. This prevents multiple password prompts from appearing as authentication
// only happens on the initial connection.
var sshMasterCmd *exec.Cmd
if !o.noReuseConnection {
newSSHFlags := fmt.Sprintf(`%v -o "ControlPath=%v"`, o.sshFlags, sshControlPath)

// -MN means "start a master socket and don't open a session, just connect".
sshMasterCmdStr := fmt.Sprintf(`ssh %v -MN %v`, newSSHFlags, host)
sshMasterCmd = exec.Command("sh", "-c", sshMasterCmdStr)
sshCmdStr := fmt.Sprintf(`exec ssh %v -MN %v`, newSSHFlags, host)
sshMasterCmd := exec.Command("sh", "-c", sshCmdStr)
sshMasterCmd.Stdin = os.Stdin
sshMasterCmd.Stdout = os.Stdout
sshMasterCmd.Stderr = os.Stderr
stopSSHMaster := func () {
if sshMasterCmd.Process != nil {
err := sshMasterCmd.Process.Signal(syscall.SIGTERM)
if err != nil {
flog.Error("failed to send SIGTERM to SSH master process: %v", err)
}
}
}
defer stopSSHMaster()

err = sshMasterCmd.Start()
if err != nil {
flog.Error("failed to start SSH master connection, disabling connection reuse feature: %v", err)
o.noReuseConnection = true
stopSSHMaster()
} else {
// Wait for master to be ready.
err = checkSSHMaster(newSSHFlags, host)
if err != nil {
flog.Error("SSH master failed to start in time, disabling connection reuse feature: %v", err)
flog.Error("SSH master failed to be ready in time, disabling connection reuse feature: %v", err)
o.noReuseConnection = true
if sshMasterCmd.Process != nil {
err = sshMasterCmd.Process.Kill()
if err != nil {
flog.Error("failed to kill SSH master connection, ignoring: %v", err)
}
}
stopSSHMaster()
} else {
sshMasterCmd.Stdin = nil
o.sshFlags = newSSHFlags
Expand Down Expand Up @@ -183,39 +188,22 @@ func sshCode(host, dir string, o options) error {
case <-ctx.Done():
case <-c:
}
flog.Info("exiting")

if o.syncBack && !o.skipSync {
flog.Info("synchronizing VS Code back to local")
flog.Info("shutting down")
if !o.syncBack || o.skipSync {
return nil
}

err = syncExtensions(o.sshFlags, host, true)
if err != nil {
flog.Error("failed to sync extensions back: %v", err)
}
flog.Info("synchronizing VS Code back to local")

err = syncUserSettings(o.sshFlags, host, true)
if err != nil {
flog.Error("failed to sync user settings settings back: %v", err)
}
err = syncExtensions(o.sshFlags, host, true)
if err != nil {
return xerrors.Errorf("failed to sync extensions back: %v", err)
}

// Kill the master connection if we made one.
if !o.noReuseConnection {
// Try using the -O exit syntax first before killing the master.
sshCmdStr = fmt.Sprintf(`ssh %v -O exit %v`, o.sshFlags, host)
sshCmd = exec.Command("sh", "-c", sshCmdStr)
sshCmd.Stdout = os.Stdout
sshCmd.Stderr = os.Stderr
err = sshCmd.Run()
if err != nil {
flog.Error("failed to gracefully stop SSH master connection, killing: %v", err)
if sshMasterCmd.Process != nil {
err = sshMasterCmd.Process.Kill()
if err != nil {
flog.Error("failed to kill SSH master connection, ignoring: %v", err)
}
}
}
err = syncUserSettings(o.sshFlags, host, true)
if err != nil {
return xerrors.Errorf("failed to sync user settings settings back: %v", err)
}

return nil
Expand Down

0 comments on commit 3141f7f

Please sign in to comment.