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

csds: implement CSDS service handler #4243

Merged
merged 10 commits into from Mar 16, 2021
Merged

csds: implement CSDS service handler #4243

merged 10 commits into from Mar 16, 2021

Conversation

menghanl
Copy link
Contributor

@menghanl menghanl commented Mar 4, 2021

No description provided.

@menghanl menghanl requested a review from easwars March 4, 2021 07:26
@menghanl menghanl added this to the 1.37 Release milestone Mar 4, 2021
xds/csds/csds.go Outdated
ret := &clientStatusServer{}
ret.xdsClient, ret.xdsClientErr = newXDSClient()
if ret.xdsClientErr != nil {
logger.Errorf("failed to create xds client: %v", ret.xdsClientErr)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not return an error as a second return value instead? What good is it to have a CSDS server without an xdsClient?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's harder to use if this function returns an error, because they cannot register this in one line.

If this fails, the server will fail all RPCs.

And also, I think the error returned here is either useless, or should have been returned by other functions.
Before this happens, the gRPC client/server that uses xDS would also fail, and the user will get the returned error from there.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not convinced by the argument that returning an error makes the function harder to use. And that if the client creation runs into an error here, it would have elsewhere as well.
Given that this is a public facing API, I feel it would be better to have it stand on its own rather than have these unsaid dependencies.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed this to return an error.

Also the returned struct is a concrete struct, instead of the interface. So we can also get rid of the finalizer.

xds/csds/csds.go Outdated Show resolved Hide resolved
xds/csds/csds.go Outdated
if err != nil {
return err
}
resp, errResp := s.buildClientStatusRespForReq(req)
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: s/errResp/err ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

xds/csds/csds.go Outdated
// If it returns an error, the error is a status error.
func (s *clientStatusServer) buildClientStatusRespForReq(req *v3statuspb.ClientStatusRequest) (*v3statuspb.ClientStatusResponse, error) {
if len(req.NodeMatchers) != 0 {
return nil, status.Errorf(codes.InvalidArgument, "NodeMatchers are not supported, request contains NodeMatchers: %v", req.NodeMatchers)
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: s/NodeMatchers/node_matchers/ in the error message.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

xds/csds/csds.go Outdated
return nil, status.Errorf(codes.InvalidArgument, "NodeMatchers are not supported, request contains NodeMatchers: %v", req.NodeMatchers)
}
if s.xdsClient == nil {
return nil, status.Errorf(codes.FailedPrecondition, "xds client creation failed with error: %v", s.xdsClientErr)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same question here? What purpose does it serve to have a CSDS server without an xdsClient?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Replied in the previous comment.

DumpCDS() (string, map[string]client.UpdateWithMD)
DumpEDS() (string, map[string]client.UpdateWithMD)
BootstrapConfig() *bootstrap.Config
Close()
Copy link
Contributor

Choose a reason for hiding this comment

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

Same for Close().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a good question actually. The client used by CSDS is never closed. We should close it, but there's no easy way.

What's I'm thinking is to set a Finalizer: https://golang.org/pkg/runtime/#SetFinalizer
But not sure if it's a good idea

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a finalizer. Does seems too bad. Let me know what you think.

Also, cc @dfawley What do you think of a finalizer?

xdsC.WatchEndpoints(target, func(client.EndpointsUpdate, error) {})
}

for i := 0; i < retryCount; i++ {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there something better than retrying in a loop and sleeping in between that we can do here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't find any better way. There are real xDS RPCs involved, and we don't have control of the timing.

xds/csds/csds_test.go Show resolved Hide resolved
xds/csds/csds_test.go Show resolved Hide resolved
if err := stream.Send(&v3statuspb.ClientStatusRequest{Node: nil}); err != nil {
return fmt.Errorf("failed to send: %v", err)
}
r, err := stream.Recv()
Copy link
Contributor

Choose a reason for hiding this comment

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

We are using the streaming method in all tests. For completeness sake, should one of the checkForXxx use the unary method?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it would be OK, because they both simply call the same function.

Copy link
Contributor

Choose a reason for hiding this comment

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

But isn't that an implementation detail. Hmm ... maybe its ok.

Copy link
Contributor

@easwars easwars left a comment

Choose a reason for hiding this comment

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

I think the only sticking point is the API of NewClientStatusDiscoveryServer. Otherwise looks good.

xds/csds/csds.go Outdated
ret := &clientStatusServer{}
ret.xdsClient, ret.xdsClientErr = newXDSClient()
if ret.xdsClientErr != nil {
logger.Errorf("failed to create xds client: %v", ret.xdsClientErr)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not convinced by the argument that returning an error makes the function harder to use. And that if the client creation runs into an error here, it would have elsewhere as well.
Given that this is a public facing API, I feel it would be better to have it stand on its own rather than have these unsaid dependencies.

xds/csds/csds.go Outdated
//
// Besides, if client cannot be created, the users should have received
// the error, because their client/server cannot work, either.
logger.Errorf("failed to create xds client: %v", ret.xdsClientErr)
Copy link
Contributor

Choose a reason for hiding this comment

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

Also, return from inside the if, so that the code under else need not be indented.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

xds/csds/csds.go Outdated
case client.ServiceStatusNACKed:
return v3adminpb.ClientResourceStatus_NACKED
}
return v3adminpb.ClientResourceStatus_UNKNOWN
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: move the last return into a default case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

if err := stream.Send(&v3statuspb.ClientStatusRequest{Node: nil}); err != nil {
return fmt.Errorf("failed to send: %v", err)
}
r, err := stream.Recv()
Copy link
Contributor

Choose a reason for hiding this comment

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

But isn't that an implementation detail. Hmm ... maybe its ok.

xds/csds/csds.go Outdated
Comment on lines 120 to 123
if s.xdsClient == nil {
// This should never happen.
return nil, status.Errorf(codes.FailedPrecondition, "xds client is nil")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

We don't need this check anymore, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed. Should be safe now.

@menghanl menghanl merged commit 95173a5 into grpc:master Mar 16, 2021
@menghanl menghanl deleted the csds_real branch March 16, 2021 21:05
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 13, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants