From f67239f3024cc0df35ccccc1685b38fdf8d510b0 Mon Sep 17 00:00:00 2001 From: Brian de Alwis Date: Wed, 17 Jul 2019 18:54:15 -0400 Subject: [PATCH] terminal: prompt to kill remote if process exited (#1621) --- pkg/terminal/terminal.go | 19 +++++++++++++++++++ pkg/terminal/terminal_test.go | 20 ++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/pkg/terminal/terminal.go b/pkg/terminal/terminal.go index 067bdd62..6475acb6 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 05c78c7b..e6a37910 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) + } + } +} -- GitLab