etcdのgRPCコードリーディング
Do'er Advent Calendar 2022の22日目です。
etcdとは「a strongly consistent, distributed key-value store that provides a reliable way to store data that needs to be accessed by a distributed system or cluster of machines」であり、KubernetesやRookで使われていて、Quickstartを参考にすれば手元で動かせます。
いくつかコミットをしていますが、etcdではgRPCが使われているのでいろいろと思い出す必要がありました。
2年前くらいにやったThe complete gRPC courseをもう一度やったらなんとなく読めるようになったのでメモ書きをします。
コードリーディングの対象は命名からして簡単そうなclient.go
のcheckVersion
にする。
Status
の返り値であるresp.Version
を使って処理がされているので、これがどこから来た何なのかを知りたい。
etcd/client.go at 16e1fff519eeff66e626dd15fef399ea2b10b9cc · etcd-io/etcd · GitHub
func (c *Client) checkVersion() (err error) { ... resp, rerr := c.Status(ctx, e) ... vs := strings.Split(resp.Version, ".") ...
Status
の定義ジャンプをすると、maintenance.go
に飛ぶ。
etcd/maintenance.go at 16e1fff519eeff66e626dd15fef399ea2b10b9cc · etcd-io/etcd · GitHub
func (m *maintenance) Status(ctx context.Context, endpoint string) (*StatusResponse, error) { ... resp, err := remote.Status(ctx, &pb.StatusRequest{}, m.callOpts...) ...
さらにStatus
の定義ジャンプをすると、proto定義から生成されるrpc.pb.go
に飛ぶ。
etcd/rpc.pb.go at 16e1fff519eeff66e626dd15fef399ea2b10b9cc · etcd-io/etcd · GitHub
type MaintenanceClient interface { // Alarm activates, deactivates, and queries alarms regarding cluster health. Alarm(ctx context.Context, in *AlarmRequest, opts ...grpc.CallOption) (*AlarmResponse, error) // Status gets the status of the member. Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error) ...
rpc.proto
を見ると、関連しているmessage
とservice
が定義されている。
StatusResponse
には目的のversion
がある。
etcd/rpc.proto at 16e1fff519eeff66e626dd15fef399ea2b10b9cc · etcd-io/etcd · GitHub
message StatusRequest { option (versionpb.etcd_version_msg) = "3.0"; } message StatusResponse { option (versionpb.etcd_version_msg) = "3.0"; ResponseHeader header = 1; // version is the cluster protocol version used by the responding member. string version = 2; ... } service Maintenance { ... // Status gets the status of the member. rpc Status(StatusRequest) returns (StatusResponse) { option (google.api.http) = { post: "/v3/maintenance/status" body: "*" }; }
RESTっぽいパスが定義されているし、scripts/genproto.sh
に--grpc-gateway_out
があったのでgRPC-Gatewayを使っていそう。だが完全に忘れているのでエンドポイントの関数がどこにあるのかわからない。Status
でコード検索をかけるとserver/etcdserver/api/v3rpc/maintenance.go
という、いかにもそれっぽいパスに関数が定義されていた。
定数のversion.Version
が返り値であるresp
に含まれている。
func (ms *maintenanceServer) Status(ctx context.Context, ar *pb.StatusRequest) (*pb.StatusResponse, error) { ... resp := &pb.StatusResponse{ Header: hdr, Version: version.Version, ...
という感じでなんとなく読めたのでおしまい。