-
Notifications
You must be signed in to change notification settings - Fork 40k
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
Various exec fixes #13322
Various exec fixes #13322
Conversation
By("executing a command in the container with noninteractive stdin") | ||
execOutput = newKubectlCommand("exec", fmt.Sprintf("--namespace=%v", ns), "-i", simplePodName, "cat"). | ||
withStdinData("abcd1234"). | ||
exec() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for tests for this scenario
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, it would be easy to add a withStdin(io.Reader)
helper so we could also test an interactive exec with a stdin that sends "echo hello\nexit\n", then blocks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea. I'll definitely want to add that. Once I figure out why interactive is broken...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Blocks via select {}
or something else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, something like https://gist.github.com/liggitt/29077b2835004caab5c3
@@ -194,12 +194,19 @@ func (e *Streamer) doStream() error { | |||
if err != nil { | |||
return err | |||
} | |||
defer remoteStdin.Reset() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't you still need the deferred remoteStdin.Reset() in the case where the remoteStdin cp
never completes, or does the conn.Close() cover that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll check and see, but it's broken until #13324 lands. I can test w/that locally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, I'm surprised the remote connection was being held open with the deferred Reset() in place previously
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit of a chicken and egg game. With this scenario:
echo foo | kubectl exec -i <pod> cat
The cat
command won't terminate until it gets EOF from its stdin. Its stdin comes from the spdy stream. The spdy stream gets its stdin from the non interactive input (echo foo
). While foo
is fully read and closed, doStream
won't exit until cat
is done, but we aren't resetting remoteStdin
until doStream
exits, etc etc etc. This makes sure that remoteStdin
gets closed/reset as soon as the copy unblocks. Make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
interesting, the cp
essentially "intercepts" the EOF, so the remote command never sees it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, assuming I merged and rebuilt everything locally correctly, trying to exit an interactive shell is hanging. Grrr....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the deferred remoteStdin.Close() in the goroutine makes sense, but I would keep the deferred Reset()
in place
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, added it back.
GCE e2e build/test passed for commit 969e3dc30b424732e00ff500e045a02d24f1ca9c. |
969e3dc
to
51681c1
Compare
GCE e2e build/test failed for commit 51681c18fd7e08d6b27dc848ca97b87a9d7a28fa. |
Labelling this PR as size/M |
bfab798
to
57d4df4
Compare
@liggitt @smarterclayton PR updated. I think I've finally gotten there... |
Labelling this PR as size/L |
LGTM... the additional e2e tests give me a lot more confidence |
GCE e2e build/test passed for commit bfab798919aa7db3b0603be882dc077cb0d4f47c. |
And e2e passed, woot! |
... oh, for a previous commit. Guess we'll wait a bit longer |
GCE e2e build/test passed for commit 57d4df45975382f754102f5e194e787b2c0c06da. |
GCE e2e build/test failed for commit addece6f95d290f0d62f32591db6a73b683d0dc1. |
e2e failure looks like flakes:
@k8s-bot test this please |
GCE e2e build/test passed for commit addece6f95d290f0d62f32591db6a73b683d0dc1. |
If stdin is noninteractive, the io.Copy from stdin to remoteStdin will unblock when it finishes reading from stdin. In this case, make sure to close remoteStdin so the server knows the client won't be sending any more data. This ensures that the remote process terminates. For example: echo foo | kubectl exec -i <pod> -- cat Without this change, the `cat` process never terminates and `kubectl exec` hangs. Fix interactive exec sessions hanging after you type 'exit'. Add e2e test to cover noninteractive stdin: `echo a | kubectl exec -i <pod> cat` Add e2e test to cover psuedo-interactive stdin: `kubectl exec -i <pod> bash` Prep for sending multiple data frames over multiple streams in remote command test, which is more likely to find flakes (requires bump of spdystream once an issue with the frame worker queues not being fully drained when a goaway frame is received).
addece6
to
c837869
Compare
GCE e2e build/test failed for commit c837869. |
e2e flake
@k8s-bot test this please |
wondering how to kick what appears to be a hung e2e... @k8s-bot test this again please? |
GCE e2e build/test passed for commit c837869. |
Woot :-) |
If stdin is noninteractive, the io.Copy from stdin to remoteStdin will
unblock when it finishes reading from stdin. In this case, make sure to
close remoteStdin so the server knows the client won't be sending any
more data. This ensures that the remote process terminates. For example:
Without this change, the
cat
process never terminates andkubectl exec
hangs.Fix interactive exec sessions hanging after you type 'exit'.
Add e2e test to cover noninteractive stdin:
echo a | kubectl exec -i <pod> cat
Add e2e test to cover psuedo-interactive stdin:
kubectl exec -i <pod> bash
Prep for sending multiple data frames over multiple streams in remote command
test, which is more likely to find flakes (requires bump of spdystream
once an issue with the frame worker queues not being fully drained when
a goaway frame is received).
Fixes #13394
Fixes #13395
Release note info
Fixed hanging when using non-interactive stdin data, e.g.
echo foo | kubectl exec -i <pod> -- cat
Fixed interactive
kubectl exec
sessions hanging after you type 'exit'