diff --git a/pkg/terminal/terminal.go b/pkg/terminal/terminal.go index 067bdd6221a4968d3c1aa5600a36462ac0d31d86..6475acb6b4765a6782a45faed544148b78af189f 100644 --- a/pkg/terminal/terminal.go +++ b/pkg/terminal/terminal.go @@ -3,6 +3,7 @@ package terminal import ( "fmt" "io" + "net/rpc" "os" "os/signal" "runtime" @@ -353,6 +354,18 @@ func (t *Term) handleExit() (int, error) { s, err := t.client.GetState() if err != nil { + if isErrProcessExited(err) && t.client.IsMulticlient() { + answer, err := yesno(t.line, "Remote process has exited. Would you like to kill the headless instance? [Y/n] ") + if err != nil { + return 2, io.EOF + } + if answer { + if err := t.client.Detach(true); err != nil { + return 1, err + } + } + return 0, err + } return 1, err } if !s.Exited { @@ -404,3 +417,9 @@ func (t *Term) loadConfig() api.LoadConfig { return r } + +// isErrProcessExited returns true if `err` is an RPC error equivalent of proc.ErrProcessExited +func isErrProcessExited(err error) bool { + rpcError, ok := err.(rpc.ServerError) + return ok && strings.Contains(rpcError.Error(), "has exited with status") +} diff --git a/pkg/terminal/terminal_test.go b/pkg/terminal/terminal_test.go index 05c78c7b198e4f541fea82f533a5a3fca6fea5a8..e6a3791099231cc22799caa6f1b442065598f4ec 100644 --- a/pkg/terminal/terminal_test.go +++ b/pkg/terminal/terminal_test.go @@ -1,6 +1,8 @@ package terminal import ( + "errors" + "net/rpc" "runtime" "testing" @@ -85,3 +87,21 @@ func TestSubstitutePath(t *testing.T) { } } } + +func TestIsErrProcessExited(t *testing.T) { + tests := []struct { + name string + err error + result bool + }{ + {"empty error", errors.New(""), false}, + {"non-ServerError", errors.New("Process 33122 has exited with status 0"), false}, + {"ServerError with zero status", rpc.ServerError("Process 33122 has exited with status 0"), true}, + {"ServerError with non-zero status", rpc.ServerError("Process 2 has exited with status 25"), true}, + } + for _, test := range tests { + if isErrProcessExited(test.err) != test.result { + t.Error(test.name) + } + } +}