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

WebSocket Client and V5 RemoteCommand Subprotocol #119157

Merged
merged 1 commit into from
Sep 5, 2023

Conversation

seans3
Copy link
Contributor

@seans3 seans3 commented Jul 7, 2023

  • Implements WebSocket client as WebSocketExecutor. The executor is not yet called by any client.
  • Creates new version 5 of remote command subprotocol
    • RemoteCommand Version 5 adds a CLOSE signal, which is handled on the websocket server by closing the STDIN stream allowing other streams to complete transmission and close gracefully.
    • doc.go in wsstream package describes every version of binary WebSockets RemoteCommand protocols.
  • Adds unit tests for new WebSocket client functionality
    • Increases tools/remotecommand test coverage from 53.8% to 75.5%.
    • File k8s.io/client-go/tools/remotecommmand/websocket.go has test coverage: 88.3%
  ok  	k8s.io/client-go/tools/remotecommand	coverage: 75.5% of statements
  ok  	k8s.io/client-go/transport/websocket	coverage: 71.4% of statements

Example stress test for WebSocket client testing STDIN and STDOUT stream

This loopback test sends 1MB of random data onto the STDIN stream copying the data back to the client onto the STDOUT stream.

$ stress ./remotecommand.test -test.run TestWebSocketClient_LoopbackStdinToStdout
5s: 4964 runs so far, 0 failures
10s: 9952 runs so far, 0 failures
15s: 14929 runs so far, 0 failures
20s: 19879 runs so far, 0 failures
25s: 24866 runs so far, 0 failures
30s: 29862 runs so far, 0 failures
35s: 34858 runs so far, 0 failures
40s: 39869 runs so far, 0 failures
45s: 44853 runs so far, 0 failures
50s: 49852 runs so far, 0 failures
55s: 54858 runs so far, 0 failures
1m0s: 59861 runs so far, 0 failures

Example stress test for WebSocket client sending multiple write streams concurrently (STDIN, TTY Resize)

$ stress ./remotecommand.test -test.run TestWebSocketClient_MultipleWriteChannels
5s: 675 runs so far, 0 failures                                                                                                                                                                        
10s: 1351 runs so far, 0 failures                                                                                                                                                                      
15s: 2057 runs so far, 0 failures                                                                                                                                                                      
20s: 2742 runs so far, 0 failures                                                                                                                                                                      
25s: 3426 runs so far, 0 failures                                                                                                                                                                      
30s: 4126 runs so far, 0 failures                                                                                                                                                                      
35s: 4836 runs so far, 0 failures                                                                                                                                                                      
40s: 5534 runs so far, 0 failures                                                                                                                                                                      
45s: 6225 runs so far, 0 failures                                                                                                                                                                      
50s: 6917 runs so far, 0 failures                                                                                                                                                                      
55s: 7612 runs so far, 0 failures                                                                                                                                                                      
1m0s: 8300 runs so far, 0 failures                                                                                                                                                                     
1m5s: 9006 runs so far, 0 failures                                                                                                                                                                     
1m10s: 9681 runs so far, 0 failures                                                                                                                                                                    
1m15s: 10368 runs so far, 0 failures 

/kind feature

Helps fix: #89163

NONE

NOTE: WebSocket client is implemented with the Gorilla WebSockets library

  • The other two possibilities are:
    1. golang stdlib websocket - which is used in the current WebSocket server code
    2. https://pkg.go.dev/nhooyr.io/websocket
  • All three libraries are very mature.
  • The Gorilla WebSockets library was used for the client because:
    1. It has far better support for client creation. The gorilla library client creation functions fit well with Kubernetes use of RoundTripper, because they return an http response which is part of the RoundTripper interface when other libraries do not.
    2. It has far better support for data messages other than binary (e.g. heartbeat ping/pong).
    3. Gorilla has direct support for proxies in the client, while the golang stdlib websockets does not.
    4. Until recently, the golang stdlib websocket library suggested using the Gorilla library as more feature rich.

@k8s-ci-robot k8s-ci-robot added release-note-none Denotes a PR that doesn't merit a release note. kind/feature Categorizes issue or PR as related to a new feature. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. do-not-merge/needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. needs-priority Indicates a PR lacks a `priority/foo` label and requires one. labels Jul 7, 2023
@seans3
Copy link
Contributor Author

seans3 commented Jul 7, 2023

/sig api-machinery

@k8s-ci-robot k8s-ci-robot added sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. and removed do-not-merge/needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. labels Jul 7, 2023
@seans3
Copy link
Contributor Author

seans3 commented Jul 7, 2023

/priority important-soon

@k8s-ci-robot k8s-ci-robot added priority/important-soon Must be staffed and worked on either currently, or very soon, ideally in time for the next release. area/cloudprovider area/kubectl sig/architecture Categorizes an issue or PR as relevant to SIG Architecture. sig/auth Categorizes an issue or PR as relevant to SIG Auth. sig/cli Categorizes an issue or PR as relevant to SIG CLI. sig/cloud-provider Categorizes an issue or PR as relevant to SIG Cloud Provider. sig/instrumentation Categorizes an issue or PR as relevant to SIG Instrumentation. sig/node Categorizes an issue or PR as relevant to SIG Node. and removed needs-priority Indicates a PR lacks a `priority/foo` label and requires one. labels Jul 7, 2023
@seans3
Copy link
Contributor Author

seans3 commented Jul 7, 2023

/cc @aojea
/cc @ardaguclu

@seans3
Copy link
Contributor Author

seans3 commented Jul 7, 2023

/retest

1 similar comment
@seans3
Copy link
Contributor Author

seans3 commented Jul 7, 2023

/retest

@seans3
Copy link
Contributor Author

seans3 commented Jul 7, 2023

/cc @jpbetz

@aojea
Copy link
Member

aojea commented Sep 1, 2023

LGTM

some questions that. may be follow ups if they make sense

@aojea
Copy link
Member

aojea commented Sep 2, 2023

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Sep 2, 2023
@k8s-ci-robot
Copy link
Contributor

LGTM label has been added.

Git tree hash: e63541a9b1e44c41bd81732a42f56e4a220c19c1

Copy link
Member

@liggitt liggitt left a comment

Choose a reason for hiding this comment

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

/lgtm
/approve
/hold for one question about the websocket impl matching the spdy impl lack of thread safety

}

// NewWebSocketExecutor allows to execute commands via a WebSocket connection.
func NewWebSocketExecutor(config *restclient.Config, method, url string) (Executor, error) {
Copy link
Member

Choose a reason for hiding this comment

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

the returned executor's Stream / StreamWithContext methods are not threadsafe, right? I think the spdy executor has the same issue (due to the coupled upgrader storing state during the connection setup) but can you verify that? would be good to explicitly document that here and on the spdy constructor, but it's fine if that goes into a follow up

Copy link
Contributor Author

@seans3 seans3 Sep 5, 2023

Choose a reason for hiding this comment

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

Yes. You are correct that neither the SPDY nor WebSocket Stream/StreamWithContext are thread-safe for a single executor. As you mention, the UpgradeRoundTripper for both store state (the dialed/created connection). SPDY already has some documentation related to this when defining the SpdyRoundTripper struct. Above the connection field is the following comment

type SpdyRoundTripper struct {
...
       /* TODO according to http://golang.org/pkg/net/http/#RoundTripper, a RoundTripper                                                                                                              
           must be safe for use by multiple concurrent goroutines. If this is absolutely                                                                                                               
           necessary, we could keep a map from http.Request to net.Conn. In practice,                                                                                                                  
           a client will create an http.Client, set the transport to a new insteace of                                                                                                                 
           SpdyRoundTripper, and use it a single time, so this hopefully won't be an issue.                                                                                                            
        */                                                                                                                                                                                             
        // conn is the underlying network connection to the remote server.                                                                                                                             
        conn net.Conn                                                                        

I have added documentation about the lack of thread safety to WebSocket.Stream/StreamWithContext

@k8s-ci-robot k8s-ci-robot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Sep 5, 2023
@k8s-ci-robot k8s-ci-robot removed the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Sep 5, 2023
@seans3
Copy link
Contributor Author

seans3 commented Sep 5, 2023

/retest

unrelated required test failure

@aojea
Copy link
Member

aojea commented Sep 5, 2023

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Sep 5, 2023
@k8s-ci-robot
Copy link
Contributor

LGTM label has been added.

Git tree hash: 4cf19be17ea27119104412468df71489446462a9

@aojea
Copy link
Member

aojea commented Sep 5, 2023

/lgtm /approve /hold for one question about the websocket impl matching the spdy impl lack of thread safety

@liggitt it is on hold and the approve label was not added

@liggitt
Copy link
Member

liggitt commented Sep 5, 2023

/hold cancel
/lgtm
/approve

@k8s-ci-robot k8s-ci-robot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Sep 5, 2023
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: liggitt, seans3

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 /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Sep 5, 2023
@k8s-ci-robot k8s-ci-robot merged commit 6013381 into kubernetes:master Sep 5, 2023
17 of 18 checks passed
SIG Node PR Triage automation moved this from Needs Reviewer to Done Sep 5, 2023
@k8s-ci-robot k8s-ci-robot added this to the v1.29 milestone Sep 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. area/cloudprovider area/kubectl area/stable-metrics Issues or PRs involving stable metrics cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/feature Categorizes issue or PR as related to a new feature. lgtm "Looks good to me", indicates that a PR is ready to be merged. priority/important-soon Must be staffed and worked on either currently, or very soon, ideally in time for the next release. release-note-none Denotes a PR that doesn't merit a release note. sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. sig/architecture Categorizes an issue or PR as relevant to SIG Architecture. sig/auth Categorizes an issue or PR as relevant to SIG Auth. sig/cli Categorizes an issue or PR as relevant to SIG CLI. sig/cloud-provider Categorizes an issue or PR as relevant to SIG Cloud Provider. sig/instrumentation Categorizes an issue or PR as relevant to SIG Instrumentation. sig/network Categorizes an issue or PR as relevant to SIG Network. sig/node Categorizes an issue or PR as relevant to SIG Node. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. triage/accepted Indicates an issue or PR is ready to be actively worked on.
Projects
Archived in project
Archived in project
Archived in project
Development

Successfully merging this pull request may close these issues.

Support kubectl exec/attach using Websocket
10 participants