-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
xds: introduce simple grpc transport for generic xds clients #8066
base: master
Are you sure you want to change the base?
xds: introduce simple grpc transport for generic xds clients #8066
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #8066 +/- ##
==========================================
+ Coverage 82.24% 82.40% +0.15%
==========================================
Files 387 388 +1
Lines 38967 39000 +33
==========================================
+ Hits 32048 32136 +88
+ Misses 5599 5553 -46
+ Partials 1320 1311 -9
|
ad889b4
to
377a648
Compare
fcbf470
to
efeddd1
Compare
a6648d7
to
c63118f
Compare
wantErr bool | ||
}{ | ||
{ | ||
name: "ServerURI_empty", |
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.
Nit: s/_/ /
throughout? t.Run
will convert them to underscores to make it a legal test name -- just make sure they're human-readable here.
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 have made it more like sentence. Was trying to follow go/go-style/decisions#subtest-names
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 is something that I learnt recently as well, and though it feels a little weird in the beginning to have subtest names that have underscrores, when it comes time to run them individually, it makes a lot of sense as direct copy paste works.
if err := stream.Send(req); err != nil { | ||
t.Fatalf("failed to send message: %v", err) | ||
} |
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.
Can you also make this do a Recv
? Codecov shows that's not covered.
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. I wanted to check on this that for Recv, we need a grpc enabled xDS server with byte-based handlers. Should we add an xDS server with byte-based handler or just have a test grpc server to test this? Eventually for e2e tests I think we do need a test xDS server because go-control-plane one proto based.
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.
For this test, we could do literally any kind of grpc server. It could be like the stub server, or whatever. Byte-based is not relevant. The server should ideally do proto as is the default, and we can serialize/deserialize proto messages into byte buffers on the client manually for the testing.
True, for e2e tests of xdsclient, we will need to use go-control-plane. If we have testing helpers that make it easy to use, that's fine but, I'd prefer to copy them into the clients
subtree and try to make sure we don't import things from the rest of the grpc tree. Otherwise it will be really hard to separate when it's time to move it out.
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.
For this test. I have created a test server using the same byteCodec to receive and send bytes and written a single test for send and receive. Let me know if that's good enough.
For e2e tests I think we will need to have management server using go-control-plane but that can be separate PR
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 server should ideally do proto as is the default
I have created a test server using the same byteCodec
Is there a reason you didn't follow the way I suggested? A normal proto server would be less testing code (which is good) and better proof the byte codec is working as intended.
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.
Kept the test logic same and change the test server to implement AggregatedDiscoveryServiceServer and handle StreamAggregatedResources
"time" | ||
|
||
"google.golang.org/grpc/credentials/insecure" | ||
"google.golang.org/grpc/internal/grpctest" |
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.
We should avoid using anything from grpc/internal. That includes grpctest and e2e. We won't be able to move this out like this.
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 intend it remove. Regarding grpctest, should we just remove subtests for now or later? Regarding e2e, as i mentioned I think we need to add grpc enabeld xds server.
e892817
to
5db47df
Compare
4d47a17
to
4ca2a7c
Compare
f7acbb9
to
6d9631e
Compare
7f0b019
to
3bc9087
Compare
3bc9087
to
f1abdf0
Compare
} | ||
|
||
func (c *byteCodec) Name() string { | ||
return "byteCodec" |
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.
Should we use a more specific name to avoid possible name conflicts with a similar byte codec used by a user? Maybe something like "grpc.xds.internal.clients.grpctransport.byte_codec" that mirrors the package path?
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.
Make sense. Changed.
wantErr bool | ||
}{ | ||
{ | ||
name: "ServerURI_empty", |
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 is something that I learnt recently as well, and though it feels a little weird in the beginning to have subtest names that have underscrores, when it comes time to run them individually, it makes a lot of sense as direct copy paste works.
} | ||
|
||
// Builder creates gRPC-based Transports. It must be paired with ServerConfigs | ||
// that contain its ServerConfigExtension. |
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.
Nit: that contain an extension of type ServerConfigExtension
? or something similar to 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.
Modified
if sc.Extensions == nil { | ||
return nil, fmt.Errorf("ServerConfig's Extensions field cannot be nil for gRPC transport") | ||
} | ||
gtsce, ok := sc.Extensions.(ServerConfigExtension) |
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.
gtsce
is not very readable. Maybe just sce
might do?
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.
Done
// transport channel to same server can be shared between xDS and LRS | ||
// client. | ||
|
||
// Create a new gRPC client/channel for the xDS management server with the |
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.
Here also it can be an xDS server or an LRS server. So, I'd probably skip the xDS part.
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.
Done
err := s.stream.RecvMsg(&typedRes) | ||
if err != nil { |
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.
Nit: Assignment and conditional in the same line.
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.
Done
return typedRes, nil | ||
} | ||
|
||
// Close closes all the gRPC streams to the server. |
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.
Maybe: Close closes the gRPC channel to the server?
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.
Modified
}, | ||
{ | ||
name: "error", | ||
serverURI: "invalid-server-uri", |
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.. ok, i see what you are doing. Maybe you can just split it into two separate tests, each with no table. So, in the second test, you wont even start a server and instead you will pass an invalid server uri to Build
.
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.
Separated into 2 different tests
builder := Builder{} | ||
transport, err := builder.Build(serverCfg) | ||
if err != nil { | ||
t.Fatalf("failed to build transport: %v", err) |
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.
Here and everywhere else, the error strings that are part of log messages and test failure messages need not obey the rules governing general error strings in Go. See: go/go-style/decisions#error-strings
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.
Done
if !ok { | ||
t.Fatalf("ts.requestChan is closed") | ||
} |
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.
requestChan
is never closed. I would get rid of this to simplify the test logic.
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.
Done
if !ok { | ||
t.Fatalf("ts.requestChan is closed") | ||
} | ||
if !cmp.Equal(testDiscoverRequest, gotReq, protocmp.Transform()) { |
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.
Please use the same order, "got before want" in your comparison (as well as the error string).
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.
Done
if err := proto.Unmarshal(res, &gotRes); err != nil { | ||
t.Fatalf("failed to unmarshal response from ts.requestChan to DiscoveryRequest: %v", err) | ||
} | ||
if !cmp.Equal(testDiscoverResponse, &gotRes, protocmp.Transform()) { |
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.
There is just way too much coupling between the test logic and the logic in the test server. This results in very brittle tests.
What is the eventual plan? Is it to use the go-control-plane as the management server here?
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, once we have xds client implemented, we will be able to use go-control-plane in e2e tests. For now, having the code coverage with simple grpc server is enough.
After last commit, response to be returned by StreamAggregatedResources handler can be controlled by test as it is a param in testServer. Regarding having test response as part of testServer struct, we can have implementation of StreamAggregatedResources within test inline so then we don't need response field in testServer.
This PR is adding a simple grpc-based transport implementation of generic xds clients transport builder which can be provided as transport builder in xDS and LRS client.
The
build()
method currently creates a new grpc channel every time. However, in future we will incorporate reference count map for existing transports and deduplicate transports based on provided ServerConfig so that transport channel to same server can be shared among xDS and LRS client.POC
Internal Design
RELEASE NOTES: None