-
Notifications
You must be signed in to change notification settings - Fork 38.7k
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
Close connection and stop listening when port forwarding errors occur so that kubectl can exit #103526
Conversation
/cc @deads2k you had some comments on a different, unmerged PR a few months ago for this issue. |
/assign |
This looks reasonable. Can you add a unit test? |
1a19be1
to
33cda18
Compare
Good idea. I added a couple unit tests. |
/retest |
6e41199
to
9596c48
Compare
/retest |
@@ -231,6 +233,8 @@ func (pf *PortForwarder) forward() error { | |||
case <-pf.stopChan: | |||
case <-pf.streamConn.CloseChan(): | |||
runtime.HandleError(errors.New("lost connection to pod")) | |||
case err := <-pf.errorChan: |
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.
- in the first case, a stop was called. portforward should probably shut down its ports on this for the library (pr wanted), but the intent is likely "process shutting down" when we wrote it.
- in the second case, the streamconnection was lost
- in this new case, the local handleConnection will stop https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/client-go/tools/portforward/portforward.go#L356, but the callsite will restart it: https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/client-go/tools/portforward/portforward.go#L302-L312
if I'm reading this code correctly, this would return an error back and start listening on the port again. the tests are for the handleConnection, but miss the waitForConnection which will restart it indefinitely.
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.
This error actually gets returned all the way up to the kubectl command itself and stops execution.
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 think that still races for whether the ForwardPort go route runs before the reconnect from waitForConnection.
I'm supportive of trying to return errors. I just want deterministic behavior when we make this change. Closing a stop channel (or even better a context) that is honored throughout the call chain is an approach that will make this deterministic and non-leaky.
/hold holding until #103526 (comment) is resolved. |
bd06c69
to
aa8652b
Compare
aa8652b
to
4a35e6c
Compare
/retest |
return | ||
} | ||
go pf.handleConnection(conn, port) |
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.
pre-existng and not blocking for this PR, but this code is so strange. it seems ripe for cleanup to have fewer go funcs launch go funcs and infinite loops.
runtime.HandleError(fmt.Errorf("error accepting connection on port %d: %v", port.Local, err)) | ||
} | ||
select { | ||
case <-pf.streamConn.CloseChan(): |
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 improvement.
I think that overall the existing code could benefit from simplification and context wiring, but this PR now looks predictable to me. /approve |
bug fix /milestone v1.23 |
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.
/lgtm
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: brianpursley, deads2k, eddiezane, justinmchase The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
What type of PR is this?
/kind bug
What this PR does / why we need it:
Currently, if port forwarding and the connection is lost and re-established, port forwarding gets into an unrecoverable state where it logs errors but does not fail. When this happens port forwarding no longer is working, but there is no way to handle this case except to manually terminate kubectl.
This PR changes the port forwarding code to capture errors that are received on the error stream and surface them to be returned so that kubectl can exit with a non-zero exit code instead of being "hung" in an unrecoverable error state.This PR changes the port forwarding code to close the remote connection and stop listening for new connections when an error occurs while port forwarding.
Which issue(s) this PR fixes:
Related to kubernetes/kubectl#686
Special notes for your reviewer:
Does this PR introduce a user-facing change?
Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.: