Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(overlord): send EOF to master pty in interactive mode #466

Merged
merged 1 commit into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion internals/overlord/cmdstate/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,12 @@ func (e *execution) do(ctx context.Context, task *state.Task) error {
// websocket and write to the PTY.
go func() {
<-wsutil.WebsocketRecvStream(master, ioConn)
master.Close()
// If the interactive is enforced, it is possible to finish
// reading earlier than the mirroring go routine sends all the
// output to the client. Thus, closing the master descriptor
// here will terminate mirroring prematurely. Instead, we
// should send Ctrl-D to the fd to indicate the end of input.
master.Write([]byte{byte(unix.VEOF)})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix makes sense, see e.g. https://stackoverflow.com/a/18366397/705086

I do wonder about some corner cases, e.g.:

  • pebble -i yada yada < somefile where input is not from a terminal, but the output is
  • all of stdin/stdout/stderr are redirected, and yet -i is supplied

Please consider how to test these -- unit tests? functional? one-off manual tests? I'm not sure what would be more appropriate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's not ideal, but we currently don't have any automated tests for interactive mode. We have on our roadmap for @IronCore864 to write end-to-end tests for pebble run; maybe some pebble exec -i tests can be included in that work?

In any case, I've done some pretty extensive manual testing of all the various exec modes, and this fix seems to work nicely. I've also tested that the number of file descriptors isn't increasing (leaking) by watching /bin/sh -c 'ls /proc/{pebble_pid}/fd/ | wc -l', and it's stable (stays at 10).

Tiexin has also done manual testing on this PR.

}()
} else {
// Non-interactive: start goroutine to receive stdin from "stdio"
Expand Down
2 changes: 1 addition & 1 deletion internals/wsutil/wsutil_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func MirrorToWebsocket(conn MessageWriter, r io.ReadCloser, exited chan struct{}
for {
buf, ok := <-in
if !ok {
r.Close()
_ = r.Close()
logger.Debugf("Sending write barrier")
err := conn.WriteMessage(websocket.TextMessage, endCommandJSON)
if err != nil {
Expand Down
Loading